igc: Add setup link functionality

Add link establishment methods
Add auto negotiation methods
Add read MAC address method

Signed-off-by: Sasha Neftin <sasha.neftin@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
Sasha Neftin 2018-10-11 10:17:34 +03:00 committed by Jeff Kirsher
parent 5586838fe9
commit 4eb8080143
8 changed files with 717 additions and 0 deletions

View file

@ -314,6 +314,7 @@ struct igc_adapter {
struct work_struct reset_task;
struct work_struct watchdog_task;
struct work_struct dma_err_task;
bool fc_autoneg;
u8 tx_timeout_factor;

View file

@ -177,6 +177,29 @@ static s32 igc_init_nvm_params_base(struct igc_hw *hw)
return 0;
}
/**
* igc_setup_copper_link_base - Configure copper link settings
* @hw: pointer to the HW structure
*
* Configures the link for auto-neg or forced speed and duplex. Then we check
* for link, once link is established calls to configure collision distance
* and flow control are called.
*/
static s32 igc_setup_copper_link_base(struct igc_hw *hw)
{
s32 ret_val = 0;
u32 ctrl;
ctrl = rd32(IGC_CTRL);
ctrl |= IGC_CTRL_SLU;
ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);
wr32(IGC_CTRL, ctrl);
ret_val = igc_setup_copper_link(hw);
return ret_val;
}
/**
* igc_init_mac_params_base - Init MAC func ptrs.
* @hw: pointer to the HW structure
@ -200,6 +223,9 @@ static s32 igc_init_mac_params_base(struct igc_hw *hw)
if (mac->type == igc_i225)
dev_spec->clear_semaphore_once = true;
/* physical interface link setup */
mac->ops.setup_physical_interface = igc_setup_copper_link_base;
return 0;
}
@ -242,6 +268,8 @@ static s32 igc_init_phy_params_base(struct igc_hw *hw)
if (ret_val)
return ret_val;
igc_check_for_link_base(hw);
/* Verify phy id and set remaining function pointers */
switch (phy->id) {
case I225_I_PHY_ID:
@ -258,10 +286,22 @@ static s32 igc_init_phy_params_base(struct igc_hw *hw)
static s32 igc_get_invariants_base(struct igc_hw *hw)
{
struct igc_mac_info *mac = &hw->mac;
u32 link_mode = 0;
u32 ctrl_ext = 0;
s32 ret_val = 0;
switch (hw->device_id) {
case IGC_DEV_ID_I225_LM:
case IGC_DEV_ID_I225_V:
mac->type = igc_i225;
break;
default:
return -IGC_ERR_MAC_INIT;
}
hw->phy.media_type = igc_media_type_copper;
ctrl_ext = rd32(IGC_CTRL_EXT);
link_mode = ctrl_ext & IGC_CTRL_EXT_LINK_MODE_MASK;

View file

@ -13,6 +13,11 @@
/* Physical Func Reset Done Indication */
#define IGC_CTRL_EXT_LINK_MODE_MASK 0x00C00000
/* Loop limit on how long we wait for auto-negotiation to complete */
#define COPPER_LINK_UP_LIMIT 10
#define PHY_AUTO_NEG_LIMIT 45
#define PHY_FORCE_LIMIT 20
/* Number of 100 microseconds we wait for PCI Express master disable */
#define MASTER_DISABLE_TIMEOUT 800
/*Blocks new Master requests */
@ -54,6 +59,12 @@
#define IGC_CTRL_RST 0x04000000 /* Global reset */
#define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */
#define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
#define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */
#define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */
#define IGC_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
#define IGC_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
/* PBA constants */
#define IGC_PBA_34K 0x0022
@ -66,6 +77,29 @@
#define IGC_SWFW_EEP_SM 0x1
#define IGC_SWFW_PHY0_SM 0x2
/* Autoneg Advertisement Register */
#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
/* Link Partner Ability Register (Base Page) */
#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
/* 1000BASE-T Control Register */
#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */
#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
/* PHY GPY 211 registers */
#define STANDARD_AN_REG_MASK 0x0007 /* MMD */
#define ANEG_MULTIGBT_AN_CTRL 0x0020 /* MULTI GBT AN Control Register */
#define MMD_DEVADDR_SHIFT 16 /* Shift MMD to higher bits */
#define CR_2500T_FD_CAPS 0x0080 /* Advertise 2500T FD capability */
/* NVM Control */
/* Number of milliseconds for NVM auto read done after MAC reset. */
#define AUTO_READ_DONE_TIMEOUT 10
@ -318,6 +352,10 @@
#define PHY_STATUS 0x01 /* Status Register */
#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
/* Bit definitions for valid PHY IDs. I = Integrated E = External */
#define I225_I_PHY_ID 0x67C9DC00

View file

@ -92,6 +92,8 @@ s32 igc_setup_link(struct igc_hw *hw)
/* In the case of the phy reset being blocked, we already have a link.
* We do not need to set it up again.
*/
if (igc_check_reset_block(hw))
goto out;
/* If requested flow control is set to default, set flow control
* based on the EEPROM flow control settings.
@ -142,9 +144,73 @@ s32 igc_setup_link(struct igc_hw *hw)
*/
static s32 igc_set_default_fc(struct igc_hw *hw)
{
hw->fc.requested_mode = igc_fc_full;
return 0;
}
/**
* igc_force_mac_fc - Force the MAC's flow control settings
* @hw: pointer to the HW structure
*
* Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the
* device control register to reflect the adapter settings. TFCE and RFCE
* need to be explicitly set by software when a copper PHY is used because
* autonegotiation is managed by the PHY rather than the MAC. Software must
* also configure these bits when link is forced on a fiber connection.
*/
s32 igc_force_mac_fc(struct igc_hw *hw)
{
s32 ret_val = 0;
u32 ctrl;
ctrl = rd32(IGC_CTRL);
/* Because we didn't get link via the internal auto-negotiation
* mechanism (we either forced link or we got link via PHY
* auto-neg), we have to manually enable/disable transmit an
* receive flow control.
*
* The "Case" statement below enables/disable flow control
* according to the "hw->fc.current_mode" parameter.
*
* The possible values of the "fc" parameter are:
* 0: Flow control is completely disabled
* 1: Rx flow control is enabled (we can receive pause
* frames but not send pause frames).
* 2: Tx flow control is enabled (we can send pause frames
* frames but we do not receive pause frames).
* 3: Both Rx and TX flow control (symmetric) is enabled.
* other: No other values should be possible at this point.
*/
hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
switch (hw->fc.current_mode) {
case igc_fc_none:
ctrl &= (~(IGC_CTRL_TFCE | IGC_CTRL_RFCE));
break;
case igc_fc_rx_pause:
ctrl &= (~IGC_CTRL_TFCE);
ctrl |= IGC_CTRL_RFCE;
break;
case igc_fc_tx_pause:
ctrl &= (~IGC_CTRL_RFCE);
ctrl |= IGC_CTRL_TFCE;
break;
case igc_fc_full:
ctrl |= (IGC_CTRL_TFCE | IGC_CTRL_RFCE);
break;
default:
hw_dbg("Flow control param set incorrectly\n");
ret_val = -IGC_ERR_CONFIG;
goto out;
}
wr32(IGC_CTRL, ctrl);
out:
return ret_val;
}
/**
* igc_set_fc_watermarks - Set flow control high/low watermarks
* @hw: pointer to the HW structure
@ -371,6 +437,7 @@ s32 igc_check_for_copper_link(struct igc_hw *hw)
* settings because we may have had to re-autoneg with a
* different link partner.
*/
ret_val = igc_config_fc_after_link_up(hw);
if (ret_val)
hw_dbg("Error configuring flow control\n");
@ -399,6 +466,210 @@ void igc_config_collision_dist(struct igc_hw *hw)
wrfl();
}
/**
* igc_config_fc_after_link_up - Configures flow control after link
* @hw: pointer to the HW structure
*
* Checks the status of auto-negotiation after link up to ensure that the
* speed and duplex were not forced. If the link needed to be forced, then
* flow control needs to be forced also. If auto-negotiation is enabled
* and did not fail, then we configure flow control based on our link
* partner.
*/
s32 igc_config_fc_after_link_up(struct igc_hw *hw)
{
u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
struct igc_mac_info *mac = &hw->mac;
u16 speed, duplex;
s32 ret_val = 0;
/* Check for the case where we have fiber media and auto-neg failed
* so we had to force link. In this case, we need to force the
* configuration of the MAC to match the "fc" parameter.
*/
if (mac->autoneg_failed) {
if (hw->phy.media_type == igc_media_type_copper)
ret_val = igc_force_mac_fc(hw);
}
if (ret_val) {
hw_dbg("Error forcing flow control settings\n");
goto out;
}
/* Check for the case where we have copper media and auto-neg is
* enabled. In this case, we need to check and see if Auto-Neg
* has completed, and if so, how the PHY and link partner has
* flow control configured.
*/
if (hw->phy.media_type == igc_media_type_copper && mac->autoneg) {
/* Read the MII Status Register and check to see if AutoNeg
* has completed. We read this twice because this reg has
* some "sticky" (latched) bits.
*/
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
&mii_status_reg);
if (ret_val)
goto out;
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
&mii_status_reg);
if (ret_val)
goto out;
if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
hw_dbg("Copper PHY and Auto Neg has not completed.\n");
goto out;
}
/* The AutoNeg process has completed, so we now need to
* read both the Auto Negotiation Advertisement
* Register (Address 4) and the Auto_Negotiation Base
* Page Ability Register (Address 5) to determine how
* flow control was negotiated.
*/
ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
&mii_nway_adv_reg);
if (ret_val)
goto out;
ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
&mii_nway_lp_ability_reg);
if (ret_val)
goto out;
/* Two bits in the Auto Negotiation Advertisement Register
* (Address 4) and two bits in the Auto Negotiation Base
* Page Ability Register (Address 5) determine flow control
* for both the PHY and the link partner. The following
* table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
* 1999, describes these PAUSE resolution bits and how flow
* control is determined based upon these settings.
* NOTE: DC = Don't Care
*
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
*-------|---------|-------|---------|--------------------
* 0 | 0 | DC | DC | igc_fc_none
* 0 | 1 | 0 | DC | igc_fc_none
* 0 | 1 | 1 | 0 | igc_fc_none
* 0 | 1 | 1 | 1 | igc_fc_tx_pause
* 1 | 0 | 0 | DC | igc_fc_none
* 1 | DC | 1 | DC | igc_fc_full
* 1 | 1 | 0 | 0 | igc_fc_none
* 1 | 1 | 0 | 1 | igc_fc_rx_pause
*
* Are both PAUSE bits set to 1? If so, this implies
* Symmetric Flow Control is enabled at both ends. The
* ASM_DIR bits are irrelevant per the spec.
*
* For Symmetric Flow Control:
*
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
*-------|---------|-------|---------|--------------------
* 1 | DC | 1 | DC | IGC_fc_full
*
*/
if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
/* Now we need to check if the user selected RX ONLY
* of pause frames. In this case, we had to advertise
* FULL flow control because we could not advertise RX
* ONLY. Hence, we must now check to see if we need to
* turn OFF the TRANSMISSION of PAUSE frames.
*/
if (hw->fc.requested_mode == igc_fc_full) {
hw->fc.current_mode = igc_fc_full;
hw_dbg("Flow Control = FULL.\n");
} else {
hw->fc.current_mode = igc_fc_rx_pause;
hw_dbg("Flow Control = RX PAUSE frames only.\n");
}
}
/* For receiving PAUSE frames ONLY.
*
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
*-------|---------|-------|---------|--------------------
* 0 | 1 | 1 | 1 | igc_fc_tx_pause
*/
else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
hw->fc.current_mode = igc_fc_tx_pause;
hw_dbg("Flow Control = TX PAUSE frames only.\n");
}
/* For transmitting PAUSE frames ONLY.
*
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
*-------|---------|-------|---------|--------------------
* 1 | 1 | 0 | 1 | igc_fc_rx_pause
*/
else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
!(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
hw->fc.current_mode = igc_fc_rx_pause;
hw_dbg("Flow Control = RX PAUSE frames only.\n");
}
/* Per the IEEE spec, at this point flow control should be
* disabled. However, we want to consider that we could
* be connected to a legacy switch that doesn't advertise
* desired flow control, but can be forced on the link
* partner. So if we advertised no flow control, that is
* what we will resolve to. If we advertised some kind of
* receive capability (Rx Pause Only or Full Flow Control)
* and the link partner advertised none, we will configure
* ourselves to enable Rx Flow Control only. We can do
* this safely for two reasons: If the link partner really
* didn't want flow control enabled, and we enable Rx, no
* harm done since we won't be receiving any PAUSE frames
* anyway. If the intent on the link partner was to have
* flow control enabled, then by us enabling RX only, we
* can at least receive pause frames and process them.
* This is a good idea because in most cases, since we are
* predominantly a server NIC, more times than not we will
* be asked to delay transmission of packets than asking
* our link partner to pause transmission of frames.
*/
else if ((hw->fc.requested_mode == igc_fc_none) ||
(hw->fc.requested_mode == igc_fc_tx_pause) ||
(hw->fc.strict_ieee)) {
hw->fc.current_mode = igc_fc_none;
hw_dbg("Flow Control = NONE.\n");
} else {
hw->fc.current_mode = igc_fc_rx_pause;
hw_dbg("Flow Control = RX PAUSE frames only.\n");
}
/* Now we need to do one last check... If we auto-
* negotiated to HALF DUPLEX, flow control should not be
* enabled per IEEE 802.3 spec.
*/
ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
if (ret_val) {
hw_dbg("Error getting link speed and duplex\n");
goto out;
}
if (duplex == HALF_DUPLEX)
hw->fc.current_mode = igc_fc_none;
/* Now we call a subroutine to actually force the MAC
* controller to use the correct flow control settings.
*/
ret_val = igc_force_mac_fc(hw);
if (ret_val) {
hw_dbg("Error forcing flow control settings\n");
goto out;
}
}
out:
return 0;
}
/**
* igc_get_auto_rd_done - Check for auto read completion
* @hw: pointer to the HW structure

View file

@ -15,6 +15,8 @@
/* forward declaration */
s32 igc_disable_pcie_master(struct igc_hw *hw);
s32 igc_check_for_copper_link(struct igc_hw *hw);
s32 igc_config_fc_after_link_up(struct igc_hw *hw);
s32 igc_force_mac_fc(struct igc_hw *hw);
void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count);
s32 igc_setup_link(struct igc_hw *hw);
void igc_clear_hw_cntrs_base(struct igc_hw *hw);

