summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjfv <jfv@FreeBSD.org>2013-10-09 17:32:52 +0000
committerjfv <jfv@FreeBSD.org>2013-10-09 17:32:52 +0000
commit7f364f2263dcbf5399bd43a3676145dd57c6613b (patch)
tree80e36a3cb165b639d4fd372f16d06bc2164bf056 /sys
parent3c43c9607a3f047c556868968167920bbf3e93ab (diff)
downloadFreeBSD-src-7f364f2263dcbf5399bd43a3676145dd57c6613b.zip
FreeBSD-src-7f364f2263dcbf5399bd43a3676145dd57c6613b.tar.gz
Update the Intel igb driver to version 2.4.0
- This version has support for the new Intel Avoton systems, including 2.5Gb support, further it now has IPv6/TSO6 support as well. Shared code has been updated where necessary as well. Thanks to my new assistant Eric Joyner for doing the transmit path changes to bring in the IPv6/TSO6 support. Thanks to Gleb for catching the one bug and change needed in NETMAP. Approved by: re
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/e1000/e1000_80003es2lan.c358
-rw-r--r--sys/dev/e1000/e1000_80003es2lan.h12
-rw-r--r--sys/dev/e1000/e1000_82571.c27
-rw-r--r--sys/dev/e1000/e1000_82575.c325
-rw-r--r--sys/dev/e1000/e1000_82575.h5
-rw-r--r--sys/dev/e1000/e1000_api.c11
-rw-r--r--sys/dev/e1000/e1000_defines.h40
-rw-r--r--sys/dev/e1000/e1000_hw.h16
-rw-r--r--sys/dev/e1000/e1000_i210.c267
-rw-r--r--sys/dev/e1000/e1000_i210.h8
-rw-r--r--sys/dev/e1000/e1000_ich8lan.c436
-rw-r--r--sys/dev/e1000/e1000_ich8lan.h50
-rw-r--r--sys/dev/e1000/e1000_mac.c40
-rw-r--r--sys/dev/e1000/e1000_osdep.h1
-rw-r--r--sys/dev/e1000/e1000_phy.c285
-rw-r--r--sys/dev/e1000/e1000_phy.h18
-rw-r--r--sys/dev/e1000/e1000_regs.h12
-rw-r--r--sys/dev/e1000/e1000_vf.h106
-rw-r--r--sys/dev/e1000/if_igb.c933
-rw-r--r--sys/dev/e1000/if_igb.h255
-rw-r--r--sys/dev/netmap/if_igb_netmap.h2
21 files changed, 2004 insertions, 1203 deletions
diff --git a/sys/dev/e1000/e1000_80003es2lan.c b/sys/dev/e1000/e1000_80003es2lan.c
index bdbb31c..076e02b 100644
--- a/sys/dev/e1000/e1000_80003es2lan.c
+++ b/sys/dev/e1000/e1000_80003es2lan.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2013, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,12 @@
******************************************************************************/
/*$FreeBSD$*/
-/*
- * 80003ES2LAN Gigabit Ethernet Controller (Copper)
+/* 80003ES2LAN Gigabit Ethernet Controller (Copper)
* 80003ES2LAN Gigabit Ethernet Controller (Serdes)
*/
#include "e1000_api.h"
-static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw);
-static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw);
-static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw);
static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw);
static void e1000_release_phy_80003es2lan(struct e1000_hw *hw);
static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw);
@@ -71,14 +67,12 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
u16 *data);
static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
u16 data);
-static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw);
static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw);
static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw);
static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw);
-/*
- * A table for the GG82563 cable length where the range is defined
+/* A table for the GG82563 cable length where the range is defined
* with a lower bound at "index" and the upper bound at
* "index + 5".
*/
@@ -95,13 +89,13 @@ static const u16 e1000_gg82563_cable_length_table[] = {
static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_init_phy_params_80003es2lan");
if (hw->phy.media_type != e1000_media_type_copper) {
phy->type = e1000_phy_none;
- goto out;
+ return E1000_SUCCESS;
} else {
phy->ops.power_up = e1000_power_up_phy_copper;
phy->ops.power_down = e1000_power_down_phy_copper_80003es2lan;
@@ -133,12 +127,9 @@ static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw)
ret_val = e1000_get_phy_id(hw);
/* Verify phy id */
- if (phy->id != GG82563_E_PHY_ID) {
- ret_val = -E1000_ERR_PHY;
- goto out;
- }
+ if (phy->id != GG82563_E_PHY_ID)
+ return -E1000_ERR_PHY;
-out:
return ret_val;
}
@@ -176,8 +167,7 @@ static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
E1000_EECD_SIZE_EX_SHIFT);
- /*
- * Added to a constant, "size" becomes the left-shift value
+ /* Added to a constant, "size" becomes the left-shift value
* for setting word_size.
*/
size += NVM_WORD_SIZE_BASE_SHIFT;
@@ -234,8 +224,8 @@ static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw)
/* FWSM register */
mac->has_fwsm = TRUE;
/* ARC supported; valid only if manageability features are enabled. */
- mac->arc_subsystem_valid = (E1000_READ_REG(hw, E1000_FWSM) &
- E1000_FWSM_MODE_MASK) ? TRUE : FALSE;
+ mac->arc_subsystem_valid = !!(E1000_READ_REG(hw, E1000_FWSM) &
+ E1000_FWSM_MODE_MASK);
/* Adaptive IFS not supported */
mac->adaptive_ifs = FALSE;
@@ -377,14 +367,13 @@ static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw)
ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = e1000_acquire_nvm_generic(hw);
if (ret_val)
e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
-out:
return ret_val;
}
@@ -415,23 +404,20 @@ static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
u32 swfw_sync;
u32 swmask = mask;
u32 fwmask = mask << 16;
- s32 ret_val = E1000_SUCCESS;
- s32 i = 0, timeout = 50;
+ s32 i = 0;
+ s32 timeout = 50;
DEBUGFUNC("e1000_acquire_swfw_sync_80003es2lan");
while (i < timeout) {
- if (e1000_get_hw_semaphore_generic(hw)) {
- ret_val = -E1000_ERR_SWFW_SYNC;
- goto out;
- }
+ if (e1000_get_hw_semaphore_generic(hw))
+ return -E1000_ERR_SWFW_SYNC;
swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
if (!(swfw_sync & (fwmask | swmask)))
break;
- /*
- * Firmware currently using resource (fwmask)
+ /* Firmware currently using resource (fwmask)
* or other software thread using resource (swmask)
*/
e1000_put_hw_semaphore_generic(hw);
@@ -441,8 +427,7 @@ static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
if (i == timeout) {
DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
- ret_val = -E1000_ERR_SWFW_SYNC;
- goto out;
+ return -E1000_ERR_SWFW_SYNC;
}
swfw_sync |= swmask;
@@ -450,8 +435,7 @@ static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
e1000_put_hw_semaphore_generic(hw);
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -497,14 +481,13 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
ret_val = e1000_acquire_phy_80003es2lan(hw);
if (ret_val)
- goto out;
+ return ret_val;
/* Select Configuration Page */
if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
page_select = GG82563_PHY_PAGE_SELECT;
} else {
- /*
- * Use Alternative Page Select register to access
+ /* Use Alternative Page Select register to access
* registers 30 and 31
*/
page_select = GG82563_PHY_PAGE_SELECT_ALT;
@@ -514,12 +497,11 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
ret_val = e1000_write_phy_reg_mdic(hw, page_select, temp);
if (ret_val) {
e1000_release_phy_80003es2lan(hw);
- goto out;
+ return ret_val;
}
- if (hw->dev_spec._80003es2lan.mdic_wa_enable == TRUE) {
- /*
- * The "ready" bit in the MDIC register may be incorrectly set
+ if (hw->dev_spec._80003es2lan.mdic_wa_enable) {
+ /* The "ready" bit in the MDIC register may be incorrectly set
* before the device has completed the "Page Select" MDI
* transaction. So we wait 200us after each MDI command...
*/
@@ -529,9 +511,8 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp);
if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
- ret_val = -E1000_ERR_PHY;
e1000_release_phy_80003es2lan(hw);
- goto out;
+ return -E1000_ERR_PHY;
}
usec_delay(200);
@@ -549,7 +530,6 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
e1000_release_phy_80003es2lan(hw);
-out:
return ret_val;
}
@@ -572,14 +552,13 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
ret_val = e1000_acquire_phy_80003es2lan(hw);
if (ret_val)
- goto out;
+ return ret_val;
/* Select Configuration Page */
if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
page_select = GG82563_PHY_PAGE_SELECT;
} else {
- /*
- * Use Alternative Page Select register to access
+ /* Use Alternative Page Select register to access
* registers 30 and 31
*/
page_select = GG82563_PHY_PAGE_SELECT_ALT;
@@ -589,12 +568,11 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
ret_val = e1000_write_phy_reg_mdic(hw, page_select, temp);
if (ret_val) {
e1000_release_phy_80003es2lan(hw);
- goto out;
+ return ret_val;
}
- if (hw->dev_spec._80003es2lan.mdic_wa_enable == TRUE) {
- /*
- * The "ready" bit in the MDIC register may be incorrectly set
+ if (hw->dev_spec._80003es2lan.mdic_wa_enable) {
+ /* The "ready" bit in the MDIC register may be incorrectly set
* before the device has completed the "Page Select" MDI
* transaction. So we wait 200us after each MDI command...
*/
@@ -604,9 +582,8 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp);
if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
- ret_val = -E1000_ERR_PHY;
e1000_release_phy_80003es2lan(hw);
- goto out;
+ return -E1000_ERR_PHY;
}
usec_delay(200);
@@ -624,7 +601,6 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
e1000_release_phy_80003es2lan(hw);
-out:
return ret_val;
}
@@ -655,7 +631,6 @@ static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset,
static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw)
{
s32 timeout = PHY_CFG_TIMEOUT;
- s32 ret_val = E1000_SUCCESS;
u32 mask = E1000_NVM_CFG_DONE_PORT_0;
DEBUGFUNC("e1000_get_cfg_done_80003es2lan");
@@ -671,12 +646,10 @@ static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw)
}
if (!timeout) {
DEBUGOUT("MNG configuration cycle has not completed.\n");
- ret_val = -E1000_ERR_RESET;
- goto out;
+ return -E1000_ERR_RESET;
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -688,33 +661,32 @@ out:
**/
static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
{
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
u16 phy_data;
bool link;
DEBUGFUNC("e1000_phy_force_speed_duplex_80003es2lan");
if (!(hw->phy.ops.read_reg))
- goto out;
+ return E1000_SUCCESS;
- /*
- * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+ /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
* forced whenever speed and duplex are forced.
*/
ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO;
ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, phy_data);
if (ret_val)
- goto out;
+ return ret_val;
DEBUGOUT1("GG82563 PSCR: %X\n", phy_data);
ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
e1000_phy_force_speed_duplex_setup(hw, &phy_data);
@@ -723,7 +695,7 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_data);
if (ret_val)
- goto out;
+ return ret_val;
usec_delay(1);
@@ -733,32 +705,30 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
100000, &link);
if (ret_val)
- goto out;
+ return ret_val;
if (!link) {
- /*
- * We didn't get link.
+ /* We didn't get link.
* Reset the DSP and cross our fingers.
*/
ret_val = e1000_phy_reset_dsp_generic(hw);
if (ret_val)
- goto out;
+ return ret_val;
}
/* Try once more */
ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
100000, &link);
if (ret_val)
- goto out;
+ return ret_val;
}
ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
&phy_data);
if (ret_val)
- goto out;
+ return ret_val;
- /*
- * Resetting the phy means we need to verify the TX_CLK corresponds
+ /* Resetting the phy means we need to verify the TX_CLK corresponds
* to the link speed. 10Mbps -> 2.5MHz, else 25MHz.
*/
phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
@@ -767,15 +737,13 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
else
phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25;
- /*
- * In addition, we must re-enable CRS on Tx for both half and full
+ /* In addition, we must re-enable CRS on Tx for both half and full
* duplex.
*/
phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
phy_data);
-out:
return ret_val;
}
@@ -789,32 +757,29 @@ out:
static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
u16 phy_data, index;
DEBUGFUNC("e1000_get_cable_length_80003es2lan");
if (!(hw->phy.ops.read_reg))
- goto out;
+ return E1000_SUCCESS;
ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
index = phy_data & GG82563_DSPD_CABLE_LENGTH;
- if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE - 5) {
- ret_val = -E1000_ERR_PHY;
- goto out;
- }
+ if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE - 5)
+ return -E1000_ERR_PHY;
phy->min_cable_length = e1000_gg82563_cable_length_table[index];
phy->max_cable_length = e1000_gg82563_cable_length_table[index + 5];
phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -855,11 +820,11 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
{
u32 ctrl;
s32 ret_val;
+ u16 kum_reg_data;
DEBUGFUNC("e1000_reset_hw_80003es2lan");
- /*
- * Prevent the PCI-E bus from sticking if there is no TLP connection
+ /* Prevent the PCI-E bus from sticking if there is no TLP connection
* on the last TLP read/write transaction when MAC is reset.
*/
ret_val = e1000_disable_pcie_master_generic(hw);
@@ -878,23 +843,30 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
ctrl = E1000_READ_REG(hw, E1000_CTRL);
ret_val = e1000_acquire_phy_80003es2lan(hw);
+ if (ret_val)
+ return ret_val;
+
DEBUGOUT("Issuing a global reset to MAC\n");
E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
e1000_release_phy_80003es2lan(hw);
+ /* Disable IBIST slave mode (far-end loopback) */
+ e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
+ &kum_reg_data);
+ kum_reg_data |= E1000_KMRNCTRLSTA_IBIST_DISABLE;
+ e1000_write_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
+ kum_reg_data);
+
ret_val = e1000_get_auto_rd_done_generic(hw);
if (ret_val)
/* We don't want to continue accessing MAC registers. */
- goto out;
+ return ret_val;
/* Clear any pending interrupt events. */
E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
E1000_READ_REG(hw, E1000_ICR);
- ret_val = e1000_check_alt_mac_addr_generic(hw);
-
-out:
- return ret_val;
+ return e1000_check_alt_mac_addr_generic(hw);
}
/**
@@ -917,9 +889,9 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
/* Initialize identification LED */
ret_val = mac->ops.id_led_init(hw);
+ /* An error is not fatal and we should not stop init due to this */
if (ret_val)
DEBUGOUT("Error initializing identification LED\n");
- /* This is not fatal and we should not stop init due to this */
/* Disabling VLAN filtering */
DEBUGOUT("Initializing the IEEE VLAN\n");
@@ -935,6 +907,8 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
/* Setup link and flow control */
ret_val = mac->ops.setup_link(hw);
+ if (ret_val)
+ return ret_val;
/* Disable IBIST slave mode (far-end loopback) */
e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
@@ -945,14 +919,14 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
/* Set the transmit descriptor write-back policy */
reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0));
- reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
- E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ reg_data = ((reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC);
E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data);
/* ...for both queues. */
reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1));
- reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
- E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ reg_data = ((reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC);
E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data);
/* Enable retransmit on late collisions */
@@ -979,18 +953,16 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
/* default to TRUE to enable the MDIC W/A */
hw->dev_spec._80003es2lan.mdic_wa_enable = TRUE;
- ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET >>
- E1000_KMRNCTRLSTA_OFFSET_SHIFT,
- &i);
+ ret_val =
+ e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_OFFSET >>
+ E1000_KMRNCTRLSTA_OFFSET_SHIFT, &i);
if (!ret_val) {
if ((i & E1000_KMRNCTRLSTA_OPMODE_MASK) ==
E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO)
hw->dev_spec._80003es2lan.mdic_wa_enable = FALSE;
}
- /*
- * Clear all of the statistics registers (clear on read). It is
+ /* Clear all of the statistics registers (clear on read). It is
* important that we do this after we have tried to establish link
* because the symbol error count will increment wildly if there
* is no link.
@@ -1037,6 +1009,13 @@ static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw)
reg |= (1 << 28);
E1000_WRITE_REG(hw, E1000_TARC(1), reg);
+ /* Disable IPv6 extension header parsing because some malformed
+ * IPv6 headers can hang the Rx.
+ */
+ reg = E1000_READ_REG(hw, E1000_RFCTL);
+ reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS);
+ E1000_WRITE_REG(hw, E1000_RFCTL, reg);
+
return;
}
@@ -1050,14 +1029,14 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val;
- u32 ctrl_ext;
+ u32 reg;
u16 data;
DEBUGFUNC("e1000_copper_link_setup_gg82563_80003es2lan");
ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, &data);
if (ret_val)
- goto out;
+ return ret_val;
data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
/* Use 25MHz for both link down and 1000Base-T for Tx clock. */
@@ -1065,10 +1044,9 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, data);
if (ret_val)
- goto out;
+ return ret_val;
- /*
- * Options:
+ /* Options:
* MDI/MDI-X = 0 (default)
* 0 - Auto for all speeds
* 1 - MDI mode
@@ -1077,7 +1055,7 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
*/
ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL, &data);
if (ret_val)
- goto out;
+ return ret_val;
data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
@@ -1094,8 +1072,7 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
break;
}
- /*
- * Options:
+ /* Options:
* disable_polarity_correction = 0 (default)
* Automatic Correction for Reversed Cable Polarity
* 0 - Disabled
@@ -1107,90 +1084,86 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, data);
if (ret_val)
- goto out;
+ return ret_val;
/* SW Reset the PHY so all changes take effect */
ret_val = hw->phy.ops.commit(hw);
if (ret_val) {
DEBUGOUT("Error Resetting the PHY\n");
- goto out;
+ return ret_val;
}
/* Bypass Rx and Tx FIFO's */
- ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
- E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
- E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
+ reg = E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL;
+ data = (E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
+ E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, reg, data);
if (ret_val)
- goto out;
+ return ret_val;
- ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, &data);
+ reg = E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE;
+ ret_val = e1000_read_kmrn_reg_80003es2lan(hw, reg, &data);
if (ret_val)
- goto out;
+ return ret_val;
data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE;
- ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, data);
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, reg, data);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL_2, &data);
if (ret_val)
- goto out;
+ return ret_val;
data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL_2, data);
if (ret_val)
- goto out;
+ return ret_val;
- ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
- ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
- E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+ reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ reg &= ~E1000_CTRL_EXT_LINK_MODE_MASK;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, &data);
if (ret_val)
- goto out;
+ return ret_val;
- /*
- * Do not init these registers when the HW is in IAMT mode, since the
+ /* 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 (!(hw->mac.ops.check_mng_mode(hw))) {
+ if (!hw->mac.ops.check_mng_mode(hw)) {
/* Enable Electrical Idle on the PHY */
data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_PWR_MGMT_CTRL,
data);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
&data);
if (ret_val)
- goto out;
+ return ret_val;
data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
data);
if (ret_val)
- goto out;
+ return ret_val;
}
- /*
- * Workaround: Disable padding in Kumeran interface in the MAC
+ /* Workaround: Disable padding in Kumeran interface in the MAC
* and in the PHY to avoid CRC errors.
*/
ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_INBAND_CTRL, &data);
if (ret_val)
- goto out;
+ return ret_val;
data |= GG82563_ICR_DIS_PADDING;
ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_INBAND_CTRL, data);
if (ret_val)
- goto out;
+ return ret_val;
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -1213,42 +1186,42 @@ static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw)
ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
- /*
- * Set the mac to wait the maximum time between each
+ /* Set the mac to wait the maximum time between each
* iteration and increase the max iterations when
* polling the phy; this fixes erroneous timeouts at 10Mbps.
*/
ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 4),
0xFFFF);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = e1000_read_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
&reg_data);
if (ret_val)
- goto out;
+ return ret_val;
reg_data |= 0x3F;
ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
reg_data);
if (ret_val)
- goto out;
- ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, &reg_data);
+ return ret_val;
+ ret_val =
+ e1000_read_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+ &reg_data);
if (ret_val)
- goto out;
+ return ret_val;
reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING;
- ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, reg_data);
+ ret_val =
+ e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+ reg_data);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = e1000_copper_link_setup_gg82563_80003es2lan(hw);
if (ret_val)
- goto out;
-
- ret_val = e1000_setup_copper_link_generic(hw);
+ return ret_val;
-out:
- return ret_val;
+ return e1000_setup_copper_link_generic(hw);
}
/**
@@ -1271,7 +1244,7 @@ static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw)
ret_val = e1000_get_speed_and_duplex_copper_generic(hw, &speed,
&duplex);
if (ret_val)
- goto out;
+ return ret_val;
if (speed == SPEED_1000)
ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw);
@@ -1279,7 +1252,6 @@ static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw)
ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw, duplex);
}
-out:
return ret_val;
}
@@ -1293,7 +1265,7 @@ out:
**/
static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
{
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
u32 tipg;
u32 i = 0;
u16 reg_data, reg_data2;
@@ -1301,11 +1273,12 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
DEBUGFUNC("e1000_configure_kmrn_for_10_100");
reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
- ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
- reg_data);
+ ret_val =
+ e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
if (ret_val)
- goto out;
+ return ret_val;
/* Configure Transmit Inter-Packet Gap */
tipg = E1000_READ_REG(hw, E1000_TIPG);
@@ -1317,12 +1290,12 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
&reg_data);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
&reg_data2);
if (ret_val)
- goto out;
+ return ret_val;
i++;
} while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
@@ -1331,11 +1304,7 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
else
reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
- ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
- reg_data);
-
-out:
- return ret_val;
+ return hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
}
/**
@@ -1347,7 +1316,7 @@ out:
**/
static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
{
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
u16 reg_data, reg_data2;
u32 tipg;
u32 i = 0;
@@ -1355,10 +1324,12 @@ static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
DEBUGFUNC("e1000_configure_kmrn_for_1000");
reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
- ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, reg_data);
+ ret_val =
+ e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
if (ret_val)
- goto out;
+ return ret_val;
/* Configure Transmit Inter-Packet Gap */
tipg = E1000_READ_REG(hw, E1000_TIPG);
@@ -1370,21 +1341,18 @@ static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
&reg_data);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
&reg_data2);
if (ret_val)
- goto out;
+ return ret_val;
i++;
} while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
- ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
- reg_data);
-out:
- return ret_val;
+ return hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
}
/**
@@ -1401,13 +1369,13 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
u16 *data)
{
u32 kmrnctrlsta;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_read_kmrn_reg_80003es2lan");
ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
if (ret_val)
- goto out;
+ return ret_val;
kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
@@ -1421,7 +1389,6 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
e1000_release_mac_csr_80003es2lan(hw);
-out:
return ret_val;
}
@@ -1439,13 +1406,13 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
u16 data)
{
u32 kmrnctrlsta;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_write_kmrn_reg_80003es2lan");
ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
if (ret_val)
- goto out;
+ return ret_val;
kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
E1000_KMRNCTRLSTA_OFFSET) | data;
@@ -1456,7 +1423,6 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
e1000_release_mac_csr_80003es2lan(hw);
-out:
return ret_val;
}
@@ -1466,23 +1432,19 @@ out:
**/
static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw)
{
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_read_mac_addr_80003es2lan");
- /*
- * If there's an alternate MAC address place it in RAR0
+ /* If there's an alternate MAC address place it in RAR0
* so that it will override the Si installed default perm
* address.
*/
ret_val = e1000_check_alt_mac_addr_generic(hw);
if (ret_val)
- goto out;
-
- ret_val = e1000_read_mac_addr_generic(hw);
+ return ret_val;
-out:
- return ret_val;
+ return e1000_read_mac_addr_generic(hw);
}
/**
diff --git a/sys/dev/e1000/e1000_80003es2lan.h b/sys/dev/e1000/e1000_80003es2lan.h
index 157468e..3807e46 100644
--- a/sys/dev/e1000/e1000_80003es2lan.h
+++ b/sys/dev/e1000/e1000_80003es2lan.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2013, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -51,34 +51,32 @@
#define E1000_KMRNCTRLSTA_OPMODE_MASK 0x000C
#define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO 0x0004
-#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
+#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gig Carry Extend Padding */
#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000
#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN 0x8
#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN 0x9
/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
-#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Disabled */
+#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Dis */
#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060
#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI */
#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX */
#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Auto crossover */
/* PHY Specific Control Register 2 (Page 0, Register 26) */
-#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000 /* 1=Reverse Auto-Nego */
+#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000 /* 1=Reverse Auto-Neg */
/* MAC Specific Control Register (Page 2, Register 21) */
/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
#define GG82563_MSCR_TX_CLK_MASK 0x0007
#define GG82563_MSCR_TX_CLK_10MBPS_2_5 0x0004
#define GG82563_MSCR_TX_CLK_100MBPS_25 0x0005
-#define GG82563_MSCR_TX_CLK_1000MBPS_2_5 0x0006
#define GG82563_MSCR_TX_CLK_1000MBPS_25 0x0007
#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */
-/* DSP Distance Register (Page 5, Register 26) */
-/*
+/* DSP Distance Register (Page 5, Register 26)
* 0 = <50M
* 1 = 50-80M
* 2 = 80-100M
diff --git a/sys/dev/e1000/e1000_82571.c b/sys/dev/e1000/e1000_82571.c
index ca7a1d0..2c98590 100644
--- a/sys/dev/e1000/e1000_82571.c
+++ b/sys/dev/e1000/e1000_82571.c
@@ -927,9 +927,9 @@ static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
}
for (i = 0; i < words; i++) {
- eewr = (data[i] << E1000_NVM_RW_REG_DATA) |
- ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
- E1000_NVM_RW_REG_START;
+ eewr = ((data[i] << E1000_NVM_RW_REG_DATA) |
+ ((offset + i) << E1000_NVM_RW_ADDR_SHIFT) |
+ E1000_NVM_RW_REG_START);
ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
if (ret_val)
@@ -1101,8 +1101,6 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
default:
break;
}
- if (ret_val)
- DEBUGOUT("Cannot acquire MDIO ownership\n");
ctrl = E1000_READ_REG(hw, E1000_CTRL);
@@ -1111,9 +1109,16 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
/* Must release MDIO ownership and mutex after MAC reset. */
switch (hw->mac.type) {
+ case e1000_82573:
+ /* Release mutex only if the hw semaphore is acquired */
+ if (!ret_val)
+ e1000_put_hw_semaphore_82573(hw);
+ break;
case e1000_82574:
case e1000_82583:
- e1000_put_hw_semaphore_82574(hw);
+ /* Release mutex only if the hw semaphore is acquired */
+ if (!ret_val)
+ e1000_put_hw_semaphore_82574(hw);
break;
default:
break;
@@ -1222,8 +1227,8 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw)
/* Set the transmit descriptor write-back policy */
reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0));
- reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
- E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ reg_data = ((reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC);
E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data);
/* ...for both queues. */
@@ -1239,9 +1244,9 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw)
break;
default:
reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1));
- reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
- E1000_TXDCTL_FULL_TX_DESC_WB |
- E1000_TXDCTL_COUNT_DESC;
+ reg_data = ((reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB |
+ E1000_TXDCTL_COUNT_DESC);
E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data);
break;
}
diff --git a/sys/dev/e1000/e1000_82575.c b/sys/dev/e1000/e1000_82575.c
index 5722f46..1707236 100644
--- a/sys/dev/e1000/e1000_82575.c
+++ b/sys/dev/e1000/e1000_82575.c
@@ -52,6 +52,7 @@ static void e1000_release_phy_82575(struct e1000_hw *hw);
static s32 e1000_acquire_nvm_82575(struct e1000_hw *hw);
static void e1000_release_nvm_82575(struct e1000_hw *hw);
static s32 e1000_check_for_link_82575(struct e1000_hw *hw);
+static s32 e1000_check_for_link_media_swap(struct e1000_hw *hw);
static s32 e1000_get_cfg_done_82575(struct e1000_hw *hw);
static s32 e1000_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed,
u16 *duplex);
@@ -144,6 +145,7 @@ static bool e1000_sgmii_uses_mdio_82575(struct e1000_hw *hw)
break;
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
case e1000_i210:
case e1000_i211:
reg = E1000_READ_REG(hw, E1000_MDICNFG);
@@ -207,6 +209,7 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw)
switch (hw->mac.type) {
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
phy->ops.read_reg = e1000_read_phy_reg_82580;
phy->ops.write_reg = e1000_write_phy_reg_82580;
break;
@@ -226,6 +229,8 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw)
/* Verify phy id and set remaining function pointers */
switch (phy->id) {
+ case M88E1543_E_PHY_ID:
+ case M88E1512_E_PHY_ID:
case I347AT4_E_PHY_ID:
case M88E1112_E_PHY_ID:
case M88E1340M_E_PHY_ID:
@@ -238,9 +243,36 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw)
phy->id == M88E1340M_E_PHY_ID)
phy->ops.get_cable_length =
e1000_get_cable_length_m88_gen2;
+ else if (phy->id == M88E1543_E_PHY_ID ||
+ phy->id == M88E1512_E_PHY_ID)
+ phy->ops.get_cable_length =
+ e1000_get_cable_length_m88_gen2;
else
phy->ops.get_cable_length = e1000_get_cable_length_m88;
phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ /* Check if this PHY is confgured for media swap. */
+ if (phy->id == M88E1112_E_PHY_ID) {
+ u16 data;
+
+ ret_val = phy->ops.write_reg(hw,
+ E1000_M88E1112_PAGE_ADDR,
+ 2);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw,
+ E1000_M88E1112_MAC_CTRL_1,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data = (data & E1000_M88E1112_MAC_CTRL_1_MODE_MASK) >>
+ E1000_M88E1112_MAC_CTRL_1_MODE_SHIFT;
+ if (data == E1000_M88E1112_AUTO_COPPER_SGMII ||
+ data == E1000_M88E1112_AUTO_COPPER_BASEX)
+ hw->mac.ops.check_for_link =
+ e1000_check_for_link_media_swap;
+ }
break;
case IGP03E1000_E_PHY_ID:
case IGP04E1000_E_PHY_ID:
@@ -355,6 +387,7 @@ s32 e1000_init_nvm_params_82575(struct e1000_hw *hw)
nvm->ops.update = e1000_update_nvm_checksum_82580;
break;
case e1000_i350:
+ case e1000_i354:
nvm->ops.validate = e1000_validate_nvm_checksum_i350;
nvm->ops.update = e1000_update_nvm_checksum_i350;
break;
@@ -388,7 +421,7 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw)
mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
if (mac->type == e1000_82580)
mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
- if (mac->type == e1000_i350)
+ if (mac->type == e1000_i350 || mac->type == e1000_i354)
mac->rar_entry_count = E1000_RAR_ENTRIES_I350;
/* Enable EEE default settings for EEE supported devices */
@@ -436,7 +469,7 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw)
mac->ops.config_collision_dist = e1000_config_collision_dist_82575;
/* multicast address update */
mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
- if (mac->type == e1000_i350) {
+ if (hw->mac.type == e1000_i350 || mac->type == e1000_i354) {
/* writing VFTA */
mac->ops.write_vfta = e1000_write_vfta_i350;
/* clearing VFTA */
@@ -622,6 +655,10 @@ static s32 e1000_get_phy_id_82575(struct e1000_hw *hw)
DEBUGFUNC("e1000_get_phy_id_82575");
+ /* some i354 devices need an extra read for phy id */
+ if (hw->mac.type == e1000_i354)
+ e1000_get_phy_id(hw);
+
/*
* For SGMII PHYs, we try the list of possible addresses until
* we find one that works. For non-SGMII PHYs
@@ -645,6 +682,7 @@ static s32 e1000_get_phy_id_82575(struct e1000_hw *hw)
break;
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
case e1000_i210:
case e1000_i211:
mdic = E1000_READ_REG(hw, E1000_MDICNFG);
@@ -1173,6 +1211,61 @@ static s32 e1000_check_for_link_82575(struct e1000_hw *hw)
}
/**
+ * e1000_check_for_link_media_swap - Check which M88E1112 interface linked
+ * @hw: pointer to the HW structure
+ *
+ * Poll the M88E1112 interfaces to see which interface achieved link.
+ */
+static s32 e1000_check_for_link_media_swap(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+ u8 port = 0;
+
+ DEBUGFUNC("e1000_check_for_link_media_swap");
+
+ /* Check the copper medium. */
+ ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = phy->ops.read_reg(hw, E1000_M88E1112_STATUS, &data);
+ if (ret_val)
+ return ret_val;
+
+ if (data & E1000_M88E1112_STATUS_LINK)
+ port = E1000_MEDIA_PORT_COPPER;
+
+ /* Check the other medium. */
+ ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 1);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = phy->ops.read_reg(hw, E1000_M88E1112_STATUS, &data);
+ if (ret_val)
+ return ret_val;
+
+ /* reset page to 0 */
+ ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0);
+ if (ret_val)
+ return ret_val;
+
+ if (data & E1000_M88E1112_STATUS_LINK)
+ port = E1000_MEDIA_PORT_OTHER;
+
+ /* Determine if a swap needs to happen. */
+ if (port && (hw->dev_spec._82575.media_port != port)) {
+ hw->dev_spec._82575.media_port = port;
+ hw->dev_spec._82575.media_changed = TRUE;
+ } else {
+ ret_val = e1000_check_for_link_82575(hw);
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
* e1000_power_up_serdes_link_82575 - Power up the serdes link after shutdown
* @hw: pointer to the HW structure
**/
@@ -1215,6 +1308,7 @@ static s32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
{
struct e1000_mac_info *mac = &hw->mac;
u32 pcs;
+ u32 status;
DEBUGFUNC("e1000_get_pcs_speed_and_duplex_82575");
@@ -1245,6 +1339,18 @@ static s32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
else
*duplex = HALF_DUPLEX;
+ /* Check if it is an I354 2.5Gb backplane connection. */
+ if (mac->type == e1000_i354) {
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ if ((status & E1000_STATUS_2P5_SKU) &&
+ !(status & E1000_STATUS_2P5_SKU_OVER)) {
+ *speed = SPEED_2500;
+ *duplex = FULL_DUPLEX;
+ DEBUGOUT("2500 Mbs, ");
+ DEBUGOUT("Full Duplex\n");
+ }
+ }
+
} else {
mac->serdes_has_link = FALSE;
*speed = 0;
@@ -1430,11 +1536,18 @@ static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw)
ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
- /* Clear Go Link Disconnect bit */
- if (hw->mac.type >= e1000_82580) {
+ /* Clear Go Link Disconnect bit on supported devices */
+ switch (hw->mac.type) {
+ case e1000_82580:
+ case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
phpm_reg = E1000_READ_REG(hw, E1000_82580_PHY_POWER_MGMT);
phpm_reg &= ~E1000_82580_PM_GO_LINKD;
E1000_WRITE_REG(hw, E1000_82580_PHY_POWER_MGMT, phpm_reg);
+ break;
+ default:
+ break;
}
ret_val = e1000_setup_serdes_link_82575(hw);
@@ -1458,6 +1571,8 @@ static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw)
case I347AT4_E_PHY_ID:
case M88E1112_E_PHY_ID:
case M88E1340M_E_PHY_ID:
+ case M88E1543_E_PHY_ID:
+ case M88E1512_E_PHY_ID:
case I210_I_PHY_ID:
ret_val = e1000_copper_link_setup_m88_gen2(hw);
break;
@@ -2132,42 +2247,33 @@ out:
**/
void e1000_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf)
{
- u32 dtxswc;
+ u32 reg_val, reg_offset;
switch (hw->mac.type) {
case e1000_82576:
- dtxswc = E1000_READ_REG(hw, E1000_DTXSWC);
- if (enable) {
- dtxswc |= (E1000_DTXSWC_MAC_SPOOF_MASK |
- E1000_DTXSWC_VLAN_SPOOF_MASK);
- /* The PF can spoof - it has to in order to
- * support emulation mode NICs */
- dtxswc ^= (1 << pf | 1 << (pf +
- E1000_DTXSWC_VLAN_SPOOF_SHIFT));
- } else {
- dtxswc &= ~(E1000_DTXSWC_MAC_SPOOF_MASK |
- E1000_DTXSWC_VLAN_SPOOF_MASK);
- }
- E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc);
+ reg_offset = E1000_DTXSWC;
break;
case e1000_i350:
- dtxswc = E1000_READ_REG(hw, E1000_TXSWC);
- if (enable) {
- dtxswc |= (E1000_DTXSWC_MAC_SPOOF_MASK |
- E1000_DTXSWC_VLAN_SPOOF_MASK);
- /* The PF can spoof - it has to in order to
- * support emulation mode NICs
- */
- dtxswc ^= (1 << pf | 1 << (pf +
- E1000_DTXSWC_VLAN_SPOOF_SHIFT));
- } else {
- dtxswc &= ~(E1000_DTXSWC_MAC_SPOOF_MASK |
- E1000_DTXSWC_VLAN_SPOOF_MASK);
- }
- E1000_WRITE_REG(hw, E1000_TXSWC, dtxswc);
- default:
+ case e1000_i354:
+ reg_offset = E1000_TXSWC;
break;
+ default:
+ return;
+ }
+
+ reg_val = E1000_READ_REG(hw, reg_offset);
+ if (enable) {
+ reg_val |= (E1000_DTXSWC_MAC_SPOOF_MASK |
+ E1000_DTXSWC_VLAN_SPOOF_MASK);
+ /* The PF can spoof - it has to in order to
+ * support emulation mode NICs
+ */
+ reg_val ^= (1 << pf | 1 << (pf + MAX_NUM_VFS));
+ } else {
+ reg_val &= ~(E1000_DTXSWC_MAC_SPOOF_MASK |
+ E1000_DTXSWC_VLAN_SPOOF_MASK);
}
+ E1000_WRITE_REG(hw, reg_offset, reg_val);
}
/**
@@ -2191,6 +2297,7 @@ void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable)
E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc);
break;
case e1000_i350:
+ case e1000_i354:
dtxswc = E1000_READ_REG(hw, E1000_TXSWC);
if (enable)
dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
@@ -2387,10 +2494,6 @@ static s32 e1000_reset_hw_82580(struct e1000_hw *hw)
DEBUGOUT("Auto Read Done did not complete\n");
}
- /* If EEPROM is not present, run manual init scripts */
- if (!(E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES))
- e1000_reset_init_script_82575(hw);
-
/* clear global device reset status bit */
E1000_WRITE_REG(hw, E1000_STATUS, E1000_STAT_DEV_RST_SET);
@@ -2645,6 +2748,45 @@ out:
}
/**
+ * __e1000_access_emi_reg - Read/write EMI register
+ * @hw: pointer to the HW structure
+ * @addr: EMI address to program
+ * @data: pointer to value to read/write from/to the EMI address
+ * @read: boolean flag to indicate read or write
+ **/
+static s32 __e1000_access_emi_reg(struct e1000_hw *hw, u16 address,
+ u16 *data, bool read)
+{
+ s32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("__e1000_access_emi_reg");
+
+ ret_val = hw->phy.ops.write_reg(hw, E1000_EMIADD, address);
+ if (ret_val)
+ return ret_val;
+
+ if (read)
+ ret_val = hw->phy.ops.read_reg(hw, E1000_EMIDATA, data);
+ else
+ ret_val = hw->phy.ops.write_reg(hw, E1000_EMIDATA, *data);
+
+ return ret_val;
+}
+
+/**
+ * e1000_read_emi_reg - Read Extended Management Interface register
+ * @hw: pointer to the HW structure
+ * @addr: EMI address to program
+ * @data: value to be read from the EMI address
+ **/
+s32 e1000_read_emi_reg(struct e1000_hw *hw, u16 addr, u16 *data)
+{
+ DEBUGFUNC("e1000_read_emi_reg");
+
+ return __e1000_access_emi_reg(hw, addr, data, TRUE);
+}
+
+/**
* e1000_set_eee_i350 - Enable/disable EEE support
* @hw: pointer to the HW structure
*
@@ -2689,6 +2831,114 @@ out:
return ret_val;
}
+/**
+ * e1000_set_eee_i354 - Enable/disable EEE support
+ * @hw: pointer to the HW structure
+ *
+ * Enable/disable EEE legacy mode based on setting in dev_spec structure.
+ *
+ **/
+s32 e1000_set_eee_i354(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val = E1000_SUCCESS;
+ u16 phy_data;
+
+ DEBUGFUNC("e1000_set_eee_i354");
+
+ if ((hw->phy.media_type != e1000_media_type_copper) ||
+ ((phy->id != M88E1543_E_PHY_ID) &&
+ (phy->id != M88E1512_E_PHY_ID)))
+ goto out;
+
+ if (!hw->dev_spec._82575.eee_disable) {
+ /* Switch to PHY page 18. */
+ ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 18);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, E1000_M88E1543_EEE_CTRL_1,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data |= E1000_M88E1543_EEE_CTRL_1_MS;
+ ret_val = phy->ops.write_reg(hw, E1000_M88E1543_EEE_CTRL_1,
+ phy_data);
+ if (ret_val)
+ goto out;
+
+ /* Return the PHY to page 0. */
+ ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0);
+ if (ret_val)
+ goto out;
+
+ /* Turn on EEE advertisement. */
+ ret_val = e1000_read_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
+ E1000_EEE_ADV_DEV_I354,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data |= E1000_EEE_ADV_100_SUPPORTED |
+ E1000_EEE_ADV_1000_SUPPORTED;
+ ret_val = e1000_write_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
+ E1000_EEE_ADV_DEV_I354,
+ phy_data);
+ } else {
+ /* Turn off EEE advertisement. */
+ ret_val = e1000_read_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
+ E1000_EEE_ADV_DEV_I354,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~(E1000_EEE_ADV_100_SUPPORTED |
+ E1000_EEE_ADV_1000_SUPPORTED);
+ ret_val = e1000_write_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
+ E1000_EEE_ADV_DEV_I354,
+ phy_data);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_eee_status_i354 - Get EEE status
+ * @hw: pointer to the HW structure
+ * @status: EEE status
+ *
+ * Get EEE status by guessing based on whether Tx or Rx LPI indications have
+ * been received.
+ **/
+s32 e1000_get_eee_status_i354(struct e1000_hw *hw, bool *status)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val = E1000_SUCCESS;
+ u16 phy_data;
+
+ DEBUGFUNC("e1000_get_eee_status_i354");
+
+ /* Check if EEE is supported on this device. */
+ if ((hw->phy.media_type != e1000_media_type_copper) ||
+ ((phy->id != M88E1543_E_PHY_ID) &&
+ (phy->id != M88E1512_E_PHY_ID)))
+ goto out;
+
+ ret_val = e1000_read_xmdio_reg(hw, E1000_PCS_STATUS_ADDR_I354,
+ E1000_PCS_STATUS_DEV_I354,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ *status = phy_data & (E1000_PCS_STATUS_TX_LPI_RCVD |
+ E1000_PCS_STATUS_RX_LPI_RCVD) ? TRUE : FALSE;
+
+out:
+ return ret_val;
+}
+
/* Due to a hw errata, if the host tries to configure the VFTA register
* while performing queries from the BMC or DMA, then the VFTA in some
* cases won't be written.
@@ -3286,4 +3536,3 @@ void e1000_i2c_bus_clear(struct e1000_hw *hw)
e1000_i2c_stop(hw);
}
-
diff --git a/sys/dev/e1000/e1000_82575.h b/sys/dev/e1000/e1000_82575.h
index c6bbe18..e7039d8 100644
--- a/sys/dev/e1000/e1000_82575.h
+++ b/sys/dev/e1000/e1000_82575.h
@@ -245,6 +245,8 @@ union e1000_adv_rx_desc {
#define E1000_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009
/* RSS Packet Types as indicated in the receive descriptor */
+#define E1000_RXDADV_PKTTYPE_ILMASK 0x000000F0
+#define E1000_RXDADV_PKTTYPE_TLMASK 0x00000F00
#define E1000_RXDADV_PKTTYPE_NONE 0x00000000
#define E1000_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPV4 hdr present */
#define E1000_RXDADV_PKTTYPE_IPV4_EX 0x00000020 /* IPV4 hdr + extensions */
@@ -491,7 +493,10 @@ void e1000_vfta_set_vf(struct e1000_hw *, u16, bool);
void e1000_rlpml_set_vf(struct e1000_hw *, u16);
s32 e1000_promisc_set_vf(struct e1000_hw *, enum e1000_promisc_type type);
u16 e1000_rxpbs_adjust_82580(u32 data);
+s32 e1000_read_emi_reg(struct e1000_hw *hw, u16 addr, u16 *data);
s32 e1000_set_eee_i350(struct e1000_hw *);
+s32 e1000_set_eee_i354(struct e1000_hw *);
+s32 e1000_get_eee_status_i354(struct e1000_hw *, bool *);
/* I2C SDA and SCL timing parameters for standard mode */
#define E1000_I2C_T_HD_STA 4
diff --git a/sys/dev/e1000/e1000_api.c b/sys/dev/e1000/e1000_api.c
index 1581913..c1ca5fd 100644
--- a/sys/dev/e1000/e1000_api.c
+++ b/sys/dev/e1000/e1000_api.c
@@ -329,9 +329,8 @@ s32 e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_I350_DA4:
mac->type = e1000_i350;
break;
-#if defined(QV_RELEASE) && defined(SPRINGVILLE_FLASHLESS_HW)
- case E1000_DEV_ID_I210_NVMLESS:
-#endif /* QV_RELEASE && SPRINGVILLE_FLASHLESS_HW */
+ case E1000_DEV_ID_I210_COPPER_FLASHLESS:
+ case E1000_DEV_ID_I210_SERDES_FLASHLESS:
case E1000_DEV_ID_I210_COPPER:
case E1000_DEV_ID_I210_COPPER_OEM1:
case E1000_DEV_ID_I210_COPPER_IT:
@@ -352,6 +351,11 @@ s32 e1000_set_mac_type(struct e1000_hw *hw)
mac->type = e1000_vfadapt_i350;
break;
+ case E1000_DEV_ID_I354_BACKPLANE_1GBPS:
+ case E1000_DEV_ID_I354_SGMII:
+ case E1000_DEV_ID_I354_BACKPLANE_2_5GBPS:
+ mac->type = e1000_i354;
+ break;
default:
/* Should never have loaded on this device */
ret_val = -E1000_ERR_MAC_INIT;
@@ -447,6 +451,7 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device)
case e1000_82576:
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
e1000_init_function_pointers_82575(hw);
break;
case e1000_i210:
diff --git a/sys/dev/e1000/e1000_defines.h b/sys/dev/e1000/e1000_defines.h
index 48c04b0..d4b2e56 100644
--- a/sys/dev/e1000/e1000_defines.h
+++ b/sys/dev/e1000/e1000_defines.h
@@ -43,6 +43,8 @@
/* Wake Up Control */
#define E1000_WUC_APME 0x00000001 /* APM Enable */
#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */
#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */
/* Wake Up Filter Control */
@@ -287,7 +289,10 @@
#define E1000_CONNSW_ENRGSRC 0x4
#define E1000_CONNSW_PHYSD 0x400
+#define E1000_CONNSW_PHY_PDN 0x800
#define E1000_CONNSW_SERDESD 0x200
+#define E1000_CONNSW_AUTOSENSE_CONF 0x2
+#define E1000_CONNSW_AUTOSENSE_EN 0x1
#define E1000_PCS_CFG_PCS_EN 8
#define E1000_PCS_LCTL_FLV_LINK_UP 1
#define E1000_PCS_LCTL_FSV_10 0
@@ -325,6 +330,8 @@
#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */
#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */
#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */
+#define E1000_STATUS_2P5_SKU 0x00001000 /* Val of 2.5GBE SKU strap */
+#define E1000_STATUS_2P5_SKU_OVER 0x00002000 /* Val of 2.5GBE SKU Over */
#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */
#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */
@@ -336,6 +343,7 @@
#define SPEED_10 10
#define SPEED_100 100
#define SPEED_1000 1000
+#define SPEED_2500 2500
#define HALF_DUPLEX 1
#define FULL_DUPLEX 2
@@ -650,6 +658,7 @@
#define E1000_EITR_ITR_INT_MASK 0x0000FFFF
/* E1000_EITR_CNT_IGNR is only for 82576 and newer */
#define E1000_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */
+#define E1000_EITR_INTERVAL 0x00007FFC
/* Transmit Descriptor Control */
#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
@@ -805,6 +814,17 @@
#define E1000_MDICNFG_PHY_MASK 0x03E00000
#define E1000_MDICNFG_PHY_SHIFT 21
+#define E1000_MEDIA_PORT_COPPER 1
+#define E1000_MEDIA_PORT_OTHER 2
+#define E1000_M88E1112_AUTO_COPPER_SGMII 0x2
+#define E1000_M88E1112_AUTO_COPPER_BASEX 0x3
+#define E1000_M88E1112_STATUS_LINK 0x0004 /* Interface Link Bit */
+#define E1000_M88E1112_MAC_CTRL_1 0x10
+#define E1000_M88E1112_MAC_CTRL_1_MODE_MASK 0x0380 /* Mode Select */
+#define E1000_M88E1112_MAC_CTRL_1_MODE_SHIFT 7
+#define E1000_M88E1112_PAGE_ADDR 0x16
+#define E1000_M88E1112_STATUS 0x01
+
#define E1000_THSTAT_LOW_EVENT 0x20000000 /* Low thermal threshold */
#define E1000_THSTAT_MID_EVENT 0x00200000 /* Mid thermal threshold */
#define E1000_THSTAT_HIGH_EVENT 0x00002000 /* High thermal threshold */
@@ -821,7 +841,21 @@
#define E1000_EEER_EEE_NEG 0x20000000 /* EEE capability nego */
#define E1000_EEER_RX_LPI_STATUS 0x40000000 /* Rx in LPI state */
#define E1000_EEER_TX_LPI_STATUS 0x80000000 /* Tx in LPI state */
+#define E1000_EEE_LP_ADV_ADDR_I350 0x040F /* EEE LP Advertisement */
+#define E1000_M88E1543_PAGE_ADDR 0x16 /* Page Offset Register */
+#define E1000_M88E1543_EEE_CTRL_1 0x0
+#define E1000_M88E1543_EEE_CTRL_1_MS 0x0001 /* EEE Master/Slave */
+#define E1000_EEE_ADV_DEV_I354 7
+#define E1000_EEE_ADV_ADDR_I354 60
+#define E1000_EEE_ADV_100_SUPPORTED (1 << 1) /* 100BaseTx EEE Supported */
+#define E1000_EEE_ADV_1000_SUPPORTED (1 << 2) /* 1000BaseT EEE Supported */
+#define E1000_PCS_STATUS_DEV_I354 3
+#define E1000_PCS_STATUS_ADDR_I354 1
+#define E1000_PCS_STATUS_RX_LPI_RCVD 0x0400
+#define E1000_PCS_STATUS_TX_LPI_RCVD 0x0800
#define E1000_EEE_SU_LPI_CLK_STP 0x00800000 /* EEE LPI Clock Stop */
+#define E1000_EEE_LP_ADV_DEV_I210 7 /* EEE LP Adv Device */
+#define E1000_EEE_LP_ADV_ADDR_I210 61 /* EEE LP Adv Register */
/* PCI Express Control */
#define E1000_GCR_RXD_NO_SNOOP 0x00000001
#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002
@@ -841,6 +875,8 @@
E1000_GCR_TXDSCW_NO_SNOOP | \
E1000_GCR_TXDSCR_NO_SNOOP)
+#define E1000_MMDAC_FUNC_DATA 0x4000 /* Data, no post increment */
+
/* mPHY address control and data registers */
#define E1000_MPHY_ADDR_CTL 0x0024 /* Address Control Reg */
#define E1000_MPHY_ADDR_CTL_OFFSET_MASK 0xFFFF0000
@@ -1169,6 +1205,8 @@
#define M88E1011_I_PHY_ID 0x01410C20
#define IGP01E1000_I_PHY_ID 0x02A80380
#define M88E1111_I_PHY_ID 0x01410CC0
+#define M88E1543_E_PHY_ID 0x01410EA0
+#define M88E1512_E_PHY_ID 0x01410DD0
#define M88E1112_E_PHY_ID 0x01410C90
#define I347AT4_E_PHY_ID 0x01410DC0
#define M88E1340M_E_PHY_ID 0x01410DF0
@@ -1416,4 +1454,6 @@
/* Lan ID bit field offset in status register */
#define E1000_STATUS_LAN_ID_OFFSET 2
#define E1000_VFTA_ENTRIES 128
+#define E1000_UNUSEDARG
+#define ERROR_REPORT(fmt) do { } while (0)
#endif /* _E1000_DEFINES_H_ */
diff --git a/sys/dev/e1000/e1000_hw.h b/sys/dev/e1000/e1000_hw.h
index e8a8c17..8901ccd 100644
--- a/sys/dev/e1000/e1000_hw.h
+++ b/sys/dev/e1000/e1000_hw.h
@@ -165,7 +165,12 @@ struct e1000_hw;
#define E1000_DEV_ID_I210_FIBER 0x1536
#define E1000_DEV_ID_I210_SERDES 0x1537
#define E1000_DEV_ID_I210_SGMII 0x1538
+#define E1000_DEV_ID_I210_COPPER_FLASHLESS 0x157B
+#define E1000_DEV_ID_I210_SERDES_FLASHLESS 0x157C
#define E1000_DEV_ID_I211_COPPER 0x1539
+#define E1000_DEV_ID_I354_BACKPLANE_1GBPS 0x1F40
+#define E1000_DEV_ID_I354_SGMII 0x1F41
+#define E1000_DEV_ID_I354_BACKPLANE_2_5GBPS 0x1F45
#define E1000_DEV_ID_DH89XXCC_SGMII 0x0438
#define E1000_DEV_ID_DH89XXCC_SERDES 0x043A
#define E1000_DEV_ID_DH89XXCC_BACKPLANE 0x043C
@@ -217,6 +222,7 @@ enum e1000_mac_type {
e1000_82576,
e1000_82580,
e1000_i350,
+ e1000_i354,
e1000_i210,
e1000_i211,
e1000_vfadapt,
@@ -238,6 +244,7 @@ enum e1000_nvm_type {
e1000_nvm_eeprom_spi,
e1000_nvm_eeprom_microwire,
e1000_nvm_flash_hw,
+ e1000_nvm_invm,
e1000_nvm_flash_sw
};
@@ -391,6 +398,10 @@ union e1000_rx_desc_extended {
};
#define MAX_PS_BUFFERS 4
+
+/* Number of packet split data buffers (not including the header buffer) */
+#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1)
+
/* Receive Descriptor - Packet Split */
union e1000_rx_desc_packet_split {
struct {
@@ -415,7 +426,8 @@ union e1000_rx_desc_packet_split {
} middle;
struct {
__le16 header_status;
- __le16 length[3]; /* length of buffers 1-3 */
+ /* length of buffers 1-3 */
+ __le16 length[PS_PAGE_BUFFERS];
} upper;
__le64 reserved;
} wb; /* writeback */
@@ -940,6 +952,8 @@ struct e1000_dev_spec_82575 {
bool clear_semaphore_once;
u32 mtu;
struct sfp_e1000_flags eth_flags;
+ u8 media_port;
+ bool media_changed;
};
struct e1000_dev_spec_vf {
diff --git a/sys/dev/e1000/e1000_i210.c b/sys/dev/e1000/e1000_i210.c
index 63302c0..019e4a9 100644
--- a/sys/dev/e1000/e1000_i210.c
+++ b/sys/dev/e1000/e1000_i210.c
@@ -42,8 +42,6 @@ static s32 e1000_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words,
u16 *data);
static s32 e1000_pool_flash_update_done_i210(struct e1000_hw *hw);
static s32 e1000_valid_led_default_i210(struct e1000_hw *hw, u16 *data);
-static s32 e1000_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words,
- u16 *data);
/**
* e1000_acquire_nvm_i210 - Request for access to EEPROM
@@ -180,9 +178,8 @@ static s32 e1000_get_hw_semaphore_i210(struct e1000_hw *hw)
}
if (i == timeout) {
- /*
- * In rare circumstances, the driver may not have released the
- * SW semaphore. Clear the semaphore once before giving up.
+ /* In rare circumstances, the SW semaphore may already be held
+ * unintentionally. Clear the semaphore once before giving up.
*/
if (hw->dev_spec._82575.clear_semaphore_once) {
hw->dev_spec._82575.clear_semaphore_once = FALSE;
@@ -368,60 +365,104 @@ out:
return ret_val;
}
-/**
- * e1000_read_nvm_i211 - Read NVM wrapper function for I211
+/** e1000_read_invm_word_i210 - Reads OTP
+ * @hw: pointer to the HW structure
+ * @address: the word address (aka eeprom offset) to read
+ * @data: pointer to the data read
+ *
+ * Reads 16-bit words from the OTP. Return error when the word is not
+ * stored in OTP.
+ **/
+static s32 e1000_read_invm_word_i210(struct e1000_hw *hw, u8 address, u16 *data)
+{
+ s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND;
+ u32 invm_dword;
+ u16 i;
+ u8 record_type, word_address;
+
+ DEBUGFUNC("e1000_read_invm_word_i210");
+
+ for (i = 0; i < E1000_INVM_SIZE; i++) {
+ invm_dword = E1000_READ_REG(hw, E1000_INVM_DATA_REG(i));
+ /* Get record type */
+ record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword);
+ if (record_type == E1000_INVM_UNINITIALIZED_STRUCTURE)
+ break;
+ if (record_type == E1000_INVM_CSR_AUTOLOAD_STRUCTURE)
+ i += E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS;
+ if (record_type == E1000_INVM_RSA_KEY_SHA256_STRUCTURE)
+ i += E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS;
+ if (record_type == E1000_INVM_WORD_AUTOLOAD_STRUCTURE) {
+ word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword);
+ if (word_address == address) {
+ *data = INVM_DWORD_TO_WORD_DATA(invm_dword);
+ DEBUGOUT2("Read INVM Word 0x%02x = %x",
+ address, *data);
+ status = E1000_SUCCESS;
+ break;
+ }
+ }
+ }
+ if (status != E1000_SUCCESS)
+ DEBUGOUT1("Requested word 0x%02x not found in OTP\n", address);
+ return status;
+}
+
+/** e1000_read_invm_i210 - Read invm wrapper function for I210/I211
* @hw: pointer to the HW structure
* @address: the word address (aka eeprom offset) to read
* @data: pointer to the data read
*
* Wrapper function to return data formerly found in the NVM.
**/
-static s32 e1000_read_nvm_i211(struct e1000_hw *hw, u16 offset,
- u16 words, u16 *data)
+static s32 e1000_read_invm_i210(struct e1000_hw *hw, u16 offset,
+ u16 E1000_UNUSEDARG words, u16 *data)
{
s32 ret_val = E1000_SUCCESS;
- DEBUGFUNC("e1000_read_nvm_i211");
+ DEBUGFUNC("e1000_read_invm_i210");
/* Only the MAC addr is required to be present in the iNVM */
switch (offset) {
case NVM_MAC_ADDR:
- ret_val = e1000_read_invm_i211(hw, (u8)offset, &data[0]);
- ret_val |= e1000_read_invm_i211(hw, (u8)offset+1, &data[1]);
- ret_val |= e1000_read_invm_i211(hw, (u8)offset+2, &data[2]);
+ ret_val = e1000_read_invm_word_i210(hw, (u8)offset, &data[0]);
+ ret_val |= e1000_read_invm_word_i210(hw, (u8)offset+1,
+ &data[1]);
+ ret_val |= e1000_read_invm_word_i210(hw, (u8)offset+2,
+ &data[2]);
if (ret_val != E1000_SUCCESS)
DEBUGOUT("MAC Addr not found in iNVM\n");
break;
case NVM_INIT_CTRL_2:
- ret_val = e1000_read_invm_i211(hw, (u8)offset, data);
+ ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data);
if (ret_val != E1000_SUCCESS) {
*data = NVM_INIT_CTRL_2_DEFAULT_I211;
ret_val = E1000_SUCCESS;
}
break;
case NVM_INIT_CTRL_4:
- ret_val = e1000_read_invm_i211(hw, (u8)offset, data);
+ ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data);
if (ret_val != E1000_SUCCESS) {
*data = NVM_INIT_CTRL_4_DEFAULT_I211;
ret_val = E1000_SUCCESS;
}
break;
case NVM_LED_1_CFG:
- ret_val = e1000_read_invm_i211(hw, (u8)offset, data);
+ ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data);
if (ret_val != E1000_SUCCESS) {
*data = NVM_LED_1_CFG_DEFAULT_I211;
ret_val = E1000_SUCCESS;
}
break;
case NVM_LED_0_2_CFG:
- ret_val = e1000_read_invm_i211(hw, (u8)offset, data);
+ ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data);
if (ret_val != E1000_SUCCESS) {
*data = NVM_LED_0_2_CFG_DEFAULT_I211;
ret_val = E1000_SUCCESS;
}
break;
case NVM_ID_LED_SETTINGS:
- ret_val = e1000_read_invm_i211(hw, (u8)offset, data);
+ ret_val = e1000_read_invm_word_i210(hw, (u8)offset, data);
if (ret_val != E1000_SUCCESS) {
*data = ID_LED_RESERVED_FFFF;
ret_val = E1000_SUCCESS;
@@ -448,50 +489,6 @@ static s32 e1000_read_nvm_i211(struct e1000_hw *hw, u16 offset,
}
/**
- * e1000_read_invm_i211 - Reads OTP
- * @hw: pointer to the HW structure
- * @address: the word address (aka eeprom offset) to read
- * @data: pointer to the data read
- *
- * Reads 16-bit words from the OTP. Return error when the word is not
- * stored in OTP.
- **/
-s32 e1000_read_invm_i211(struct e1000_hw *hw, u8 address, u16 *data)
-{
- s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND;
- u32 invm_dword;
- u16 i;
- u8 record_type, word_address;
-
- DEBUGFUNC("e1000_read_invm_i211");
-
- for (i = 0; i < E1000_INVM_SIZE; i++) {
- invm_dword = E1000_READ_REG(hw, E1000_INVM_DATA_REG(i));
- /* Get record type */
- record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword);
- if (record_type == E1000_INVM_UNINITIALIZED_STRUCTURE)
- break;
- if (record_type == E1000_INVM_CSR_AUTOLOAD_STRUCTURE)
- i += E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS;
- if (record_type == E1000_INVM_RSA_KEY_SHA256_STRUCTURE)
- i += E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS;
- if (record_type == E1000_INVM_WORD_AUTOLOAD_STRUCTURE) {
- word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword);
- if (word_address == address) {
- *data = INVM_DWORD_TO_WORD_DATA(invm_dword);
- DEBUGOUT2("Read INVM Word 0x%02x = %x",
- address, *data);
- status = E1000_SUCCESS;
- break;
- }
- }
- }
- if (status != E1000_SUCCESS)
- DEBUGOUT1("Requested word 0x%02x not found in OTP\n", address);
- return status;
-}
-
-/**
* e1000_validate_nvm_checksum_i210 - Validate EEPROM checksum
* @hw: pointer to the HW structure
*
@@ -592,6 +589,26 @@ out:
}
/**
+ * e1000_get_flash_presence_i210 - Check if flash device is detected.
+ * @hw: pointer to the HW structure
+ *
+ **/
+bool e1000_get_flash_presence_i210(struct e1000_hw *hw)
+{
+ u32 eec = 0;
+ bool ret_val = FALSE;
+
+ DEBUGFUNC("e1000_get_flash_presence_i210");
+
+ eec = E1000_READ_REG(hw, E1000_EECD);
+
+ if (eec & E1000_EECD_FLASH_DETECTED_I210)
+ ret_val = TRUE;
+
+ return ret_val;
+}
+
+/**
* e1000_update_flash_i210 - Commit EEPROM to the flash
* @hw: pointer to the HW structure
*
@@ -650,7 +667,7 @@ s32 e1000_pool_flash_update_done_i210(struct e1000_hw *hw)
* e1000_init_nvm_params_i210 - Initialize i210 NVM function pointers
* @hw: pointer to the HW structure
*
- * Initialize the i210 NVM parameters and function pointers.
+ * Initialize the i210/i211 NVM parameters and function pointers.
**/
static s32 e1000_init_nvm_params_i210(struct e1000_hw *hw)
{
@@ -660,42 +677,26 @@ static s32 e1000_init_nvm_params_i210(struct e1000_hw *hw)
DEBUGFUNC("e1000_init_nvm_params_i210");
ret_val = e1000_init_nvm_params_82575(hw);
-
nvm->ops.acquire = e1000_acquire_nvm_i210;
nvm->ops.release = e1000_release_nvm_i210;
- nvm->ops.read = e1000_read_nvm_srrd_i210;
- nvm->ops.write = e1000_write_nvm_srwr_i210;
nvm->ops.valid_led_default = e1000_valid_led_default_i210;
- nvm->ops.validate = e1000_validate_nvm_checksum_i210;
- nvm->ops.update = e1000_update_nvm_checksum_i210;
-
+ if (e1000_get_flash_presence_i210(hw)) {
+ hw->nvm.type = e1000_nvm_flash_hw;
+ nvm->ops.read = e1000_read_nvm_srrd_i210;
+ nvm->ops.write = e1000_write_nvm_srwr_i210;
+ nvm->ops.validate = e1000_validate_nvm_checksum_i210;
+ nvm->ops.update = e1000_update_nvm_checksum_i210;
+ } else {
+ hw->nvm.type = e1000_nvm_invm;
+ nvm->ops.read = e1000_read_invm_i210;
+ nvm->ops.write = e1000_null_write_nvm;
+ nvm->ops.validate = e1000_null_ops_generic;
+ nvm->ops.update = e1000_null_ops_generic;
+ }
return ret_val;
}
/**
- * e1000_init_nvm_params_i211 - Initialize i211 NVM function pointers
- * @hw: pointer to the HW structure
- *
- * Initialize the NVM parameters and function pointers for i211.
- **/
-static s32 e1000_init_nvm_params_i211(struct e1000_hw *hw)
-{
- struct e1000_nvm_info *nvm = &hw->nvm;
-
- DEBUGFUNC("e1000_init_nvm_params_i211");
-
- nvm->ops.acquire = e1000_acquire_nvm_i210;
- nvm->ops.release = e1000_release_nvm_i210;
- nvm->ops.read = e1000_read_nvm_i211;
- nvm->ops.valid_led_default = e1000_valid_led_default_i210;
- nvm->ops.write = e1000_null_write_nvm;
- nvm->ops.validate = e1000_null_ops_generic;
- nvm->ops.update = e1000_null_ops_generic;
-
- return E1000_SUCCESS;
-}
-
-/**
* e1000_init_function_pointers_i210 - Init func ptrs.
* @hw: pointer to the HW structure
*
@@ -704,17 +705,8 @@ static s32 e1000_init_nvm_params_i211(struct e1000_hw *hw)
void e1000_init_function_pointers_i210(struct e1000_hw *hw)
{
e1000_init_function_pointers_82575(hw);
+ hw->nvm.ops.init_params = e1000_init_nvm_params_i210;
- switch (hw->mac.type) {
- case e1000_i210:
- hw->nvm.ops.init_params = e1000_init_nvm_params_i210;
- break;
- case e1000_i211:
- hw->nvm.ops.init_params = e1000_init_nvm_params_i211;
- break;
- default:
- break;
- }
return;
}
@@ -752,3 +744,74 @@ static s32 e1000_valid_led_default_i210(struct e1000_hw *hw, u16 *data)
out:
return ret_val;
}
+
+/**
+ * __e1000_access_xmdio_reg - Read/write XMDIO register
+ * @hw: pointer to the HW structure
+ * @address: XMDIO address to program
+ * @dev_addr: device address to program
+ * @data: pointer to value to read/write from/to the XMDIO address
+ * @read: boolean flag to indicate read or write
+ **/
+static s32 __e1000_access_xmdio_reg(struct e1000_hw *hw, u16 address,
+ u8 dev_addr, u16 *data, bool read)
+{
+ s32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("__e1000_access_xmdio_reg");
+
+ ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, dev_addr);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAAD, address);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, E1000_MMDAC_FUNC_DATA |
+ dev_addr);
+ if (ret_val)
+ return ret_val;
+
+ if (read)
+ ret_val = hw->phy.ops.read_reg(hw, E1000_MMDAAD, data);
+ else
+ ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAAD, *data);
+ if (ret_val)
+ return ret_val;
+
+ /* Recalibrate the device back to 0 */
+ ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, 0);
+ if (ret_val)
+ return ret_val;
+
+ return ret_val;
+}
+
+/**
+ * e1000_read_xmdio_reg - Read XMDIO register
+ * @hw: pointer to the HW structure
+ * @addr: XMDIO address to program
+ * @dev_addr: device address to program
+ * @data: value to be read from the EMI address
+ **/
+s32 e1000_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 *data)
+{
+ DEBUGFUNC("e1000_read_xmdio_reg");
+
+ return __e1000_access_xmdio_reg(hw, addr, dev_addr, data, TRUE);
+}
+
+/**
+ * e1000_write_xmdio_reg - Write XMDIO register
+ * @hw: pointer to the HW structure
+ * @addr: XMDIO address to program
+ * @dev_addr: device address to program
+ * @data: value to be written to the XMDIO address
+ **/
+s32 e1000_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 data)
+{
+ DEBUGFUNC("e1000_read_xmdio_reg");
+
+ return __e1000_access_xmdio_reg(hw, addr, dev_addr, &data, FALSE);
+}
diff --git a/sys/dev/e1000/e1000_i210.h b/sys/dev/e1000/e1000_i210.h
index d7711fe..d8de1bd 100644
--- a/sys/dev/e1000/e1000_i210.h
+++ b/sys/dev/e1000/e1000_i210.h
@@ -35,6 +35,7 @@
#ifndef _E1000_I210_H_
#define _E1000_I210_H_
+bool e1000_get_flash_presence_i210(struct e1000_hw *hw);
s32 e1000_update_flash_i210(struct e1000_hw *hw);
s32 e1000_update_nvm_checksum_i210(struct e1000_hw *hw);
s32 e1000_validate_nvm_checksum_i210(struct e1000_hw *hw);
@@ -42,9 +43,12 @@ s32 e1000_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset,
u16 words, u16 *data);
s32 e1000_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset,
u16 words, u16 *data);
-s32 e1000_read_invm_i211(struct e1000_hw *hw, u8 address, u16 *data);
s32 e1000_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
void e1000_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
+s32 e1000_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr,
+ u16 *data);
+s32 e1000_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr,
+ u16 data);
#define E1000_STM_OPCODE 0xDB00
#define E1000_EEPROM_FLASH_SIZE_WORD 0x11
@@ -82,7 +86,7 @@ enum E1000_INVM_STRUCTURE_TYPE {
(ID_LED_OFF1_OFF2))
#define ID_LED_DEFAULT_I210_SERDES ((ID_LED_DEF1_DEF2 << 8) | \
(ID_LED_DEF1_DEF2 << 4) | \
- (ID_LED_DEF1_DEF2))
+ (ID_LED_OFF1_ON2))
/* NVM offset defaults for I211 devices */
#define NVM_INIT_CTRL_2_DEFAULT_I211 0X7243
diff --git a/sys/dev/e1000/e1000_ich8lan.c b/sys/dev/e1000/e1000_ich8lan.c
index bd94355..82ffceb 100644
--- a/sys/dev/e1000/e1000_ich8lan.c
+++ b/sys/dev/e1000/e1000_ich8lan.c
@@ -59,6 +59,10 @@
* 82578DC Gigabit Network Connection
* 82579LM Gigabit Network Connection
* 82579V Gigabit Network Connection
+ * Ethernet Connection I217-LM
+ * Ethernet Connection I217-V
+ * Ethernet Connection I218-V
+ * Ethernet Connection I218-LM
*/
#include "e1000_api.h"
@@ -71,6 +75,7 @@ static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index);
static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index);
+static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw);
static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw,
u8 *mc_addr_list,
u32 mc_addr_count);
@@ -181,8 +186,9 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
{
u16 phy_reg = 0;
u32 phy_id = 0;
- s32 ret_val;
+ s32 ret_val = 0;
u16 retry_count;
+ u32 mac_reg = 0;
for (retry_count = 0; retry_count < 2; retry_count++) {
ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_reg);
@@ -201,23 +207,84 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
if (hw->phy.id) {
if (hw->phy.id == phy_id)
- return TRUE;
+ goto out;
} else if (phy_id) {
hw->phy.id = phy_id;
hw->phy.revision = (u32)(phy_reg & ~PHY_REVISION_MASK);
- return TRUE;
+ goto out;
}
/* In case the PHY needs to be in mdio slow mode,
* set slow mode and try to get the PHY id again.
*/
- hw->phy.ops.release(hw);
- ret_val = e1000_set_mdio_slow_mode_hv(hw);
- if (!ret_val)
- ret_val = e1000_get_phy_id(hw);
- hw->phy.ops.acquire(hw);
+ if (hw->mac.type < e1000_pch_lpt) {
+ hw->phy.ops.release(hw);
+ ret_val = e1000_set_mdio_slow_mode_hv(hw);
+ if (!ret_val)
+ ret_val = e1000_get_phy_id(hw);
+ hw->phy.ops.acquire(hw);
+ }
+
+ if (ret_val)
+ return FALSE;
+out:
+ if (hw->mac.type == e1000_pch_lpt) {
+ /* Unforce SMBus mode in PHY */
+ hw->phy.ops.read_reg_locked(hw, CV_SMB_CTRL, &phy_reg);
+ phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
+ hw->phy.ops.write_reg_locked(hw, CV_SMB_CTRL, phy_reg);
+
+ /* Unforce SMBus mode in MAC */
+ mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
+ }
+
+ return TRUE;
+}
+
+/**
+ * e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value
+ * @hw: pointer to the HW structure
+ *
+ * Toggling the LANPHYPC pin value fully power-cycles the PHY and is
+ * used to reset the PHY to a quiescent state when necessary.
+ **/
+void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw)
+{
+ u32 mac_reg;
+
+ DEBUGFUNC("e1000_toggle_lanphypc_pch_lpt");
+
+ /* Set Phy Config Counter to 50msec */
+ mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM3);
+ mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
+ mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
+ E1000_WRITE_REG(hw, E1000_FEXTNVM3, mac_reg);
+
+ /* Toggle LANPHYPC Value bit */
+ mac_reg = E1000_READ_REG(hw, E1000_CTRL);
+ mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
+ mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
+ E1000_WRITE_REG(hw, E1000_CTRL, mac_reg);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(10);
+ mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
+ E1000_WRITE_REG(hw, E1000_CTRL, mac_reg);
+ E1000_WRITE_FLUSH(hw);
+
+ if (hw->mac.type < e1000_pch_lpt) {
+ msec_delay(50);
+ } else {
+ u16 count = 20;
+
+ do {
+ msec_delay(5);
+ } while (!(E1000_READ_REG(hw, E1000_CTRL_EXT) &
+ E1000_CTRL_EXT_LPCD) && count--);
- return !ret_val;
+ msec_delay(30);
+ }
}
/**
@@ -231,7 +298,6 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
{
u32 mac_reg, fwsm = E1000_READ_REG(hw, E1000_FWSM);
s32 ret_val;
- u16 phy_reg;
DEBUGFUNC("e1000_init_phy_workarounds_pchlan");
@@ -262,24 +328,16 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
+ /* Wait 50 milliseconds for MAC to finish any retries
+ * that it might be trying to perform from previous
+ * attempts to acknowledge any phy read requests.
+ */
+ msec_delay(50);
+
/* fall-through */
case e1000_pch2lan:
- if (e1000_phy_is_accessible_pchlan(hw)) {
- if (hw->mac.type == e1000_pch_lpt) {
- /* Unforce SMBus mode in PHY */
- hw->phy.ops.read_reg_locked(hw, CV_SMB_CTRL,
- &phy_reg);
- phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
- hw->phy.ops.write_reg_locked(hw, CV_SMB_CTRL,
- phy_reg);
-
- /* Unforce SMBus mode in MAC */
- mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
- mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
- E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
- }
+ if (e1000_phy_is_accessible_pchlan(hw))
break;
- }
/* fall-through */
case e1000_pchlan:
@@ -289,44 +347,27 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
if (hw->phy.ops.check_reset_block(hw)) {
DEBUGOUT("Required LANPHYPC toggle blocked by ME\n");
+ ret_val = -E1000_ERR_PHY;
break;
}
- DEBUGOUT("Toggling LANPHYPC\n");
-
- /* Set Phy Config Counter to 50msec */
- mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM3);
- mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
- mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
- E1000_WRITE_REG(hw, E1000_FEXTNVM3, mac_reg);
+ /* Toggle LANPHYPC Value bit */
+ e1000_toggle_lanphypc_pch_lpt(hw);
+ if (hw->mac.type >= e1000_pch_lpt) {
+ if (e1000_phy_is_accessible_pchlan(hw))
+ break;
- if (hw->mac.type == e1000_pch_lpt) {
/* Toggling LANPHYPC brings the PHY out of SMBus mode
- * So ensure that the MAC is also out of SMBus mode
+ * so ensure that the MAC is also out of SMBus mode
*/
mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
- }
- /* Toggle LANPHYPC Value bit */
- mac_reg = E1000_READ_REG(hw, E1000_CTRL);
- mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
- mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
- E1000_WRITE_REG(hw, E1000_CTRL, mac_reg);
- E1000_WRITE_FLUSH(hw);
- usec_delay(10);
- mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
- E1000_WRITE_REG(hw, E1000_CTRL, mac_reg);
- E1000_WRITE_FLUSH(hw);
- if (hw->mac.type < e1000_pch_lpt) {
- msec_delay(50);
- } else {
- u16 count = 20;
- do {
- msec_delay(5);
- } while (!(E1000_READ_REG(hw, E1000_CTRL_EXT) &
- E1000_CTRL_EXT_LPCD) && count--);
+ if (e1000_phy_is_accessible_pchlan(hw))
+ break;
+
+ ret_val = -E1000_ERR_PHY;
}
break;
default:
@@ -334,13 +375,33 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
}
hw->phy.ops.release(hw);
+ if (!ret_val) {
- /* Reset the PHY before any access to it. Doing so, ensures
- * that the PHY is in a known good state before we read/write
- * PHY registers. The generic reset is sufficient here,
- * because we haven't determined the PHY type yet.
- */
- ret_val = e1000_phy_hw_reset_generic(hw);
+ /* Check to see if able to reset PHY. Print error if not */
+ if (hw->phy.ops.check_reset_block(hw)) {
+ ERROR_REPORT("Reset blocked by ME\n");
+ goto out;
+ }
+
+ /* Reset the PHY before any access to it. Doing so, ensures
+ * that the PHY is in a known good state before we read/write
+ * PHY registers. The generic reset is sufficient here,
+ * because we haven't determined the PHY type yet.
+ */
+ ret_val = e1000_phy_hw_reset_generic(hw);
+ if (ret_val)
+ goto out;
+
+ /* On a successful reset, possibly need to wait for the PHY
+ * to quiesce to an accessible state before returning control
+ * to the calling function. If the PHY does not quiesce, then
+ * return E1000E_BLK_PHY_RESET, as this is the condition that
+ * the PHY is in.
+ */
+ ret_val = hw->phy.ops.check_reset_block(hw);
+ if (ret_val)
+ ERROR_REPORT("ME blocked access to PHY after reset\n");
+ }
out:
/* Ungate automatic PHY configuration on non-managed 82579 */
@@ -572,8 +633,8 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
/* find total size of the NVM, then cut in half since the total
* size represents two separate NVM banks.
*/
- nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
- << FLASH_SECTOR_ADDR_SHIFT;
+ nvm->flash_bank_size = ((sector_end_addr - sector_base_addr)
+ << FLASH_SECTOR_ADDR_SHIFT);
nvm->flash_bank_size /= 2;
/* Adjust to word count */
nvm->flash_bank_size /= sizeof(u16);
@@ -766,7 +827,7 @@ s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data)
*
* Assumes the SW/FW/HW Semaphore is already acquired.
**/
-static s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
+s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
{
DEBUGFUNC("e1000_read_emi_reg_locked");
@@ -780,18 +841,35 @@ static s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
* Enable/disable EEE based on setting in dev_spec structure, the duplex of
* the link and the EEE capabilities of the link partner. The LPI Control
* register bits will remain set only if/when link is up.
+ *
+ * EEE LPI must not be asserted earlier than one second after link is up.
+ * On 82579, EEE LPI should not be enabled until such time otherwise there
+ * can be link issues with some switches. Other devices can have EEE LPI
+ * enabled immediately upon link up since they have a timer in hardware which
+ * prevents LPI from being asserted too early.
**/
-static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
+s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
{
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
s32 ret_val;
- u16 lpi_ctrl;
+ u16 lpa, pcs_status, adv, adv_addr, lpi_ctrl, data;
DEBUGFUNC("e1000_set_eee_pchlan");
- if ((hw->phy.type != e1000_phy_82579) &&
- (hw->phy.type != e1000_phy_i217))
+ switch (hw->phy.type) {
+ case e1000_phy_82579:
+ lpa = I82579_EEE_LP_ABILITY;
+ pcs_status = I82579_EEE_PCS_STATUS;
+ adv_addr = I82579_EEE_ADVERTISEMENT;
+ break;
+ case e1000_phy_i217:
+ lpa = I217_EEE_LP_ABILITY;
+ pcs_status = I217_EEE_PCS_STATUS;
+ adv_addr = I217_EEE_ADVERTISEMENT;
+ break;
+ default:
return E1000_SUCCESS;
+ }
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
@@ -806,34 +884,24 @@ static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
/* Enable EEE if not disabled by user */
if (!dev_spec->eee_disable) {
- u16 lpa, pcs_status, data;
-
/* Save off link partner's EEE ability */
- switch (hw->phy.type) {
- case e1000_phy_82579:
- lpa = I82579_EEE_LP_ABILITY;
- pcs_status = I82579_EEE_PCS_STATUS;
- break;
- case e1000_phy_i217:
- lpa = I217_EEE_LP_ABILITY;
- pcs_status = I217_EEE_PCS_STATUS;
- break;
- default:
- ret_val = -E1000_ERR_PHY;
- goto release;
- }
ret_val = e1000_read_emi_reg_locked(hw, lpa,
&dev_spec->eee_lp_ability);
if (ret_val)
goto release;
+ /* Read EEE advertisement */
+ ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &adv);
+ if (ret_val)
+ goto release;
+
/* Enable EEE only for speeds in which the link partner is
- * EEE capable.
+ * EEE capable and for which we advertise EEE.
*/
- if (dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
+ if (adv & dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE;
- if (dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) {
+ if (adv & dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) {
hw->phy.ops.read_reg_locked(hw, PHY_LP_ABILITY, &data);
if (data & NWAY_LPAR_100TX_FD_CAPS)
lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE;
@@ -845,13 +913,13 @@ static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
dev_spec->eee_lp_ability &=
~I82579_EEE_100_SUPPORTED;
}
-
- /* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
- ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
- if (ret_val)
- goto release;
}
+ /* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
+ ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
+ if (ret_val)
+ goto release;
+
ret_val = hw->phy.ops.write_reg_locked(hw, I82579_LPI_CTRL, lpi_ctrl);
release:
hw->phy.ops.release(hw);
@@ -867,30 +935,31 @@ release:
* When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications
* preventing further DMA write requests. Workaround the issue by disabling
* the de-assertion of the clock request when in 1Gpbs mode.
+ * Also, set appropriate Tx re-transmission timeouts for 10 and 100Half link
+ * speeds in order to avoid Tx hangs.
**/
static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link)
{
u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
+ u32 status = E1000_READ_REG(hw, E1000_STATUS);
s32 ret_val = E1000_SUCCESS;
+ u16 reg;
- if (link && (E1000_READ_REG(hw, E1000_STATUS) &
- E1000_STATUS_SPEED_1000)) {
- u16 kmrn_reg;
-
+ if (link && (status & E1000_STATUS_SPEED_1000)) {
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
return ret_val;
ret_val =
e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
- &kmrn_reg);
+ &reg);
if (ret_val)
goto release;
ret_val =
e1000_write_kmrn_reg_locked(hw,
E1000_KMRNCTRLSTA_K1_CONFIG,
- kmrn_reg &
+ reg &
~E1000_KMRNCTRLSTA_K1_ENABLE);
if (ret_val)
goto release;
@@ -903,13 +972,45 @@ static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link)
ret_val =
e1000_write_kmrn_reg_locked(hw,
E1000_KMRNCTRLSTA_K1_CONFIG,
- kmrn_reg);
+ reg);
release:
hw->phy.ops.release(hw);
} else {
/* clear FEXTNVM6 bit 8 on link down or 10/100 */
- E1000_WRITE_REG(hw, E1000_FEXTNVM6,
- fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK);
+ fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK;
+
+ if (!link || ((status & E1000_STATUS_SPEED_100) &&
+ (status & E1000_STATUS_FD)))
+ goto update_fextnvm6;
+
+ ret_val = hw->phy.ops.read_reg(hw, I217_INBAND_CTRL, &reg);
+ if (ret_val)
+ return ret_val;
+
+ /* Clear link status transmit timeout */
+ reg &= ~I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK;
+
+ if (status & E1000_STATUS_SPEED_100) {
+ /* Set inband Tx timeout to 5x10us for 100Half */
+ reg |= 5 << I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;
+
+ /* Do not extend the K1 entry latency for 100Half */
+ fextnvm6 &= ~E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
+ } else {
+ /* Set inband Tx timeout to 50x10us for 10Full/Half */
+ reg |= 50 <<
+ I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;
+
+ /* Extend the K1 entry latency for 10 Mbps */
+ fextnvm6 |= E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
+ }
+
+ ret_val = hw->phy.ops.write_reg(hw, I217_INBAND_CTRL, reg);
+ if (ret_val)
+ return ret_val;
+
+update_fextnvm6:
+ E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6);
}
return ret_val;
@@ -1018,7 +1119,6 @@ static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
lat_ns /= 1000000000;
obff_hwm = (s32)(rxa - lat_ns);
}
-
if ((obff_hwm < 0) || (obff_hwm > E1000_SVT_OFF_HWM_MASK)) {
DEBUGOUT1("Invalid high water mark %d\n", obff_hwm);
return -E1000_ERR_CONFIG;
@@ -1103,13 +1203,13 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
if (!mac->get_link_status)
return E1000_SUCCESS;
- /* First we want to see if the MII Status Register reports
- * link. If so, then we want to get the current speed/duplex
- * of the PHY.
- */
- ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
- if (ret_val)
- return ret_val;
+ /* First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ */
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ return ret_val;
if (hw->mac.type == e1000_pchlan) {
ret_val = e1000_k1_gig_workaround_hv(hw, link);
@@ -1153,8 +1253,9 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
}
if (hw->mac.type == e1000_pch_lpt) {
- /* Set platform power management values for Latency Tolerance
- * Reporting (LTR) and Optimized Buffer Flush/Fill (OBFF).
+ /* Set platform power management values for
+ * Latency Tolerance Reporting (LTR)
+ * Optimized Buffer Flush/Fill (OBFF)
*/
ret_val = e1000_platform_pm_pch_lpt(hw, link);
if (ret_val)
@@ -1206,9 +1307,11 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
e1000_check_downshift_generic(hw);
/* Enable/Disable EEE after link up */
- ret_val = e1000_set_eee_pchlan(hw);
- if (ret_val)
- return ret_val;
+ if (hw->phy.type > e1000_phy_82579) {
+ ret_val = e1000_set_eee_pchlan(hw);
+ if (ret_val)
+ return ret_val;
+ }
/* If we are forcing speed/duplex, then we simply return since
* we have already determined whether we have link or not.
@@ -1396,9 +1499,9 @@ static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
fwsm = E1000_READ_REG(hw, E1000_FWSM);
- return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
- ((fwsm & E1000_FWSM_MODE_MASK) ==
- (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
+ return ((fwsm & E1000_ICH_FWSM_FW_VALID) &&
+ ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)));
}
/**
@@ -1459,7 +1562,10 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index)
return;
}
- if (index < hw->mac.rar_entry_count) {
+ /* RAR[1-6] are owned by manageability. Skip those and program the
+ * next address into the SHRA register array.
+ */
+ if (index < (u32) (hw->mac.rar_entry_count - 6)) {
s32 ret_val;
ret_val = e1000_acquire_swflag_ich8lan(hw);
@@ -1619,13 +1725,21 @@ release:
static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
{
u32 fwsm;
+ bool blocked = FALSE;
+ int i = 0;
DEBUGFUNC("e1000_check_reset_block_ich8lan");
- fwsm = E1000_READ_REG(hw, E1000_FWSM);
-
- return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS
- : E1000_BLK_PHY_RESET;
+ do {
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+ if (!(fwsm & E1000_ICH_FWSM_RSPCIPHY)) {
+ blocked = TRUE;
+ msec_delay(10);
+ continue;
+ }
+ blocked = FALSE;
+ } while (blocked && (i++ < 10));
+ return blocked ? E1000_BLK_PHY_RESET : E1000_SUCCESS;
}
/**
@@ -1825,9 +1939,9 @@ static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
if (ret_val)
goto release;
- status_reg &= BM_CS_STATUS_LINK_UP |
- BM_CS_STATUS_RESOLVED |
- BM_CS_STATUS_SPEED_MASK;
+ status_reg &= (BM_CS_STATUS_LINK_UP |
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_MASK);
if (status_reg == (BM_CS_STATUS_LINK_UP |
BM_CS_STATUS_RESOLVED |
@@ -1841,9 +1955,9 @@ static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
if (ret_val)
goto release;
- status_reg &= HV_M_STATUS_LINK_UP |
- HV_M_STATUS_AUTONEG_COMPLETE |
- HV_M_STATUS_SPEED_MASK;
+ status_reg &= (HV_M_STATUS_LINK_UP |
+ HV_M_STATUS_AUTONEG_COMPLETE |
+ HV_M_STATUS_SPEED_MASK);
if (status_reg == (HV_M_STATUS_LINK_UP |
HV_M_STATUS_AUTONEG_COMPLETE |
@@ -2125,8 +2239,8 @@ void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
if (ret_val)
goto release;
- /* Copy both RAL/H (rar_entry_count) and SHRAL/H (+4) to PHY */
- for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+ /* Copy both RAL/H (rar_entry_count) and SHRAL/H to PHY */
+ for (i = 0; i < (hw->mac.rar_entry_count); i++) {
mac_reg = E1000_READ_REG(hw, E1000_RAL(i));
hw->phy.ops.write_reg_page(hw, BM_RAR_L(i),
(u16)(mac_reg & 0xFFFF));
@@ -2191,10 +2305,10 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
return ret_val;
if (enable) {
- /* Write Rx addresses (rar_entry_count for RAL/H, +4 for
+ /* Write Rx addresses (rar_entry_count for RAL/H, and
* SHRAL/H) and initial CRC values to the MAC
*/
- for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+ for (i = 0; i < hw->mac.rar_entry_count; i++) {
u8 mac_addr[ETH_ADDR_LEN] = {0};
u32 addr_high, addr_low;
@@ -3112,11 +3226,11 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
DEBUGFUNC("e1000_read_flash_data_ich8lan");
- if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
return -E1000_ERR_NVM;
- flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
- hw->nvm.flash_base_addr;
+ flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr);
do {
usec_delay(1);
@@ -3133,8 +3247,9 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
- ret_val = e1000_flash_cycle_ich8lan(hw,
- ICH_FLASH_READ_COMMAND_TIMEOUT);
+ ret_val =
+ e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_READ_COMMAND_TIMEOUT);
/* Check if FCERR is set to 1, if set to 1, clear it
* and try the whole sequence a few more times, else
@@ -3437,8 +3552,8 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
offset > ICH_FLASH_LINEAR_ADDR_MASK)
return -E1000_ERR_NVM;
- flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
- hw->nvm.flash_base_addr;
+ flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr);
do {
usec_delay(1);
@@ -3465,8 +3580,9 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
/* check if FCERR is set to 1 , if set to 1, clear it
* and try the whole sequence a few more times else done
*/
- ret_val = e1000_flash_cycle_ich8lan(hw,
- ICH_FLASH_WRITE_COMMAND_TIMEOUT);
+ ret_val =
+ e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_WRITE_COMMAND_TIMEOUT);
if (ret_val == E1000_SUCCESS)
break;
@@ -3602,8 +3718,10 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
flash_linear_addr = hw->nvm.flash_base_addr;
flash_linear_addr += (bank) ? flash_bank_size : 0;
- for (j = 0; j < iteration ; j++) {
+ for (j = 0; j < iteration; j++) {
do {
+ u32 timeout = ICH_FLASH_ERASE_COMMAND_TIMEOUT;
+
/* Steps */
ret_val = e1000_flash_cycle_init_ich8lan(hw);
if (ret_val)
@@ -3626,8 +3744,7 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR,
flash_linear_addr);
- ret_val = e1000_flash_cycle_ich8lan(hw,
- ICH_FLASH_ERASE_COMMAND_TIMEOUT);
+ ret_val = e1000_flash_cycle_ich8lan(hw, timeout);
if (ret_val == E1000_SUCCESS)
break;
@@ -3947,16 +4064,16 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
/* Set the transmit descriptor write-back policy for both queues */
txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
- txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
- E1000_TXDCTL_FULL_TX_DESC_WB;
- txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
- E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+ txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB);
+ txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) |
+ E1000_TXDCTL_MAX_TX_DESC_PREFETCH);
E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1));
- txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
- E1000_TXDCTL_FULL_TX_DESC_WB;
- txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
- E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+ txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB);
+ txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) |
+ E1000_TXDCTL_MAX_TX_DESC_PREFETCH);
E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl);
/* ICH8 has opposite polarity of no_snoop bits.
@@ -4041,6 +4158,7 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
*/
reg = E1000_READ_REG(hw, E1000_RFCTL);
reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
+
/* Disable IPv6 extension header parsing because some malformed
* IPv6 headers can hang the Rx.
*/
@@ -4502,14 +4620,25 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
/* Disable LPLU if both link partners support 100BaseT
* EEE and 100Full is advertised on both ends of the
- * link.
+ * link, and enable Auto Enable LPI since there will
+ * be no driver to enable LPI while in Sx.
*/
if ((eee_advert & I82579_EEE_100_SUPPORTED) &&
(dev_spec->eee_lp_ability &
I82579_EEE_100_SUPPORTED) &&
- (hw->phy.autoneg_advertised & ADVERTISE_100_FULL))
+ (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)) {
phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU |
E1000_PHY_CTRL_NOND0A_LPLU);
+
+ /* Set Auto Enable LPI after link up */
+ hw->phy.ops.read_reg_locked(hw,
+ I217_LPI_GPIO_CTRL,
+ &phy_reg);
+ phy_reg |= I217_LPI_GPIO_CTRL_AUTO_EN_LPI;
+ hw->phy.ops.write_reg_locked(hw,
+ I217_LPI_GPIO_CTRL,
+ phy_reg);
+ }
}
/* For i217 Intel Rapid Start Technology support,
@@ -4613,6 +4742,11 @@ void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
return;
}
+ /* Clear Auto Enable LPI after link up */
+ hw->phy.ops.read_reg_locked(hw, I217_LPI_GPIO_CTRL, &phy_reg);
+ phy_reg &= ~I217_LPI_GPIO_CTRL_AUTO_EN_LPI;
+ hw->phy.ops.write_reg_locked(hw, I217_LPI_GPIO_CTRL, phy_reg);
+
if (!(E1000_READ_REG(hw, E1000_FWSM) &
E1000_ICH_FWSM_FW_VALID)) {
/* Restore clear on SMB if no manageability engine
diff --git a/sys/dev/e1000/e1000_ich8lan.h b/sys/dev/e1000/e1000_ich8lan.h
index bf92898..2dbf812 100644
--- a/sys/dev/e1000/e1000_ich8lan.h
+++ b/sys/dev/e1000/e1000_ich8lan.h
@@ -60,10 +60,10 @@
#define ICH_FLASH_SEG_SIZE_8K 8192
#define ICH_FLASH_SEG_SIZE_64K 65536
-#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */
+#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */
/* FW established a valid mode */
-#define E1000_ICH_FWSM_FW_VALID 0x00008000
-#define E1000_ICH_FWSM_PCIM2PCI 0x01000000 /* ME PCIm-to-PCI active */
+#define E1000_ICH_FWSM_FW_VALID 0x00008000
+#define E1000_ICH_FWSM_PCIM2PCI 0x01000000 /* ME PCIm-to-PCI active */
#define E1000_ICH_FWSM_PCIM2PCI_COUNT 2000
#define E1000_ICH_MNG_IAMT_MODE 0x2
@@ -88,7 +88,7 @@
#define E1000_ICH8_LAN_INIT_TIMEOUT 1500
#define E1000_FEXTNVM_SW_CONFIG 1
-#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M */
+#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* different on ICH8M */
#define E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK 0x0C000000
#define E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC 0x08000000
@@ -98,18 +98,19 @@
#define E1000_FEXTNVM4_BEACON_DURATION_16USEC 0x3
#define E1000_FEXTNVM6_REQ_PLL_CLK 0x00000100
+#define E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION 0x00000200
#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL
#define E1000_ICH_RAR_ENTRIES 7
-#define E1000_PCH2_RAR_ENTRIES 5 /* RAR[0], SHRA[0-3] */
+#define E1000_PCH2_RAR_ENTRIES 11 /* RAR[0-6], SHRA[0-3] */
#define E1000_PCH_LPT_RAR_ENTRIES 12 /* RAR[0], SHRA[0-10] */
#define PHY_PAGE_SHIFT 5
#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
((reg) & MAX_PHY_REG_ADDRESS))
-#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */
-#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */
+#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */
+#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */
#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002
#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
@@ -140,19 +141,20 @@
#define HV_MUX_DATA_CTRL_GEN_TO_MAC 0x0400
#define HV_MUX_DATA_CTRL_FORCE_SPEED 0x0004
#define HV_STATS_PAGE 778
-#define HV_SCC_UPPER PHY_REG(HV_STATS_PAGE, 16) /* Single Collision Count */
+/* Half-duplex collision counts */
+#define HV_SCC_UPPER PHY_REG(HV_STATS_PAGE, 16) /* Single Collision */
#define HV_SCC_LOWER PHY_REG(HV_STATS_PAGE, 17)
-#define HV_ECOL_UPPER PHY_REG(HV_STATS_PAGE, 18) /* Excessive Coll. Count */
+#define HV_ECOL_UPPER PHY_REG(HV_STATS_PAGE, 18) /* Excessive Coll. */
#define HV_ECOL_LOWER PHY_REG(HV_STATS_PAGE, 19)
-#define HV_MCC_UPPER PHY_REG(HV_STATS_PAGE, 20) /* Multiple Coll. Count */
+#define HV_MCC_UPPER PHY_REG(HV_STATS_PAGE, 20) /* Multiple Collision */
#define HV_MCC_LOWER PHY_REG(HV_STATS_PAGE, 21)
-#define HV_LATECOL_UPPER PHY_REG(HV_STATS_PAGE, 23) /* Late Collision Count */
+#define HV_LATECOL_UPPER PHY_REG(HV_STATS_PAGE, 23) /* Late Collision */
#define HV_LATECOL_LOWER PHY_REG(HV_STATS_PAGE, 24)
-#define HV_COLC_UPPER PHY_REG(HV_STATS_PAGE, 25) /* Collision Count */
+#define HV_COLC_UPPER PHY_REG(HV_STATS_PAGE, 25) /* Collision */
#define HV_COLC_LOWER PHY_REG(HV_STATS_PAGE, 26)
#define HV_DC_UPPER PHY_REG(HV_STATS_PAGE, 27) /* Defer Count */
#define HV_DC_LOWER PHY_REG(HV_STATS_PAGE, 28)
-#define HV_TNCRS_UPPER PHY_REG(HV_STATS_PAGE, 29) /* Transmit with no CRS */
+#define HV_TNCRS_UPPER PHY_REG(HV_STATS_PAGE, 29) /* Tx with no CRS */
#define HV_TNCRS_LOWER PHY_REG(HV_STATS_PAGE, 30)
#define E1000_FCRTV_PCH 0x05F40 /* PCH Flow Control Refresh Timer Value */
@@ -201,6 +203,15 @@
#define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in ms */
+/* Inband Control */
+#define I217_INBAND_CTRL PHY_REG(770, 18)
+#define I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK 0x3F00
+#define I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT 8
+
+/* Low Power Idle GPIO Control */
+#define I217_LPI_GPIO_CTRL PHY_REG(772, 18)
+#define I217_LPI_GPIO_CTRL_AUTO_EN_LPI 0x0800
+
/* PHY Low Power Idle Control */
#define I82579_LPI_CTRL PHY_REG(772, 20)
#define I82579_LPI_CTRL_100_ENABLE 0x2000
@@ -208,6 +219,10 @@
#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
#define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT 0x80
+/* 82579 DFT Control */
+#define I82579_DFT_CTRL PHY_REG(769, 20)
+#define I82579_DFT_CTRL_GATE_PHY_RESET 0x0040 /* Gate PHY Reset on MAC Reset */
+
/* Extended Management Interface (EMI) Registers */
#define I82579_EMI_ADDR 0x10
#define I82579_EMI_DATA 0x11
@@ -216,12 +231,12 @@
#define I82577_MSE_THRESHOLD 0x0887 /* 82577 Mean Square Error Threshold */
#define I82579_MSE_LINK_DOWN 0x2411 /* MSE count before dropping link */
#define I82579_RX_CONFIG 0x3412 /* Receive configuration */
-#define I82579_EEE_PCS_STATUS 0x182D /* IEEE MMD Register 3.1 >> 8 */
+#define I82579_EEE_PCS_STATUS 0x182E /* IEEE MMD Register 3.1 >> 8 */
#define I82579_EEE_CAPABILITY 0x0410 /* IEEE MMD Register 3.20 */
#define I82579_EEE_ADVERTISEMENT 0x040E /* IEEE MMD Register 7.60 */
#define I82579_EEE_LP_ABILITY 0x040F /* IEEE MMD Register 7.61 */
-#define I82579_EEE_100_SUPPORTED (1 << 1) /* 100BaseTx EEE supported */
-#define I82579_EEE_1000_SUPPORTED (1 << 2) /* 1000BaseTx EEE supported */
+#define I82579_EEE_100_SUPPORTED (1 << 1) /* 100BaseTx EEE */
+#define I82579_EEE_1000_SUPPORTED (1 << 2) /* 1000BaseTx EEE */
#define I217_EEE_PCS_STATUS 0x9401 /* IEEE MMD Register 3.1 */
#define I217_EEE_CAPABILITY 0x8000 /* IEEE MMD Register 3.20 */
#define I217_EEE_ADVERTISEMENT 0x8001 /* IEEE MMD Register 7.60 */
@@ -274,4 +289,7 @@ s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data);
+s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data);
+s32 e1000_set_eee_pchlan(struct e1000_hw *hw);
+void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw);
#endif /* _E1000_ICH8LAN_H_ */
diff --git a/sys/dev/e1000/e1000_mac.c b/sys/dev/e1000/e1000_mac.c
index 9e6b30c..cba3fea 100644
--- a/sys/dev/e1000/e1000_mac.c
+++ b/sys/dev/e1000/e1000_mac.c
@@ -85,7 +85,7 @@ void e1000_init_mac_ops_generic(struct e1000_hw *hw)
* e1000_null_ops_generic - No-op function, returns 0
* @hw: pointer to the HW structure
**/
-s32 e1000_null_ops_generic(struct e1000_hw *hw)
+s32 e1000_null_ops_generic(struct e1000_hw E1000_UNUSEDARG *hw)
{
DEBUGFUNC("e1000_null_ops_generic");
return E1000_SUCCESS;
@@ -95,7 +95,7 @@ s32 e1000_null_ops_generic(struct e1000_hw *hw)
* e1000_null_mac_generic - No-op function, return void
* @hw: pointer to the HW structure
**/
-void e1000_null_mac_generic(struct e1000_hw *hw)
+void e1000_null_mac_generic(struct e1000_hw E1000_UNUSEDARG *hw)
{
DEBUGFUNC("e1000_null_mac_generic");
return;
@@ -105,7 +105,8 @@ void e1000_null_mac_generic(struct e1000_hw *hw)
* e1000_null_link_info - No-op function, return 0
* @hw: pointer to the HW structure
**/
-s32 e1000_null_link_info(struct e1000_hw *hw, u16 *s, u16 *d)
+s32 e1000_null_link_info(struct e1000_hw E1000_UNUSEDARG *hw,
+ u16 E1000_UNUSEDARG *s, u16 E1000_UNUSEDARG *d)
{
DEBUGFUNC("e1000_null_link_info");
return E1000_SUCCESS;
@@ -115,7 +116,8 @@ s32 e1000_null_link_info(struct e1000_hw *hw, u16 *s, u16 *d)
* e1000_null_mng_mode - No-op function, return FALSE
* @hw: pointer to the HW structure
**/
-bool e1000_null_mng_mode(struct e1000_hw *hw) {
+bool e1000_null_mng_mode(struct e1000_hw E1000_UNUSEDARG *hw)
+{
DEBUGFUNC("e1000_null_mng_mode");
return FALSE;
}
@@ -124,7 +126,8 @@ bool e1000_null_mng_mode(struct e1000_hw *hw) {
* e1000_null_update_mc - No-op function, return void
* @hw: pointer to the HW structure
**/
-void e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a)
+void e1000_null_update_mc(struct e1000_hw E1000_UNUSEDARG *hw,
+ u8 E1000_UNUSEDARG *h, u32 E1000_UNUSEDARG a)
{
DEBUGFUNC("e1000_null_update_mc");
return;
@@ -134,7 +137,8 @@ void e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a)
* e1000_null_write_vfta - No-op function, return void
* @hw: pointer to the HW structure
**/
-void e1000_null_write_vfta(struct e1000_hw *hw, u32 a, u32 b)
+void e1000_null_write_vfta(struct e1000_hw E1000_UNUSEDARG *hw,
+ u32 E1000_UNUSEDARG a, u32 E1000_UNUSEDARG b)
{
DEBUGFUNC("e1000_null_write_vfta");
return;
@@ -144,7 +148,8 @@ void e1000_null_write_vfta(struct e1000_hw *hw, u32 a, u32 b)
* e1000_null_rar_set - No-op function, return void
* @hw: pointer to the HW structure
**/
-void e1000_null_rar_set(struct e1000_hw *hw, u8 *h, u32 a)
+void e1000_null_rar_set(struct e1000_hw E1000_UNUSEDARG *hw,
+ u8 E1000_UNUSEDARG *h, u32 E1000_UNUSEDARG a)
{
DEBUGFUNC("e1000_null_rar_set");
return;
@@ -154,7 +159,8 @@ void e1000_null_rar_set(struct e1000_hw *hw, u8 *h, u32 a)
* e1000_null_set_obff_timer - No-op function, return 0
* @hw: pointer to the HW structure
**/
-s32 e1000_null_set_obff_timer(struct e1000_hw *hw, u32 a)
+s32 e1000_null_set_obff_timer(struct e1000_hw E1000_UNUSEDARG *hw,
+ u32 E1000_UNUSEDARG a)
{
DEBUGFUNC("e1000_null_set_obff_timer");
return E1000_SUCCESS;
@@ -940,6 +946,7 @@ s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
{
s32 ret_val;
u16 nvm_data;
+ u16 nvm_offset = 0;
DEBUGFUNC("e1000_set_default_fc_generic");
@@ -951,7 +958,18 @@ s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
* control setting, then the variable hw->fc will
* be initialized based on a value in the EEPROM.
*/
- ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
+ if (hw->mac.type == e1000_i350) {
+ nvm_offset = NVM_82580_LAN_FUNC_OFFSET(hw->bus.func);
+ ret_val = hw->nvm.ops.read(hw,
+ NVM_INIT_CONTROL2_REG +
+ nvm_offset,
+ 1, &nvm_data);
+ } else {
+ ret_val = hw->nvm.ops.read(hw,
+ NVM_INIT_CONTROL2_REG,
+ 1, &nvm_data);
+ }
+
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
@@ -1675,7 +1693,7 @@ s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
* Sets the speed and duplex to gigabit full duplex (the only possible option)
* for fiber/serdes links.
**/
-s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
+s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw E1000_UNUSEDARG *hw,
u16 *speed, u16 *duplex)
{
DEBUGFUNC("e1000_get_speed_and_duplex_fiber_serdes_generic");
@@ -2187,7 +2205,7 @@ static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw)
* Validate the MDI/MDIx setting, allowing for auto-crossover during forced
* operation.
**/
-s32 e1000_validate_mdi_setting_crossover_generic(struct e1000_hw *hw)
+s32 e1000_validate_mdi_setting_crossover_generic(struct e1000_hw E1000_UNUSEDARG *hw)
{
DEBUGFUNC("e1000_validate_mdi_setting_crossover_generic");
diff --git a/sys/dev/e1000/e1000_osdep.h b/sys/dev/e1000/e1000_osdep.h
index dd19613..9cf710e 100644
--- a/sys/dev/e1000/e1000_osdep.h
+++ b/sys/dev/e1000/e1000_osdep.h
@@ -60,6 +60,7 @@
#define ASSERT(x) if(!(x)) panic("EM: x")
#define usec_delay(x) DELAY(x)
+#define usec_delay_irq(x) DELAY(x)
#define msec_delay(x) DELAY(1000*(x))
#define msec_delay_irq(x) DELAY(1000*(x))
diff --git a/sys/dev/e1000/e1000_phy.c b/sys/dev/e1000/e1000_phy.c
index 241c1d5..3820410 100644
--- a/sys/dev/e1000/e1000_phy.c
+++ b/sys/dev/e1000/e1000_phy.c
@@ -104,7 +104,8 @@ void e1000_init_phy_ops_generic(struct e1000_hw *hw)
* e1000_null_set_page - No-op function, return 0
* @hw: pointer to the HW structure
**/
-s32 e1000_null_set_page(struct e1000_hw *hw, u16 data)
+s32 e1000_null_set_page(struct e1000_hw E1000_UNUSEDARG *hw,
+ u16 E1000_UNUSEDARG data)
{
DEBUGFUNC("e1000_null_set_page");
return E1000_SUCCESS;
@@ -114,7 +115,8 @@ s32 e1000_null_set_page(struct e1000_hw *hw, u16 data)
* e1000_null_read_reg - No-op function, return 0
* @hw: pointer to the HW structure
**/
-s32 e1000_null_read_reg(struct e1000_hw *hw, u32 offset, u16 *data)
+s32 e1000_null_read_reg(struct e1000_hw E1000_UNUSEDARG *hw,
+ u32 E1000_UNUSEDARG offset, u16 E1000_UNUSEDARG *data)
{
DEBUGFUNC("e1000_null_read_reg");
return E1000_SUCCESS;
@@ -124,7 +126,7 @@ s32 e1000_null_read_reg(struct e1000_hw *hw, u32 offset, u16 *data)
* e1000_null_phy_generic - No-op function, return void
* @hw: pointer to the HW structure
**/
-void e1000_null_phy_generic(struct e1000_hw *hw)
+void e1000_null_phy_generic(struct e1000_hw E1000_UNUSEDARG *hw)
{
DEBUGFUNC("e1000_null_phy_generic");
return;
@@ -134,7 +136,8 @@ void e1000_null_phy_generic(struct e1000_hw *hw)
* e1000_null_lplu_state - No-op function, return 0
* @hw: pointer to the HW structure
**/
-s32 e1000_null_lplu_state(struct e1000_hw *hw, bool active)
+s32 e1000_null_lplu_state(struct e1000_hw E1000_UNUSEDARG *hw,
+ bool E1000_UNUSEDARG active)
{
DEBUGFUNC("e1000_null_lplu_state");
return E1000_SUCCESS;
@@ -144,7 +147,8 @@ s32 e1000_null_lplu_state(struct e1000_hw *hw, bool active)
* e1000_null_write_reg - No-op function, return 0
* @hw: pointer to the HW structure
**/
-s32 e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data)
+s32 e1000_null_write_reg(struct e1000_hw E1000_UNUSEDARG *hw,
+ u32 E1000_UNUSEDARG offset, u16 E1000_UNUSEDARG data)
{
DEBUGFUNC("e1000_null_write_reg");
return E1000_SUCCESS;
@@ -158,8 +162,10 @@ s32 e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data)
* @data: data value read
*
**/
-s32 e1000_read_i2c_byte_null(struct e1000_hw *hw, u8 byte_offset,
- u8 dev_addr, u8 *data)
+s32 e1000_read_i2c_byte_null(struct e1000_hw E1000_UNUSEDARG *hw,
+ u8 E1000_UNUSEDARG byte_offset,
+ u8 E1000_UNUSEDARG dev_addr,
+ u8 E1000_UNUSEDARG *data)
{
DEBUGFUNC("e1000_read_i2c_byte_null");
return E1000_SUCCESS;
@@ -173,10 +179,10 @@ s32 e1000_read_i2c_byte_null(struct e1000_hw *hw, u8 byte_offset,
* @data: data value to write
*
**/
-s32 e1000_write_i2c_byte_null(struct e1000_hw *hw,
- u8 byte_offset,
- u8 dev_addr,
- u8 data)
+s32 e1000_write_i2c_byte_null(struct e1000_hw E1000_UNUSEDARG *hw,
+ u8 E1000_UNUSEDARG byte_offset,
+ u8 E1000_UNUSEDARG dev_addr,
+ u8 E1000_UNUSEDARG data)
{
DEBUGFUNC("e1000_write_i2c_byte_null");
return E1000_SUCCESS;
@@ -302,7 +308,7 @@ s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
* the lower time out
*/
for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
- usec_delay(50);
+ usec_delay_irq(50);
mdic = E1000_READ_REG(hw, E1000_MDIC);
if (mdic & E1000_MDIC_READY)
break;
@@ -327,7 +333,7 @@ s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
* reading duplicate data in the next MDIC transaction.
*/
if (hw->mac.type == e1000_pch2lan)
- usec_delay(100);
+ usec_delay_irq(100);
return E1000_SUCCESS;
}
@@ -368,7 +374,7 @@ s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
* the lower time out
*/
for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
- usec_delay(50);
+ usec_delay_irq(50);
mdic = E1000_READ_REG(hw, E1000_MDIC);
if (mdic & E1000_MDIC_READY)
break;
@@ -392,7 +398,7 @@ s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
* reading duplicate data in the next MDIC transaction.
*/
if (hw->mac.type == e1000_pch2lan)
- usec_delay(100);
+ usec_delay_irq(100);
return E1000_SUCCESS;
}
@@ -1054,16 +1060,12 @@ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw)
}
}
- /* Enable CRS on Tx. This must be set for half-duplex operation.
- * Not required on some PHYs.
- */
+ /* Enable CRS on Tx. This must be set for half-duplex operation. */
ret_val = hw->phy.ops.read_reg(hw, I82577_CFG_REG, &phy_data);
if (ret_val)
return ret_val;
- if ((hw->phy.type != e1000_phy_82579) &&
- (hw->phy.type != e1000_phy_i217))
- phy_data |= I82577_CFG_ASSERT_CRS_ON_TX;
+ phy_data |= I82577_CFG_ASSERT_CRS_ON_TX;
/* Enable downshift */
phy_data |= I82577_CFG_ENABLE_DOWNSHIFT;
@@ -1249,12 +1251,6 @@ s32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
return ret_val;
}
- if (phy->type == e1000_phy_i210) {
- ret_val = e1000_set_master_slave_mode(hw);
- if (ret_val)
- return ret_val;
- }
-
return E1000_SUCCESS;
}
@@ -1318,6 +1314,20 @@ s32 e1000_copper_link_setup_m88_gen2(struct e1000_hw *hw)
phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
/* Enable downshift and setting it to X6 */
+ if (phy->id == M88E1543_E_PHY_ID) {
+ phy_data &= ~I347AT4_PSCR_DOWNSHIFT_ENABLE;
+ ret_val =
+ phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = phy->ops.commit(hw);
+ if (ret_val) {
+ DEBUGOUT("Error committing the PHY changes\n");
+ return ret_val;
+ }
+ }
+
phy_data &= ~I347AT4_PSCR_DOWNSHIFT_MASK;
phy_data |= I347AT4_PSCR_DOWNSHIFT_6X;
phy_data |= I347AT4_PSCR_DOWNSHIFT_ENABLE;
@@ -1333,6 +1343,10 @@ s32 e1000_copper_link_setup_m88_gen2(struct e1000_hw *hw)
return ret_val;
}
+ ret_val = e1000_set_master_slave_mode(hw);
+ if (ret_val)
+ return ret_val;
+
return E1000_SUCCESS;
}
@@ -1847,6 +1861,8 @@ s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
case I347AT4_E_PHY_ID:
case M88E1340M_E_PHY_ID:
case M88E1112_E_PHY_ID:
+ case M88E1543_E_PHY_ID:
+ case M88E1512_E_PHY_ID:
case I210_I_PHY_ID:
reset_dsp = FALSE;
break;
@@ -1889,6 +1905,9 @@ s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
return E1000_SUCCESS;
if (hw->phy.id == I210_I_PHY_ID)
return E1000_SUCCESS;
+ if ((hw->phy.id == M88E1543_E_PHY_ID) ||
+ (hw->phy.id == M88E1512_E_PHY_ID))
+ return E1000_SUCCESS;
ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
if (ret_val)
return ret_val;
@@ -2194,9 +2213,9 @@ s32 e1000_check_polarity_m88(struct e1000_hw *hw)
ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
if (!ret_val)
- phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
- ? e1000_rev_polarity_reversed
- : e1000_rev_polarity_normal;
+ phy->cable_polarity = ((data & M88E1000_PSSR_REV_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal);
return ret_val;
}
@@ -2240,9 +2259,9 @@ s32 e1000_check_polarity_igp(struct e1000_hw *hw)
ret_val = phy->ops.read_reg(hw, offset, &data);
if (!ret_val)
- phy->cable_polarity = (data & mask)
- ? e1000_rev_polarity_reversed
- : e1000_rev_polarity_normal;
+ phy->cable_polarity = ((data & mask)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal);
return ret_val;
}
@@ -2274,9 +2293,9 @@ s32 e1000_check_polarity_ife(struct e1000_hw *hw)
ret_val = phy->ops.read_reg(hw, offset, &phy_data);
if (!ret_val)
- phy->cable_polarity = (phy_data & mask)
+ phy->cable_polarity = ((phy_data & mask)
? e1000_rev_polarity_reversed
- : e1000_rev_polarity_normal;
+ : e1000_rev_polarity_normal);
return ret_val;
}
@@ -2392,8 +2411,8 @@ s32 e1000_get_cable_length_m88(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
- M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+ index = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT);
if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1)
return -E1000_ERR_PHY;
@@ -2437,6 +2456,8 @@ s32 e1000_get_cable_length_m88_gen2(struct e1000_hw *hw)
phy->max_cable_length = phy_data / (is_cm ? 100 : 1);
phy->cable_length = phy_data / (is_cm ? 100 : 1);
break;
+ case M88E1543_E_PHY_ID:
+ case M88E1512_E_PHY_ID:
case M88E1340M_E_PHY_ID:
case I347AT4_E_PHY_ID:
/* Remember the original page select and set it to 7 */
@@ -2554,8 +2575,8 @@ s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
* that can be put into the lookup table to obtain the
* approximate cable length.
*/
- cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
- IGP02E1000_AGC_LENGTH_MASK;
+ cur_agc_index = ((phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+ IGP02E1000_AGC_LENGTH_MASK);
/* Array index bound check. */
if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
@@ -2578,8 +2599,8 @@ s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
/* Calculate cable length with the error range of +/- 10 meters. */
- phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
- (agc_value - IGP02E1000_AGC_RANGE) : 0;
+ phy->min_cable_length = (((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+ (agc_value - IGP02E1000_AGC_RANGE) : 0);
phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
@@ -2763,9 +2784,9 @@ s32 e1000_get_phy_info_ife(struct e1000_hw *hw)
return ret_val;
} else {
/* Polarity is forced */
- phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
- ? e1000_rev_polarity_reversed
- : e1000_rev_polarity_normal;
+ phy->cable_polarity = ((data & IFE_PSC_FORCE_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal);
}
ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
@@ -2863,7 +2884,7 @@ s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw)
* Generic function to wait 10 milli-seconds for configuration to complete
* and return success.
**/
-s32 e1000_get_cfg_done_generic(struct e1000_hw *hw)
+s32 e1000_get_cfg_done_generic(struct e1000_hw E1000_UNUSEDARG *hw)
{
DEBUGFUNC("e1000_get_cfg_done_generic");
@@ -2970,6 +2991,8 @@ enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id)
case M88E1000_E_PHY_ID:
case M88E1111_I_PHY_ID:
case M88E1011_I_PHY_ID:
+ case M88E1543_E_PHY_ID:
+ case M88E1512_E_PHY_ID:
case I347AT4_E_PHY_ID:
case M88E1112_E_PHY_ID:
case M88E1340M_E_PHY_ID:
@@ -3776,8 +3799,8 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
DEBUGFUNC("e1000_access_phy_debug_regs_hv");
/* This takes care of the difference with desktop vs mobile phy */
- addr_reg = (hw->phy.type == e1000_phy_82578) ?
- I82578_ADDR_REG : I82577_ADDR_REG;
+ addr_reg = ((hw->phy.type == e1000_phy_82578) ?
+ I82578_ADDR_REG : I82577_ADDR_REG);
data_reg = addr_reg + 1;
/* All operations in this function are phy address 2 */
@@ -3833,8 +3856,8 @@ s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- data &= BM_CS_STATUS_LINK_UP | BM_CS_STATUS_RESOLVED |
- BM_CS_STATUS_SPEED_MASK;
+ data &= (BM_CS_STATUS_LINK_UP | BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_MASK);
if (data != (BM_CS_STATUS_LINK_UP | BM_CS_STATUS_RESOLVED |
BM_CS_STATUS_SPEED_1000))
@@ -3872,9 +3895,9 @@ s32 e1000_check_polarity_82577(struct e1000_hw *hw)
ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
if (!ret_val)
- phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY)
- ? e1000_rev_polarity_reversed
- : e1000_rev_polarity_normal;
+ phy->cable_polarity = ((data & I82577_PHY_STATUS2_REV_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal);
return ret_val;
}
@@ -4009,8 +4032,8 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
- I82577_DSTATUS_CABLE_LENGTH_SHIFT;
+ length = ((phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
+ I82577_DSTATUS_CABLE_LENGTH_SHIFT);
if (length == E1000_CABLE_LENGTH_UNDEFINED)
return -E1000_ERR_PHY;
@@ -4083,3 +4106,157 @@ release:
return ret_val;
}
+/**
+ * e1000_read_phy_reg_mphy - Read mPHY control register
+ * @hw: pointer to the HW structure
+ * @address: address to be read
+ * @data: pointer to the read data
+ *
+ * Reads the mPHY control register in the PHY at offset and stores the
+ * information read to data.
+ **/
+s32 e1000_read_phy_reg_mphy(struct e1000_hw *hw, u32 address, u32 *data)
+{
+ u32 mphy_ctrl = 0;
+ bool locked = FALSE;
+ bool ready = FALSE;
+
+ DEBUGFUNC("e1000_read_phy_reg_mphy");
+
+ /* Check if mPHY is ready to read/write operations */
+ ready = e1000_is_mphy_ready(hw);
+ if (!ready)
+ return -E1000_ERR_PHY;
+
+ /* Check if mPHY access is disabled and enable it if so */
+ mphy_ctrl = E1000_READ_REG(hw, E1000_MPHY_ADDR_CTRL);
+ if (mphy_ctrl & E1000_MPHY_DIS_ACCESS) {
+ locked = TRUE;
+ ready = e1000_is_mphy_ready(hw);
+ if (!ready)
+ return -E1000_ERR_PHY;
+ mphy_ctrl |= E1000_MPHY_ENA_ACCESS;
+ E1000_WRITE_REG(hw, E1000_MPHY_ADDR_CTRL, mphy_ctrl);
+ }
+
+ /* Set the address that we want to read */
+ ready = e1000_is_mphy_ready(hw);
+ if (!ready)
+ return -E1000_ERR_PHY;
+
+ /* We mask address, because we want to use only current lane */
+ mphy_ctrl = (mphy_ctrl & ~E1000_MPHY_ADDRESS_MASK &
+ ~E1000_MPHY_ADDRESS_FNC_OVERRIDE) |
+ (address & E1000_MPHY_ADDRESS_MASK);
+ E1000_WRITE_REG(hw, E1000_MPHY_ADDR_CTRL, mphy_ctrl);
+
+ /* Read data from the address */
+ ready = e1000_is_mphy_ready(hw);
+ if (!ready)
+ return -E1000_ERR_PHY;
+ *data = E1000_READ_REG(hw, E1000_MPHY_DATA);
+
+ /* Disable access to mPHY if it was originally disabled */
+ if (locked)
+ ready = e1000_is_mphy_ready(hw);
+ if (!ready)
+ return -E1000_ERR_PHY;
+ E1000_WRITE_REG(hw, E1000_MPHY_ADDR_CTRL,
+ E1000_MPHY_DIS_ACCESS);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_write_phy_reg_mphy - Write mPHY control register
+ * @hw: pointer to the HW structure
+ * @address: address to write to
+ * @data: data to write to register at offset
+ * @line_override: used when we want to use different line than default one
+ *
+ * Writes data to mPHY control register.
+ **/
+s32 e1000_write_phy_reg_mphy(struct e1000_hw *hw, u32 address, u32 data,
+ bool line_override)
+{
+ u32 mphy_ctrl = 0;
+ bool locked = FALSE;
+ bool ready = FALSE;
+
+ DEBUGFUNC("e1000_write_phy_reg_mphy");
+
+ /* Check if mPHY is ready to read/write operations */
+ ready = e1000_is_mphy_ready(hw);
+ if (!ready)
+ return -E1000_ERR_PHY;
+
+ /* Check if mPHY access is disabled and enable it if so */
+ mphy_ctrl = E1000_READ_REG(hw, E1000_MPHY_ADDR_CTRL);
+ if (mphy_ctrl & E1000_MPHY_DIS_ACCESS) {
+ locked = TRUE;
+ ready = e1000_is_mphy_ready(hw);
+ if (!ready)
+ return -E1000_ERR_PHY;
+ mphy_ctrl |= E1000_MPHY_ENA_ACCESS;
+ E1000_WRITE_REG(hw, E1000_MPHY_ADDR_CTRL, mphy_ctrl);
+ }
+
+ /* Set the address that we want to read */
+ ready = e1000_is_mphy_ready(hw);
+ if (!ready)
+ return -E1000_ERR_PHY;
+
+ /* We mask address, because we want to use only current lane */
+ if (line_override)
+ mphy_ctrl |= E1000_MPHY_ADDRESS_FNC_OVERRIDE;
+ else
+ mphy_ctrl &= ~E1000_MPHY_ADDRESS_FNC_OVERRIDE;
+ mphy_ctrl = (mphy_ctrl & ~E1000_MPHY_ADDRESS_MASK) |
+ (address & E1000_MPHY_ADDRESS_MASK);
+ E1000_WRITE_REG(hw, E1000_MPHY_ADDR_CTRL, mphy_ctrl);
+
+ /* Read data from the address */
+ ready = e1000_is_mphy_ready(hw);
+ if (!ready)
+ return -E1000_ERR_PHY;
+ E1000_WRITE_REG(hw, E1000_MPHY_DATA, data);
+
+ /* Disable access to mPHY if it was originally disabled */
+ if (locked)
+ ready = e1000_is_mphy_ready(hw);
+ if (!ready)
+ return -E1000_ERR_PHY;
+ E1000_WRITE_REG(hw, E1000_MPHY_ADDR_CTRL,
+ E1000_MPHY_DIS_ACCESS);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_is_mphy_ready - Check if mPHY control register is not busy
+ * @hw: pointer to the HW structure
+ *
+ * Returns mPHY control register status.
+ **/
+bool e1000_is_mphy_ready(struct e1000_hw *hw)
+{
+ u16 retry_count = 0;
+ u32 mphy_ctrl = 0;
+ bool ready = FALSE;
+
+ while (retry_count < 2) {
+ mphy_ctrl = E1000_READ_REG(hw, E1000_MPHY_ADDR_CTRL);
+ if (mphy_ctrl & E1000_MPHY_BUSY) {
+ usec_delay(20);
+ retry_count++;
+ continue;
+ }
+ ready = TRUE;
+ break;
+ }
+
+ if (!ready)
+ DEBUGOUT("ERROR READING mPHY control register, phy is busy.\n");
+
+ return ready;
+}
diff --git a/sys/dev/e1000/e1000_phy.h b/sys/dev/e1000/e1000_phy.h
index 9911df77..32685ee 100644
--- a/sys/dev/e1000/e1000_phy.h
+++ b/sys/dev/e1000/e1000_phy.h
@@ -116,6 +116,10 @@ s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw);
s32 e1000_get_cable_length_82577(struct e1000_hw *hw);
s32 e1000_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data);
s32 e1000_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_read_phy_reg_mphy(struct e1000_hw *hw, u32 address, u32 *data);
+s32 e1000_write_phy_reg_mphy(struct e1000_hw *hw, u32 address, u32 data,
+ bool line_override);
+bool e1000_is_mphy_ready(struct e1000_hw *hw);
#define E1000_MAX_PHY_ADDR 8
@@ -170,7 +174,7 @@ s32 e1000_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data);
#define I82577_ADDR_REG 16
#define I82577_CFG_REG 22
#define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15)
-#define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */
+#define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift */
#define I82577_CTRL_REG 23
/* 82577 specific PHY registers */
@@ -201,6 +205,12 @@ s32 e1000_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data);
#define E1000_82580_PM_D3_LPLU 0x0004 /* For all other states */
#define E1000_82580_PM_GO_LINKD 0x0020 /* Go Link Disconnect */
+#define E1000_MPHY_DIS_ACCESS 0x80000000 /* disable_access bit */
+#define E1000_MPHY_ENA_ACCESS 0x40000000 /* enable_access bit */
+#define E1000_MPHY_BUSY 0x00010000 /* busy bit */
+#define E1000_MPHY_ADDRESS_FNC_OVERRIDE 0x20000000 /* fnc_override bit */
+#define E1000_MPHY_ADDRESS_MASK 0x0000FFFF /* address mask */
+
/* BM PHY Copper Specific Control 1 */
#define BM_CS_CTRL1 16
@@ -247,7 +257,7 @@ s32 e1000_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data);
#define IGP02E1000_PHY_AGC_C 0x14B1
#define IGP02E1000_PHY_AGC_D 0x18B1
-#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course=15:13, Fine=12:9 */
#define IGP02E1000_AGC_LENGTH_MASK 0x7F
#define IGP02E1000_AGC_RANGE 15
@@ -267,8 +277,8 @@ s32 e1000_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data);
#define E1000_KMRNCTRLSTA_HD_CTRL 0x10 /* Kumeran HD Control */
#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
-#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */
-#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
+#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Ctrl */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Ctrl */
#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */
/* IFE PHY Extended Status Control */
diff --git a/sys/dev/e1000/e1000_regs.h b/sys/dev/e1000/e1000_regs.h
index 516d377..f2b37db 100644
--- a/sys/dev/e1000/e1000_regs.h
+++ b/sys/dev/e1000/e1000_regs.h
@@ -50,6 +50,10 @@
#define E1000_BARCTRL 0x5BBC /* BAR ctrl reg */
#define E1000_BARCTRL_FLSIZE 0x0700 /* BAR ctrl Flsize */
#define E1000_BARCTRL_CSRSIZE 0x2000 /* BAR ctrl CSR size */
+#define E1000_MPHY_ADDR_CTRL 0x0024 /* GbE MPHY Address Control */
+#define E1000_MPHY_DATA 0x0E10 /* GBE MPHY Data */
+#define E1000_MPHY_STAT 0x0E0C /* GBE MPHY Statistics */
+#define E1000_PPHY_CTRL 0x5b48 /* PCIe PHY Control */
#define E1000_I350_BARCTRL 0x5BFC /* BAR ctrl reg */
#define E1000_I350_DTXMXPKTSZ 0x355C /* Maximum sent packet size reg*/
#define E1000_SCTL 0x00024 /* SerDes Control - RW */
@@ -94,6 +98,7 @@
#define E1000_TBT 0x00448 /* Tx Burst Timer - RW */
#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
+#define E1000_LEDMUX 0x08130 /* LED MUX Control */
#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */
@@ -152,6 +157,8 @@
#define E1000_PBRWAC 0x024E8 /* Rx packet buffer wrap around counter - RO */
#define E1000_RDTR 0x02820 /* Rx Delay Timer - RW */
#define E1000_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */
+#define E1000_EMIADD 0x10 /* Extended Memory Indirect Address */
+#define E1000_EMIDATA 0x11 /* Extended Memory Indirect Data */
#define E1000_SRWR 0x12018 /* Shadow Ram Write Register - RW */
#define E1000_I210_FLMNGCTL 0x12038
#define E1000_I210_FLMNGDATA 0x1203C
@@ -208,6 +215,9 @@
/* Queues packet buffer size masks where _n can be 0-3 and _s 0-63 [kB] */
#define E1000_I210_TXPBS_SIZE(_n, _s) ((_s) << (6 * _n))
+#define E1000_MMDAC 13 /* MMD Access Control */
+#define E1000_MMDAAD 14 /* MMD Access Address/Data */
+
/* Convenience macros
*
* Note: "_n" is the queue number of the register to be written to.
@@ -484,8 +494,6 @@
#define E1000_PBACL 0x05B68 /* MSIx PBA Clear - Read/Write 1's to clear */
#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */
#define E1000_HOST_IF 0x08800 /* Host Interface */
-#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */
-#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */
#define E1000_HIBBA 0x8F40 /* Host Interface Buffer Base Address */
/* Flexible Host Filter Table */
#define E1000_FHFT(_n) (0x09000 + ((_n) * 0x100))
diff --git a/sys/dev/e1000/e1000_vf.h b/sys/dev/e1000/e1000_vf.h
index 0ee73ae..4dfebe7 100644
--- a/sys/dev/e1000/e1000_vf.h
+++ b/sys/dev/e1000/e1000_vf.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2010, Intel Corporation
+ Copyright (c) 2001-2013, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -41,48 +41,50 @@
struct e1000_hw;
-#define E1000_DEV_ID_82576_VF 0x10CA
-#define E1000_DEV_ID_I350_VF 0x1520
+#define E1000_DEV_ID_82576_VF 0x10CA
+#define E1000_DEV_ID_I350_VF 0x1520
-#define E1000_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */
+#define E1000_VF_INIT_TIMEOUT 200 /* Num of retries to clear RSTI */
/* Additional Descriptor Control definitions */
-#define E1000_TXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */
-#define E1000_RXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Rx Queue */
+#define E1000_TXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Tx Queue */
+#define E1000_RXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Rx Queue */
/* SRRCTL bit definitions */
-#define E1000_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */
-#define E1000_SRRCTL_BSIZEHDRSIZE_MASK 0x00000F00
-#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */
-#define E1000_SRRCTL_DESCTYPE_LEGACY 0x00000000
-#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
-#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000
-#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
-#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION 0x06000000
+#define E1000_SRRCTL(_n) ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \
+ (0x0C00C + ((_n) * 0x40)))
+#define E1000_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */
+#define E1000_SRRCTL_BSIZEHDRSIZE_MASK 0x00000F00
+#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */
+#define E1000_SRRCTL_DESCTYPE_LEGACY 0x00000000
+#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
+#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION 0x06000000
#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
-#define E1000_SRRCTL_DESCTYPE_MASK 0x0E000000
-#define E1000_SRRCTL_DROP_EN 0x80000000
+#define E1000_SRRCTL_DESCTYPE_MASK 0x0E000000
+#define E1000_SRRCTL_DROP_EN 0x80000000
-#define E1000_SRRCTL_BSIZEPKT_MASK 0x0000007F
-#define E1000_SRRCTL_BSIZEHDR_MASK 0x00003F00
+#define E1000_SRRCTL_BSIZEPKT_MASK 0x0000007F
+#define E1000_SRRCTL_BSIZEHDR_MASK 0x00003F00
/* Interrupt Defines */
-#define E1000_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */
-#define E1000_EITR(_n) (0x01680 + ((_n) << 2))
-#define E1000_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */
-#define E1000_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */
-#define E1000_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */
-#define E1000_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */
-#define E1000_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */
-#define E1000_IVAR0 0x01700 /* Interrupt Vector Allocation (array) - RW */
-#define E1000_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
-#define E1000_IVAR_VALID 0x80
+#define E1000_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */
+#define E1000_EITR(_n) (0x01680 + ((_n) << 2))
+#define E1000_EICS 0x01520 /* Ext. Intr Cause Set -W0 */
+#define E1000_EIMS 0x01524 /* Ext. Intr Mask Set/Read -RW */
+#define E1000_EIMC 0x01528 /* Ext. Intr Mask Clear -WO */
+#define E1000_EIAC 0x0152C /* Ext. Intr Auto Clear -RW */
+#define E1000_EIAM 0x01530 /* Ext. Intr Ack Auto Clear Mask -RW */
+#define E1000_IVAR0 0x01700 /* Intr Vector Alloc (array) -RW */
+#define E1000_IVAR_MISC 0x01740 /* IVAR for "other" causes -RW */
+#define E1000_IVAR_VALID 0x80
/* Receive Descriptor - Advanced */
union e1000_adv_rx_desc {
struct {
- u64 pkt_addr; /* Packet buffer address */
- u64 hdr_addr; /* Header buffer address */
+ u64 pkt_addr; /* Packet buffer address */
+ u64 hdr_addr; /* Header buffer address */
} read;
struct {
struct {
@@ -96,23 +98,23 @@ union e1000_adv_rx_desc {
} hs_rss;
} lo_dword;
union {
- u32 rss; /* RSS Hash */
+ u32 rss; /* RSS Hash */
struct {
- u16 ip_id; /* IP id */
- u16 csum; /* Packet Checksum */
+ u16 ip_id; /* IP id */
+ u16 csum; /* Packet Checksum */
} csum_ip;
} hi_dword;
} lower;
struct {
- u32 status_error; /* ext status/error */
- u16 length; /* Packet length */
- u16 vlan; /* VLAN tag */
+ u32 status_error; /* ext status/error */
+ u16 length; /* Packet length */
+ u16 vlan; /* VLAN tag */
} upper;
} wb; /* writeback */
};
-#define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0
-#define E1000_RXDADV_HDRBUFLEN_SHIFT 5
+#define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0
+#define E1000_RXDADV_HDRBUFLEN_SHIFT 5
/* Transmit Descriptor - Advanced */
union e1000_adv_tx_desc {
@@ -129,15 +131,15 @@ union e1000_adv_tx_desc {
};
/* Adv Transmit Descriptor Config Masks */
-#define E1000_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
-#define E1000_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
-#define E1000_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
-#define E1000_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_ADVTXD_DCMD_RS 0x08000000 /* Report Status */
-#define E1000_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */
-#define E1000_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */
-#define E1000_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
-#define E1000_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
+#define E1000_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
+#define E1000_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
+#define E1000_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
+#define E1000_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_ADVTXD_DCMD_RS 0x08000000 /* Report Status */
+#define E1000_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */
+#define E1000_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */
+#define E1000_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
+#define E1000_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
/* Context descriptors */
struct e1000_adv_tx_context_desc {
@@ -147,11 +149,11 @@ struct e1000_adv_tx_context_desc {
u32 mss_l4len_idx;
};
-#define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
-#define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */
-#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
-#define E1000_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
-#define E1000_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
+#define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
+#define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */
+#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
+#define E1000_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
+#define E1000_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
enum e1000_mac_type {
e1000_undefined = 0,
diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c
index 600c2de..07a9d3e 100644
--- a/sys/dev/e1000/if_igb.c
+++ b/sys/dev/e1000/if_igb.c
@@ -101,7 +101,7 @@ int igb_display_debug_stats = 0;
/*********************************************************************
* Driver version:
*********************************************************************/
-char igb_driver_version[] = "version - 2.3.10";
+char igb_driver_version[] = "version - 2.4.0";
/*********************************************************************
@@ -155,10 +155,19 @@ static igb_vendor_info_t igb_vendor_info_array[] =
{ 0x8086, E1000_DEV_ID_I210_COPPER_IT, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_I210_COPPER_OEM1,
PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_I210_COPPER_FLASHLESS,
+ PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_I210_SERDES_FLASHLESS,
+ PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_I210_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_I210_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_I210_SGMII, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_I211_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_I354_BACKPLANE_1GBPS,
+ PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_I354_BACKPLANE_2_5GBPS,
+ PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_I354_SGMII, PCI_ANY_ID, PCI_ANY_ID, 0},
/* required last entry */
{ 0, 0, 0, 0, 0}
};
@@ -233,9 +242,10 @@ static __inline void igb_rx_input(struct rx_ring *,
static bool igb_rxeof(struct igb_queue *, int, int *);
static void igb_rx_checksum(u32, struct mbuf *, u32);
-static bool igb_tx_ctx_setup(struct tx_ring *, struct mbuf *);
-static bool igb_tso_setup(struct tx_ring *, struct mbuf *, int,
- struct ip *, struct tcphdr *);
+static int igb_tx_ctx_setup(struct tx_ring *,
+ struct mbuf *, u32 *, u32 *);
+static int igb_tso_setup(struct tx_ring *,
+ struct mbuf *, u32 *, u32 *);
static void igb_set_promisc(struct adapter *);
static void igb_disable_promisc(struct adapter *);
static void igb_set_multi(struct adapter *);
@@ -351,7 +361,7 @@ TUNABLE_INT("hw.igb.max_interrupt_rate", &igb_max_interrupt_rate);
SYSCTL_INT(_hw_igb, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN,
&igb_max_interrupt_rate, 0, "Maximum interrupts per second");
-#if __FreeBSD_version >= 800000
+#ifndef IGB_LEGACY_TX
/*
** Tuneable number of buffers in the buf-ring (drbr_xxx)
*/
@@ -557,7 +567,6 @@ igb_attach(device_t dev)
* standard ethernet sized frames.
*/
adapter->max_frame_size = ETHERMTU + ETHER_HDR_LEN + ETHERNET_FCS_SIZE;
- adapter->min_frame_size = ETH_ZLEN + ETHERNET_FCS_SIZE;
/*
** Allocate and Setup Queues
@@ -603,8 +612,12 @@ igb_attach(device_t dev)
OID_AUTO, "eee_disabled", CTLTYPE_INT|CTLFLAG_RW,
adapter, 0, igb_sysctl_eee, "I",
"Disable Energy Efficient Ethernet");
- if (adapter->hw.phy.media_type == e1000_media_type_copper)
- e1000_set_eee_i350(&adapter->hw);
+ if (adapter->hw.phy.media_type == e1000_media_type_copper) {
+ if (adapter->hw.mac.type == e1000_i354)
+ e1000_set_eee_i354(&adapter->hw);
+ else
+ e1000_set_eee_i350(&adapter->hw);
+ }
}
/*
@@ -988,7 +1001,7 @@ igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr)
{
struct adapter *adapter = txr->adapter;
struct mbuf *next;
- int err = 0, enq;
+ int err = 0, enq = 0;
IGB_TX_LOCK_ASSERT(txr);
@@ -996,7 +1009,6 @@ igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr)
adapter->link_active == 0)
return (ENETDOWN);
- enq = 0;
/* Process the queue */
while ((next = drbr_peek(ifp, txr->br)) != NULL) {
@@ -1224,6 +1236,10 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
ifp->if_capenable ^= IFCAP_TSO4;
reinit = 1;
}
+ if (mask & IFCAP_TSO6) {
+ ifp->if_capenable ^= IFCAP_TSO6;
+ reinit = 1;
+ }
if (mask & IFCAP_VLAN_HWTAGGING) {
ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
reinit = 1;
@@ -1301,7 +1317,7 @@ igb_init_locked(struct adapter *adapter)
#endif
}
- if (ifp->if_capenable & IFCAP_TSO4)
+ if (ifp->if_capenable & IFCAP_TSO)
ifp->if_hwassist |= CSUM_TSO;
/* Configure for OS presence */
@@ -1365,8 +1381,12 @@ igb_init_locked(struct adapter *adapter)
}
/* Set Energy Efficient Ethernet */
- if (adapter->hw.phy.media_type == e1000_media_type_copper)
- e1000_set_eee_i350(&adapter->hw);
+ if (adapter->hw.phy.media_type == e1000_media_type_copper) {
+ if (adapter->hw.mac.type == e1000_i354)
+ e1000_set_eee_i354(&adapter->hw);
+ else
+ e1000_set_eee_i350(&adapter->hw);
+ }
}
static void
@@ -1734,6 +1754,9 @@ igb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
case 1000:
ifmr->ifm_active |= IFM_1000_T;
break;
+ case 2500:
+ ifmr->ifm_active |= IFM_2500_SX;
+ break;
}
if (adapter->link_duplex == FULL_DUPLEX)
@@ -1810,273 +1833,142 @@ igb_media_change(struct ifnet *ifp)
static int
igb_xmit(struct tx_ring *txr, struct mbuf **m_headp)
{
- struct adapter *adapter = txr->adapter;
- bus_dma_segment_t segs[IGB_MAX_SCATTER];
- bus_dmamap_t map;
- struct igb_tx_buffer *tx_buffer, *tx_buffer_mapped;
- union e1000_adv_tx_desc *txd = NULL;
- struct mbuf *m_head = *m_headp;
- struct ether_vlan_header *eh = NULL;
- struct ip *ip = NULL;
- struct tcphdr *th = NULL;
- u32 hdrlen, cmd_type_len, olinfo_status = 0;
- int ehdrlen, poff;
- int nsegs, i, first, last = 0;
- int error, do_tso, remap = 1;
-
- /* Set basic descriptor constants */
- cmd_type_len = E1000_ADVTXD_DTYP_DATA;
- cmd_type_len |= E1000_ADVTXD_DCMD_IFCS | E1000_ADVTXD_DCMD_DEXT;
- if (m_head->m_flags & M_VLANTAG)
- cmd_type_len |= E1000_ADVTXD_DCMD_VLE;
+ struct adapter *adapter = txr->adapter;
+ u32 olinfo_status = 0, cmd_type_len;
+ int i, j, error, nsegs;
+ int first;
+ bool remap = TRUE;
+ struct mbuf *m_head;
+ bus_dma_segment_t segs[IGB_MAX_SCATTER];
+ bus_dmamap_t map;
+ struct igb_tx_buf *txbuf;
+ union e1000_adv_tx_desc *txd = NULL;
-retry:
m_head = *m_headp;
- do_tso = ((m_head->m_pkthdr.csum_flags & CSUM_TSO) != 0);
- hdrlen = ehdrlen = poff = 0;
- /*
- * Intel recommends entire IP/TCP header length reside in a single
- * buffer. If multiple descriptors are used to describe the IP and
- * TCP header, each descriptor should describe one or more
- * complete headers; descriptors referencing only parts of headers
- * are not supported. If all layer headers are not coalesced into
- * a single buffer, each buffer should not cross a 4KB boundary,
- * or be larger than the maximum read request size.
- * Controller also requires modifing IP/TCP header to make TSO work
- * so we firstly get a writable mbuf chain then coalesce ethernet/
- * IP/TCP header into a single buffer to meet the requirement of
- * controller. This also simplifies IP/TCP/UDP checksum offloading
- * which also has similiar restrictions.
- */
- if (do_tso || m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) {
- if (do_tso || (m_head->m_next != NULL &&
- m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD)) {
- if (M_WRITABLE(*m_headp) == 0) {
- m_head = m_dup(*m_headp, M_NOWAIT);
- m_freem(*m_headp);
- if (m_head == NULL) {
- *m_headp = NULL;
- return (ENOBUFS);
- }
- *m_headp = m_head;
- }
- }
- /*
- * Assume IPv4, we don't have TSO/checksum offload support
- * for IPv6 yet.
- */
- ehdrlen = sizeof(struct ether_header);
- m_head = m_pullup(m_head, ehdrlen);
- if (m_head == NULL) {
- *m_headp = NULL;
- return (ENOBUFS);
- }
- eh = mtod(m_head, struct ether_vlan_header *);
- if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
- ehdrlen = sizeof(struct ether_vlan_header);
- m_head = m_pullup(m_head, ehdrlen);
- if (m_head == NULL) {
- *m_headp = NULL;
- return (ENOBUFS);
- }
- }
- m_head = m_pullup(m_head, ehdrlen + sizeof(struct ip));
- if (m_head == NULL) {
- *m_headp = NULL;
- return (ENOBUFS);
- }
- ip = (struct ip *)(mtod(m_head, char *) + ehdrlen);
- poff = ehdrlen + (ip->ip_hl << 2);
- if (do_tso) {
- m_head = m_pullup(m_head, poff + sizeof(struct tcphdr));
- if (m_head == NULL) {
- *m_headp = NULL;
- return (ENOBUFS);
- }
- /*
- * The pseudo TCP checksum does not include TCP payload
- * length so driver should recompute the checksum here
- * what hardware expect to see. This is adherence of
- * Microsoft's Large Send specification.
- */
- th = (struct tcphdr *)(mtod(m_head, char *) + poff);
- th->th_sum = in_pseudo(ip->ip_src.s_addr,
- ip->ip_dst.s_addr, htons(IPPROTO_TCP));
- /* Keep track of the full header length */
- hdrlen = poff + (th->th_off << 2);
- } else if (m_head->m_pkthdr.csum_flags & CSUM_TCP) {
- m_head = m_pullup(m_head, poff + sizeof(struct tcphdr));
- if (m_head == NULL) {
- *m_headp = NULL;
- return (ENOBUFS);
- }
- th = (struct tcphdr *)(mtod(m_head, char *) + poff);
- m_head = m_pullup(m_head, poff + (th->th_off << 2));
- if (m_head == NULL) {
- *m_headp = NULL;
- return (ENOBUFS);
- }
- ip = (struct ip *)(mtod(m_head, char *) + ehdrlen);
- th = (struct tcphdr *)(mtod(m_head, char *) + poff);
- } else if (m_head->m_pkthdr.csum_flags & CSUM_UDP) {
- m_head = m_pullup(m_head, poff + sizeof(struct udphdr));
- if (m_head == NULL) {
- *m_headp = NULL;
- return (ENOBUFS);
- }
- ip = (struct ip *)(mtod(m_head, char *) + ehdrlen);
- }
- *m_headp = m_head;
- }
+ /* Basic descriptor defines */
+ cmd_type_len = (E1000_ADVTXD_DTYP_DATA |
+ E1000_ADVTXD_DCMD_IFCS | E1000_ADVTXD_DCMD_DEXT);
+
+ if (m_head->m_flags & M_VLANTAG)
+ cmd_type_len |= E1000_ADVTXD_DCMD_VLE;
+
+ /*
+ * Important to capture the first descriptor
+ * used because it will contain the index of
+ * the one we tell the hardware to report back
+ */
+ first = txr->next_avail_desc;
+ txbuf = &txr->tx_buffers[first];
+ map = txbuf->map;
/*
- * Map the packet for DMA
- *
- * Capture the first descriptor index,
- * this descriptor will have the index
- * of the EOP which is the only one that
- * now gets a DONE bit writeback.
+ * Map the packet for DMA.
*/
- first = txr->next_avail_desc;
- tx_buffer = &txr->tx_buffers[first];
- tx_buffer_mapped = tx_buffer;
- map = tx_buffer->map;
-
+retry:
error = bus_dmamap_load_mbuf_sg(txr->txtag, map,
*m_headp, segs, &nsegs, BUS_DMA_NOWAIT);
- /*
- * There are two types of errors we can (try) to handle:
- * - EFBIG means the mbuf chain was too long and bus_dma ran
- * out of segments. Defragment the mbuf chain and try again.
- * - ENOMEM means bus_dma could not obtain enough bounce buffers
- * at this point in time. Defer sending and try again later.
- * All other errors, in particular EINVAL, are fatal and prevent the
- * mbuf chain from ever going through. Drop it and report error.
- */
- if (error == EFBIG && remap) {
+ if (__predict_false(error)) {
struct mbuf *m;
- m = m_defrag(*m_headp, M_NOWAIT);
- if (m == NULL) {
- adapter->mbuf_defrag_failed++;
+ switch (error) {
+ case EFBIG:
+ /* Try it again? - one try */
+ if (remap == TRUE) {
+ remap = FALSE;
+ m = m_defrag(*m_headp, M_NOWAIT);
+ if (m == NULL) {
+ adapter->mbuf_defrag_failed++;
+ m_freem(*m_headp);
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ *m_headp = m;
+ goto retry;
+ } else
+ return (error);
+ case ENOMEM:
+ txr->no_tx_dma_setup++;
+ return (error);
+ default:
+ txr->no_tx_dma_setup++;
m_freem(*m_headp);
*m_headp = NULL;
- return (ENOBUFS);
+ return (error);
}
- *m_headp = m;
-
- /* Try it again, but only once */
- remap = 0;
- goto retry;
- } else if (error == ENOMEM) {
- adapter->no_tx_dma_setup++;
- return (error);
- } else if (error != 0) {
- adapter->no_tx_dma_setup++;
- m_freem(*m_headp);
- *m_headp = NULL;
- return (error);
}
- /*
- ** Make sure we don't overrun the ring,
- ** we need nsegs descriptors and one for
- ** the context descriptor used for the
- ** offloads.
- */
- if ((nsegs + 1) > (txr->tx_avail - 2)) {
- txr->no_desc_avail++;
+ /* Make certain there are enough descriptors */
+ if (nsegs > txr->tx_avail - 2) {
+ txr->no_desc_avail++;
bus_dmamap_unload(txr->txtag, map);
return (ENOBUFS);
- }
+ }
m_head = *m_headp;
- /* Do hardware assists:
- * Set up the context descriptor, used
- * when any hardware offload is done.
- * This includes CSUM, VLAN, and TSO.
- * It will use the first descriptor.
- */
-
- if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
- if (igb_tso_setup(txr, m_head, ehdrlen, ip, th)) {
- cmd_type_len |= E1000_ADVTXD_DCMD_TSE;
- olinfo_status |= E1000_TXD_POPTS_IXSM << 8;
- olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
- } else
- return (ENXIO);
- } else if (igb_tx_ctx_setup(txr, m_head))
- olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
-
- /* Calculate payload length */
- olinfo_status |= ((m_head->m_pkthdr.len - hdrlen)
- << E1000_ADVTXD_PAYLEN_SHIFT);
+ /*
+ ** Set up the appropriate offload context
+ ** this will consume the first descriptor
+ */
+ error = igb_tx_ctx_setup(txr, m_head, &cmd_type_len, &olinfo_status);
+ if (__predict_false(error)) {
+ m_freem(*m_headp);
+ *m_headp = NULL;
+ return (error);
+ }
/* 82575 needs the queue index added */
if (adapter->hw.mac.type == e1000_82575)
olinfo_status |= txr->me << 4;
- /* Set up our transmit descriptors */
i = txr->next_avail_desc;
- for (int j = 0; j < nsegs; j++) {
- bus_size_t seg_len;
- bus_addr_t seg_addr;
-
- tx_buffer = &txr->tx_buffers[i];
- txd = (union e1000_adv_tx_desc *)&txr->tx_base[i];
- seg_addr = segs[j].ds_addr;
- seg_len = segs[j].ds_len;
-
- txd->read.buffer_addr = htole64(seg_addr);
- txd->read.cmd_type_len = htole32(cmd_type_len | seg_len);
+ for (j = 0; j < nsegs; j++) {
+ bus_size_t seglen;
+ bus_addr_t segaddr;
+
+ txbuf = &txr->tx_buffers[i];
+ txd = &txr->tx_base[i];
+ seglen = segs[j].ds_len;
+ segaddr = htole64(segs[j].ds_addr);
+
+ txd->read.buffer_addr = segaddr;
+ txd->read.cmd_type_len = htole32(E1000_TXD_CMD_IFCS |
+ cmd_type_len | seglen);
txd->read.olinfo_status = htole32(olinfo_status);
- last = i;
- if (++i == adapter->num_tx_desc)
+
+ if (++i == txr->num_desc)
i = 0;
- tx_buffer->m_head = NULL;
- tx_buffer->next_eop = -1;
}
- txr->next_avail_desc = i;
+ txd->read.cmd_type_len |=
+ htole32(E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS);
txr->tx_avail -= nsegs;
- tx_buffer->m_head = m_head;
+ txr->next_avail_desc = i;
+ txbuf->m_head = m_head;
/*
** Here we swap the map so the last descriptor,
** which gets the completion interrupt has the
** real map, and the first descriptor gets the
** unused map from this descriptor.
*/
- tx_buffer_mapped->map = tx_buffer->map;
- tx_buffer->map = map;
- bus_dmamap_sync(txr->txtag, map, BUS_DMASYNC_PREWRITE);
+ txr->tx_buffers[first].map = txbuf->map;
+ txbuf->map = map;
+ bus_dmamap_sync(txr->txtag, map, BUS_DMASYNC_PREWRITE);
- /*
- * Last Descriptor of Packet
- * needs End Of Packet (EOP)
- * and Report Status (RS)
- */
- txd->read.cmd_type_len |=
- htole32(E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS);
- /*
- * Keep track in the first buffer which
- * descriptor will be written back
- */
- tx_buffer = &txr->tx_buffers[first];
- tx_buffer->next_eop = last;
- /* Update the watchdog time early and often */
- txr->watchdog_time = ticks;
+ /* Set the EOP descriptor that will be marked done */
+ txbuf = &txr->tx_buffers[first];
+ txbuf->eop = txd;
+ bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
/*
- * Advance the Transmit Descriptor Tail (TDT), this tells the E1000
- * that this frame is available to transmit.
+ * Advance the Transmit Descriptor Tail (Tdt), this tells the
+ * hardware that this frame is available to transmit.
*/
- bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
- BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ ++txr->total_packets;
E1000_WRITE_REG(&adapter->hw, E1000_TDT(txr->me), i);
- ++txr->tx_packets;
return (0);
}
@@ -2345,6 +2237,17 @@ igb_update_link_status(struct adapter *adapter)
if ((ctrl & E1000_CTRL_EXT_LINK_MODE_GMII) &&
(thstat & E1000_THSTAT_LINK_THROTTLE))
device_printf(dev, "Link: thermal downshift\n");
+ /* Delay Link Up for Phy update */
+ if (((hw->mac.type == e1000_i210) ||
+ (hw->mac.type == e1000_i211)) &&
+ (hw->phy.id == I210_I_PHY_ID))
+ msec_delay(I210_LINK_DELAY);
+ /* Reset if the media type changed. */
+ if (hw->dev_spec._82575.media_changed) {
+ hw->dev_spec._82575.media_changed = false;
+ adapter->flags |= IGB_MEDIA_RESET;
+ igb_reset(adapter);
+ }
/* This can sleep */
if_link_state_change(ifp, LINK_STATE_UP);
} else if (!link_check && (adapter->link_active == 1)) {
@@ -2477,6 +2380,7 @@ igb_allocate_legacy(struct adapter *adapter)
{
device_t dev = adapter->dev;
struct igb_queue *que = adapter->queues;
+ struct tx_ring *txr = adapter->tx_rings;
int error, rid = 0;
/* Turn off all interrupts */
@@ -2496,7 +2400,7 @@ igb_allocate_legacy(struct adapter *adapter)
}
#ifndef IGB_LEGACY_TX
- TASK_INIT(&que->txr->txq_task, 0, igb_deferred_mq_start, que->txr);
+ TASK_INIT(&txr->txq_task, 0, igb_deferred_mq_start, txr);
#endif
/*
@@ -2633,6 +2537,7 @@ igb_configure_queues(struct adapter *adapter)
switch (adapter->hw.mac.type) {
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
case e1000_i210:
case e1000_i211:
case e1000_vfadapt:
@@ -2818,7 +2723,7 @@ mem:
if (adapter->msix_mem != NULL)
bus_release_resource(dev, SYS_RES_MEMORY,
- PCIR_BAR(IGB_MSIX_BAR), adapter->msix_mem);
+ adapter->memrid, adapter->msix_mem);
if (adapter->pci_mem != NULL)
bus_release_resource(dev, SYS_RES_MEMORY,
@@ -2832,8 +2737,8 @@ mem:
static int
igb_setup_msix(struct adapter *adapter)
{
- device_t dev = adapter->dev;
- int rid, want, queues, msgs, maxqueues;
+ device_t dev = adapter->dev;
+ int bar, want, queues, msgs, maxqueues;
/* tuneable override */
if (igb_enable_msix == 0)
@@ -2843,9 +2748,17 @@ igb_setup_msix(struct adapter *adapter)
msgs = pci_msix_count(dev);
if (msgs == 0)
goto msi;
- rid = PCIR_BAR(IGB_MSIX_BAR);
+ /*
+ ** Some new devices, as with ixgbe, now may
+ ** use a different BAR, so we need to keep
+ ** track of which is used.
+ */
+ adapter->memrid = PCIR_BAR(IGB_MSIX_BAR);
+ bar = pci_read_config(dev, adapter->memrid, 4);
+ if (bar == 0) /* use next bar */
+ adapter->memrid += 4;
adapter->msix_mem = bus_alloc_resource_any(dev,
- SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ SYS_RES_MEMORY, &adapter->memrid, RF_ACTIVE);
if (adapter->msix_mem == NULL) {
/* May not be enabled */
device_printf(adapter->dev,
@@ -2868,6 +2781,7 @@ igb_setup_msix(struct adapter *adapter)
case e1000_82576:
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
maxqueues = 8;
break;
case e1000_i210:
@@ -2883,8 +2797,9 @@ igb_setup_msix(struct adapter *adapter)
if (queues > maxqueues)
queues = maxqueues;
- /* reflect correct sysctl value */
- igb_num_queues = queues;
+ /* Manual override */
+ if (igb_num_queues != 0)
+ queues = igb_num_queues;
/*
** One vector (RX/TX pair) per queue
@@ -2929,6 +2844,129 @@ msi:
/*********************************************************************
*
+ * Initialize the DMA Coalescing feature
+ *
+ **********************************************************************/
+static void
+igb_init_dmac(struct adapter *adapter, u32 pba)
+{
+ device_t dev = adapter->dev;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 dmac, reg = ~E1000_DMACR_DMAC_EN;
+ u16 hwm;
+
+ if (hw->mac.type == e1000_i211)
+ return;
+
+ if (hw->mac.type > e1000_82580) {
+
+ if (adapter->dmac == 0) { /* Disabling it */
+ E1000_WRITE_REG(hw, E1000_DMACR, reg);
+ return;
+ } else
+ device_printf(dev, "DMA Coalescing enabled\n");
+
+ /* Set starting threshold */
+ E1000_WRITE_REG(hw, E1000_DMCTXTH, 0);
+
+ hwm = 64 * pba - adapter->max_frame_size / 16;
+ if (hwm < 64 * (pba - 6))
+ hwm = 64 * (pba - 6);
+ reg = E1000_READ_REG(hw, E1000_FCRTC);
+ reg &= ~E1000_FCRTC_RTH_COAL_MASK;
+ reg |= ((hwm << E1000_FCRTC_RTH_COAL_SHIFT)
+ & E1000_FCRTC_RTH_COAL_MASK);
+ E1000_WRITE_REG(hw, E1000_FCRTC, reg);
+
+
+ dmac = pba - adapter->max_frame_size / 512;
+ if (dmac < pba - 10)
+ dmac = pba - 10;
+ reg = E1000_READ_REG(hw, E1000_DMACR);
+ reg &= ~E1000_DMACR_DMACTHR_MASK;
+ reg = ((dmac << E1000_DMACR_DMACTHR_SHIFT)
+ & E1000_DMACR_DMACTHR_MASK);
+
+ /* transition to L0x or L1 if available..*/
+ reg |= (E1000_DMACR_DMAC_EN | E1000_DMACR_DMAC_LX_MASK);
+
+ /* Check if status is 2.5Gb backplane connection
+ * before configuration of watchdog timer, which is
+ * in msec values in 12.8usec intervals
+ * watchdog timer= msec values in 32usec intervals
+ * for non 2.5Gb connection
+ */
+ if (hw->mac.type == e1000_i354) {
+ int status = E1000_READ_REG(hw, E1000_STATUS);
+ if ((status & E1000_STATUS_2P5_SKU) &&
+ (!(status & E1000_STATUS_2P5_SKU_OVER)))
+ reg |= ((adapter->dmac * 5) >> 6);
+ else
+ reg |= (adapter->dmac >> 5);
+ } else {
+ reg |= (adapter->dmac >> 5);
+ }
+
+ E1000_WRITE_REG(hw, E1000_DMACR, reg);
+
+#ifdef I210_OBFF_SUPPORT
+ /*
+ * Set the OBFF Rx threshold to DMA Coalescing Rx
+ * threshold - 2KB and enable the feature in the
+ * hardware for I210.
+ */
+ if (hw->mac.type == e1000_i210) {
+ int obff = dmac - 2;
+ reg = E1000_READ_REG(hw, E1000_DOBFFCTL);
+ reg &= ~E1000_DOBFFCTL_OBFFTHR_MASK;
+ reg |= (obff & E1000_DOBFFCTL_OBFFTHR_MASK)
+ | E1000_DOBFFCTL_EXIT_ACT_MASK;
+ E1000_WRITE_REG(hw, E1000_DOBFFCTL, reg);
+ }
+#endif
+ E1000_WRITE_REG(hw, E1000_DMCRTRH, 0);
+
+ /* Set the interval before transition */
+ reg = E1000_READ_REG(hw, E1000_DMCTLX);
+ if (hw->mac.type == e1000_i350)
+ reg |= IGB_DMCTLX_DCFLUSH_DIS;
+ /*
+ ** in 2.5Gb connection, TTLX unit is 0.4 usec
+ ** which is 0x4*2 = 0xA. But delay is still 4 usec
+ */
+ if (hw->mac.type == e1000_i354) {
+ int status = E1000_READ_REG(hw, E1000_STATUS);
+ if ((status & E1000_STATUS_2P5_SKU) &&
+ (!(status & E1000_STATUS_2P5_SKU_OVER)))
+ reg |= 0xA;
+ else
+ reg |= 0x4;
+ } else {
+ reg |= 0x4;
+ }
+
+ E1000_WRITE_REG(hw, E1000_DMCTLX, reg);
+
+ /* free space in tx packet buffer to wake from DMA coal */
+ E1000_WRITE_REG(hw, E1000_DMCTXTH, (IGB_TXPBSIZE -
+ (2 * adapter->max_frame_size)) >> 6);
+
+ /* make low power state decision controlled by DMA coal */
+ reg = E1000_READ_REG(hw, E1000_PCIEMISC);
+ reg &= ~E1000_PCIEMISC_LX_DECISION;
+ E1000_WRITE_REG(hw, E1000_PCIEMISC, reg);
+
+ } else if (hw->mac.type == e1000_82580) {
+ u32 reg = E1000_READ_REG(hw, E1000_PCIEMISC);
+ E1000_WRITE_REG(hw, E1000_PCIEMISC,
+ reg & ~E1000_PCIEMISC_LX_DECISION);
+ E1000_WRITE_REG(hw, E1000_DMACR, 0);
+ }
+}
+
+
+/*********************************************************************
+ *
* Set up an fresh starting state
*
**********************************************************************/
@@ -2963,6 +3001,7 @@ igb_reset(struct adapter *adapter)
break;
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
case e1000_vfadapt_i350:
pba = E1000_READ_REG(hw, E1000_RXPBS);
pba = e1000_rxpbs_adjust_82580(pba);
@@ -3033,70 +3072,19 @@ igb_reset(struct adapter *adapter)
e1000_reset_hw(hw);
E1000_WRITE_REG(hw, E1000_WUC, 0);
+ /* Reset for AutoMediaDetect */
+ if (adapter->flags & IGB_MEDIA_RESET) {
+ e1000_setup_init_funcs(hw, TRUE);
+ e1000_get_bus_info(hw);
+ adapter->flags &= ~IGB_MEDIA_RESET;
+ }
+
if (e1000_init_hw(hw) < 0)
device_printf(dev, "Hardware Initialization Failed\n");
/* Setup DMA Coalescing */
- if ((hw->mac.type > e1000_82580) &&
- (hw->mac.type != e1000_i211)) {
- u32 dmac;
- u32 reg = ~E1000_DMACR_DMAC_EN;
-
- if (adapter->dmac == 0) { /* Disabling it */
- E1000_WRITE_REG(hw, E1000_DMACR, reg);
- goto reset_out;
- }
+ igb_init_dmac(adapter, pba);
- /* Set starting thresholds */
- E1000_WRITE_REG(hw, E1000_DMCTXTH, 0);
- E1000_WRITE_REG(hw, E1000_DMCRTRH, 0);
-
- hwm = 64 * pba - adapter->max_frame_size / 16;
- if (hwm < 64 * (pba - 6))
- hwm = 64 * (pba - 6);
- reg = E1000_READ_REG(hw, E1000_FCRTC);
- reg &= ~E1000_FCRTC_RTH_COAL_MASK;
- reg |= ((hwm << E1000_FCRTC_RTH_COAL_SHIFT)
- & E1000_FCRTC_RTH_COAL_MASK);
- E1000_WRITE_REG(hw, E1000_FCRTC, reg);
-
-
- dmac = pba - adapter->max_frame_size / 512;
- if (dmac < pba - 10)
- dmac = pba - 10;
- reg = E1000_READ_REG(hw, E1000_DMACR);
- reg &= ~E1000_DMACR_DMACTHR_MASK;
- reg = ((dmac << E1000_DMACR_DMACTHR_SHIFT)
- & E1000_DMACR_DMACTHR_MASK);
- /* transition to L0x or L1 if available..*/
- reg |= (E1000_DMACR_DMAC_EN | E1000_DMACR_DMAC_LX_MASK);
- /* timer = value in adapter->dmac in 32usec intervals */
- reg |= (adapter->dmac >> 5);
- E1000_WRITE_REG(hw, E1000_DMACR, reg);
-
- /* Set the interval before transition */
- reg = E1000_READ_REG(hw, E1000_DMCTLX);
- reg |= 0x80000004;
- E1000_WRITE_REG(hw, E1000_DMCTLX, reg);
-
- /* free space in tx packet buffer to wake from DMA coal */
- E1000_WRITE_REG(hw, E1000_DMCTXTH,
- (20480 - (2 * adapter->max_frame_size)) >> 6);
-
- /* make low power state decision controlled by DMA coal */
- reg = E1000_READ_REG(hw, E1000_PCIEMISC);
- reg &= ~E1000_PCIEMISC_LX_DECISION;
- E1000_WRITE_REG(hw, E1000_PCIEMISC, reg);
- device_printf(dev, "DMA Coalescing enabled\n");
-
- } else if (hw->mac.type == e1000_82580) {
- u32 reg = E1000_READ_REG(hw, E1000_PCIEMISC);
- E1000_WRITE_REG(hw, E1000_DMACR, 0);
- E1000_WRITE_REG(hw, E1000_PCIEMISC,
- reg & ~E1000_PCIEMISC_LX_DECISION);
- }
-
-reset_out:
E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN);
e1000_get_phy_info(hw);
e1000_check_for_link(hw);
@@ -3140,7 +3128,7 @@ igb_setup_interface(device_t dev, struct adapter *adapter)
ifp->if_capabilities = ifp->if_capenable = 0;
ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
- ifp->if_capabilities |= IFCAP_TSO4;
+ ifp->if_capabilities |= IFCAP_TSO;
ifp->if_capabilities |= IFCAP_JUMBO_MTU;
ifp->if_capenable = ifp->if_capabilities;
@@ -3346,6 +3334,7 @@ igb_allocate_queues(struct adapter *adapter)
txr = &adapter->tx_rings[i];
txr->adapter = adapter;
txr->me = i;
+ txr->num_desc = adapter->num_tx_desc;
/* Initialize the TX lock */
snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
@@ -3359,7 +3348,7 @@ igb_allocate_queues(struct adapter *adapter)
error = ENOMEM;
goto err_tx_desc;
}
- txr->tx_base = (struct e1000_tx_desc *)txr->txdma.dma_vaddr;
+ txr->tx_base = (union e1000_adv_tx_desc *)txr->txdma.dma_vaddr;
bzero((void *)txr->tx_base, tsize);
/* Now allocate transmit buffers for the ring */
@@ -3452,7 +3441,7 @@ igb_allocate_transmit_buffers(struct tx_ring *txr)
{
struct adapter *adapter = txr->adapter;
device_t dev = adapter->dev;
- struct igb_tx_buffer *txbuf;
+ struct igb_tx_buf *txbuf;
int error, i;
/*
@@ -3475,7 +3464,7 @@ igb_allocate_transmit_buffers(struct tx_ring *txr)
}
if (!(txr->tx_buffers =
- (struct igb_tx_buffer *) malloc(sizeof(struct igb_tx_buffer) *
+ (struct igb_tx_buf *) malloc(sizeof(struct igb_tx_buf) *
adapter->num_tx_desc, M_DEVBUF, M_NOWAIT | M_ZERO))) {
device_printf(dev, "Unable to allocate tx_buffer memory\n");
error = ENOMEM;
@@ -3508,7 +3497,7 @@ static void
igb_setup_transmit_ring(struct tx_ring *txr)
{
struct adapter *adapter = txr->adapter;
- struct igb_tx_buffer *txbuf;
+ struct igb_tx_buf *txbuf;
int i;
#ifdef DEV_NETMAP
struct netmap_adapter *na = NA(adapter->ifp);
@@ -3544,7 +3533,7 @@ igb_setup_transmit_ring(struct tx_ring *txr)
}
#endif /* DEV_NETMAP */
/* clear the watch index */
- txbuf->next_eop = -1;
+ txbuf->eop = NULL;
}
/* Set number of descriptors available */
@@ -3658,7 +3647,7 @@ static void
igb_free_transmit_buffers(struct tx_ring *txr)
{
struct adapter *adapter = txr->adapter;
- struct igb_tx_buffer *tx_buffer;
+ struct igb_tx_buf *tx_buffer;
int i;
INIT_DEBUGOUT("free_transmit_ring: begin");
@@ -3705,44 +3694,100 @@ igb_free_transmit_buffers(struct tx_ring *txr)
/**********************************************************************
*
- * Setup work for hardware segmentation offload (TSO)
+ * Setup work for hardware segmentation offload (TSO) on
+ * adapters using advanced tx descriptors
*
**********************************************************************/
-static bool
-igb_tso_setup(struct tx_ring *txr, struct mbuf *mp, int ehdrlen,
- struct ip *ip, struct tcphdr *th)
+static int
+igb_tso_setup(struct tx_ring *txr, struct mbuf *mp,
+ u32 *cmd_type_len, u32 *olinfo_status)
{
struct adapter *adapter = txr->adapter;
struct e1000_adv_tx_context_desc *TXD;
- struct igb_tx_buffer *tx_buffer;
u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0;
- u32 mss_l4len_idx = 0;
- u16 vtag = 0;
- int ctxd, ip_hlen, tcp_hlen;
+ u32 mss_l4len_idx = 0, paylen;
+ u16 vtag = 0, eh_type;
+ int ctxd, ehdrlen, ip_hlen, tcp_hlen;
+ struct ether_vlan_header *eh;
+#ifdef INET6
+ struct ip6_hdr *ip6;
+#endif
+#ifdef INET
+ struct ip *ip;
+#endif
+ struct tcphdr *th;
+
+
+ /*
+ * Determine where frame payload starts.
+ * Jump over vlan headers if already present
+ */
+ eh = mtod(mp, struct ether_vlan_header *);
+ if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
+ ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
+ eh_type = eh->evl_proto;
+ } else {
+ ehdrlen = ETHER_HDR_LEN;
+ eh_type = eh->evl_encap_proto;
+ }
+
+ switch (ntohs(eh_type)) {
+#ifdef INET6
+ case ETHERTYPE_IPV6:
+ ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
+ /* XXX-BZ For now we do not pretend to support ext. hdrs. */
+ if (ip6->ip6_nxt != IPPROTO_TCP)
+ return (ENXIO);
+ ip_hlen = sizeof(struct ip6_hdr);
+ ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
+ th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen);
+ th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
+ type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV6;
+ break;
+#endif
+#ifdef INET
+ case ETHERTYPE_IP:
+ ip = (struct ip *)(mp->m_data + ehdrlen);
+ if (ip->ip_p != IPPROTO_TCP)
+ return (ENXIO);
+ ip->ip_sum = 0;
+ ip_hlen = ip->ip_hl << 2;
+ th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
+ th->th_sum = in_pseudo(ip->ip_src.s_addr,
+ ip->ip_dst.s_addr, htons(IPPROTO_TCP));
+ type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV4;
+ /* Tell transmit desc to also do IPv4 checksum. */
+ *olinfo_status |= E1000_TXD_POPTS_IXSM << 8;
+ break;
+#endif
+ default:
+ panic("%s: CSUM_TSO but no supported IP version (0x%04x)",
+ __func__, ntohs(eh_type));
+ break;
+ }
ctxd = txr->next_avail_desc;
- tx_buffer = &txr->tx_buffers[ctxd];
TXD = (struct e1000_adv_tx_context_desc *) &txr->tx_base[ctxd];
- ip->ip_sum = 0;
- ip_hlen = ip->ip_hl << 2;
tcp_hlen = th->th_off << 2;
+ /* This is used in the transmit desc in encap */
+ paylen = mp->m_pkthdr.len - ehdrlen - ip_hlen - tcp_hlen;
+
/* VLAN MACLEN IPLEN */
if (mp->m_flags & M_VLANTAG) {
vtag = htole16(mp->m_pkthdr.ether_vtag);
- vlan_macip_lens |= (vtag << E1000_ADVTXD_VLAN_SHIFT);
+ vlan_macip_lens |= (vtag << E1000_ADVTXD_VLAN_SHIFT);
}
- vlan_macip_lens |= (ehdrlen << E1000_ADVTXD_MACLEN_SHIFT);
+ vlan_macip_lens |= ehdrlen << E1000_ADVTXD_MACLEN_SHIFT;
vlan_macip_lens |= ip_hlen;
- TXD->vlan_macip_lens |= htole32(vlan_macip_lens);
+ TXD->vlan_macip_lens = htole32(vlan_macip_lens);
/* ADV DTYPE TUCMD */
type_tucmd_mlhl |= E1000_ADVTXD_DCMD_DEXT | E1000_ADVTXD_DTYP_CTXT;
type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_TCP;
- type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV4;
- TXD->type_tucmd_mlhl |= htole32(type_tucmd_mlhl);
+ TXD->type_tucmd_mlhl = htole32(type_tucmd_mlhl);
/* MSS L4LEN IDX */
mss_l4len_idx |= (mp->m_pkthdr.tso_segsz << E1000_ADVTXD_MSS_SHIFT);
@@ -3753,57 +3798,65 @@ igb_tso_setup(struct tx_ring *txr, struct mbuf *mp, int ehdrlen,
TXD->mss_l4len_idx = htole32(mss_l4len_idx);
TXD->seqnum_seed = htole32(0);
- tx_buffer->m_head = NULL;
- tx_buffer->next_eop = -1;
- if (++ctxd == adapter->num_tx_desc)
+ if (++ctxd == txr->num_desc)
ctxd = 0;
txr->tx_avail--;
txr->next_avail_desc = ctxd;
- return TRUE;
+ *cmd_type_len |= E1000_ADVTXD_DCMD_TSE;
+ *olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
+ *olinfo_status |= paylen << E1000_ADVTXD_PAYLEN_SHIFT;
+ ++txr->tso_tx;
+ return (0);
}
-
/*********************************************************************
*
- * Context Descriptor setup for VLAN or CSUM
+ * Advanced Context Descriptor setup for VLAN, CSUM or TSO
*
**********************************************************************/
-static bool
-igb_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp)
+static int
+igb_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp,
+ u32 *cmd_type_len, u32 *olinfo_status)
{
- struct adapter *adapter = txr->adapter;
struct e1000_adv_tx_context_desc *TXD;
- struct igb_tx_buffer *tx_buffer;
- u32 vlan_macip_lens, type_tucmd_mlhl, mss_l4len_idx;
+ struct adapter *adapter = txr->adapter;
struct ether_vlan_header *eh;
- struct ip *ip = NULL;
+ struct ip *ip;
struct ip6_hdr *ip6;
- int ehdrlen, ctxd, ip_hlen = 0;
- u16 etype, vtag = 0;
+ u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0, mss_l4len_idx = 0;
+ int ehdrlen, ip_hlen = 0;
+ u16 etype;
u8 ipproto = 0;
- bool offload = TRUE;
+ int offload = TRUE;
+ int ctxd = txr->next_avail_desc;
+ u16 vtag = 0;
+
+ /* First check if TSO is to be used */
+ if (mp->m_pkthdr.csum_flags & CSUM_TSO)
+ return (igb_tso_setup(txr, mp, cmd_type_len, olinfo_status));
if ((mp->m_pkthdr.csum_flags & CSUM_OFFLOAD) == 0)
offload = FALSE;
- vlan_macip_lens = type_tucmd_mlhl = mss_l4len_idx = 0;
- ctxd = txr->next_avail_desc;
- tx_buffer = &txr->tx_buffers[ctxd];
+ /* Indicate the whole packet as payload when not doing TSO */
+ *olinfo_status |= mp->m_pkthdr.len << E1000_ADVTXD_PAYLEN_SHIFT;
+
+ /* Now ready a context descriptor */
TXD = (struct e1000_adv_tx_context_desc *) &txr->tx_base[ctxd];
/*
** In advanced descriptors the vlan tag must
- ** be placed into the context descriptor, thus
- ** we need to be here just for that setup.
+ ** be placed into the context descriptor. Hence
+ ** we need to make one even if not doing offloads.
*/
if (mp->m_flags & M_VLANTAG) {
vtag = htole16(mp->m_pkthdr.ether_vtag);
vlan_macip_lens |= (vtag << E1000_ADVTXD_VLAN_SHIFT);
- } else if (offload == FALSE)
- return FALSE;
+ } else if (offload == FALSE) /* ... no offload to do */
+ return (0);
/*
* Determine where frame payload starts.
@@ -3826,16 +3879,13 @@ igb_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp)
case ETHERTYPE_IP:
ip = (struct ip *)(mp->m_data + ehdrlen);
ip_hlen = ip->ip_hl << 2;
- if (mp->m_len < ehdrlen + ip_hlen) {
- offload = FALSE;
- break;
- }
ipproto = ip->ip_p;
type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV4;
break;
case ETHERTYPE_IPV6:
ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
ip_hlen = sizeof(struct ip6_hdr);
+ /* XXX-BZ this will go badly in case of ext hdrs. */
ipproto = ip6->ip6_nxt;
type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV6;
break;
@@ -3856,6 +3906,7 @@ igb_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp)
if (mp->m_pkthdr.csum_flags & CSUM_UDP)
type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_UDP;
break;
+
#if __FreeBSD_version >= 800000
case IPPROTO_SCTP:
if (mp->m_pkthdr.csum_flags & CSUM_SCTP)
@@ -3867,29 +3918,28 @@ igb_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp)
break;
}
+ if (offload) /* For the TX descriptor setup */
+ *olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
+
/* 82575 needs the queue index added */
if (adapter->hw.mac.type == e1000_82575)
mss_l4len_idx = txr->me << 4;
/* Now copy bits into descriptor */
- TXD->vlan_macip_lens |= htole32(vlan_macip_lens);
- TXD->type_tucmd_mlhl |= htole32(type_tucmd_mlhl);
+ TXD->vlan_macip_lens = htole32(vlan_macip_lens);
+ TXD->type_tucmd_mlhl = htole32(type_tucmd_mlhl);
TXD->seqnum_seed = htole32(0);
TXD->mss_l4len_idx = htole32(mss_l4len_idx);
- tx_buffer->m_head = NULL;
- tx_buffer->next_eop = -1;
-
/* We've consumed the first desc, adjust counters */
- if (++ctxd == adapter->num_tx_desc)
+ if (++ctxd == txr->num_desc)
ctxd = 0;
txr->next_avail_desc = ctxd;
--txr->tx_avail;
- return (offload);
+ return (0);
}
-
/**********************************************************************
*
* Examine each tx_buffer in the used queue. If the hardware is done
@@ -3901,90 +3951,106 @@ igb_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp)
static bool
igb_txeof(struct tx_ring *txr)
{
- struct adapter *adapter = txr->adapter;
- int first, last, done, processed;
- struct igb_tx_buffer *tx_buffer;
- struct e1000_tx_desc *tx_desc, *eop_desc;
- struct ifnet *ifp = adapter->ifp;
+ struct adapter *adapter = txr->adapter;
+ struct ifnet *ifp = adapter->ifp;
+ u32 work, processed = 0;
+ u16 limit = txr->process_limit;
+ struct igb_tx_buf *buf;
+ union e1000_adv_tx_desc *txd;
- IGB_TX_LOCK_ASSERT(txr);
+ mtx_assert(&txr->tx_mtx, MA_OWNED);
#ifdef DEV_NETMAP
if (netmap_tx_irq(ifp, txr->me |
(NETMAP_LOCKED_ENTER|NETMAP_LOCKED_EXIT)))
return (FALSE);
#endif /* DEV_NETMAP */
- if (txr->tx_avail == adapter->num_tx_desc) {
+
+ if (txr->tx_avail == txr->num_desc) {
txr->queue_status = IGB_QUEUE_IDLE;
- return FALSE;
+ return FALSE;
}
- processed = 0;
- first = txr->next_to_clean;
- tx_desc = &txr->tx_base[first];
- tx_buffer = &txr->tx_buffers[first];
- last = tx_buffer->next_eop;
- eop_desc = &txr->tx_base[last];
-
- /*
- * What this does is get the index of the
- * first descriptor AFTER the EOP of the
- * first packet, that way we can do the
- * simple comparison on the inner while loop.
- */
- if (++last == adapter->num_tx_desc)
- last = 0;
- done = last;
-
+ /* Get work starting point */
+ work = txr->next_to_clean;
+ buf = &txr->tx_buffers[work];
+ txd = &txr->tx_base[work];
+ work -= txr->num_desc; /* The distance to ring end */
bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ do {
+ union e1000_adv_tx_desc *eop = buf->eop;
+ if (eop == NULL) /* No work */
+ break;
- while (eop_desc->upper.fields.status & E1000_TXD_STAT_DD) {
- /* We clean the range of the packet */
- while (first != done) {
- tx_desc->upper.data = 0;
- tx_desc->lower.data = 0;
- tx_desc->buffer_addr = 0;
- ++txr->tx_avail;
- ++processed;
+ if ((eop->wb.status & E1000_TXD_STAT_DD) == 0)
+ break; /* I/O not complete */
- if (tx_buffer->m_head) {
+ if (buf->m_head) {
+ txr->bytes +=
+ buf->m_head->m_pkthdr.len;
+ bus_dmamap_sync(txr->txtag,
+ buf->map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(txr->txtag,
+ buf->map);
+ m_freem(buf->m_head);
+ buf->m_head = NULL;
+ buf->map = NULL;
+ }
+ buf->eop = NULL;
+ ++txr->tx_avail;
+
+ /* We clean the range if multi segment */
+ while (txd != eop) {
+ ++txd;
+ ++buf;
+ ++work;
+ /* wrap the ring? */
+ if (__predict_false(!work)) {
+ work -= txr->num_desc;
+ buf = txr->tx_buffers;
+ txd = txr->tx_base;
+ }
+ if (buf->m_head) {
txr->bytes +=
- tx_buffer->m_head->m_pkthdr.len;
+ buf->m_head->m_pkthdr.len;
bus_dmamap_sync(txr->txtag,
- tx_buffer->map,
+ buf->map,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(txr->txtag,
- tx_buffer->map);
-
- m_freem(tx_buffer->m_head);
- tx_buffer->m_head = NULL;
- }
- tx_buffer->next_eop = -1;
- txr->watchdog_time = ticks;
-
- if (++first == adapter->num_tx_desc)
- first = 0;
+ buf->map);
+ m_freem(buf->m_head);
+ buf->m_head = NULL;
+ buf->map = NULL;
+ }
+ ++txr->tx_avail;
+ buf->eop = NULL;
- tx_buffer = &txr->tx_buffers[first];
- tx_desc = &txr->tx_base[first];
}
++txr->packets;
+ ++processed;
++ifp->if_opackets;
- /* See if we can continue to the next packet */
- last = tx_buffer->next_eop;
- if (last != -1) {
- eop_desc = &txr->tx_base[last];
- /* Get new done point */
- if (++last == adapter->num_tx_desc) last = 0;
- done = last;
- } else
- break;
- }
- bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
- BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ txr->watchdog_time = ticks;
- txr->next_to_clean = first;
+ /* Try the next packet */
+ ++txd;
+ ++buf;
+ ++work;
+ /* reset with a wrap */
+ if (__predict_false(!work)) {
+ work -= txr->num_desc;
+ buf = txr->tx_buffers;
+ txd = txr->tx_base;
+ }
+ prefetch(txd);
+ } while (__predict_true(--limit));
+
+ bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ work += txr->num_desc;
+ txr->next_to_clean = work;
/*
** Watchdog calculation, we know there's
@@ -3994,18 +4060,14 @@ igb_txeof(struct tx_ring *txr)
*/
if ((!processed) && ((ticks - txr->watchdog_time) > IGB_WATCHDOG))
txr->queue_status |= IGB_QUEUE_HUNG;
- /*
- * If we have a minimum free,
- * clear depleted state bit
- */
- if (txr->tx_avail >= IGB_QUEUE_THRESHOLD)
- txr->queue_status &= ~IGB_QUEUE_DEPLETED;
- /* All clean, turn off the watchdog */
- if (txr->tx_avail == adapter->num_tx_desc) {
+ if (txr->tx_avail >= IGB_QUEUE_THRESHOLD)
+ txr->queue_status &= ~IGB_QUEUE_DEPLETED;
+
+ if (txr->tx_avail == txr->num_desc) {
txr->queue_status = IGB_QUEUE_IDLE;
return (FALSE);
- }
+ }
return (TRUE);
}
@@ -4789,7 +4851,8 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
rxbuf = &rxr->rx_buffers[i];
plen = le16toh(cur->wb.upper.length);
ptype = le32toh(cur->wb.lower.lo_dword.data) & IGB_PKTTYPE_MASK;
- if ((adapter->hw.mac.type == e1000_i350) &&
+ if (((adapter->hw.mac.type == e1000_i350) ||
+ (adapter->hw.mac.type == e1000_i354)) &&
(staterr & E1000_RXDEXT_STATERR_LB))
vtag = be16toh(cur->wb.upper.vlan);
else
@@ -5590,8 +5653,8 @@ igb_add_hw_stats(struct adapter *adapter)
SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
CTLFLAG_RD, &txr->no_desc_avail,
"Queue No Descriptor Available");
- SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "tx_packets",
- CTLFLAG_RD, &txr->tx_packets,
+ SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
+ CTLFLAG_RD, &txr->total_packets,
"Queue Packets Transmitted");
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head",
@@ -6032,7 +6095,7 @@ igb_sysctl_dmac(SYSCTL_HANDLER_ARGS)
default:
/* Do nothing, illegal value */
adapter->dmac = 0;
- return (error);
+ return (EINVAL);
}
/* Reinit the interface */
igb_init(adapter);
diff --git a/sys/dev/e1000/if_igb.h b/sys/dev/e1000/if_igb.h
index 6f3a3a5..0c44741 100644
--- a/sys/dev/e1000/if_igb.h
+++ b/sys/dev/e1000/if_igb.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2013, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -162,6 +162,9 @@
/* PHY master/slave setting */
#define IGB_MASTER_SLAVE e1000_ms_hw_default
+/* Support AutoMediaDetect for Marvell M88 PHY in i354 */
+#define IGB_MEDIA_RESET (1 << 0)
+
/*
* Micellaneous constants
*/
@@ -173,11 +176,13 @@
#define IGB_SMARTSPEED_MAX 15
#define IGB_MAX_LOOP 10
-#define IGB_RX_PTHRESH (hw->mac.type <= e1000_82576 ? 16 : 8)
+#define IGB_RX_PTHRESH ((hw->mac.type == e1000_i354) ? 12 : \
+ ((hw->mac.type <= e1000_82576) ? 16 : 8))
#define IGB_RX_HTHRESH 8
-#define IGB_RX_WTHRESH 1
+#define IGB_RX_WTHRESH ((hw->mac.type == e1000_82576 && \
+ adapter->msix_mem) ? 1 : 4)
-#define IGB_TX_PTHRESH 8
+#define IGB_TX_PTHRESH ((hw->mac.type == e1000_i354) ? 20 : 8)
#define IGB_TX_HTHRESH 1
#define IGB_TX_WTHRESH ((hw->mac.type != e1000_82575 && \
adapter->msix_mem) ? 1 : 16)
@@ -190,11 +195,6 @@
#define IGB_EEPROM_APME 0x400;
/* Queue minimum free for use */
#define IGB_QUEUE_THRESHOLD (adapter->num_tx_desc / 8)
-/* Queue bit defines */
-#define IGB_QUEUE_IDLE 1
-#define IGB_QUEUE_WORKING 2
-#define IGB_QUEUE_HUNG 4
-#define IGB_QUEUE_DEPLETED 8
/*
* TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be
@@ -228,8 +228,10 @@
#define IGB_BR_SIZE 4096 /* ring buf size */
#define IGB_TSO_SIZE (65535 + sizeof(struct ether_vlan_header))
#define IGB_TSO_SEG_SIZE 4096 /* Max dma segment size */
+#define IGB_TXPBSIZE 20408
#define IGB_HDR_BUF 128
#define IGB_PKTTYPE_MASK 0x0000FFF0
+#define IGB_DMCTLX_DCFLUSH_DIS 0x80000000 /* Disable DMA Coalesce Flush */
#define ETH_ZLEN 60
#define ETH_ADDR_LEN 6
@@ -245,6 +247,7 @@
#define IGB_DEFAULT_ITR ((1000000/IGB_INTS_PER_SEC) << 2)
#define IGB_LINK_ITR 2000
+#define I210_LINK_DELAY 1000
/* Precision Time Sync (IEEE 1588) defines */
#define ETHERTYPE_IEEE1588 0x88F7
@@ -284,34 +287,42 @@ struct igb_queue {
};
/*
- * Transmit ring: one per queue
+ * The transmit ring, one per queue
*/
struct tx_ring {
- struct adapter *adapter;
- u32 me;
+ struct adapter *adapter;
struct mtx tx_mtx;
- char mtx_name[16];
+ u32 me;
+ int watchdog_time;
+ union e1000_adv_tx_desc *tx_base;
+ struct igb_tx_buf *tx_buffers;
struct igb_dma_alloc txdma;
- struct e1000_tx_desc *tx_base;
- u32 next_avail_desc;
- u32 next_to_clean;
volatile u16 tx_avail;
- struct igb_tx_buffer *tx_buffers;
+ u16 next_avail_desc;
+ u16 next_to_clean;
+ u16 process_limit;
+ u16 num_desc;
+ enum {
+ IGB_QUEUE_IDLE = 1,
+ IGB_QUEUE_WORKING = 2,
+ IGB_QUEUE_HUNG = 4,
+ IGB_QUEUE_DEPLETED = 8,
+ } queue_status;
+ u32 txd_cmd;
+ bus_dma_tag_t txtag;
+ char mtx_name[16];
#ifndef IGB_LEGACY_TX
struct buf_ring *br;
struct task txq_task;
#endif
- bus_dma_tag_t txtag;
-
- u32 bytes;
+ u32 bytes; /* used for AIM */
u32 packets;
-
- int queue_status;
- int watchdog_time;
- int tdt;
- int tdh;
+ /* Soft Stats */
+ unsigned long tso_tx;
+ unsigned long no_tx_map_avail;
+ unsigned long no_tx_dma_setup;
u64 no_desc_avail;
- u64 tx_packets;
+ u64 total_packets;
};
/*
@@ -353,43 +364,38 @@ struct rx_ring {
};
struct adapter {
- struct ifnet *ifp;
- struct e1000_hw hw;
-
- struct e1000_osdep osdep;
- struct device *dev;
- struct cdev *led_dev;
-
- struct resource *pci_mem;
- struct resource *msix_mem;
- struct resource *res;
- void *tag;
- u32 que_mask;
-
- int linkvec;
- int link_mask;
- struct task link_task;
- int link_irq;
-
- struct ifmedia media;
- struct callout timer;
- int msix; /* total vectors allocated */
- int if_flags;
- int max_frame_size;
- int min_frame_size;
- int pause_frames;
- struct mtx core_mtx;
- int igb_insert_vlan_header;
- u16 num_queues;
- u16 vf_ifp; /* a VF interface */
-
- eventhandler_tag vlan_attach;
- eventhandler_tag vlan_detach;
- u32 num_vlans;
-
- /* Management and WOL features */
- int wol;
- int has_manage;
+ struct ifnet *ifp;
+ struct e1000_hw hw;
+
+ struct e1000_osdep osdep;
+ struct device *dev;
+ struct cdev *led_dev;
+
+ struct resource *pci_mem;
+ struct resource *msix_mem;
+ int memrid;
+
+ /*
+ * Interrupt resources: this set is
+ * either used for legacy, or for Link
+ * when doing MSIX
+ */
+ void *tag;
+ struct resource *res;
+
+ struct ifmedia media;
+ struct callout timer;
+ int msix;
+ int if_flags;
+ int pause_frames;
+
+ struct mtx core_mtx;
+
+ eventhandler_tag vlan_attach;
+ eventhandler_tag vlan_detach;
+
+ u16 num_vlans;
+ u16 num_queues;
/*
** Shadow VFTA table, this is needed because
@@ -397,66 +403,86 @@ struct adapter {
** a soft reset and the driver needs to be able
** to repopulate it.
*/
- u32 shadow_vfta[IGB_VFTA_SIZE];
+ u32 shadow_vfta[IGB_VFTA_SIZE];
/* Info about the interface */
- u16 link_active;
- u16 fc;
- u16 link_speed;
- u16 link_duplex;
- u32 smartspeed;
- u32 dmac;
- int enable_aim;
-
- /* Interface queues */
+ u32 optics;
+ u32 fc; /* local flow ctrl setting */
+ int advertise; /* link speeds */
+ bool link_active;
+ u16 max_frame_size;
+ u16 num_segs;
+ u16 link_speed;
+ bool link_up;
+ u32 linkvec;
+ u16 link_duplex;
+ u32 dmac;
+ int link_mask;
+
+ /* Flags */
+ u32 flags;
+
+ /* Mbuf cluster size */
+ u32 rx_mbuf_sz;
+
+ /* Support for pluggable optics */
+ bool sfp_probe;
+ struct task link_task; /* Link tasklet */
+ struct task mod_task; /* SFP tasklet */
+ struct task msf_task; /* Multispeed Fiber */
+ struct taskqueue *tq;
+
+ /*
+ ** Queues:
+ ** This is the irq holder, it has
+ ** and RX/TX pair or rings associated
+ ** with it.
+ */
struct igb_queue *queues;
/*
- * Transmit rings
+ * Transmit rings:
+ * Allocated at run time, an array of rings.
*/
struct tx_ring *tx_rings;
- u16 num_tx_desc;
-
- /* Multicast array pointer */
- u8 *mta;
+ u32 num_tx_desc;
- /*
- * Receive rings
+ /*
+ * Receive rings:
+ * Allocated at run time, an array of rings.
*/
struct rx_ring *rx_rings;
- bool rx_hdr_split;
- u16 num_rx_desc;
- int rx_process_limit;
- u32 rx_mbuf_sz;
- u32 rx_mask;
+ u64 que_mask;
+ u32 num_rx_desc;
+
+ /* Multicast array memory */
+ u8 *mta;
/* Misc stats maintained by the driver */
- unsigned long dropped_pkts;
- unsigned long mbuf_defrag_failed;
- unsigned long mbuf_header_failed;
- unsigned long mbuf_packet_failed;
- unsigned long no_tx_map_avail;
- unsigned long no_tx_dma_setup;
- unsigned long watchdog_events;
- unsigned long rx_overruns;
- unsigned long device_control;
- unsigned long rx_control;
- unsigned long int_mask;
- unsigned long eint_mask;
- unsigned long packet_buf_alloc_rx;
- unsigned long packet_buf_alloc_tx;
-
- boolean_t in_detach;
-
-#ifdef IGB_IEEE1588
- /* IEEE 1588 precision time support */
- struct cyclecounter cycles;
- struct nettimer clock;
- struct nettime_compare compare;
- struct hwtstamp_ctrl hwtstamp;
-#endif
+ unsigned long dropped_pkts;
+ unsigned long mbuf_defrag_failed;
+ unsigned long mbuf_header_failed;
+ unsigned long mbuf_packet_failed;
+ unsigned long no_tx_dma_setup;
+ unsigned long watchdog_events;
+ unsigned long link_irq;
+ unsigned long rx_overruns;
+ unsigned long device_control;
+ unsigned long rx_control;
+ unsigned long int_mask;
+ unsigned long eint_mask;
+ unsigned long packet_buf_alloc_rx;
+ unsigned long packet_buf_alloc_tx;
+ /* Used in pf and vf */
+ void *stats;
+
+ int enable_aim;
+ int has_manage;
+ int wol;
+ int rx_process_limit;
+ u16 vf_ifp; /* a VF interface */
+ bool in_detach; /* Used only in igb_ioctl */
- void *stats;
};
/* ******************************************************************************
@@ -474,11 +500,10 @@ typedef struct _igb_vendor_info_t {
unsigned int index;
} igb_vendor_info_t;
-
-struct igb_tx_buffer {
- int next_eop; /* Index of the desc to watch */
- struct mbuf *m_head;
- bus_dmamap_t map; /* bus_dma map for packet */
+struct igb_tx_buf {
+ union e1000_adv_tx_desc *eop;
+ struct mbuf *m_head;
+ bus_dmamap_t map;
};
struct igb_rx_buf {
diff --git a/sys/dev/netmap/if_igb_netmap.h b/sys/dev/netmap/if_igb_netmap.h
index a94ca3b..d4e5dfe 100644
--- a/sys/dev/netmap/if_igb_netmap.h
+++ b/sys/dev/netmap/if_igb_netmap.h
@@ -153,7 +153,7 @@ igb_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
/* curr is the current slot in the nic ring */
union e1000_adv_tx_desc *curr =
(union e1000_adv_tx_desc *)&txr->tx_base[l];
- struct igb_tx_buffer *txbuf = &txr->tx_buffers[l];
+ struct igb_tx_buf *txbuf = &txr->tx_buffers[l];
int flags = ((slot->flags & NS_REPORT) ||
j == 0 || j == report_frequency) ?
E1000_ADVTXD_DCMD_RS : 0;
OpenPOWER on IntegriCloud