Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 162872
b: refs/heads/master
c: 2fb02a2
h: refs/heads/master
v: v3
  • Loading branch information
Alexander Duyck authored and David S. Miller committed Sep 15, 2009
1 parent 38bf248 commit a5ab647
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 110 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6b1be1990d2f7d1a3b1f25bf3e6444600665764a
refs/heads/master: 2fb02a26bda1cbc3553164a8358c303d936255c5
198 changes: 92 additions & 106 deletions trunk/drivers/net/igb/e1000_82575.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,10 @@ static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16 *);
static s32 igb_reset_hw_82575(struct e1000_hw *);
static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *, bool);
static s32 igb_setup_copper_link_82575(struct e1000_hw *);
static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *);
static s32 igb_setup_serdes_link_82575(struct e1000_hw *);
static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16);
static void igb_clear_hw_cntrs_82575(struct e1000_hw *);
static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *, u16);
static void igb_configure_pcs_link_82575(struct e1000_hw *);
static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *, u16 *,
u16 *);
static s32 igb_get_phy_id_82575(struct e1000_hw *);
Expand Down Expand Up @@ -105,16 +104,20 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
dev_spec->sgmii_active = false;

ctrl_ext = rd32(E1000_CTRL_EXT);
if ((ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) ==
E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES) {
hw->phy.media_type = e1000_media_type_internal_serdes;
ctrl_ext |= E1000_CTRL_I2C_ENA;
} else if (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_SGMII) {
switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
case E1000_CTRL_EXT_LINK_MODE_SGMII:
dev_spec->sgmii_active = true;
ctrl_ext |= E1000_CTRL_I2C_ENA;
} else {
break;
case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
hw->phy.media_type = e1000_media_type_internal_serdes;
ctrl_ext |= E1000_CTRL_I2C_ENA;
break;
default:
ctrl_ext &= ~E1000_CTRL_I2C_ENA;
break;
}

wr32(E1000_CTRL_EXT, ctrl_ext);

/* Set mta register count */
Expand All @@ -134,7 +137,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
mac->ops.setup_physical_interface =
(hw->phy.media_type == e1000_media_type_copper)
? igb_setup_copper_link_82575
: igb_setup_fiber_serdes_link_82575;
: igb_setup_serdes_link_82575;

/* NVM initialization */
eecd = rd32(E1000_EECD);
Expand Down Expand Up @@ -379,6 +382,7 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val = 0;
u16 phy_id;
u32 ctrl_ext;

/*
* For SGMII PHYs, we try the list of possible addresses until
Expand All @@ -393,6 +397,12 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
goto out;
}

/* Power on sgmii phy if it is disabled */
ctrl_ext = rd32(E1000_CTRL_EXT);
wr32(E1000_CTRL_EXT, ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA);
wrfl();
msleep(300);

/*
* The address field in the I2CCMD register is 3 bits and 0 is invalid.
* Therefore, we need to test 1-7
Expand All @@ -418,9 +428,12 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
phy->addr = 0;
ret_val = -E1000_ERR_PHY;
goto out;
} else {
ret_val = igb_get_phy_id(hw);
}

ret_val = igb_get_phy_id(hw);
/* restore previous sfp cage power state */
wr32(E1000_CTRL_EXT, ctrl_ext);

out:
return ret_val;
Expand Down Expand Up @@ -766,17 +779,18 @@ static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed,
}

/**
* igb_shutdown_fiber_serdes_link_82575 - Remove link during power down
* igb_shutdown_serdes_link_82575 - Remove link during power down
* @hw: pointer to the HW structure
*
* In the case of fiber serdes, shut down optics and PCS on driver unload
* when management pass thru is not enabled.
**/
void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw)
void igb_shutdown_serdes_link_82575(struct e1000_hw *hw)
{
u32 reg;

if (hw->phy.media_type != e1000_media_type_internal_serdes)
if (hw->phy.media_type != e1000_media_type_internal_serdes ||
igb_sgmii_active_82575(hw))
return;

/* if the management interface is not enabled, then power down */
Expand All @@ -788,7 +802,7 @@ void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw)

/* shutdown the laser */
reg = rd32(E1000_CTRL_EXT);
reg |= E1000_CTRL_EXT_SDP7_DATA;
reg |= E1000_CTRL_EXT_SDP3_DATA;
wr32(E1000_CTRL_EXT, reg);

