numam-dpdk/lib/librte_pmd_ixgbe/ixgbe_82599_bypass.c
Bruce Richardson e9d48c0072 update Intel copyright years to 2014
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
2014-02-25 21:29:14 +01:00

310 lines
8.9 KiB
C

/*-
* BSD LICENSE
*
* Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ixgbe/ixgbe_type.h"
#include "ixgbe/ixgbe_82599.h"
#include "ixgbe/ixgbe_api.h"
#include "ixgbe/ixgbe_common.h"
#include "ixgbe/ixgbe_phy.h"
#include "ixgbe_bypass_defines.h"
#include "ixgbe_bypass.h"
/**
* ixgbe_set_fiber_fixed_speed - Set module link speed for fixed fiber
* @hw: pointer to hardware structure
* @speed: link speed to set
*
* We set the module speed differently for fixed fiber. For other
* multi-speed devices we don't have an error value so here if we
* detect an error we just log it and exit.
*/
static void
ixgbe_set_fiber_fixed_speed(struct ixgbe_hw *hw, ixgbe_link_speed speed)
{
s32 status;
u8 rs, eeprom_data;
switch (speed) {
case IXGBE_LINK_SPEED_10GB_FULL:
/* one bit mask same as setting on */
rs = IXGBE_SFF_SOFT_RS_SELECT_10G;
break;
case IXGBE_LINK_SPEED_1GB_FULL:
rs = IXGBE_SFF_SOFT_RS_SELECT_1G;
break;
default:
DEBUGOUT("Invalid fixed module speed\n");
return;
}
/* Set RS0 */
status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB,
IXGBE_I2C_EEPROM_DEV_ADDR2,
&eeprom_data);
if (status) {
DEBUGOUT("Failed to read Rx Rate Select RS0\n");
goto out;
}
eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) & rs;
status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB,
IXGBE_I2C_EEPROM_DEV_ADDR2,
eeprom_data);
if (status) {
DEBUGOUT("Failed to write Rx Rate Select RS0\n");
goto out;
}
/* Set RS1 */
status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB,
IXGBE_I2C_EEPROM_DEV_ADDR2,
&eeprom_data);
if (status) {
DEBUGOUT("Failed to read Rx Rate Select RS1\n");
goto out;
}
eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) & rs;
status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB,
IXGBE_I2C_EEPROM_DEV_ADDR2,
eeprom_data);
if (status) {
DEBUGOUT("Failed to write Rx Rate Select RS1\n");
goto out;
}
out:
return;
}
/**
* ixgbe_setup_mac_link_multispeed_fixed_fiber - Set MAC link speed
* @hw: pointer to hardware structure
* @speed: new link speed
* @autoneg: true if autonegotiation enabled
* @autoneg_wait_to_complete: true when waiting for completion is needed
*
* Set the link speed in the AUTOC register and restarts link.
**/
static s32
ixgbe_setup_mac_link_multispeed_fixed_fiber(struct ixgbe_hw *hw,
ixgbe_link_speed speed, bool autoneg,
bool autoneg_wait_to_complete)
{
s32 status = IXGBE_SUCCESS;
ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN;
ixgbe_link_speed highest_link_speed = IXGBE_LINK_SPEED_UNKNOWN;
u32 speedcnt = 0;
u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
u32 i = 0;
bool link_up = false;
bool negotiation;
DEBUGFUNC("");
/* Mask off requested but non-supported speeds */
status = ixgbe_get_link_capabilities(hw, &link_speed, &negotiation);
if (status != IXGBE_SUCCESS)
return status;
speed &= link_speed;
/*
* Try each speed one by one, highest priority first. We do this in
* software because 10gb fiber doesn't support speed autonegotiation.
*/
if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
speedcnt++;
highest_link_speed = IXGBE_LINK_SPEED_10GB_FULL;
/* If we already have link at this speed, just jump out */
status = ixgbe_check_link(hw, &link_speed, &link_up, false);
if (status != IXGBE_SUCCESS)
return status;
if ((link_speed == IXGBE_LINK_SPEED_10GB_FULL) && link_up)
goto out;
/* Set the module link speed */
ixgbe_set_fiber_fixed_speed(hw, IXGBE_LINK_SPEED_10GB_FULL);
/* Set the module link speed */
esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5);
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
IXGBE_WRITE_FLUSH(hw);
/* Allow module to change analog characteristics (1G->10G) */
msec_delay(40);
status = ixgbe_setup_mac_link_82599(hw,
IXGBE_LINK_SPEED_10GB_FULL,
autoneg,
autoneg_wait_to_complete);
if (status != IXGBE_SUCCESS)
return status;
/* Flap the tx laser if it has not already been done */
ixgbe_flap_tx_laser(hw);
/*
* Wait for the controller to acquire link. Per IEEE 802.3ap,
* Section 73.10.2, we may have to wait up to 500ms if KR is
* attempted. 82599 uses the same timing for 10g SFI.
*/
for (i = 0; i < 5; i++) {
/* Wait for the link partner to also set speed */
msec_delay(100);
/* If we have link, just jump out */
status = ixgbe_check_link(hw, &link_speed,
&link_up, false);
if (status != IXGBE_SUCCESS)
return status;
if (link_up)
goto out;
}
}
if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
speedcnt++;
if (highest_link_speed == IXGBE_LINK_SPEED_UNKNOWN)
highest_link_speed = IXGBE_LINK_SPEED_1GB_FULL;
/* If we already have link at this speed, just jump out */
status = ixgbe_check_link(hw, &link_speed, &link_up, false);
if (status != IXGBE_SUCCESS)
return status;
if ((link_speed == IXGBE_LINK_SPEED_1GB_FULL) && link_up)
goto out;
/* Set the module link speed */
ixgbe_set_fiber_fixed_speed(hw, IXGBE_LINK_SPEED_1GB_FULL);
/* Allow module to change analog characteristics (10G->1G) */
msec_delay(40);
status = ixgbe_setup_mac_link_82599(hw,
IXGBE_LINK_SPEED_1GB_FULL,
autoneg,
autoneg_wait_to_complete);
if (status != IXGBE_SUCCESS)
return status;
/* Flap the tx laser if it has not already been done */
ixgbe_flap_tx_laser(hw);
/* Wait for the link partner to also set speed */
msec_delay(100);
/* If we have link, just jump out */
status = ixgbe_check_link(hw, &link_speed, &link_up, false);
if (status != IXGBE_SUCCESS)
return status;
if (link_up)
goto out;
}
/*
* We didn't get link. Configure back to the highest speed we tried,
* (if there was more than one). We call ourselves back with just the
* single highest speed that the user requested.
*/
if (speedcnt > 1)
status = ixgbe_setup_mac_link_multispeed_fixed_fiber(hw,
highest_link_speed, autoneg, autoneg_wait_to_complete);
out:
/* Set autoneg_advertised value based on input link speed */
hw->phy.autoneg_advertised = 0;
if (speed & IXGBE_LINK_SPEED_10GB_FULL)
hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
if (speed & IXGBE_LINK_SPEED_1GB_FULL)
hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
return status;
}
/*
* Wrapper around ND functions to support BYPASS nic.
*/
s32
ixgbe_bypass_init_shared_code(struct ixgbe_hw *hw)
{
if (hw->device_id == IXGBE_DEV_ID_82599_BYPASS) {
hw->mac.type = ixgbe_mac_82599EB;
}
return (ixgbe_init_shared_code(hw));
}
static enum ixgbe_media_type
ixgbe_bypass_get_media_type(struct ixgbe_hw *hw)
{
enum ixgbe_media_type media_type;
DEBUGFUNC("");
if (hw->device_id == IXGBE_DEV_ID_82599_BYPASS) {
media_type = ixgbe_media_type_fiber;
} else {
media_type = ixgbe_get_media_type_82599(hw);
}
return (media_type);
}
s32
ixgbe_bypass_init_hw(struct ixgbe_hw *hw)
{
int rc;
if ((rc = ixgbe_init_hw(hw)) == 0 &&
hw->device_id == IXGBE_DEV_ID_82599_BYPASS) {
hw->mac.ops.setup_link =
&ixgbe_setup_mac_link_multispeed_fixed_fiber;
hw->mac.ops.get_media_type = &ixgbe_bypass_get_media_type;
hw->mac.ops.disable_tx_laser = NULL;
hw->mac.ops.enable_tx_laser = NULL;
hw->mac.ops.flap_tx_laser = NULL;
}
return (rc);
}