aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/e1000/e1000_hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/e1000/e1000_hw.c')
-rw-r--r--drivers/net/e1000/e1000_hw.c685
1 files changed, 669 insertions, 16 deletions
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 5ee42c75adb160..63e237084a5141 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -100,6 +100,8 @@ static void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset,
#define E1000_WRITE_REG_IO(a, reg, val) \
e1000_write_reg_io((a), E1000_##reg, val)
+static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw);
+static int32_t e1000_configure_kmrn_for_1000(struct e1000_hw *hw);
/* IGP cable length table */
static const
@@ -153,6 +155,11 @@ e1000_set_phy_type(struct e1000_hw *hw)
hw->phy_type = e1000_phy_igp;
break;
}
+ case GG82563_E_PHY_ID:
+ if (hw->mac_type == e1000_80003es2lan) {
+ hw->phy_type = e1000_phy_gg82563;
+ break;
+ }
/* Fall Through */
default:
/* Should never have loaded on this device */
@@ -353,12 +360,19 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82573L:
hw->mac_type = e1000_82573;
break;
+ case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+ hw->mac_type = e1000_80003es2lan;
+ break;
default:
/* Should never have loaded on this device */
return -E1000_ERR_MAC_TYPE;
}
switch(hw->mac_type) {
+ case e1000_80003es2lan:
+ hw->swfw_sync_present = TRUE;
+ /* fall through */
case e1000_82571:
case e1000_82572:
case e1000_82573:
@@ -399,6 +413,7 @@ e1000_set_media_type(struct e1000_hw *hw)
case E1000_DEV_ID_82546GB_SERDES:
case E1000_DEV_ID_82571EB_SERDES:
case E1000_DEV_ID_82572EI_SERDES:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
hw->media_type = e1000_media_type_internal_serdes;
break;
default:
@@ -575,6 +590,7 @@ e1000_reset_hw(struct e1000_hw *hw)
/* fall through */
case e1000_82571:
case e1000_82572:
+ case e1000_80003es2lan:
ret_val = e1000_get_auto_rd_done(hw);
if(ret_val)
/* We don't want to continue accessing MAC registers. */
@@ -641,6 +657,7 @@ e1000_init_hw(struct e1000_hw *hw)
uint16_t cmd_mmrbc;
uint16_t stat_mmrbc;
uint32_t mta_size;
+ uint32_t reg_data;
uint32_t ctrl_ext;
DEBUGFUNC("e1000_init_hw");
@@ -739,6 +756,7 @@ e1000_init_hw(struct e1000_hw *hw)
case e1000_82571:
case e1000_82572:
case e1000_82573:
+ case e1000_80003es2lan:
ctrl |= E1000_TXDCTL_COUNT_DESC;
break;
}
@@ -752,12 +770,34 @@ e1000_init_hw(struct e1000_hw *hw)
switch (hw->mac_type) {
default:
break;
+ case e1000_80003es2lan:
+ /* Enable retransmit on late collisions */
+ reg_data = E1000_READ_REG(hw, TCTL);
+ reg_data |= E1000_TCTL_RTLC;
+ E1000_WRITE_REG(hw, TCTL, reg_data);
+
+ /* Configure Gigabit Carry Extend Padding */
+ reg_data = E1000_READ_REG(hw, TCTL_EXT);
+ reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
+ reg_data |= DEFAULT_80003ES2LAN_TCTL_EXT_GCEX;
+ E1000_WRITE_REG(hw, TCTL_EXT, reg_data);
+
+ /* Configure Transmit Inter-Packet Gap */
+ reg_data = E1000_READ_REG(hw, TIPG);
+ reg_data &= ~E1000_TIPG_IPGT_MASK;
+ reg_data |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000;
+ E1000_WRITE_REG(hw, TIPG, reg_data);
+
+ reg_data = E1000_READ_REG_ARRAY(hw, FFLT, 0x0001);
+ reg_data &= ~0x00100000;
+ E1000_WRITE_REG_ARRAY(hw, FFLT, 0x0001, reg_data);
+ /* Fall through */
case e1000_82571:
case e1000_82572:
ctrl = E1000_READ_REG(hw, TXDCTL1);
- ctrl &= ~E1000_TXDCTL_WTHRESH;
- ctrl |= E1000_TXDCTL_COUNT_DESC | E1000_TXDCTL_FULL_TX_DESC_WB;
- ctrl |= (1 << 22);
+ ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
+ if(hw->mac_type >= e1000_82571)
+ ctrl |= E1000_TXDCTL_COUNT_DESC;
E1000_WRITE_REG(hw, TXDCTL1, ctrl);
break;
}
@@ -1314,6 +1354,154 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw)
return E1000_SUCCESS;
}
+/********************************************************************
+* Copper link setup for e1000_phy_gg82563 series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_ggp_setup(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+ uint32_t reg_data;
+
+ DEBUGFUNC("e1000_copper_link_ggp_setup");
+
+ if(!hw->phy_reset_disable) {
+
+ /* Enable CRS on TX for half-duplex operation. */
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
+ &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+ /* Use 25MHz for both link down and 1000BASE-T for Tx clock */
+ phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
+
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
+ phy_data);
+ if(ret_val)
+ return ret_val;
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_SPEC_CTRL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
+
+ switch (hw->mdix) {
+ case 1:
+ phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
+ break;
+ case 2:
+ phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
+ break;
+ case 0:
+ default:
+ phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
+ break;
+ }
+
+ /* Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+ if(hw->disable_polarity_correction == 1)
+ phy_data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_SPEC_CTRL, phy_data);
+
+ if(ret_val)
+ return ret_val;
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = e1000_phy_reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ return ret_val;
+ }
+ } /* phy_reset_disable */
+
+ if (hw->mac_type == e1000_80003es2lan) {
+ /* Bypass RX and TX FIFO's */
+ ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_FIFO_CTRL,
+ E1000_KUMCTRLSTA_FIFO_CTRL_RX_BYPASS |
+ E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_SPEC_CTRL_2, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_SPEC_CTRL_2, phy_data);
+
+ if (ret_val)
+ return ret_val;
+
+ reg_data = E1000_READ_REG(hw, CTRL_EXT);
+ reg_data &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
+ E1000_WRITE_REG(hw, CTRL_EXT, reg_data);
+
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_PWR_MGMT_CTRL,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Do not init these registers when the HW is in IAMT mode, since the
+ * firmware will have already initialized them. We only initialize
+ * them if the HW is not in IAMT mode.
+ */
+ if (e1000_check_mng_mode(hw) == FALSE) {
+ /* Enable Electrical Idle on the PHY */
+ phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_PWR_MGMT_CTRL,
+ phy_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Enable Pass False Carrier on the PHY */
+ phy_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Workaround: Disable padding in Kumeran interface in the MAC
+ * and in the PHY to avoid CRC errors.
+ */
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_INBAND_CTRL,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+ phy_data |= GG82563_ICR_DIS_PADDING;
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_INBAND_CTRL,
+ phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+}
/********************************************************************
* Copper link setup for e1000_phy_m88 series.
@@ -1524,6 +1712,7 @@ e1000_setup_copper_link(struct e1000_hw *hw)
int32_t ret_val;
uint16_t i;
uint16_t phy_data;
+ uint16_t reg_data;
DEBUGFUNC("e1000_setup_copper_link");
@@ -1532,6 +1721,22 @@ e1000_setup_copper_link(struct e1000_hw *hw)
if(ret_val)
return ret_val;
+ switch (hw->mac_type) {
+ case e1000_80003es2lan:
+ ret_val = e1000_read_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL,
+ &reg_data);
+ if (ret_val)
+ return ret_val;
+ reg_data |= E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING;
+ ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL,
+ reg_data);
+ if (ret_val)
+ return ret_val;
+ break;
+ default:
+ break;
+ }
+
if (hw->phy_type == e1000_phy_igp ||
hw->phy_type == e1000_phy_igp_2) {
ret_val = e1000_copper_link_igp_setup(hw);
@@ -1541,6 +1746,10 @@ e1000_setup_copper_link(struct e1000_hw *hw)
ret_val = e1000_copper_link_mgp_setup(hw);
if(ret_val)
return ret_val;
+ } else if (hw->phy_type == e1000_phy_gg82563) {
+ ret_val = e1000_copper_link_ggp_setup(hw);
+ if(ret_val)
+ return ret_val;
}
if(hw->autoneg) {
@@ -1588,6 +1797,59 @@ e1000_setup_copper_link(struct e1000_hw *hw)
}
/******************************************************************************
+* Configure the MAC-to-PHY interface for 10/100Mbps
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_configure_kmrn_for_10_100(struct e1000_hw *hw)
+{
+ int32_t ret_val = E1000_SUCCESS;
+ uint32_t tipg;
+ uint16_t reg_data;
+
+ DEBUGFUNC("e1000_configure_kmrn_for_10_100");
+
+ reg_data = E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT;
+ ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = E1000_READ_REG(hw, TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_10_100;
+ E1000_WRITE_REG(hw, TIPG, tipg);
+
+ return ret_val;
+}
+
+static int32_t
+e1000_configure_kmrn_for_1000(struct e1000_hw *hw)
+{
+ int32_t ret_val = E1000_SUCCESS;
+ uint16_t reg_data;
+ uint32_t tipg;
+
+ DEBUGFUNC("e1000_configure_kmrn_for_1000");
+
+ reg_data = E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT;
+ ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = E1000_READ_REG(hw, TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000;
+ E1000_WRITE_REG(hw, TIPG, tipg);
+
+ return ret_val;
+}
+
+/******************************************************************************
* Configures PHY autoneg and flow control advertisement settings
*
* hw - Struct containing variables accessed by shared code
@@ -1808,7 +2070,8 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
/* Write the configured values back to the Device Control Reg. */
E1000_WRITE_REG(hw, CTRL, ctrl);
- if (hw->phy_type == e1000_phy_m88) {
+ if ((hw->phy_type == e1000_phy_m88) ||
+ (hw->phy_type == e1000_phy_gg82563)) {
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
if(ret_val)
return ret_val;
@@ -1877,7 +2140,8 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
msec_delay(100);
}
if((i == 0) &&
- (hw->phy_type == e1000_phy_m88)) {
+ ((hw->phy_type == e1000_phy_m88) ||
+ (hw->phy_type == e1000_phy_gg82563))) {
/* We didn't get link. Reset the DSP and wait again for link. */
ret_val = e1000_phy_reset_dsp(hw);
if(ret_val) {
@@ -1936,6 +2200,27 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
if(ret_val)
return ret_val;
}
+ } else if (hw->phy_type == e1000_phy_gg82563) {
+ /* The TX_CLK of the Extended PHY Specific Control Register defaults
+ * to 2.5MHz on a reset. We need to re-force it back to 25MHz, if
+ * we're not in a forced 10/duplex configuration. */
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
+ if ((hw->forced_speed_duplex == e1000_10_full) ||
+ (hw->forced_speed_duplex == e1000_10_half))
+ phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ;
+ else
+ phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ;
+
+ /* Also due to the reset, we need to enable CRS on Tx. */
+ phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
}
return E1000_SUCCESS;
}
@@ -2598,6 +2883,16 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw,
}
}
+ if ((hw->mac_type == e1000_80003es2lan) &&
+ (hw->media_type == e1000_media_type_copper)) {
+ if (*speed == SPEED_1000)
+ ret_val = e1000_configure_kmrn_for_1000(hw);
+ else
+ ret_val = e1000_configure_kmrn_for_10_100(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
return E1000_SUCCESS;
}
@@ -2773,6 +3068,72 @@ e1000_shift_in_mdi_bits(struct e1000_hw *hw)
return data;
}
+int32_t
+e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask)
+{
+ uint32_t swfw_sync = 0;
+ uint32_t swmask = mask;
+ uint32_t fwmask = mask << 16;
+ int32_t timeout = 200;
+
+ DEBUGFUNC("e1000_swfw_sync_acquire");
+
+ if (!hw->swfw_sync_present)
+ return e1000_get_hw_eeprom_semaphore(hw);
+
+ while(timeout) {
+ if (e1000_get_hw_eeprom_semaphore(hw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ swfw_sync = E1000_READ_REG(hw, SW_FW_SYNC);
+ if (!(swfw_sync & (fwmask | swmask))) {
+ break;
+ }
+
+ /* firmware currently using resource (fwmask) */
+ /* or other software thread currently using resource (swmask) */
+ e1000_put_hw_eeprom_semaphore(hw);
+ msec_delay_irq(5);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
+ return -E1000_ERR_SWFW_SYNC;
+ }
+
+ swfw_sync |= swmask;
+ E1000_WRITE_REG(hw, SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_eeprom_semaphore(hw);
+ return E1000_SUCCESS;
+}
+
+void
+e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask)
+{
+ uint32_t swfw_sync;
+ uint32_t swmask = mask;
+
+ DEBUGFUNC("e1000_swfw_sync_release");
+
+ if (!hw->swfw_sync_present) {
+ e1000_put_hw_eeprom_semaphore(hw);
+ return;
+ }
+
+ /* if (e1000_get_hw_eeprom_semaphore(hw))
+ * return -E1000_ERR_SWFW_SYNC; */
+ while (e1000_get_hw_eeprom_semaphore(hw) != E1000_SUCCESS);
+ /* empty */
+
+ swfw_sync = E1000_READ_REG(hw, SW_FW_SYNC);
+ swfw_sync &= ~swmask;
+ E1000_WRITE_REG(hw, SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_eeprom_semaphore(hw);
+}
+
/*****************************************************************************
* Reads the value from a PHY register, if the value is on a specific non zero
* page, sets the page first.
@@ -2785,22 +3146,55 @@ e1000_read_phy_reg(struct e1000_hw *hw,
uint16_t *phy_data)
{
uint32_t ret_val;
+ uint16_t swfw;
DEBUGFUNC("e1000_read_phy_reg");
+ if ((hw->mac_type == e1000_80003es2lan) &&
+ (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
+ swfw = E1000_SWFW_PHY1_SM;
+ } else {
+ swfw = E1000_SWFW_PHY0_SM;
+ }
+ if (e1000_swfw_sync_acquire(hw, swfw))
+ return -E1000_ERR_SWFW_SYNC;
+
if((hw->phy_type == e1000_phy_igp ||
hw->phy_type == e1000_phy_igp_2) &&
(reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
(uint16_t)reg_addr);
if(ret_val) {
+ e1000_swfw_sync_release(hw, swfw);
return ret_val;
}
+ } else if (hw->phy_type == e1000_phy_gg82563) {
+ if (((reg_addr & MAX_PHY_REG_ADDRESS) > MAX_PHY_MULTI_PAGE_REG) ||
+ (hw->mac_type == e1000_80003es2lan)) {
+ /* Select Configuration Page */
+ if ((reg_addr & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
+ ret_val = e1000_write_phy_reg_ex(hw, GG82563_PHY_PAGE_SELECT,
+ (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT));
+ } else {
+ /* Use Alternative Page Select register to access
+ * registers 30 and 31
+ */
+ ret_val = e1000_write_phy_reg_ex(hw,
+ GG82563_PHY_PAGE_SELECT_ALT,
+ (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT));
+ }
+
+ if (ret_val) {
+ e1000_swfw_sync_release(hw, swfw);
+ return ret_val;
+ }
+ }
}
ret_val = e1000_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
phy_data);
+ e1000_swfw_sync_release(hw, swfw);
return ret_val;
}
@@ -2891,22 +3285,55 @@ e1000_write_phy_reg(struct e1000_hw *hw,
uint16_t phy_data)
{
uint32_t ret_val;
+ uint16_t swfw;
DEBUGFUNC("e1000_write_phy_reg");
+ if ((hw->mac_type == e1000_80003es2lan) &&
+ (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
+ swfw = E1000_SWFW_PHY1_SM;
+ } else {
+ swfw = E1000_SWFW_PHY0_SM;
+ }
+ if (e1000_swfw_sync_acquire(hw, swfw))
+ return -E1000_ERR_SWFW_SYNC;
+
if((hw->phy_type == e1000_phy_igp ||
hw->phy_type == e1000_phy_igp_2) &&
(reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
(uint16_t)reg_addr);
if(ret_val) {
+ e1000_swfw_sync_release(hw, swfw);
return ret_val;
}
+ } else if (hw->phy_type == e1000_phy_gg82563) {
+ if (((reg_addr & MAX_PHY_REG_ADDRESS) > MAX_PHY_MULTI_PAGE_REG) ||
+ (hw->mac_type == e1000_80003es2lan)) {
+ /* Select Configuration Page */
+ if ((reg_addr & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
+ ret_val = e1000_write_phy_reg_ex(hw, GG82563_PHY_PAGE_SELECT,
+ (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT));
+ } else {
+ /* Use Alternative Page Select register to access
+ * registers 30 and 31
+ */
+ ret_val = e1000_write_phy_reg_ex(hw,
+ GG82563_PHY_PAGE_SELECT_ALT,
+ (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT));
+ }
+
+ if (ret_val) {
+ e1000_swfw_sync_release(hw, swfw);
+ return ret_val;
+ }
+ }
}
ret_val = e1000_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
phy_data);
+ e1000_swfw_sync_release(hw, swfw);
return ret_val;
}
@@ -2973,6 +3400,65 @@ e1000_write_phy_reg_ex(struct e1000_hw *hw,
return E1000_SUCCESS;
}
+int32_t
+e1000_read_kmrn_reg(struct e1000_hw *hw,
+ uint32_t reg_addr,
+ uint16_t *data)
+{
+ uint32_t reg_val;
+ uint16_t swfw;
+ DEBUGFUNC("e1000_read_kmrn_reg");
+
+ if ((hw->mac_type == e1000_80003es2lan) &&
+ (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
+ swfw = E1000_SWFW_PHY1_SM;
+ } else {
+ swfw = E1000_SWFW_PHY0_SM;
+ }
+ if (e1000_swfw_sync_acquire(hw, swfw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ /* Write register address */
+ reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) &
+ E1000_KUMCTRLSTA_OFFSET) |
+ E1000_KUMCTRLSTA_REN;
+ E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val);
+ udelay(2);
+
+ /* Read the data returned */
+ reg_val = E1000_READ_REG(hw, KUMCTRLSTA);
+ *data = (uint16_t)reg_val;
+
+ e1000_swfw_sync_release(hw, swfw);
+ return E1000_SUCCESS;
+}
+
+int32_t
+e1000_write_kmrn_reg(struct e1000_hw *hw,
+ uint32_t reg_addr,
+ uint16_t data)
+{
+ uint32_t reg_val;
+ uint16_t swfw;
+ DEBUGFUNC("e1000_write_kmrn_reg");
+
+ if ((hw->mac_type == e1000_80003es2lan) &&
+ (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
+ swfw = E1000_SWFW_PHY1_SM;
+ } else {
+ swfw = E1000_SWFW_PHY0_SM;
+ }
+ if (e1000_swfw_sync_acquire(hw, swfw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) &
+ E1000_KUMCTRLSTA_OFFSET) | data;
+ E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val);
+ udelay(2);
+
+ e1000_swfw_sync_release(hw, swfw);
+ return E1000_SUCCESS;
+}
/******************************************************************************
* Returns the PHY to the power-on reset state
@@ -2985,6 +3471,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
uint32_t ctrl, ctrl_ext;
uint32_t led_ctrl;
int32_t ret_val;
+ uint16_t swfw;
DEBUGFUNC("e1000_phy_hw_reset");
@@ -2997,6 +3484,16 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
DEBUGOUT("Resetting Phy...\n");
if(hw->mac_type > e1000_82543) {
+ if ((hw->mac_type == e1000_80003es2lan) &&
+ (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
+ swfw = E1000_SWFW_PHY1_SM;
+ } else {
+ swfw = E1000_SWFW_PHY0_SM;
+ }
+ if (e1000_swfw_sync_acquire(hw, swfw)) {
+ e1000_release_software_semaphore(hw);
+ return -E1000_ERR_SWFW_SYNC;
+ }
/* Read the device control register and assert the E1000_CTRL_PHY_RST
* bit. Then, take it out of reset.
* For pre-e1000_82571 hardware, we delay for 10ms between the assert
@@ -3017,6 +3514,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
if (hw->mac_type >= e1000_82571)
msec_delay(10);
+ e1000_swfw_sync_release(hw, swfw);
} else {
/* Read the Extended Device Control Register, assert the PHY_RESET_DIR
* bit to put the PHY into reset. Then, take it out of reset.
@@ -3043,6 +3541,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
/* Wait for FW to finish PHY configuration. */
ret_val = e1000_get_phy_cfg_done(hw);
+ e1000_release_software_semaphore(hw);
return ret_val;
}
@@ -3120,6 +3619,15 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
return E1000_SUCCESS;
}
+ /* ESB-2 PHY reads require e1000_phy_gg82563 to be set because of a work-
+ * around that forces PHY page 0 to be set or the reads fail. The rest of
+ * the code in this routine uses e1000_read_phy_reg to read the PHY ID.
+ * So for ESB-2 we need to have this set so our reads won't fail. If the
+ * attached PHY is not a e1000_phy_gg82563, the routines below will figure
+ * this out as well. */
+ if (hw->mac_type == e1000_80003es2lan)
+ hw->phy_type = e1000_phy_gg82563;
+
/* Read the PHY ID Registers to identify which PHY is onboard. */
ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high);
if(ret_val)
@@ -3157,6 +3665,9 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
case e1000_82573:
if(hw->phy_id == M88E1111_I_PHY_ID) match = TRUE;
break;
+ case e1000_80003es2lan:
+ if (hw->phy_id == GG82563_E_PHY_ID) match = TRUE;
+ break;
default:
DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
return -E1000_ERR_CONFIG;
@@ -3183,8 +3694,10 @@ e1000_phy_reset_dsp(struct e1000_hw *hw)
DEBUGFUNC("e1000_phy_reset_dsp");
do {
- ret_val = e1000_write_phy_reg(hw, 29, 0x001d);
- if(ret_val) break;
+ if (hw->phy_type != e1000_phy_gg82563) {
+ ret_val = e1000_write_phy_reg(hw, 29, 0x001d);
+ if(ret_val) break;
+ }
ret_val = e1000_write_phy_reg(hw, 30, 0x00c1);
if(ret_val) break;
ret_val = e1000_write_phy_reg(hw, 30, 0x0000);
@@ -3316,8 +3829,17 @@ e1000_phy_m88_get_info(struct e1000_hw *hw,
/* Cable Length Estimation and Local/Remote Receiver Information
* are only valid at 1000 Mbps.
*/
- phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
- M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+ if (hw->phy_type != e1000_phy_gg82563) {
+ phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+ } else {
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_DSP_DISTANCE,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_info->cable_length = phy_data & GG82563_DSPD_CABLE_LENGTH;
+ }
ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
if(ret_val)
@@ -3511,6 +4033,20 @@ e1000_init_eeprom_params(struct e1000_hw *hw)
E1000_WRITE_REG(hw, EECD, eecd);
}
break;
+ case e1000_80003es2lan:
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ eeprom->use_eerd = TRUE;
+ eeprom->use_eewr = FALSE;
+ break;
default:
break;
}
@@ -3691,9 +4227,8 @@ e1000_acquire_eeprom(struct e1000_hw *hw)
DEBUGFUNC("e1000_acquire_eeprom");
- if(e1000_get_hw_eeprom_semaphore(hw))
- return -E1000_ERR_EEPROM;
-
+ if (e1000_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM))
+ return -E1000_ERR_SWFW_SYNC;
eecd = E1000_READ_REG(hw, EECD);
if (hw->mac_type != e1000_82573) {
@@ -3712,7 +4247,7 @@ e1000_acquire_eeprom(struct e1000_hw *hw)
eecd &= ~E1000_EECD_REQ;
E1000_WRITE_REG(hw, EECD, eecd);
DEBUGOUT("Could not acquire EEPROM grant\n");
- e1000_put_hw_eeprom_semaphore(hw);
+ e1000_swfw_sync_release(hw, E1000_SWFW_EEP_SM);
return -E1000_ERR_EEPROM;
}
}
@@ -3835,7 +4370,7 @@ e1000_release_eeprom(struct e1000_hw *hw)
E1000_WRITE_REG(hw, EECD, eecd);
}
- e1000_put_hw_eeprom_semaphore(hw);
+ e1000_swfw_sync_release(hw, E1000_SWFW_EEP_SM);
}
/******************************************************************************
@@ -3914,6 +4449,8 @@ e1000_read_eeprom(struct e1000_hw *hw,
if (e1000_is_onboard_nvm_eeprom(hw) == TRUE &&
hw->eeprom.use_eerd == FALSE) {
switch (hw->mac_type) {
+ case e1000_80003es2lan:
+ break;
default:
/* Prepare the EEPROM for reading */
if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
@@ -4031,6 +4568,9 @@ e1000_write_eeprom_eewr(struct e1000_hw *hw,
uint32_t i = 0;
int32_t error = 0;
+ if (e1000_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM))
+ return -E1000_ERR_SWFW_SYNC;
+
for (i = 0; i < words; i++) {
register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) |
((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) |
@@ -4050,6 +4590,7 @@ e1000_write_eeprom_eewr(struct e1000_hw *hw,
}
}
+ e1000_swfw_sync_release(hw, E1000_SWFW_EEP_SM);
return error;
}
@@ -4091,6 +4632,8 @@ e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw)
{
uint32_t eecd = 0;
+ DEBUGFUNC("e1000_is_onboard_nvm_eeprom");
+
if(hw->mac_type == e1000_82573) {
eecd = E1000_READ_REG(hw, EECD);
@@ -4517,6 +5060,7 @@ e1000_read_mac_addr(struct e1000_hw * hw)
case e1000_82546:
case e1000_82546_rev_3:
case e1000_82571:
+ case e1000_80003es2lan:
if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
hw->perm_mac_addr[5] ^= 0x01;
break;
@@ -4778,6 +5322,7 @@ e1000_rar_set(struct e1000_hw *hw,
switch (hw->mac_type) {
case e1000_82571:
case e1000_82572:
+ case e1000_80003es2lan:
if (hw->leave_av_bit_off == TRUE)
break;
default:
@@ -5364,6 +5909,7 @@ e1000_get_bus_info(struct e1000_hw *hw)
hw->bus_width = e1000_bus_width_pciex_1;
break;
case e1000_82571:
+ case e1000_80003es2lan:
hw->bus_type = e1000_bus_type_pci_express;
hw->bus_speed = e1000_bus_speed_2500;
hw->bus_width = e1000_bus_width_pciex_4;
@@ -5509,6 +6055,34 @@ e1000_get_cable_length(struct e1000_hw *hw,
return -E1000_ERR_PHY;
break;
}
+ } else if (hw->phy_type == e1000_phy_gg82563) {
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_DSP_DISTANCE,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+ cable_length = phy_data & GG82563_DSPD_CABLE_LENGTH;
+
+ switch (cable_length) {
+ case e1000_gg_cable_length_60:
+ *min_length = 0;
+ *max_length = e1000_igp_cable_length_60;
+ break;
+ case e1000_gg_cable_length_60_115:
+ *min_length = e1000_igp_cable_length_60;
+ *max_length = e1000_igp_cable_length_115;
+ break;
+ case e1000_gg_cable_length_115_150:
+ *min_length = e1000_igp_cable_length_115;
+ *max_length = e1000_igp_cable_length_150;
+ break;
+ case e1000_gg_cable_length_150:
+ *min_length = e1000_igp_cable_length_150;
+ *max_length = e1000_igp_cable_length_180;
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
} else if(hw->phy_type == e1000_phy_igp) { /* For IGP PHY */
uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
{IGP01E1000_PHY_AGC_A,
@@ -5618,7 +6192,8 @@ e1000_check_polarity(struct e1000_hw *hw,
DEBUGFUNC("e1000_check_polarity");
- if(hw->phy_type == e1000_phy_m88) {
+ if ((hw->phy_type == e1000_phy_m88) ||
+ (hw->phy_type == e1000_phy_gg82563)) {
/* return the Polarity bit in the Status register. */
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
&phy_data);
@@ -5687,7 +6262,8 @@ e1000_check_downshift(struct e1000_hw *hw)
return ret_val;
hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
- } else if(hw->phy_type == e1000_phy_m88) {
+ } else if ((hw->phy_type == e1000_phy_m88) ||
+ (hw->phy_type == e1000_phy_gg82563)) {
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
&phy_data);
if(ret_val)
@@ -6720,6 +7296,7 @@ e1000_get_auto_rd_done(struct e1000_hw *hw)
case e1000_82571:
case e1000_82572:
case e1000_82573:
+ case e1000_80003es2lan:
while(timeout) {
if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break;
else msec_delay(1);
@@ -6763,6 +7340,11 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw)
default:
msec_delay(10);
break;
+ case e1000_80003es2lan:
+ /* Separate *_CFG_DONE_* bit for each port */
+ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
+ cfg_mask = E1000_EEPROM_CFG_DONE_PORT_1;
+ /* Fall Through */
case e1000_82571:
case e1000_82572:
while (timeout) {
@@ -6805,6 +7387,11 @@ e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw)
if(!hw->eeprom_semaphore_present)
return E1000_SUCCESS;
+ if (hw->mac_type == e1000_80003es2lan) {
+ /* Get the SW semaphore. */
+ if (e1000_get_software_semaphore(hw) != E1000_SUCCESS)
+ return -E1000_ERR_EEPROM;
+ }
/* Get the FW semaphore. */
timeout = hw->eeprom.word_size + 1;
@@ -6850,10 +7437,75 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw)
return;
swsm = E1000_READ_REG(hw, SWSM);
+ if (hw->mac_type == e1000_80003es2lan) {
+ /* Release both semaphores. */
+ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+ } else
swsm &= ~(E1000_SWSM_SWESMBI);
E1000_WRITE_REG(hw, SWSM, swsm);
}
+/***************************************************************************
+ *
+ * Obtaining software semaphore bit (SMBI) before resetting PHY.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to obtain semaphore.
+ * E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+int32_t
+e1000_get_software_semaphore(struct e1000_hw *hw)
+{
+ int32_t timeout = hw->eeprom.word_size + 1;
+ uint32_t swsm;
+
+ DEBUGFUNC("e1000_get_software_semaphore");
+
+ if (hw->mac_type != e1000_80003es2lan)
+ return E1000_SUCCESS;
+
+ while(timeout) {
+ swsm = E1000_READ_REG(hw, SWSM);
+ /* If SMBI bit cleared, it is now set and we hold the semaphore */
+ if(!(swsm & E1000_SWSM_SMBI))
+ break;
+ msec_delay_irq(1);
+ timeout--;
+ }
+
+ if(!timeout) {
+ DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+ return -E1000_ERR_RESET;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Release semaphore bit (SMBI).
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+void
+e1000_release_software_semaphore(struct e1000_hw *hw)
+{
+ uint32_t swsm;
+
+ DEBUGFUNC("e1000_release_software_semaphore");
+
+ if (hw->mac_type != e1000_80003es2lan)
+ return;
+
+ swsm = E1000_READ_REG(hw, SWSM);
+ /* Release the SW semaphores.*/
+ swsm &= ~E1000_SWSM_SMBI;
+ E1000_WRITE_REG(hw, SWSM, swsm);
+}
+
/******************************************************************************
* Checks if PHY reset is blocked due to SOL/IDER session, for example.
* Returning E1000_BLK_PHY_RESET isn't necessarily an error. But it's up to
@@ -6890,6 +7542,7 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw)
case e1000_82571:
case e1000_82572:
case e1000_82573:
+ case e1000_80003es2lan:
fwsm = E1000_READ_REG(hw, FWSM);
if((fwsm & E1000_FWSM_MODE_MASK) != 0)
return TRUE;