/* flush the write to verify completion */
Expand Down Expand Up @@ -927,6 +941,17 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
wr32(E1000_CTRL, ctrl);

ret_val = igb_setup_serdes_link_82575(hw);
if (ret_val)
goto out;

if (igb_sgmii_active_82575(hw) && !hw->phy.reset_disable) {
ret_val = hw->phy.ops.reset(hw);
if (ret_val) {
hw_dbg("Error resetting the PHY.\n");
goto out;
}
}
switch (hw->phy.type) {
case e1000_phy_m88:
ret_val = igb_copper_link_setup_m88(hw);
Expand Down Expand Up @@ -963,8 +988,6 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
}
}

igb_configure_pcs_link_82575(hw);

/*
* Check link status. Wait up to 100 microseconds for link to become
* valid.
Expand All @@ -987,14 +1010,18 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
}

/**
* igb_setup_fiber_serdes_link_82575 - Setup link for fiber/serdes
* igb_setup_serdes_link_82575 - Setup link for fiber/serdes
* @hw: pointer to the HW structure
*
* Configures speed and duplex for fiber and serdes links.
**/
static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw)
static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw)
{
u32 reg;
u32 ctrl_reg, reg;

if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
!igb_sgmii_active_82575(hw))
return 0;

/*
* On the 82575, SerDes loopback mode persists until it is
Expand All @@ -1004,39 +1031,60 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw)
*/
wr32(E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);

/* Force link up, set 1gb, set both sw defined pins */
reg = rd32(E1000_CTRL);
reg |= E1000_CTRL_SLU |
E1000_CTRL_SPD_1000 |
E1000_CTRL_FRCSPD |
E1000_CTRL_SWDPIN0 |
E1000_CTRL_SWDPIN1;
wr32(E1000_CTRL, reg);

/* Power on phy for 82576 fiber adapters */
if (hw->mac.type == e1000_82576) {
reg = rd32(E1000_CTRL_EXT);
reg &= ~E1000_CTRL_EXT_SDP7_DATA;
wr32(E1000_CTRL_EXT, reg);
/* power on the sfp cage if present */
reg = rd32(E1000_CTRL_EXT);
reg &= ~E1000_CTRL_EXT_SDP3_DATA;
wr32(E1000_CTRL_EXT, reg);

ctrl_reg = rd32(E1000_CTRL);
ctrl_reg |= E1000_CTRL_SLU;

if (hw->mac.type == e1000_82575 || hw->mac.type == e1000_82576) {
/* set both sw defined pins */
ctrl_reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1;

/* Set switch control to serdes energy detect */
reg = rd32(E1000_CONNSW);
reg |= E1000_CONNSW_ENRGSRC;
wr32(E1000_CONNSW, reg);
}

reg = rd32(E1000_PCS_LCTL);

if (igb_sgmii_active_82575(hw)) {
/* allow time for SFP cage to power up phy */
msleep(300);

/* AN time out should be disabled for SGMII mode */
reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT);
} else {
ctrl_reg |= E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD |
E1000_CTRL_FD | E1000_CTRL_FRCDPX;
}

/* Set switch control to serdes energy detect */
reg = rd32(E1000_CONNSW);
reg |= E1000_CONNSW_ENRGSRC;
wr32(E1000_CONNSW, reg);
wr32(E1000_CTRL, ctrl_reg);

/*
* New SerDes mode allows for forcing speed or autonegotiating speed
* at 1gb. Autoneg should be default set by most drivers. This is the
* mode that will be compatible with older link partners and switches.
* However, both are supported by the hardware and some drivers/tools.
*/
reg = rd32(E1000_PCS_LCTL);

reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP |
E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK);

if (hw->mac.autoneg) {
/*
* We force flow control to prevent the CTRL register values from being
* overwritten by the autonegotiated flow control values
*/
reg |= E1000_PCS_LCTL_FORCE_FCTRL;

/*
* we always set sgmii to autoneg since it is the phy that will be
* forcing the link and the serdes is just a go-between
*/
if (hw->mac.autoneg || igb_sgmii_active_82575(hw)) {
/* Set PCS register for autoneg */
reg |= E1000_PCS_LCTL_FSV_1000 | /* Force 1000 */
E1000_PCS_LCTL_FDV_FULL | /* SerDes Full duplex */
Expand All @@ -1053,75 +1101,12 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw)
hw_dbg("Configuring Forced Link; PCS_LCTL = 0x%08X\n", reg);
}

