1282289Serj/****************************************************************************** 2282289Serj 3315333Serj Copyright (c) 2001-2017, Intel Corporation 4282289Serj All rights reserved. 5315333Serj 6315333Serj Redistribution and use in source and binary forms, with or without 7282289Serj modification, are permitted provided that the following conditions are met: 8315333Serj 9315333Serj 1. Redistributions of source code must retain the above copyright notice, 10282289Serj this list of conditions and the following disclaimer. 11315333Serj 12315333Serj 2. Redistributions in binary form must reproduce the above copyright 13315333Serj notice, this list of conditions and the following disclaimer in the 14282289Serj documentation and/or other materials provided with the distribution. 15315333Serj 16315333Serj 3. Neither the name of the Intel Corporation nor the names of its 17315333Serj contributors may be used to endorse or promote products derived from 18282289Serj this software without specific prior written permission. 19315333Serj 20282289Serj THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21315333Serj AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22315333Serj IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23315333Serj ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24315333Serj LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25315333Serj CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26315333Serj SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27315333Serj INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28315333Serj CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29282289Serj ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30282289Serj POSSIBILITY OF SUCH DAMAGE. 31282289Serj 32282289Serj******************************************************************************/ 33282289Serj/*$FreeBSD: stable/10/sys/dev/ixgbe/ixgbe_x550.c 315333 2017-03-15 21:20:17Z erj $*/ 34282289Serj 35282289Serj#include "ixgbe_x550.h" 36282289Serj#include "ixgbe_x540.h" 37282289Serj#include "ixgbe_type.h" 38282289Serj#include "ixgbe_api.h" 39282289Serj#include "ixgbe_common.h" 40282289Serj#include "ixgbe_phy.h" 41282289Serj 42282289Serjstatic s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed); 43315333Serjstatic s32 ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *, u32 mask); 44315333Serjstatic void ixgbe_release_swfw_sync_X550a(struct ixgbe_hw *, u32 mask); 45315333Serjstatic s32 ixgbe_read_mng_if_sel_x550em(struct ixgbe_hw *hw); 46282289Serj 47282289Serj/** 48282289Serj * ixgbe_init_ops_X550 - Inits func ptrs and MAC type 49282289Serj * @hw: pointer to hardware structure 50282289Serj * 51282289Serj * Initialize the function pointers and assign the MAC type for X550. 52282289Serj * Does not touch the hardware. 53282289Serj **/ 54282289Serjs32 ixgbe_init_ops_X550(struct ixgbe_hw *hw) 55282289Serj{ 56282289Serj struct ixgbe_mac_info *mac = &hw->mac; 57282289Serj struct ixgbe_eeprom_info *eeprom = &hw->eeprom; 58282289Serj s32 ret_val; 59282289Serj 60282289Serj DEBUGFUNC("ixgbe_init_ops_X550"); 61282289Serj 62282289Serj ret_val = ixgbe_init_ops_X540(hw); 63282289Serj mac->ops.dmac_config = ixgbe_dmac_config_X550; 64282289Serj mac->ops.dmac_config_tcs = ixgbe_dmac_config_tcs_X550; 65282289Serj mac->ops.dmac_update_tcs = ixgbe_dmac_update_tcs_X550; 66315333Serj mac->ops.setup_eee = NULL; 67282289Serj mac->ops.set_source_address_pruning = 68282289Serj ixgbe_set_source_address_pruning_X550; 69282289Serj mac->ops.set_ethertype_anti_spoofing = 70282289Serj ixgbe_set_ethertype_anti_spoofing_X550; 71282289Serj 72282289Serj mac->ops.get_rtrup2tc = ixgbe_dcb_get_rtrup2tc_generic; 73282289Serj eeprom->ops.init_params = ixgbe_init_eeprom_params_X550; 74282289Serj eeprom->ops.calc_checksum = ixgbe_calc_eeprom_checksum_X550; 75282289Serj eeprom->ops.read = ixgbe_read_ee_hostif_X550; 76282289Serj eeprom->ops.read_buffer = ixgbe_read_ee_hostif_buffer_X550; 77282289Serj eeprom->ops.write = ixgbe_write_ee_hostif_X550; 78282289Serj eeprom->ops.write_buffer = ixgbe_write_ee_hostif_buffer_X550; 79282289Serj eeprom->ops.update_checksum = ixgbe_update_eeprom_checksum_X550; 80282289Serj eeprom->ops.validate_checksum = ixgbe_validate_eeprom_checksum_X550; 81282289Serj 82282289Serj mac->ops.disable_mdd = ixgbe_disable_mdd_X550; 83282289Serj mac->ops.enable_mdd = ixgbe_enable_mdd_X550; 84282289Serj mac->ops.mdd_event = ixgbe_mdd_event_X550; 85282289Serj mac->ops.restore_mdd_vf = ixgbe_restore_mdd_vf_X550; 86282289Serj mac->ops.disable_rx = ixgbe_disable_rx_x550; 87315333Serj /* Manageability interface */ 88315333Serj mac->ops.set_fw_drv_ver = ixgbe_set_fw_drv_ver_x550; 89315333Serj switch (hw->device_id) { 90315333Serj case IXGBE_DEV_ID_X550EM_X_10G_T: 91315333Serj case IXGBE_DEV_ID_X550EM_A_10G_T: 92282289Serj hw->mac.ops.led_on = ixgbe_led_on_t_X550em; 93282289Serj hw->mac.ops.led_off = ixgbe_led_off_t_X550em; 94315333Serj break; 95315333Serj default: 96315333Serj break; 97282289Serj } 98282289Serj return ret_val; 99282289Serj} 100282289Serj 101282289Serj/** 102282289Serj * ixgbe_read_cs4227 - Read CS4227 register 103282289Serj * @hw: pointer to hardware structure 104282289Serj * @reg: register number to write 105282289Serj * @value: pointer to receive value read 106282289Serj * 107282289Serj * Returns status code 108282289Serj **/ 109282289Serjstatic s32 ixgbe_read_cs4227(struct ixgbe_hw *hw, u16 reg, u16 *value) 110282289Serj{ 111315333Serj return hw->link.ops.read_link_unlocked(hw, hw->link.addr, reg, value); 112282289Serj} 113282289Serj 114282289Serj/** 115282289Serj * ixgbe_write_cs4227 - Write CS4227 register 116282289Serj * @hw: pointer to hardware structure 117282289Serj * @reg: register number to write 118282289Serj * @value: value to write to register 119282289Serj * 120282289Serj * Returns status code 121282289Serj **/ 122282289Serjstatic s32 ixgbe_write_cs4227(struct ixgbe_hw *hw, u16 reg, u16 value) 123282289Serj{ 124315333Serj return hw->link.ops.write_link_unlocked(hw, hw->link.addr, reg, value); 125282289Serj} 126282289Serj 127282289Serj/** 128282289Serj * ixgbe_read_pe - Read register from port expander 129282289Serj * @hw: pointer to hardware structure 130282289Serj * @reg: register number to read 131282289Serj * @value: pointer to receive read value 132282289Serj * 133282289Serj * Returns status code 134282289Serj **/ 135282289Serjstatic s32 ixgbe_read_pe(struct ixgbe_hw *hw, u8 reg, u8 *value) 136282289Serj{ 137282289Serj s32 status; 138282289Serj 139282289Serj status = ixgbe_read_i2c_byte_unlocked(hw, reg, IXGBE_PE, value); 140282289Serj if (status != IXGBE_SUCCESS) 141282289Serj ERROR_REPORT2(IXGBE_ERROR_CAUTION, 142282289Serj "port expander access failed with %d\n", status); 143282289Serj return status; 144282289Serj} 145282289Serj 146282289Serj/** 147282289Serj * ixgbe_write_pe - Write register to port expander 148282289Serj * @hw: pointer to hardware structure 149282289Serj * @reg: register number to write 150282289Serj * @value: value to write 151282289Serj * 152282289Serj * Returns status code 153282289Serj **/ 154282289Serjstatic s32 ixgbe_write_pe(struct ixgbe_hw *hw, u8 reg, u8 value) 155282289Serj{ 156282289Serj s32 status; 157282289Serj 158282289Serj status = ixgbe_write_i2c_byte_unlocked(hw, reg, IXGBE_PE, value); 159282289Serj if (status != IXGBE_SUCCESS) 160282289Serj ERROR_REPORT2(IXGBE_ERROR_CAUTION, 161282289Serj "port expander access failed with %d\n", status); 162282289Serj return status; 163282289Serj} 164282289Serj 165282289Serj/** 166282289Serj * ixgbe_reset_cs4227 - Reset CS4227 using port expander 167282289Serj * @hw: pointer to hardware structure 168282289Serj * 169295524Ssbruno * This function assumes that the caller has acquired the proper semaphore. 170282289Serj * Returns error code 171282289Serj **/ 172282289Serjstatic s32 ixgbe_reset_cs4227(struct ixgbe_hw *hw) 173282289Serj{ 174282289Serj s32 status; 175295524Ssbruno u32 retry; 176295524Ssbruno u16 value; 177282289Serj u8 reg; 178282289Serj 179295524Ssbruno /* Trigger hard reset. */ 180282289Serj status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, ®); 181282289Serj if (status != IXGBE_SUCCESS) 182282289Serj return status; 183282289Serj reg |= IXGBE_PE_BIT1; 184282289Serj status = ixgbe_write_pe(hw, IXGBE_PE_OUTPUT, reg); 185282289Serj if (status != IXGBE_SUCCESS) 186282289Serj return status; 187282289Serj 188282289Serj status = ixgbe_read_pe(hw, IXGBE_PE_CONFIG, ®); 189282289Serj if (status != IXGBE_SUCCESS) 190282289Serj return status; 191282289Serj reg &= ~IXGBE_PE_BIT1; 192282289Serj status = ixgbe_write_pe(hw, IXGBE_PE_CONFIG, reg); 193282289Serj if (status != IXGBE_SUCCESS) 194282289Serj return status; 195282289Serj 196282289Serj status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, ®); 197282289Serj if (status != IXGBE_SUCCESS) 198282289Serj return status; 199282289Serj reg &= ~IXGBE_PE_BIT1; 200282289Serj status = ixgbe_write_pe(hw, IXGBE_PE_OUTPUT, reg); 201282289Serj if (status != IXGBE_SUCCESS) 202282289Serj return status; 203282289Serj 204282289Serj usec_delay(IXGBE_CS4227_RESET_HOLD); 205282289Serj 206282289Serj status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, ®); 207282289Serj if (status != IXGBE_SUCCESS) 208282289Serj return status; 209282289Serj reg |= IXGBE_PE_BIT1; 210282289Serj status = ixgbe_write_pe(hw, IXGBE_PE_OUTPUT, reg); 211282289Serj if (status != IXGBE_SUCCESS) 212282289Serj return status; 213282289Serj 214295524Ssbruno /* Wait for the reset to complete. */ 215282289Serj msec_delay(IXGBE_CS4227_RESET_DELAY); 216295524Ssbruno for (retry = 0; retry < IXGBE_CS4227_RETRIES; retry++) { 217295524Ssbruno status = ixgbe_read_cs4227(hw, IXGBE_CS4227_EFUSE_STATUS, 218295524Ssbruno &value); 219295524Ssbruno if (status == IXGBE_SUCCESS && 220295524Ssbruno value == IXGBE_CS4227_EEPROM_LOAD_OK) 221295524Ssbruno break; 222295524Ssbruno msec_delay(IXGBE_CS4227_CHECK_DELAY); 223295524Ssbruno } 224295524Ssbruno if (retry == IXGBE_CS4227_RETRIES) { 225295524Ssbruno ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE, 226295524Ssbruno "CS4227 reset did not complete."); 227295524Ssbruno return IXGBE_ERR_PHY; 228295524Ssbruno } 229282289Serj 230295524Ssbruno status = ixgbe_read_cs4227(hw, IXGBE_CS4227_EEPROM_STATUS, &value); 231295524Ssbruno if (status != IXGBE_SUCCESS || 232295524Ssbruno !(value & IXGBE_CS4227_EEPROM_LOAD_OK)) { 233295524Ssbruno ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE, 234295524Ssbruno "CS4227 EEPROM did not load successfully."); 235295524Ssbruno return IXGBE_ERR_PHY; 236295524Ssbruno } 237295524Ssbruno 238282289Serj return IXGBE_SUCCESS; 239282289Serj} 240282289Serj 241282289Serj/** 242282289Serj * ixgbe_check_cs4227 - Check CS4227 and reset as needed 243282289Serj * @hw: pointer to hardware structure 244282289Serj **/ 245282289Serjstatic void ixgbe_check_cs4227(struct ixgbe_hw *hw) 246282289Serj{ 247295524Ssbruno s32 status = IXGBE_SUCCESS; 248282289Serj u32 swfw_mask = hw->phy.phy_semaphore_mask; 249295524Ssbruno u16 value = 0; 250282289Serj u8 retry; 251282289Serj 252282289Serj for (retry = 0; retry < IXGBE_CS4227_RETRIES; retry++) { 253282289Serj status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask); 254282289Serj if (status != IXGBE_SUCCESS) { 255282289Serj ERROR_REPORT2(IXGBE_ERROR_CAUTION, 256295524Ssbruno "semaphore failed with %d", status); 257295524Ssbruno msec_delay(IXGBE_CS4227_CHECK_DELAY); 258295524Ssbruno continue; 259282289Serj } 260295524Ssbruno 261295524Ssbruno /* Get status of reset flow. */ 262295524Ssbruno status = ixgbe_read_cs4227(hw, IXGBE_CS4227_SCRATCH, &value); 263295524Ssbruno 264295524Ssbruno if (status == IXGBE_SUCCESS && 265295524Ssbruno value == IXGBE_CS4227_RESET_COMPLETE) 266295524Ssbruno goto out; 267295524Ssbruno 268295524Ssbruno if (status != IXGBE_SUCCESS || 269295524Ssbruno value != IXGBE_CS4227_RESET_PENDING) 270295524Ssbruno break; 271295524Ssbruno 272295524Ssbruno /* Reset is pending. Wait and check again. */ 273295524Ssbruno hw->mac.ops.release_swfw_sync(hw, swfw_mask); 274295524Ssbruno msec_delay(IXGBE_CS4227_CHECK_DELAY); 275295524Ssbruno } 276295524Ssbruno 277295524Ssbruno /* If still pending, assume other instance failed. */ 278295524Ssbruno if (retry == IXGBE_CS4227_RETRIES) { 279295524Ssbruno status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask); 280295524Ssbruno if (status != IXGBE_SUCCESS) { 281295524Ssbruno ERROR_REPORT2(IXGBE_ERROR_CAUTION, 282295524Ssbruno "semaphore failed with %d", status); 283282289Serj return; 284282289Serj } 285282289Serj } 286295524Ssbruno 287295524Ssbruno /* Reset the CS4227. */ 288295524Ssbruno status = ixgbe_reset_cs4227(hw); 289295524Ssbruno if (status != IXGBE_SUCCESS) { 290295524Ssbruno ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, 291295524Ssbruno "CS4227 reset failed: %d", status); 292295524Ssbruno goto out; 293295524Ssbruno } 294295524Ssbruno 295295524Ssbruno /* Reset takes so long, temporarily release semaphore in case the 296295524Ssbruno * other driver instance is waiting for the reset indication. 297295524Ssbruno */ 298295524Ssbruno ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH, 299295524Ssbruno IXGBE_CS4227_RESET_PENDING); 300295524Ssbruno hw->mac.ops.release_swfw_sync(hw, swfw_mask); 301295524Ssbruno msec_delay(10); 302295524Ssbruno status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask); 303295524Ssbruno if (status != IXGBE_SUCCESS) { 304295524Ssbruno ERROR_REPORT2(IXGBE_ERROR_CAUTION, 305295524Ssbruno "semaphore failed with %d", status); 306295524Ssbruno return; 307295524Ssbruno } 308295524Ssbruno 309295524Ssbruno /* Record completion for next time. */ 310295524Ssbruno status = ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH, 311295524Ssbruno IXGBE_CS4227_RESET_COMPLETE); 312295524Ssbruno 313295524Ssbrunoout: 314295524Ssbruno hw->mac.ops.release_swfw_sync(hw, swfw_mask); 315295524Ssbruno msec_delay(hw->eeprom.semaphore_delay); 316282289Serj} 317282289Serj 318282289Serj/** 319282289Serj * ixgbe_setup_mux_ctl - Setup ESDP register for I2C mux control 320282289Serj * @hw: pointer to hardware structure 321282289Serj **/ 322282289Serjstatic void ixgbe_setup_mux_ctl(struct ixgbe_hw *hw) 323282289Serj{ 324282289Serj u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 325282289Serj 326282289Serj if (hw->bus.lan_id) { 327282289Serj esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1); 328282289Serj esdp |= IXGBE_ESDP_SDP1_DIR; 329282289Serj } 330282289Serj esdp &= ~(IXGBE_ESDP_SDP0_NATIVE | IXGBE_ESDP_SDP0_DIR); 331282289Serj IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 332282289Serj IXGBE_WRITE_FLUSH(hw); 333282289Serj} 334282289Serj 335282289Serj/** 336315333Serj * ixgbe_read_phy_reg_mdi_22 - Read from a clause 22 PHY register without lock 337315333Serj * @hw: pointer to hardware structure 338315333Serj * @reg_addr: 32 bit address of PHY register to read 339315333Serj * @dev_type: always unused 340315333Serj * @phy_data: Pointer to read data from PHY register 341315333Serj */ 342315333Serjstatic s32 ixgbe_read_phy_reg_mdi_22(struct ixgbe_hw *hw, u32 reg_addr, 343315333Serj u32 dev_type, u16 *phy_data) 344315333Serj{ 345315333Serj u32 i, data, command; 346315333Serj UNREFERENCED_1PARAMETER(dev_type); 347315333Serj 348315333Serj /* Setup and write the read command */ 349315333Serj command = (reg_addr << IXGBE_MSCA_DEV_TYPE_SHIFT) | 350315333Serj (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | 351315333Serj IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_READ_AUTOINC | 352315333Serj IXGBE_MSCA_MDI_COMMAND; 353315333Serj 354315333Serj IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 355315333Serj 356315333Serj /* Check every 10 usec to see if the access completed. 357315333Serj * The MDI Command bit will clear when the operation is 358315333Serj * complete 359315333Serj */ 360315333Serj for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 361315333Serj usec_delay(10); 362315333Serj 363315333Serj command = IXGBE_READ_REG(hw, IXGBE_MSCA); 364315333Serj if (!(command & IXGBE_MSCA_MDI_COMMAND)) 365315333Serj break; 366315333Serj } 367315333Serj 368315333Serj if (command & IXGBE_MSCA_MDI_COMMAND) { 369315333Serj ERROR_REPORT1(IXGBE_ERROR_POLLING, 370315333Serj "PHY read command did not complete.\n"); 371315333Serj return IXGBE_ERR_PHY; 372315333Serj } 373315333Serj 374315333Serj /* Read operation is complete. Get the data from MSRWD */ 375315333Serj data = IXGBE_READ_REG(hw, IXGBE_MSRWD); 376315333Serj data >>= IXGBE_MSRWD_READ_DATA_SHIFT; 377315333Serj *phy_data = (u16)data; 378315333Serj 379315333Serj return IXGBE_SUCCESS; 380315333Serj} 381315333Serj 382315333Serj/** 383315333Serj * ixgbe_write_phy_reg_mdi_22 - Write to a clause 22 PHY register without lock 384315333Serj * @hw: pointer to hardware structure 385315333Serj * @reg_addr: 32 bit PHY register to write 386315333Serj * @dev_type: always unused 387315333Serj * @phy_data: Data to write to the PHY register 388315333Serj */ 389315333Serjstatic s32 ixgbe_write_phy_reg_mdi_22(struct ixgbe_hw *hw, u32 reg_addr, 390315333Serj u32 dev_type, u16 phy_data) 391315333Serj{ 392315333Serj u32 i, command; 393315333Serj UNREFERENCED_1PARAMETER(dev_type); 394315333Serj 395315333Serj /* Put the data in the MDI single read and write data register*/ 396315333Serj IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data); 397315333Serj 398315333Serj /* Setup and write the write command */ 399315333Serj command = (reg_addr << IXGBE_MSCA_DEV_TYPE_SHIFT) | 400315333Serj (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | 401315333Serj IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_WRITE | 402315333Serj IXGBE_MSCA_MDI_COMMAND; 403315333Serj 404315333Serj IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 405315333Serj 406315333Serj /* Check every 10 usec to see if the access completed. 407315333Serj * The MDI Command bit will clear when the operation is 408315333Serj * complete 409315333Serj */ 410315333Serj for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 411315333Serj usec_delay(10); 412315333Serj 413315333Serj command = IXGBE_READ_REG(hw, IXGBE_MSCA); 414315333Serj if (!(command & IXGBE_MSCA_MDI_COMMAND)) 415315333Serj break; 416315333Serj } 417315333Serj 418315333Serj if (command & IXGBE_MSCA_MDI_COMMAND) { 419315333Serj ERROR_REPORT1(IXGBE_ERROR_POLLING, 420315333Serj "PHY write cmd didn't complete\n"); 421315333Serj return IXGBE_ERR_PHY; 422315333Serj } 423315333Serj 424315333Serj return IXGBE_SUCCESS; 425315333Serj} 426315333Serj 427315333Serj/** 428282289Serj * ixgbe_identify_phy_x550em - Get PHY type based on device id 429282289Serj * @hw: pointer to hardware structure 430282289Serj * 431282289Serj * Returns error code 432282289Serj */ 433282289Serjstatic s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw) 434282289Serj{ 435315333Serj hw->mac.ops.set_lan_id(hw); 436315333Serj 437315333Serj ixgbe_read_mng_if_sel_x550em(hw); 438315333Serj 439282289Serj switch (hw->device_id) { 440315333Serj case IXGBE_DEV_ID_X550EM_A_SFP: 441315333Serj return ixgbe_identify_module_generic(hw); 442282289Serj case IXGBE_DEV_ID_X550EM_X_SFP: 443282289Serj /* set up for CS4227 usage */ 444282289Serj ixgbe_setup_mux_ctl(hw); 445282289Serj ixgbe_check_cs4227(hw); 446315333Serj /* Fallthrough */ 447282289Serj 448315333Serj case IXGBE_DEV_ID_X550EM_A_SFP_N: 449282289Serj return ixgbe_identify_module_generic(hw); 450282289Serj break; 451282289Serj case IXGBE_DEV_ID_X550EM_X_KX4: 452282289Serj hw->phy.type = ixgbe_phy_x550em_kx4; 453282289Serj break; 454315333Serj case IXGBE_DEV_ID_X550EM_X_XFI: 455315333Serj hw->phy.type = ixgbe_phy_x550em_xfi; 456315333Serj break; 457282289Serj case IXGBE_DEV_ID_X550EM_X_KR: 458315333Serj case IXGBE_DEV_ID_X550EM_A_KR: 459315333Serj case IXGBE_DEV_ID_X550EM_A_KR_L: 460282289Serj hw->phy.type = ixgbe_phy_x550em_kr; 461282289Serj break; 462315333Serj case IXGBE_DEV_ID_X550EM_A_10G_T: 463282289Serj case IXGBE_DEV_ID_X550EM_X_1G_T: 464282289Serj case IXGBE_DEV_ID_X550EM_X_10G_T: 465282289Serj return ixgbe_identify_phy_generic(hw); 466315333Serj case IXGBE_DEV_ID_X550EM_A_1G_T: 467315333Serj case IXGBE_DEV_ID_X550EM_A_1G_T_L: 468315333Serj hw->phy.type = ixgbe_phy_fw; 469315333Serj hw->phy.ops.read_reg = NULL; 470315333Serj hw->phy.ops.write_reg = NULL; 471315333Serj if (hw->bus.lan_id) 472315333Serj hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM; 473315333Serj else 474315333Serj hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM; 475315333Serj break; 476282289Serj default: 477282289Serj break; 478282289Serj } 479282289Serj return IXGBE_SUCCESS; 480282289Serj} 481282289Serj 482315333Serj/** 483315333Serj * ixgbe_fw_phy_activity - Perform an activity on a PHY 484315333Serj * @hw: pointer to hardware structure 485315333Serj * @activity: activity to perform 486315333Serj * @data: Pointer to 4 32-bit words of data 487315333Serj */ 488315333Serjs32 ixgbe_fw_phy_activity(struct ixgbe_hw *hw, u16 activity, 489315333Serj u32 (*data)[FW_PHY_ACT_DATA_COUNT]) 490315333Serj{ 491315333Serj union { 492315333Serj struct ixgbe_hic_phy_activity_req cmd; 493315333Serj struct ixgbe_hic_phy_activity_resp rsp; 494315333Serj } hic; 495315333Serj u16 retries = FW_PHY_ACT_RETRIES; 496315333Serj s32 rc; 497315333Serj u16 i; 498315333Serj 499315333Serj do { 500315333Serj memset(&hic, 0, sizeof(hic)); 501315333Serj hic.cmd.hdr.cmd = FW_PHY_ACT_REQ_CMD; 502315333Serj hic.cmd.hdr.buf_len = FW_PHY_ACT_REQ_LEN; 503315333Serj hic.cmd.hdr.checksum = FW_DEFAULT_CHECKSUM; 504315333Serj hic.cmd.port_number = hw->bus.lan_id; 505315333Serj hic.cmd.activity_id = IXGBE_CPU_TO_LE16(activity); 506315333Serj for (i = 0; i < FW_PHY_ACT_DATA_COUNT; ++i) 507315333Serj hic.cmd.data[i] = IXGBE_CPU_TO_BE32((*data)[i]); 508315333Serj 509315333Serj rc = ixgbe_host_interface_command(hw, (u32 *)&hic.cmd, 510315333Serj sizeof(hic.cmd), 511315333Serj IXGBE_HI_COMMAND_TIMEOUT, 512315333Serj TRUE); 513315333Serj if (rc != IXGBE_SUCCESS) 514315333Serj return rc; 515315333Serj if (hic.rsp.hdr.cmd_or_resp.ret_status == 516315333Serj FW_CEM_RESP_STATUS_SUCCESS) { 517315333Serj for (i = 0; i < FW_PHY_ACT_DATA_COUNT; ++i) 518315333Serj (*data)[i] = IXGBE_BE32_TO_CPU(hic.rsp.data[i]); 519315333Serj return IXGBE_SUCCESS; 520315333Serj } 521315333Serj usec_delay(20); 522315333Serj --retries; 523315333Serj } while (retries > 0); 524315333Serj 525315333Serj return IXGBE_ERR_HOST_INTERFACE_COMMAND; 526315333Serj} 527315333Serj 528315333Serjstatic const struct { 529315333Serj u16 fw_speed; 530315333Serj ixgbe_link_speed phy_speed; 531315333Serj} ixgbe_fw_map[] = { 532315333Serj { FW_PHY_ACT_LINK_SPEED_10, IXGBE_LINK_SPEED_10_FULL }, 533315333Serj { FW_PHY_ACT_LINK_SPEED_100, IXGBE_LINK_SPEED_100_FULL }, 534315333Serj { FW_PHY_ACT_LINK_SPEED_1G, IXGBE_LINK_SPEED_1GB_FULL }, 535315333Serj { FW_PHY_ACT_LINK_SPEED_2_5G, IXGBE_LINK_SPEED_2_5GB_FULL }, 536315333Serj { FW_PHY_ACT_LINK_SPEED_5G, IXGBE_LINK_SPEED_5GB_FULL }, 537315333Serj { FW_PHY_ACT_LINK_SPEED_10G, IXGBE_LINK_SPEED_10GB_FULL }, 538315333Serj}; 539315333Serj 540315333Serj/** 541315333Serj * ixgbe_get_phy_id_fw - Get the phy ID via firmware command 542315333Serj * @hw: pointer to hardware structure 543315333Serj * 544315333Serj * Returns error code 545315333Serj */ 546315333Serjstatic s32 ixgbe_get_phy_id_fw(struct ixgbe_hw *hw) 547315333Serj{ 548315333Serj u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 }; 549315333Serj u16 phy_speeds; 550315333Serj u16 phy_id_lo; 551315333Serj s32 rc; 552315333Serj u16 i; 553315333Serj 554315333Serj rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_PHY_INFO, &info); 555315333Serj if (rc) 556315333Serj return rc; 557315333Serj 558315333Serj hw->phy.speeds_supported = 0; 559315333Serj phy_speeds = info[0] & FW_PHY_INFO_SPEED_MASK; 560315333Serj for (i = 0; i < sizeof(ixgbe_fw_map) / sizeof(ixgbe_fw_map[0]); ++i) { 561315333Serj if (phy_speeds & ixgbe_fw_map[i].fw_speed) 562315333Serj hw->phy.speeds_supported |= ixgbe_fw_map[i].phy_speed; 563315333Serj } 564315333Serj if (!hw->phy.autoneg_advertised) 565315333Serj hw->phy.autoneg_advertised = hw->phy.speeds_supported; 566315333Serj 567315333Serj hw->phy.id = info[0] & FW_PHY_INFO_ID_HI_MASK; 568315333Serj phy_id_lo = info[1] & FW_PHY_INFO_ID_LO_MASK; 569315333Serj hw->phy.id |= phy_id_lo & IXGBE_PHY_REVISION_MASK; 570315333Serj hw->phy.revision = phy_id_lo & ~IXGBE_PHY_REVISION_MASK; 571315333Serj if (!hw->phy.id || hw->phy.id == IXGBE_PHY_REVISION_MASK) 572315333Serj return IXGBE_ERR_PHY_ADDR_INVALID; 573315333Serj return IXGBE_SUCCESS; 574315333Serj} 575315333Serj 576315333Serj/** 577315333Serj * ixgbe_identify_phy_fw - Get PHY type based on firmware command 578315333Serj * @hw: pointer to hardware structure 579315333Serj * 580315333Serj * Returns error code 581315333Serj */ 582315333Serjstatic s32 ixgbe_identify_phy_fw(struct ixgbe_hw *hw) 583315333Serj{ 584315333Serj if (hw->bus.lan_id) 585315333Serj hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY1_SM; 586315333Serj else 587315333Serj hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM; 588315333Serj 589315333Serj hw->phy.type = ixgbe_phy_fw; 590315333Serj hw->phy.ops.read_reg = NULL; 591315333Serj hw->phy.ops.write_reg = NULL; 592315333Serj return ixgbe_get_phy_id_fw(hw); 593315333Serj} 594315333Serj 595315333Serj/** 596315333Serj * ixgbe_shutdown_fw_phy - Shutdown a firmware-controlled PHY 597315333Serj * @hw: pointer to hardware structure 598315333Serj * 599315333Serj * Returns error code 600315333Serj */ 601315333Serjs32 ixgbe_shutdown_fw_phy(struct ixgbe_hw *hw) 602315333Serj{ 603315333Serj u32 setup[FW_PHY_ACT_DATA_COUNT] = { 0 }; 604315333Serj 605315333Serj setup[0] = FW_PHY_ACT_FORCE_LINK_DOWN_OFF; 606315333Serj return ixgbe_fw_phy_activity(hw, FW_PHY_ACT_FORCE_LINK_DOWN, &setup); 607315333Serj} 608315333Serj 609282289Serjstatic s32 ixgbe_read_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, 610282289Serj u32 device_type, u16 *phy_data) 611282289Serj{ 612282289Serj UNREFERENCED_4PARAMETER(*hw, reg_addr, device_type, *phy_data); 613282289Serj return IXGBE_NOT_IMPLEMENTED; 614282289Serj} 615282289Serj 616282289Serjstatic s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, 617282289Serj u32 device_type, u16 phy_data) 618282289Serj{ 619282289Serj UNREFERENCED_4PARAMETER(*hw, reg_addr, device_type, phy_data); 620282289Serj return IXGBE_NOT_IMPLEMENTED; 621282289Serj} 622282289Serj 623282289Serj/** 624315333Serj * ixgbe_read_i2c_combined_generic - Perform I2C read combined operation 625315333Serj * @hw: pointer to the hardware structure 626315333Serj * @addr: I2C bus address to read from 627315333Serj * @reg: I2C device register to read from 628315333Serj * @val: pointer to location to receive read value 629315333Serj * 630315333Serj * Returns an error code on error. 631315333Serj **/ 632315333Serjstatic s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, 633315333Serj u16 reg, u16 *val) 634315333Serj{ 635315333Serj return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, TRUE); 636315333Serj} 637315333Serj 638315333Serj/** 639315333Serj * ixgbe_read_i2c_combined_generic_unlocked - Do I2C read combined operation 640315333Serj * @hw: pointer to the hardware structure 641315333Serj * @addr: I2C bus address to read from 642315333Serj * @reg: I2C device register to read from 643315333Serj * @val: pointer to location to receive read value 644315333Serj * 645315333Serj * Returns an error code on error. 646315333Serj **/ 647315333Serjstatic s32 648315333Serjixgbe_read_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, u8 addr, 649315333Serj u16 reg, u16 *val) 650315333Serj{ 651315333Serj return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, FALSE); 652315333Serj} 653315333Serj 654315333Serj/** 655315333Serj * ixgbe_write_i2c_combined_generic - Perform I2C write combined operation 656315333Serj * @hw: pointer to the hardware structure 657315333Serj * @addr: I2C bus address to write to 658315333Serj * @reg: I2C device register to write to 659315333Serj * @val: value to write 660315333Serj * 661315333Serj * Returns an error code on error. 662315333Serj **/ 663315333Serjstatic s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, 664315333Serj u8 addr, u16 reg, u16 val) 665315333Serj{ 666315333Serj return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, TRUE); 667315333Serj} 668315333Serj 669315333Serj/** 670315333Serj * ixgbe_write_i2c_combined_generic_unlocked - Do I2C write combined operation 671315333Serj * @hw: pointer to the hardware structure 672315333Serj * @addr: I2C bus address to write to 673315333Serj * @reg: I2C device register to write to 674315333Serj * @val: value to write 675315333Serj * 676315333Serj * Returns an error code on error. 677315333Serj **/ 678315333Serjstatic s32 679315333Serjixgbe_write_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, 680315333Serj u8 addr, u16 reg, u16 val) 681315333Serj{ 682315333Serj return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, FALSE); 683315333Serj} 684315333Serj 685315333Serj/** 686282289Serj* ixgbe_init_ops_X550EM - Inits func ptrs and MAC type 687282289Serj* @hw: pointer to hardware structure 688282289Serj* 689282289Serj* Initialize the function pointers and for MAC type X550EM. 690282289Serj* Does not touch the hardware. 691282289Serj**/ 692282289Serjs32 ixgbe_init_ops_X550EM(struct ixgbe_hw *hw) 693282289Serj{ 694282289Serj struct ixgbe_mac_info *mac = &hw->mac; 695282289Serj struct ixgbe_eeprom_info *eeprom = &hw->eeprom; 696282289Serj struct ixgbe_phy_info *phy = &hw->phy; 697282289Serj s32 ret_val; 698282289Serj 699282289Serj DEBUGFUNC("ixgbe_init_ops_X550EM"); 700282289Serj 701282289Serj /* Similar to X550 so start there. */ 702282289Serj ret_val = ixgbe_init_ops_X550(hw); 703282289Serj 704282289Serj /* Since this function eventually calls 705282289Serj * ixgbe_init_ops_540 by design, we are setting 706282289Serj * the pointers to NULL explicitly here to overwrite 707282289Serj * the values being set in the x540 function. 708282289Serj */ 709282289Serj 710315333Serj /* Bypass not supported in x550EM */ 711315333Serj mac->ops.bypass_rw = NULL; 712315333Serj mac->ops.bypass_valid_rd = NULL; 713315333Serj mac->ops.bypass_set = NULL; 714315333Serj mac->ops.bypass_rd_eep = NULL; 715315333Serj 716282289Serj /* FCOE not supported in x550EM */ 717282289Serj mac->ops.get_san_mac_addr = NULL; 718282289Serj mac->ops.set_san_mac_addr = NULL; 719282289Serj mac->ops.get_wwn_prefix = NULL; 720282289Serj mac->ops.get_fcoe_boot_status = NULL; 721282289Serj 722282289Serj /* IPsec not supported in x550EM */ 723282289Serj mac->ops.disable_sec_rx_path = NULL; 724282289Serj mac->ops.enable_sec_rx_path = NULL; 725282289Serj 726282289Serj /* AUTOC register is not present in x550EM. */ 727282289Serj mac->ops.prot_autoc_read = NULL; 728282289Serj mac->ops.prot_autoc_write = NULL; 729282289Serj 730282289Serj /* X550EM bus type is internal*/ 731282289Serj hw->bus.type = ixgbe_bus_type_internal; 732282289Serj mac->ops.get_bus_info = ixgbe_get_bus_info_X550em; 733282289Serj 734295524Ssbruno 735282289Serj mac->ops.get_media_type = ixgbe_get_media_type_X550em; 736282289Serj mac->ops.setup_sfp = ixgbe_setup_sfp_modules_X550em; 737282289Serj mac->ops.get_link_capabilities = ixgbe_get_link_capabilities_X550em; 738282289Serj mac->ops.reset_hw = ixgbe_reset_hw_X550em; 739282289Serj mac->ops.get_supported_physical_layer = 740282289Serj ixgbe_get_supported_physical_layer_X550em; 741282289Serj 742282289Serj if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) 743282289Serj mac->ops.setup_fc = ixgbe_setup_fc_generic; 744282289Serj else 745282289Serj mac->ops.setup_fc = ixgbe_setup_fc_X550em; 746282289Serj 747282289Serj /* PHY */ 748282289Serj phy->ops.init = ixgbe_init_phy_ops_X550em; 749315333Serj switch (hw->device_id) { 750315333Serj case IXGBE_DEV_ID_X550EM_A_1G_T: 751315333Serj case IXGBE_DEV_ID_X550EM_A_1G_T_L: 752315333Serj mac->ops.setup_fc = NULL; 753315333Serj phy->ops.identify = ixgbe_identify_phy_fw; 754315333Serj phy->ops.set_phy_power = NULL; 755315333Serj phy->ops.get_firmware_version = NULL; 756315333Serj break; 757315333Serj default: 758315333Serj phy->ops.identify = ixgbe_identify_phy_x550em; 759315333Serj } 760315333Serj 761282289Serj if (mac->ops.get_media_type(hw) != ixgbe_media_type_copper) 762282289Serj phy->ops.set_phy_power = NULL; 763282289Serj 764282289Serj 765282289Serj /* EEPROM */ 766282289Serj eeprom->ops.init_params = ixgbe_init_eeprom_params_X540; 767282289Serj eeprom->ops.read = ixgbe_read_ee_hostif_X550; 768282289Serj eeprom->ops.read_buffer = ixgbe_read_ee_hostif_buffer_X550; 769282289Serj eeprom->ops.write = ixgbe_write_ee_hostif_X550; 770282289Serj eeprom->ops.write_buffer = ixgbe_write_ee_hostif_buffer_X550; 771282289Serj eeprom->ops.update_checksum = ixgbe_update_eeprom_checksum_X550; 772282289Serj eeprom->ops.validate_checksum = ixgbe_validate_eeprom_checksum_X550; 773282289Serj eeprom->ops.calc_checksum = ixgbe_calc_eeprom_checksum_X550; 774282289Serj 775282289Serj return ret_val; 776282289Serj} 777282289Serj 778282289Serj/** 779315333Serj * ixgbe_setup_fw_link - Setup firmware-controlled PHYs 780315333Serj * @hw: pointer to hardware structure 781315333Serj */ 782315333Serjstatic s32 ixgbe_setup_fw_link(struct ixgbe_hw *hw) 783315333Serj{ 784315333Serj u32 setup[FW_PHY_ACT_DATA_COUNT] = { 0 }; 785315333Serj s32 rc; 786315333Serj u16 i; 787315333Serj 788315333Serj if (hw->phy.reset_disable || ixgbe_check_reset_blocked(hw)) 789315333Serj return 0; 790315333Serj 791315333Serj if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { 792315333Serj ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED, 793315333Serj "ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); 794315333Serj return IXGBE_ERR_INVALID_LINK_SETTINGS; 795315333Serj } 796315333Serj 797315333Serj switch (hw->fc.requested_mode) { 798315333Serj case ixgbe_fc_full: 799315333Serj setup[0] |= FW_PHY_ACT_SETUP_LINK_PAUSE_RXTX << 800315333Serj FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT; 801315333Serj break; 802315333Serj case ixgbe_fc_rx_pause: 803315333Serj setup[0] |= FW_PHY_ACT_SETUP_LINK_PAUSE_RX << 804315333Serj FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT; 805315333Serj break; 806315333Serj case ixgbe_fc_tx_pause: 807315333Serj setup[0] |= FW_PHY_ACT_SETUP_LINK_PAUSE_TX << 808315333Serj FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT; 809315333Serj break; 810315333Serj default: 811315333Serj break; 812315333Serj } 813315333Serj 814315333Serj for (i = 0; i < sizeof(ixgbe_fw_map) / sizeof(ixgbe_fw_map[0]); ++i) { 815315333Serj if (hw->phy.autoneg_advertised & ixgbe_fw_map[i].phy_speed) 816315333Serj setup[0] |= ixgbe_fw_map[i].fw_speed; 817315333Serj } 818315333Serj setup[0] |= FW_PHY_ACT_SETUP_LINK_HP | FW_PHY_ACT_SETUP_LINK_AN; 819315333Serj 820315333Serj if (hw->phy.eee_speeds_advertised) 821315333Serj setup[0] |= FW_PHY_ACT_SETUP_LINK_EEE; 822315333Serj 823315333Serj rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_SETUP_LINK, &setup); 824315333Serj if (rc) 825315333Serj return rc; 826315333Serj if (setup[0] == FW_PHY_ACT_SETUP_LINK_RSP_DOWN) 827315333Serj return IXGBE_ERR_OVERTEMP; 828315333Serj return IXGBE_SUCCESS; 829315333Serj} 830315333Serj 831315333Serj/** 832315333Serj * ixgbe_fc_autoneg_fw _ Set up flow control for FW-controlled PHYs 833315333Serj * @hw: pointer to hardware structure 834315333Serj * 835315333Serj * Called at init time to set up flow control. 836315333Serj */ 837315333Serjstatic s32 ixgbe_fc_autoneg_fw(struct ixgbe_hw *hw) 838315333Serj{ 839315333Serj if (hw->fc.requested_mode == ixgbe_fc_default) 840315333Serj hw->fc.requested_mode = ixgbe_fc_full; 841315333Serj 842315333Serj return ixgbe_setup_fw_link(hw); 843315333Serj} 844315333Serj 845315333Serj/** 846315333Serj * ixgbe_setup_eee_fw - Enable/disable EEE support 847315333Serj * @hw: pointer to the HW structure 848315333Serj * @enable_eee: boolean flag to enable EEE 849315333Serj * 850315333Serj * Enable/disable EEE based on enable_eee flag. 851315333Serj * This function controls EEE for firmware-based PHY implementations. 852315333Serj */ 853315333Serjstatic s32 ixgbe_setup_eee_fw(struct ixgbe_hw *hw, bool enable_eee) 854315333Serj{ 855315333Serj if (!!hw->phy.eee_speeds_advertised == enable_eee) 856315333Serj return IXGBE_SUCCESS; 857315333Serj if (enable_eee) 858315333Serj hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported; 859315333Serj else 860315333Serj hw->phy.eee_speeds_advertised = 0; 861315333Serj return hw->phy.ops.setup_link(hw); 862315333Serj} 863315333Serj 864315333Serj/** 865315333Serj* ixgbe_init_ops_X550EM_a - Inits func ptrs and MAC type 866315333Serj* @hw: pointer to hardware structure 867315333Serj* 868315333Serj* Initialize the function pointers and for MAC type X550EM_a. 869315333Serj* Does not touch the hardware. 870315333Serj**/ 871315333Serjs32 ixgbe_init_ops_X550EM_a(struct ixgbe_hw *hw) 872315333Serj{ 873315333Serj struct ixgbe_mac_info *mac = &hw->mac; 874315333Serj s32 ret_val; 875315333Serj 876315333Serj DEBUGFUNC("ixgbe_init_ops_X550EM_a"); 877315333Serj 878315333Serj /* Start with generic X550EM init */ 879315333Serj ret_val = ixgbe_init_ops_X550EM(hw); 880315333Serj 881315333Serj if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII || 882315333Serj hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII_L) { 883315333Serj mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550; 884315333Serj mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550; 885315333Serj } else { 886315333Serj mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550a; 887315333Serj mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550a; 888315333Serj } 889315333Serj mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550a; 890315333Serj mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550a; 891315333Serj 892315333Serj switch (mac->ops.get_media_type(hw)) { 893315333Serj case ixgbe_media_type_fiber: 894315333Serj mac->ops.setup_fc = NULL; 895315333Serj mac->ops.fc_autoneg = ixgbe_fc_autoneg_fiber_x550em_a; 896315333Serj break; 897315333Serj case ixgbe_media_type_backplane: 898315333Serj mac->ops.fc_autoneg = ixgbe_fc_autoneg_backplane_x550em_a; 899315333Serj mac->ops.setup_fc = ixgbe_setup_fc_backplane_x550em_a; 900315333Serj break; 901315333Serj default: 902315333Serj break; 903315333Serj } 904315333Serj 905315333Serj switch (hw->device_id) { 906315333Serj case IXGBE_DEV_ID_X550EM_A_1G_T: 907315333Serj case IXGBE_DEV_ID_X550EM_A_1G_T_L: 908315333Serj mac->ops.fc_autoneg = ixgbe_fc_autoneg_sgmii_x550em_a; 909315333Serj mac->ops.setup_fc = ixgbe_fc_autoneg_fw; 910315333Serj mac->ops.setup_eee = ixgbe_setup_eee_fw; 911315333Serj hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_100_FULL | 912315333Serj IXGBE_LINK_SPEED_1GB_FULL; 913315333Serj hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported; 914315333Serj break; 915315333Serj default: 916315333Serj break; 917315333Serj } 918315333Serj 919315333Serj return ret_val; 920315333Serj} 921315333Serj 922315333Serj/** 923315333Serj* ixgbe_init_ops_X550EM_x - Inits func ptrs and MAC type 924315333Serj* @hw: pointer to hardware structure 925315333Serj* 926315333Serj* Initialize the function pointers and for MAC type X550EM_x. 927315333Serj* Does not touch the hardware. 928315333Serj**/ 929315333Serjs32 ixgbe_init_ops_X550EM_x(struct ixgbe_hw *hw) 930315333Serj{ 931315333Serj struct ixgbe_mac_info *mac = &hw->mac; 932315333Serj struct ixgbe_link_info *link = &hw->link; 933315333Serj s32 ret_val; 934315333Serj 935315333Serj DEBUGFUNC("ixgbe_init_ops_X550EM_x"); 936315333Serj 937315333Serj /* Start with generic X550EM init */ 938315333Serj ret_val = ixgbe_init_ops_X550EM(hw); 939315333Serj 940315333Serj mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550; 941315333Serj mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550; 942315333Serj mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550em; 943315333Serj mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550em; 944315333Serj link->ops.read_link = ixgbe_read_i2c_combined_generic; 945315333Serj link->ops.read_link_unlocked = ixgbe_read_i2c_combined_generic_unlocked; 946315333Serj link->ops.write_link = ixgbe_write_i2c_combined_generic; 947315333Serj link->ops.write_link_unlocked = 948315333Serj ixgbe_write_i2c_combined_generic_unlocked; 949315333Serj link->addr = IXGBE_CS4227; 950315333Serj 951315333Serj 952315333Serj return ret_val; 953315333Serj} 954315333Serj 955315333Serj/** 956282289Serj * ixgbe_dmac_config_X550 957282289Serj * @hw: pointer to hardware structure 958282289Serj * 959282289Serj * Configure DMA coalescing. If enabling dmac, dmac is activated. 960282289Serj * When disabling dmac, dmac enable dmac bit is cleared. 961282289Serj **/ 962282289Serjs32 ixgbe_dmac_config_X550(struct ixgbe_hw *hw) 963282289Serj{ 964282289Serj u32 reg, high_pri_tc; 965282289Serj 966282289Serj DEBUGFUNC("ixgbe_dmac_config_X550"); 967282289Serj 968282289Serj /* Disable DMA coalescing before configuring */ 969282289Serj reg = IXGBE_READ_REG(hw, IXGBE_DMACR); 970282289Serj reg &= ~IXGBE_DMACR_DMAC_EN; 971282289Serj IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg); 972282289Serj 973282289Serj /* Disable DMA Coalescing if the watchdog timer is 0 */ 974282289Serj if (!hw->mac.dmac_config.watchdog_timer) 975282289Serj goto out; 976282289Serj 977282289Serj ixgbe_dmac_config_tcs_X550(hw); 978282289Serj 979282289Serj /* Configure DMA Coalescing Control Register */ 980282289Serj reg = IXGBE_READ_REG(hw, IXGBE_DMACR); 981282289Serj 982282289Serj /* Set the watchdog timer in units of 40.96 usec */ 983282289Serj reg &= ~IXGBE_DMACR_DMACWT_MASK; 984282289Serj reg |= (hw->mac.dmac_config.watchdog_timer * 100) / 4096; 985282289Serj 986282289Serj reg &= ~IXGBE_DMACR_HIGH_PRI_TC_MASK; 987282289Serj /* If fcoe is enabled, set high priority traffic class */ 988282289Serj if (hw->mac.dmac_config.fcoe_en) { 989282289Serj high_pri_tc = 1 << hw->mac.dmac_config.fcoe_tc; 990282289Serj reg |= ((high_pri_tc << IXGBE_DMACR_HIGH_PRI_TC_SHIFT) & 991282289Serj IXGBE_DMACR_HIGH_PRI_TC_MASK); 992282289Serj } 993282289Serj reg |= IXGBE_DMACR_EN_MNG_IND; 994282289Serj 995282289Serj /* Enable DMA coalescing after configuration */ 996282289Serj reg |= IXGBE_DMACR_DMAC_EN; 997282289Serj IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg); 998282289Serj 999282289Serjout: 1000282289Serj return IXGBE_SUCCESS; 1001282289Serj} 1002282289Serj 1003282289Serj/** 1004282289Serj * ixgbe_dmac_config_tcs_X550 1005282289Serj * @hw: pointer to hardware structure 1006282289Serj * 1007282289Serj * Configure DMA coalescing threshold per TC. The dmac enable bit must 1008282289Serj * be cleared before configuring. 1009282289Serj **/ 1010282289Serjs32 ixgbe_dmac_config_tcs_X550(struct ixgbe_hw *hw) 1011282289Serj{ 1012282289Serj u32 tc, reg, pb_headroom, rx_pb_size, maxframe_size_kb; 1013282289Serj 1014282289Serj DEBUGFUNC("ixgbe_dmac_config_tcs_X550"); 1015282289Serj 1016282289Serj /* Configure DMA coalescing enabled */ 1017282289Serj switch (hw->mac.dmac_config.link_speed) { 1018315333Serj case IXGBE_LINK_SPEED_10_FULL: 1019282289Serj case IXGBE_LINK_SPEED_100_FULL: 1020282289Serj pb_headroom = IXGBE_DMACRXT_100M; 1021282289Serj break; 1022282289Serj case IXGBE_LINK_SPEED_1GB_FULL: 1023282289Serj pb_headroom = IXGBE_DMACRXT_1G; 1024282289Serj break; 1025282289Serj default: 1026282289Serj pb_headroom = IXGBE_DMACRXT_10G; 1027282289Serj break; 1028282289Serj } 1029282289Serj 1030282289Serj maxframe_size_kb = ((IXGBE_READ_REG(hw, IXGBE_MAXFRS) >> 1031282289Serj IXGBE_MHADD_MFS_SHIFT) / 1024); 1032282289Serj 1033282289Serj /* Set the per Rx packet buffer receive threshold */ 1034282289Serj for (tc = 0; tc < IXGBE_DCB_MAX_TRAFFIC_CLASS; tc++) { 1035282289Serj reg = IXGBE_READ_REG(hw, IXGBE_DMCTH(tc)); 1036282289Serj reg &= ~IXGBE_DMCTH_DMACRXT_MASK; 1037282289Serj 1038282289Serj if (tc < hw->mac.dmac_config.num_tcs) { 1039282289Serj /* Get Rx PB size */ 1040282289Serj rx_pb_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(tc)); 1041282289Serj rx_pb_size = (rx_pb_size & IXGBE_RXPBSIZE_MASK) >> 1042282289Serj IXGBE_RXPBSIZE_SHIFT; 1043282289Serj 1044282289Serj /* Calculate receive buffer threshold in kilobytes */ 1045282289Serj if (rx_pb_size > pb_headroom) 1046282289Serj rx_pb_size = rx_pb_size - pb_headroom; 1047282289Serj else 1048282289Serj rx_pb_size = 0; 1049282289Serj 1050282289Serj /* Minimum of MFS shall be set for DMCTH */ 1051282289Serj reg |= (rx_pb_size > maxframe_size_kb) ? 1052282289Serj rx_pb_size : maxframe_size_kb; 1053282289Serj } 1054282289Serj IXGBE_WRITE_REG(hw, IXGBE_DMCTH(tc), reg); 1055282289Serj } 1056282289Serj return IXGBE_SUCCESS; 1057282289Serj} 1058282289Serj 1059282289Serj/** 1060282289Serj * ixgbe_dmac_update_tcs_X550 1061282289Serj * @hw: pointer to hardware structure 1062282289Serj * 1063282289Serj * Disables dmac, updates per TC settings, and then enables dmac. 1064282289Serj **/ 1065282289Serjs32 ixgbe_dmac_update_tcs_X550(struct ixgbe_hw *hw) 1066282289Serj{ 1067282289Serj u32 reg; 1068282289Serj 1069282289Serj DEBUGFUNC("ixgbe_dmac_update_tcs_X550"); 1070282289Serj 1071282289Serj /* Disable DMA coalescing before configuring */ 1072282289Serj reg = IXGBE_READ_REG(hw, IXGBE_DMACR); 1073282289Serj reg &= ~IXGBE_DMACR_DMAC_EN; 1074282289Serj IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg); 1075282289Serj 1076282289Serj ixgbe_dmac_config_tcs_X550(hw); 1077282289Serj 1078282289Serj /* Enable DMA coalescing after configuration */ 1079282289Serj reg = IXGBE_READ_REG(hw, IXGBE_DMACR); 1080282289Serj reg |= IXGBE_DMACR_DMAC_EN; 1081282289Serj IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg); 1082282289Serj 1083282289Serj return IXGBE_SUCCESS; 1084282289Serj} 1085282289Serj 1086282289Serj/** 1087282289Serj * ixgbe_init_eeprom_params_X550 - Initialize EEPROM params 1088282289Serj * @hw: pointer to hardware structure 1089282289Serj * 1090282289Serj * Initializes the EEPROM parameters ixgbe_eeprom_info within the 1091282289Serj * ixgbe_hw struct in order to set up EEPROM access. 1092282289Serj **/ 1093282289Serjs32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw) 1094282289Serj{ 1095282289Serj struct ixgbe_eeprom_info *eeprom = &hw->eeprom; 1096282289Serj u32 eec; 1097282289Serj u16 eeprom_size; 1098282289Serj 1099282289Serj DEBUGFUNC("ixgbe_init_eeprom_params_X550"); 1100282289Serj 1101282289Serj if (eeprom->type == ixgbe_eeprom_uninitialized) { 1102282289Serj eeprom->semaphore_delay = 10; 1103282289Serj eeprom->type = ixgbe_flash; 1104282289Serj 1105282289Serj eec = IXGBE_READ_REG(hw, IXGBE_EEC); 1106282289Serj eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >> 1107282289Serj IXGBE_EEC_SIZE_SHIFT); 1108282289Serj eeprom->word_size = 1 << (eeprom_size + 1109282289Serj IXGBE_EEPROM_WORD_SIZE_SHIFT); 1110282289Serj 1111282289Serj DEBUGOUT2("Eeprom params: type = %d, size = %d\n", 1112282289Serj eeprom->type, eeprom->word_size); 1113282289Serj } 1114282289Serj 1115282289Serj return IXGBE_SUCCESS; 1116282289Serj} 1117282289Serj 1118282289Serj/** 1119282289Serj * ixgbe_set_source_address_pruning_X550 - Enable/Disbale source address pruning 1120282289Serj * @hw: pointer to hardware structure 1121282289Serj * @enable: enable or disable source address pruning 1122282289Serj * @pool: Rx pool to set source address pruning for 1123282289Serj **/ 1124282289Serjvoid ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, bool enable, 1125282289Serj unsigned int pool) 1126282289Serj{ 1127282289Serj u64 pfflp; 1128282289Serj 1129282289Serj /* max rx pool is 63 */ 1130282289Serj if (pool > 63) 1131282289Serj return; 1132282289Serj 1133282289Serj pfflp = (u64)IXGBE_READ_REG(hw, IXGBE_PFFLPL); 1134282289Serj pfflp |= (u64)IXGBE_READ_REG(hw, IXGBE_PFFLPH) << 32; 1135282289Serj 1136282289Serj if (enable) 1137282289Serj pfflp |= (1ULL << pool); 1138282289Serj else 1139282289Serj pfflp &= ~(1ULL << pool); 1140282289Serj 1141282289Serj IXGBE_WRITE_REG(hw, IXGBE_PFFLPL, (u32)pfflp); 1142282289Serj IXGBE_WRITE_REG(hw, IXGBE_PFFLPH, (u32)(pfflp >> 32)); 1143282289Serj} 1144282289Serj 1145282289Serj/** 1146282289Serj * ixgbe_set_ethertype_anti_spoofing_X550 - Enable/Disable Ethertype anti-spoofing 1147282289Serj * @hw: pointer to hardware structure 1148282289Serj * @enable: enable or disable switch for Ethertype anti-spoofing 1149282289Serj * @vf: Virtual Function pool - VF Pool to set for Ethertype anti-spoofing 1150282289Serj * 1151282289Serj **/ 1152282289Serjvoid ixgbe_set_ethertype_anti_spoofing_X550(struct ixgbe_hw *hw, 1153282289Serj bool enable, int vf) 1154282289Serj{ 1155282289Serj int vf_target_reg = vf >> 3; 1156282289Serj int vf_target_shift = vf % 8 + IXGBE_SPOOF_ETHERTYPEAS_SHIFT; 1157282289Serj u32 pfvfspoof; 1158282289Serj 1159282289Serj DEBUGFUNC("ixgbe_set_ethertype_anti_spoofing_X550"); 1160282289Serj 1161282289Serj pfvfspoof = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg)); 1162282289Serj if (enable) 1163282289Serj pfvfspoof |= (1 << vf_target_shift); 1164282289Serj else 1165282289Serj pfvfspoof &= ~(1 << vf_target_shift); 1166282289Serj 1167282289Serj IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof); 1168282289Serj} 1169282289Serj 1170282289Serj/** 1171282289Serj * ixgbe_iosf_wait - Wait for IOSF command completion 1172282289Serj * @hw: pointer to hardware structure 1173282289Serj * @ctrl: pointer to location to receive final IOSF control value 1174282289Serj * 1175282289Serj * Returns failing status on timeout 1176282289Serj * 1177282289Serj * Note: ctrl can be NULL if the IOSF control register value is not needed 1178282289Serj **/ 1179282289Serjstatic s32 ixgbe_iosf_wait(struct ixgbe_hw *hw, u32 *ctrl) 1180282289Serj{ 1181295524Ssbruno u32 i, command = 0; 1182282289Serj 1183282289Serj /* Check every 10 usec to see if the address cycle completed. 1184282289Serj * The SB IOSF BUSY bit will clear when the operation is 1185282289Serj * complete 1186282289Serj */ 1187282289Serj for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 1188282289Serj command = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL); 1189282289Serj if ((command & IXGBE_SB_IOSF_CTRL_BUSY) == 0) 1190282289Serj break; 1191282289Serj usec_delay(10); 1192282289Serj } 1193282289Serj if (ctrl) 1194282289Serj *ctrl = command; 1195282289Serj if (i == IXGBE_MDIO_COMMAND_TIMEOUT) { 1196282289Serj ERROR_REPORT1(IXGBE_ERROR_POLLING, "Wait timed out\n"); 1197282289Serj return IXGBE_ERR_PHY; 1198282289Serj } 1199282289Serj 1200282289Serj return IXGBE_SUCCESS; 1201282289Serj} 1202282289Serj 1203282289Serj/** 1204315333Serj * ixgbe_write_iosf_sb_reg_x550 - Writes a value to specified register 1205315333Serj * of the IOSF device 1206282289Serj * @hw: pointer to hardware structure 1207282289Serj * @reg_addr: 32 bit PHY register to write 1208282289Serj * @device_type: 3 bit device type 1209282289Serj * @data: Data to write to the register 1210282289Serj **/ 1211282289Serjs32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, 1212282289Serj u32 device_type, u32 data) 1213282289Serj{ 1214282289Serj u32 gssr = IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_PHY0_SM; 1215282289Serj u32 command, error; 1216282289Serj s32 ret; 1217282289Serj 1218282289Serj ret = ixgbe_acquire_swfw_semaphore(hw, gssr); 1219282289Serj if (ret != IXGBE_SUCCESS) 1220282289Serj return ret; 1221282289Serj 1222282289Serj ret = ixgbe_iosf_wait(hw, NULL); 1223282289Serj if (ret != IXGBE_SUCCESS) 1224282289Serj goto out; 1225282289Serj 1226282289Serj command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) | 1227282289Serj (device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT)); 1228282289Serj 1229282289Serj /* Write IOSF control register */ 1230282289Serj IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command); 1231282289Serj 1232282289Serj /* Write IOSF data register */ 1233282289Serj IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA, data); 1234282289Serj 1235282289Serj ret = ixgbe_iosf_wait(hw, &command); 1236282289Serj 1237282289Serj if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) { 1238282289Serj error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >> 1239282289Serj IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT; 1240282289Serj ERROR_REPORT2(IXGBE_ERROR_POLLING, 1241282289Serj "Failed to write, error %x\n", error); 1242282289Serj ret = IXGBE_ERR_PHY; 1243282289Serj } 1244282289Serj 1245282289Serjout: 1246282289Serj ixgbe_release_swfw_semaphore(hw, gssr); 1247282289Serj return ret; 1248282289Serj} 1249282289Serj 1250282289Serj/** 1251315333Serj * ixgbe_read_iosf_sb_reg_x550 - Reads specified register of the IOSF device 1252282289Serj * @hw: pointer to hardware structure 1253282289Serj * @reg_addr: 32 bit PHY register to write 1254282289Serj * @device_type: 3 bit device type 1255315333Serj * @data: Pointer to read data from the register 1256282289Serj **/ 1257282289Serjs32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, 1258282289Serj u32 device_type, u32 *data) 1259282289Serj{ 1260282289Serj u32 gssr = IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_PHY0_SM; 1261282289Serj u32 command, error; 1262282289Serj s32 ret; 1263282289Serj 1264282289Serj ret = ixgbe_acquire_swfw_semaphore(hw, gssr); 1265282289Serj if (ret != IXGBE_SUCCESS) 1266282289Serj return ret; 1267282289Serj 1268282289Serj ret = ixgbe_iosf_wait(hw, NULL); 1269282289Serj if (ret != IXGBE_SUCCESS) 1270282289Serj goto out; 1271282289Serj 1272282289Serj command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) | 1273282289Serj (device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT)); 1274282289Serj 1275282289Serj /* Write IOSF control register */ 1276282289Serj IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command); 1277282289Serj 1278282289Serj ret = ixgbe_iosf_wait(hw, &command); 1279282289Serj 1280282289Serj if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) { 1281282289Serj error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >> 1282282289Serj IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT; 1283282289Serj ERROR_REPORT2(IXGBE_ERROR_POLLING, 1284282289Serj "Failed to read, error %x\n", error); 1285282289Serj ret = IXGBE_ERR_PHY; 1286282289Serj } 1287282289Serj 1288282289Serj if (ret == IXGBE_SUCCESS) 1289282289Serj *data = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA); 1290282289Serj 1291282289Serjout: 1292282289Serj ixgbe_release_swfw_semaphore(hw, gssr); 1293282289Serj return ret; 1294282289Serj} 1295282289Serj 1296282289Serj/** 1297315333Serj * ixgbe_get_phy_token - Get the token for shared phy access 1298315333Serj * @hw: Pointer to hardware structure 1299315333Serj */ 1300315333Serj 1301315333Serjs32 ixgbe_get_phy_token(struct ixgbe_hw *hw) 1302315333Serj{ 1303315333Serj struct ixgbe_hic_phy_token_req token_cmd; 1304315333Serj s32 status; 1305315333Serj 1306315333Serj token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD; 1307315333Serj token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN; 1308315333Serj token_cmd.hdr.cmd_or_resp.cmd_resv = 0; 1309315333Serj token_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM; 1310315333Serj token_cmd.port_number = hw->bus.lan_id; 1311315333Serj token_cmd.command_type = FW_PHY_TOKEN_REQ; 1312315333Serj token_cmd.pad = 0; 1313315333Serj status = ixgbe_host_interface_command(hw, (u32 *)&token_cmd, 1314315333Serj sizeof(token_cmd), 1315315333Serj IXGBE_HI_COMMAND_TIMEOUT, 1316315333Serj TRUE); 1317315333Serj if (status) { 1318315333Serj DEBUGOUT1("Issuing host interface command failed with Status = %d\n", 1319315333Serj status); 1320315333Serj return status; 1321315333Serj } 1322315333Serj if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK) 1323315333Serj return IXGBE_SUCCESS; 1324315333Serj if (token_cmd.hdr.cmd_or_resp.ret_status != FW_PHY_TOKEN_RETRY) { 1325315333Serj DEBUGOUT1("Host interface command returned 0x%08x , returning IXGBE_ERR_FW_RESP_INVALID\n", 1326315333Serj token_cmd.hdr.cmd_or_resp.ret_status); 1327315333Serj return IXGBE_ERR_FW_RESP_INVALID; 1328315333Serj } 1329315333Serj 1330315333Serj DEBUGOUT("Returning IXGBE_ERR_TOKEN_RETRY\n"); 1331315333Serj return IXGBE_ERR_TOKEN_RETRY; 1332315333Serj} 1333315333Serj 1334315333Serj/** 1335315333Serj * ixgbe_put_phy_token - Put the token for shared phy access 1336315333Serj * @hw: Pointer to hardware structure 1337315333Serj */ 1338315333Serj 1339315333Serjs32 ixgbe_put_phy_token(struct ixgbe_hw *hw) 1340315333Serj{ 1341315333Serj struct ixgbe_hic_phy_token_req token_cmd; 1342315333Serj s32 status; 1343315333Serj 1344315333Serj token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD; 1345315333Serj token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN; 1346315333Serj token_cmd.hdr.cmd_or_resp.cmd_resv = 0; 1347315333Serj token_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM; 1348315333Serj token_cmd.port_number = hw->bus.lan_id; 1349315333Serj token_cmd.command_type = FW_PHY_TOKEN_REL; 1350315333Serj token_cmd.pad = 0; 1351315333Serj status = ixgbe_host_interface_command(hw, (u32 *)&token_cmd, 1352315333Serj sizeof(token_cmd), 1353315333Serj IXGBE_HI_COMMAND_TIMEOUT, 1354315333Serj TRUE); 1355315333Serj if (status) 1356315333Serj return status; 1357315333Serj if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK) 1358315333Serj return IXGBE_SUCCESS; 1359315333Serj 1360315333Serj DEBUGOUT("Put PHY Token host interface command failed"); 1361315333Serj return IXGBE_ERR_FW_RESP_INVALID; 1362315333Serj} 1363315333Serj 1364315333Serj/** 1365315333Serj * ixgbe_write_iosf_sb_reg_x550a - Writes a value to specified register 1366315333Serj * of the IOSF device 1367315333Serj * @hw: pointer to hardware structure 1368315333Serj * @reg_addr: 32 bit PHY register to write 1369315333Serj * @device_type: 3 bit device type 1370315333Serj * @data: Data to write to the register 1371315333Serj **/ 1372315333Serjs32 ixgbe_write_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, 1373315333Serj u32 device_type, u32 data) 1374315333Serj{ 1375315333Serj struct ixgbe_hic_internal_phy_req write_cmd; 1376315333Serj s32 status; 1377315333Serj UNREFERENCED_1PARAMETER(device_type); 1378315333Serj 1379315333Serj memset(&write_cmd, 0, sizeof(write_cmd)); 1380315333Serj write_cmd.hdr.cmd = FW_INT_PHY_REQ_CMD; 1381315333Serj write_cmd.hdr.buf_len = FW_INT_PHY_REQ_LEN; 1382315333Serj write_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM; 1383315333Serj write_cmd.port_number = hw->bus.lan_id; 1384315333Serj write_cmd.command_type = FW_INT_PHY_REQ_WRITE; 1385315333Serj write_cmd.address = IXGBE_CPU_TO_BE16(reg_addr); 1386315333Serj write_cmd.write_data = IXGBE_CPU_TO_BE32(data); 1387315333Serj 1388315333Serj status = ixgbe_host_interface_command(hw, (u32 *)&write_cmd, 1389315333Serj sizeof(write_cmd), 1390315333Serj IXGBE_HI_COMMAND_TIMEOUT, FALSE); 1391315333Serj 1392315333Serj return status; 1393315333Serj} 1394315333Serj 1395315333Serj/** 1396315333Serj * ixgbe_read_iosf_sb_reg_x550a - Reads specified register of the IOSF device 1397315333Serj * @hw: pointer to hardware structure 1398315333Serj * @reg_addr: 32 bit PHY register to write 1399315333Serj * @device_type: 3 bit device type 1400315333Serj * @data: Pointer to read data from the register 1401315333Serj **/ 1402315333Serjs32 ixgbe_read_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, 1403315333Serj u32 device_type, u32 *data) 1404315333Serj{ 1405315333Serj union { 1406315333Serj struct ixgbe_hic_internal_phy_req cmd; 1407315333Serj struct ixgbe_hic_internal_phy_resp rsp; 1408315333Serj } hic; 1409315333Serj s32 status; 1410315333Serj UNREFERENCED_1PARAMETER(device_type); 1411315333Serj 1412315333Serj memset(&hic, 0, sizeof(hic)); 1413315333Serj hic.cmd.hdr.cmd = FW_INT_PHY_REQ_CMD; 1414315333Serj hic.cmd.hdr.buf_len = FW_INT_PHY_REQ_LEN; 1415315333Serj hic.cmd.hdr.checksum = FW_DEFAULT_CHECKSUM; 1416315333Serj hic.cmd.port_number = hw->bus.lan_id; 1417315333Serj hic.cmd.command_type = FW_INT_PHY_REQ_READ; 1418315333Serj hic.cmd.address = IXGBE_CPU_TO_BE16(reg_addr); 1419315333Serj 1420315333Serj status = ixgbe_host_interface_command(hw, (u32 *)&hic.cmd, 1421315333Serj sizeof(hic.cmd), 1422315333Serj IXGBE_HI_COMMAND_TIMEOUT, TRUE); 1423315333Serj 1424315333Serj /* Extract the register value from the response. */ 1425315333Serj *data = IXGBE_BE32_TO_CPU(hic.rsp.read_data); 1426315333Serj 1427315333Serj return status; 1428315333Serj} 1429315333Serj 1430315333Serj/** 1431282289Serj * ixgbe_disable_mdd_X550 1432282289Serj * @hw: pointer to hardware structure 1433282289Serj * 1434282289Serj * Disable malicious driver detection 1435282289Serj **/ 1436282289Serjvoid ixgbe_disable_mdd_X550(struct ixgbe_hw *hw) 1437282289Serj{ 1438282289Serj u32 reg; 1439282289Serj 1440282289Serj DEBUGFUNC("ixgbe_disable_mdd_X550"); 1441282289Serj 1442282289Serj /* Disable MDD for TX DMA and interrupt */ 1443282289Serj reg = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); 1444282289Serj reg &= ~(IXGBE_DMATXCTL_MDP_EN | IXGBE_DMATXCTL_MBINTEN); 1445282289Serj IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg); 1446282289Serj 1447282289Serj /* Disable MDD for RX and interrupt */ 1448282289Serj reg = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); 1449282289Serj reg &= ~(IXGBE_RDRXCTL_MDP_EN | IXGBE_RDRXCTL_MBINTEN); 1450282289Serj IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg); 1451282289Serj} 1452282289Serj 1453282289Serj/** 1454282289Serj * ixgbe_enable_mdd_X550 1455282289Serj * @hw: pointer to hardware structure 1456282289Serj * 1457282289Serj * Enable malicious driver detection 1458282289Serj **/ 1459282289Serjvoid ixgbe_enable_mdd_X550(struct ixgbe_hw *hw) 1460282289Serj{ 1461282289Serj u32 reg; 1462282289Serj 1463282289Serj DEBUGFUNC("ixgbe_enable_mdd_X550"); 1464282289Serj 1465282289Serj /* Enable MDD for TX DMA and interrupt */ 1466282289Serj reg = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); 1467282289Serj reg |= (IXGBE_DMATXCTL_MDP_EN | IXGBE_DMATXCTL_MBINTEN); 1468282289Serj IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg); 1469282289Serj 1470282289Serj /* Enable MDD for RX and interrupt */ 1471282289Serj reg = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); 1472282289Serj reg |= (IXGBE_RDRXCTL_MDP_EN | IXGBE_RDRXCTL_MBINTEN); 1473282289Serj IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg); 1474282289Serj} 1475282289Serj 1476282289Serj/** 1477282289Serj * ixgbe_restore_mdd_vf_X550 1478282289Serj * @hw: pointer to hardware structure 1479282289Serj * @vf: vf index 1480282289Serj * 1481282289Serj * Restore VF that was disabled during malicious driver detection event 1482282289Serj **/ 1483282289Serjvoid ixgbe_restore_mdd_vf_X550(struct ixgbe_hw *hw, u32 vf) 1484282289Serj{ 1485282289Serj u32 idx, reg, num_qs, start_q, bitmask; 1486282289Serj 1487282289Serj DEBUGFUNC("ixgbe_restore_mdd_vf_X550"); 1488282289Serj 1489282289Serj /* Map VF to queues */ 1490282289Serj reg = IXGBE_READ_REG(hw, IXGBE_MRQC); 1491282289Serj switch (reg & IXGBE_MRQC_MRQE_MASK) { 1492282289Serj case IXGBE_MRQC_VMDQRT8TCEN: 1493282289Serj num_qs = 8; /* 16 VFs / pools */ 1494282289Serj bitmask = 0x000000FF; 1495282289Serj break; 1496282289Serj case IXGBE_MRQC_VMDQRSS32EN: 1497282289Serj case IXGBE_MRQC_VMDQRT4TCEN: 1498282289Serj num_qs = 4; /* 32 VFs / pools */ 1499282289Serj bitmask = 0x0000000F; 1500282289Serj break; 1501315333Serj default: /* 64 VFs / pools */ 1502282289Serj num_qs = 2; 1503282289Serj bitmask = 0x00000003; 1504282289Serj break; 1505282289Serj } 1506282289Serj start_q = vf * num_qs; 1507282289Serj 1508282289Serj /* Release vf's queues by clearing WQBR_TX and WQBR_RX (RW1C) */ 1509282289Serj idx = start_q / 32; 1510282289Serj reg = 0; 1511282289Serj reg |= (bitmask << (start_q % 32)); 1512282289Serj IXGBE_WRITE_REG(hw, IXGBE_WQBR_TX(idx), reg); 1513282289Serj IXGBE_WRITE_REG(hw, IXGBE_WQBR_RX(idx), reg); 1514282289Serj} 1515282289Serj 1516282289Serj/** 1517282289Serj * ixgbe_mdd_event_X550 1518282289Serj * @hw: pointer to hardware structure 1519282289Serj * @vf_bitmap: vf bitmap of malicious vfs 1520282289Serj * 1521282289Serj * Handle malicious driver detection event. 1522282289Serj **/ 1523282289Serjvoid ixgbe_mdd_event_X550(struct ixgbe_hw *hw, u32 *vf_bitmap) 1524282289Serj{ 1525282289Serj u32 wqbr; 1526282289Serj u32 i, j, reg, q, shift, vf, idx; 1527282289Serj 1528282289Serj DEBUGFUNC("ixgbe_mdd_event_X550"); 1529282289Serj 1530282289Serj /* figure out pool size for mapping to vf's */ 1531282289Serj reg = IXGBE_READ_REG(hw, IXGBE_MRQC); 1532282289Serj switch (reg & IXGBE_MRQC_MRQE_MASK) { 1533282289Serj case IXGBE_MRQC_VMDQRT8TCEN: 1534282289Serj shift = 3; /* 16 VFs / pools */ 1535282289Serj break; 1536282289Serj case IXGBE_MRQC_VMDQRSS32EN: 1537282289Serj case IXGBE_MRQC_VMDQRT4TCEN: 1538282289Serj shift = 2; /* 32 VFs / pools */ 1539282289Serj break; 1540282289Serj default: 1541282289Serj shift = 1; /* 64 VFs / pools */ 1542282289Serj break; 1543282289Serj } 1544282289Serj 1545282289Serj /* Read WQBR_TX and WQBR_RX and check for malicious queues */ 1546282289Serj for (i = 0; i < 4; i++) { 1547282289Serj wqbr = IXGBE_READ_REG(hw, IXGBE_WQBR_TX(i)); 1548282289Serj wqbr |= IXGBE_READ_REG(hw, IXGBE_WQBR_RX(i)); 1549282289Serj 1550282289Serj if (!wqbr) 1551282289Serj continue; 1552282289Serj 1553282289Serj /* Get malicious queue */ 1554282289Serj for (j = 0; j < 32 && wqbr; j++) { 1555282289Serj 1556282289Serj if (!(wqbr & (1 << j))) 1557282289Serj continue; 1558282289Serj 1559282289Serj /* Get queue from bitmask */ 1560282289Serj q = j + (i * 32); 1561282289Serj 1562282289Serj /* Map queue to vf */ 1563282289Serj vf = (q >> shift); 1564282289Serj 1565282289Serj /* Set vf bit in vf_bitmap */ 1566282289Serj idx = vf / 32; 1567282289Serj vf_bitmap[idx] |= (1 << (vf % 32)); 1568282289Serj wqbr &= ~(1 << j); 1569282289Serj } 1570282289Serj } 1571282289Serj} 1572282289Serj 1573282289Serj/** 1574282289Serj * ixgbe_get_media_type_X550em - Get media type 1575282289Serj * @hw: pointer to hardware structure 1576282289Serj * 1577282289Serj * Returns the media type (fiber, copper, backplane) 1578282289Serj */ 1579282289Serjenum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw) 1580282289Serj{ 1581282289Serj enum ixgbe_media_type media_type; 1582282289Serj 1583282289Serj DEBUGFUNC("ixgbe_get_media_type_X550em"); 1584282289Serj 1585282289Serj /* Detect if there is a copper PHY attached. */ 1586282289Serj switch (hw->device_id) { 1587282289Serj case IXGBE_DEV_ID_X550EM_X_KR: 1588282289Serj case IXGBE_DEV_ID_X550EM_X_KX4: 1589315333Serj case IXGBE_DEV_ID_X550EM_X_XFI: 1590315333Serj case IXGBE_DEV_ID_X550EM_A_KR: 1591315333Serj case IXGBE_DEV_ID_X550EM_A_KR_L: 1592282289Serj media_type = ixgbe_media_type_backplane; 1593282289Serj break; 1594282289Serj case IXGBE_DEV_ID_X550EM_X_SFP: 1595315333Serj case IXGBE_DEV_ID_X550EM_A_SFP: 1596315333Serj case IXGBE_DEV_ID_X550EM_A_SFP_N: 1597315333Serj case IXGBE_DEV_ID_X550EM_A_QSFP: 1598315333Serj case IXGBE_DEV_ID_X550EM_A_QSFP_N: 1599282289Serj media_type = ixgbe_media_type_fiber; 1600282289Serj break; 1601282289Serj case IXGBE_DEV_ID_X550EM_X_1G_T: 1602282289Serj case IXGBE_DEV_ID_X550EM_X_10G_T: 1603315333Serj case IXGBE_DEV_ID_X550EM_A_10G_T: 1604282289Serj media_type = ixgbe_media_type_copper; 1605282289Serj break; 1606315333Serj case IXGBE_DEV_ID_X550EM_A_SGMII: 1607315333Serj case IXGBE_DEV_ID_X550EM_A_SGMII_L: 1608315333Serj media_type = ixgbe_media_type_backplane; 1609315333Serj hw->phy.type = ixgbe_phy_sgmii; 1610315333Serj break; 1611315333Serj case IXGBE_DEV_ID_X550EM_A_1G_T: 1612315333Serj case IXGBE_DEV_ID_X550EM_A_1G_T_L: 1613315333Serj media_type = ixgbe_media_type_copper; 1614315333Serj break; 1615282289Serj default: 1616282289Serj media_type = ixgbe_media_type_unknown; 1617282289Serj break; 1618282289Serj } 1619282289Serj return media_type; 1620282289Serj} 1621282289Serj 1622282289Serj/** 1623282289Serj * ixgbe_supported_sfp_modules_X550em - Check if SFP module type is supported 1624282289Serj * @hw: pointer to hardware structure 1625282289Serj * @linear: TRUE if SFP module is linear 1626282289Serj */ 1627282289Serjstatic s32 ixgbe_supported_sfp_modules_X550em(struct ixgbe_hw *hw, bool *linear) 1628282289Serj{ 1629282289Serj DEBUGFUNC("ixgbe_supported_sfp_modules_X550em"); 1630282289Serj 1631282289Serj switch (hw->phy.sfp_type) { 1632282289Serj case ixgbe_sfp_type_not_present: 1633282289Serj return IXGBE_ERR_SFP_NOT_PRESENT; 1634282289Serj case ixgbe_sfp_type_da_cu_core0: 1635282289Serj case ixgbe_sfp_type_da_cu_core1: 1636282289Serj *linear = TRUE; 1637282289Serj break; 1638282289Serj case ixgbe_sfp_type_srlr_core0: 1639282289Serj case ixgbe_sfp_type_srlr_core1: 1640282289Serj case ixgbe_sfp_type_da_act_lmt_core0: 1641282289Serj case ixgbe_sfp_type_da_act_lmt_core1: 1642282289Serj case ixgbe_sfp_type_1g_sx_core0: 1643282289Serj case ixgbe_sfp_type_1g_sx_core1: 1644282289Serj case ixgbe_sfp_type_1g_lx_core0: 1645282289Serj case ixgbe_sfp_type_1g_lx_core1: 1646282289Serj *linear = FALSE; 1647282289Serj break; 1648282289Serj case ixgbe_sfp_type_unknown: 1649282289Serj case ixgbe_sfp_type_1g_cu_core0: 1650282289Serj case ixgbe_sfp_type_1g_cu_core1: 1651282289Serj default: 1652282289Serj return IXGBE_ERR_SFP_NOT_SUPPORTED; 1653282289Serj } 1654282289Serj 1655282289Serj return IXGBE_SUCCESS; 1656282289Serj} 1657282289Serj 1658282289Serj/** 1659282289Serj * ixgbe_identify_sfp_module_X550em - Identifies SFP modules 1660282289Serj * @hw: pointer to hardware structure 1661282289Serj * 1662282289Serj * Searches for and identifies the SFP module and assigns appropriate PHY type. 1663282289Serj **/ 1664282289Serjs32 ixgbe_identify_sfp_module_X550em(struct ixgbe_hw *hw) 1665282289Serj{ 1666282289Serj s32 status; 1667282289Serj bool linear; 1668282289Serj 1669282289Serj DEBUGFUNC("ixgbe_identify_sfp_module_X550em"); 1670282289Serj 1671282289Serj status = ixgbe_identify_module_generic(hw); 1672282289Serj 1673282289Serj if (status != IXGBE_SUCCESS) 1674282289Serj return status; 1675282289Serj 1676282289Serj /* Check if SFP module is supported */ 1677282289Serj status = ixgbe_supported_sfp_modules_X550em(hw, &linear); 1678282289Serj 1679282289Serj return status; 1680282289Serj} 1681282289Serj 1682282289Serj/** 1683282289Serj * ixgbe_setup_sfp_modules_X550em - Setup MAC link ops 1684282289Serj * @hw: pointer to hardware structure 1685282289Serj */ 1686282289Serjs32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw) 1687282289Serj{ 1688282289Serj s32 status; 1689282289Serj bool linear; 1690282289Serj 1691282289Serj DEBUGFUNC("ixgbe_setup_sfp_modules_X550em"); 1692282289Serj 1693282289Serj /* Check if SFP module is supported */ 1694282289Serj status = ixgbe_supported_sfp_modules_X550em(hw, &linear); 1695282289Serj 1696282289Serj if (status != IXGBE_SUCCESS) 1697282289Serj return status; 1698282289Serj 1699282289Serj ixgbe_init_mac_link_ops_X550em(hw); 1700282289Serj hw->phy.ops.reset = NULL; 1701282289Serj 1702282289Serj return IXGBE_SUCCESS; 1703282289Serj} 1704282289Serj 1705282289Serj/** 1706315333Serj* ixgbe_restart_an_internal_phy_x550em - restart autonegotiation for the 1707315333Serj* internal PHY 1708315333Serj* @hw: pointer to hardware structure 1709315333Serj**/ 1710315333Serjstatic s32 ixgbe_restart_an_internal_phy_x550em(struct ixgbe_hw *hw) 1711315333Serj{ 1712315333Serj s32 status; 1713315333Serj u32 link_ctrl; 1714315333Serj 1715315333Serj /* Restart auto-negotiation. */ 1716315333Serj status = hw->mac.ops.read_iosf_sb_reg(hw, 1717315333Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 1718315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, &link_ctrl); 1719315333Serj 1720315333Serj if (status) { 1721315333Serj DEBUGOUT("Auto-negotiation did not complete\n"); 1722315333Serj return status; 1723315333Serj } 1724315333Serj 1725315333Serj link_ctrl |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART; 1726315333Serj status = hw->mac.ops.write_iosf_sb_reg(hw, 1727315333Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 1728315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, link_ctrl); 1729315333Serj 1730315333Serj if (hw->mac.type == ixgbe_mac_X550EM_a) { 1731315333Serj u32 flx_mask_st20; 1732315333Serj 1733315333Serj /* Indicate to FW that AN restart has been asserted */ 1734315333Serj status = hw->mac.ops.read_iosf_sb_reg(hw, 1735315333Serj IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), 1736315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, &flx_mask_st20); 1737315333Serj 1738315333Serj if (status) { 1739315333Serj DEBUGOUT("Auto-negotiation did not complete\n"); 1740315333Serj return status; 1741315333Serj } 1742315333Serj 1743315333Serj flx_mask_st20 |= IXGBE_KRM_PMD_FLX_MASK_ST20_FW_AN_RESTART; 1744315333Serj status = hw->mac.ops.write_iosf_sb_reg(hw, 1745315333Serj IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), 1746315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, flx_mask_st20); 1747315333Serj } 1748315333Serj 1749315333Serj return status; 1750315333Serj} 1751315333Serj 1752315333Serj/** 1753315333Serj * ixgbe_setup_sgmii - Set up link for sgmii 1754315333Serj * @hw: pointer to hardware structure 1755315333Serj */ 1756315333Serjstatic s32 ixgbe_setup_sgmii(struct ixgbe_hw *hw, ixgbe_link_speed speed, 1757315333Serj bool autoneg_wait) 1758315333Serj{ 1759315333Serj struct ixgbe_mac_info *mac = &hw->mac; 1760315333Serj u32 lval, sval, flx_val; 1761315333Serj s32 rc; 1762315333Serj 1763315333Serj rc = mac->ops.read_iosf_sb_reg(hw, 1764315333Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 1765315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, &lval); 1766315333Serj if (rc) 1767315333Serj return rc; 1768315333Serj 1769315333Serj lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE; 1770315333Serj lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK; 1771315333Serj lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_SGMII_EN; 1772315333Serj lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CLAUSE_37_EN; 1773315333Serj lval |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G; 1774315333Serj rc = mac->ops.write_iosf_sb_reg(hw, 1775315333Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 1776315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, lval); 1777315333Serj if (rc) 1778315333Serj return rc; 1779315333Serj 1780315333Serj rc = mac->ops.read_iosf_sb_reg(hw, 1781315333Serj IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id), 1782315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, &sval); 1783315333Serj if (rc) 1784315333Serj return rc; 1785315333Serj 1786315333Serj sval |= IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_10_D; 1787315333Serj sval |= IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_100_D; 1788315333Serj rc = mac->ops.write_iosf_sb_reg(hw, 1789315333Serj IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id), 1790315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, sval); 1791315333Serj if (rc) 1792315333Serj return rc; 1793315333Serj 1794315333Serj rc = mac->ops.read_iosf_sb_reg(hw, 1795315333Serj IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), 1796315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, &flx_val); 1797315333Serj if (rc) 1798315333Serj return rc; 1799315333Serj 1800315333Serj flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK; 1801315333Serj flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_1G; 1802315333Serj flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN; 1803315333Serj flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN; 1804315333Serj flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN; 1805315333Serj 1806315333Serj rc = mac->ops.write_iosf_sb_reg(hw, 1807315333Serj IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), 1808315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, flx_val); 1809315333Serj if (rc) 1810315333Serj return rc; 1811315333Serj 1812315333Serj rc = ixgbe_restart_an_internal_phy_x550em(hw); 1813315333Serj if (rc) 1814315333Serj return rc; 1815315333Serj 1816315333Serj return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait); 1817315333Serj} 1818315333Serj 1819315333Serj/** 1820315333Serj * ixgbe_setup_sgmii_fw - Set up link for sgmii with firmware-controlled PHYs 1821315333Serj * @hw: pointer to hardware structure 1822315333Serj */ 1823315333Serjstatic s32 ixgbe_setup_sgmii_fw(struct ixgbe_hw *hw, ixgbe_link_speed speed, 1824315333Serj bool autoneg_wait) 1825315333Serj{ 1826315333Serj struct ixgbe_mac_info *mac = &hw->mac; 1827315333Serj u32 lval, sval, flx_val; 1828315333Serj s32 rc; 1829315333Serj 1830315333Serj rc = mac->ops.read_iosf_sb_reg(hw, 1831315333Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 1832315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, &lval); 1833315333Serj if (rc) 1834315333Serj return rc; 1835315333Serj 1836315333Serj lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE; 1837315333Serj lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK; 1838315333Serj lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_SGMII_EN; 1839315333Serj lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CLAUSE_37_EN; 1840315333Serj lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G; 1841315333Serj rc = mac->ops.write_iosf_sb_reg(hw, 1842315333Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 1843315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, lval); 1844315333Serj if (rc) 1845315333Serj return rc; 1846315333Serj 1847315333Serj rc = mac->ops.read_iosf_sb_reg(hw, 1848315333Serj IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id), 1849315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, &sval); 1850315333Serj if (rc) 1851315333Serj return rc; 1852315333Serj 1853315333Serj sval &= ~IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_10_D; 1854315333Serj sval &= ~IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_100_D; 1855315333Serj rc = mac->ops.write_iosf_sb_reg(hw, 1856315333Serj IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id), 1857315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, sval); 1858315333Serj if (rc) 1859315333Serj return rc; 1860315333Serj 1861315333Serj rc = mac->ops.write_iosf_sb_reg(hw, 1862315333Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 1863315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, lval); 1864315333Serj if (rc) 1865315333Serj return rc; 1866315333Serj 1867315333Serj rc = mac->ops.read_iosf_sb_reg(hw, 1868315333Serj IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), 1869315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, &flx_val); 1870315333Serj if (rc) 1871315333Serj return rc; 1872315333Serj 1873315333Serj flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK; 1874315333Serj flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_AN; 1875315333Serj flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN; 1876315333Serj flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN; 1877315333Serj flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN; 1878315333Serj 1879315333Serj rc = mac->ops.write_iosf_sb_reg(hw, 1880315333Serj IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), 1881315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, flx_val); 1882315333Serj if (rc) 1883315333Serj return rc; 1884315333Serj 1885315333Serj rc = ixgbe_restart_an_internal_phy_x550em(hw); 1886315333Serj 1887315333Serj return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait); 1888315333Serj} 1889315333Serj 1890315333Serj/** 1891282289Serj * ixgbe_init_mac_link_ops_X550em - init mac link function pointers 1892282289Serj * @hw: pointer to hardware structure 1893282289Serj */ 1894282289Serjvoid ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw) 1895282289Serj{ 1896282289Serj struct ixgbe_mac_info *mac = &hw->mac; 1897282289Serj 1898282289Serj DEBUGFUNC("ixgbe_init_mac_link_ops_X550em"); 1899282289Serj 1900315333Serj switch (hw->mac.ops.get_media_type(hw)) { 1901315333Serj case ixgbe_media_type_fiber: 1902282289Serj /* CS4227 does not support autoneg, so disable the laser control 1903282289Serj * functions for SFP+ fiber 1904282289Serj */ 1905282289Serj mac->ops.disable_tx_laser = NULL; 1906282289Serj mac->ops.enable_tx_laser = NULL; 1907282289Serj mac->ops.flap_tx_laser = NULL; 1908282289Serj mac->ops.setup_link = ixgbe_setup_mac_link_multispeed_fiber; 1909282289Serj mac->ops.set_rate_select_speed = 1910282289Serj ixgbe_set_soft_rate_select_speed; 1911315333Serj 1912315333Serj if ((hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N) || 1913315333Serj (hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP)) 1914315333Serj mac->ops.setup_mac_link = 1915315333Serj ixgbe_setup_mac_link_sfp_x550a; 1916315333Serj else 1917315333Serj mac->ops.setup_mac_link = 1918315333Serj ixgbe_setup_mac_link_sfp_x550em; 1919282289Serj break; 1920282289Serj case ixgbe_media_type_copper: 1921315333Serj if (hw->mac.type == ixgbe_mac_X550EM_a) { 1922315333Serj if (hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T || 1923315333Serj hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L) { 1924315333Serj mac->ops.setup_link = ixgbe_setup_sgmii_fw; 1925315333Serj mac->ops.check_link = 1926315333Serj ixgbe_check_mac_link_generic; 1927315333Serj } else { 1928315333Serj mac->ops.setup_link = 1929315333Serj ixgbe_setup_mac_link_t_X550em; 1930315333Serj } 1931315333Serj } else { 1932315333Serj mac->ops.setup_link = ixgbe_setup_mac_link_t_X550em; 1933315333Serj mac->ops.check_link = ixgbe_check_link_t_X550em; 1934315333Serj } 1935282289Serj break; 1936315333Serj case ixgbe_media_type_backplane: 1937315333Serj if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII || 1938315333Serj hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII_L) 1939315333Serj mac->ops.setup_link = ixgbe_setup_sgmii; 1940315333Serj break; 1941282289Serj default: 1942282289Serj break; 1943315333Serj } 1944282289Serj} 1945282289Serj 1946282289Serj/** 1947282289Serj * ixgbe_get_link_capabilities_x550em - Determines link capabilities 1948282289Serj * @hw: pointer to hardware structure 1949282289Serj * @speed: pointer to link speed 1950282289Serj * @autoneg: TRUE when autoneg or autotry is enabled 1951282289Serj */ 1952282289Serjs32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw, 1953282289Serj ixgbe_link_speed *speed, 1954282289Serj bool *autoneg) 1955282289Serj{ 1956282289Serj DEBUGFUNC("ixgbe_get_link_capabilities_X550em"); 1957282289Serj 1958315333Serj 1959315333Serj if (hw->phy.type == ixgbe_phy_fw) { 1960315333Serj *autoneg = TRUE; 1961315333Serj *speed = hw->phy.speeds_supported; 1962315333Serj return 0; 1963315333Serj } 1964315333Serj 1965282289Serj /* SFP */ 1966282289Serj if (hw->phy.media_type == ixgbe_media_type_fiber) { 1967282289Serj 1968282289Serj /* CS4227 SFP must not enable auto-negotiation */ 1969282289Serj *autoneg = FALSE; 1970282289Serj 1971282289Serj /* Check if 1G SFP module. */ 1972282289Serj if (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || 1973282289Serj hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 1974282289Serj || hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || 1975282289Serj hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1) { 1976282289Serj *speed = IXGBE_LINK_SPEED_1GB_FULL; 1977282289Serj return IXGBE_SUCCESS; 1978282289Serj } 1979282289Serj 1980282289Serj /* Link capabilities are based on SFP */ 1981282289Serj if (hw->phy.multispeed_fiber) 1982282289Serj *speed = IXGBE_LINK_SPEED_10GB_FULL | 1983282289Serj IXGBE_LINK_SPEED_1GB_FULL; 1984282289Serj else 1985282289Serj *speed = IXGBE_LINK_SPEED_10GB_FULL; 1986282289Serj } else { 1987315333Serj switch (hw->phy.type) { 1988315333Serj case ixgbe_phy_sgmii: 1989315333Serj *speed = IXGBE_LINK_SPEED_1GB_FULL; 1990315333Serj break; 1991315333Serj case ixgbe_phy_x550em_kr: 1992315333Serj if (hw->mac.type == ixgbe_mac_X550EM_a) { 1993315333Serj /* check different backplane modes */ 1994315333Serj if (hw->phy.nw_mng_if_sel & 1995315333Serj IXGBE_NW_MNG_IF_SEL_PHY_SPEED_2_5G) { 1996315333Serj *speed = IXGBE_LINK_SPEED_2_5GB_FULL; 1997315333Serj break; 1998315333Serj } else if (hw->device_id == 1999315333Serj IXGBE_DEV_ID_X550EM_A_KR_L) { 2000315333Serj *speed = IXGBE_LINK_SPEED_1GB_FULL; 2001315333Serj break; 2002315333Serj } 2003315333Serj } 2004315333Serj /* fall through */ 2005315333Serj default: 2006315333Serj *speed = IXGBE_LINK_SPEED_10GB_FULL | 2007315333Serj IXGBE_LINK_SPEED_1GB_FULL; 2008315333Serj break; 2009315333Serj } 2010282289Serj *autoneg = TRUE; 2011282289Serj } 2012282289Serj 2013282289Serj return IXGBE_SUCCESS; 2014282289Serj} 2015282289Serj 2016282289Serj/** 2017282289Serj * ixgbe_get_lasi_ext_t_x550em - Determime external Base T PHY interrupt cause 2018282289Serj * @hw: pointer to hardware structure 2019282289Serj * @lsc: pointer to boolean flag which indicates whether external Base T 2020282289Serj * PHY interrupt is lsc 2021282289Serj * 2022282289Serj * Determime if external Base T PHY interrupt cause is high temperature 2023282289Serj * failure alarm or link status change. 2024282289Serj * 2025282289Serj * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature 2026282289Serj * failure alarm, else return PHY access status. 2027282289Serj */ 2028282289Serjstatic s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc) 2029282289Serj{ 2030282289Serj u32 status; 2031282289Serj u16 reg; 2032282289Serj 2033282289Serj *lsc = FALSE; 2034282289Serj 2035282289Serj /* Vendor alarm triggered */ 2036282289Serj status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG, 2037282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2038282289Serj ®); 2039282289Serj 2040282289Serj if (status != IXGBE_SUCCESS || 2041282289Serj !(reg & IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN)) 2042282289Serj return status; 2043282289Serj 2044282289Serj /* Vendor Auto-Neg alarm triggered or Global alarm 1 triggered */ 2045282289Serj status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_FLAG, 2046282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2047282289Serj ®); 2048282289Serj 2049282289Serj if (status != IXGBE_SUCCESS || 2050282289Serj !(reg & (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN | 2051282289Serj IXGBE_MDIO_GLOBAL_ALARM_1_INT))) 2052282289Serj return status; 2053282289Serj 2054295528Ssmh /* Global alarm triggered */ 2055282289Serj status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_ALARM_1, 2056282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2057282289Serj ®); 2058282289Serj 2059282289Serj if (status != IXGBE_SUCCESS) 2060282289Serj return status; 2061282289Serj 2062282289Serj /* If high temperature failure, then return over temp error and exit */ 2063282289Serj if (reg & IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL) { 2064282289Serj /* power down the PHY in case the PHY FW didn't already */ 2065282289Serj ixgbe_set_copper_phy_power(hw, FALSE); 2066282289Serj return IXGBE_ERR_OVERTEMP; 2067295528Ssmh } else if (reg & IXGBE_MDIO_GLOBAL_ALM_1_DEV_FAULT) { 2068295528Ssmh /* device fault alarm triggered */ 2069295528Ssmh status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_FAULT_MSG, 2070295528Ssmh IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2071295528Ssmh ®); 2072295528Ssmh 2073295528Ssmh if (status != IXGBE_SUCCESS) 2074295528Ssmh return status; 2075295528Ssmh 2076295528Ssmh /* if device fault was due to high temp alarm handle and exit */ 2077295528Ssmh if (reg == IXGBE_MDIO_GLOBAL_FAULT_MSG_HI_TMP) { 2078295528Ssmh /* power down the PHY in case the PHY FW didn't */ 2079295528Ssmh ixgbe_set_copper_phy_power(hw, FALSE); 2080295528Ssmh return IXGBE_ERR_OVERTEMP; 2081295528Ssmh } 2082282289Serj } 2083282289Serj 2084282289Serj /* Vendor alarm 2 triggered */ 2085282289Serj status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG, 2086282289Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, ®); 2087282289Serj 2088282289Serj if (status != IXGBE_SUCCESS || 2089282289Serj !(reg & IXGBE_MDIO_GLOBAL_STD_ALM2_INT)) 2090282289Serj return status; 2091282289Serj 2092282289Serj /* link connect/disconnect event occurred */ 2093282289Serj status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM2, 2094282289Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, ®); 2095282289Serj 2096282289Serj if (status != IXGBE_SUCCESS) 2097282289Serj return status; 2098282289Serj 2099282289Serj /* Indicate LSC */ 2100282289Serj if (reg & IXGBE_MDIO_AUTO_NEG_VEN_LSC) 2101282289Serj *lsc = TRUE; 2102282289Serj 2103282289Serj return IXGBE_SUCCESS; 2104282289Serj} 2105282289Serj 2106282289Serj/** 2107282289Serj * ixgbe_enable_lasi_ext_t_x550em - Enable external Base T PHY interrupts 2108282289Serj * @hw: pointer to hardware structure 2109282289Serj * 2110282289Serj * Enable link status change and temperature failure alarm for the external 2111282289Serj * Base T PHY 2112282289Serj * 2113282289Serj * Returns PHY access status 2114282289Serj */ 2115282289Serjstatic s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw) 2116282289Serj{ 2117282289Serj u32 status; 2118282289Serj u16 reg; 2119282289Serj bool lsc; 2120282289Serj 2121282289Serj /* Clear interrupt flags */ 2122282289Serj status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc); 2123282289Serj 2124282289Serj /* Enable link status change alarm */ 2125282289Serj 2126315333Serj /* Enable the LASI interrupts on X552 devices to receive notifications 2127315333Serj * of the link configurations of the external PHY and correspondingly 2128315333Serj * support the configuration of the internal iXFI link, since iXFI does 2129315333Serj * not support auto-negotiation. This is not required for X553 devices 2130315333Serj * having KR support, which performs auto-negotiations and which is used 2131315333Serj * as the internal link to the external PHY. Hence adding a check here 2132315333Serj * to avoid enabling LASI interrupts for X553 devices. 2133315333Serj */ 2134315333Serj if (hw->mac.type != ixgbe_mac_X550EM_a) { 2135315333Serj status = hw->phy.ops.read_reg(hw, 2136315333Serj IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK, 2137315333Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, ®); 2138282289Serj 2139315333Serj if (status != IXGBE_SUCCESS) 2140315333Serj return status; 2141282289Serj 2142315333Serj reg |= IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN; 2143282289Serj 2144315333Serj status = hw->phy.ops.write_reg(hw, 2145315333Serj IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK, 2146315333Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, reg); 2147282289Serj 2148315333Serj if (status != IXGBE_SUCCESS) 2149315333Serj return status; 2150315333Serj } 2151315333Serj 2152315333Serj /* Enable high temperature failure and global fault alarms */ 2153282289Serj status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK, 2154282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2155282289Serj ®); 2156282289Serj 2157282289Serj if (status != IXGBE_SUCCESS) 2158282289Serj return status; 2159282289Serj 2160315333Serj reg |= (IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN | 2161315333Serj IXGBE_MDIO_GLOBAL_INT_DEV_FAULT_EN); 2162282289Serj 2163282289Serj status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK, 2164282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2165282289Serj reg); 2166282289Serj 2167282289Serj if (status != IXGBE_SUCCESS) 2168282289Serj return status; 2169282289Serj 2170282289Serj /* Enable vendor Auto-Neg alarm and Global Interrupt Mask 1 alarm */ 2171282289Serj status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK, 2172282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2173282289Serj ®); 2174282289Serj 2175282289Serj if (status != IXGBE_SUCCESS) 2176282289Serj return status; 2177282289Serj 2178282289Serj reg |= (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN | 2179282289Serj IXGBE_MDIO_GLOBAL_ALARM_1_INT); 2180282289Serj 2181282289Serj status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK, 2182282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2183282289Serj reg); 2184282289Serj 2185282289Serj if (status != IXGBE_SUCCESS) 2186282289Serj return status; 2187282289Serj 2188282289Serj /* Enable chip-wide vendor alarm */ 2189282289Serj status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK, 2190282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2191282289Serj ®); 2192282289Serj 2193282289Serj if (status != IXGBE_SUCCESS) 2194282289Serj return status; 2195282289Serj 2196282289Serj reg |= IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN; 2197282289Serj 2198282289Serj status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK, 2199282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2200282289Serj reg); 2201282289Serj 2202282289Serj return status; 2203282289Serj} 2204282289Serj 2205282289Serj/** 2206282289Serj * ixgbe_setup_kr_speed_x550em - Configure the KR PHY for link speed. 2207282289Serj * @hw: pointer to hardware structure 2208282289Serj * @speed: link speed 2209282289Serj * 2210282289Serj * Configures the integrated KR PHY. 2211282289Serj **/ 2212282289Serjstatic s32 ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *hw, 2213282289Serj ixgbe_link_speed speed) 2214282289Serj{ 2215282289Serj s32 status; 2216282289Serj u32 reg_val; 2217282289Serj 2218315333Serj status = hw->mac.ops.read_iosf_sb_reg(hw, 2219315333Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 2220315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 2221282289Serj if (status) 2222282289Serj return status; 2223282289Serj 2224282289Serj reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE; 2225282289Serj reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR | 2226282289Serj IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX); 2227282289Serj 2228282289Serj /* Advertise 10G support. */ 2229282289Serj if (speed & IXGBE_LINK_SPEED_10GB_FULL) 2230282289Serj reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR; 2231282289Serj 2232282289Serj /* Advertise 1G support. */ 2233282289Serj if (speed & IXGBE_LINK_SPEED_1GB_FULL) 2234282289Serj reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX; 2235282289Serj 2236315333Serj status = hw->mac.ops.write_iosf_sb_reg(hw, 2237315333Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 2238315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 2239282289Serj 2240315333Serj if (hw->mac.type == ixgbe_mac_X550EM_a) { 2241315333Serj /* Set lane mode to KR auto negotiation */ 2242315333Serj status = hw->mac.ops.read_iosf_sb_reg(hw, 2243315333Serj IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), 2244315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 2245315333Serj 2246315333Serj if (status) 2247315333Serj return status; 2248315333Serj 2249315333Serj reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK; 2250315333Serj reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_AN; 2251315333Serj reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN; 2252315333Serj reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN; 2253315333Serj reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN; 2254315333Serj 2255315333Serj status = hw->mac.ops.write_iosf_sb_reg(hw, 2256315333Serj IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), 2257315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 2258315333Serj } 2259315333Serj 2260315333Serj return ixgbe_restart_an_internal_phy_x550em(hw); 2261282289Serj} 2262282289Serj 2263282289Serj/** 2264315333Serj * ixgbe_reset_phy_fw - Reset firmware-controlled PHYs 2265315333Serj * @hw: pointer to hardware structure 2266315333Serj */ 2267315333Serjstatic s32 ixgbe_reset_phy_fw(struct ixgbe_hw *hw) 2268315333Serj{ 2269315333Serj u32 store[FW_PHY_ACT_DATA_COUNT] = { 0 }; 2270315333Serj s32 rc; 2271315333Serj 2272315333Serj if (hw->phy.reset_disable || ixgbe_check_reset_blocked(hw)) 2273315333Serj return IXGBE_SUCCESS; 2274315333Serj 2275315333Serj rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_PHY_SW_RESET, &store); 2276315333Serj if (rc) 2277315333Serj return rc; 2278315333Serj memset(store, 0, sizeof(store)); 2279315333Serj 2280315333Serj rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_INIT_PHY, &store); 2281315333Serj if (rc) 2282315333Serj return rc; 2283315333Serj 2284315333Serj return ixgbe_setup_fw_link(hw); 2285315333Serj} 2286315333Serj 2287315333Serj/** 2288315333Serj * ixgbe_check_overtemp_fw - Check firmware-controlled PHYs for overtemp 2289315333Serj * @hw: pointer to hardware structure 2290315333Serj */ 2291315333Serjstatic s32 ixgbe_check_overtemp_fw(struct ixgbe_hw *hw) 2292315333Serj{ 2293315333Serj u32 store[FW_PHY_ACT_DATA_COUNT] = { 0 }; 2294315333Serj s32 rc; 2295315333Serj 2296315333Serj rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &store); 2297315333Serj if (rc) 2298315333Serj return rc; 2299315333Serj 2300315333Serj if (store[0] & FW_PHY_ACT_GET_LINK_INFO_TEMP) { 2301315333Serj ixgbe_shutdown_fw_phy(hw); 2302315333Serj return IXGBE_ERR_OVERTEMP; 2303315333Serj } 2304315333Serj return IXGBE_SUCCESS; 2305315333Serj} 2306315333Serj 2307315333Serj/** 2308315333Serj * ixgbe_read_mng_if_sel_x550em - Read NW_MNG_IF_SEL register 2309315333Serj * @hw: pointer to hardware structure 2310315333Serj * 2311315333Serj * Read NW_MNG_IF_SEL register and save field values, and check for valid field 2312315333Serj * values. 2313315333Serj **/ 2314315333Serjstatic s32 ixgbe_read_mng_if_sel_x550em(struct ixgbe_hw *hw) 2315315333Serj{ 2316315333Serj /* Save NW management interface connected on board. This is used 2317315333Serj * to determine internal PHY mode. 2318315333Serj */ 2319315333Serj hw->phy.nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL); 2320315333Serj 2321315333Serj /* If X552 (X550EM_a) and MDIO is connected to external PHY, then set 2322315333Serj * PHY address. This register field was has only been used for X552. 2323315333Serj */ 2324315333Serj if (hw->mac.type == ixgbe_mac_X550EM_a && 2325315333Serj hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_MDIO_ACT) { 2326315333Serj hw->phy.addr = (hw->phy.nw_mng_if_sel & 2327315333Serj IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >> 2328315333Serj IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT; 2329315333Serj } 2330315333Serj 2331315333Serj return IXGBE_SUCCESS; 2332315333Serj} 2333315333Serj 2334315333Serj/** 2335282289Serj * ixgbe_init_phy_ops_X550em - PHY/SFP specific init 2336282289Serj * @hw: pointer to hardware structure 2337282289Serj * 2338282289Serj * Initialize any function pointers that were not able to be 2339282289Serj * set during init_shared_code because the PHY/SFP type was 2340282289Serj * not known. Perform the SFP init if necessary. 2341282289Serj */ 2342282289Serjs32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) 2343282289Serj{ 2344282289Serj struct ixgbe_phy_info *phy = &hw->phy; 2345282289Serj s32 ret_val; 2346282289Serj 2347282289Serj DEBUGFUNC("ixgbe_init_phy_ops_X550em"); 2348282289Serj 2349282289Serj hw->mac.ops.set_lan_id(hw); 2350315333Serj ixgbe_read_mng_if_sel_x550em(hw); 2351282289Serj 2352282289Serj if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) { 2353282289Serj phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM; 2354282289Serj ixgbe_setup_mux_ctl(hw); 2355282289Serj phy->ops.identify_sfp = ixgbe_identify_sfp_module_X550em; 2356282289Serj } 2357282289Serj 2358315333Serj switch (hw->device_id) { 2359315333Serj case IXGBE_DEV_ID_X550EM_A_1G_T: 2360315333Serj case IXGBE_DEV_ID_X550EM_A_1G_T_L: 2361315333Serj phy->ops.read_reg_mdi = ixgbe_read_phy_reg_mdi_22; 2362315333Serj phy->ops.write_reg_mdi = ixgbe_write_phy_reg_mdi_22; 2363315333Serj hw->phy.ops.read_reg = ixgbe_read_phy_reg_x550a; 2364315333Serj hw->phy.ops.write_reg = ixgbe_write_phy_reg_x550a; 2365315333Serj phy->ops.check_overtemp = ixgbe_check_overtemp_fw; 2366315333Serj if (hw->bus.lan_id) 2367315333Serj hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM; 2368315333Serj else 2369315333Serj hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM; 2370315333Serj 2371315333Serj break; 2372315333Serj case IXGBE_DEV_ID_X550EM_A_10G_T: 2373315333Serj case IXGBE_DEV_ID_X550EM_A_SFP: 2374315333Serj hw->phy.ops.read_reg = ixgbe_read_phy_reg_x550a; 2375315333Serj hw->phy.ops.write_reg = ixgbe_write_phy_reg_x550a; 2376315333Serj if (hw->bus.lan_id) 2377315333Serj hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM; 2378315333Serj else 2379315333Serj hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM; 2380315333Serj break; 2381315333Serj case IXGBE_DEV_ID_X550EM_X_SFP: 2382315333Serj /* set up for CS4227 usage */ 2383315333Serj hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM; 2384315333Serj break; 2385315333Serj default: 2386315333Serj break; 2387315333Serj } 2388315333Serj 2389282289Serj /* Identify the PHY or SFP module */ 2390282289Serj ret_val = phy->ops.identify(hw); 2391315333Serj if (ret_val == IXGBE_ERR_SFP_NOT_SUPPORTED || 2392315333Serj ret_val == IXGBE_ERR_PHY_ADDR_INVALID) 2393282289Serj return ret_val; 2394282289Serj 2395282289Serj /* Setup function pointers based on detected hardware */ 2396282289Serj ixgbe_init_mac_link_ops_X550em(hw); 2397282289Serj if (phy->sfp_type != ixgbe_sfp_type_unknown) 2398282289Serj phy->ops.reset = NULL; 2399282289Serj 2400282289Serj /* Set functions pointers based on phy type */ 2401282289Serj switch (hw->phy.type) { 2402282289Serj case ixgbe_phy_x550em_kx4: 2403295524Ssbruno phy->ops.setup_link = NULL; 2404282289Serj phy->ops.read_reg = ixgbe_read_phy_reg_x550em; 2405282289Serj phy->ops.write_reg = ixgbe_write_phy_reg_x550em; 2406282289Serj break; 2407282289Serj case ixgbe_phy_x550em_kr: 2408282289Serj phy->ops.setup_link = ixgbe_setup_kr_x550em; 2409282289Serj phy->ops.read_reg = ixgbe_read_phy_reg_x550em; 2410282289Serj phy->ops.write_reg = ixgbe_write_phy_reg_x550em; 2411282289Serj break; 2412315333Serj case ixgbe_phy_x550em_xfi: 2413315333Serj /* link is managed by HW */ 2414315333Serj phy->ops.setup_link = NULL; 2415315333Serj phy->ops.read_reg = ixgbe_read_phy_reg_x550em; 2416315333Serj phy->ops.write_reg = ixgbe_write_phy_reg_x550em; 2417315333Serj break; 2418282289Serj case ixgbe_phy_x550em_ext_t: 2419282289Serj /* If internal link mode is XFI, then setup iXFI internal link, 2420282289Serj * else setup KR now. 2421282289Serj */ 2422315333Serj phy->ops.setup_internal_link = 2423282289Serj ixgbe_setup_internal_phy_t_x550em; 2424282289Serj 2425315333Serj /* setup SW LPLU only for first revision of X550EM_x */ 2426315333Serj if ((hw->mac.type == ixgbe_mac_X550EM_x) && 2427315333Serj !(IXGBE_FUSES0_REV_MASK & 2428315333Serj IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0)))) 2429295524Ssbruno phy->ops.enter_lplu = ixgbe_enter_lplu_t_x550em; 2430295524Ssbruno 2431282289Serj phy->ops.handle_lasi = ixgbe_handle_lasi_ext_t_x550em; 2432282289Serj phy->ops.reset = ixgbe_reset_phy_t_X550em; 2433282289Serj break; 2434315333Serj case ixgbe_phy_sgmii: 2435315333Serj phy->ops.setup_link = NULL; 2436315333Serj break; 2437315333Serj case ixgbe_phy_fw: 2438315333Serj phy->ops.setup_link = ixgbe_setup_fw_link; 2439315333Serj phy->ops.reset = ixgbe_reset_phy_fw; 2440315333Serj break; 2441282289Serj default: 2442282289Serj break; 2443282289Serj } 2444282289Serj return ret_val; 2445282289Serj} 2446282289Serj 2447282289Serj/** 2448315333Serj * ixgbe_set_mdio_speed - Set MDIO clock speed 2449315333Serj * @hw: pointer to hardware structure 2450315333Serj */ 2451315333Serjstatic void ixgbe_set_mdio_speed(struct ixgbe_hw *hw) 2452315333Serj{ 2453315333Serj u32 hlreg0; 2454315333Serj 2455315333Serj switch (hw->device_id) { 2456315333Serj case IXGBE_DEV_ID_X550EM_X_10G_T: 2457315333Serj case IXGBE_DEV_ID_X550EM_A_SGMII: 2458315333Serj case IXGBE_DEV_ID_X550EM_A_SGMII_L: 2459315333Serj case IXGBE_DEV_ID_X550EM_A_10G_T: 2460315333Serj case IXGBE_DEV_ID_X550EM_A_SFP: 2461315333Serj case IXGBE_DEV_ID_X550EM_A_QSFP: 2462315333Serj /* Config MDIO clock speed before the first MDIO PHY access */ 2463315333Serj hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0); 2464315333Serj hlreg0 &= ~IXGBE_HLREG0_MDCSPD; 2465315333Serj IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); 2466315333Serj break; 2467315333Serj case IXGBE_DEV_ID_X550EM_A_1G_T: 2468315333Serj case IXGBE_DEV_ID_X550EM_A_1G_T_L: 2469315333Serj /* Select fast MDIO clock speed for these devices */ 2470315333Serj hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0); 2471315333Serj hlreg0 |= IXGBE_HLREG0_MDCSPD; 2472315333Serj IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); 2473315333Serj break; 2474315333Serj default: 2475315333Serj break; 2476315333Serj } 2477315333Serj} 2478315333Serj 2479315333Serj/** 2480282289Serj * ixgbe_reset_hw_X550em - Perform hardware reset 2481282289Serj * @hw: pointer to hardware structure 2482282289Serj * 2483282289Serj * Resets the hardware by resetting the transmit and receive units, masks 2484282289Serj * and clears all interrupts, perform a PHY reset, and perform a link (MAC) 2485282289Serj * reset. 2486282289Serj */ 2487282289Serjs32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) 2488282289Serj{ 2489282289Serj ixgbe_link_speed link_speed; 2490282289Serj s32 status; 2491282289Serj u32 ctrl = 0; 2492282289Serj u32 i; 2493282289Serj bool link_up = FALSE; 2494282289Serj 2495282289Serj DEBUGFUNC("ixgbe_reset_hw_X550em"); 2496282289Serj 2497282289Serj /* Call adapter stop to disable Tx/Rx and clear interrupts */ 2498282289Serj status = hw->mac.ops.stop_adapter(hw); 2499315333Serj if (status != IXGBE_SUCCESS) { 2500315333Serj DEBUGOUT1("Failed to stop adapter, STATUS = %d\n", status); 2501282289Serj return status; 2502315333Serj } 2503282289Serj /* flush pending Tx transactions */ 2504282289Serj ixgbe_clear_tx_pending(hw); 2505282289Serj 2506315333Serj ixgbe_set_mdio_speed(hw); 2507295524Ssbruno 2508282289Serj /* PHY ops must be identified and initialized prior to reset */ 2509282289Serj status = hw->phy.ops.init(hw); 2510282289Serj 2511315333Serj if (status) 2512315333Serj DEBUGOUT1("Failed to initialize PHY ops, STATUS = %d\n", 2513315333Serj status); 2514315333Serj 2515315333Serj if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) { 2516315333Serj DEBUGOUT("Returning from reset HW due to PHY init failure\n"); 2517282289Serj return status; 2518315333Serj } 2519282289Serj 2520282289Serj /* start the external PHY */ 2521282289Serj if (hw->phy.type == ixgbe_phy_x550em_ext_t) { 2522282289Serj status = ixgbe_init_ext_t_x550em(hw); 2523315333Serj if (status) { 2524315333Serj DEBUGOUT1("Failed to start the external PHY, STATUS = %d\n", 2525315333Serj status); 2526282289Serj return status; 2527315333Serj } 2528282289Serj } 2529282289Serj 2530282289Serj /* Setup SFP module if there is one present. */ 2531282289Serj if (hw->phy.sfp_setup_needed) { 2532282289Serj status = hw->mac.ops.setup_sfp(hw); 2533282289Serj hw->phy.sfp_setup_needed = FALSE; 2534282289Serj } 2535282289Serj 2536282289Serj if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) 2537282289Serj return status; 2538282289Serj 2539282289Serj /* Reset PHY */ 2540315333Serj if (!hw->phy.reset_disable && hw->phy.ops.reset) { 2541315333Serj if (hw->phy.ops.reset(hw) == IXGBE_ERR_OVERTEMP) 2542315333Serj return IXGBE_ERR_OVERTEMP; 2543315333Serj } 2544282289Serj 2545282289Serjmac_reset_top: 2546282289Serj /* Issue global reset to the MAC. Needs to be SW reset if link is up. 2547282289Serj * If link reset is used when link is up, it might reset the PHY when 2548282289Serj * mng is using it. If link is down or the flag to force full link 2549282289Serj * reset is set, then perform link reset. 2550282289Serj */ 2551282289Serj ctrl = IXGBE_CTRL_LNK_RST; 2552282289Serj if (!hw->force_full_reset) { 2553282289Serj hw->mac.ops.check_link(hw, &link_speed, &link_up, FALSE); 2554282289Serj if (link_up) 2555282289Serj ctrl = IXGBE_CTRL_RST; 2556282289Serj } 2557282289Serj 2558282289Serj ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL); 2559282289Serj IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl); 2560282289Serj IXGBE_WRITE_FLUSH(hw); 2561282289Serj 2562282289Serj /* Poll for reset bit to self-clear meaning reset is complete */ 2563282289Serj for (i = 0; i < 10; i++) { 2564282289Serj usec_delay(1); 2565282289Serj ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); 2566282289Serj if (!(ctrl & IXGBE_CTRL_RST_MASK)) 2567282289Serj break; 2568282289Serj } 2569282289Serj 2570282289Serj if (ctrl & IXGBE_CTRL_RST_MASK) { 2571282289Serj status = IXGBE_ERR_RESET_FAILED; 2572282289Serj DEBUGOUT("Reset polling failed to complete.\n"); 2573282289Serj } 2574282289Serj 2575282289Serj msec_delay(50); 2576282289Serj 2577282289Serj /* Double resets are required for recovery from certain error 2578282289Serj * conditions. Between resets, it is necessary to stall to 2579282289Serj * allow time for any pending HW events to complete. 2580282289Serj */ 2581282289Serj if (hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED) { 2582282289Serj hw->mac.flags &= ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED; 2583282289Serj goto mac_reset_top; 2584282289Serj } 2585282289Serj 2586282289Serj /* Store the permanent mac address */ 2587282289Serj hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); 2588282289Serj 2589282289Serj /* Store MAC address from RAR0, clear receive address registers, and 2590282289Serj * clear the multicast table. Also reset num_rar_entries to 128, 2591282289Serj * since we modify this value when programming the SAN MAC address. 2592282289Serj */ 2593282289Serj hw->mac.num_rar_entries = 128; 2594282289Serj hw->mac.ops.init_rx_addrs(hw); 2595282289Serj 2596315333Serj ixgbe_set_mdio_speed(hw); 2597315333Serj 2598282289Serj if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) 2599282289Serj ixgbe_setup_mux_ctl(hw); 2600282289Serj 2601315333Serj if (status != IXGBE_SUCCESS) 2602315333Serj DEBUGOUT1("Reset HW failed, STATUS = %d\n", status); 2603315333Serj 2604282289Serj return status; 2605282289Serj} 2606282289Serj 2607282289Serj/** 2608282289Serj * ixgbe_init_ext_t_x550em - Start (unstall) the external Base T PHY. 2609282289Serj * @hw: pointer to hardware structure 2610282289Serj */ 2611282289Serjs32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw) 2612282289Serj{ 2613282289Serj u32 status; 2614282289Serj u16 reg; 2615282289Serj 2616282289Serj status = hw->phy.ops.read_reg(hw, 2617282289Serj IXGBE_MDIO_TX_VENDOR_ALARMS_3, 2618282289Serj IXGBE_MDIO_PMA_PMD_DEV_TYPE, 2619282289Serj ®); 2620282289Serj 2621282289Serj if (status != IXGBE_SUCCESS) 2622282289Serj return status; 2623282289Serj 2624282289Serj /* If PHY FW reset completed bit is set then this is the first 2625282289Serj * SW instance after a power on so the PHY FW must be un-stalled. 2626282289Serj */ 2627282289Serj if (reg & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) { 2628282289Serj status = hw->phy.ops.read_reg(hw, 2629282289Serj IXGBE_MDIO_GLOBAL_RES_PR_10, 2630282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2631282289Serj ®); 2632282289Serj 2633282289Serj if (status != IXGBE_SUCCESS) 2634282289Serj return status; 2635282289Serj 2636282289Serj reg &= ~IXGBE_MDIO_POWER_UP_STALL; 2637282289Serj 2638282289Serj status = hw->phy.ops.write_reg(hw, 2639282289Serj IXGBE_MDIO_GLOBAL_RES_PR_10, 2640282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2641282289Serj reg); 2642282289Serj 2643282289Serj if (status != IXGBE_SUCCESS) 2644282289Serj return status; 2645282289Serj } 2646282289Serj 2647282289Serj return status; 2648282289Serj} 2649282289Serj 2650282289Serj/** 2651282289Serj * ixgbe_setup_kr_x550em - Configure the KR PHY. 2652282289Serj * @hw: pointer to hardware structure 2653282289Serj **/ 2654282289Serjs32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) 2655282289Serj{ 2656315333Serj /* leave link alone for 2.5G */ 2657315333Serj if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL) 2658315333Serj return IXGBE_SUCCESS; 2659315333Serj 2660282289Serj return ixgbe_setup_kr_speed_x550em(hw, hw->phy.autoneg_advertised); 2661282289Serj} 2662282289Serj 2663282289Serj/** 2664282289Serj * ixgbe_setup_mac_link_sfp_x550em - Setup internal/external the PHY for SFP 2665282289Serj * @hw: pointer to hardware structure 2666282289Serj * 2667282289Serj * Configure the external PHY and the integrated KR PHY for SFP support. 2668282289Serj **/ 2669282289Serjs32 ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw, 2670282289Serj ixgbe_link_speed speed, 2671282289Serj bool autoneg_wait_to_complete) 2672282289Serj{ 2673282289Serj s32 ret_val; 2674282289Serj u16 reg_slice, reg_val; 2675282289Serj bool setup_linear = FALSE; 2676282289Serj UNREFERENCED_1PARAMETER(autoneg_wait_to_complete); 2677282289Serj 2678282289Serj /* Check if SFP module is supported and linear */ 2679282289Serj ret_val = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear); 2680282289Serj 2681282289Serj /* If no SFP module present, then return success. Return success since 2682282289Serj * there is no reason to configure CS4227 and SFP not present error is 2683282289Serj * not excepted in the setup MAC link flow. 2684282289Serj */ 2685282289Serj if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT) 2686282289Serj return IXGBE_SUCCESS; 2687282289Serj 2688282289Serj if (ret_val != IXGBE_SUCCESS) 2689282289Serj return ret_val; 2690282289Serj 2691315333Serj /* Configure internal PHY for KR/KX. */ 2692315333Serj ixgbe_setup_kr_speed_x550em(hw, speed); 2693282289Serj 2694315333Serj /* Configure CS4227 LINE side to proper mode. */ 2695315333Serj reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + 2696315333Serj (hw->bus.lan_id << 12); 2697315333Serj if (setup_linear) 2698315333Serj reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1; 2699315333Serj else 2700282289Serj reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; 2701315333Serj ret_val = hw->link.ops.write_link(hw, hw->link.addr, reg_slice, 2702315333Serj reg_val); 2703282289Serj return ret_val; 2704282289Serj} 2705282289Serj 2706282289Serj/** 2707315333Serj * ixgbe_setup_sfi_x550a - Configure the internal PHY for native SFI mode 2708282289Serj * @hw: pointer to hardware structure 2709282289Serj * @speed: the link speed to force 2710282289Serj * 2711315333Serj * Configures the integrated PHY for native SFI mode. Used to connect the 2712315333Serj * internal PHY directly to an SFP cage, without autonegotiation. 2713282289Serj **/ 2714315333Serjstatic s32 ixgbe_setup_sfi_x550a(struct ixgbe_hw *hw, ixgbe_link_speed *speed) 2715282289Serj{ 2716315333Serj struct ixgbe_mac_info *mac = &hw->mac; 2717282289Serj s32 status; 2718282289Serj u32 reg_val; 2719282289Serj 2720315333Serj /* Disable all AN and force speed to 10G Serial. */ 2721315333Serj status = mac->ops.read_iosf_sb_reg(hw, 2722315333Serj IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), 2723315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 2724282289Serj if (status != IXGBE_SUCCESS) 2725282289Serj return status; 2726282289Serj 2727315333Serj reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN; 2728315333Serj reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN; 2729315333Serj reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN; 2730315333Serj reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK; 2731282289Serj 2732282289Serj /* Select forced link speed for internal PHY. */ 2733282289Serj switch (*speed) { 2734282289Serj case IXGBE_LINK_SPEED_10GB_FULL: 2735315333Serj reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_10G; 2736282289Serj break; 2737282289Serj case IXGBE_LINK_SPEED_1GB_FULL: 2738315333Serj reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_1G; 2739282289Serj break; 2740282289Serj default: 2741315333Serj /* Other link speeds are not supported by internal PHY. */ 2742282289Serj return IXGBE_ERR_LINK_SETUP; 2743282289Serj } 2744282289Serj 2745315333Serj status = mac->ops.write_iosf_sb_reg(hw, 2746315333Serj IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), 2747315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 2748282289Serj 2749315333Serj /* Toggle port SW reset by AN reset. */ 2750315333Serj status = ixgbe_restart_an_internal_phy_x550em(hw); 2751315333Serj 2752315333Serj return status; 2753315333Serj} 2754315333Serj 2755315333Serj/** 2756315333Serj * ixgbe_setup_mac_link_sfp_x550a - Setup internal PHY for SFP 2757315333Serj * @hw: pointer to hardware structure 2758315333Serj * 2759315333Serj * Configure the the integrated PHY for SFP support. 2760315333Serj **/ 2761315333Serjs32 ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, 2762315333Serj ixgbe_link_speed speed, 2763315333Serj bool autoneg_wait_to_complete) 2764315333Serj{ 2765315333Serj s32 ret_val; 2766315333Serj u16 reg_phy_ext; 2767315333Serj bool setup_linear = FALSE; 2768315333Serj u32 reg_slice, reg_phy_int, slice_offset; 2769315333Serj 2770315333Serj UNREFERENCED_1PARAMETER(autoneg_wait_to_complete); 2771315333Serj 2772315333Serj /* Check if SFP module is supported and linear */ 2773315333Serj ret_val = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear); 2774315333Serj 2775315333Serj /* If no SFP module present, then return success. Return success since 2776315333Serj * SFP not present error is not excepted in the setup MAC link flow. 2777315333Serj */ 2778315333Serj if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT) 2779315333Serj return IXGBE_SUCCESS; 2780315333Serj 2781315333Serj if (ret_val != IXGBE_SUCCESS) 2782315333Serj return ret_val; 2783315333Serj 2784315333Serj if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N) { 2785315333Serj /* Configure internal PHY for native SFI based on module type */ 2786315333Serj ret_val = hw->mac.ops.read_iosf_sb_reg(hw, 2787315333Serj IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), 2788315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_phy_int); 2789315333Serj 2790315333Serj if (ret_val != IXGBE_SUCCESS) 2791315333Serj return ret_val; 2792315333Serj 2793315333Serj reg_phy_int &= IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_DA; 2794315333Serj if (!setup_linear) 2795315333Serj reg_phy_int |= IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_SR; 2796315333Serj 2797315333Serj ret_val = hw->mac.ops.write_iosf_sb_reg(hw, 2798315333Serj IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), 2799315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_phy_int); 2800315333Serj 2801315333Serj if (ret_val != IXGBE_SUCCESS) 2802315333Serj return ret_val; 2803315333Serj 2804315333Serj /* Setup SFI internal link. */ 2805315333Serj ret_val = ixgbe_setup_sfi_x550a(hw, &speed); 2806315333Serj } else { 2807315333Serj /* Configure internal PHY for KR/KX. */ 2808315333Serj ixgbe_setup_kr_speed_x550em(hw, speed); 2809315333Serj 2810315333Serj if (hw->phy.addr == 0x0 || hw->phy.addr == 0xFFFF) { 2811315333Serj /* Find Address */ 2812315333Serj DEBUGOUT("Invalid NW_MNG_IF_SEL.MDIO_PHY_ADD value\n"); 2813315333Serj return IXGBE_ERR_PHY_ADDR_INVALID; 2814315333Serj } 2815315333Serj 2816315333Serj /* Get external PHY SKU id */ 2817315333Serj ret_val = hw->phy.ops.read_reg(hw, IXGBE_CS4227_EFUSE_PDF_SKU, 2818315333Serj IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); 2819315333Serj 2820315333Serj if (ret_val != IXGBE_SUCCESS) 2821315333Serj return ret_val; 2822315333Serj 2823315333Serj /* When configuring quad port CS4223, the MAC instance is part 2824315333Serj * of the slice offset. 2825315333Serj */ 2826315333Serj if (reg_phy_ext == IXGBE_CS4223_SKU_ID) 2827315333Serj slice_offset = (hw->bus.lan_id + 2828315333Serj (hw->bus.instance_id << 1)) << 12; 2829315333Serj else 2830315333Serj slice_offset = hw->bus.lan_id << 12; 2831315333Serj 2832315333Serj /* Configure CS4227/CS4223 LINE side to proper mode. */ 2833315333Serj reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + slice_offset; 2834315333Serj 2835315333Serj ret_val = hw->phy.ops.read_reg(hw, reg_slice, 2836315333Serj IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); 2837315333Serj 2838315333Serj if (ret_val != IXGBE_SUCCESS) 2839315333Serj return ret_val; 2840315333Serj 2841315333Serj reg_phy_ext &= ~((IXGBE_CS4227_EDC_MODE_CX1 << 1) | 2842315333Serj (IXGBE_CS4227_EDC_MODE_SR << 1)); 2843315333Serj 2844315333Serj if (setup_linear) 2845315333Serj reg_phy_ext = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1; 2846315333Serj else 2847315333Serj reg_phy_ext = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; 2848315333Serj ret_val = hw->phy.ops.write_reg(hw, reg_slice, 2849315333Serj IXGBE_MDIO_ZERO_DEV_TYPE, reg_phy_ext); 2850315333Serj 2851315333Serj /* Flush previous write with a read */ 2852315333Serj ret_val = hw->phy.ops.read_reg(hw, reg_slice, 2853315333Serj IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); 2854315333Serj } 2855315333Serj return ret_val; 2856315333Serj} 2857315333Serj 2858315333Serj/** 2859315333Serj * ixgbe_setup_ixfi_x550em_x - MAC specific iXFI configuration 2860315333Serj * @hw: pointer to hardware structure 2861315333Serj * 2862315333Serj * iXfI configuration needed for ixgbe_mac_X550EM_x devices. 2863315333Serj **/ 2864315333Serjstatic s32 ixgbe_setup_ixfi_x550em_x(struct ixgbe_hw *hw) 2865315333Serj{ 2866315333Serj struct ixgbe_mac_info *mac = &hw->mac; 2867315333Serj s32 status; 2868315333Serj u32 reg_val; 2869315333Serj 2870282289Serj /* Disable training protocol FSM. */ 2871315333Serj status = mac->ops.read_iosf_sb_reg(hw, 2872282289Serj IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id), 2873282289Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 2874282289Serj if (status != IXGBE_SUCCESS) 2875282289Serj return status; 2876282289Serj reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_CONV_WO_PROTOCOL; 2877315333Serj status = mac->ops.write_iosf_sb_reg(hw, 2878282289Serj IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id), 2879282289Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 2880282289Serj if (status != IXGBE_SUCCESS) 2881282289Serj return status; 2882282289Serj 2883282289Serj /* Disable Flex from training TXFFE. */ 2884315333Serj status = mac->ops.read_iosf_sb_reg(hw, 2885282289Serj IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id), 2886282289Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 2887282289Serj if (status != IXGBE_SUCCESS) 2888282289Serj return status; 2889282289Serj reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN; 2890282289Serj reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN; 2891282289Serj reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN; 2892315333Serj status = mac->ops.write_iosf_sb_reg(hw, 2893282289Serj IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id), 2894282289Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 2895282289Serj if (status != IXGBE_SUCCESS) 2896282289Serj return status; 2897315333Serj status = mac->ops.read_iosf_sb_reg(hw, 2898282289Serj IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id), 2899282289Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 2900282289Serj if (status != IXGBE_SUCCESS) 2901282289Serj return status; 2902282289Serj reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN; 2903282289Serj reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN; 2904282289Serj reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN; 2905315333Serj status = mac->ops.write_iosf_sb_reg(hw, 2906282289Serj IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id), 2907282289Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 2908282289Serj if (status != IXGBE_SUCCESS) 2909282289Serj return status; 2910282289Serj 2911282289Serj /* Enable override for coefficients. */ 2912315333Serj status = mac->ops.read_iosf_sb_reg(hw, 2913282289Serj IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id), 2914282289Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 2915282289Serj if (status != IXGBE_SUCCESS) 2916282289Serj return status; 2917282289Serj reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_OVRRD_EN; 2918282289Serj reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CZERO_EN; 2919282289Serj reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CPLUS1_OVRRD_EN; 2920282289Serj reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CMINUS1_OVRRD_EN; 2921315333Serj status = mac->ops.write_iosf_sb_reg(hw, 2922282289Serj IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id), 2923282289Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 2924315333Serj return status; 2925315333Serj} 2926282289Serj 2927315333Serj/** 2928315333Serj * ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI mode. 2929315333Serj * @hw: pointer to hardware structure 2930315333Serj * @speed: the link speed to force 2931315333Serj * 2932315333Serj * Configures the integrated KR PHY to use iXFI mode. Used to connect an 2933315333Serj * internal and external PHY at a specific speed, without autonegotiation. 2934315333Serj **/ 2935315333Serjstatic s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) 2936315333Serj{ 2937315333Serj struct ixgbe_mac_info *mac = &hw->mac; 2938315333Serj s32 status; 2939315333Serj u32 reg_val; 2940315333Serj 2941315333Serj /* iXFI is only supported with X552 */ 2942315333Serj if (mac->type != ixgbe_mac_X550EM_x) 2943315333Serj return IXGBE_ERR_LINK_SETUP; 2944315333Serj 2945315333Serj /* Disable AN and force speed to 10G Serial. */ 2946315333Serj status = mac->ops.read_iosf_sb_reg(hw, 2947282289Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 2948282289Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 2949282289Serj if (status != IXGBE_SUCCESS) 2950282289Serj return status; 2951315333Serj 2952315333Serj reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE; 2953315333Serj reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK; 2954315333Serj 2955315333Serj /* Select forced link speed for internal PHY. */ 2956315333Serj switch (*speed) { 2957315333Serj case IXGBE_LINK_SPEED_10GB_FULL: 2958315333Serj reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G; 2959315333Serj break; 2960315333Serj case IXGBE_LINK_SPEED_1GB_FULL: 2961315333Serj reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G; 2962315333Serj break; 2963315333Serj default: 2964315333Serj /* Other link speeds are not supported by internal KR PHY. */ 2965315333Serj return IXGBE_ERR_LINK_SETUP; 2966315333Serj } 2967315333Serj 2968315333Serj status = mac->ops.write_iosf_sb_reg(hw, 2969282289Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 2970282289Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 2971315333Serj if (status != IXGBE_SUCCESS) 2972315333Serj return status; 2973282289Serj 2974315333Serj /* Additional configuration needed for x550em_x */ 2975315333Serj if (hw->mac.type == ixgbe_mac_X550EM_x) { 2976315333Serj status = ixgbe_setup_ixfi_x550em_x(hw); 2977315333Serj if (status != IXGBE_SUCCESS) 2978315333Serj return status; 2979315333Serj } 2980315333Serj 2981315333Serj /* Toggle port SW reset by AN reset. */ 2982315333Serj status = ixgbe_restart_an_internal_phy_x550em(hw); 2983315333Serj 2984282289Serj return status; 2985282289Serj} 2986282289Serj 2987282289Serj/** 2988282289Serj * ixgbe_ext_phy_t_x550em_get_link - Get ext phy link status 2989282289Serj * @hw: address of hardware structure 2990282289Serj * @link_up: address of boolean to indicate link status 2991282289Serj * 2992282289Serj * Returns error code if unable to get link status. 2993282289Serj */ 2994282289Serjstatic s32 ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up) 2995282289Serj{ 2996282289Serj u32 ret; 2997282289Serj u16 autoneg_status; 2998282289Serj 2999282289Serj *link_up = FALSE; 3000282289Serj 3001282289Serj /* read this twice back to back to indicate current status */ 3002282289Serj ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, 3003282289Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 3004282289Serj &autoneg_status); 3005282289Serj if (ret != IXGBE_SUCCESS) 3006282289Serj return ret; 3007282289Serj 3008282289Serj ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, 3009282289Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 3010282289Serj &autoneg_status); 3011282289Serj if (ret != IXGBE_SUCCESS) 3012282289Serj return ret; 3013282289Serj 3014282289Serj *link_up = !!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS); 3015282289Serj 3016282289Serj return IXGBE_SUCCESS; 3017282289Serj} 3018282289Serj 3019282289Serj/** 3020282289Serj * ixgbe_setup_internal_phy_t_x550em - Configure KR PHY to X557 link 3021282289Serj * @hw: point to hardware structure 3022282289Serj * 3023282289Serj * Configures the link between the integrated KR PHY and the external X557 PHY 3024282289Serj * The driver will call this function when it gets a link status change 3025282289Serj * interrupt from the X557 PHY. This function configures the link speed 3026282289Serj * between the PHYs to match the link speed of the BASE-T link. 3027282289Serj * 3028282289Serj * A return of a non-zero value indicates an error, and the base driver should 3029282289Serj * not report link up. 3030282289Serj */ 3031282289Serjs32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw) 3032282289Serj{ 3033282289Serj ixgbe_link_speed force_speed; 3034282289Serj bool link_up; 3035282289Serj u32 status; 3036282289Serj u16 speed; 3037282289Serj 3038282289Serj if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper) 3039282289Serj return IXGBE_ERR_CONFIG; 3040282289Serj 3041315333Serj if (hw->mac.type == ixgbe_mac_X550EM_x && 3042315333Serj !(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) { 3043315333Serj /* If link is down, there is no setup necessary so return */ 3044315333Serj status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); 3045315333Serj if (status != IXGBE_SUCCESS) 3046315333Serj return status; 3047282289Serj 3048315333Serj if (!link_up) 3049315333Serj return IXGBE_SUCCESS; 3050282289Serj 3051315333Serj status = hw->phy.ops.read_reg(hw, 3052315333Serj IXGBE_MDIO_AUTO_NEG_VENDOR_STAT, 3053315333Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 3054315333Serj &speed); 3055315333Serj if (status != IXGBE_SUCCESS) 3056315333Serj return status; 3057282289Serj 3058315333Serj /* If link is still down - no setup is required so return */ 3059315333Serj status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); 3060315333Serj if (status != IXGBE_SUCCESS) 3061315333Serj return status; 3062315333Serj if (!link_up) 3063315333Serj return IXGBE_SUCCESS; 3064282289Serj 3065315333Serj /* clear everything but the speed and duplex bits */ 3066315333Serj speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK; 3067282289Serj 3068315333Serj switch (speed) { 3069315333Serj case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB_FULL: 3070315333Serj force_speed = IXGBE_LINK_SPEED_10GB_FULL; 3071315333Serj break; 3072315333Serj case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB_FULL: 3073315333Serj force_speed = IXGBE_LINK_SPEED_1GB_FULL; 3074315333Serj break; 3075315333Serj default: 3076315333Serj /* Internal PHY does not support anything else */ 3077315333Serj return IXGBE_ERR_INVALID_LINK_SETTINGS; 3078315333Serj } 3079315333Serj 3080315333Serj return ixgbe_setup_ixfi_x550em(hw, &force_speed); 3081315333Serj } else { 3082315333Serj speed = IXGBE_LINK_SPEED_10GB_FULL | 3083315333Serj IXGBE_LINK_SPEED_1GB_FULL; 3084315333Serj return ixgbe_setup_kr_speed_x550em(hw, speed); 3085282289Serj } 3086282289Serj} 3087282289Serj 3088282289Serj/** 3089282289Serj * ixgbe_setup_phy_loopback_x550em - Configure the KR PHY for loopback. 3090282289Serj * @hw: pointer to hardware structure 3091282289Serj * 3092282289Serj * Configures the integrated KR PHY to use internal loopback mode. 3093282289Serj **/ 3094282289Serjs32 ixgbe_setup_phy_loopback_x550em(struct ixgbe_hw *hw) 3095282289Serj{ 3096282289Serj s32 status; 3097282289Serj u32 reg_val; 3098282289Serj 3099282289Serj /* Disable AN and force speed to 10G Serial. */ 3100315333Serj status = hw->mac.ops.read_iosf_sb_reg(hw, 3101315333Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 3102315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 3103282289Serj if (status != IXGBE_SUCCESS) 3104282289Serj return status; 3105282289Serj reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE; 3106282289Serj reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK; 3107282289Serj reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G; 3108315333Serj status = hw->mac.ops.write_iosf_sb_reg(hw, 3109315333Serj IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), 3110315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 3111282289Serj if (status != IXGBE_SUCCESS) 3112282289Serj return status; 3113282289Serj 3114282289Serj /* Set near-end loopback clocks. */ 3115315333Serj status = hw->mac.ops.read_iosf_sb_reg(hw, 3116315333Serj IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id), 3117315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 3118282289Serj if (status != IXGBE_SUCCESS) 3119282289Serj return status; 3120282289Serj reg_val |= IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_32B; 3121282289Serj reg_val |= IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_KRPCS; 3122315333Serj status = hw->mac.ops.write_iosf_sb_reg(hw, 3123315333Serj IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id), 3124315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 3125282289Serj if (status != IXGBE_SUCCESS) 3126282289Serj return status; 3127282289Serj 3128282289Serj /* Set loopback enable. */ 3129315333Serj status = hw->mac.ops.read_iosf_sb_reg(hw, 3130315333Serj IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id), 3131315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 3132282289Serj if (status != IXGBE_SUCCESS) 3133282289Serj return status; 3134282289Serj reg_val |= IXGBE_KRM_PMD_DFX_BURNIN_TX_RX_KR_LB_MASK; 3135315333Serj status = hw->mac.ops.write_iosf_sb_reg(hw, 3136315333Serj IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id), 3137315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 3138282289Serj if (status != IXGBE_SUCCESS) 3139282289Serj return status; 3140282289Serj 3141282289Serj /* Training bypass. */ 3142315333Serj status = hw->mac.ops.read_iosf_sb_reg(hw, 3143315333Serj IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id), 3144315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 3145282289Serj if (status != IXGBE_SUCCESS) 3146282289Serj return status; 3147282289Serj reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_PROTOCOL_BYPASS; 3148315333Serj status = hw->mac.ops.write_iosf_sb_reg(hw, 3149315333Serj IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id), 3150315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 3151282289Serj 3152282289Serj return status; 3153282289Serj} 3154282289Serj 3155282289Serj/** 3156282289Serj * ixgbe_read_ee_hostif_X550 - Read EEPROM word using a host interface command 3157282289Serj * assuming that the semaphore is already obtained. 3158282289Serj * @hw: pointer to hardware structure 3159282289Serj * @offset: offset of word in the EEPROM to read 3160282289Serj * @data: word read from the EEPROM 3161282289Serj * 3162282289Serj * Reads a 16 bit word from the EEPROM using the hostif. 3163282289Serj **/ 3164315333Serjs32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) 3165282289Serj{ 3166315333Serj const u32 mask = IXGBE_GSSR_SW_MNG_SM | IXGBE_GSSR_EEP_SM; 3167315333Serj struct ixgbe_hic_read_shadow_ram buffer; 3168282289Serj s32 status; 3169282289Serj 3170315333Serj DEBUGFUNC("ixgbe_read_ee_hostif_X550"); 3171282289Serj buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD; 3172282289Serj buffer.hdr.req.buf_lenh = 0; 3173282289Serj buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN; 3174282289Serj buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM; 3175282289Serj 3176282289Serj /* convert offset from words to bytes */ 3177282289Serj buffer.address = IXGBE_CPU_TO_BE32(offset * 2); 3178282289Serj /* one word */ 3179282289Serj buffer.length = IXGBE_CPU_TO_BE16(sizeof(u16)); 3180282289Serj 3181315333Serj status = hw->mac.ops.acquire_swfw_sync(hw, mask); 3182282289Serj if (status) 3183282289Serj return status; 3184282289Serj 3185315333Serj status = ixgbe_hic_unlocked(hw, (u32 *)&buffer, sizeof(buffer), 3186315333Serj IXGBE_HI_COMMAND_TIMEOUT); 3187315333Serj if (!status) { 3188315333Serj *data = (u16)IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, 3189315333Serj FW_NVM_DATA_OFFSET); 3190282289Serj } 3191282289Serj 3192315333Serj hw->mac.ops.release_swfw_sync(hw, mask); 3193282289Serj return status; 3194282289Serj} 3195282289Serj 3196282289Serj/** 3197282289Serj * ixgbe_read_ee_hostif_buffer_X550- Read EEPROM word(s) using hostif 3198282289Serj * @hw: pointer to hardware structure 3199282289Serj * @offset: offset of word in the EEPROM to read 3200282289Serj * @words: number of words 3201282289Serj * @data: word(s) read from the EEPROM 3202282289Serj * 3203282289Serj * Reads a 16 bit word(s) from the EEPROM using the hostif. 3204282289Serj **/ 3205282289Serjs32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw, 3206282289Serj u16 offset, u16 words, u16 *data) 3207282289Serj{ 3208315333Serj const u32 mask = IXGBE_GSSR_SW_MNG_SM | IXGBE_GSSR_EEP_SM; 3209282289Serj struct ixgbe_hic_read_shadow_ram buffer; 3210282289Serj u32 current_word = 0; 3211282289Serj u16 words_to_read; 3212282289Serj s32 status; 3213282289Serj u32 i; 3214282289Serj 3215282289Serj DEBUGFUNC("ixgbe_read_ee_hostif_buffer_X550"); 3216282289Serj 3217282289Serj /* Take semaphore for the entire operation. */ 3218315333Serj status = hw->mac.ops.acquire_swfw_sync(hw, mask); 3219282289Serj if (status) { 3220282289Serj DEBUGOUT("EEPROM read buffer - semaphore failed\n"); 3221282289Serj return status; 3222282289Serj } 3223315333Serj 3224282289Serj while (words) { 3225282289Serj if (words > FW_MAX_READ_BUFFER_SIZE / 2) 3226282289Serj words_to_read = FW_MAX_READ_BUFFER_SIZE / 2; 3227282289Serj else 3228282289Serj words_to_read = words; 3229282289Serj 3230282289Serj buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD; 3231282289Serj buffer.hdr.req.buf_lenh = 0; 3232282289Serj buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN; 3233282289Serj buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM; 3234282289Serj 3235282289Serj /* convert offset from words to bytes */ 3236282289Serj buffer.address = IXGBE_CPU_TO_BE32((offset + current_word) * 2); 3237282289Serj buffer.length = IXGBE_CPU_TO_BE16(words_to_read * 2); 3238282289Serj 3239315333Serj status = ixgbe_hic_unlocked(hw, (u32 *)&buffer, sizeof(buffer), 3240315333Serj IXGBE_HI_COMMAND_TIMEOUT); 3241282289Serj 3242282289Serj if (status) { 3243282289Serj DEBUGOUT("Host interface command failed\n"); 3244282289Serj goto out; 3245282289Serj } 3246282289Serj 3247282289Serj for (i = 0; i < words_to_read; i++) { 3248282289Serj u32 reg = IXGBE_FLEX_MNG + (FW_NVM_DATA_OFFSET << 2) + 3249282289Serj 2 * i; 3250282289Serj u32 value = IXGBE_READ_REG(hw, reg); 3251282289Serj 3252282289Serj data[current_word] = (u16)(value & 0xffff); 3253282289Serj current_word++; 3254282289Serj i++; 3255282289Serj if (i < words_to_read) { 3256282289Serj value >>= 16; 3257282289Serj data[current_word] = (u16)(value & 0xffff); 3258282289Serj current_word++; 3259282289Serj } 3260282289Serj } 3261282289Serj words -= words_to_read; 3262282289Serj } 3263282289Serj 3264282289Serjout: 3265315333Serj hw->mac.ops.release_swfw_sync(hw, mask); 3266282289Serj return status; 3267282289Serj} 3268282289Serj 3269282289Serj/** 3270282289Serj * ixgbe_write_ee_hostif_X550 - Write EEPROM word using hostif 3271282289Serj * @hw: pointer to hardware structure 3272282289Serj * @offset: offset of word in the EEPROM to write 3273282289Serj * @data: word write to the EEPROM 3274282289Serj * 3275282289Serj * Write a 16 bit word to the EEPROM using the hostif. 3276282289Serj **/ 3277282289Serjs32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, 3278282289Serj u16 data) 3279282289Serj{ 3280282289Serj s32 status; 3281282289Serj struct ixgbe_hic_write_shadow_ram buffer; 3282282289Serj 3283282289Serj DEBUGFUNC("ixgbe_write_ee_hostif_data_X550"); 3284282289Serj 3285282289Serj buffer.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD; 3286282289Serj buffer.hdr.req.buf_lenh = 0; 3287282289Serj buffer.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN; 3288282289Serj buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM; 3289282289Serj 3290282289Serj /* one word */ 3291282289Serj buffer.length = IXGBE_CPU_TO_BE16(sizeof(u16)); 3292282289Serj buffer.data = data; 3293282289Serj buffer.address = IXGBE_CPU_TO_BE32(offset * 2); 3294282289Serj 3295282289Serj status = ixgbe_host_interface_command(hw, (u32 *)&buffer, 3296282289Serj sizeof(buffer), 3297282289Serj IXGBE_HI_COMMAND_TIMEOUT, FALSE); 3298282289Serj 3299282289Serj return status; 3300282289Serj} 3301282289Serj 3302282289Serj/** 3303282289Serj * ixgbe_write_ee_hostif_X550 - Write EEPROM word using hostif 3304282289Serj * @hw: pointer to hardware structure 3305282289Serj * @offset: offset of word in the EEPROM to write 3306282289Serj * @data: word write to the EEPROM 3307282289Serj * 3308282289Serj * Write a 16 bit word to the EEPROM using the hostif. 3309282289Serj **/ 3310282289Serjs32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, 3311282289Serj u16 data) 3312282289Serj{ 3313282289Serj s32 status = IXGBE_SUCCESS; 3314282289Serj 3315282289Serj DEBUGFUNC("ixgbe_write_ee_hostif_X550"); 3316282289Serj 3317282289Serj if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 3318282289Serj IXGBE_SUCCESS) { 3319282289Serj status = ixgbe_write_ee_hostif_data_X550(hw, offset, data); 3320282289Serj hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); 3321282289Serj } else { 3322282289Serj DEBUGOUT("write ee hostif failed to get semaphore"); 3323282289Serj status = IXGBE_ERR_SWFW_SYNC; 3324282289Serj } 3325282289Serj 3326282289Serj return status; 3327282289Serj} 3328282289Serj 3329282289Serj/** 3330282289Serj * ixgbe_write_ee_hostif_buffer_X550 - Write EEPROM word(s) using hostif 3331282289Serj * @hw: pointer to hardware structure 3332282289Serj * @offset: offset of word in the EEPROM to write 3333282289Serj * @words: number of words 3334282289Serj * @data: word(s) write to the EEPROM 3335282289Serj * 3336282289Serj * Write a 16 bit word(s) to the EEPROM using the hostif. 3337282289Serj **/ 3338282289Serjs32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw, 3339282289Serj u16 offset, u16 words, u16 *data) 3340282289Serj{ 3341282289Serj s32 status = IXGBE_SUCCESS; 3342282289Serj u32 i = 0; 3343282289Serj 3344282289Serj DEBUGFUNC("ixgbe_write_ee_hostif_buffer_X550"); 3345282289Serj 3346282289Serj /* Take semaphore for the entire operation. */ 3347282289Serj status = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM); 3348282289Serj if (status != IXGBE_SUCCESS) { 3349282289Serj DEBUGOUT("EEPROM write buffer - semaphore failed\n"); 3350282289Serj goto out; 3351282289Serj } 3352282289Serj 3353282289Serj for (i = 0; i < words; i++) { 3354282289Serj status = ixgbe_write_ee_hostif_data_X550(hw, offset + i, 3355282289Serj data[i]); 3356282289Serj 3357282289Serj if (status != IXGBE_SUCCESS) { 3358282289Serj DEBUGOUT("Eeprom buffered write failed\n"); 3359282289Serj break; 3360282289Serj } 3361282289Serj } 3362282289Serj 3363282289Serj hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); 3364282289Serjout: 3365282289Serj 3366282289Serj return status; 3367282289Serj} 3368282289Serj 3369282289Serj/** 3370282289Serj * ixgbe_checksum_ptr_x550 - Checksum one pointer region 3371282289Serj * @hw: pointer to hardware structure 3372282289Serj * @ptr: pointer offset in eeprom 3373282289Serj * @size: size of section pointed by ptr, if 0 first word will be used as size 3374282289Serj * @csum: address of checksum to update 3375282289Serj * 3376282289Serj * Returns error status for any failure 3377282289Serj */ 3378282289Serjstatic s32 ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr, 3379282289Serj u16 size, u16 *csum, u16 *buffer, 3380282289Serj u32 buffer_size) 3381282289Serj{ 3382282289Serj u16 buf[256]; 3383282289Serj s32 status; 3384282289Serj u16 length, bufsz, i, start; 3385282289Serj u16 *local_buffer; 3386282289Serj 3387282289Serj bufsz = sizeof(buf) / sizeof(buf[0]); 3388282289Serj 3389282289Serj /* Read a chunk at the pointer location */ 3390282289Serj if (!buffer) { 3391282289Serj status = ixgbe_read_ee_hostif_buffer_X550(hw, ptr, bufsz, buf); 3392282289Serj if (status) { 3393282289Serj DEBUGOUT("Failed to read EEPROM image\n"); 3394282289Serj return status; 3395282289Serj } 3396282289Serj local_buffer = buf; 3397282289Serj } else { 3398282289Serj if (buffer_size < ptr) 3399282289Serj return IXGBE_ERR_PARAM; 3400282289Serj local_buffer = &buffer[ptr]; 3401282289Serj } 3402282289Serj 3403282289Serj if (size) { 3404282289Serj start = 0; 3405282289Serj length = size; 3406282289Serj } else { 3407282289Serj start = 1; 3408282289Serj length = local_buffer[0]; 3409282289Serj 3410282289Serj /* Skip pointer section if length is invalid. */ 3411282289Serj if (length == 0xFFFF || length == 0 || 3412282289Serj (ptr + length) >= hw->eeprom.word_size) 3413282289Serj return IXGBE_SUCCESS; 3414282289Serj } 3415282289Serj 3416282289Serj if (buffer && ((u32)start + (u32)length > buffer_size)) 3417282289Serj return IXGBE_ERR_PARAM; 3418282289Serj 3419282289Serj for (i = start; length; i++, length--) { 3420282289Serj if (i == bufsz && !buffer) { 3421282289Serj ptr += bufsz; 3422282289Serj i = 0; 3423282289Serj if (length < bufsz) 3424282289Serj bufsz = length; 3425282289Serj 3426282289Serj /* Read a chunk at the pointer location */ 3427282289Serj status = ixgbe_read_ee_hostif_buffer_X550(hw, ptr, 3428282289Serj bufsz, buf); 3429282289Serj if (status) { 3430282289Serj DEBUGOUT("Failed to read EEPROM image\n"); 3431282289Serj return status; 3432282289Serj } 3433282289Serj } 3434282289Serj *csum += local_buffer[i]; 3435282289Serj } 3436282289Serj return IXGBE_SUCCESS; 3437282289Serj} 3438282289Serj 3439282289Serj/** 3440282289Serj * ixgbe_calc_checksum_X550 - Calculates and returns the checksum 3441282289Serj * @hw: pointer to hardware structure 3442282289Serj * @buffer: pointer to buffer containing calculated checksum 3443282289Serj * @buffer_size: size of buffer 3444282289Serj * 3445282289Serj * Returns a negative error code on error, or the 16-bit checksum 3446282289Serj **/ 3447282289Serjs32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size) 3448282289Serj{ 3449282289Serj u16 eeprom_ptrs[IXGBE_EEPROM_LAST_WORD + 1]; 3450282289Serj u16 *local_buffer; 3451282289Serj s32 status; 3452282289Serj u16 checksum = 0; 3453282289Serj u16 pointer, i, size; 3454282289Serj 3455282289Serj DEBUGFUNC("ixgbe_calc_eeprom_checksum_X550"); 3456282289Serj 3457282289Serj hw->eeprom.ops.init_params(hw); 3458282289Serj 3459282289Serj if (!buffer) { 3460282289Serj /* Read pointer area */ 3461282289Serj status = ixgbe_read_ee_hostif_buffer_X550(hw, 0, 3462282289Serj IXGBE_EEPROM_LAST_WORD + 1, 3463282289Serj eeprom_ptrs); 3464282289Serj if (status) { 3465282289Serj DEBUGOUT("Failed to read EEPROM image\n"); 3466282289Serj return status; 3467282289Serj } 3468282289Serj local_buffer = eeprom_ptrs; 3469282289Serj } else { 3470282289Serj if (buffer_size < IXGBE_EEPROM_LAST_WORD) 3471282289Serj return IXGBE_ERR_PARAM; 3472282289Serj local_buffer = buffer; 3473282289Serj } 3474282289Serj 3475282289Serj /* 3476282289Serj * For X550 hardware include 0x0-0x41 in the checksum, skip the 3477282289Serj * checksum word itself 3478282289Serj */ 3479282289Serj for (i = 0; i <= IXGBE_EEPROM_LAST_WORD; i++) 3480282289Serj if (i != IXGBE_EEPROM_CHECKSUM) 3481282289Serj checksum += local_buffer[i]; 3482282289Serj 3483282289Serj /* 3484282289Serj * Include all data from pointers 0x3, 0x6-0xE. This excludes the 3485282289Serj * FW, PHY module, and PCIe Expansion/Option ROM pointers. 3486282289Serj */ 3487282289Serj for (i = IXGBE_PCIE_ANALOG_PTR_X550; i < IXGBE_FW_PTR; i++) { 3488282289Serj if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR) 3489282289Serj continue; 3490282289Serj 3491282289Serj pointer = local_buffer[i]; 3492282289Serj 3493282289Serj /* Skip pointer section if the pointer is invalid. */ 3494282289Serj if (pointer == 0xFFFF || pointer == 0 || 3495282289Serj pointer >= hw->eeprom.word_size) 3496282289Serj continue; 3497282289Serj 3498282289Serj switch (i) { 3499282289Serj case IXGBE_PCIE_GENERAL_PTR: 3500282289Serj size = IXGBE_IXGBE_PCIE_GENERAL_SIZE; 3501282289Serj break; 3502282289Serj case IXGBE_PCIE_CONFIG0_PTR: 3503282289Serj case IXGBE_PCIE_CONFIG1_PTR: 3504282289Serj size = IXGBE_PCIE_CONFIG_SIZE; 3505282289Serj break; 3506282289Serj default: 3507282289Serj size = 0; 3508282289Serj break; 3509282289Serj } 3510282289Serj 3511282289Serj status = ixgbe_checksum_ptr_x550(hw, pointer, size, &checksum, 3512282289Serj buffer, buffer_size); 3513282289Serj if (status) 3514282289Serj return status; 3515282289Serj } 3516282289Serj 3517282289Serj checksum = (u16)IXGBE_EEPROM_SUM - checksum; 3518282289Serj 3519282289Serj return (s32)checksum; 3520282289Serj} 3521282289Serj 3522282289Serj/** 3523282289Serj * ixgbe_calc_eeprom_checksum_X550 - Calculates and returns the checksum 3524282289Serj * @hw: pointer to hardware structure 3525282289Serj * 3526282289Serj * Returns a negative error code on error, or the 16-bit checksum 3527282289Serj **/ 3528282289Serjs32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw) 3529282289Serj{ 3530282289Serj return ixgbe_calc_checksum_X550(hw, NULL, 0); 3531282289Serj} 3532282289Serj 3533282289Serj/** 3534282289Serj * ixgbe_validate_eeprom_checksum_X550 - Validate EEPROM checksum 3535282289Serj * @hw: pointer to hardware structure 3536282289Serj * @checksum_val: calculated checksum 3537282289Serj * 3538282289Serj * Performs checksum calculation and validates the EEPROM checksum. If the 3539282289Serj * caller does not need checksum_val, the value can be NULL. 3540282289Serj **/ 3541282289Serjs32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val) 3542282289Serj{ 3543282289Serj s32 status; 3544282289Serj u16 checksum; 3545282289Serj u16 read_checksum = 0; 3546282289Serj 3547282289Serj DEBUGFUNC("ixgbe_validate_eeprom_checksum_X550"); 3548282289Serj 3549282289Serj /* Read the first word from the EEPROM. If this times out or fails, do 3550282289Serj * not continue or we could be in for a very long wait while every 3551282289Serj * EEPROM read fails 3552282289Serj */ 3553282289Serj status = hw->eeprom.ops.read(hw, 0, &checksum); 3554282289Serj if (status) { 3555282289Serj DEBUGOUT("EEPROM read failed\n"); 3556282289Serj return status; 3557282289Serj } 3558282289Serj 3559282289Serj status = hw->eeprom.ops.calc_checksum(hw); 3560282289Serj if (status < 0) 3561282289Serj return status; 3562282289Serj 3563282289Serj checksum = (u16)(status & 0xffff); 3564282289Serj 3565282289Serj status = ixgbe_read_ee_hostif_X550(hw, IXGBE_EEPROM_CHECKSUM, 3566282289Serj &read_checksum); 3567282289Serj if (status) 3568282289Serj return status; 3569282289Serj 3570282289Serj /* Verify read checksum from EEPROM is the same as 3571282289Serj * calculated checksum 3572282289Serj */ 3573282289Serj if (read_checksum != checksum) { 3574282289Serj status = IXGBE_ERR_EEPROM_CHECKSUM; 3575282289Serj ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE, 3576282289Serj "Invalid EEPROM checksum"); 3577282289Serj } 3578282289Serj 3579282289Serj /* If the user cares, return the calculated checksum */ 3580282289Serj if (checksum_val) 3581282289Serj *checksum_val = checksum; 3582282289Serj 3583282289Serj return status; 3584282289Serj} 3585282289Serj 3586282289Serj/** 3587282289Serj * ixgbe_update_eeprom_checksum_X550 - Updates the EEPROM checksum and flash 3588282289Serj * @hw: pointer to hardware structure 3589282289Serj * 3590282289Serj * After writing EEPROM to shadow RAM using EEWR register, software calculates 3591282289Serj * checksum and updates the EEPROM and instructs the hardware to update 3592282289Serj * the flash. 3593282289Serj **/ 3594282289Serjs32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw) 3595282289Serj{ 3596282289Serj s32 status; 3597282289Serj u16 checksum = 0; 3598282289Serj 3599282289Serj DEBUGFUNC("ixgbe_update_eeprom_checksum_X550"); 3600282289Serj 3601282289Serj /* Read the first word from the EEPROM. If this times out or fails, do 3602282289Serj * not continue or we could be in for a very long wait while every 3603282289Serj * EEPROM read fails 3604282289Serj */ 3605282289Serj status = ixgbe_read_ee_hostif_X550(hw, 0, &checksum); 3606282289Serj if (status) { 3607282289Serj DEBUGOUT("EEPROM read failed\n"); 3608282289Serj return status; 3609282289Serj } 3610282289Serj 3611282289Serj status = ixgbe_calc_eeprom_checksum_X550(hw); 3612282289Serj if (status < 0) 3613282289Serj return status; 3614282289Serj 3615282289Serj checksum = (u16)(status & 0xffff); 3616282289Serj 3617282289Serj status = ixgbe_write_ee_hostif_X550(hw, IXGBE_EEPROM_CHECKSUM, 3618282289Serj checksum); 3619282289Serj if (status) 3620282289Serj return status; 3621282289Serj 3622282289Serj status = ixgbe_update_flash_X550(hw); 3623282289Serj 3624282289Serj return status; 3625282289Serj} 3626282289Serj 3627282289Serj/** 3628282289Serj * ixgbe_update_flash_X550 - Instruct HW to copy EEPROM to Flash device 3629282289Serj * @hw: pointer to hardware structure 3630282289Serj * 3631282289Serj * Issue a shadow RAM dump to FW to copy EEPROM from shadow RAM to the flash. 3632282289Serj **/ 3633282289Serjs32 ixgbe_update_flash_X550(struct ixgbe_hw *hw) 3634282289Serj{ 3635282289Serj s32 status = IXGBE_SUCCESS; 3636282289Serj union ixgbe_hic_hdr2 buffer; 3637282289Serj 3638282289Serj DEBUGFUNC("ixgbe_update_flash_X550"); 3639282289Serj 3640282289Serj buffer.req.cmd = FW_SHADOW_RAM_DUMP_CMD; 3641282289Serj buffer.req.buf_lenh = 0; 3642282289Serj buffer.req.buf_lenl = FW_SHADOW_RAM_DUMP_LEN; 3643282289Serj buffer.req.checksum = FW_DEFAULT_CHECKSUM; 3644282289Serj 3645282289Serj status = ixgbe_host_interface_command(hw, (u32 *)&buffer, 3646282289Serj sizeof(buffer), 3647282289Serj IXGBE_HI_COMMAND_TIMEOUT, FALSE); 3648282289Serj 3649282289Serj return status; 3650282289Serj} 3651282289Serj 3652282289Serj/** 3653282289Serj * ixgbe_get_supported_physical_layer_X550em - Returns physical layer type 3654282289Serj * @hw: pointer to hardware structure 3655282289Serj * 3656282289Serj * Determines physical layer capabilities of the current configuration. 3657282289Serj **/ 3658282289Serju32 ixgbe_get_supported_physical_layer_X550em(struct ixgbe_hw *hw) 3659282289Serj{ 3660282289Serj u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; 3661282289Serj u16 ext_ability = 0; 3662282289Serj 3663282289Serj DEBUGFUNC("ixgbe_get_supported_physical_layer_X550em"); 3664282289Serj 3665282289Serj hw->phy.ops.identify(hw); 3666282289Serj 3667282289Serj switch (hw->phy.type) { 3668282289Serj case ixgbe_phy_x550em_kr: 3669315333Serj case ixgbe_phy_x550em_xfi: 3670282289Serj physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KR | 3671282289Serj IXGBE_PHYSICAL_LAYER_1000BASE_KX; 3672282289Serj break; 3673282289Serj case ixgbe_phy_x550em_kx4: 3674282289Serj physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | 3675282289Serj IXGBE_PHYSICAL_LAYER_1000BASE_KX; 3676282289Serj break; 3677282289Serj case ixgbe_phy_x550em_ext_t: 3678282289Serj hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY, 3679282289Serj IXGBE_MDIO_PMA_PMD_DEV_TYPE, 3680282289Serj &ext_ability); 3681282289Serj if (ext_ability & IXGBE_MDIO_PHY_10GBASET_ABILITY) 3682282289Serj physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T; 3683282289Serj if (ext_ability & IXGBE_MDIO_PHY_1000BASET_ABILITY) 3684282289Serj physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; 3685282289Serj break; 3686315333Serj case ixgbe_phy_fw: 3687315333Serj if (hw->phy.speeds_supported & IXGBE_LINK_SPEED_1GB_FULL) 3688315333Serj physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; 3689315333Serj if (hw->phy.speeds_supported & IXGBE_LINK_SPEED_100_FULL) 3690315333Serj physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX; 3691315333Serj if (hw->phy.speeds_supported & IXGBE_LINK_SPEED_10_FULL) 3692315333Serj physical_layer |= IXGBE_PHYSICAL_LAYER_10BASE_T; 3693315333Serj break; 3694315333Serj case ixgbe_phy_sgmii: 3695315333Serj physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_KX; 3696315333Serj break; 3697282289Serj default: 3698282289Serj break; 3699282289Serj } 3700282289Serj 3701282289Serj if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) 3702282289Serj physical_layer = ixgbe_get_supported_phy_sfp_layer_generic(hw); 3703282289Serj 3704282289Serj return physical_layer; 3705282289Serj} 3706282289Serj 3707282289Serj/** 3708282289Serj * ixgbe_get_bus_info_x550em - Set PCI bus info 3709282289Serj * @hw: pointer to hardware structure 3710282289Serj * 3711282289Serj * Sets bus link width and speed to unknown because X550em is 3712282289Serj * not a PCI device. 3713282289Serj **/ 3714282289Serjs32 ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw) 3715282289Serj{ 3716282289Serj 3717282289Serj DEBUGFUNC("ixgbe_get_bus_info_x550em"); 3718282289Serj 3719282289Serj hw->bus.width = ixgbe_bus_width_unknown; 3720282289Serj hw->bus.speed = ixgbe_bus_speed_unknown; 3721282289Serj 3722282289Serj hw->mac.ops.set_lan_id(hw); 3723282289Serj 3724282289Serj return IXGBE_SUCCESS; 3725282289Serj} 3726282289Serj 3727282289Serj/** 3728282289Serj * ixgbe_disable_rx_x550 - Disable RX unit 3729282289Serj * 3730282289Serj * Enables the Rx DMA unit for x550 3731282289Serj **/ 3732282289Serjvoid ixgbe_disable_rx_x550(struct ixgbe_hw *hw) 3733282289Serj{ 3734282289Serj u32 rxctrl, pfdtxgswc; 3735282289Serj s32 status; 3736282289Serj struct ixgbe_hic_disable_rxen fw_cmd; 3737282289Serj 3738282289Serj DEBUGFUNC("ixgbe_enable_rx_dma_x550"); 3739282289Serj 3740282289Serj rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); 3741282289Serj if (rxctrl & IXGBE_RXCTRL_RXEN) { 3742282289Serj pfdtxgswc = IXGBE_READ_REG(hw, IXGBE_PFDTXGSWC); 3743282289Serj if (pfdtxgswc & IXGBE_PFDTXGSWC_VT_LBEN) { 3744282289Serj pfdtxgswc &= ~IXGBE_PFDTXGSWC_VT_LBEN; 3745282289Serj IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, pfdtxgswc); 3746282289Serj hw->mac.set_lben = TRUE; 3747282289Serj } else { 3748282289Serj hw->mac.set_lben = FALSE; 3749282289Serj } 3750282289Serj 3751282289Serj fw_cmd.hdr.cmd = FW_DISABLE_RXEN_CMD; 3752282289Serj fw_cmd.hdr.buf_len = FW_DISABLE_RXEN_LEN; 3753282289Serj fw_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM; 3754282289Serj fw_cmd.port_number = (u8)hw->bus.lan_id; 3755282289Serj 3756282289Serj status = ixgbe_host_interface_command(hw, (u32 *)&fw_cmd, 3757282289Serj sizeof(struct ixgbe_hic_disable_rxen), 3758282289Serj IXGBE_HI_COMMAND_TIMEOUT, TRUE); 3759282289Serj 3760282289Serj /* If we fail - disable RX using register write */ 3761282289Serj if (status) { 3762282289Serj rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); 3763282289Serj if (rxctrl & IXGBE_RXCTRL_RXEN) { 3764282289Serj rxctrl &= ~IXGBE_RXCTRL_RXEN; 3765282289Serj IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl); 3766282289Serj } 3767282289Serj } 3768282289Serj } 3769282289Serj} 3770282289Serj 3771282289Serj/** 3772282289Serj * ixgbe_enter_lplu_x550em - Transition to low power states 3773282289Serj * @hw: pointer to hardware structure 3774282289Serj * 3775282289Serj * Configures Low Power Link Up on transition to low power states 3776282289Serj * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting the 3777282289Serj * X557 PHY immediately prior to entering LPLU. 3778282289Serj **/ 3779282289Serjs32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw) 3780282289Serj{ 3781282289Serj u16 an_10g_cntl_reg, autoneg_reg, speed; 3782282289Serj s32 status; 3783282289Serj ixgbe_link_speed lcd_speed; 3784282289Serj u32 save_autoneg; 3785282289Serj bool link_up; 3786282289Serj 3787295524Ssbruno /* SW LPLU not required on later HW revisions. */ 3788315333Serj if ((hw->mac.type == ixgbe_mac_X550EM_x) && 3789315333Serj (IXGBE_FUSES0_REV_MASK & 3790315333Serj IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0)))) 3791295524Ssbruno return IXGBE_SUCCESS; 3792295524Ssbruno 3793282289Serj /* If blocked by MNG FW, then don't restart AN */ 3794282289Serj if (ixgbe_check_reset_blocked(hw)) 3795282289Serj return IXGBE_SUCCESS; 3796282289Serj 3797282289Serj status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); 3798282289Serj if (status != IXGBE_SUCCESS) 3799282289Serj return status; 3800282289Serj 3801282289Serj status = ixgbe_read_eeprom(hw, NVM_INIT_CTRL_3, &hw->eeprom.ctrl_word_3); 3802282289Serj 3803282289Serj if (status != IXGBE_SUCCESS) 3804282289Serj return status; 3805282289Serj 3806282289Serj /* If link is down, LPLU disabled in NVM, WoL disabled, or manageability 3807282289Serj * disabled, then force link down by entering low power mode. 3808282289Serj */ 3809282289Serj if (!link_up || !(hw->eeprom.ctrl_word_3 & NVM_INIT_CTRL_3_LPLU) || 3810282289Serj !(hw->wol_enabled || ixgbe_mng_present(hw))) 3811282289Serj return ixgbe_set_copper_phy_power(hw, FALSE); 3812282289Serj 3813282289Serj /* Determine LCD */ 3814282289Serj status = ixgbe_get_lcd_t_x550em(hw, &lcd_speed); 3815282289Serj 3816282289Serj if (status != IXGBE_SUCCESS) 3817282289Serj return status; 3818282289Serj 3819282289Serj /* If no valid LCD link speed, then force link down and exit. */ 3820282289Serj if (lcd_speed == IXGBE_LINK_SPEED_UNKNOWN) 3821282289Serj return ixgbe_set_copper_phy_power(hw, FALSE); 3822282289Serj 3823282289Serj status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT, 3824282289Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 3825282289Serj &speed); 3826282289Serj 3827282289Serj if (status != IXGBE_SUCCESS) 3828282289Serj return status; 3829282289Serj 3830282289Serj /* If no link now, speed is invalid so take link down */ 3831282289Serj status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); 3832282289Serj if (status != IXGBE_SUCCESS) 3833282289Serj return ixgbe_set_copper_phy_power(hw, FALSE); 3834282289Serj 3835282289Serj /* clear everything but the speed bits */ 3836282289Serj speed &= IXGBE_MDIO_AUTO_NEG_VEN_STAT_SPEED_MASK; 3837282289Serj 3838282289Serj /* If current speed is already LCD, then exit. */ 3839282289Serj if (((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB) && 3840282289Serj (lcd_speed == IXGBE_LINK_SPEED_1GB_FULL)) || 3841282289Serj ((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB) && 3842282289Serj (lcd_speed == IXGBE_LINK_SPEED_10GB_FULL))) 3843282289Serj return status; 3844282289Serj 3845282289Serj /* Clear AN completed indication */ 3846282289Serj status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM, 3847282289Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 3848282289Serj &autoneg_reg); 3849282289Serj 3850282289Serj if (status != IXGBE_SUCCESS) 3851282289Serj return status; 3852282289Serj 3853282289Serj status = hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, 3854282289Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 3855282289Serj &an_10g_cntl_reg); 3856282289Serj 3857282289Serj if (status != IXGBE_SUCCESS) 3858282289Serj return status; 3859282289Serj 3860282289Serj status = hw->phy.ops.read_reg(hw, 3861282289Serj IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, 3862282289Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 3863282289Serj &autoneg_reg); 3864282289Serj 3865282289Serj if (status != IXGBE_SUCCESS) 3866282289Serj return status; 3867282289Serj 3868282289Serj save_autoneg = hw->phy.autoneg_advertised; 3869282289Serj 3870282289Serj /* Setup link at least common link speed */ 3871282289Serj status = hw->mac.ops.setup_link(hw, lcd_speed, FALSE); 3872282289Serj 3873282289Serj /* restore autoneg from before setting lplu speed */ 3874282289Serj hw->phy.autoneg_advertised = save_autoneg; 3875282289Serj 3876282289Serj return status; 3877282289Serj} 3878282289Serj 3879282289Serj/** 3880282289Serj * ixgbe_get_lcd_x550em - Determine lowest common denominator 3881282289Serj * @hw: pointer to hardware structure 3882282289Serj * @lcd_speed: pointer to lowest common link speed 3883282289Serj * 3884282289Serj * Determine lowest common link speed with link partner. 3885282289Serj **/ 3886282289Serjs32 ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *lcd_speed) 3887282289Serj{ 3888282289Serj u16 an_lp_status; 3889282289Serj s32 status; 3890282289Serj u16 word = hw->eeprom.ctrl_word_3; 3891282289Serj 3892282289Serj *lcd_speed = IXGBE_LINK_SPEED_UNKNOWN; 3893282289Serj 3894282289Serj status = hw->phy.ops.read_reg(hw, IXGBE_AUTO_NEG_LP_STATUS, 3895282289Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 3896282289Serj &an_lp_status); 3897282289Serj 3898282289Serj if (status != IXGBE_SUCCESS) 3899282289Serj return status; 3900282289Serj 3901282289Serj /* If link partner advertised 1G, return 1G */ 3902282289Serj if (an_lp_status & IXGBE_AUTO_NEG_LP_1000BASE_CAP) { 3903282289Serj *lcd_speed = IXGBE_LINK_SPEED_1GB_FULL; 3904282289Serj return status; 3905282289Serj } 3906282289Serj 3907282289Serj /* If 10G disabled for LPLU via NVM D10GMP, then return no valid LCD */ 3908282289Serj if ((hw->bus.lan_id && (word & NVM_INIT_CTRL_3_D10GMP_PORT1)) || 3909282289Serj (word & NVM_INIT_CTRL_3_D10GMP_PORT0)) 3910282289Serj return status; 3911282289Serj 3912282289Serj /* Link partner not capable of lower speeds, return 10G */ 3913282289Serj *lcd_speed = IXGBE_LINK_SPEED_10GB_FULL; 3914282289Serj return status; 3915282289Serj} 3916282289Serj 3917282289Serj/** 3918282289Serj * ixgbe_setup_fc_X550em - Set up flow control 3919282289Serj * @hw: pointer to hardware structure 3920282289Serj * 3921282289Serj * Called at init time to set up flow control. 3922282289Serj **/ 3923282289Serjs32 ixgbe_setup_fc_X550em(struct ixgbe_hw *hw) 3924282289Serj{ 3925282289Serj s32 ret_val = IXGBE_SUCCESS; 3926282289Serj u32 pause, asm_dir, reg_val; 3927282289Serj 3928282289Serj DEBUGFUNC("ixgbe_setup_fc_X550em"); 3929282289Serj 3930282289Serj /* Validate the requested mode */ 3931282289Serj if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { 3932282289Serj ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED, 3933282289Serj "ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); 3934282289Serj ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; 3935282289Serj goto out; 3936282289Serj } 3937282289Serj 3938282289Serj /* 10gig parts do not have a word in the EEPROM to determine the 3939282289Serj * default flow control setting, so we explicitly set it to full. 3940282289Serj */ 3941282289Serj if (hw->fc.requested_mode == ixgbe_fc_default) 3942282289Serj hw->fc.requested_mode = ixgbe_fc_full; 3943282289Serj 3944282289Serj /* Determine PAUSE and ASM_DIR bits. */ 3945282289Serj switch (hw->fc.requested_mode) { 3946282289Serj case ixgbe_fc_none: 3947282289Serj pause = 0; 3948282289Serj asm_dir = 0; 3949282289Serj break; 3950282289Serj case ixgbe_fc_tx_pause: 3951282289Serj pause = 0; 3952282289Serj asm_dir = 1; 3953282289Serj break; 3954282289Serj case ixgbe_fc_rx_pause: 3955282289Serj /* Rx Flow control is enabled and Tx Flow control is 3956282289Serj * disabled by software override. Since there really 3957282289Serj * isn't a way to advertise that we are capable of RX 3958282289Serj * Pause ONLY, we will advertise that we support both 3959282289Serj * symmetric and asymmetric Rx PAUSE, as such we fall 3960282289Serj * through to the fc_full statement. Later, we will 3961282289Serj * disable the adapter's ability to send PAUSE frames. 3962282289Serj */ 3963282289Serj case ixgbe_fc_full: 3964282289Serj pause = 1; 3965282289Serj asm_dir = 1; 3966282289Serj break; 3967282289Serj default: 3968282289Serj ERROR_REPORT1(IXGBE_ERROR_ARGUMENT, 3969282289Serj "Flow control param set incorrectly\n"); 3970282289Serj ret_val = IXGBE_ERR_CONFIG; 3971282289Serj goto out; 3972282289Serj } 3973282289Serj 3974315333Serj switch (hw->device_id) { 3975315333Serj case IXGBE_DEV_ID_X550EM_X_KR: 3976315333Serj case IXGBE_DEV_ID_X550EM_A_KR: 3977315333Serj case IXGBE_DEV_ID_X550EM_A_KR_L: 3978315333Serj ret_val = hw->mac.ops.read_iosf_sb_reg(hw, 3979315333Serj IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), 3980315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); 3981282289Serj if (ret_val != IXGBE_SUCCESS) 3982282289Serj goto out; 3983282289Serj reg_val &= ~(IXGBE_KRM_AN_CNTL_1_SYM_PAUSE | 3984282289Serj IXGBE_KRM_AN_CNTL_1_ASM_PAUSE); 3985282289Serj if (pause) 3986282289Serj reg_val |= IXGBE_KRM_AN_CNTL_1_SYM_PAUSE; 3987282289Serj if (asm_dir) 3988282289Serj reg_val |= IXGBE_KRM_AN_CNTL_1_ASM_PAUSE; 3989315333Serj ret_val = hw->mac.ops.write_iosf_sb_reg(hw, 3990315333Serj IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), 3991315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); 3992282289Serj 3993295524Ssbruno /* This device does not fully support AN. */ 3994295524Ssbruno hw->fc.disable_fc_autoneg = TRUE; 3995315333Serj break; 3996315333Serj default: 3997315333Serj break; 3998282289Serj } 3999282289Serj 4000282289Serjout: 4001282289Serj return ret_val; 4002282289Serj} 4003282289Serj 4004282289Serj/** 4005315333Serj * ixgbe_fc_autoneg_backplane_x550em_a - Enable flow control IEEE clause 37 4006315333Serj * @hw: pointer to hardware structure 4007315333Serj * 4008315333Serj * Enable flow control according to IEEE clause 37. 4009315333Serj **/ 4010315333Serjvoid ixgbe_fc_autoneg_backplane_x550em_a(struct ixgbe_hw *hw) 4011315333Serj{ 4012315333Serj u32 link_s1, lp_an_page_low, an_cntl_1; 4013315333Serj s32 status = IXGBE_ERR_FC_NOT_NEGOTIATED; 4014315333Serj ixgbe_link_speed speed; 4015315333Serj bool link_up; 4016315333Serj 4017315333Serj /* AN should have completed when the cable was plugged in. 4018315333Serj * Look for reasons to bail out. Bail out if: 4019315333Serj * - FC autoneg is disabled, or if 4020315333Serj * - link is not up. 4021315333Serj */ 4022315333Serj if (hw->fc.disable_fc_autoneg) { 4023315333Serj ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED, 4024315333Serj "Flow control autoneg is disabled"); 4025315333Serj goto out; 4026315333Serj } 4027315333Serj 4028315333Serj hw->mac.ops.check_link(hw, &speed, &link_up, FALSE); 4029315333Serj if (!link_up) { 4030315333Serj ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, "The link is down"); 4031315333Serj goto out; 4032315333Serj } 4033315333Serj 4034315333Serj /* Check at auto-negotiation has completed */ 4035315333Serj status = hw->mac.ops.read_iosf_sb_reg(hw, 4036315333Serj IXGBE_KRM_LINK_S1(hw->bus.lan_id), 4037315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, &link_s1); 4038315333Serj 4039315333Serj if (status != IXGBE_SUCCESS || 4040315333Serj (link_s1 & IXGBE_KRM_LINK_S1_MAC_AN_COMPLETE) == 0) { 4041315333Serj DEBUGOUT("Auto-Negotiation did not complete\n"); 4042315333Serj status = IXGBE_ERR_FC_NOT_NEGOTIATED; 4043315333Serj goto out; 4044315333Serj } 4045315333Serj 4046315333Serj /* Read the 10g AN autoc and LP ability registers and resolve 4047315333Serj * local flow control settings accordingly 4048315333Serj */ 4049315333Serj status = hw->mac.ops.read_iosf_sb_reg(hw, 4050315333Serj IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), 4051315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, &an_cntl_1); 4052315333Serj 4053315333Serj if (status != IXGBE_SUCCESS) { 4054315333Serj DEBUGOUT("Auto-Negotiation did not complete\n"); 4055315333Serj goto out; 4056315333Serj } 4057315333Serj 4058315333Serj status = hw->mac.ops.read_iosf_sb_reg(hw, 4059315333Serj IXGBE_KRM_LP_BASE_PAGE_HIGH(hw->bus.lan_id), 4060315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, &lp_an_page_low); 4061315333Serj 4062315333Serj if (status != IXGBE_SUCCESS) { 4063315333Serj DEBUGOUT("Auto-Negotiation did not complete\n"); 4064315333Serj goto out; 4065315333Serj } 4066315333Serj 4067315333Serj status = ixgbe_negotiate_fc(hw, an_cntl_1, lp_an_page_low, 4068315333Serj IXGBE_KRM_AN_CNTL_1_SYM_PAUSE, 4069315333Serj IXGBE_KRM_AN_CNTL_1_ASM_PAUSE, 4070315333Serj IXGBE_KRM_LP_BASE_PAGE_HIGH_SYM_PAUSE, 4071315333Serj IXGBE_KRM_LP_BASE_PAGE_HIGH_ASM_PAUSE); 4072315333Serj 4073315333Serjout: 4074315333Serj if (status == IXGBE_SUCCESS) { 4075315333Serj hw->fc.fc_was_autonegged = TRUE; 4076315333Serj } else { 4077315333Serj hw->fc.fc_was_autonegged = FALSE; 4078315333Serj hw->fc.current_mode = hw->fc.requested_mode; 4079315333Serj } 4080315333Serj} 4081315333Serj 4082315333Serj/** 4083315333Serj * ixgbe_fc_autoneg_fiber_x550em_a - passthrough FC settings 4084315333Serj * @hw: pointer to hardware structure 4085315333Serj * 4086315333Serj **/ 4087315333Serjvoid ixgbe_fc_autoneg_fiber_x550em_a(struct ixgbe_hw *hw) 4088315333Serj{ 4089315333Serj hw->fc.fc_was_autonegged = FALSE; 4090315333Serj hw->fc.current_mode = hw->fc.requested_mode; 4091315333Serj} 4092315333Serj 4093315333Serj/** 4094315333Serj * ixgbe_fc_autoneg_sgmii_x550em_a - Enable flow control IEEE clause 37 4095315333Serj * @hw: pointer to hardware structure 4096315333Serj * 4097315333Serj * Enable flow control according to IEEE clause 37. 4098315333Serj **/ 4099315333Serjvoid ixgbe_fc_autoneg_sgmii_x550em_a(struct ixgbe_hw *hw) 4100315333Serj{ 4101315333Serj s32 status = IXGBE_ERR_FC_NOT_NEGOTIATED; 4102315333Serj u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 }; 4103315333Serj ixgbe_link_speed speed; 4104315333Serj bool link_up; 4105315333Serj 4106315333Serj /* AN should have completed when the cable was plugged in. 4107315333Serj * Look for reasons to bail out. Bail out if: 4108315333Serj * - FC autoneg is disabled, or if 4109315333Serj * - link is not up. 4110315333Serj */ 4111315333Serj if (hw->fc.disable_fc_autoneg) { 4112315333Serj ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED, 4113315333Serj "Flow control autoneg is disabled"); 4114315333Serj goto out; 4115315333Serj } 4116315333Serj 4117315333Serj hw->mac.ops.check_link(hw, &speed, &link_up, FALSE); 4118315333Serj if (!link_up) { 4119315333Serj ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, "The link is down"); 4120315333Serj goto out; 4121315333Serj } 4122315333Serj 4123315333Serj /* Check if auto-negotiation has completed */ 4124315333Serj status = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &info); 4125315333Serj if (status != IXGBE_SUCCESS || 4126315333Serj !(info[0] & FW_PHY_ACT_GET_LINK_INFO_AN_COMPLETE)) { 4127315333Serj DEBUGOUT("Auto-Negotiation did not complete\n"); 4128315333Serj status = IXGBE_ERR_FC_NOT_NEGOTIATED; 4129315333Serj goto out; 4130315333Serj } 4131315333Serj 4132315333Serj /* Negotiate the flow control */ 4133315333Serj status = ixgbe_negotiate_fc(hw, info[0], info[0], 4134315333Serj FW_PHY_ACT_GET_LINK_INFO_FC_RX, 4135315333Serj FW_PHY_ACT_GET_LINK_INFO_FC_TX, 4136315333Serj FW_PHY_ACT_GET_LINK_INFO_LP_FC_RX, 4137315333Serj FW_PHY_ACT_GET_LINK_INFO_LP_FC_TX); 4138315333Serj 4139315333Serjout: 4140315333Serj if (status == IXGBE_SUCCESS) { 4141315333Serj hw->fc.fc_was_autonegged = TRUE; 4142315333Serj } else { 4143315333Serj hw->fc.fc_was_autonegged = FALSE; 4144315333Serj hw->fc.current_mode = hw->fc.requested_mode; 4145315333Serj } 4146315333Serj} 4147315333Serj 4148315333Serj/** 4149315333Serj * ixgbe_setup_fc_backplane_x550em_a - Set up flow control 4150315333Serj * @hw: pointer to hardware structure 4151315333Serj * 4152315333Serj * Called at init time to set up flow control. 4153315333Serj **/ 4154315333Serjs32 ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *hw) 4155315333Serj{ 4156315333Serj s32 status = IXGBE_SUCCESS; 4157315333Serj u32 an_cntl = 0; 4158315333Serj 4159315333Serj DEBUGFUNC("ixgbe_setup_fc_backplane_x550em_a"); 4160315333Serj 4161315333Serj /* Validate the requested mode */ 4162315333Serj if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { 4163315333Serj ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED, 4164315333Serj "ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); 4165315333Serj return IXGBE_ERR_INVALID_LINK_SETTINGS; 4166315333Serj } 4167315333Serj 4168315333Serj if (hw->fc.requested_mode == ixgbe_fc_default) 4169315333Serj hw->fc.requested_mode = ixgbe_fc_full; 4170315333Serj 4171315333Serj /* Set up the 1G and 10G flow control advertisement registers so the 4172315333Serj * HW will be able to do FC autoneg once the cable is plugged in. If 4173315333Serj * we link at 10G, the 1G advertisement is harmless and vice versa. 4174315333Serj */ 4175315333Serj status = hw->mac.ops.read_iosf_sb_reg(hw, 4176315333Serj IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), 4177315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, &an_cntl); 4178315333Serj 4179315333Serj if (status != IXGBE_SUCCESS) { 4180315333Serj DEBUGOUT("Auto-Negotiation did not complete\n"); 4181315333Serj return status; 4182315333Serj } 4183315333Serj 4184315333Serj /* The possible values of fc.requested_mode are: 4185315333Serj * 0: Flow control is completely disabled 4186315333Serj * 1: Rx flow control is enabled (we can receive pause frames, 4187315333Serj * but not send pause frames). 4188315333Serj * 2: Tx flow control is enabled (we can send pause frames but 4189315333Serj * we do not support receiving pause frames). 4190315333Serj * 3: Both Rx and Tx flow control (symmetric) are enabled. 4191315333Serj * other: Invalid. 4192315333Serj */ 4193315333Serj switch (hw->fc.requested_mode) { 4194315333Serj case ixgbe_fc_none: 4195315333Serj /* Flow control completely disabled by software override. */ 4196315333Serj an_cntl &= ~(IXGBE_KRM_AN_CNTL_1_SYM_PAUSE | 4197315333Serj IXGBE_KRM_AN_CNTL_1_ASM_PAUSE); 4198315333Serj break; 4199315333Serj case ixgbe_fc_tx_pause: 4200315333Serj /* Tx Flow control is enabled, and Rx Flow control is 4201315333Serj * disabled by software override. 4202315333Serj */ 4203315333Serj an_cntl |= IXGBE_KRM_AN_CNTL_1_ASM_PAUSE; 4204315333Serj an_cntl &= ~IXGBE_KRM_AN_CNTL_1_SYM_PAUSE; 4205315333Serj break; 4206315333Serj case ixgbe_fc_rx_pause: 4207315333Serj /* Rx Flow control is enabled and Tx Flow control is 4208315333Serj * disabled by software override. Since there really 4209315333Serj * isn't a way to advertise that we are capable of RX 4210315333Serj * Pause ONLY, we will advertise that we support both 4211315333Serj * symmetric and asymmetric Rx PAUSE, as such we fall 4212315333Serj * through to the fc_full statement. Later, we will 4213315333Serj * disable the adapter's ability to send PAUSE frames. 4214315333Serj */ 4215315333Serj case ixgbe_fc_full: 4216315333Serj /* Flow control (both Rx and Tx) is enabled by SW override. */ 4217315333Serj an_cntl |= IXGBE_KRM_AN_CNTL_1_SYM_PAUSE | 4218315333Serj IXGBE_KRM_AN_CNTL_1_ASM_PAUSE; 4219315333Serj break; 4220315333Serj default: 4221315333Serj ERROR_REPORT1(IXGBE_ERROR_ARGUMENT, 4222315333Serj "Flow control param set incorrectly\n"); 4223315333Serj return IXGBE_ERR_CONFIG; 4224315333Serj } 4225315333Serj 4226315333Serj status = hw->mac.ops.write_iosf_sb_reg(hw, 4227315333Serj IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), 4228315333Serj IXGBE_SB_IOSF_TARGET_KR_PHY, an_cntl); 4229315333Serj 4230315333Serj /* Restart auto-negotiation. */ 4231315333Serj status = ixgbe_restart_an_internal_phy_x550em(hw); 4232315333Serj 4233315333Serj return status; 4234315333Serj} 4235315333Serj 4236315333Serj/** 4237282289Serj * ixgbe_set_mux - Set mux for port 1 access with CS4227 4238282289Serj * @hw: pointer to hardware structure 4239282289Serj * @state: set mux if 1, clear if 0 4240282289Serj */ 4241282289Serjstatic void ixgbe_set_mux(struct ixgbe_hw *hw, u8 state) 4242282289Serj{ 4243282289Serj u32 esdp; 4244282289Serj 4245282289Serj if (!hw->bus.lan_id) 4246282289Serj return; 4247282289Serj esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 4248282289Serj if (state) 4249282289Serj esdp |= IXGBE_ESDP_SDP1; 4250282289Serj else 4251282289Serj esdp &= ~IXGBE_ESDP_SDP1; 4252282289Serj IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 4253282289Serj IXGBE_WRITE_FLUSH(hw); 4254282289Serj} 4255282289Serj 4256282289Serj/** 4257282289Serj * ixgbe_acquire_swfw_sync_X550em - Acquire SWFW semaphore 4258282289Serj * @hw: pointer to hardware structure 4259282289Serj * @mask: Mask to specify which semaphore to acquire 4260282289Serj * 4261282289Serj * Acquires the SWFW semaphore and sets the I2C MUX 4262282289Serj **/ 4263282289Serjs32 ixgbe_acquire_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask) 4264282289Serj{ 4265282289Serj s32 status; 4266282289Serj 4267282289Serj DEBUGFUNC("ixgbe_acquire_swfw_sync_X550em"); 4268282289Serj 4269282289Serj status = ixgbe_acquire_swfw_sync_X540(hw, mask); 4270282289Serj if (status) 4271282289Serj return status; 4272282289Serj 4273282289Serj if (mask & IXGBE_GSSR_I2C_MASK) 4274282289Serj ixgbe_set_mux(hw, 1); 4275282289Serj 4276282289Serj return IXGBE_SUCCESS; 4277282289Serj} 4278282289Serj 4279282289Serj/** 4280282289Serj * ixgbe_release_swfw_sync_X550em - Release SWFW semaphore 4281282289Serj * @hw: pointer to hardware structure 4282282289Serj * @mask: Mask to specify which semaphore to release 4283282289Serj * 4284282289Serj * Releases the SWFW semaphore and sets the I2C MUX 4285282289Serj **/ 4286282289Serjvoid ixgbe_release_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask) 4287282289Serj{ 4288282289Serj DEBUGFUNC("ixgbe_release_swfw_sync_X550em"); 4289282289Serj 4290282289Serj if (mask & IXGBE_GSSR_I2C_MASK) 4291282289Serj ixgbe_set_mux(hw, 0); 4292282289Serj 4293282289Serj ixgbe_release_swfw_sync_X540(hw, mask); 4294282289Serj} 4295282289Serj 4296282289Serj/** 4297315333Serj * ixgbe_acquire_swfw_sync_X550a - Acquire SWFW semaphore 4298315333Serj * @hw: pointer to hardware structure 4299315333Serj * @mask: Mask to specify which semaphore to acquire 4300315333Serj * 4301315333Serj * Acquires the SWFW semaphore and get the shared phy token as needed 4302315333Serj */ 4303315333Serjstatic s32 ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *hw, u32 mask) 4304315333Serj{ 4305315333Serj u32 hmask = mask & ~IXGBE_GSSR_TOKEN_SM; 4306315333Serj int retries = FW_PHY_TOKEN_RETRIES; 4307315333Serj s32 status = IXGBE_SUCCESS; 4308315333Serj 4309315333Serj DEBUGFUNC("ixgbe_acquire_swfw_sync_X550a"); 4310315333Serj 4311315333Serj while (--retries) { 4312315333Serj status = IXGBE_SUCCESS; 4313315333Serj if (hmask) 4314315333Serj status = ixgbe_acquire_swfw_sync_X540(hw, hmask); 4315315333Serj if (status) { 4316315333Serj DEBUGOUT1("Could not acquire SWFW semaphore, Status = %d\n", 4317315333Serj status); 4318315333Serj return status; 4319315333Serj } 4320315333Serj if (!(mask & IXGBE_GSSR_TOKEN_SM)) 4321315333Serj return IXGBE_SUCCESS; 4322315333Serj 4323315333Serj status = ixgbe_get_phy_token(hw); 4324315333Serj if (status == IXGBE_ERR_TOKEN_RETRY) 4325315333Serj DEBUGOUT1("Could not acquire PHY token, Status = %d\n", 4326315333Serj status); 4327315333Serj 4328315333Serj if (status == IXGBE_SUCCESS) 4329315333Serj return IXGBE_SUCCESS; 4330315333Serj 4331315333Serj if (hmask) 4332315333Serj ixgbe_release_swfw_sync_X540(hw, hmask); 4333315333Serj 4334315333Serj if (status != IXGBE_ERR_TOKEN_RETRY) { 4335315333Serj DEBUGOUT1("Unable to retry acquiring the PHY token, Status = %d\n", 4336315333Serj status); 4337315333Serj return status; 4338315333Serj } 4339315333Serj } 4340315333Serj 4341315333Serj DEBUGOUT1("Semaphore acquisition retries failed!: PHY ID = 0x%08X\n", 4342315333Serj hw->phy.id); 4343315333Serj return status; 4344315333Serj} 4345315333Serj 4346315333Serj/** 4347315333Serj * ixgbe_release_swfw_sync_X550a - Release SWFW semaphore 4348315333Serj * @hw: pointer to hardware structure 4349315333Serj * @mask: Mask to specify which semaphore to release 4350315333Serj * 4351315333Serj * Releases the SWFW semaphore and puts the shared phy token as needed 4352315333Serj */ 4353315333Serjstatic void ixgbe_release_swfw_sync_X550a(struct ixgbe_hw *hw, u32 mask) 4354315333Serj{ 4355315333Serj u32 hmask = mask & ~IXGBE_GSSR_TOKEN_SM; 4356315333Serj 4357315333Serj DEBUGFUNC("ixgbe_release_swfw_sync_X550a"); 4358315333Serj 4359315333Serj if (mask & IXGBE_GSSR_TOKEN_SM) 4360315333Serj ixgbe_put_phy_token(hw); 4361315333Serj 4362315333Serj if (hmask) 4363315333Serj ixgbe_release_swfw_sync_X540(hw, hmask); 4364315333Serj} 4365315333Serj 4366315333Serj/** 4367315333Serj * ixgbe_read_phy_reg_x550a - Reads specified PHY register 4368315333Serj * @hw: pointer to hardware structure 4369315333Serj * @reg_addr: 32 bit address of PHY register to read 4370315333Serj * @phy_data: Pointer to read data from PHY register 4371315333Serj * 4372315333Serj * Reads a value from a specified PHY register using the SWFW lock and PHY 4373315333Serj * Token. The PHY Token is needed since the MDIO is shared between to MAC 4374315333Serj * instances. 4375315333Serj **/ 4376315333Serjs32 ixgbe_read_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, 4377315333Serj u32 device_type, u16 *phy_data) 4378315333Serj{ 4379315333Serj s32 status; 4380315333Serj u32 mask = hw->phy.phy_semaphore_mask | IXGBE_GSSR_TOKEN_SM; 4381315333Serj 4382315333Serj DEBUGFUNC("ixgbe_read_phy_reg_x550a"); 4383315333Serj 4384315333Serj if (hw->mac.ops.acquire_swfw_sync(hw, mask)) 4385315333Serj return IXGBE_ERR_SWFW_SYNC; 4386315333Serj 4387315333Serj status = hw->phy.ops.read_reg_mdi(hw, reg_addr, device_type, phy_data); 4388315333Serj 4389315333Serj hw->mac.ops.release_swfw_sync(hw, mask); 4390315333Serj 4391315333Serj return status; 4392315333Serj} 4393315333Serj 4394315333Serj/** 4395315333Serj * ixgbe_write_phy_reg_x550a - Writes specified PHY register 4396315333Serj * @hw: pointer to hardware structure 4397315333Serj * @reg_addr: 32 bit PHY register to write 4398315333Serj * @device_type: 5 bit device type 4399315333Serj * @phy_data: Data to write to the PHY register 4400315333Serj * 4401315333Serj * Writes a value to specified PHY register using the SWFW lock and PHY Token. 4402315333Serj * The PHY Token is needed since the MDIO is shared between to MAC instances. 4403315333Serj **/ 4404315333Serjs32 ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, 4405315333Serj u32 device_type, u16 phy_data) 4406315333Serj{ 4407315333Serj s32 status; 4408315333Serj u32 mask = hw->phy.phy_semaphore_mask | IXGBE_GSSR_TOKEN_SM; 4409315333Serj 4410315333Serj DEBUGFUNC("ixgbe_write_phy_reg_x550a"); 4411315333Serj 4412315333Serj if (hw->mac.ops.acquire_swfw_sync(hw, mask) == IXGBE_SUCCESS) { 4413315333Serj status = hw->phy.ops.write_reg_mdi(hw, reg_addr, device_type, 4414315333Serj phy_data); 4415315333Serj hw->mac.ops.release_swfw_sync(hw, mask); 4416315333Serj } else { 4417315333Serj status = IXGBE_ERR_SWFW_SYNC; 4418315333Serj } 4419315333Serj 4420315333Serj return status; 4421315333Serj} 4422315333Serj 4423315333Serj/** 4424282289Serj * ixgbe_handle_lasi_ext_t_x550em - Handle external Base T PHY interrupt 4425282289Serj * @hw: pointer to hardware structure 4426282289Serj * 4427282289Serj * Handle external Base T PHY interrupt. If high temperature 4428282289Serj * failure alarm then return error, else if link status change 4429282289Serj * then setup internal/external PHY link 4430282289Serj * 4431282289Serj * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature 4432282289Serj * failure alarm, else return PHY access status. 4433282289Serj */ 4434282289Serjs32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw) 4435282289Serj{ 4436282289Serj bool lsc; 4437282289Serj u32 status; 4438282289Serj 4439282289Serj status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc); 4440282289Serj 4441282289Serj if (status != IXGBE_SUCCESS) 4442282289Serj return status; 4443282289Serj 4444282289Serj if (lsc) 4445282289Serj return ixgbe_setup_internal_phy(hw); 4446282289Serj 4447282289Serj return IXGBE_SUCCESS; 4448282289Serj} 4449282289Serj 4450282289Serj/** 4451282289Serj * ixgbe_setup_mac_link_t_X550em - Sets the auto advertised link speed 4452282289Serj * @hw: pointer to hardware structure 4453282289Serj * @speed: new link speed 4454282289Serj * @autoneg_wait_to_complete: TRUE when waiting for completion is needed 4455282289Serj * 4456282289Serj * Setup internal/external PHY link speed based on link speed, then set 4457282289Serj * external PHY auto advertised link speed. 4458282289Serj * 4459282289Serj * Returns error status for any failure 4460282289Serj **/ 4461282289Serjs32 ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw, 4462282289Serj ixgbe_link_speed speed, 4463282289Serj bool autoneg_wait_to_complete) 4464282289Serj{ 4465282289Serj s32 status; 4466282289Serj ixgbe_link_speed force_speed; 4467282289Serj 4468282289Serj DEBUGFUNC("ixgbe_setup_mac_link_t_X550em"); 4469282289Serj 4470282289Serj /* Setup internal/external PHY link speed to iXFI (10G), unless 4471282289Serj * only 1G is auto advertised then setup KX link. 4472282289Serj */ 4473282289Serj if (speed & IXGBE_LINK_SPEED_10GB_FULL) 4474282289Serj force_speed = IXGBE_LINK_SPEED_10GB_FULL; 4475282289Serj else 4476282289Serj force_speed = IXGBE_LINK_SPEED_1GB_FULL; 4477282289Serj 4478315333Serj /* If X552 and internal link mode is XFI, then setup XFI internal link. 4479315333Serj */ 4480315333Serj if (hw->mac.type == ixgbe_mac_X550EM_x && 4481315333Serj !(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) { 4482282289Serj status = ixgbe_setup_ixfi_x550em(hw, &force_speed); 4483282289Serj 4484282289Serj if (status != IXGBE_SUCCESS) 4485282289Serj return status; 4486282289Serj } 4487282289Serj 4488282289Serj return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait_to_complete); 4489282289Serj} 4490282289Serj 4491282289Serj/** 4492282289Serj * ixgbe_check_link_t_X550em - Determine link and speed status 4493282289Serj * @hw: pointer to hardware structure 4494282289Serj * @speed: pointer to link speed 4495282289Serj * @link_up: TRUE when link is up 4496282289Serj * @link_up_wait_to_complete: bool used to wait for link up or not 4497282289Serj * 4498282289Serj * Check that both the MAC and X557 external PHY have link. 4499282289Serj **/ 4500282289Serjs32 ixgbe_check_link_t_X550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed, 4501282289Serj bool *link_up, bool link_up_wait_to_complete) 4502282289Serj{ 4503282289Serj u32 status; 4504315333Serj u16 i, autoneg_status = 0; 4505282289Serj 4506282289Serj if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper) 4507282289Serj return IXGBE_ERR_CONFIG; 4508282289Serj 4509282289Serj status = ixgbe_check_mac_link_generic(hw, speed, link_up, 4510282289Serj link_up_wait_to_complete); 4511282289Serj 4512282289Serj /* If check link fails or MAC link is not up, then return */ 4513282289Serj if (status != IXGBE_SUCCESS || !(*link_up)) 4514282289Serj return status; 4515282289Serj 4516282289Serj /* MAC link is up, so check external PHY link. 4517315333Serj * X557 PHY. Link status is latching low, and can only be used to detect 4518315333Serj * link drop, and not the current status of the link without performing 4519315333Serj * back-to-back reads. 4520282289Serj */ 4521315333Serj for (i = 0; i < 2; i++) { 4522315333Serj status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, 4523315333Serj IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 4524315333Serj &autoneg_status); 4525282289Serj 4526315333Serj if (status != IXGBE_SUCCESS) 4527315333Serj return status; 4528315333Serj } 4529282289Serj 4530282289Serj /* If external PHY link is not up, then indicate link not up */ 4531282289Serj if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS)) 4532282289Serj *link_up = FALSE; 4533282289Serj 4534282289Serj return IXGBE_SUCCESS; 4535282289Serj} 4536282289Serj 4537282289Serj/** 4538282289Serj * ixgbe_reset_phy_t_X550em - Performs X557 PHY reset and enables LASI 4539282289Serj * @hw: pointer to hardware structure 4540282289Serj **/ 4541282289Serjs32 ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw) 4542282289Serj{ 4543282289Serj s32 status; 4544282289Serj 4545282289Serj status = ixgbe_reset_phy_generic(hw); 4546282289Serj 4547282289Serj if (status != IXGBE_SUCCESS) 4548282289Serj return status; 4549282289Serj 4550282289Serj /* Configure Link Status Alarm and Temperature Threshold interrupts */ 4551282289Serj return ixgbe_enable_lasi_ext_t_x550em(hw); 4552282289Serj} 4553282289Serj 4554282289Serj/** 4555282289Serj * ixgbe_led_on_t_X550em - Turns on the software controllable LEDs. 4556282289Serj * @hw: pointer to hardware structure 4557282289Serj * @led_idx: led number to turn on 4558282289Serj **/ 4559282289Serjs32 ixgbe_led_on_t_X550em(struct ixgbe_hw *hw, u32 led_idx) 4560282289Serj{ 4561282289Serj u16 phy_data; 4562282289Serj 4563282289Serj DEBUGFUNC("ixgbe_led_on_t_X550em"); 4564282289Serj 4565282289Serj if (led_idx >= IXGBE_X557_MAX_LED_INDEX) 4566282289Serj return IXGBE_ERR_PARAM; 4567282289Serj 4568282289Serj /* To turn on the LED, set mode to ON. */ 4569282289Serj ixgbe_read_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx, 4570282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &phy_data); 4571282289Serj phy_data |= IXGBE_X557_LED_MANUAL_SET_MASK; 4572282289Serj ixgbe_write_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx, 4573282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, phy_data); 4574282289Serj 4575282289Serj return IXGBE_SUCCESS; 4576282289Serj} 4577282289Serj 4578282289Serj/** 4579282289Serj * ixgbe_led_off_t_X550em - Turns off the software controllable LEDs. 4580282289Serj * @hw: pointer to hardware structure 4581282289Serj * @led_idx: led number to turn off 4582282289Serj **/ 4583282289Serjs32 ixgbe_led_off_t_X550em(struct ixgbe_hw *hw, u32 led_idx) 4584282289Serj{ 4585282289Serj u16 phy_data; 4586282289Serj 4587282289Serj DEBUGFUNC("ixgbe_led_off_t_X550em"); 4588282289Serj 4589282289Serj if (led_idx >= IXGBE_X557_MAX_LED_INDEX) 4590282289Serj return IXGBE_ERR_PARAM; 4591282289Serj 4592282289Serj /* To turn on the LED, set mode to ON. */ 4593282289Serj ixgbe_read_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx, 4594282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &phy_data); 4595282289Serj phy_data &= ~IXGBE_X557_LED_MANUAL_SET_MASK; 4596282289Serj ixgbe_write_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx, 4597282289Serj IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, phy_data); 4598282289Serj 4599282289Serj return IXGBE_SUCCESS; 4600282289Serj} 4601282289Serj 4602315333Serj/** 4603315333Serj * ixgbe_set_fw_drv_ver_x550 - Sends driver version to firmware 4604315333Serj * @hw: pointer to the HW structure 4605315333Serj * @maj: driver version major number 4606315333Serj * @min: driver version minor number 4607315333Serj * @build: driver version build number 4608315333Serj * @sub: driver version sub build number 4609315333Serj * @len: length of driver_ver string 4610315333Serj * @driver_ver: driver string 4611315333Serj * 4612315333Serj * Sends driver version number to firmware through the manageability 4613315333Serj * block. On success return IXGBE_SUCCESS 4614315333Serj * else returns IXGBE_ERR_SWFW_SYNC when encountering an error acquiring 4615315333Serj * semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. 4616315333Serj **/ 4617315333Serjs32 ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min, 4618315333Serj u8 build, u8 sub, u16 len, const char *driver_ver) 4619315333Serj{ 4620315333Serj struct ixgbe_hic_drv_info2 fw_cmd; 4621315333Serj s32 ret_val = IXGBE_SUCCESS; 4622315333Serj int i; 4623315333Serj 4624315333Serj DEBUGFUNC("ixgbe_set_fw_drv_ver_x550"); 4625315333Serj 4626315333Serj if ((len == 0) || (driver_ver == NULL) || 4627315333Serj (len > sizeof(fw_cmd.driver_string))) 4628315333Serj return IXGBE_ERR_INVALID_ARGUMENT; 4629315333Serj 4630315333Serj fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO; 4631315333Serj fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN + len; 4632315333Serj fw_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; 4633315333Serj fw_cmd.port_num = (u8)hw->bus.func; 4634315333Serj fw_cmd.ver_maj = maj; 4635315333Serj fw_cmd.ver_min = min; 4636315333Serj fw_cmd.ver_build = build; 4637315333Serj fw_cmd.ver_sub = sub; 4638315333Serj fw_cmd.hdr.checksum = 0; 4639315333Serj memcpy(fw_cmd.driver_string, driver_ver, len); 4640315333Serj fw_cmd.hdr.checksum = ixgbe_calculate_checksum((u8 *)&fw_cmd, 4641315333Serj (FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len)); 4642315333Serj 4643315333Serj for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { 4644315333Serj ret_val = ixgbe_host_interface_command(hw, (u32 *)&fw_cmd, 4645315333Serj sizeof(fw_cmd), 4646315333Serj IXGBE_HI_COMMAND_TIMEOUT, 4647315333Serj TRUE); 4648315333Serj if (ret_val != IXGBE_SUCCESS) 4649315333Serj continue; 4650315333Serj 4651315333Serj if (fw_cmd.hdr.cmd_or_resp.ret_status == 4652315333Serj FW_CEM_RESP_STATUS_SUCCESS) 4653315333Serj ret_val = IXGBE_SUCCESS; 4654315333Serj else 4655315333Serj ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND; 4656315333Serj 4657315333Serj break; 4658315333Serj } 4659315333Serj 4660315333Serj return ret_val; 4661315333Serj} 4662