View file

@ -3403,6 +3403,25 @@ static int igc_probe(struct pci_dev *pdev,
netdev->min_mtu = ETH_MIN_MTU;
netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE;
/* before reading the NVM, reset the controller to put the device in a
* known good starting state
*/
hw->mac.ops.reset_hw(hw);
if (eth_platform_get_mac_address(&pdev->dev, hw->mac.addr)) {
/* copy the MAC address out of the NVM */
if (hw->mac.ops.read_mac_addr(hw))
dev_err(&pdev->dev, "NVM Read Error\n");
}
memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len);
if (!is_valid_ether_addr(netdev->dev_addr)) {
dev_err(&pdev->dev, "Invalid MAC Address\n");
err = -EIO;
goto err_eeprom;
}
/* configure RXPBSIZE and TXPBSIZE */
wr32(IGC_RXPBS, I225_RXPBSIZE_DEFAULT);
wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);
@ -3411,6 +3430,14 @@ static int igc_probe(struct pci_dev *pdev,
INIT_WORK(&adapter->reset_task, igc_reset_task);
/* Initialize link properties that are user-changeable */
adapter->fc_autoneg = true;
hw->mac.autoneg = true;
hw->phy.autoneg_advertised = 0xaf;
hw->fc.requested_mode = igc_fc_default;
hw->fc.current_mode = igc_fc_default;
/* reset the hardware with the new settings */
igc_reset(adapter);
@ -3438,6 +3465,9 @@ static int igc_probe(struct pci_dev *pdev,
err_register:
igc_release_hw_control(adapter);
err_eeprom:
if (!igc_check_reset_block(hw))
igc_reset_phy(hw);
err_sw_init:
igc_clear_interrupt_scheme(adapter);
iounmap(adapter->io_addr);

View file

@ -3,6 +3,10 @@
#include "igc_phy.h"
/* forward declaration */
static s32 igc_phy_setup_autoneg(struct igc_hw *hw);
static s32 igc_wait_autoneg(struct igc_hw *hw);
/**
* igc_check_reset_block - Check if PHY reset is blocked
* @hw: pointer to the HW structure
@ -211,6 +215,336 @@ s32 igc_phy_hw_reset(struct igc_hw *hw)
return ret_val;
}
/**
* igc_copper_link_autoneg - Setup/Enable autoneg for copper link
* @hw: pointer to the HW structure
*
* Performs initial bounds checking on autoneg advertisement parameter, then
* configure to advertise the full capability. Setup the PHY to autoneg
* and restart the negotiation process between the link partner. If
* autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
*/
static s32 igc_copper_link_autoneg(struct igc_hw *hw)
{
struct igc_phy_info *phy = &hw->phy;
u16 phy_ctrl;
s32 ret_val;
/* Perform some bounds checking on the autoneg advertisement
* parameter.
*/
phy->autoneg_advertised &= phy->autoneg_mask;
/* If autoneg_advertised is zero, we assume it was not defaulted
* by the calling code so we set to advertise full capability.
*/
if (phy->autoneg_advertised == 0)
phy->autoneg_advertised = phy->autoneg_mask;
hw_dbg("Reconfiguring auto-neg advertisement params\n");
ret_val = igc_phy_setup_autoneg(hw);
if (ret_val) {
hw_dbg("Error Setting up Auto-Negotiation\n");
goto out;
}
hw_dbg("Restarting Auto-Neg\n");
/* Restart auto-negotiation by setting the Auto Neg Enable bit and
* the Auto Neg Restart bit in the PHY control register.
*/
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
if (ret_val)
goto out;
phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
if (ret_val)
goto out;
/* Does the user want to wait for Auto-Neg to complete here, or
* check at a later time (for example, callback routine).
*/
if (phy->autoneg_wait_to_complete) {
ret_val = igc_wait_autoneg(hw);
if (ret_val) {
hw_dbg("Error while waiting for autoneg to complete\n");
goto out;
}
}
hw->mac.get_link_status = true;
out:
return ret_val;
}
/**
* igc_wait_autoneg - Wait for auto-neg completion
* @hw: pointer to the HW structure
*
* Waits for auto-negotiation to complete or for the auto-negotiation time
* limit to expire, which ever happens first.
*/
static s32 igc_wait_autoneg(struct igc_hw *hw)
{
u16 i, phy_status;
s32 ret_val = 0;
/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
if (ret_val)
break;
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
if (ret_val)
break;
if (phy_status & MII_SR_AUTONEG_COMPLETE)
break;
msleep(100);
}
/* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
* has completed.
*/
return ret_val;
}
/**
* igc_phy_setup_autoneg - Configure PHY for auto-negotiation
* @hw: pointer to the HW structure
*
* Reads the MII auto-neg advertisement register and/or the 1000T control
* register and if the PHY is already setup for auto-negotiation, then
* return successful. Otherwise, setup advertisement and flow control to
* the appropriate values for the wanted auto-negotiation.
*/
static s32 igc_phy_setup_autoneg(struct igc_hw *hw)
{
struct igc_phy_info *phy = &hw->phy;
u16 aneg_multigbt_an_ctrl = 0;
u16 mii_1000t_ctrl_reg = 0;
u16 mii_autoneg_adv_reg;
s32 ret_val;
phy->autoneg_advertised &= phy->autoneg_mask;
/* Read the MII Auto-Neg Advertisement Register (Address 4). */
ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
if (ret_val)
return ret_val;
if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
/* Read the MII 1000Base-T Control Register (Address 9). */
ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
&mii_1000t_ctrl_reg);
if (ret_val)
return ret_val;
}
if ((phy->autoneg_mask & ADVERTISE_2500_FULL) &&
hw->phy.id == I225_I_PHY_ID) {
/* Read the MULTI GBT AN Control Register - reg 7.32 */
ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
MMD_DEVADDR_SHIFT) |
ANEG_MULTIGBT_AN_CTRL,
&aneg_multigbt_an_ctrl);
if (ret_val)
return ret_val;
}
/* Need to parse both autoneg_advertised and fc and set up
* the appropriate PHY registers. First we will parse for
* autoneg_advertised software override. Since we can advertise
* a plethora of combinations, we need to check each bit
* individually.
*/
/* First we clear all the 10/100 mb speed bits in the Auto-Neg
* Advertisement Register (Address 4) and the 1000 mb speed bits in
* the 1000Base-T Control Register (Address 9).
*/
mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
NWAY_AR_100TX_HD_CAPS |
NWAY_AR_10T_FD_CAPS |
NWAY_AR_10T_HD_CAPS);
mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised);
/* Do we want to advertise 10 Mb Half Duplex? */
if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
hw_dbg("Advertise 10mb Half duplex\n");
mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
}
/* Do we want to advertise 10 Mb Full Duplex? */
if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
hw_dbg("Advertise 10mb Full duplex\n");
mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
}
/* Do we want to advertise 100 Mb Half Duplex? */
if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
hw_dbg("Advertise 100mb Half duplex\n");
mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
}
/* Do we want to advertise 100 Mb Full Duplex? */
if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
hw_dbg("Advertise 100mb Full duplex\n");
mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
}
/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
hw_dbg("Advertise 1000mb Half duplex request denied!\n");
/* Do we want to advertise 1000 Mb Full Duplex? */
if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
hw_dbg("Advertise 1000mb Full duplex\n");
mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
}
/* We do not allow the Phy to advertise 2500 Mb Half Duplex */
if (phy->autoneg_advertised & ADVERTISE_2500_HALF)
hw_dbg("Advertise 2500mb Half duplex request denied!\n");
/* Do we want to advertise 2500 Mb Full Duplex? */
if (phy->autoneg_advertised & ADVERTISE_2500_FULL) {
hw_dbg("Advertise 2500mb Full duplex\n");
aneg_multigbt_an_ctrl |= CR_2500T_FD_CAPS;
} else {
aneg_multigbt_an_ctrl &= ~CR_2500T_FD_CAPS;
}
/* Check for a software override of the flow control settings, and
* setup the PHY advertisement registers accordingly. If
* auto-negotiation is enabled, then software will have to set the
* "PAUSE" bits to the correct value in the Auto-Negotiation
* Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
* negotiation.
*
* The possible values of the "fc" parameter are:
* 0: Flow control is completely disabled
* 1: Rx flow control is enabled (we can receive pause frames
* but not send pause frames).
* 2: Tx flow control is enabled (we can send pause frames
* but we do not support receiving pause frames).
* 3: Both Rx and Tx flow control (symmetric) are enabled.
* other: No software override. The flow control configuration
* in the EEPROM is used.
*/
switch (hw->fc.current_mode) {
case igc_fc_none:
/* Flow control (Rx & Tx) is completely disabled by a
* software over-ride.
*/
mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
break;
case igc_fc_rx_pause:
/* Rx Flow control is enabled, and Tx Flow control is
* disabled, by a software over-ride.
*
* Since there really isn't a way to advertise that we are
* capable of Rx Pause ONLY, we will advertise that we
* support both symmetric and asymmetric Rx PAUSE. Later
* (in igc_config_fc_after_link_up) we will disable the
* hw's ability to send PAUSE frames.
*/
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
break;
case igc_fc_tx_pause:
/* Tx Flow control is enabled, and Rx Flow control is
* disabled, by a software over-ride.
*/
mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
break;
case igc_fc_full:
/* Flow control (both Rx and Tx) is enabled by a software
* over-ride.
*/
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
break;
default:
hw_dbg("Flow control param set incorrectly\n");
return -IGC_ERR_CONFIG;
}
ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
if (ret_val)
return ret_val;
hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
if (phy->autoneg_mask & ADVERTISE_1000_FULL)
ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL,
mii_1000t_ctrl_reg);
if ((phy->autoneg_mask & ADVERTISE_2500_FULL) &&
hw->phy.id == I225_I_PHY_ID)
ret_val = phy->ops.write_reg(hw,
(STANDARD_AN_REG_MASK <<
MMD_DEVADDR_SHIFT) |
ANEG_MULTIGBT_AN_CTRL,
aneg_multigbt_an_ctrl);
return ret_val;
}
/**
* igc_setup_copper_link - Configure copper link settings
* @hw: pointer to the HW structure
*
* Calls the appropriate function to configure the link for auto-neg or forced
* speed and duplex. Then we check for link, once link is established calls
* to configure collision distance and flow control are called. If link is
* not established, we return -IGC_ERR_PHY (-2).
*/
s32 igc_setup_copper_link(struct igc_hw *hw)
{
s32 ret_val = 0;
bool link;
if (hw->mac.autoneg) {
/* Setup autoneg and flow control advertisement and perform
* autonegotiation.
*/
ret_val = igc_copper_link_autoneg(hw);
if (ret_val)
goto out;
} else {
/* PHY will be set to 10H, 10F, 100H or 100F
* depending on user settings.
*/
hw_dbg("Forcing Speed and Duplex\n");
ret_val = hw->phy.ops.force_speed_duplex(hw);
if (ret_val) {
hw_dbg("Error Forcing Speed and Duplex\n");
goto out;
}
}
/* Check link status. Wait up to 100 microseconds for link to become
* valid.
*/
ret_val = igc_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link);
if (ret_val)
goto out;
if (link) {
hw_dbg("Valid link established!!!\n");
igc_config_collision_dist(hw);
ret_val = igc_config_fc_after_link_up(hw);
} else {
hw_dbg("Unable to establish link!!!\n");
}
out:
return ret_val;
}
/**
* igc_read_phy_reg_mdic - Read MDI control register
* @hw: pointer to the HW structure

View file

@ -12,6 +12,7 @@ s32 igc_get_phy_id(struct igc_hw *hw);
s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
u32 usec_interval, bool *success);
s32 igc_check_downshift(struct igc_hw *hw);
s32 igc_setup_copper_link(struct igc_hw *hw);
void igc_power_up_phy_copper(struct igc_hw *hw);
void igc_power_down_phy_copper(struct igc_hw *hw);
s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data);