if (hw->mac.type == e1000_82576) {
reg |= E1000_PCS_LCTL_FORCE_FCTRL;
igb_force_mac_fc(hw);
}

wr32(E1000_PCS_LCTL, reg);

return 0;
}

/**
* igb_configure_pcs_link_82575 - Configure PCS link
* @hw: pointer to the HW structure
*
* Configure the physical coding sub-layer (PCS) link. The PCS link is
* only used on copper connections where the serialized gigabit media
* independent interface (sgmii) is being used. Configures the link
* for auto-negotiation or forces speed/duplex.
**/
static void igb_configure_pcs_link_82575(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
u32 reg = 0;

if (hw->phy.media_type != e1000_media_type_copper ||
!(igb_sgmii_active_82575(hw)))
return;

/* For SGMII, we need to issue a PCS autoneg restart */
reg = rd32(E1000_PCS_LCTL);

/* AN time out should be disabled for SGMII mode */
reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT);

if (mac->autoneg) {
/* Make sure forced speed and force link are not set */
reg &= ~(E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK);

/*
* The PHY should be setup prior to calling this function.
* All we need to do is restart autoneg and enable autoneg.
*/
reg |= E1000_PCS_LCTL_AN_RESTART | E1000_PCS_LCTL_AN_ENABLE;
} else {
/* Set PCS register for forced speed */

/* Turn off bits for full duplex, speed, and autoneg */
reg &= ~(E1000_PCS_LCTL_FSV_1000 |
E1000_PCS_LCTL_FSV_100 |
E1000_PCS_LCTL_FDV_FULL |
E1000_PCS_LCTL_AN_ENABLE);

/* Check for duplex first */
if (mac->forced_speed_duplex & E1000_ALL_FULL_DUPLEX)
reg |= E1000_PCS_LCTL_FDV_FULL;

/* Now set speed */
if (mac->forced_speed_duplex & E1000_ALL_100_SPEED)
reg |= E1000_PCS_LCTL_FSV_100;

/* Force speed and force link */
reg |= E1000_PCS_LCTL_FSD |
E1000_PCS_LCTL_FORCE_LINK |
E1000_PCS_LCTL_FLV_LINK_UP;
if (!igb_sgmii_active_82575(hw))
igb_force_mac_fc(hw);

hw_dbg("Wrote 0x%08X to PCS_LCTL to configure forced link\n",
reg);
}
wr32(E1000_PCS_LCTL, reg);
return 0;
}

/**
Expand Down Expand Up @@ -1248,7 +1233,8 @@ static void igb_clear_hw_cntrs_82575(struct e1000_hw *hw)
temp = rd32(E1000_LENERRS);

/* This register should not be read in copper configurations */
if (hw->phy.media_type == e1000_media_type_internal_serdes)
if (hw->phy.media_type == e1000_media_type_internal_serdes ||
igb_sgmii_active_82575(hw))
temp = rd32(E1000_SCVPC);
}

Expand Down
2 changes: 1 addition & 1 deletion trunk/drivers/net/igb/e1000_82575.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#ifndef _E1000_82575_H_
#define _E1000_82575_H_

extern void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw);
extern void igb_shutdown_serdes_link_82575(struct e1000_hw *hw);
extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);

#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
Expand Down
2 changes: 1 addition & 1 deletion trunk/drivers/net/igb/e1000_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */

/* Extended Device Control */
#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Defineable Pin 3 */
/* Physical Func Reset Done Indication */
#define E1000_CTRL_EXT_PFRSTD 0x00004000
#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
Expand Down
2 changes: 1 addition & 1 deletion trunk/drivers/net/igb/igb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5320,7 +5320,7 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake)

*enable_wake = wufc || adapter->en_mng_pt;
if (!*enable_wake)
igb_shutdown_fiber_serdes_link_82575(hw);
igb_shutdown_serdes_link_82575(hw);

/* Release control of h/w to f/w. If f/w is AMT enabled, this
* would have already happened in close and is redundant. */
Expand Down

0 comments on commit a5ab647

Please sign in to comment.