summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJack F Vogel <jfv@FreeBSD.org>2010-11-27 01:09:54 +0000
committerJack F Vogel <jfv@FreeBSD.org>2010-11-27 01:09:54 +0000
commit560747b6289d5d0ebee983e11e3d46dabf190653 (patch)
treeea58a4c9dd7d73a9e0831a48f1148c17e6ceb169 /sys/dev
parentc3b293be2011147fe82ec036f0908ac0c2bb56e8 (diff)
Notes
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/e1000/e1000_82571.c269
-rw-r--r--sys/dev/e1000/e1000_82571.h8
-rw-r--r--sys/dev/e1000/e1000_82575.c160
-rw-r--r--sys/dev/e1000/e1000_82575.h12
-rw-r--r--sys/dev/e1000/e1000_api.c78
-rw-r--r--sys/dev/e1000/e1000_api.h4
-rw-r--r--sys/dev/e1000/e1000_defines.h37
-rw-r--r--sys/dev/e1000/e1000_hw.h80
-rw-r--r--sys/dev/e1000/e1000_ich8lan.c831
-rw-r--r--sys/dev/e1000/e1000_ich8lan.h40
-rw-r--r--sys/dev/e1000/e1000_mac.c10
-rw-r--r--sys/dev/e1000/e1000_nvm.c186
-rw-r--r--sys/dev/e1000/e1000_nvm.h5
-rw-r--r--sys/dev/e1000/e1000_osdep.h10
-rw-r--r--sys/dev/e1000/e1000_phy.c22
-rw-r--r--sys/dev/e1000/e1000_phy.h2
-rw-r--r--sys/dev/e1000/e1000_regs.h15
-rw-r--r--sys/dev/e1000/if_em.c1317
-rw-r--r--sys/dev/e1000/if_em.h39
-rw-r--r--sys/dev/e1000/if_igb.c1064
-rw-r--r--sys/dev/e1000/if_igb.h64
-rw-r--r--sys/dev/e1000/if_lem.c251
-rw-r--r--sys/dev/e1000/if_lem.h21
23 files changed, 2959 insertions, 1566 deletions
diff --git a/sys/dev/e1000/e1000_82571.c b/sys/dev/e1000/e1000_82571.c
index afeb1a05e5c3..5e12c4995e5e 100644
--- a/sys/dev/e1000/e1000_82571.c
+++ b/sys/dev/e1000/e1000_82571.c
@@ -78,6 +78,10 @@ static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw);
static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw);
+static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw);
+static s32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw);
static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
u16 words, u16 *data);
@@ -91,6 +95,7 @@ static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw);
static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
+ struct e1000_dev_spec_82571 *dev_spec = &hw->dev_spec._82571;
s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_init_phy_params_82571");
@@ -104,9 +109,7 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
phy->reset_delay_us = 100;
- phy->ops.acquire = e1000_get_hw_semaphore_82571;
phy->ops.check_reset_block = e1000_check_reset_block_generic;
- phy->ops.release = e1000_put_hw_semaphore_82571;
phy->ops.reset = e1000_phy_hw_reset_generic;
phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82571;
phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic;
@@ -124,6 +127,8 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
phy->ops.read_reg = e1000_read_phy_reg_igp;
phy->ops.write_reg = e1000_write_phy_reg_igp;
+ phy->ops.acquire = e1000_get_hw_semaphore_82571;
+ phy->ops.release = e1000_put_hw_semaphore_82571;
/* This uses above function pointers */
ret_val = e1000_get_phy_id_82571(hw);
@@ -145,6 +150,8 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
phy->ops.get_cable_length = e1000_get_cable_length_m88;
phy->ops.read_reg = e1000_read_phy_reg_m88;
phy->ops.write_reg = e1000_write_phy_reg_m88;
+ phy->ops.acquire = e1000_get_hw_semaphore_82571;
+ phy->ops.release = e1000_put_hw_semaphore_82571;
/* This uses above function pointers */
ret_val = e1000_get_phy_id_82571(hw);
@@ -158,6 +165,8 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
break;
case e1000_82574:
case e1000_82583:
+ E1000_MUTEX_INIT(&dev_spec->swflag_mutex);
+
phy->type = e1000_phy_bm;
phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
phy->ops.get_info = e1000_get_phy_info_m88;
@@ -167,6 +176,8 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
phy->ops.get_cable_length = e1000_get_cable_length_m88;
phy->ops.read_reg = e1000_read_phy_reg_bm2;
phy->ops.write_reg = e1000_write_phy_reg_bm2;
+ phy->ops.acquire = e1000_get_hw_semaphore_82574;
+ phy->ops.release = e1000_put_hw_semaphore_82574;
/* This uses above function pointers */
ret_val = e1000_get_phy_id_82571(hw);
@@ -250,9 +261,18 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
}
/* Function Pointers */
- nvm->ops.acquire = e1000_acquire_nvm_82571;
+ switch (hw->mac.type) {
+ case e1000_82574:
+ case e1000_82583:
+ nvm->ops.acquire = e1000_get_hw_semaphore_82574;
+ nvm->ops.release = e1000_put_hw_semaphore_82574;
+ break;
+ default:
+ nvm->ops.acquire = e1000_acquire_nvm_82571;
+ nvm->ops.release = e1000_release_nvm_82571;
+ break;
+ }
nvm->ops.read = e1000_read_nvm_eerd;
- nvm->ops.release = e1000_release_nvm_82571;
nvm->ops.update = e1000_update_nvm_checksum_82571;
nvm->ops.validate = e1000_validate_nvm_checksum_82571;
nvm->ops.valid_led_default = e1000_valid_led_default_82571;
@@ -578,6 +598,101 @@ static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
}
/**
+ * e1000_get_hw_semaphore_82573 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore during reset.
+ *
+ **/
+static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw)
+{
+ u32 extcnf_ctrl;
+ s32 ret_val = E1000_SUCCESS;
+ s32 i = 0;
+
+ DEBUGFUNC("e1000_get_hw_semaphore_82573");
+
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+ do {
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+ break;
+
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+ msec_delay(2);
+ i++;
+ } while (i < MDIO_OWNERSHIP_TIMEOUT);
+
+ if (i == MDIO_OWNERSHIP_TIMEOUT) {
+ /* Release semaphores */
+ e1000_put_hw_semaphore_82573(hw);
+ DEBUGOUT("Driver can't access the PHY\n");
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_put_hw_semaphore_82573 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used during reset.
+ *
+ **/
+static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw)
+{
+ u32 extcnf_ctrl;
+
+ DEBUGFUNC("e1000_put_hw_semaphore_82573");
+
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+}
+
+/**
+ * e1000_get_hw_semaphore_82574 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM.
+ *
+ **/
+static s32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw)
+{
+ s32 ret_val;
+
+ DEBUGFUNC("e1000_get_hw_semaphore_82574");
+
+ E1000_MUTEX_LOCK(&hw->dev_spec._82571.swflag_mutex);
+ ret_val = e1000_get_hw_semaphore_82573(hw);
+ if (ret_val)
+ E1000_MUTEX_UNLOCK(&hw->dev_spec._82571.swflag_mutex);
+ return ret_val;
+}
+
+/**
+ * e1000_put_hw_semaphore_82574 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ *
+ **/
+static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_put_hw_semaphore_82574");
+
+ e1000_put_hw_semaphore_82573(hw);
+ E1000_MUTEX_UNLOCK(&hw->dev_spec._82571.swflag_mutex);
+}
+
+/**
* e1000_acquire_nvm_82571 - Request for access to the EEPROM
* @hw: pointer to the HW structure
*
@@ -598,8 +713,6 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
switch (hw->mac.type) {
case e1000_82573:
- case e1000_82574:
- case e1000_82583:
break;
default:
ret_val = e1000_acquire_nvm_generic(hw);
@@ -926,9 +1039,8 @@ out:
**/
static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
{
- u32 ctrl, extcnf_ctrl, ctrl_ext, icr;
+ u32 ctrl, ctrl_ext, icr;
s32 ret_val;
- u16 i = 0;
DEBUGFUNC("e1000_reset_hw_82571");
@@ -955,33 +1067,33 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
*/
switch (hw->mac.type) {
case e1000_82573:
+ ret_val = e1000_get_hw_semaphore_82573(hw);
+ break;
case e1000_82574:
case e1000_82583:
- extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
- extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
-
- do {
- E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
- extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
-
- if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
- break;
-
- extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
-
- msec_delay(2);
- i++;
- } while (i < MDIO_OWNERSHIP_TIMEOUT);
+ ret_val = e1000_get_hw_semaphore_82574(hw);
break;
default:
break;
}
+ if (ret_val)
+ DEBUGOUT("Cannot acquire MDIO ownership\n");
ctrl = E1000_READ_REG(hw, E1000_CTRL);
DEBUGOUT("Issuing a global reset to MAC\n");
E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+ /* Must release MDIO ownership and mutex after MAC reset. */
+ switch (hw->mac.type) {
+ case e1000_82574:
+ case e1000_82583:
+ e1000_put_hw_semaphore_82574(hw);
+ break;
+ default:
+ break;
+ }
+
if (hw->nvm.type == e1000_nvm_flash_hw) {
usec_delay(10);
ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
@@ -1015,12 +1127,14 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
icr = E1000_READ_REG(hw, E1000_ICR);
- /* Install any alternate MAC address into RAR0 */
- ret_val = e1000_check_alt_mac_addr_generic(hw);
- if (ret_val)
- goto out;
+ if (hw->mac.type == e1000_82571) {
+ /* Install any alternate MAC address into RAR0 */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+ if (ret_val)
+ goto out;
- e1000_set_laa_state_82571(hw, TRUE);
+ e1000_set_laa_state_82571(hw, TRUE);
+ }
/* Reinitialize the 82571 serdes link state machine */
if (hw->phy.media_type == e1000_media_type_internal_serdes)
@@ -1330,6 +1444,42 @@ static s32 e1000_led_on_82574(struct e1000_hw *hw)
return E1000_SUCCESS;
}
+/**
+ * e1000_check_phy_82574 - check 82574 phy hung state
+ * @hw: pointer to the HW structure
+ *
+ * Returns whether phy is hung or not
+ **/
+bool e1000_check_phy_82574(struct e1000_hw *hw)
+{
+ u16 status_1kbt = 0;
+ u16 receive_errors = 0;
+ bool phy_hung = FALSE;
+ s32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_check_phy_82574");
+
+ /*
+ * Read PHY Receive Error counter first, if its is max - all F's then
+ * read the Base1000T status register If both are max then PHY is hung.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, E1000_RECEIVE_ERROR_COUNTER,
+ &receive_errors);
+ if (ret_val)
+ goto out;
+ if (receive_errors == E1000_RECEIVE_ERROR_MAX) {
+ ret_val = hw->phy.ops.read_reg(hw, E1000_BASE1000T_STATUS,
+ &status_1kbt);
+ if (ret_val)
+ goto out;
+ if ((status_1kbt & E1000_IDLE_ERROR_COUNT_MASK) ==
+ E1000_IDLE_ERROR_COUNT_MASK)
+ phy_hung = TRUE;
+ }
+out:
+ return phy_hung;
+}
+
/**
* e1000_setup_link_82571 - Setup flow control and link settings
@@ -1460,6 +1610,8 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
u32 rxcw;
u32 ctrl;
u32 status;
+ u32 txcw;
+ u32 i;
s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_check_for_serdes_link_82571");
@@ -1482,8 +1634,10 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
e1000_serdes_link_autoneg_progress;
mac->serdes_has_link = FALSE;
DEBUGOUT("AN_UP -> AN_PROG\n");
+ } else {
+ mac->serdes_has_link = TRUE;
}
- break;
+ break;
case e1000_serdes_link_forced_up:
/*
@@ -1491,8 +1645,10 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
* auto-negotiation in the TXCW register and disable
* forced link in the Device Control register in an
* attempt to auto-negotiate with our link partner.
+ * If the partner code word is null, stop forcing
+ * and restart auto negotiation.
*/
- if (rxcw & E1000_RXCW_C) {
+ if ((rxcw & E1000_RXCW_C) || !(rxcw & E1000_RXCW_CW)) {
/* Enable autoneg, and unforce link up */
E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
E1000_WRITE_REG(hw, E1000_CTRL,
@@ -1501,6 +1657,8 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
e1000_serdes_link_autoneg_progress;
mac->serdes_has_link = FALSE;
DEBUGOUT("FORCED_UP -> AN_PROG\n");
+ } else {
+ mac->serdes_has_link = TRUE;
}
break;
@@ -1559,6 +1717,7 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
(ctrl & ~E1000_CTRL_SLU));
mac->serdes_link_state =
e1000_serdes_link_autoneg_progress;
+ mac->serdes_has_link = FALSE;
DEBUGOUT("DOWN -> AN_PROG\n");
break;
}
@@ -1569,16 +1728,32 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
DEBUGOUT("ANYSTATE -> DOWN\n");
} else {
/*
- * We have sync, and can tolerate one invalid (IV)
- * codeword before declaring link down, so reread
- * to look again.
+ * Check several times, if Sync and Config
+ * both are consistently 1 then simply ignore
+ * the Invalid bit and restart Autoneg
*/
- usec_delay(10);
- rxcw = E1000_READ_REG(hw, E1000_RXCW);
- if (rxcw & E1000_RXCW_IV) {
- mac->serdes_link_state = e1000_serdes_link_down;
+ for (i = 0; i < AN_RETRY_COUNT; i++) {
+ usec_delay(10);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+ if ((rxcw & E1000_RXCW_IV) &&
+ !((rxcw & E1000_RXCW_SYNCH) &&
+ (rxcw & E1000_RXCW_C))) {
+ mac->serdes_has_link = FALSE;
+ mac->serdes_link_state =
+ e1000_serdes_link_down;
+ DEBUGOUT("ANYSTATE -> DOWN\n");
+ break;
+ }
+ }
+
+ if (i == AN_RETRY_COUNT) {
+ txcw = E1000_READ_REG(hw, E1000_TXCW);
+ txcw |= E1000_TXCW_ANE;
+ E1000_WRITE_REG(hw, E1000_TXCW, txcw);
+ mac->serdes_link_state =
+ e1000_serdes_link_autoneg_progress;
mac->serdes_has_link = FALSE;
- DEBUGOUT("ANYSTATE -> DOWN\n");
+ DEBUGOUT("ANYSTATE -> AN_PROG\n");
}
}
}
@@ -1736,14 +1911,16 @@ static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw)
DEBUGFUNC("e1000_read_mac_addr_82571");
- /*
- * 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;
+ if (hw->mac.type == e1000_82571) {
+ /*
+ * 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);
diff --git a/sys/dev/e1000/e1000_82571.h b/sys/dev/e1000/e1000_82571.h
index 5e66793c0138..c76f16fe1798 100644
--- a/sys/dev/e1000/e1000_82571.h
+++ b/sys/dev/e1000/e1000_82571.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2008, Intel Corporation
+ Copyright (c) 2001-2010, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,7 @@
(ID_LED_DEF1_DEF2))
#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+#define AN_RETRY_COUNT 5 /* Autoneg Retry Count value */
/* Intr Throttling - RW */
#define E1000_EITR_82574(_n) (0x000E8 + (0x4 * (_n)))
@@ -53,6 +54,11 @@
#define E1000_RXCFGL 0x0B634 /* TimeSync Rx EtherType & Msg Type Reg - RW */
+#define E1000_BASE1000T_STATUS 10
+#define E1000_IDLE_ERROR_COUNT_MASK 0xFF
+#define E1000_RECEIVE_ERROR_COUNTER 21
+#define E1000_RECEIVE_ERROR_MAX 0xFFFF
+bool e1000_check_phy_82574(struct e1000_hw *hw);
bool e1000_get_laa_state_82571(struct e1000_hw *hw);
void e1000_set_laa_state_82571(struct e1000_hw *hw, bool state);
diff --git a/sys/dev/e1000/e1000_82575.c b/sys/dev/e1000/e1000_82575.c
index 65b3ce47a41a..bc04b452e495 100644
--- a/sys/dev/e1000/e1000_82575.c
+++ b/sys/dev/e1000/e1000_82575.c
@@ -85,6 +85,7 @@ static void e1000_power_down_phy_copper_82575(struct e1000_hw *hw);
static void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw);
static void e1000_power_up_serdes_link_82575(struct e1000_hw *hw);
static s32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw);
+static s32 e1000_reset_mdicnfg_82580(struct e1000_hw *hw);
static const u16 e1000_82580_rxpbs_table[] =
{ 36, 72, 144, 1, 2, 4, 8, 16,
@@ -92,6 +93,37 @@ static const u16 e1000_82580_rxpbs_table[] =
#define E1000_82580_RXPBS_TABLE_SIZE \
(sizeof(e1000_82580_rxpbs_table)/sizeof(u16))
+
+/**
+ * e1000_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
+ * @hw: pointer to the HW structure
+ *
+ * Called to determine if the I2C pins are being used for I2C or as an
+ * external MDIO interface since the two options are mutually exclusive.
+ **/
+static bool e1000_sgmii_uses_mdio_82575(struct e1000_hw *hw)
+{
+ u32 reg = 0;
+ bool ext_mdio = FALSE;
+
+ DEBUGFUNC("e1000_sgmii_uses_mdio_82575");
+
+ switch (hw->mac.type) {
+ case e1000_82575:
+ case e1000_82576:
+ reg = E1000_READ_REG(hw, E1000_MDIC);
+ ext_mdio = !!(reg & E1000_MDIC_DEST);
+ break;
+ case e1000_82580:
+ reg = E1000_READ_REG(hw, E1000_MDICNFG);
+ ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO);
+ break;
+ default:
+ break;
+ }
+ return ext_mdio;
+}
+
/**
* e1000_init_phy_params_82575 - Init PHY func ptrs.
* @hw: pointer to the HW structure
@@ -100,6 +132,7 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val = E1000_SUCCESS;
+ u32 ctrl_ext;
DEBUGFUNC("e1000_init_phy_params_82575");
@@ -120,16 +153,26 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw)
phy->ops.get_cfg_done = e1000_get_cfg_done_82575;
phy->ops.release = e1000_release_phy_82575;
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+
if (e1000_sgmii_active_82575(hw)) {
phy->ops.reset = e1000_phy_hw_reset_sgmii_82575;
+ ctrl_ext |= E1000_CTRL_I2C_ENA;
+ } else {
+ phy->ops.reset = e1000_phy_hw_reset_generic;
+ ctrl_ext &= ~E1000_CTRL_I2C_ENA;
+ }
+
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+ e1000_reset_mdicnfg_82580(hw);
+
+ if (e1000_sgmii_active_82575(hw) && !e1000_sgmii_uses_mdio_82575(hw)) {
phy->ops.read_reg = e1000_read_phy_reg_sgmii_82575;
phy->ops.write_reg = e1000_write_phy_reg_sgmii_82575;
} else if (hw->mac.type >= e1000_82580) {
- phy->ops.reset = e1000_phy_hw_reset_generic;
phy->ops.read_reg = e1000_read_phy_reg_82580;
phy->ops.write_reg = e1000_write_phy_reg_82580;
} else {
- phy->ops.reset = e1000_phy_hw_reset_generic;
phy->ops.read_reg = e1000_read_phy_reg_igp;
phy->ops.write_reg = e1000_write_phy_reg_igp;
}
@@ -256,27 +299,15 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw)
switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
case E1000_CTRL_EXT_LINK_MODE_SGMII:
dev_spec->sgmii_active = TRUE;
- ctrl_ext |= E1000_CTRL_I2C_ENA;
break;
case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
hw->phy.media_type = e1000_media_type_internal_serdes;
- ctrl_ext |= E1000_CTRL_I2C_ENA;
break;
default:
- ctrl_ext &= ~E1000_CTRL_I2C_ENA;
break;
}
- E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
-
- /*
- * if using i2c make certain the MDICNFG register is cleared to prevent
- * communications from being misrouted to the mdic registers
- */
- if ((ctrl_ext & E1000_CTRL_I2C_ENA) && (hw->mac.type == e1000_82580))
- E1000_WRITE_REG(hw, E1000_MDICNFG, 0);
-
/* Set mta register count */
mac->mta_reg_count = 128;
/* Set uta register count */
@@ -367,6 +398,7 @@ void e1000_init_function_pointers_82575(struct e1000_hw *hw)
hw->mac.ops.init_params = e1000_init_mac_params_82575;
hw->nvm.ops.init_params = e1000_init_nvm_params_82575;
hw->phy.ops.init_params = e1000_init_phy_params_82575;
+ hw->mbx.ops.init_params = e1000_init_mbx_params_pf;
}
/**
@@ -492,6 +524,7 @@ static s32 e1000_get_phy_id_82575(struct e1000_hw *hw)
s32 ret_val = E1000_SUCCESS;
u16 phy_id;
u32 ctrl_ext;
+ u32 mdic;
DEBUGFUNC("e1000_get_phy_id_82575");
@@ -508,6 +541,28 @@ static s32 e1000_get_phy_id_82575(struct e1000_hw *hw)
goto out;
}
+ if (e1000_sgmii_uses_mdio_82575(hw)) {
+ switch (hw->mac.type) {
+ case e1000_82575:
+ case e1000_82576:
+ mdic = E1000_READ_REG(hw, E1000_MDIC);
+ mdic &= E1000_MDIC_PHY_MASK;
+ phy->addr = mdic >> E1000_MDIC_PHY_SHIFT;
+ break;
+ case e1000_82580:
+ mdic = E1000_READ_REG(hw, E1000_MDICNFG);
+ mdic &= E1000_MDICNFG_PHY_MASK;
+ phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT;
+ break;
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ break;
+ }
+ ret_val = e1000_get_phy_id(hw);
+ goto out;
+ }
+
/* Power on sgmii phy if it is disabled */
ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
E1000_WRITE_REG(hw, E1000_CTRL_EXT,
@@ -1243,6 +1298,7 @@ static s32 e1000_setup_serdes_link_82575(struct e1000_hw *hw)
case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
/* disable PCS autoneg and support parallel detect only */
pcs_autoneg = FALSE;
+ /* fall through to default case */
default:
/*
* non-SGMII modes only supports a speed of 1000/Full for the
@@ -1638,6 +1694,39 @@ out:
return ret_val;
}
+
+/**
+ * e1000_vmdq_set_anti_spoofing_pf - enable or disable anti-spoofing
+ * @hw: pointer to the hardware struct
+ * @enable: state to enter, either enabled or disabled
+ * @pf: Physical Function pool - do not set anti-spoofing for the PF
+ *
+ * enables/disables L2 switch anti-spoofing functionality.
+ **/
+void e1000_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf)
+{
+ u32 dtxswc;
+
+ 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 + MAX_NUM_VFS));
+ } else {
+ dtxswc &= ~(E1000_DTXSWC_MAC_SPOOF_MASK |
+ E1000_DTXSWC_VLAN_SPOOF_MASK);
+ }
+ E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc);
+ break;
+ default:
+ break;
+ }
+}
+
/**
* e1000_vmdq_set_loopback_pf - enable or disable vmdq loopback
* @hw: pointer to the hardware struct
@@ -1739,6 +1828,45 @@ out:
}
/**
+ * e1000_reset_mdicnfg_82580 - Reset MDICNFG destination and com_mdio bits
+ * @hw: pointer to the HW structure
+ *
+ * This resets the the MDICNFG.Destination and MDICNFG.Com_MDIO bits based on
+ * the values found in the EEPROM. This addresses an issue in which these
+ * bits are not restored from EEPROM after reset.
+ **/
+static s32 e1000_reset_mdicnfg_82580(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_SUCCESS;
+ u32 mdicnfg;
+ u16 nvm_data;
+
+ DEBUGFUNC("e1000_reset_mdicnfg_82580");
+
+ if (hw->mac.type != e1000_82580)
+ goto out;
+ if (!e1000_sgmii_active_82575(hw))
+ goto out;
+
+ ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A +
+ NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1,
+ &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ mdicnfg = E1000_READ_REG(hw, E1000_MDICNFG);
+ if (nvm_data & NVM_WORD24_EXT_MDIO)
+ mdicnfg |= E1000_MDICNFG_EXT_MDIO;
+ if (nvm_data & NVM_WORD24_COM_MDIO)
+ mdicnfg |= E1000_MDICNFG_COM_MDIO;
+ E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg);
+out:
+ return ret_val;
+}
+
+/**
* e1000_reset_hw_82580 - Reset hardware
* @hw: pointer to the HW structure
*
@@ -1814,6 +1942,10 @@ static s32 e1000_reset_hw_82580(struct e1000_hw *hw)
E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
icr = E1000_READ_REG(hw, E1000_ICR);
+ ret_val = e1000_reset_mdicnfg_82580(hw);
+ if (ret_val)
+ DEBUGOUT("Could not reset MDICNFG based on EEPROM\n");
+
/* Install any alternate MAC address into RAR0 */
ret_val = e1000_check_alt_mac_addr_generic(hw);
diff --git a/sys/dev/e1000/e1000_82575.h b/sys/dev/e1000/e1000_82575.h
index 1fc7e26dd590..eb05262d3863 100644
--- a/sys/dev/e1000/e1000_82575.h
+++ b/sys/dev/e1000/e1000_82575.h
@@ -458,6 +458,18 @@ struct e1000_adv_tx_context_desc {
/* RX packet buffer size defines */
#define E1000_RXPBS_SIZE_MASK_82576 0x0000007F
void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable);
+void e1000_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf);
void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable);
+enum e1000_promisc_type {
+ e1000_promisc_disabled = 0, /* all promisc modes disabled */
+ e1000_promisc_unicast = 1, /* unicast promiscuous enabled */
+ e1000_promisc_multicast = 2, /* multicast promiscuous enabled */
+ e1000_promisc_enabled = 3, /* both uni and multicast promisc */
+ e1000_num_promisc_types
+};
+
+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);
#endif /* _E1000_82575_H_ */
diff --git a/sys/dev/e1000/e1000_api.c b/sys/dev/e1000/e1000_api.c
index bf9fa2abb903..b3a7ef9a6cb6 100644
--- a/sys/dev/e1000/e1000_api.c
+++ b/sys/dev/e1000/e1000_api.c
@@ -112,6 +112,31 @@ out:
return ret_val;
}
+/**
+ * e1000_init_mbx_params - Initialize mailbox function pointers
+ * @hw: pointer to the HW structure
+ *
+ * This function initializes the function pointers for the PHY
+ * set of functions. Called by drivers or by e1000_setup_init_funcs.
+ **/
+s32 e1000_init_mbx_params(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_SUCCESS;
+
+ if (hw->mbx.ops.init_params) {
+ ret_val = hw->mbx.ops.init_params(hw);
+ if (ret_val) {
+ DEBUGOUT("Mailbox Initialization Error\n");
+ goto out;
+ }
+ } else {
+ DEBUGOUT("mbx.init_mbx_params was NULL\n");
+ ret_val = -E1000_ERR_CONFIG;
+ }
+
+out:
+ return ret_val;
+}
/**
* e1000_set_mac_type - Sets MAC type
@@ -251,6 +276,8 @@ s32 e1000_set_mac_type(struct e1000_hw *hw)
break;
case E1000_DEV_ID_ICH10_D_BM_LM:
case E1000_DEV_ID_ICH10_D_BM_LF:
+ case E1000_DEV_ID_ICH10_D_BM_V:
+ case E1000_DEV_ID_ICH10_HANKSVILLE:
mac->type = e1000_ich10lan;
break;
case E1000_DEV_ID_PCH_D_HV_DM:
@@ -259,6 +286,10 @@ s32 e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_PCH_M_HV_LC:
mac->type = e1000_pchlan;
break;
+ case E1000_DEV_ID_PCH2_LV_LM:
+ case E1000_DEV_ID_PCH2_LV_V:
+ mac->type = e1000_pch2lan;
+ break;
case E1000_DEV_ID_82575EB_COPPER:
case E1000_DEV_ID_82575EB_FIBER_SERDES:
case E1000_DEV_ID_82575GB_QUAD_COPPER:
@@ -269,6 +300,7 @@ s32 e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82576_FIBER:
case E1000_DEV_ID_82576_SERDES:
case E1000_DEV_ID_82576_QUAD_COPPER:
+ case E1000_DEV_ID_82576_QUAD_COPPER_ET2:
case E1000_DEV_ID_82576_NS:
case E1000_DEV_ID_82576_NS_SERDES:
case E1000_DEV_ID_82576_SERDES_QUAD:
@@ -279,8 +311,14 @@ s32 e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82580_SERDES:
case E1000_DEV_ID_82580_SGMII:
case E1000_DEV_ID_82580_COPPER_DUAL:
+ case E1000_DEV_ID_82580_QUAD_FIBER:
+ case E1000_DEV_ID_DH89XXCC_SGMII:
+ case E1000_DEV_ID_DH89XXCC_SERDES:
mac->type = e1000_82580;
break;
+ case E1000_DEV_ID_82576_VF:
+ mac->type = e1000_vfadapt;
+ break;
default:
/* Should never have loaded on this device */
ret_val = -E1000_ERR_MAC_INIT;
@@ -326,6 +364,7 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device)
e1000_init_mac_ops_generic(hw);
e1000_init_phy_ops_generic(hw);
e1000_init_nvm_ops_generic(hw);
+ e1000_init_mbx_ops_generic(hw);
/*
* Set up the init function pointers. These are functions within the
@@ -367,6 +406,7 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device)
case e1000_ich9lan:
case e1000_ich10lan:
case e1000_pchlan:
+ case e1000_pch2lan:
e1000_init_function_pointers_ich8lan(hw);
break;
case e1000_82575:
@@ -374,6 +414,9 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device)
case e1000_82580:
e1000_init_function_pointers_82575(hw);
break;
+ case e1000_vfadapt:
+ e1000_init_function_pointers_vf(hw);
+ break;
default:
DEBUGOUT("Hardware not supported\n");
ret_val = -E1000_ERR_CONFIG;
@@ -396,6 +439,10 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device)
ret_val = e1000_init_phy_params(hw);
if (ret_val)
goto out;
+
+ ret_val = e1000_init_mbx_params(hw);
+ if (ret_val)
+ goto out;
}
out:
@@ -1095,6 +1142,37 @@ s32 e1000_read_mac_addr(struct e1000_hw *hw)
}
/**
+ * e1000_read_pba_string - Read device part number string
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+s32 e1000_read_pba_string(struct e1000_hw *hw, u8 *pba_num, u32 pba_num_size)
+{
+ return e1000_read_pba_string_generic(hw, pba_num, pba_num_size);
+}
+
+/**
+ * e1000_read_pba_length - Read device part number string length
+ * @hw: pointer to the HW structure
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number length from the EEPROM and
+ * stores the value in pba_num.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+s32 e1000_read_pba_length(struct e1000_hw *hw, u32 *pba_num_size)
+{
+ return e1000_read_pba_length_generic(hw, pba_num_size);
+}
+
+/**
* e1000_read_pba_num - Read device part number
* @hw: pointer to the HW structure
* @pba_num: pointer to device part number
diff --git a/sys/dev/e1000/e1000_api.h b/sys/dev/e1000/e1000_api.h
index b7bc14c8f314..36ba712857fb 100644
--- a/sys/dev/e1000/e1000_api.h
+++ b/sys/dev/e1000/e1000_api.h
@@ -55,6 +55,7 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device);
s32 e1000_init_mac_params(struct e1000_hw *hw);
s32 e1000_init_nvm_params(struct e1000_hw *hw);
s32 e1000_init_phy_params(struct e1000_hw *hw);
+s32 e1000_init_mbx_params(struct e1000_hw *hw);
s32 e1000_get_bus_info(struct e1000_hw *hw);
void e1000_clear_vfta(struct e1000_hw *hw);
void e1000_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
@@ -96,6 +97,9 @@ void e1000_power_up_phy(struct e1000_hw *hw);
void e1000_power_down_phy(struct e1000_hw *hw);
s32 e1000_read_mac_addr(struct e1000_hw *hw);
s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *part_num);
+s32 e1000_read_pba_string(struct e1000_hw *hw, u8 *pba_num,
+ u32 pba_num_size);
+s32 e1000_read_pba_length(struct e1000_hw *hw, u32 *pba_num_size);
void e1000_reload_nvm(struct e1000_hw *hw);
s32 e1000_update_nvm_checksum(struct e1000_hw *hw);
s32 e1000_validate_nvm_checksum(struct e1000_hw *hw);
diff --git a/sys/dev/e1000/e1000_defines.h b/sys/dev/e1000/e1000_defines.h
index 7ac5d8b8b1d7..5d09ad92dfa0 100644
--- a/sys/dev/e1000/e1000_defines.h
+++ b/sys/dev/e1000/e1000_defines.h
@@ -49,6 +49,8 @@
#define E1000_WUC_LSCWO 0x00000020 /* Link Status wake up override */
#define E1000_WUC_SPM 0x80000000 /* Enable SPM */
#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */
+#define E1000_WUC_FLX6_PHY 0x4000 /* Flexible Filter 6 Enable */
+#define E1000_WUC_FLX7_PHY 0x8000 /* Flexible Filter 7 Enable */
/* Wake Up Filter Control */
#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
@@ -73,6 +75,8 @@
#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
#define E1000_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */
#define E1000_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */
+#define E1000_WUFC_FLX6 0x00400000 /* Flexible Filter 6 Enable */
+#define E1000_WUFC_FLX7 0x00800000 /* Flexible Filter 7 Enable */
#define E1000_WUFC_ALL_FILTERS_PHY_4 0x0000F0FF /*Mask for all wakeup filters*/
#define E1000_WUFC_FLX_OFFSET_PHY 12 /* Offset to the Flexible Filters bits */
#define E1000_WUFC_FLX_FILTERS_PHY_4 0x0000F000 /*Mask for 4 flexible filters*/
@@ -80,9 +84,11 @@
#define E1000_WUFC_FLX_FILTERS_PHY_6 0x0000F600 /*Mask for 6 flexible filters*/
#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */
#define E1000_WUFC_ALL_FILTERS_6 0x003F00FF /* Mask for all 6 wakeup filters*/
+#define E1000_WUFC_ALL_FILTERS_8 0x00FF00FF /* Mask for all 8 wakeup filters*/
#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */
#define E1000_WUFC_FLX_FILTERS 0x000F0000 /*Mask for the 4 flexible filters */
#define E1000_WUFC_FLX_FILTERS_6 0x003F0000 /* Mask for 6 flexible filters */
+#define E1000_WUFC_FLX_FILTERS_8 0x00FF0000 /* Mask for 8 flexible filters */
/*
* For 82576 to utilize Extended filter masks in addition to
* existing (filter) masks
@@ -109,10 +115,15 @@
#define E1000_WUS_FLX3 E1000_WUFC_FLX3
#define E1000_WUS_FLX4 E1000_WUFC_FLX4
#define E1000_WUS_FLX5 E1000_WUFC_FLX5
+#define E1000_WUS_FLX6 E1000_WUFC_FLX6
+#define E1000_WUS_FLX7 E1000_WUFC_FLX7
#define E1000_WUS_FLX4_PHY E1000_WUFC_FLX4_PHY
#define E1000_WUS_FLX5_PHY E1000_WUFC_FLX5_PHY
+#define E1000_WUS_FLX6_PHY 0x0400
+#define E1000_WUS_FLX7_PHY 0x0800
#define E1000_WUS_FLX_FILTERS E1000_WUFC_FLX_FILTERS
#define E1000_WUS_FLX_FILTERS_6 E1000_WUFC_FLX_FILTERS_6
+#define E1000_WUS_FLX_FILTERS_8 E1000_WUFC_FLX_FILTERS_8
#define E1000_WUS_FLX_FILTERS_PHY_6 E1000_WUFC_FLX_FILTERS_PHY_6
/* Wake Up Packet Length */
@@ -122,6 +133,8 @@
#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
/* Six Flexible Filters are supported */
#define E1000_FLEXIBLE_FILTER_COUNT_MAX_6 6
+/* Eight Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX_8 8
/* Two Extended Flexible Filters are supported (82576) */
#define E1000_EXT_FLEXIBLE_FILTER_COUNT_MAX 2
#define E1000_FHFT_LENGTH_OFFSET 0xFC /* Length byte in FHFT */
@@ -132,6 +145,7 @@
#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
#define E1000_FFLT_SIZE_6 E1000_FLEXIBLE_FILTER_COUNT_MAX_6
+#define E1000_FFLT_SIZE_8 E1000_FLEXIBLE_FILTER_COUNT_MAX_8
#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
@@ -710,6 +724,7 @@
#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001
#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE 0x00000008
#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020
+#define E1000_EXTCNF_CTRL_GATE_PHY_CFG 0x00000080
#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000
#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16
#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000
@@ -1013,6 +1028,9 @@
#define E1000_ERR_SWFW_SYNC 13
#define E1000_NOT_IMPLEMENTED 14
#define E1000_ERR_MBX 15
+#define E1000_ERR_INVALID_ARGUMENT 16
+#define E1000_ERR_NO_SPACE 17
+#define E1000_ERR_NVM_PBA_SECTION 18
/* Loop limit on how long we wait for auto-negotiation to complete */
#define FIBER_LINK_UP_LIMIT 50
@@ -1106,6 +1124,11 @@
#define E1000_IMIR_PRIORITY_SHIFT 29 /* IMIR Priority Shift */
#define E1000_IMIREXT_CLEAR_MASK 0x7FFFF /* IMIREXT Reg Clear Mask */
+#define E1000_MDICNFG_EXT_MDIO 0x80000000 /* MDI ext/int destination */
+#define E1000_MDICNFG_COM_MDIO 0x40000000 /* MDI shared w/ lan 0 */
+#define E1000_MDICNFG_PHY_MASK 0x03E00000
+#define E1000_MDICNFG_PHY_SHIFT 21
+
/* PCI Express Control */
#define E1000_GCR_RXD_NO_SNOOP 0x00000001
#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002
@@ -1301,6 +1324,10 @@
#define NVM_82580_LAN_FUNC_OFFSET(a) (a ? (0x40 + (0x40 * a)) : 0)
+/* Mask bits for fields in Word 0x24 of the NVM */
+#define NVM_WORD24_COM_MDIO 0x0008 /* MDIO interface shared */
+#define NVM_WORD24_EXT_MDIO 0x0004 /* MDIO accesses routed external */
+
/* Mask bits for fields in Word 0x0f of the NVM */
#define NVM_WORD0F_PAUSE_MASK 0x3000
#define NVM_WORD0F_PAUSE 0x1000
@@ -1312,12 +1339,19 @@
/* Mask bits for fields in Word 0x1a of the NVM */
#define NVM_WORD1A_ASPM_MASK 0x000C
+/* Mask bits for fields in Word 0x03 of the EEPROM */
+#define NVM_COMPAT_LOM 0x0800
+
+/* length of string needed to store PBA number */
+#define E1000_PBANUM_LENGTH 11
+
/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
#define NVM_SUM 0xBABA
#define NVM_MAC_ADDR_OFFSET 0
#define NVM_PBA_OFFSET_0 8
#define NVM_PBA_OFFSET_1 9
+#define NVM_PBA_PTR_GUARD 0xFAFA
#define NVM_RESERVED_WORD 0xFFFF
#define NVM_PHY_CLASS_A 0x8000
#define NVM_SERDES_AMPLITUDE_MASK 0x000F
@@ -1422,6 +1456,7 @@
#define BME1000_E_PHY_ID_R2 0x01410CB1
#define I82577_E_PHY_ID 0x01540050
#define I82578_E_PHY_ID 0x004DD040
+#define I82579_E_PHY_ID 0x01540090
#define I82580_I_PHY_ID 0x015403A0
#define IGP04E1000_E_PHY_ID 0x02A80391
#define M88_VENDOR 0x0141
@@ -1622,6 +1657,7 @@
#define E1000_MDIC_READY 0x10000000
#define E1000_MDIC_INT_EN 0x20000000
#define E1000_MDIC_ERROR 0x40000000
+#define E1000_MDIC_DEST 0x80000000
/* SerDes Control */
#define E1000_GEN_CTL_READY 0x80000000
@@ -1683,4 +1719,5 @@
#define E1000_PCIEMISC_LX_DECISION 0x00000080 /* Lx power decision based
on DMA coal */
+
#endif /* _E1000_DEFINES_H_ */
diff --git a/sys/dev/e1000/e1000_hw.h b/sys/dev/e1000/e1000_hw.h
index ce5dffdd67d3..e80e8709331e 100644
--- a/sys/dev/e1000/e1000_hw.h
+++ b/sys/dev/e1000/e1000_hw.h
@@ -120,20 +120,26 @@ struct e1000_hw;
#define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC
#define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD
#define E1000_DEV_ID_ICH10_R_BM_V 0x10CE
+#define E1000_DEV_ID_ICH10_HANKSVILLE 0xF0FE
#define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE
#define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF
+#define E1000_DEV_ID_ICH10_D_BM_V 0x1525
#define E1000_DEV_ID_PCH_M_HV_LM 0x10EA
#define E1000_DEV_ID_PCH_M_HV_LC 0x10EB
#define E1000_DEV_ID_PCH_D_HV_DM 0x10EF
#define E1000_DEV_ID_PCH_D_HV_DC 0x10F0
+#define E1000_DEV_ID_PCH2_LV_LM 0x1502
+#define E1000_DEV_ID_PCH2_LV_V 0x1503
#define E1000_DEV_ID_82576 0x10C9
#define E1000_DEV_ID_82576_FIBER 0x10E6
#define E1000_DEV_ID_82576_SERDES 0x10E7
#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8
+#define E1000_DEV_ID_82576_QUAD_COPPER_ET2 0x1526
#define E1000_DEV_ID_82576_NS 0x150A
#define E1000_DEV_ID_82576_NS_SERDES 0x1518
#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D
+#define E1000_DEV_ID_82576_VF 0x10CA
#define E1000_DEV_ID_82575EB_COPPER 0x10A7
#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9
#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6
@@ -143,6 +149,9 @@ struct e1000_hw;
#define E1000_DEV_ID_82580_SERDES 0x1510
#define E1000_DEV_ID_82580_SGMII 0x1511
#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516
+#define E1000_DEV_ID_82580_QUAD_FIBER 0x1527
+#define E1000_DEV_ID_DH89XXCC_SGMII 0x0436
+#define E1000_DEV_ID_DH89XXCC_SERDES 0x0438
#define E1000_REVISION_0 0
#define E1000_REVISION_1 1
#define E1000_REVISION_2 2
@@ -183,9 +192,11 @@ enum e1000_mac_type {
e1000_ich9lan,
e1000_ich10lan,
e1000_pchlan,
+ e1000_pch2lan,
e1000_82575,
e1000_82576,
e1000_82580,
+ e1000_vfadapt,
e1000_num_macs /* List is 1-based, so subtract 1 for TRUE count. */
};
@@ -226,6 +237,7 @@ enum e1000_phy_type {
e1000_phy_bm,
e1000_phy_82578,
e1000_phy_82577,
+ e1000_phy_82579,
e1000_phy_82580,
e1000_phy_vf,
};
@@ -314,6 +326,9 @@ enum e1000_serdes_link_state {
e1000_serdes_link_forced_up
};
+#define __le16 u16
+#define __le32 u32
+#define __le64 u64
/* Receive Descriptor */
struct e1000_rx_desc {
__le64 buffer_addr; /* Address of the descriptor's data buffer */
@@ -531,6 +546,37 @@ struct e1000_hw_stats {
u64 doosync;
};
+struct e1000_vf_stats {
+ u64 base_gprc;
+ u64 base_gptc;
+ u64 base_gorc;
+ u64 base_gotc;
+ u64 base_mprc;
+ u64 base_gotlbc;
+ u64 base_gptlbc;
+ u64 base_gorlbc;
+ u64 base_gprlbc;
+
+ u32 last_gprc;
+ u32 last_gptc;
+ u32 last_gorc;
+ u32 last_gotc;
+ u32 last_mprc;
+ u32 last_gotlbc;
+ u32 last_gptlbc;
+ u32 last_gorlbc;
+ u32 last_gprlbc;
+
+ u64 gprc;
+ u64 gptc;
+ u64 gorc;
+ u64 gotc;
+ u64 mprc;
+ u64 gotlbc;
+ u64 gptlbc;
+ u64 gorlbc;
+ u64 gprlbc;
+};
struct e1000_phy_stats {
u32 idle_errors;
@@ -581,6 +627,7 @@ struct e1000_host_mng_command_info {
#include "e1000_phy.h"
#include "e1000_nvm.h"
#include "e1000_manage.h"
+#include "e1000_mbx.h"
struct e1000_mac_operations {
/* Function pointers for the MAC. */
@@ -758,12 +805,41 @@ struct e1000_fc_info {
u32 high_water; /* Flow control high-water mark */
u32 low_water; /* Flow control low-water mark */
u16 pause_time; /* Flow control pause timer */
+ u16 refresh_time; /* Flow control refresh timer */
bool send_xon; /* Flow control send XON */
bool strict_ieee; /* Strict IEEE mode */
enum e1000_fc_mode current_mode; /* FC mode in effect */
enum e1000_fc_mode requested_mode; /* FC mode requested by caller */
};
+struct e1000_mbx_operations {
+ s32 (*init_params)(struct e1000_hw *hw);
+ s32 (*read)(struct e1000_hw *, u32 *, u16, u16);
+ s32 (*write)(struct e1000_hw *, u32 *, u16, u16);
+ s32 (*read_posted)(struct e1000_hw *, u32 *, u16, u16);
+ s32 (*write_posted)(struct e1000_hw *, u32 *, u16, u16);
+ s32 (*check_for_msg)(struct e1000_hw *, u16);
+ s32 (*check_for_ack)(struct e1000_hw *, u16);
+ s32 (*check_for_rst)(struct e1000_hw *, u16);
+};
+
+struct e1000_mbx_stats {
+ u32 msgs_tx;
+ u32 msgs_rx;
+
+ u32 acks;
+ u32 reqs;
+ u32 rsts;
+};
+
+struct e1000_mbx_info {
+ struct e1000_mbx_operations ops;
+ struct e1000_mbx_stats stats;
+ u32 timeout;
+ u32 usec_delay;
+ u16 size;
+};
+
struct e1000_dev_spec_82541 {
enum e1000_dsp_config dsp_config;
enum e1000_ffe_config ffe_config;
@@ -784,6 +860,7 @@ struct e1000_dev_spec_82543 {
struct e1000_dev_spec_82571 {
bool laa_is_present;
u32 smb_counter;
+ E1000_MUTEX swflag_mutex;
};
struct e1000_dev_spec_80003es2lan {
@@ -803,6 +880,7 @@ struct e1000_dev_spec_ich8lan {
E1000_MUTEX nvm_mutex;
E1000_MUTEX swflag_mutex;
bool nvm_k1_enabled;
+ bool eee_disable;
};
struct e1000_dev_spec_82575 {
@@ -815,7 +893,6 @@ struct e1000_dev_spec_vf {
u32 v2p_mailbox;
};
-
struct e1000_hw {
void *back;
@@ -828,6 +905,7 @@ struct e1000_hw {
struct e1000_phy_info phy;
struct e1000_nvm_info nvm;
struct e1000_bus_info bus;
+ struct e1000_mbx_info mbx;
struct e1000_host_mng_dhcp_cookie mng_cookie;
union {
diff --git a/sys/dev/e1000/e1000_ich8lan.c b/sys/dev/e1000/e1000_ich8lan.c
index 6b3c25d8218d..fdd517233b5c 100644
--- a/sys/dev/e1000/e1000_ich8lan.c
+++ b/sys/dev/e1000/e1000_ich8lan.c
@@ -58,6 +58,8 @@
* 82577LC Gigabit Network Connection
* 82578DM Gigabit Network Connection
* 82578DC Gigabit Network Connection
+ * 82579LM Gigabit Network Connection
+ * 82579V Gigabit Network Connection
*/
#include "e1000_api.h"
@@ -71,6 +73,8 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw);
static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw);
static void e1000_release_nvm_ich8lan(struct e1000_hw *hw);
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 s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw);
static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw);
static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
@@ -126,6 +130,8 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw);
static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw);
static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw);
static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
+static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
+static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
/* Offset 04h HSFSTS */
@@ -177,7 +183,7 @@ union ich8_hws_flash_regacc {
static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
- u32 ctrl;
+ u32 ctrl, fwsm;
s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_init_phy_params_pchlan");
@@ -200,15 +206,14 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
- if ((hw->mac.type == e1000_pchlan) &&
- (!(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))) {
-
- /*
- * The MAC-PHY interconnect may still be in SMBus mode
- * after Sx->S0. Toggle the LANPHYPC Value bit to force
- * the interconnect to PCIe mode, but only if there is no
- * firmware present otherwise firmware will have done it.
- */
+ /*
+ * The MAC-PHY interconnect may still be in SMBus mode
+ * after Sx->S0. If the manageability engine (ME) is
+ * disabled, then toggle the LANPHYPC Value bit to force
+ * the interconnect to PCIe mode.
+ */
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+ if (!(fwsm & E1000_ICH_FWSM_FW_VALID)) {
ctrl = E1000_READ_REG(hw, E1000_CTRL);
ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE;
ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
@@ -217,6 +222,13 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
msec_delay(50);
+
+ /*
+ * Gate automatic PHY configuration by hardware on
+ * non-managed 82579
+ */
+ if (hw->mac.type == e1000_pch2lan)
+ e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
}
/*
@@ -229,13 +241,25 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
if (ret_val)
goto out;
+ /* Ungate automatic PHY configuration on non-managed 82579 */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
+ msec_delay(10);
+ e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
+ }
+
phy->id = e1000_phy_unknown;
- ret_val = e1000_get_phy_id(hw);
- if (ret_val)
- goto out;
- if ((phy->id == 0) || (phy->id == PHY_REVISION_MASK)) {
+ switch (hw->mac.type) {
+ default:
+ ret_val = e1000_get_phy_id(hw);
+ if (ret_val)
+ goto out;
+ if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK))
+ break;
+ /* fall-through */
+ case e1000_pch2lan:
/*
- * In case the PHY needs to be in mdio slow mode (eg. 82577),
+ * In case the PHY needs to be in mdio slow mode,
* set slow mode and try to get the PHY id again.
*/
ret_val = e1000_set_mdio_slow_mode_hv(hw);
@@ -244,11 +268,13 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
ret_val = e1000_get_phy_id(hw);
if (ret_val)
goto out;
+ break;
}
phy->type = e1000_get_phy_type_from_id(phy->id);
switch (phy->type) {
case e1000_phy_82577:
+ case e1000_phy_82579:
phy->ops.check_polarity = e1000_check_polarity_82577;
phy->ops.force_speed_duplex =
e1000_phy_force_speed_duplex_82577;
@@ -485,8 +511,6 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
/* check for link */
mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan;
- /* check management mode */
- mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
/* link info */
mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan;
/* multicast address update */
@@ -499,6 +523,8 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
case e1000_ich8lan:
case e1000_ich9lan:
case e1000_ich10lan:
+ /* check management mode */
+ mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
/* ID LED init */
mac->ops.id_led_init = e1000_id_led_init_generic;
/* blink LED */
@@ -511,10 +537,16 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
mac->ops.led_on = e1000_led_on_ich8lan;
mac->ops.led_off = e1000_led_off_ich8lan;
break;
+ case e1000_pch2lan:
+ mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES;
+ mac->ops.rar_set = e1000_rar_set_pch2lan;
+ /* fall-through */
case e1000_pchlan:
/* save PCH revision_id */
e1000_read_pci_cfg(hw, 0x2, &pci_cfg);
hw->revision_id = (u8)(pci_cfg &= 0x000F);
+ /* check management mode */
+ mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
/* ID LED init */
mac->ops.id_led_init = e1000_id_led_init_pchlan;
/* setup LED */
@@ -533,10 +565,46 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
if (mac->type == e1000_ich8lan)
e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE);
+ /* Gate automatic PHY configuration by hardware on managed 82579 */
+ if ((mac->type == e1000_pch2lan) &&
+ (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
+ e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
+
return E1000_SUCCESS;
}
/**
+ * e1000_set_eee_pchlan - Enable/disable EEE support
+ * @hw: pointer to the HW structure
+ *
+ * Enable/disable EEE based on setting in dev_spec structure. The bits in
+ * the LPI Control register will remain set only if/when link is up.
+ **/
+static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_SUCCESS;
+ u16 phy_reg;
+
+ DEBUGFUNC("e1000_set_eee_pchlan");
+
+ if (hw->phy.type != e1000_phy_82579)
+ goto out;
+
+ ret_val = hw->phy.ops.read_reg(hw, I82579_LPI_CTRL, &phy_reg);
+ if (ret_val)
+ goto out;
+
+ if (hw->dev_spec.ich8lan.eee_disable)
+ phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK;
+ else
+ phy_reg |= I82579_LPI_CTRL_ENABLE_MASK;
+
+ ret_val = hw->phy.ops.write_reg(hw, I82579_LPI_CTRL, phy_reg);
+out:
+ return ret_val;
+}
+
+/**
* e1000_check_for_copper_link_ich8lan - Check for link (Copper)
* @hw: pointer to the HW structure
*
@@ -589,12 +657,23 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
goto out;
}
+ if (hw->mac.type == e1000_pch2lan) {
+ ret_val = e1000_k1_workaround_lv(hw);
+ if (ret_val)
+ goto out;
+ }
+
/*
* Check if there was DownShift, must be checked
* immediately after link-up
*/
e1000_check_downshift_generic(hw);
+ /* Enable/Disable EEE after link up */
+ ret_val = e1000_set_eee_pchlan(hw);
+ if (ret_val)
+ goto out;
+
/*
* If we are forcing speed/duplex, then we simply return since
* we have already determined whether we have link or not.
@@ -644,6 +723,7 @@ void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
break;
case e1000_pchlan:
+ case e1000_pch2lan:
hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
break;
default:
@@ -767,7 +847,7 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
* e1000_check_mng_mode_ich8lan - Checks management mode
* @hw: pointer to the HW structure
*
- * This checks if the adapter has manageability enabled.
+ * This checks if the adapter has any manageability enabled.
* This is a function pointer entry point only called by read/write
* routines for the PHY and NVM parts.
**/
@@ -779,8 +859,86 @@ static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
fwsm = E1000_READ_REG(hw, E1000_FWSM);
- return (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));
+}
+
+/**
+ * e1000_check_mng_mode_pchlan - Checks management mode
+ * @hw: pointer to the HW structure
+ *
+ * This checks if the adapter has iAMT enabled.
+ * This is a function pointer entry point only called by read/write
+ * routines for the PHY and NVM parts.
+ **/
+static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw)
+{
+ u32 fwsm;
+
+ DEBUGFUNC("e1000_check_mng_mode_pchlan");
+
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+ return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
+ (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
+}
+
+/**
+ * e1000_rar_set_pch2lan - Set receive address register
+ * @hw: pointer to the HW structure
+ * @addr: pointer to the receive address
+ * @index: receive address array register
+ *
+ * Sets the receive address array register at index to the address passed
+ * in by addr. For 82579, RAR[0] is the base address register that is to
+ * contain the MAC address but RAR[1-6] are reserved for manageability (ME).
+ * Use SHRA[0-3] in place of those reserved for ME.
+ **/
+static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+ u32 rar_low, rar_high;
+
+ DEBUGFUNC("e1000_rar_set_pch2lan");
+
+ /*
+ * HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ rar_low = ((u32) addr[0] |
+ ((u32) addr[1] << 8) |
+ ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+
+ rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+
+ /* If MAC address zero, no need to set the AV bit */
+ if (rar_low || rar_high)
+ rar_high |= E1000_RAH_AV;
+
+ if (index == 0) {
+ E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
+ E1000_WRITE_FLUSH(hw);
+ E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
+ E1000_WRITE_FLUSH(hw);
+ return;
+ }
+
+ if (index < hw->mac.rar_entry_count) {
+ E1000_WRITE_REG(hw, E1000_SHRAL(index - 1), rar_low);
+ E1000_WRITE_FLUSH(hw);
+ E1000_WRITE_REG(hw, E1000_SHRAH(index - 1), rar_high);
+ E1000_WRITE_FLUSH(hw);
+
+ /* verify the register updates */
+ if ((E1000_READ_REG(hw, E1000_SHRAL(index - 1)) == rar_low) &&
+ (E1000_READ_REG(hw, E1000_SHRAH(index - 1)) == rar_high))
+ return;
+
+ DEBUGOUT2("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n",
+ (index - 1), E1000_READ_REG(hw, E1000_FWSM));
+ }
+
+ DEBUGOUT1("Failed to write receive address at index %d\n", index);
}
/**
@@ -807,6 +965,34 @@ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
}
/**
+ * e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states
+ * @hw: pointer to the HW structure
+ *
+ * Assumes semaphore already acquired.
+ *
+ **/
+static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
+{
+ u16 phy_data;
+ u32 strap = E1000_READ_REG(hw, E1000_STRAP);
+ s32 ret_val = E1000_SUCCESS;
+
+ strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
+
+ ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~HV_SMB_ADDR_MASK;
+ phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT);
+ phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
+ ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data);
+
+out:
+ return ret_val;
+}
+
+/**
* e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
* @hw: pointer to the HW structure
*
@@ -820,13 +1006,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
s32 ret_val = E1000_SUCCESS;
u16 word_addr, reg_data, reg_addr, phy_page = 0;
- if (!(hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) &&
- !(hw->mac.type == e1000_pchlan))
- return ret_val;
-
- ret_val = hw->phy.ops.acquire(hw);
- if (ret_val)
- return ret_val;
+ DEBUGFUNC("e1000_sw_lcd_config_ich8lan");
/*
* Initialize the PHY from the NVM on ICH platforms. This
@@ -835,27 +1015,42 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
* Therefore, after each PHY reset, we will load the
* configuration data out of the NVM manually.
*/
- if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
- (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) ||
- (hw->mac.type == e1000_pchlan))
+ switch (hw->mac.type) {
+ case e1000_ich8lan:
+ if (phy->type != e1000_phy_igp_3)
+ return ret_val;
+
+ if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_AMT) ||
+ (hw->device_id == E1000_DEV_ID_ICH8_IGP_C)) {
+ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+ break;
+ }
+ /* Fall-thru */
+ case e1000_pchlan:
+ case e1000_pch2lan:
sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
- else
- sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+ break;
+ default:
+ return ret_val;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
data = E1000_READ_REG(hw, E1000_FEXTNVM);
if (!(data & sw_cfg_mask))
goto out;
- /* Wait for basic configuration completes before proceeding */
- e1000_lan_init_done_ich8lan(hw);
-
/*
* Make sure HW does not configure LCD from PHY
* extended configuration before SW configuration
*/
data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
- if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
- goto out;
+ if (!(hw->mac.type == e1000_pch2lan)) {
+ if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+ goto out;
+ }
cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
@@ -866,20 +1061,16 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
- if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
- (hw->mac.type == e1000_pchlan)) {
+ if ((!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
+ (hw->mac.type == e1000_pchlan)) ||
+ (hw->mac.type == e1000_pch2lan)) {
/*
* HW configures the SMBus address and LEDs when the
* OEM and LCD Write Enable bits are set in the NVM.
* When both NVM bits are cleared, SW will configure
* them instead.
*/
- data = E1000_READ_REG(hw, E1000_STRAP);
- data &= E1000_STRAP_SMBUS_ADDRESS_MASK;
- reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT;
- reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
- ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR,
- reg_data);
+ ret_val = e1000_write_smbus_addr(hw);
if (ret_val)
goto out;
@@ -1026,6 +1217,8 @@ s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
u32 reg = 0;
u16 kmrn_reg = 0;
+ DEBUGFUNC("e1000_configure_k1_ich8lan");
+
ret_val = e1000_read_kmrn_reg_locked(hw,
E1000_KMRNCTRLSTA_K1_CONFIG,
&kmrn_reg);
@@ -1076,16 +1269,20 @@ s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
u32 mac_reg;
u16 oem_reg;
- if (hw->mac.type != e1000_pchlan)
+ DEBUGFUNC("e1000_oem_bits_config_ich8lan");
+
+ if ((hw->mac.type != e1000_pch2lan) && (hw->mac.type != e1000_pchlan))
return ret_val;
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
return ret_val;
- mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
- if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
- goto out;
+ if (!(hw->mac.type == e1000_pch2lan)) {
+ mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
+ goto out;
+ }
mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM);
if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
@@ -1130,6 +1327,8 @@ out:
**/
s32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
{
+ DEBUGFUNC("e1000_hv_phy_powerdown_workaround_ich8lan");
+
if ((hw->phy.type != e1000_phy_82577) || (hw->revision_id > 2))
return E1000_SUCCESS;
@@ -1145,6 +1344,8 @@ static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw)
s32 ret_val;
u16 data;
+ DEBUGFUNC("e1000_set_mdio_slow_mode_hv");
+
ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data);
if (ret_val)
return ret_val;
@@ -1165,6 +1366,8 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
s32 ret_val = E1000_SUCCESS;
u16 phy_data;
+ DEBUGFUNC("e1000_hv_phy_workarounds_ich8lan");
+
if (hw->mac.type != e1000_pchlan)
goto out;
@@ -1294,6 +1497,336 @@ out:
}
/**
+ * e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY
+ * @hw: pointer to the HW structure
+ **/
+void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
+{
+ u32 mac_reg;
+ u16 i;
+
+ DEBUGFUNC("e1000_copy_rx_addrs_to_phy_ich8lan");
+
+ /* Copy both RAL/H (rar_entry_count) and SHRAL/H (+4) to PHY */
+ for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+ mac_reg = E1000_READ_REG(hw, E1000_RAL(i));
+ hw->phy.ops.write_reg(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF));
+ hw->phy.ops.write_reg(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF));
+ mac_reg = E1000_READ_REG(hw, E1000_RAH(i));
+ hw->phy.ops.write_reg(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF));
+ hw->phy.ops.write_reg(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0x8000));
+ }
+}
+
+static u32 e1000_calc_rx_da_crc(u8 mac[])
+{
+ u32 poly = 0xEDB88320; /* Polynomial for 802.3 CRC calculation */
+ u32 i, j, mask, crc;
+
+ DEBUGFUNC("e1000_calc_rx_da_crc");
+
+ crc = 0xffffffff;
+ for (i = 0; i < 6; i++) {
+ crc = crc ^ mac[i];
+ for (j = 8; j > 0; j--) {
+ mask = (crc & 1) * (-1);
+ crc = (crc >> 1) ^ (poly & mask);
+ }
+ }
+ return ~crc;
+}
+
+/**
+ * e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation
+ * with 82579 PHY
+ * @hw: pointer to the HW structure
+ * @enable: flag to enable/disable workaround when enabling/disabling jumbos
+ **/
+s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
+{
+ s32 ret_val = E1000_SUCCESS;
+ u16 phy_reg, data;
+ u32 mac_reg;
+ u16 i;
+
+ DEBUGFUNC("e1000_lv_jumbo_workaround_ich8lan");
+
+ if (hw->mac.type != e1000_pch2lan)
+ goto out;
+
+ /* disable Rx path while enabling/disabling workaround */
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg | (1 << 14));
+ if (ret_val)
+ goto out;
+
+ if (enable) {
+ /*
+ * Write Rx addresses (rar_entry_count for RAL/H, +4 for
+ * SHRAL/H) and initial CRC values to the MAC
+ */
+ for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+ u8 mac_addr[ETH_ADDR_LEN] = {0};
+ u32 addr_high, addr_low;
+
+ addr_high = E1000_READ_REG(hw, E1000_RAH(i));
+ if (!(addr_high & E1000_RAH_AV))
+ continue;
+ addr_low = E1000_READ_REG(hw, E1000_RAL(i));
+ mac_addr[0] = (addr_low & 0xFF);
+ mac_addr[1] = ((addr_low >> 8) & 0xFF);
+ mac_addr[2] = ((addr_low >> 16) & 0xFF);
+ mac_addr[3] = ((addr_low >> 24) & 0xFF);
+ mac_addr[4] = (addr_high & 0xFF);
+ mac_addr[5] = ((addr_high >> 8) & 0xFF);
+
+ E1000_WRITE_REG(hw, E1000_PCH_RAICC(i),
+ e1000_calc_rx_da_crc(mac_addr));
+ }
+
+ /* Write Rx addresses to the PHY */
+ e1000_copy_rx_addrs_to_phy_ich8lan(hw);
+
+ /* Enable jumbo frame workaround in the MAC */
+ mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
+ mac_reg &= ~(1 << 14);
+ mac_reg |= (7 << 15);
+ E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
+
+ mac_reg = E1000_READ_REG(hw, E1000_RCTL);
+ mac_reg |= E1000_RCTL_SECRC;
+ E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
+
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ &data);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ data | (1 << 0));
+ if (ret_val)
+ goto out;
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ &data);
+ if (ret_val)
+ goto out;
+ data &= ~(0xF << 8);
+ data |= (0xB << 8);
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* Enable jumbo frame workaround in the PHY */
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
+ data &= ~(0x7F << 5);
+ data |= (0x37 << 5);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
+ data &= ~(1 << 13);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
+ data &= ~(0x3FF << 2);
+ data |= (0x1A << 2);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0xFE00);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
+ ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data | (1 << 10));
+ if (ret_val)
+ goto out;
+ } else {
+ /* Write MAC register values back to h/w defaults */
+ mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
+ mac_reg &= ~(0xF << 14);
+ E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
+
+ mac_reg = E1000_READ_REG(hw, E1000_RCTL);
+ mac_reg &= ~E1000_RCTL_SECRC;
+ E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
+
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ &data);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ data & ~(1 << 0));
+ if (ret_val)
+ goto out;
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ &data);
+ if (ret_val)
+ goto out;
+ data &= ~(0xF << 8);
+ data |= (0xB << 8);
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* Write PHY register values back to h/w defaults */
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
+ data &= ~(0x7F << 5);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
+ data |= (1 << 13);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
+ data &= ~(0x3FF << 2);
+ data |= (0x8 << 2);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0x7E00);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
+ ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data & ~(1 << 10));
+ if (ret_val)
+ goto out;
+ }
+
+ /* re-enable Rx path after enabling/disabling workaround */
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg & ~(1 << 14));
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ * done after every PHY reset.
+ **/
+static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan");
+
+ if (hw->mac.type != e1000_pch2lan)
+ goto out;
+
+ /* Set MDIO slow mode before any other MDIO access */
+ ret_val = e1000_set_mdio_slow_mode_hv(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_k1_gig_workaround_lv - K1 Si workaround
+ * @hw: pointer to the HW structure
+ *
+ * Workaround to set the K1 beacon duration for 82579 parts
+ **/
+static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_SUCCESS;
+ u16 status_reg = 0;
+ u32 mac_reg;
+
+ DEBUGFUNC("e1000_k1_workaround_lv");
+
+ if (hw->mac.type != e1000_pch2lan)
+ goto out;
+
+ /* Set K1 beacon duration based on 1Gbps speed or otherwise */
+ ret_val = hw->phy.ops.read_reg(hw, HV_M_STATUS, &status_reg);
+ if (ret_val)
+ goto out;
+
+ if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE))
+ == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) {
+ mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4);
+ mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
+
+ if (status_reg & HV_M_STATUS_SPEED_1000)
+ mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
+ else
+ mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
+
+ E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware
+ * @hw: pointer to the HW structure
+ * @gate: boolean set to TRUE to gate, FALSE to un-gate
+ *
+ * Gate/ungate the automatic PHY configuration via hardware; perform
+ * the configuration via software instead.
+ **/
+static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate)
+{
+ u32 extcnf_ctrl;
+
+ DEBUGFUNC("e1000_gate_hw_phy_config_ich8lan");
+
+ if (hw->mac.type != e1000_pch2lan)
+ return;
+
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+
+ if (gate)
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+ else
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+ return;
+}
+
+/**
+ * e1000_hv_phy_tuning_workaround_ich8lan - This is a Phy tuning work around
+ * needed for Nahum3 + Hanksville testing, requested by HW team
+ **/
+static s32 e1000_hv_phy_tuning_workaround_ich8lan(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_hv_phy_tuning_workaround_ich8lan");
+
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x29, 0x66C0);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x1E, 0xFFFF);
+
+out:
+ return ret_val;
+}
+
+/**
* e1000_lan_init_done_ich8lan - Check for PHY config completion
* @hw: pointer to the HW structure
*
@@ -1328,25 +1861,20 @@ static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
}
/**
- * e1000_phy_hw_reset_ich8lan - Performs a PHY reset
+ * e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset
* @hw: pointer to the HW structure
- *
- * Resets the PHY
- * This is a function pointer entry point called by drivers
- * or other shared routines.
**/
-static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
+static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
{
s32 ret_val = E1000_SUCCESS;
u16 reg;
- DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
+ DEBUGFUNC("e1000_post_phy_reset_ich8lan");
- ret_val = e1000_phy_hw_reset_generic(hw);
- if (ret_val)
+ if (hw->phy.ops.check_reset_block(hw))
goto out;
- /* Allow time for h/w to get to a quiescent state after reset */
+ /* Allow time for h/w to get to quiescent state after reset */
msec_delay(10);
/* Perform any necessary post-reset workarounds */
@@ -1356,12 +1884,23 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
if (ret_val)
goto out;
break;
+ case e1000_pch2lan:
+ ret_val = e1000_lv_phy_workarounds_ich8lan(hw);
+ if (ret_val)
+ goto out;
+ break;
default:
break;
}
+ if (hw->device_id == E1000_DEV_ID_ICH10_HANKSVILLE) {
+ ret_val = e1000_hv_phy_tuning_workaround_ich8lan(hw);
+ if (ret_val)
+ goto out;
+ }
+
/* Dummy read to clear the phy wakeup bit after lcd reset */
- if (hw->mac.type == e1000_pchlan)
+ if (hw->mac.type >= e1000_pchlan)
hw->phy.ops.read_reg(hw, BM_WUC, &reg);
/* Configure the LCD with the extended configuration region in NVM */
@@ -1372,6 +1911,42 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
/* Configure the LCD with the OEM bits in NVM */
ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE);
+ /* Ungate automatic PHY configuration on non-managed 82579 */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) {
+ msec_delay(10);
+ e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_hw_reset_ich8lan - Performs a PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Resets the PHY
+ * This is a function pointer entry point called by drivers
+ * or other shared routines.
+ **/
+static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
+
+ /* Gate automatic PHY configuration by hardware on non-managed 82579 */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
+ e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
+
+ ret_val = e1000_phy_hw_reset_generic(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_post_phy_reset_ich8lan(hw);
+
out:
return ret_val;
}
@@ -1621,6 +2196,8 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
u8 sig_byte = 0;
s32 ret_val = E1000_SUCCESS;
+ DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan");
+
switch (hw->mac.type) {
case e1000_ich8lan:
case e1000_ich9lan:
@@ -2670,20 +3247,21 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
ctrl = E1000_READ_REG(hw, E1000_CTRL);
- if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) {
- /* Clear PHY Reset Asserted bit */
- if (hw->mac.type >= e1000_pchlan) {
- u32 status = E1000_READ_REG(hw, E1000_STATUS);
- E1000_WRITE_REG(hw, E1000_STATUS, status &
- ~E1000_STATUS_PHYRA);
- }
-
+ if (!hw->phy.ops.check_reset_block(hw)) {
/*
- * PHY HW reset requires MAC CORE reset at the same
+ * Full-chip reset requires MAC and PHY reset at the same
* time to make sure the interface between MAC and the
* external PHY is reset.
*/
ctrl |= E1000_CTRL_PHY_RST;
+
+ /*
+ * Gate automatic PHY configuration by hardware on
+ * non-managed 82579
+ */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
+ e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
}
ret_val = e1000_acquire_swflag_ich8lan(hw);
DEBUGOUT("Issuing a global reset to ich8lan\n");
@@ -2693,44 +3271,16 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
if (!ret_val)
e1000_release_swflag_ich8lan(hw);
- /* Perform any necessary post-reset workarounds */
- switch (hw->mac.type) {
- case e1000_pchlan:
- ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
+ if (ctrl & E1000_CTRL_PHY_RST) {
+ ret_val = hw->phy.ops.get_cfg_done(hw);
if (ret_val)
goto out;
- break;
- default:
- break;
- }
-
- if (ctrl & E1000_CTRL_PHY_RST)
- ret_val = hw->phy.ops.get_cfg_done(hw);
- if (hw->mac.type >= e1000_ich10lan) {
- e1000_lan_init_done_ich8lan(hw);
- } else {
- ret_val = e1000_get_auto_rd_done_generic(hw);
- if (ret_val) {
- /*
- * When auto config read does not complete, do not
- * return with an error. This can happen in situations
- * where there is no eeprom and prevents getting link.
- */
- DEBUGOUT("Auto Read Done did not complete\n");
- }
+ ret_val = e1000_post_phy_reset_ich8lan(hw);
+ if (ret_val)
+ goto out;
}
- /* Dummy read to clear the phy wakeup bit after lcd reset */
- if (hw->mac.type == e1000_pchlan)
- hw->phy.ops.read_reg(hw, BM_WUC, &reg);
- ret_val = e1000_sw_lcd_config_ich8lan(hw);
- if (ret_val)
- goto out;
-
- ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE);
- if (ret_val)
- goto out;
/*
* For PCH, this write will make sure that any noise
* will be detected as a CRC error and be dropped rather than show up
@@ -2948,7 +3498,10 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
if ((hw->phy.type == e1000_phy_82578) ||
+ (hw->phy.type == e1000_phy_82579) ||
(hw->phy.type == e1000_phy_82577)) {
+ E1000_WRITE_REG(hw, E1000_FCRTV_PCH, hw->fc.refresh_time);
+
ret_val = hw->phy.ops.write_reg(hw,
PHY_REG(BM_PORT_CTRL_PAGE, 27),
hw->fc.pause_time);
@@ -3017,6 +3570,7 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
goto out;
break;
case e1000_phy_82577:
+ case e1000_phy_82579:
ret_val = e1000_copper_link_setup_82577(hw);
if (ret_val)
goto out;
@@ -3300,21 +3854,21 @@ out:
void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw)
{
u32 phy_ctrl;
+ s32 ret_val;
- switch (hw->mac.type) {
- case e1000_ich8lan:
- case e1000_ich9lan:
- case e1000_ich10lan:
- case e1000_pchlan:
- phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
- phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
- E1000_PHY_CTRL_GBE_DISABLE;
- E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+ DEBUGFUNC("e1000_disable_gig_wol_ich8lan");
- if (hw->mac.type == e1000_pchlan)
- e1000_phy_hw_reset_ich8lan(hw);
- default:
- break;
+ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE;
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ if (hw->mac.type >= e1000_pchlan) {
+ e1000_oem_bits_config_ich8lan(hw, FALSE);
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return;
+ e1000_write_smbus_addr(hw);
+ hw->phy.ops.release(hw);
}
return;
@@ -3469,31 +4023,49 @@ static s32 e1000_led_off_pchlan(struct e1000_hw *hw)
}
/**
- * e1000_get_cfg_done_ich8lan - Read config done bit
+ * e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset
* @hw: pointer to the HW structure
*
- * Read the management control register for the config done bit for
- * completion status. NOTE: silicon which is EEPROM-less will fail trying
- * to read the config done bit, so an error is *ONLY* logged and returns
- * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon
- * would not be able to be reset or change link.
+ * Read appropriate register for the config done bit for completion status
+ * and configure the PHY through s/w for EEPROM-less parts.
+ *
+ * NOTE: some silicon which is EEPROM-less will fail trying to read the
+ * config done bit, so only an error is logged and continues. If we were
+ * to return with error, EEPROM-less silicon would not be able to be reset
+ * or change link.
**/
static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
{
s32 ret_val = E1000_SUCCESS;
u32 bank = 0;
+ u32 status;
- if (hw->mac.type >= e1000_pchlan) {
- u32 status = E1000_READ_REG(hw, E1000_STATUS);
+ DEBUGFUNC("e1000_get_cfg_done_ich8lan");
- if (status & E1000_STATUS_PHYRA)
- E1000_WRITE_REG(hw, E1000_STATUS, status &
- ~E1000_STATUS_PHYRA);
- else
- DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
+ e1000_get_cfg_done_generic(hw);
+
+ /* Wait for indication from h/w that it has completed basic config */
+ if (hw->mac.type >= e1000_ich10lan) {
+ e1000_lan_init_done_ich8lan(hw);
+ } else {
+ ret_val = e1000_get_auto_rd_done_generic(hw);
+ if (ret_val) {
+ /*
+ * When auto config read does not complete, do not
+ * return with an error. This can happen in situations
+ * where there is no eeprom and prevents getting link.
+ */
+ DEBUGOUT("Auto Read Done did not complete\n");
+ ret_val = E1000_SUCCESS;
+ }
}
- e1000_get_cfg_done_generic(hw);
+ /* Clear PHY Reset Asserted bit */
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ if (status & E1000_STATUS_PHYRA)
+ E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA);
+ else
+ DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
/* If EEPROM is not marked present, init the IGP 3 PHY manually */
if (hw->mac.type <= e1000_ich9lan) {
@@ -3560,6 +4132,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
/* Clear PHY statistics registers */
if ((hw->phy.type == e1000_phy_82578) ||
+ (hw->phy.type == e1000_phy_82579) ||
(hw->phy.type == e1000_phy_82577)) {
hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data);
hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data);
diff --git a/sys/dev/e1000/e1000_ich8lan.h b/sys/dev/e1000/e1000_ich8lan.h
index f26b7b9f70a5..2935af5689ec 100644
--- a/sys/dev/e1000/e1000_ich8lan.h
+++ b/sys/dev/e1000/e1000_ich8lan.h
@@ -70,6 +70,23 @@
#define E1000_ICH_MNG_IAMT_MODE 0x2
+#define E1000_FWSM_PROXY_MODE 0x00000008 /* FW is in proxy mode */
+
+/* Shared Receive Address Registers */
+#define E1000_SHRAL(_i) (0x05438 + ((_i) * 8))
+#define E1000_SHRAH(_i) (0x0543C + ((_i) * 8))
+#define E1000_SHRAH_AV 0x80000000 /* Addr Valid bit */
+#define E1000_SHRAH_MAV 0x40000000 /* Multicast Addr Valid bit */
+
+#define E1000_H2ME 0x05B50 /* Host to ME */
+#define E1000_H2ME_LSECREQ 0x00000001 /* Linksec Request */
+#define E1000_H2ME_LSECA 0x00000002 /* Linksec Active */
+#define E1000_H2ME_LSECSF 0x00000004 /* Linksec Failed */
+#define E1000_H2ME_LSECD 0x00000008 /* Linksec Disabled */
+#define E1000_H2ME_SLCAPD 0x00000010 /* Start LCAPD */
+#define E1000_H2ME_IPV4_ARP_EN 0x00000020 /* Arp Offload enable bit */
+#define E1000_H2ME_IPV6_NS_EN 0x00000040 /* NS Offload enable bit */
+
#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
(ID_LED_OFF1_OFF2 << 8) | \
(ID_LED_OFF1_ON2 << 4) | \
@@ -85,9 +102,14 @@
#define E1000_FEXTNVM_SW_CONFIG 1
#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M */
+#define E1000_FEXTNVM4_BEACON_DURATION_MASK 0x7
+#define E1000_FEXTNVM4_BEACON_DURATION_8USEC 0x7
+#define E1000_FEXTNVM4_BEACON_DURATION_16USEC 0x3
+
#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 PHY_PAGE_SHIFT 5
#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
@@ -112,6 +134,14 @@
#define BM_RAR_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
#define BM_MTA(_i) (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))
+#define BM_IPAV (BM_PHY_REG(BM_WUC_PAGE, 64))
+#define BM_IP4AT_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 82 + ((_i) * 2)))
+#define BM_IP4AT_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 83 + ((_i) * 2)))
+
+#define BM_SHRAL_LOWER(_i) (BM_PHY_REG(BM_WUC_PAGE, 44 + ((_i) * 4)))
+#define BM_SHRAL_UPPER(_i) (BM_PHY_REG(BM_WUC_PAGE, 45 + ((_i) * 4)))
+#define BM_SHRAH_LOWER(_i) (BM_PHY_REG(BM_WUC_PAGE, 46 + ((_i) * 4)))
+#define BM_SHRAH_UPPER(_i) (BM_PHY_REG(BM_WUC_PAGE, 47 + ((_i) * 4)))
#define BM_RCTL_UPE 0x0001 /* Unicast Promiscuous Mode */
#define BM_RCTL_MPE 0x0002 /* Multicast Promiscuous Mode */
@@ -147,6 +177,7 @@
/* SMBus Address Phy Register */
#define HV_SMB_ADDR PHY_REG(768, 26)
+#define HV_SMB_ADDR_MASK 0x007F
#define HV_SMB_ADDR_PEC_EN 0x0200
#define HV_SMB_ADDR_VALID 0x0080
@@ -172,6 +203,10 @@
#define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in milliseconds */
+/* PHY Low Power Idle Control */
+#define I82579_LPI_CTRL PHY_REG(772, 20)
+#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
+
/*
* Additional interrupts need to be handled for ICH family:
* DSW = The FW changed the status of the DISSW bit in FWSM
@@ -195,6 +230,9 @@
#define E1000_RXDEXT_LINKSEC_ERROR_REPLAY_ERROR 0x40000000
#define E1000_RXDEXT_LINKSEC_ERROR_BAD_SIG 0x60000000
+/* Receive Address Initial CRC Calculation */
+#define E1000_PCH_RAICC(_n) (0x05F50 + ((_n) * 4))
+
void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
bool state);
void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
@@ -203,4 +241,6 @@ void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw);
s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_config);
s32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
+void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
+s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
#endif
diff --git a/sys/dev/e1000/e1000_mac.c b/sys/dev/e1000/e1000_mac.c
index d4d2bec27bdc..121667104e35 100644
--- a/sys/dev/e1000/e1000_mac.c
+++ b/sys/dev/e1000/e1000_mac.c
@@ -395,6 +395,16 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
DEBUGFUNC("e1000_check_alt_mac_addr_generic");
+ ret_val = hw->nvm.ops.read(hw, NVM_COMPAT, 1, &nvm_data);
+ if (ret_val)
+ goto out;
+
+ /* Check for LOM (vs. NIC) or one of two valid mezzanine cards */
+ if (!((nvm_data & NVM_COMPAT_LOM) ||
+ (hw->device_id == E1000_DEV_ID_82571EB_SERDES_DUAL) ||
+ (hw->device_id == E1000_DEV_ID_82571EB_SERDES_QUAD)))
+ goto out;
+
ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1,
&nvm_alt_mac_addr_offset);
if (ret_val) {
diff --git a/sys/dev/e1000/e1000_nvm.c b/sys/dev/e1000/e1000_nvm.c
index 83557ef96503..05c793193771 100644
--- a/sys/dev/e1000/e1000_nvm.c
+++ b/sys/dev/e1000/e1000_nvm.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2009, Intel Corporation
+ Copyright (c) 2001-2010, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -775,6 +775,184 @@ out:
}
/**
+ * e1000_read_pba_string_generic - Read device part number
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ **/
+s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
+ u32 pba_num_size)
+{
+ s32 ret_val;
+ u16 nvm_data;
+ u16 pba_ptr;
+ u16 offset;
+ u16 length;
+
+ DEBUGFUNC("e1000_read_pba_string_generic");
+
+ if (pba_num == NULL) {
+ DEBUGOUT("PBA string buffer was null\n");
+ ret_val = E1000_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &pba_ptr);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ /*
+ * if nvm_data is not ptr guard the PBA must be in legacy format which
+ * means pba_ptr is actually our second data word for the PBA number
+ * and we can decode it into an ascii string
+ */
+ if (nvm_data != NVM_PBA_PTR_GUARD) {
+ DEBUGOUT("NVM PBA number is not stored as string\n");
+
+ /* we will need 11 characters to store the PBA */
+ if (pba_num_size < 11) {
+ DEBUGOUT("PBA string buffer too small\n");
+ return E1000_ERR_NO_SPACE;
+ }
+
+ /* extract hex string from data and pba_ptr */
+ pba_num[0] = (nvm_data >> 12) & 0xF;
+ pba_num[1] = (nvm_data >> 8) & 0xF;
+ pba_num[2] = (nvm_data >> 4) & 0xF;
+ pba_num[3] = nvm_data & 0xF;
+ pba_num[4] = (pba_ptr >> 12) & 0xF;
+ pba_num[5] = (pba_ptr >> 8) & 0xF;
+ pba_num[6] = '-';
+ pba_num[7] = 0;
+ pba_num[8] = (pba_ptr >> 4) & 0xF;
+ pba_num[9] = pba_ptr & 0xF;
+
+ /* put a null character on the end of our string */
+ pba_num[10] = '\0';
+
+ /* switch all the data but the '-' to hex char */
+ for (offset = 0; offset < 10; offset++) {
+ if (pba_num[offset] < 0xA)
+ pba_num[offset] += '0';
+ else if (pba_num[offset] < 0x10)
+ pba_num[offset] += 'A' - 0xA;
+ }
+
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, pba_ptr, 1, &length);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (length == 0xFFFF || length == 0) {
+ DEBUGOUT("NVM PBA number section invalid length\n");
+ ret_val = E1000_ERR_NVM_PBA_SECTION;
+ goto out;
+ }
+ /* check if pba_num buffer is big enough */
+ if (pba_num_size < (((u32)length * 2) - 1)) {
+ DEBUGOUT("PBA string buffer too small\n");
+ ret_val = E1000_ERR_NO_SPACE;
+ goto out;
+ }
+
+ /* trim pba length from start of string */
+ pba_ptr++;
+ length--;
+
+ for (offset = 0; offset < length; offset++) {
+ ret_val = hw->nvm.ops.read(hw, pba_ptr + offset, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+ pba_num[offset * 2] = (u8)(nvm_data >> 8);
+ pba_num[(offset * 2) + 1] = (u8)(nvm_data & 0xFF);
+ }
+ pba_num[offset * 2] = '\0';
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_pba_length_generic - Read device part number length
+ * @hw: pointer to the HW structure
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number length from the EEPROM and
+ * stores the value in pba_num_size.
+ **/
+s32 e1000_read_pba_length_generic(struct e1000_hw *hw, u32 *pba_num_size)
+{
+ s32 ret_val;
+ u16 nvm_data;
+ u16 pba_ptr;
+ u16 length;
+
+ DEBUGFUNC("e1000_read_pba_length_generic");
+
+ if (pba_num_size == NULL) {
+ DEBUGOUT("PBA buffer size was null\n");
+ ret_val = E1000_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &pba_ptr);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ /* if data is not ptr guard the PBA must be in legacy format */
+ if (nvm_data != NVM_PBA_PTR_GUARD) {
+ *pba_num_size = 11;
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, pba_ptr, 1, &length);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (length == 0xFFFF || length == 0) {
+ DEBUGOUT("NVM PBA number section invalid length\n");
+ ret_val = E1000_ERR_NVM_PBA_SECTION;
+ goto out;
+ }
+
+ /*
+ * Convert from length in u16 values to u8 chars, add 1 for NULL,
+ * and subtract 2 because length field is included in length.
+ */
+ *pba_num_size = ((u32)length * 2) - 1;
+
+out:
+ return ret_val;
+}
+
+/**
* e1000_read_pba_num_generic - Read device part number
* @hw: pointer to the HW structure
* @pba_num: pointer to device part number
@@ -793,6 +971,10 @@ s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num)
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
goto out;
+ } else if (nvm_data == NVM_PBA_PTR_GUARD) {
+ DEBUGOUT("NVM Not Supported\n");
+ ret_val = E1000_NOT_IMPLEMENTED;
+ goto out;
}
*pba_num = (u32)(nvm_data << 16);
@@ -880,7 +1062,7 @@ out:
**/
s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw)
{
- s32 ret_val;
+ s32 ret_val;
u16 checksum = 0;
u16 i, nvm_data;
diff --git a/sys/dev/e1000/e1000_nvm.h b/sys/dev/e1000/e1000_nvm.h
index 974c407b41ff..36ee4448ff7f 100644
--- a/sys/dev/e1000/e1000_nvm.h
+++ b/sys/dev/e1000/e1000_nvm.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2009, Intel Corporation
+ Copyright (c) 2001-2010, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,9 @@ s32 e1000_acquire_nvm_generic(struct e1000_hw *hw);
s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
s32 e1000_read_mac_addr_generic(struct e1000_hw *hw);
s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num);
+s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
+ u32 pba_num_size);
+s32 e1000_read_pba_length_generic(struct e1000_hw *hw, u32 *pba_num_size);
s32 e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
s32 e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset,
u16 words, u16 *data);
diff --git a/sys/dev/e1000/e1000_osdep.h b/sys/dev/e1000/e1000_osdep.h
index ff505cc19ca1..25231a76d4ef 100644
--- a/sys/dev/e1000/e1000_osdep.h
+++ b/sys/dev/e1000/e1000_osdep.h
@@ -65,11 +65,11 @@
#define MSGOUT(S, A, B) printf(S "\n", A, B)
#define DEBUGFUNC(F) DEBUGOUT(F);
- #define DEBUGOUT(S)
- #define DEBUGOUT1(S,A)
- #define DEBUGOUT2(S,A,B)
- #define DEBUGOUT3(S,A,B,C)
- #define DEBUGOUT7(S,A,B,C,D,E,F,G)
+#define DEBUGOUT(S) do {} while (0)
+#define DEBUGOUT1(S,A) do {} while (0)
+#define DEBUGOUT2(S,A,B) do {} while (0)
+#define DEBUGOUT3(S,A,B,C) do {} while (0)
+#define DEBUGOUT7(S,A,B,C,D,E,F,G) do {} while (0)
#define STATIC static
#define FALSE 0
diff --git a/sys/dev/e1000/e1000_phy.c b/sys/dev/e1000/e1000_phy.c
index 24ca36f6ebb0..fb666233a12b 100644
--- a/sys/dev/e1000/e1000_phy.c
+++ b/sys/dev/e1000/e1000_phy.c
@@ -281,6 +281,13 @@ s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
goto out;
}
*data = (u16) mdic;
+
+ /*
+ * Allow some time after each MDIC transaction to avoid
+ * reading duplicate data in the next MDIC transaction.
+ */
+ if (hw->mac.type == e1000_pch2lan)
+ usec_delay(100);
out:
return ret_val;
@@ -345,6 +352,13 @@ s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
goto out;
}
+ /*
+ * Allow some time after each MDIC transaction to avoid
+ * reading duplicate data in the next MDIC transaction.
+ */
+ if (hw->mac.type == e1000_pch2lan)
+ usec_delay(100);
+
out:
return ret_val;
}
@@ -868,9 +882,10 @@ s32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
if (ret_val)
goto out;
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
/* For BM PHY this bit is downshift enable */
- if (phy->type != e1000_phy_bm)
- phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ if (phy->type == e1000_phy_bm)
+ phy_data &= ~M88E1000_PSCR_ASSERT_CRS_ON_TX;
/*
* Options:
@@ -2618,6 +2633,9 @@ enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id)
case I82577_E_PHY_ID:
phy_type = e1000_phy_82577;
break;
+ case I82579_E_PHY_ID:
+ phy_type = e1000_phy_82579;
+ break;
case I82580_I_PHY_ID:
phy_type = e1000_phy_82580;
break;
diff --git a/sys/dev/e1000/e1000_phy.h b/sys/dev/e1000/e1000_phy.h
index 692cbaa91eb9..c42ef6c688b2 100644
--- a/sys/dev/e1000/e1000_phy.h
+++ b/sys/dev/e1000/e1000_phy.h
@@ -230,12 +230,14 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw);
#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000
#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16
#define E1000_KMRNCTRLSTA_REN 0x00200000
+#define E1000_KMRNCTRLSTA_CTRL_OFFSET 0x1 /* Kumeran Control */
#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */
#define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */
#define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */
#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */
#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7
#define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002
+#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 */
diff --git a/sys/dev/e1000/e1000_regs.h b/sys/dev/e1000/e1000_regs.h
index b2a477e82345..38ccff326ae0 100644
--- a/sys/dev/e1000/e1000_regs.h
+++ b/sys/dev/e1000/e1000_regs.h
@@ -53,6 +53,7 @@
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
#define E1000_FEXT 0x0002C /* Future Extended - RW */
+#define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */
#define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */
#define E1000_FCT 0x00030 /* Flow Control Type - RW */
#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
@@ -186,6 +187,8 @@
(0x054E0 + ((_i - 16) * 8)))
#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
(0x054E4 + ((_i - 16) * 8)))
+#define E1000_SHRAL(_i) (0x05438 + ((_i) * 8))
+#define E1000_SHRAH(_i) (0x0543C + ((_i) * 8))
#define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8))
#define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4))
#define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4))
@@ -282,6 +285,15 @@
#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */
#define E1000_CRC_OFFSET 0x05F50 /* CRC Offset register */
+#define E1000_VFGPRC 0x00F10
+#define E1000_VFGORC 0x00F18
+#define E1000_VFMPRC 0x00F3C
+#define E1000_VFGPTC 0x00F14
+#define E1000_VFGOTC 0x00F34
+#define E1000_VFGOTLBC 0x00F50
+#define E1000_VFGPTLBC 0x00F44
+#define E1000_VFGORLBC 0x00F48
+#define E1000_VFGPRLBC 0x00F40
/* Virtualization statistical counters */
#define E1000_PFVFGPRC(_n) (0x010010 + (0x100 * (_n)))
#define E1000_PFVFGPTC(_n) (0x010014 + (0x100 * (_n)))
@@ -448,6 +460,7 @@
#define E1000_VFTE 0x00C90 /* VF Transmit Enables */
#define E1000_QDE 0x02408 /* Queue Drop Enable - RW */
#define E1000_DTXSWC 0x03500 /* DMA Tx Switch Control - RW */
+#define E1000_WVBR 0x03554 /* VM Wrong Behavior - RWS */
#define E1000_RPLOLR 0x05AF0 /* Replication Offload - RW */
#define E1000_UTA 0x0A000 /* Unicast Table Array - RW */
#define E1000_IOVTCL 0x05BBC /* IOV Control Register */
@@ -530,4 +543,6 @@
/* PCIe Parity Status Register */
#define E1000_PCIEERRSTS 0x05BA8
+
+
#endif
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 11681c3acf2d..23c0b3338685 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -39,9 +39,6 @@
#include <sys/param.h>
#include <sys/systm.h>
-#if __FreeBSD_version >= 800000
-#include <sys/buf_ring.h>
-#endif
#include <sys/bus.h>
#include <sys/endian.h>
#include <sys/kernel.h>
@@ -93,8 +90,7 @@ int em_display_debug_stats = 0;
/*********************************************************************
* Driver version:
*********************************************************************/
-char em_driver_version[] = "7.0.5";
-
+char em_driver_version[] = "7.1.8";
/*********************************************************************
* PCI Device ID Table
@@ -165,10 +161,13 @@ static em_vendor_info_t em_vendor_info_array[] =
{ 0x8086, E1000_DEV_ID_ICH10_R_BM_V, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_ICH10_D_BM_LM, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_ICH10_D_BM_LF, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_ICH10_D_BM_V, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_PCH_M_HV_LM, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_PCH_M_HV_LC, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_PCH_D_HV_DM, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_PCH_D_HV_DC, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_PCH2_LV_LM, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_PCH2_LV_V, PCI_ANY_ID, PCI_ANY_ID, 0},
/* required last entry */
{ 0, 0, 0, 0, 0}
};
@@ -192,12 +191,6 @@ static int em_suspend(device_t);
static int em_resume(device_t);
static void em_start(struct ifnet *);
static void em_start_locked(struct ifnet *, struct tx_ring *);
-#ifdef EM_MULTIQUEUE
-static int em_mq_start(struct ifnet *, struct mbuf *);
-static int em_mq_start_locked(struct ifnet *,
- struct tx_ring *, struct mbuf *);
-static void em_qflush(struct ifnet *);
-#endif
static int em_ioctl(struct ifnet *, u_long, caddr_t);
static void em_init(void *);
static void em_init_locked(struct adapter *);
@@ -237,9 +230,10 @@ static bool em_rxeof(struct rx_ring *, int, int *);
static int em_fixup_rx(struct rx_ring *);
#endif
static void em_receive_checksum(struct e1000_rx_desc *, struct mbuf *);
-static void em_transmit_checksum_setup(struct tx_ring *, struct mbuf *,
- u32 *, u32 *);
-static bool em_tso_setup(struct tx_ring *, struct mbuf *, u32 *, u32 *);
+static void em_transmit_checksum_setup(struct tx_ring *, struct mbuf *, int,
+ struct ip *, u32 *, u32 *);
+static void em_tso_setup(struct tx_ring *, struct mbuf *, int, struct ip *,
+ struct tcphdr *, u32 *, u32 *);
static void em_set_promisc(struct adapter *);
static void em_disable_promisc(struct adapter *);
static void em_set_multi(struct adapter *);
@@ -254,6 +248,8 @@ static int em_dma_malloc(struct adapter *, bus_size_t,
static void em_dma_free(struct adapter *, struct em_dma_alloc *);
static int em_sysctl_nvm_info(SYSCTL_HANDLER_ARGS);
static void em_print_nvm_info(struct adapter *);
+static int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
+static void em_print_debug_info(struct adapter *);
static int em_is_valid_ether_addr(u8 *);
static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS);
static void em_add_int_delay_sysctl(struct adapter *, const char *,
@@ -267,6 +263,7 @@ static void em_get_wakeup(device_t);
static void em_enable_wakeup(device_t);
static int em_enable_phy_wakeup(struct adapter *);
static void em_led_func(void *, int);
+static void em_disable_aspm(struct adapter *);
static int em_irq_fast(void *);
@@ -280,6 +277,10 @@ static void em_handle_link(void *context, int pending);
static void em_add_rx_process_limit(struct adapter *, const char *,
const char *, int *, int);
+static void em_set_flow_cntrl(struct adapter *, const char *,
+ const char *, int *, int);
+
+static __inline void em_rx_discard(struct rx_ring *, int);
#ifdef DEVICE_POLLING
static poll_handler_t em_poll;
@@ -344,16 +345,8 @@ TUNABLE_INT("hw.em.smart_pwr_down", &em_smart_pwr_down);
static int em_debug_sbp = FALSE;
TUNABLE_INT("hw.em.sbp", &em_debug_sbp);
-/* Local controls for MSI/MSIX */
-#ifdef EM_MULTIQUEUE
static int em_enable_msix = TRUE;
-static int em_msix_queues = 2; /* for 82574, can be 1 or 2 */
-#else
-static int em_enable_msix = FALSE;
-static int em_msix_queues = 0; /* disable */
-#endif
TUNABLE_INT("hw.em.enable_msix", &em_enable_msix);
-TUNABLE_INT("hw.em.msix_queues", &em_msix_queues);
/* How many packets rxeof tries to clean at a time */
static int em_rx_process_limit = 100;
@@ -363,14 +356,6 @@ TUNABLE_INT("hw.em.rx_process_limit", &em_rx_process_limit);
static int em_fc_setting = e1000_fc_full;
TUNABLE_INT("hw.em.fc_setting", &em_fc_setting);
-/*
-** Shadow VFTA table, this is needed because
-** the real vlan filter table gets cleared during
-** a soft reset and the driver needs to be able
-** to repopulate it.
-*/
-static u32 em_shadow_vfta[EM_VFTA_SIZE];
-
/* Global used in WOL setup with multiport cards */
static int global_quad_port_a = 0;
@@ -453,6 +438,11 @@ em_attach(device_t dev)
OID_AUTO, "nvm", CTLTYPE_INT|CTLFLAG_RW, adapter, 0,
em_sysctl_nvm_info, "I", "NVM Information");
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, adapter, 0,
+ em_sysctl_debug_info, "I", "Debug Information");
+
callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0);
/* Determine hardware and mac info */
@@ -472,9 +462,10 @@ em_attach(device_t dev)
** identified
*/
if ((adapter->hw.mac.type == e1000_ich8lan) ||
- (adapter->hw.mac.type == e1000_pchlan) ||
(adapter->hw.mac.type == e1000_ich9lan) ||
- (adapter->hw.mac.type == e1000_ich10lan)) {
+ (adapter->hw.mac.type == e1000_ich10lan) ||
+ (adapter->hw.mac.type == e1000_pchlan) ||
+ (adapter->hw.mac.type == e1000_pch2lan)) {
int rid = EM_BAR_TYPE_FLASH;
adapter->flash = bus_alloc_resource_any(dev,
SYS_RES_MEMORY, &rid, RF_ACTIVE);
@@ -518,11 +509,16 @@ em_attach(device_t dev)
E1000_REGISTER(&adapter->hw, E1000_TADV),
em_tx_abs_int_delay_dflt);
- /* Sysctls for limiting the amount of work done in the taskqueue */
+ /* Sysctl for limiting the amount of work done in the taskqueue */
em_add_rx_process_limit(adapter, "rx_processing_limit",
"max number of rx packets to process", &adapter->rx_process_limit,
em_rx_process_limit);
+ /* Sysctl for setting the interface flow control */
+ em_set_flow_cntrl(adapter, "flow_control",
+ "max number of rx packets to process",
+ &adapter->fc_setting, em_fc_setting);
+
/*
* Validate number of transmit and receive descriptors. It
* must not exceed hardware maximum, and must be multiple
@@ -585,6 +581,11 @@ em_attach(device_t dev)
goto err_late;
}
+ /* Check SOL/IDER usage */
+ if (e1000_check_reset_block(&adapter->hw))
+ device_printf(dev, "PHY reset is blocked"
+ " due to SOL/IDER session.\n");
+
/*
** Start from a known state, this is
** important in reading the nvm and
@@ -648,11 +649,6 @@ em_attach(device_t dev)
adapter->hw.mac.get_link_status = 1;
em_update_link_status(adapter);
- /* Indicate SOL/IDER usage */
- if (e1000_check_reset_block(&adapter->hw))
- device_printf(dev,
- "PHY reset is blocked due to SOL/IDER session.\n");
-
/* Register for VLAN events */
adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
em_register_vlan, adapter, EVENTHANDLER_PRI_FIRST);
@@ -810,112 +806,6 @@ em_resume(device_t dev)
* In case resources are not available stack is notified and
* the packet is requeued.
**********************************************************************/
-
-#ifdef EM_MULTIQUEUE
-static int
-em_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m)
-{
- struct adapter *adapter = txr->adapter;
- struct mbuf *next;
- int err = 0, enq = 0;
-
- if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
- IFF_DRV_RUNNING || adapter->link_active == 0) {
- if (m != NULL)
- err = drbr_enqueue(ifp, txr->br, m);
- return (err);
- }
-
- /* Call cleanup if number of TX descriptors low */
- if (txr->tx_avail <= EM_TX_CLEANUP_THRESHOLD)
- em_txeof(txr);
-
- enq = 0;
- if (m == NULL) {
- next = drbr_dequeue(ifp, txr->br);
- } else if (drbr_needs_enqueue(ifp, txr->br)) {
- if ((err = drbr_enqueue(ifp, txr->br, m)) != 0)
- return (err);
- next = drbr_dequeue(ifp, txr->br);
- } else
- next = m;
-
- /* Process the queue */
- while (next != NULL) {
- if ((err = em_xmit(txr, &next)) != 0) {
- if (next != NULL)
- err = drbr_enqueue(ifp, txr->br, next);
- break;
- }
- enq++;
- drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
- ETHER_BPF_MTAP(ifp, next);
- if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
- break;
- if (txr->tx_avail < EM_MAX_SCATTER) {
- ifp->if_drv_flags |= IFF_DRV_OACTIVE;
- break;
- }
- next = drbr_dequeue(ifp, txr->br);
- }
-
- if (enq > 0) {
- /* Set the watchdog */
- txr->watchdog_check = TRUE;
- txr->watchdog_time = ticks;
- }
- return (err);
-}
-
-/*
-** Multiqueue capable stack interface, this is not
-** yet truely multiqueue, but that is coming...
-*/
-static int
-em_mq_start(struct ifnet *ifp, struct mbuf *m)
-{
- struct adapter *adapter = ifp->if_softc;
- struct tx_ring *txr;
- int i, error = 0;
-
- /* Which queue to use */
- if ((m->m_flags & M_FLOWID) != 0)
- i = m->m_pkthdr.flowid % adapter->num_queues;
- else
- i = curcpu % adapter->num_queues;
-
- txr = &adapter->tx_rings[i];
-
- if (EM_TX_TRYLOCK(txr)) {
- error = em_mq_start_locked(ifp, txr, m);
- EM_TX_UNLOCK(txr);
- } else
- error = drbr_enqueue(ifp, txr->br, m);
-
- return (error);
-}
-
-/*
-** Flush all ring buffers
-*/
-static void
-em_qflush(struct ifnet *ifp)
-{
- struct adapter *adapter = ifp->if_softc;
- struct tx_ring *txr = adapter->tx_rings;
- struct mbuf *m;
-
- for (int i = 0; i < adapter->num_queues; i++, txr++) {
- EM_TX_LOCK(txr);
- while ((m = buf_ring_dequeue_sc(txr->br)) != NULL)
- m_freem(m);
- EM_TX_UNLOCK(txr);
- }
- if_qflush(ifp);
-}
-
-#endif /* EM_MULTIQUEUE */
-
static void
em_start_locked(struct ifnet *ifp, struct tx_ring *txr)
{
@@ -960,7 +850,7 @@ em_start_locked(struct ifnet *ifp, struct tx_ring *txr)
/* Set timeout in case hardware has problems transmitting. */
txr->watchdog_time = ticks;
- txr->watchdog_check = TRUE;
+ txr->queue_status = EM_QUEUE_WORKING;
}
return;
@@ -1036,6 +926,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
case e1000_82572:
case e1000_ich9lan:
case e1000_ich10lan:
+ case e1000_pch2lan:
case e1000_82574:
case e1000_80003es2lan: /* 9K Jumbo Frame size */
max_frame_size = 9234;
@@ -1099,6 +990,11 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
break;
case SIOCSIFMEDIA:
+ /*
+ ** As the speed/duplex settings are being
+ ** changed, we need to reset the PHY.
+ */
+ adapter->hw.phy.reset_disable = FALSE;
/* Check SOL/IDER usage */
EM_CORE_LOCK(adapter);
if (e1000_check_reset_block(&adapter->hw)) {
@@ -1108,6 +1004,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
break;
}
EM_CORE_UNLOCK(adapter);
+ /* falls thru */
case SIOCGIFMEDIA:
IOCTL_DEBUGOUT("ioctl rcv'd: \
SIOCxIFMEDIA (Get/Set Interface Media)");
@@ -1222,13 +1119,16 @@ em_init_locked(struct adapter *adapter)
case e1000_82583:
pba = E1000_PBA_20K; /* 20K for Rx, 20K for Tx */
break;
+ case e1000_ich8lan:
+ pba = E1000_PBA_8K;
+ break;
case e1000_ich9lan:
case e1000_ich10lan:
- case e1000_pchlan:
pba = E1000_PBA_10K;
break;
- case e1000_ich8lan:
- pba = E1000_PBA_8K;
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ pba = E1000_PBA_26K;
break;
default:
if (adapter->max_frame_size > 8192)
@@ -1266,19 +1166,6 @@ em_init_locked(struct adapter *adapter)
/* Setup VLAN support, basic and offload if available */
E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN);
- /* Use real VLAN Filter support? */
- if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
- if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
- /* Use real VLAN Filter support */
- em_setup_vlan_hw_support(adapter);
- else {
- u32 ctrl;
- ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL);
- ctrl |= E1000_CTRL_VME;
- E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
- }
- }
-
/* Set hardware offload abilities */
ifp->if_hwassist = 0;
if (ifp->if_capenable & IFCAP_TXCSUM)
@@ -1296,6 +1183,17 @@ em_init_locked(struct adapter *adapter)
/* Setup Multicast table */
em_set_multi(adapter);
+ /*
+ ** Figure out the desired mbuf
+ ** pool for doing jumbos
+ */
+ if (adapter->max_frame_size <= 2048)
+ adapter->rx_mbuf_sz = MCLBYTES;
+ else if (adapter->max_frame_size <= 4096)
+ adapter->rx_mbuf_sz = MJUMPAGESIZE;
+ else
+ adapter->rx_mbuf_sz = MJUM9BYTES;
+
/* Prepare receive descriptors and buffers */
if (em_setup_receive_structures(adapter)) {
device_printf(dev, "Could not setup receive structures\n");
@@ -1304,6 +1202,19 @@ em_init_locked(struct adapter *adapter)
}
em_initialize_receive_unit(adapter);
+ /* Use real VLAN Filter support? */
+ if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
+ if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
+ /* Use real VLAN Filter support */
+ em_setup_vlan_hw_support(adapter);
+ else {
+ u32 ctrl;
+ ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_VME;
+ E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
+ }
+ }
+
/* Don't lose promiscuous settings */
em_set_promisc(adapter);
@@ -1359,7 +1270,7 @@ em_init(void *arg)
* Legacy polling routine: note this only works with single queue
*
*********************************************************************/
-static void
+static int
em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
{
struct adapter *adapter = ifp->if_softc;
@@ -1371,7 +1282,7 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
EM_CORE_LOCK(adapter);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
EM_CORE_UNLOCK(adapter);
- return;
+ return (0);
}
if (cmd == POLL_AND_CHECK_STATUS) {
@@ -1390,14 +1301,11 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
EM_TX_LOCK(txr);
em_txeof(txr);
-#ifdef EM_MULTIQUEUE
- if (!drbr_empty(ifp, txr->br))
- em_mq_start_locked(ifp, txr, NULL);
-#else
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
em_start_locked(ifp, txr);
-#endif
EM_TX_UNLOCK(txr);
+
+ return (rx_done);
}
#endif /* DEVICE_POLLING */
@@ -1463,15 +1371,10 @@ em_handle_que(void *context, int pending)
more = em_rxeof(rxr, adapter->rx_process_limit, NULL);
EM_TX_LOCK(txr);
- if (em_txeof(txr))
- more = TRUE;
-#ifdef EM_MULTIQUEUE
- if (!drbr_empty(ifp, txr->br))
- em_mq_start_locked(ifp, txr, NULL);
-#else
+ em_txeof(txr);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
em_start_locked(ifp, txr);
-#endif
+ em_txeof(txr);
EM_TX_UNLOCK(txr);
if (more) {
taskqueue_enqueue(adapter->tq, &adapter->que_task);
@@ -1576,18 +1479,11 @@ em_handle_tx(void *context, int pending)
struct adapter *adapter = txr->adapter;
struct ifnet *ifp = adapter->ifp;
- if (!EM_TX_TRYLOCK(txr))
- return;
-
+ EM_TX_LOCK(txr);
em_txeof(txr);
-
-#ifdef EM_MULTIQUEUE
- if (!drbr_empty(ifp, txr->br))
- em_mq_start_locked(ifp, txr, NULL);
-#else
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
em_start_locked(ifp, txr);
-#endif
+ em_txeof(txr);
E1000_WRITE_REG(&adapter->hw, E1000_IMS, txr->ims);
EM_TX_UNLOCK(txr);
}
@@ -1714,11 +1610,6 @@ em_media_change(struct ifnet *ifp)
device_printf(adapter->dev, "Unsupported media type\n");
}
- /* As the speed/duplex settings my have changed we need to
- * reset the PHY.
- */
- adapter->hw.phy.reset_disable = FALSE;
-
em_init_locked(adapter);
EM_CORE_UNLOCK(adapter);
@@ -1741,37 +1632,119 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp)
struct em_buffer *tx_buffer, *tx_buffer_mapped;
struct e1000_tx_desc *ctxd = NULL;
struct mbuf *m_head;
+ struct ether_header *eh;
+ struct ip *ip = NULL;
+ struct tcphdr *tp = NULL;
u32 txd_upper, txd_lower, txd_used, txd_saved;
+ int ip_off, poff;
int nsegs, i, j, first, last = 0;
int error, do_tso, tso_desc = 0;
m_head = *m_headp;
txd_upper = txd_lower = txd_used = txd_saved = 0;
do_tso = ((m_head->m_pkthdr.csum_flags & CSUM_TSO) != 0);
+ ip_off = poff = 0;
/*
- ** When doing checksum offload, it is critical to
- ** make sure the first mbuf has more than header,
- ** because that routine expects data to be present.
- */
- if ((m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) &&
- (m_head->m_len < ETHER_HDR_LEN + sizeof(struct ip))) {
- m_head = m_pullup(m_head, ETHER_HDR_LEN + sizeof(struct ip));
- *m_headp = m_head;
- if (m_head == NULL)
- return (ENOBUFS);
- }
-
- /*
- * TSO workaround:
- * If an mbuf is only header we need
- * to pull 4 bytes of data into it.
+ * 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_len <= M_TSO_LEN)) {
- m_head = m_pullup(m_head, M_TSO_LEN + 4);
- *m_headp = m_head;
- if (m_head == NULL)
+ 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_DONTWAIT);
+ m_freem(*m_headp);
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ *m_headp = m_head;
+ }
+ }
+ /*
+ * XXX
+ * Assume IPv4, we don't have TSO/checksum offload support
+ * for IPv6 yet.
+ */
+ ip_off = sizeof(struct ether_header);
+ m_head = m_pullup(m_head, ip_off);
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ eh = mtod(m_head, struct ether_header *);
+ if (eh->ether_type == htons(ETHERTYPE_VLAN)) {
+ ip_off = sizeof(struct ether_vlan_header);
+ m_head = m_pullup(m_head, ip_off);
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ }
+ m_head = m_pullup(m_head, ip_off + sizeof(struct ip));
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ ip = (struct ip *)(mtod(m_head, char *) + ip_off);
+ poff = ip_off + (ip->ip_hl << 2);
+ m_head = m_pullup(m_head, poff + sizeof(struct tcphdr));
+ if (m_head == NULL) {
+ *m_headp = NULL;
return (ENOBUFS);
+ }
+ if (do_tso) {
+ tp = (struct tcphdr *)(mtod(m_head, char *) + poff);
+ /*
+ * TSO workaround:
+ * pull 4 more bytes of data into it.
+ */
+ m_head = m_pullup(m_head, poff + (tp->th_off << 2) + 4);
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ ip = (struct ip *)(mtod(m_head, char *) + ip_off);
+ ip->ip_len = 0;
+ ip->ip_sum = 0;
+ /*
+ * 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.
+ */
+ tp = (struct tcphdr *)(mtod(m_head, char *) + poff);
+ tp->th_sum = in_pseudo(ip->ip_src.s_addr,
+ ip->ip_dst.s_addr, htons(IPPROTO_TCP));
+ } else if (m_head->m_pkthdr.csum_flags & CSUM_TCP) {
+ tp = (struct tcphdr *)(mtod(m_head, char *) + poff);
+ m_head = m_pullup(m_head, poff + (tp->th_off << 2));
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ ip = (struct ip *)(mtod(m_head, char *) + ip_off);
+ tp = (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 *) + ip_off);
+ }
+ *m_headp = m_head;
}
/*
@@ -1846,18 +1819,14 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp)
m_head = *m_headp;
/* Do hardware assists */
-#if __FreeBSD_version >= 700000
if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
- error = em_tso_setup(txr, m_head, &txd_upper, &txd_lower);
- if (error != TRUE)
- return (ENXIO); /* something foobar */
+ em_tso_setup(txr, m_head, ip_off, ip, tp,
+ &txd_upper, &txd_lower);
/* we need to make a final sentinel transmit desc */
tso_desc = TRUE;
- } else
-#endif
- if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD)
- em_transmit_checksum_setup(txr, m_head,
- &txd_upper, &txd_lower);
+ } else if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD)
+ em_transmit_checksum_setup(txr, m_head,
+ ip_off, ip, &txd_upper, &txd_lower);
i = txr->next_avail_desc;
@@ -1942,6 +1911,8 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp)
*/
tx_buffer = &txr->tx_buffers[first];
tx_buffer->next_eop = last;
+ /* Update the watchdog time early and often */
+ txr->watchdog_time = ticks;
/*
* Advance the Transmit Descriptor Tail (TDT), this tells the E1000
@@ -2020,11 +1991,7 @@ em_set_multi(struct adapter *adapter)
msec_delay(5);
}
-#if __FreeBSD_version < 800000
IF_ADDR_LOCK(ifp);
-#else
- if_maddr_rlock(ifp);
-#endif
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
@@ -2036,11 +2003,7 @@ em_set_multi(struct adapter *adapter)
&mta[mcnt * ETH_ADDR_LEN], ETH_ADDR_LEN);
mcnt++;
}
-#if __FreeBSD_version < 800000
IF_ADDR_UNLOCK(ifp);
-#else
- if_maddr_runlock(ifp);
-#endif
if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) {
reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
reg_rctl |= E1000_RCTL_MPE;
@@ -2080,27 +2043,38 @@ em_local_timer(void *arg)
em_update_stats_counters(adapter);
/* Reset LAA into RAR[0] on 82571 */
- if (e1000_get_laa_state_82571(&adapter->hw) == TRUE)
+ if ((adapter->hw.mac.type == e1000_82571) &&
+ e1000_get_laa_state_82571(&adapter->hw))
e1000_rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
+ /*
+ ** Don't do TX watchdog check if we've been paused
+ */
+ if (adapter->pause_frames) {
+ adapter->pause_frames = 0;
+ goto out;
+ }
/*
- ** Check for time since any descriptor was cleaned
+ ** Check on the state of the TX queue(s), this
+ ** can be done without the lock because its RO
+ ** and the HUNG state will be static if set.
*/
- for (int i = 0; i < adapter->num_queues; i++, txr++) {
- EM_TX_LOCK(txr);
- if (txr->watchdog_check == FALSE) {
- EM_TX_UNLOCK(txr);
- continue;
- }
- if ((ticks - txr->watchdog_time) > EM_WATCHDOG)
+ for (int i = 0; i < adapter->num_queues; i++, txr++)
+ if (txr->queue_status == EM_QUEUE_HUNG)
goto hung;
- EM_TX_UNLOCK(txr);
- }
-
+out:
callout_reset(&adapter->timer, hz, em_local_timer, adapter);
return;
hung:
+ /* Looks like we're hung */
device_printf(adapter->dev, "Watchdog timeout -- resetting\n");
+ device_printf(adapter->dev,
+ "Queue(%d) tdh = %d, hw tdt = %d\n", txr->me,
+ E1000_READ_REG(&adapter->hw, E1000_TDH(txr->me)),
+ E1000_READ_REG(&adapter->hw, E1000_TDT(txr->me)));
+ device_printf(adapter->dev,"TX(%d) desc avail = %d,"
+ "Next TX to Clean = %d\n",
+ txr->me, txr->tx_avail, txr->next_to_clean);
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
adapter->watchdog_events++;
EM_TX_UNLOCK(txr);
@@ -2114,6 +2088,7 @@ em_update_link_status(struct adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
struct ifnet *ifp = adapter->ifp;
device_t dev = adapter->dev;
+ struct tx_ring *txr = adapter->tx_rings;
u32 link_check = 0;
/* Get the cached link value or read phy for real */
@@ -2171,8 +2146,8 @@ em_update_link_status(struct adapter *adapter)
device_printf(dev, "Link is Down\n");
adapter->link_active = 0;
/* Link down, disable watchdog */
- // JFV change later
- //adapter->watchdog_check = FALSE;
+ for (int i = 0; i < adapter->num_queues; i++, txr++)
+ txr->queue_status = EM_QUEUE_IDLE;
if_link_state_change(ifp, LINK_STATE_DOWN);
}
}
@@ -2206,7 +2181,7 @@ em_stop(void *arg)
/* Unarm watchdog timer. */
for (int i = 0; i < adapter->num_queues; i++, txr++) {
EM_TX_LOCK(txr);
- txr->watchdog_check = FALSE;
+ txr->queue_status = EM_QUEUE_IDLE;
EM_TX_UNLOCK(txr);
}
@@ -2462,6 +2437,9 @@ em_free_pci_resources(struct adapter *adapter)
for (int i = 0; i < adapter->num_queues; i++) {
txr = &adapter->tx_rings[i];
rxr = &adapter->rx_rings[i];
+ /* an early abort? */
+ if ((txr == NULL) || (rxr == NULL))
+ break;
rid = txr->msix +1;
if (txr->tag != NULL) {
bus_teardown_intr(dev, txr->res, txr->tag);
@@ -2520,7 +2498,12 @@ em_setup_msix(struct adapter *adapter)
int val = 0;
- /* Setup MSI/X for Hartwell */
+ /*
+ ** Setup MSI/X for Hartwell: tests have shown
+ ** use of two queues to be unstable, and to
+ ** provide no great gain anyway, so we simply
+ ** seperate the interrupts and use a single queue.
+ */
if ((adapter->hw.mac.type == e1000_82574) &&
(em_enable_msix == TRUE)) {
/* Map the MSIX BAR */
@@ -2534,21 +2517,16 @@ em_setup_msix(struct adapter *adapter)
goto msi;
}
val = pci_msix_count(dev);
- if (val != 5) {
+ if (val < 3) {
bus_release_resource(dev, SYS_RES_MEMORY,
PCIR_BAR(EM_MSIX_BAR), adapter->msix_mem);
adapter->msix_mem = NULL;
device_printf(adapter->dev,
- "MSIX vectors wrong, using MSI \n");
+ "MSIX: insufficient vectors, using MSI\n");
goto msi;
}
- if (em_msix_queues == 2) {
- val = 5;
- adapter->num_queues = 2;
- } else {
- val = 3;
- adapter->num_queues = 1;
- }
+ val = 3;
+ adapter->num_queues = 1;
if (pci_alloc_msix(dev, &val) == 0) {
device_printf(adapter->dev,
"Using MSIX interrupts "
@@ -2561,11 +2539,11 @@ msi:
val = pci_msi_count(dev);
if (val == 1 && pci_alloc_msi(dev, &val) == 0) {
adapter->msix = 1;
- device_printf(adapter->dev,"Using MSI interrupt\n");
+ device_printf(adapter->dev,"Using an MSI interrupt\n");
return (val);
}
- /* Should only happen due to manual invention */
- device_printf(adapter->dev,"Setup MSIX failure\n");
+ /* Should only happen due to manual configuration */
+ device_printf(adapter->dev,"No MSI/MSIX using a Legacy IRQ\n");
return (0);
}
@@ -2580,6 +2558,7 @@ static void
em_reset(struct adapter *adapter)
{
device_t dev = adapter->dev;
+ struct ifnet *ifp = adapter->ifp;
struct e1000_hw *hw = &adapter->hw;
u16 rx_buffer_size;
@@ -2624,18 +2603,29 @@ em_reset(struct adapter *adapter)
hw->fc.send_xon = TRUE;
/* Set Flow control, use the tunable location if sane */
- if ((em_fc_setting >= 0) || (em_fc_setting < 4))
- hw->fc.requested_mode = em_fc_setting;
- else
- hw->fc.requested_mode = e1000_fc_none;
+ hw->fc.requested_mode = adapter->fc_setting;
- /* Override - workaround for PCHLAN issue */
+ /* Workaround: no TX flow ctrl for PCH */
if (hw->mac.type == e1000_pchlan)
hw->fc.requested_mode = e1000_fc_rx_pause;
+ /* Override - settings for PCH2LAN, ya its magic :) */
+ if (hw->mac.type == e1000_pch2lan) {
+ hw->fc.high_water = 0x5C20;
+ hw->fc.low_water = 0x5048;
+ hw->fc.pause_time = 0x0650;
+ hw->fc.refresh_time = 0x0400;
+ /* Jumbos need adjusted PBA */
+ if (ifp->if_mtu > ETHERMTU)
+ E1000_WRITE_REG(hw, E1000_PBA, 12);
+ else
+ E1000_WRITE_REG(hw, E1000_PBA, 26);
+ }
+
/* Issue a global reset */
e1000_reset_hw(hw);
E1000_WRITE_REG(hw, E1000_WUC, 0);
+ em_disable_aspm(adapter);
if (e1000_init_hw(hw) < 0) {
device_printf(dev, "Hardware Initialization Failed\n");
@@ -2680,12 +2670,6 @@ em_setup_interface(device_t dev, struct adapter *adapter)
ifp->if_capabilities = ifp->if_capenable = 0;
-#ifdef EM_MULTIQUEUE
- /* Multiqueue tx functions */
- ifp->if_transmit = em_mq_start;
- ifp->if_qflush = em_qflush;
-#endif
-
ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
ifp->if_capenable |= IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
@@ -2909,11 +2893,6 @@ em_allocate_queues(struct adapter *adapter)
error = ENOMEM;
goto err_tx_desc;
}
-#if __FreeBSD_version >= 800000
- /* Allocate a buf ring */
- txr->br = buf_ring_alloc(4096, M_DEVBUF,
- M_WAITOK, &txr->tx_mtx);
-#endif
}
/*
@@ -2960,9 +2939,6 @@ err_tx_desc:
em_dma_free(adapter, &txr->txdma);
free(adapter->rx_rings, M_DEVBUF);
rx_fail:
-#if __FreeBSD_version >= 800000
- buf_ring_free(txr->br, M_DEVBUF);
-#endif
free(adapter->tx_rings, M_DEVBUF);
fail:
return (error);
@@ -3064,6 +3040,14 @@ em_setup_transmit_ring(struct tx_ring *txr)
/* Set number of descriptors available */
txr->tx_avail = adapter->num_tx_desc;
+ txr->queue_status = EM_QUEUE_IDLE;
+
+ /* Clear checksum offload context. */
+ txr->last_hw_offload = 0;
+ txr->last_hw_ipcss = 0;
+ txr->last_hw_ipcso = 0;
+ txr->last_hw_tucss = 0;
+ txr->last_hw_tucso = 0;
bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@@ -3117,7 +3101,7 @@ em_initialize_transmit_unit(struct adapter *adapter)
E1000_READ_REG(&adapter->hw, E1000_TDBAL(i)),
E1000_READ_REG(&adapter->hw, E1000_TDLEN(i)));
- txr->watchdog_check = FALSE;
+ txr->queue_status = EM_QUEUE_IDLE;
}
/* Set the default values for the Tx Inter Packet Gap timer */
@@ -3242,10 +3226,6 @@ em_free_transmit_buffers(struct tx_ring *txr)
txbuf->map = NULL;
}
}
-#if __FreeBSD_version >= 800000
- if (txr->br != NULL)
- buf_ring_free(txr->br, M_DEVBUF);
-#endif
if (txr->tx_buffers != NULL) {
free(txr->tx_buffers, M_DEVBUF);
txr->tx_buffers = NULL;
@@ -3259,146 +3239,138 @@ em_free_transmit_buffers(struct tx_ring *txr)
/*********************************************************************
- *
- * The offload context needs to be set when we transfer the first
- * packet of a particular protocol (TCP/UDP). This routine has been
- * enhanced to deal with inserted VLAN headers, and IPV6 (not complete)
- *
- * Added back the old method of keeping the current context type
- * and not setting if unnecessary, as this is reported to be a
- * big performance win. -jfv
+ * The offload context is protocol specific (TCP/UDP) and thus
+ * only needs to be set when the protocol changes. The occasion
+ * of a context change can be a performance detriment, and
+ * might be better just disabled. The reason arises in the way
+ * in which the controller supports pipelined requests from the
+ * Tx data DMA. Up to four requests can be pipelined, and they may
+ * belong to the same packet or to multiple packets. However all
+ * requests for one packet are issued before a request is issued
+ * for a subsequent packet and if a request for the next packet
+ * requires a context change, that request will be stalled
+ * until the previous request completes. This means setting up
+ * a new context effectively disables pipelined Tx data DMA which
+ * in turn greatly slow down performance to send small sized
+ * frames.
**********************************************************************/
static void
-em_transmit_checksum_setup(struct tx_ring *txr, struct mbuf *mp,
- u32 *txd_upper, u32 *txd_lower)
+em_transmit_checksum_setup(struct tx_ring *txr, struct mbuf *mp, int ip_off,
+ struct ip *ip, u32 *txd_upper, u32 *txd_lower)
{
struct adapter *adapter = txr->adapter;
struct e1000_context_desc *TXD = NULL;
- struct em_buffer *tx_buffer;
- struct ether_vlan_header *eh;
- struct ip *ip = NULL;
- struct ip6_hdr *ip6;
- int cur, ehdrlen;
- u32 cmd, hdr_len, ip_hlen;
- u16 etype;
- u8 ipproto;
-
+ struct em_buffer *tx_buffer;
+ int cur, hdr_len;
+ u32 cmd = 0;
+ u16 offload = 0;
+ u8 ipcso, ipcss, tucso, tucss;
- cmd = hdr_len = ipproto = 0;
- *txd_upper = *txd_lower = 0;
+ ipcss = ipcso = tucss = tucso = 0;
+ hdr_len = ip_off + (ip->ip_hl << 2);
cur = txr->next_avail_desc;
- /*
- * Determine where frame payload starts.
- * Jump over vlan headers if already present,
- * helpful for QinQ too.
- */
- eh = mtod(mp, struct ether_vlan_header *);
- if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
- etype = ntohs(eh->evl_proto);
- ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
- } else {
- etype = ntohs(eh->evl_encap_proto);
- ehdrlen = ETHER_HDR_LEN;
- }
-
- /*
- * We only support TCP/UDP for IPv4 and IPv6 for the moment.
- * TODO: Support SCTP too when it hits the tree.
- */
- switch (etype) {
- case ETHERTYPE_IP:
- ip = (struct ip *)(mp->m_data + ehdrlen);
- ip_hlen = ip->ip_hl << 2;
-
- /* Setup of IP header checksum. */
- if (mp->m_pkthdr.csum_flags & CSUM_IP) {
- /*
- * Start offset for header checksum calculation.
- * End offset for header checksum calculation.
- * Offset of place to put the checksum.
- */
- TXD = (struct e1000_context_desc *)
- &txr->tx_base[cur];
- TXD->lower_setup.ip_fields.ipcss = ehdrlen;
- TXD->lower_setup.ip_fields.ipcse =
- htole16(ehdrlen + ip_hlen);
- TXD->lower_setup.ip_fields.ipcso =
- ehdrlen + offsetof(struct ip, ip_sum);
- cmd |= E1000_TXD_CMD_IP;
- *txd_upper |= E1000_TXD_POPTS_IXSM << 8;
- }
-
- hdr_len = ehdrlen + ip_hlen;
- ipproto = ip->ip_p;
- break;
-
- case ETHERTYPE_IPV6:
- ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
- ip_hlen = sizeof(struct ip6_hdr); /* XXX: No header stacking. */
-
- /* IPv6 doesn't have a header checksum. */
-
- hdr_len = ehdrlen + ip_hlen;
- ipproto = ip6->ip6_nxt;
- break;
-
- default:
- return;
+ /* Setup of IP header checksum. */
+ if (mp->m_pkthdr.csum_flags & CSUM_IP) {
+ *txd_upper |= E1000_TXD_POPTS_IXSM << 8;
+ offload |= CSUM_IP;
+ ipcss = ip_off;
+ ipcso = ip_off + offsetof(struct ip, ip_sum);
+ /*
+ * Start offset for header checksum calculation.
+ * End offset for header checksum calculation.
+ * Offset of place to put the checksum.
+ */
+ TXD = (struct e1000_context_desc *)&txr->tx_base[cur];
+ TXD->lower_setup.ip_fields.ipcss = ipcss;
+ TXD->lower_setup.ip_fields.ipcse = htole16(hdr_len);
+ TXD->lower_setup.ip_fields.ipcso = ipcso;
+ cmd |= E1000_TXD_CMD_IP;
}
- switch (ipproto) {
- case IPPROTO_TCP:
- if (mp->m_pkthdr.csum_flags & CSUM_TCP) {
- *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
- *txd_upper |= E1000_TXD_POPTS_TXSM << 8;
- /* no need for context if already set */
- if (txr->last_hw_offload == CSUM_TCP)
- return;
- txr->last_hw_offload = CSUM_TCP;
- /*
- * Start offset for payload checksum calculation.
- * End offset for payload checksum calculation.
- * Offset of place to put the checksum.
- */
- TXD = (struct e1000_context_desc *)
- &txr->tx_base[cur];
- TXD->upper_setup.tcp_fields.tucss = hdr_len;
- TXD->upper_setup.tcp_fields.tucse = htole16(0);
- TXD->upper_setup.tcp_fields.tucso =
- hdr_len + offsetof(struct tcphdr, th_sum);
- cmd |= E1000_TXD_CMD_TCP;
- }
- break;
- case IPPROTO_UDP:
- {
- if (mp->m_pkthdr.csum_flags & CSUM_UDP) {
- *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
- *txd_upper |= E1000_TXD_POPTS_TXSM << 8;
- /* no need for context if already set */
- if (txr->last_hw_offload == CSUM_UDP)
- return;
- txr->last_hw_offload = CSUM_UDP;
- /*
- * Start offset for header checksum calculation.
- * End offset for header checksum calculation.
- * Offset of place to put the checksum.
- */
- TXD = (struct e1000_context_desc *)
- &txr->tx_base[cur];
- TXD->upper_setup.tcp_fields.tucss = hdr_len;
- TXD->upper_setup.tcp_fields.tucse = htole16(0);
- TXD->upper_setup.tcp_fields.tucso =
- hdr_len + offsetof(struct udphdr, uh_sum);
- }
- /* Fall Thru */
- }
- default:
- break;
- }
+ if (mp->m_pkthdr.csum_flags & CSUM_TCP) {
+ *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+ *txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+ offload |= CSUM_TCP;
+ tucss = hdr_len;
+ tucso = hdr_len + offsetof(struct tcphdr, th_sum);
+ /*
+ * Setting up new checksum offload context for every frames
+ * takes a lot of processing time for hardware. This also
+ * reduces performance a lot for small sized frames so avoid
+ * it if driver can use previously configured checksum
+ * offload context.
+ */
+ if (txr->last_hw_offload == offload) {
+ if (offload & CSUM_IP) {
+ if (txr->last_hw_ipcss == ipcss &&
+ txr->last_hw_ipcso == ipcso &&
+ txr->last_hw_tucss == tucss &&
+ txr->last_hw_tucso == tucso)
+ return;
+ } else {
+ if (txr->last_hw_tucss == tucss &&
+ txr->last_hw_tucso == tucso)
+ return;
+ }
+ }
+ txr->last_hw_offload = offload;
+ txr->last_hw_tucss = tucss;
+ txr->last_hw_tucso = tucso;
+ /*
+ * Start offset for payload checksum calculation.
+ * End offset for payload checksum calculation.
+ * Offset of place to put the checksum.
+ */
+ TXD = (struct e1000_context_desc *)&txr->tx_base[cur];
+ TXD->upper_setup.tcp_fields.tucss = hdr_len;
+ TXD->upper_setup.tcp_fields.tucse = htole16(0);
+ TXD->upper_setup.tcp_fields.tucso = tucso;
+ cmd |= E1000_TXD_CMD_TCP;
+ } else if (mp->m_pkthdr.csum_flags & CSUM_UDP) {
+ *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+ *txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+ tucss = hdr_len;
+ tucso = hdr_len + offsetof(struct udphdr, uh_sum);
+ /*
+ * Setting up new checksum offload context for every frames
+ * takes a lot of processing time for hardware. This also
+ * reduces performance a lot for small sized frames so avoid
+ * it if driver can use previously configured checksum
+ * offload context.
+ */
+ if (txr->last_hw_offload == offload) {
+ if (offload & CSUM_IP) {
+ if (txr->last_hw_ipcss == ipcss &&
+ txr->last_hw_ipcso == ipcso &&
+ txr->last_hw_tucss == tucss &&
+ txr->last_hw_tucso == tucso)
+ return;
+ } else {
+ if (txr->last_hw_tucss == tucss &&
+ txr->last_hw_tucso == tucso)
+ return;
+ }
+ }
+ txr->last_hw_offload = offload;
+ txr->last_hw_tucss = tucss;
+ txr->last_hw_tucso = tucso;
+ /*
+ * Start offset for header checksum calculation.
+ * End offset for header checksum calculation.
+ * Offset of place to put the checksum.
+ */
+ TXD = (struct e1000_context_desc *)&txr->tx_base[cur];
+ TXD->upper_setup.tcp_fields.tucss = tucss;
+ TXD->upper_setup.tcp_fields.tucse = htole16(0);
+ TXD->upper_setup.tcp_fields.tucso = tucso;
+ }
+
+ if (offload & CSUM_IP) {
+ txr->last_hw_ipcss = ipcss;
+ txr->last_hw_ipcso = ipcso;
+ }
- if (TXD == NULL)
- return;
TXD->tcp_seg_setup.data = htole32(0);
TXD->cmd_and_length =
htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT | cmd);
@@ -3419,124 +3391,52 @@ em_transmit_checksum_setup(struct tx_ring *txr, struct mbuf *mp,
* Setup work for hardware segmentation offload (TSO)
*
**********************************************************************/
-static bool
-em_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *txd_upper,
- u32 *txd_lower)
+static void
+em_tso_setup(struct tx_ring *txr, struct mbuf *mp, int ip_off,
+ struct ip *ip, struct tcphdr *tp, u32 *txd_upper, u32 *txd_lower)
{
struct adapter *adapter = txr->adapter;
struct e1000_context_desc *TXD;
struct em_buffer *tx_buffer;
- struct ether_vlan_header *eh;
- struct ip *ip;
- struct ip6_hdr *ip6;
- struct tcphdr *th;
- int cur, ehdrlen, hdr_len, ip_hlen, isip6;
- u16 etype;
-
- /*
- * This function could/should be extended to support IP/IPv6
- * fragmentation as well. But as they say, one step at a time.
- */
-
- /*
- * Determine where frame payload starts.
- * Jump over vlan headers if already present,
- * helpful for QinQ too.
- */
- eh = mtod(mp, struct ether_vlan_header *);
- if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
- etype = ntohs(eh->evl_proto);
- ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
- } else {
- etype = ntohs(eh->evl_encap_proto);
- ehdrlen = ETHER_HDR_LEN;
- }
-
- /* Ensure we have at least the IP+TCP header in the first mbuf. */
- if (mp->m_len < ehdrlen + sizeof(struct ip) + sizeof(struct tcphdr))
- return FALSE; /* -1 */
+ int cur, hdr_len;
/*
- * We only support TCP for IPv4 and IPv6 (notyet) for the moment.
- * TODO: Support SCTP too when it hits the tree.
+ * In theory we can use the same TSO context if and only if
+ * frame is the same type(IP/TCP) and the same MSS. However
+ * checking whether a frame has the same IP/TCP structure is
+ * hard thing so just ignore that and always restablish a
+ * new TSO context.
*/
- switch (etype) {
- case ETHERTYPE_IP:
- isip6 = 0;
- ip = (struct ip *)(mp->m_data + ehdrlen);
- if (ip->ip_p != IPPROTO_TCP)
- return FALSE; /* 0 */
- ip->ip_len = 0;
- ip->ip_sum = 0;
- ip_hlen = ip->ip_hl << 2;
- if (mp->m_len < ehdrlen + ip_hlen + sizeof(struct tcphdr))
- return FALSE; /* -1 */
- th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
-#if 1
- th->th_sum = in_pseudo(ip->ip_src.s_addr,
- ip->ip_dst.s_addr, htons(IPPROTO_TCP));
-#else
- th->th_sum = mp->m_pkthdr.csum_data;
-#endif
- break;
- case ETHERTYPE_IPV6:
- isip6 = 1;
- return FALSE; /* Not supported yet. */
- ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
- if (ip6->ip6_nxt != IPPROTO_TCP)
- return FALSE; /* 0 */
- ip6->ip6_plen = 0;
- ip_hlen = sizeof(struct ip6_hdr); /* XXX: no header stacking. */
- if (mp->m_len < ehdrlen + ip_hlen + sizeof(struct tcphdr))
- return FALSE; /* -1 */
- th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen);
-#if 0
- th->th_sum = in6_pseudo(ip6->ip6_src, ip->ip6_dst,
- htons(IPPROTO_TCP)); /* XXX: function notyet. */
-#else
- th->th_sum = mp->m_pkthdr.csum_data;
-#endif
- break;
- default:
- return FALSE;
- }
- hdr_len = ehdrlen + ip_hlen + (th->th_off << 2);
-
+ hdr_len = ip_off + (ip->ip_hl << 2) + (tp->th_off << 2);
*txd_lower = (E1000_TXD_CMD_DEXT | /* Extended descr type */
E1000_TXD_DTYP_D | /* Data descr type */
E1000_TXD_CMD_TSE); /* Do TSE on this packet */
/* IP and/or TCP header checksum calculation and insertion. */
- *txd_upper = ((isip6 ? 0 : E1000_TXD_POPTS_IXSM) |
- E1000_TXD_POPTS_TXSM) << 8;
+ *txd_upper = (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8;
cur = txr->next_avail_desc;
tx_buffer = &txr->tx_buffers[cur];
TXD = (struct e1000_context_desc *) &txr->tx_base[cur];
- /* IPv6 doesn't have a header checksum. */
- if (!isip6) {
- /*
- * Start offset for header checksum calculation.
- * End offset for header checksum calculation.
- * Offset of place put the checksum.
- */
- TXD->lower_setup.ip_fields.ipcss = ehdrlen;
- TXD->lower_setup.ip_fields.ipcse =
- htole16(ehdrlen + ip_hlen - 1);
- TXD->lower_setup.ip_fields.ipcso =
- ehdrlen + offsetof(struct ip, ip_sum);
- }
+ /*
+ * Start offset for header checksum calculation.
+ * End offset for header checksum calculation.
+ * Offset of place put the checksum.
+ */
+ TXD->lower_setup.ip_fields.ipcss = ip_off;
+ TXD->lower_setup.ip_fields.ipcse =
+ htole16(ip_off + (ip->ip_hl << 2) - 1);
+ TXD->lower_setup.ip_fields.ipcso = ip_off + offsetof(struct ip, ip_sum);
/*
* Start offset for payload checksum calculation.
* End offset for payload checksum calculation.
* Offset of place to put the checksum.
*/
- TXD->upper_setup.tcp_fields.tucss =
- ehdrlen + ip_hlen;
+ TXD->upper_setup.tcp_fields.tucss = ip_off + (ip->ip_hl << 2);
TXD->upper_setup.tcp_fields.tucse = 0;
TXD->upper_setup.tcp_fields.tucso =
- ehdrlen + ip_hlen + offsetof(struct tcphdr, th_sum);
+ ip_off + (ip->ip_hl << 2) + offsetof(struct tcphdr, th_sum);
/*
* Payload size per packet w/o any headers.
* Length of all headers up to payload.
@@ -3547,7 +3447,7 @@ em_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *txd_upper,
TXD->cmd_and_length = htole32(adapter->txd_cmd |
E1000_TXD_CMD_DEXT | /* Extended descr */
E1000_TXD_CMD_TSE | /* TSE context */
- (isip6 ? 0 : E1000_TXD_CMD_IP) |
+ E1000_TXD_CMD_IP | /* Do IP csum */
E1000_TXD_CMD_TCP | /* Do TCP checksum */
(mp->m_pkthdr.len - (hdr_len))); /* Total len */
@@ -3560,8 +3460,6 @@ em_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *txd_upper,
txr->tx_avail--;
txr->next_avail_desc = cur;
txr->tx_tso = TRUE;
-
- return TRUE;
}
@@ -3576,17 +3474,20 @@ static bool
em_txeof(struct tx_ring *txr)
{
struct adapter *adapter = txr->adapter;
- int first, last, done, num_avail;
+ int first, last, done, processed;
struct em_buffer *tx_buffer;
struct e1000_tx_desc *tx_desc, *eop_desc;
struct ifnet *ifp = adapter->ifp;
EM_TX_LOCK_ASSERT(txr);
- if (txr->tx_avail == adapter->num_tx_desc)
+ /* No work, make sure watchdog is off */
+ if (txr->tx_avail == adapter->num_tx_desc) {
+ txr->queue_status = EM_QUEUE_IDLE;
return (FALSE);
+ }
- num_avail = txr->tx_avail;
+ processed = 0;
first = txr->next_to_clean;
tx_desc = &txr->tx_base[first];
tx_buffer = &txr->tx_buffers[first];
@@ -3612,16 +3513,15 @@ em_txeof(struct tx_ring *txr)
tx_desc->upper.data = 0;
tx_desc->lower.data = 0;
tx_desc->buffer_addr = 0;
- ++num_avail;
+ ++txr->tx_avail;
+ ++processed;
if (tx_buffer->m_head) {
- ifp->if_opackets++;
bus_dmamap_sync(txr->txtag,
tx_buffer->map,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(txr->txtag,
tx_buffer->map);
-
m_freem(tx_buffer->m_head);
tx_buffer->m_head = NULL;
}
@@ -3634,6 +3534,7 @@ em_txeof(struct tx_ring *txr)
tx_buffer = &txr->tx_buffers[first];
tx_desc = &txr->tx_base[first];
}
+ ++ifp->if_opackets;
/* See if we can continue to the next packet */
last = tx_buffer->next_eop;
if (last != -1) {
@@ -3649,21 +3550,29 @@ em_txeof(struct tx_ring *txr)
txr->next_to_clean = first;
+ /*
+ ** Watchdog calculation, we know there's
+ ** work outstanding or the first return
+ ** would have been taken, so none processed
+ ** for too long indicates a hang. local timer
+ ** will examine this and do a reset if needed.
+ */
+ if ((!processed) && ((ticks - txr->watchdog_time) > EM_WATCHDOG))
+ txr->queue_status = EM_QUEUE_HUNG;
+
/*
- * If we have enough room, clear IFF_DRV_OACTIVE to
- * tell the stack that it is OK to send packets.
- * If there are no pending descriptors, clear the watchdog.
+ * If we have enough room, clear IFF_DRV_OACTIVE
+ * to tell the stack that it is OK to send packets.
*/
- if (num_avail > EM_TX_CLEANUP_THRESHOLD) {
+ if (txr->tx_avail > EM_TX_CLEANUP_THRESHOLD) {
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- if (num_avail == adapter->num_tx_desc) {
- txr->watchdog_check = FALSE;
- txr->tx_avail = num_avail;
+ /* Disable watchdog if all clean */
+ if (txr->tx_avail == adapter->num_tx_desc) {
+ txr->queue_status = EM_QUEUE_IDLE;
return (FALSE);
}
}
- txr->tx_avail = num_avail;
return (TRUE);
}
@@ -3679,26 +3588,34 @@ em_refresh_mbufs(struct rx_ring *rxr, int limit)
struct adapter *adapter = rxr->adapter;
struct mbuf *m;
bus_dma_segment_t segs[1];
- bus_dmamap_t map;
struct em_buffer *rxbuf;
int i, error, nsegs, cleaned;
i = rxr->next_to_refresh;
cleaned = -1;
while (i != limit) {
- m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ rxbuf = &rxr->rx_buffers[i];
+ /*
+ ** Just skip entries with a buffer,
+ ** they can only be due to an error
+ ** and are to be reused.
+ */
+ if (rxbuf->m_head != NULL)
+ goto reuse;
+ m = m_getjcl(M_DONTWAIT, MT_DATA,
+ M_PKTHDR, adapter->rx_mbuf_sz);
+ /*
+ ** If we have a temporary resource shortage
+ ** that causes a failure, just abort refresh
+ ** for now, we will return to this point when
+ ** reinvoked from em_rxeof.
+ */
if (m == NULL)
goto update;
- m->m_len = m->m_pkthdr.len = MCLBYTES;
+ m->m_len = m->m_pkthdr.len = adapter->rx_mbuf_sz;
- if (adapter->max_frame_size <= (MCLBYTES - ETHER_ALIGN))
- m_adj(m, ETHER_ALIGN);
-
- /*
- * Using memory from the mbuf cluster pool, invoke the
- * bus_dma machinery to arrange the memory mapping.
- */
- error = bus_dmamap_load_mbuf_sg(rxr->rxtag, rxr->rx_sparemap,
+ /* Use bus_dma machinery to setup the memory mapping */
+ error = bus_dmamap_load_mbuf_sg(rxr->rxtag, rxbuf->map,
m, segs, &nsegs, BUS_DMA_NOWAIT);
if (error != 0) {
m_free(m);
@@ -3708,18 +3625,11 @@ em_refresh_mbufs(struct rx_ring *rxr, int limit)
/* If nsegs is wrong then the stack is corrupt. */
KASSERT(nsegs == 1, ("Too many segments returned!"));
- rxbuf = &rxr->rx_buffers[i];
- if (rxbuf->m_head != NULL)
- bus_dmamap_unload(rxr->rxtag, rxbuf->map);
-
- map = rxbuf->map;
- rxbuf->map = rxr->rx_sparemap;
- rxr->rx_sparemap = map;
bus_dmamap_sync(rxr->rxtag,
rxbuf->map, BUS_DMASYNC_PREREAD);
rxbuf->m_head = m;
rxr->rx_base[i].buffer_addr = htole64(segs[0].ds_addr);
-
+reuse:
cleaned = i;
/* Calculate next index */
if (++i == adapter->num_rx_desc)
@@ -3728,8 +3638,10 @@ em_refresh_mbufs(struct rx_ring *rxr, int limit)
rxr->next_to_refresh = i;
}
update:
- bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
- BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ /*
+ ** Update the tail pointer only if,
+ ** and as far as we have refreshed.
+ */
if (cleaned != -1) /* Update tail index */
E1000_WRITE_REG(&adapter->hw,
E1000_RDT(rxr->me), cleaned);
@@ -3766,9 +3678,9 @@ em_allocate_receive_buffers(struct rx_ring *rxr)
BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
- MCLBYTES, /* maxsize */
+ MJUM9BYTES, /* maxsize */
1, /* nsegments */
- MCLBYTES, /* maxsegsize */
+ MJUM9BYTES, /* maxsegsize */
0, /* flags */
NULL, /* lockfunc */
NULL, /* lockarg */
@@ -3779,15 +3691,6 @@ em_allocate_receive_buffers(struct rx_ring *rxr)
goto fail;
}
- /* Create the spare map (used by getbuf) */
- error = bus_dmamap_create(rxr->rxtag, BUS_DMA_NOWAIT,
- &rxr->rx_sparemap);
- if (error) {
- device_printf(dev, "%s: bus_dmamap_create failed: %d\n",
- __func__, error);
- goto fail;
- }
-
rxbuf = rxr->rx_buffers;
for (int i = 0; i < adapter->num_rx_desc; i++, rxbuf++) {
rxbuf = &rxr->rx_buffers[i];
@@ -3845,12 +3748,13 @@ em_setup_receive_ring(struct rx_ring *rxr)
for (int j = 0; j != adapter->num_rx_desc; ++j) {
rxbuf = &rxr->rx_buffers[j];
- rxbuf->m_head = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ rxbuf->m_head = m_getjcl(M_DONTWAIT, MT_DATA,
+ M_PKTHDR, adapter->rx_mbuf_sz);
if (rxbuf->m_head == NULL)
return (ENOBUFS);
- rxbuf->m_head->m_len = MCLBYTES;
+ rxbuf->m_head->m_len = adapter->rx_mbuf_sz;
rxbuf->m_head->m_flags &= ~M_HASFCS; /* we strip it */
- rxbuf->m_head->m_pkthdr.len = MCLBYTES;
+ rxbuf->m_head->m_pkthdr.len = adapter->rx_mbuf_sz;
/* Get the memory mapping */
error = bus_dmamap_load_mbuf_sg(rxr->rxtag,
@@ -3954,11 +3858,6 @@ em_free_receive_buffers(struct rx_ring *rxr)
INIT_DEBUGOUT("free_receive_buffers: begin");
- if (rxr->rx_sparemap) {
- bus_dmamap_destroy(rxr->rxtag, rxr->rx_sparemap);
- rxr->rx_sparemap = NULL;
- }
-
if (rxr->rx_buffers != NULL) {
for (int i = 0; i < adapter->num_rx_desc; i++) {
rxbuf = &rxr->rx_buffers[i];
@@ -4061,6 +3960,23 @@ em_initialize_receive_unit(struct adapter *adapter)
E1000_WRITE_REG(hw, E1000_RDT(i), adapter->num_rx_desc - 1);
}
+ /* Set early receive threshold on appropriate hw */
+ if (((adapter->hw.mac.type == e1000_ich9lan) ||
+ (adapter->hw.mac.type == e1000_pch2lan) ||
+ (adapter->hw.mac.type == e1000_ich10lan)) &&
+ (ifp->if_mtu > ETHERMTU)) {
+ u32 rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(0));
+ E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl | 3);
+ E1000_WRITE_REG(hw, E1000_ERT, 0x100 | (1 << 13));
+ }
+
+ if (adapter->hw.mac.type == e1000_pch2lan) {
+ if (ifp->if_mtu > ETHERMTU)
+ e1000_lv_jumbo_workaround_ich8lan(hw, TRUE);
+ else
+ e1000_lv_jumbo_workaround_ich8lan(hw, FALSE);
+ }
+
/* Setup the Receive Control Register */
rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
@@ -4073,7 +3989,14 @@ em_initialize_receive_unit(struct adapter *adapter)
/* Make sure VLAN Filters are off */
rctl &= ~E1000_RCTL_VFE;
rctl &= ~E1000_RCTL_SBP;
- rctl |= E1000_RCTL_SZ_2048;
+
+ if (adapter->rx_mbuf_sz == MCLBYTES)
+ rctl |= E1000_RCTL_SZ_2048;
+ else if (adapter->rx_mbuf_sz == MJUMPAGESIZE)
+ rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX;
+ else if (adapter->rx_mbuf_sz > MJUMPAGESIZE)
+ rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX;
+
if (ifp->if_mtu > ETHERMTU)
rctl |= E1000_RCTL_LPE;
else
@@ -4128,71 +4051,62 @@ em_rxeof(struct rx_ring *rxr, int count, int *done)
len = le16toh(cur->length);
eop = (status & E1000_RXD_STAT_EOP) != 0;
- count--;
- if ((cur->errors & E1000_RXD_ERR_FRAME_ERR_MASK) == 0) {
+ if ((rxr->discard == TRUE) || (cur->errors &
+ E1000_RXD_ERR_FRAME_ERR_MASK)) {
+ ifp->if_ierrors++;
+ ++rxr->rx_discarded;
+ if (!eop) /* Catch subsequent segs */
+ rxr->discard = TRUE;
+ else
+ rxr->discard = FALSE;
+ em_rx_discard(rxr, i);
+ goto next_desc;
+ }
- /* Assign correct length to the current fragment */
- mp = rxr->rx_buffers[i].m_head;
- mp->m_len = len;
+ /* Assign correct length to the current fragment */
+ mp = rxr->rx_buffers[i].m_head;
+ mp->m_len = len;
- if (rxr->fmp == NULL) {
- mp->m_pkthdr.len = len;
- rxr->fmp = mp; /* Store the first mbuf */
- rxr->lmp = mp;
- } else {
- /* Chain mbuf's together */
- mp->m_flags &= ~M_PKTHDR;
- rxr->lmp->m_next = mp;
- rxr->lmp = rxr->lmp->m_next;
- rxr->fmp->m_pkthdr.len += len;
- }
+ /* Trigger for refresh */
+ rxr->rx_buffers[i].m_head = NULL;
- if (eop) {
- rxr->fmp->m_pkthdr.rcvif = ifp;
- ifp->if_ipackets++;
- em_receive_checksum(cur, rxr->fmp);
+ /* First segment? */
+ if (rxr->fmp == NULL) {
+ mp->m_pkthdr.len = len;
+ rxr->fmp = rxr->lmp = mp;
+ } else {
+ /* Chain mbuf's together */
+ mp->m_flags &= ~M_PKTHDR;
+ rxr->lmp->m_next = mp;
+ rxr->lmp = mp;
+ rxr->fmp->m_pkthdr.len += len;
+ }
+
+ if (eop) {
+ --count;
+ sendmp = rxr->fmp;
+ sendmp->m_pkthdr.rcvif = ifp;
+ ifp->if_ipackets++;
+ em_receive_checksum(cur, sendmp);
#ifndef __NO_STRICT_ALIGNMENT
- if (adapter->max_frame_size >
- (MCLBYTES - ETHER_ALIGN) &&
- em_fixup_rx(rxr) != 0)
- goto skip;
-#endif
- if (status & E1000_RXD_STAT_VP) {
- rxr->fmp->m_pkthdr.ether_vtag =
- (le16toh(cur->special) &
- E1000_RXD_SPC_VLAN_MASK);
- rxr->fmp->m_flags |= M_VLANTAG;
- }
-#ifdef EM_MULTIQUEUE
- rxr->fmp->m_pkthdr.flowid = curcpu;
- rxr->fmp->m_flags |= M_FLOWID;
+ if (adapter->max_frame_size >
+ (MCLBYTES - ETHER_ALIGN) &&
+ em_fixup_rx(rxr) != 0)
+ goto skip;
#endif
+ if (status & E1000_RXD_STAT_VP) {
+ sendmp->m_pkthdr.ether_vtag =
+ (le16toh(cur->special) &
+ E1000_RXD_SPC_VLAN_MASK);
+ sendmp->m_flags |= M_VLANTAG;
+ }
#ifndef __NO_STRICT_ALIGNMENT
skip:
#endif
- sendmp = rxr->fmp;
- rxr->fmp = NULL;
- rxr->lmp = NULL;
- }
- } else {
- ifp->if_ierrors++;
- /* Reuse loaded DMA map and just update mbuf chain */
- mp = rxr->rx_buffers[i].m_head;
- mp->m_len = mp->m_pkthdr.len = MCLBYTES;
- mp->m_data = mp->m_ext.ext_buf;
- mp->m_next = NULL;
- if (adapter->max_frame_size <=
- (MCLBYTES - ETHER_ALIGN))
- m_adj(mp, ETHER_ALIGN);
- if (rxr->fmp != NULL) {
- m_freem(rxr->fmp);
- rxr->fmp = NULL;
- rxr->lmp = NULL;
- }
- sendmp = NULL;
+ rxr->fmp = rxr->lmp = NULL;
}
-
+next_desc:
/* Zero out the receive descriptors status. */
cur->status = 0;
++rxdone; /* cumulative for POLL */
@@ -4219,10 +4133,7 @@ skip:
}
/* Catch any remaining refresh work */
- if (processed != 0) {
- em_refresh_mbufs(rxr, i);
- processed = 0;
- }
+ em_refresh_mbufs(rxr, i);
rxr->next_to_check = i;
if (done != NULL)
@@ -4232,6 +4143,32 @@ skip:
return ((status & E1000_RXD_STAT_DD) ? TRUE : FALSE);
}
+static __inline void
+em_rx_discard(struct rx_ring *rxr, int i)
+{
+ struct adapter *adapter = rxr->adapter;
+ struct em_buffer *rbuf;
+ struct mbuf *m;
+
+ rbuf = &rxr->rx_buffers[i];
+ /* Free any previous pieces */
+ if (rxr->fmp != NULL) {
+ rxr->fmp->m_flags |= M_PKTHDR;
+ m_freem(rxr->fmp);
+ rxr->fmp = NULL;
+ rxr->lmp = NULL;
+ }
+
+ /* Reset state, keep loaded DMA map and reuse */
+ m = rbuf->m_head;
+ m->m_len = m->m_pkthdr.len = adapter->rx_mbuf_sz;
+ m->m_flags |= M_PKTHDR;
+ m->m_data = m->m_ext.ext_buf;
+ m->m_next = NULL;
+
+ return;
+}
+
#ifndef __NO_STRICT_ALIGNMENT
/*
* When jumbo frames are enabled we should realign entire payload on
@@ -4335,12 +4272,15 @@ em_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
if ((vtag == 0) || (vtag > 4095)) /* Invalid ID */
return;
+ EM_CORE_LOCK(adapter);
index = (vtag >> 5) & 0x7F;
bit = vtag & 0x1F;
- em_shadow_vfta[index] |= (1 << bit);
+ adapter->shadow_vfta[index] |= (1 << bit);
++adapter->num_vlans;
/* Re-init to load the changes */
- em_init(adapter);
+ if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
+ em_init_locked(adapter);
+ EM_CORE_UNLOCK(adapter);
}
/*
@@ -4359,12 +4299,15 @@ em_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
if ((vtag == 0) || (vtag > 4095)) /* Invalid */
return;
+ EM_CORE_LOCK(adapter);
index = (vtag >> 5) & 0x7F;
bit = vtag & 0x1F;
- em_shadow_vfta[index] &= ~(1 << bit);
+ adapter->shadow_vfta[index] &= ~(1 << bit);
--adapter->num_vlans;
/* Re-init to load the changes */
- em_init(adapter);
+ if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
+ em_init_locked(adapter);
+ EM_CORE_UNLOCK(adapter);
}
static void
@@ -4387,9 +4330,9 @@ em_setup_vlan_hw_support(struct adapter *adapter)
** we need to repopulate it now.
*/
for (int i = 0; i < EM_VFTA_SIZE; i++)
- if (em_shadow_vfta[i] != 0)
+ if (adapter->shadow_vfta[i] != 0)
E1000_WRITE_REG_ARRAY(hw, E1000_VFTA,
- i, em_shadow_vfta[i]);
+ i, adapter->shadow_vfta[i]);
reg = E1000_READ_REG(hw, E1000_CTRL);
reg |= E1000_CTRL_VME;
@@ -4400,10 +4343,6 @@ em_setup_vlan_hw_support(struct adapter *adapter)
reg &= ~E1000_RCTL_CFIEN;
reg |= E1000_RCTL_VFE;
E1000_WRITE_REG(hw, E1000_RCTL, reg);
-
- /* Update the frame size */
- E1000_WRITE_REG(&adapter->hw, E1000_RLPML,
- adapter->max_frame_size + VLAN_TAG_SIZE);
}
static void
@@ -4572,6 +4511,7 @@ em_get_wakeup(device_t dev)
case e1000_ich9lan:
case e1000_ich10lan:
case e1000_pchlan:
+ case e1000_pch2lan:
apme_mask = E1000_WUC_APME;
adapter->has_amt = TRUE;
eeprom_data = E1000_READ_REG(&adapter->hw, E1000_WUC);
@@ -4663,7 +4603,8 @@ em_enable_wakeup(device_t dev)
E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl);
}
- if (adapter->hw.mac.type == e1000_pchlan) {
+ if ((adapter->hw.mac.type == e1000_pchlan) ||
+ (adapter->hw.mac.type == e1000_pch2lan)) {
if (em_enable_phy_wakeup(adapter))
return;
} else {
@@ -4696,16 +4637,7 @@ em_enable_phy_wakeup(struct adapter *adapter)
u16 preg;
/* copy MAC RARs to PHY RARs */
- for (int i = 0; i < adapter->hw.mac.rar_entry_count; i++) {
- mreg = E1000_READ_REG(hw, E1000_RAL(i));
- e1000_write_phy_reg(hw, BM_RAR_L(i), (u16)(mreg & 0xFFFF));
- e1000_write_phy_reg(hw, BM_RAR_M(i),
- (u16)((mreg >> 16) & 0xFFFF));
- mreg = E1000_READ_REG(hw, E1000_RAH(i));
- e1000_write_phy_reg(hw, BM_RAR_H(i), (u16)(mreg & 0xFFFF));
- e1000_write_phy_reg(hw, BM_RAR_CTRL(i),
- (u16)((mreg >> 16) & 0xFFFF));
- }
+ e1000_copy_rx_addrs_to_phy_ich8lan(hw);
/* copy MAC MTA to PHY MTA */
for (int i = 0; i < adapter->hw.mac.mta_reg_count; i++) {
@@ -4783,6 +4715,37 @@ em_led_func(void *arg, int onoff)
EM_CORE_UNLOCK(adapter);
}
+/*
+** Disable the L0S and L1 LINK states
+*/
+static void
+em_disable_aspm(struct adapter *adapter)
+{
+ int base, reg;
+ u16 link_cap,link_ctrl;
+ device_t dev = adapter->dev;
+
+ switch (adapter->hw.mac.type) {
+ case e1000_82573:
+ case e1000_82574:
+ case e1000_82583:
+ break;
+ default:
+ return;
+ }
+ if (pci_find_extcap(dev, PCIY_EXPRESS, &base) != 0)
+ return;
+ reg = base + PCIR_EXPRESS_LINK_CAP;
+ link_cap = pci_read_config(dev, reg, 2);
+ if ((link_cap & PCIM_LINK_CAP_ASPM) == 0)
+ return;
+ reg = base + PCIR_EXPRESS_LINK_CTL;
+ link_ctrl = pci_read_config(dev, reg, 2);
+ link_ctrl &= 0xFFFC; /* turn off bit 1 and 2 */
+ pci_write_config(dev, reg, link_ctrl, 2);
+ return;
+}
+
/**********************************************************************
*
* Update the board statistics counters.
@@ -4810,7 +4773,12 @@ em_update_stats_counters(struct adapter *adapter)
adapter->stats.rlec += E1000_READ_REG(&adapter->hw, E1000_RLEC);
adapter->stats.xonrxc += E1000_READ_REG(&adapter->hw, E1000_XONRXC);
adapter->stats.xontxc += E1000_READ_REG(&adapter->hw, E1000_XONTXC);
- adapter->stats.xoffrxc += E1000_READ_REG(&adapter->hw, E1000_XOFFRXC);
+ /*
+ ** For watchdog management we need to know if we have been
+ ** paused during the last interval, so capture that here.
+ */
+ adapter->pause_frames = E1000_READ_REG(&adapter->hw, E1000_XOFFRXC);
+ adapter->stats.xoffrxc += adapter->pause_frames;
adapter->stats.xofftxc += E1000_READ_REG(&adapter->hw, E1000_XOFFTXC);
adapter->stats.fcruc += E1000_READ_REG(&adapter->hw, E1000_FCRUC);
adapter->stats.prc64 += E1000_READ_REG(&adapter->hw, E1000_PRC64);
@@ -5191,8 +5159,6 @@ em_add_hw_stats(struct adapter *adapter)
SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "rx_overrun",
CTLFLAG_RD, &adapter->stats.icrxoc,
"Interrupt Cause Receiver Overrun Count");
-
-
}
/**********************************************************************
@@ -5202,7 +5168,6 @@ em_add_hw_stats(struct adapter *adapter)
* 32 words, stuff that matters is in that extent.
*
**********************************************************************/
-
static int
em_sysctl_nvm_info(SYSCTL_HANDLER_ARGS)
{
@@ -5314,4 +5279,70 @@ em_add_rx_process_limit(struct adapter *adapter, const char *name,
OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description);
}
+static void
+em_set_flow_cntrl(struct adapter *adapter, const char *name,
+ const char *description, int *limit, int value)
+{
+ *limit = value;
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)),
+ OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description);
+}
+
+static int
+em_sysctl_debug_info(SYSCTL_HANDLER_ARGS)
+{
+ struct adapter *adapter;
+ int error;
+ int result;
+ result = -1;
+ error = sysctl_handle_int(oidp, &result, 0, req);
+
+ if (error || !req->newptr)
+ return (error);
+
+ if (result == 1) {
+ adapter = (struct adapter *)arg1;
+ em_print_debug_info(adapter);
+ }
+
+ return (error);
+}
+
+/*
+** This routine is meant to be fluid, add whatever is
+** needed for debugging a problem. -jfv
+*/
+static void
+em_print_debug_info(struct adapter *adapter)
+{
+ device_t dev = adapter->dev;
+ struct tx_ring *txr = adapter->tx_rings;
+ struct rx_ring *rxr = adapter->rx_rings;
+
+ if (adapter->ifp->if_drv_flags & IFF_DRV_RUNNING)
+ printf("Interface is RUNNING ");
+ else
+ printf("Interface is NOT RUNNING\n");
+ if (adapter->ifp->if_drv_flags & IFF_DRV_OACTIVE)
+ printf("and ACTIVE\n");
+ else
+ printf("and INACTIVE\n");
+
+ device_printf(dev, "hw tdh = %d, hw tdt = %d\n",
+ E1000_READ_REG(&adapter->hw, E1000_TDH(0)),
+ E1000_READ_REG(&adapter->hw, E1000_TDT(0)));
+ device_printf(dev, "hw rdh = %d, hw rdt = %d\n",
+ E1000_READ_REG(&adapter->hw, E1000_RDH(0)),
+ E1000_READ_REG(&adapter->hw, E1000_RDT(0)));
+ device_printf(dev, "Tx Queue Status = %d\n", txr->queue_status);
+ device_printf(dev, "TX descriptors avail = %d\n",
+ txr->tx_avail);
+ device_printf(dev, "Tx Descriptors avail failure = %ld\n",
+ txr->no_desc_avail);
+ device_printf(dev, "RX discarded packets = %ld\n",
+ rxr->rx_discarded);
+ device_printf(dev, "RX Next to Check = %d\n", rxr->next_to_check);
+ device_printf(dev, "RX Next to Refresh = %d\n", rxr->next_to_refresh);
+}
diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h
index d164edb18592..f163b71605fc 100644
--- a/sys/dev/e1000/if_em.h
+++ b/sys/dev/e1000/if_em.h
@@ -188,6 +188,10 @@
#define EM_EEPROM_APME 0x400;
#define EM_82544_APME 0x0004;
+#define EM_QUEUE_IDLE 0
+#define EM_QUEUE_WORKING 1
+#define EM_QUEUE_HUNG 2
+
/*
* TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be
* multiple of 128 bytes. So we align TDBA/RDBA on 128 byte boundary. This will
@@ -272,7 +276,7 @@ struct tx_ring {
u32 me;
u32 msix;
u32 ims;
- bool watchdog_check;
+ int queue_status;
int watchdog_time;
struct em_dma_alloc txdma;
struct e1000_tx_desc *tx_base;
@@ -284,9 +288,10 @@ struct tx_ring {
volatile u16 tx_avail;
u32 tx_tso; /* last tx was tso */
u16 last_hw_offload;
-#if __FreeBSD_version >= 800000
- struct buf_ring *br;
-#endif
+ u8 last_hw_ipcso;
+ u8 last_hw_ipcss;
+ u8 last_hw_tucso;
+ u8 last_hw_tucss;
/* Interrupt resources */
bus_dma_tag_t txtag;
void *tag;
@@ -320,10 +325,11 @@ struct rx_ring {
void *tag;
struct resource *res;
bus_dma_tag_t rxtag;
- bus_dmamap_t rx_sparemap;
+ bool discard;
/* Soft stats */
unsigned long rx_irq;
+ unsigned long rx_discarded;
unsigned long rx_packets;
unsigned long rx_bytes;
};
@@ -354,6 +360,7 @@ struct adapter {
int if_flags;
int max_frame_size;
int min_frame_size;
+ int pause_frames;
struct mtx core_mtx;
int em_insert_vlan_header;
u32 ims;
@@ -385,6 +392,7 @@ struct adapter {
struct rx_ring *rx_rings;
int num_rx_desc;
u32 rx_process_limit;
+ u32 rx_mbuf_sz;
/* Management and WOL features */
u32 wol;
@@ -393,11 +401,22 @@ struct adapter {
/* Multicast array memory */
u8 *mta;
- /* Info about the board itself */
- uint8_t link_active;
- uint16_t link_speed;
- uint16_t link_duplex;
- uint32_t smartspeed;
+
+ /*
+ ** Shadow VFTA table, this is needed because
+ ** the real vlan filter table gets cleared during
+ ** a soft reset and the driver needs to be able
+ ** to repopulate it.
+ */
+ u32 shadow_vfta[EM_VFTA_SIZE];
+
+ /* Info about the interface */
+ u8 link_active;
+ u16 link_speed;
+ u16 link_duplex;
+ u32 smartspeed;
+ u32 fc_setting;
+
struct em_int_delay_info tx_int_delay;
struct em_int_delay_info tx_abs_int_delay;
struct em_int_delay_info rx_int_delay;
diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c
index b9e31561519a..133887e9d3f7 100644
--- a/sys/dev/e1000/if_igb.c
+++ b/sys/dev/e1000/if_igb.c
@@ -41,9 +41,6 @@
#include <sys/param.h>
#include <sys/systm.h>
-#if __FreeBSD_version >= 800000
-#include <sys/buf_ring.h>
-#endif
#include <sys/bus.h>
#include <sys/endian.h>
#include <sys/kernel.h>
@@ -99,7 +96,7 @@ int igb_display_debug_stats = 0;
/*********************************************************************
* Driver version:
*********************************************************************/
-char igb_driver_version[] = "version - 1.9.6";
+char igb_driver_version[] = "version - 2.0.7";
/*********************************************************************
@@ -128,12 +125,19 @@ static igb_vendor_info_t igb_vendor_info_array[] =
PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_82576_QUAD_COPPER,
PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82576_QUAD_COPPER_ET2,
+ PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82576_VF, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_82580_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_82580_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_82580_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_82580_SGMII, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_82580_COPPER_DUAL,
PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82580_QUAD_FIBER,
+ PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_DH89XXCC_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_DH89XXCC_SGMII, PCI_ANY_ID, PCI_ANY_ID, 0},
/* required last entry */
{ 0, 0, 0, 0, 0}
};
@@ -157,12 +161,6 @@ static int igb_suspend(device_t);
static int igb_resume(device_t);
static void igb_start(struct ifnet *);
static void igb_start_locked(struct tx_ring *, struct ifnet *ifp);
-#if __FreeBSD_version >= 800000
-static int igb_mq_start(struct ifnet *, struct mbuf *);
-static int igb_mq_start_locked(struct ifnet *,
- struct tx_ring *, struct mbuf *);
-static void igb_qflush(struct ifnet *);
-#endif
static int igb_ioctl(struct ifnet *, u_long, caddr_t);
static void igb_init(void *);
static void igb_init_locked(struct adapter *);
@@ -226,7 +224,11 @@ static void igb_dma_free(struct adapter *, struct igb_dma_alloc *);
static int igb_sysctl_nvm_info(SYSCTL_HANDLER_ARGS);
static void igb_print_nvm_info(struct adapter *);
static int igb_is_valid_ether_addr(u8 *);
-static void igb_add_hw_stats(struct adapter *adapter);
+static void igb_add_hw_stats(struct adapter *);
+
+static void igb_vf_init_stats(struct adapter *);
+static void igb_update_vf_stats_counters(struct adapter *);
+
/* Management and WOL Support */
static void igb_init_manageability(struct adapter *);
static void igb_release_manageability(struct adapter *);
@@ -300,11 +302,19 @@ static int igb_enable_msix = 1;
TUNABLE_INT("hw.igb.enable_msix", &igb_enable_msix);
/*
- * Header split has seemed to be beneficial in
- * many circumstances tested, however there have
- * been some stability issues, so the default is
- * off.
- */
+** Tuneable Interrupt rate
+*/
+static int igb_max_interrupt_rate = 8000;
+TUNABLE_INT("hw.igb.max_interrupt_rate", &igb_max_interrupt_rate);
+
+/*
+** Header split causes the packet header to
+** be dma'd to a seperate mbuf from the payload.
+** this can have memory alignment benefits. But
+** another plus is that small packets often fit
+** into the header and thus use no cluster. Its
+** a very workload dependent type feature.
+*/
static bool igb_header_split = FALSE;
TUNABLE_INT("hw.igb.hdr_split", &igb_header_split);
@@ -323,15 +333,6 @@ TUNABLE_INT("hw.igb.rx_process_limit", &igb_rx_process_limit);
static int igb_fc_setting = e1000_fc_full;
TUNABLE_INT("hw.igb.fc_setting", &igb_fc_setting);
-/*
-** Shadow VFTA table, this is needed because
-** the real filter table gets cleared during
-** a soft reset and the driver needs to be able
-** to repopulate it.
-*/
-static u32 igb_shadow_vfta[IGB_VFTA_SIZE];
-
-
/*********************************************************************
* Device identification routine
*
@@ -494,6 +495,22 @@ igb_attach(device_t dev)
goto err_pci;
}
+ /* Allocate the appropriate stats memory */
+ if (adapter->hw.mac.type == e1000_vfadapt) {
+ adapter->stats =
+ (struct e1000_vf_stats *)malloc(sizeof \
+ (struct e1000_vf_stats), M_DEVBUF, M_NOWAIT | M_ZERO);
+ igb_vf_init_stats(adapter);
+ } else
+ adapter->stats =
+ (struct e1000_hw_stats *)malloc(sizeof \
+ (struct e1000_hw_stats), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (adapter->stats == NULL) {
+ device_printf(dev, "Can not allocate stats memory\n");
+ error = ENOMEM;
+ goto err_late;
+ }
+
/* Allocate multicast array memory. */
adapter->mta = malloc(sizeof(u8) * ETH_ADDR_LEN *
MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT);
@@ -795,7 +812,7 @@ igb_start_locked(struct tx_ring *txr, struct ifnet *ifp)
/* Set watchdog on */
txr->watchdog_time = ticks;
- txr->watchdog_check = TRUE;
+ txr->queue_status = IGB_QUEUE_WORKING;
}
}
@@ -818,113 +835,6 @@ igb_start(struct ifnet *ifp)
return;
}
-#if __FreeBSD_version >= 800000
-/*
-** Multiqueue Transmit driver
-**
-*/
-static int
-igb_mq_start(struct ifnet *ifp, struct mbuf *m)
-{
- struct adapter *adapter = ifp->if_softc;
- struct igb_queue *que;
- struct tx_ring *txr;
- int i = 0, err = 0;
-
- /* Which queue to use */
- if ((m->m_flags & M_FLOWID) != 0)
- i = m->m_pkthdr.flowid % adapter->num_queues;
-
- txr = &adapter->tx_rings[i];
- que = &adapter->queues[i];
-
- if (IGB_TX_TRYLOCK(txr)) {
- err = igb_mq_start_locked(ifp, txr, m);
- IGB_TX_UNLOCK(txr);
- } else {
- err = drbr_enqueue(ifp, txr->br, m);
- taskqueue_enqueue(que->tq, &que->que_task);
- }
-
- return (err);
-}
-
-static int
-igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m)
-{
- struct adapter *adapter = txr->adapter;
- struct mbuf *next;
- int err = 0, enq;
-
- IGB_TX_LOCK_ASSERT(txr);
-
- if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
- IFF_DRV_RUNNING || adapter->link_active == 0) {
- if (m != NULL)
- err = drbr_enqueue(ifp, txr->br, m);
- return (err);
- }
-
- /* Call cleanup if number of TX descriptors low */
- if (txr->tx_avail <= IGB_TX_CLEANUP_THRESHOLD)
- igb_txeof(txr);
-
- enq = 0;
- if (m == NULL) {
- next = drbr_dequeue(ifp, txr->br);
- } else if (drbr_needs_enqueue(ifp, txr->br)) {
- if ((err = drbr_enqueue(ifp, txr->br, m)) != 0)
- return (err);
- next = drbr_dequeue(ifp, txr->br);
- } else
- next = m;
-
- /* Process the queue */
- while (next != NULL) {
- if ((err = igb_xmit(txr, &next)) != 0) {
- if (next != NULL)
- err = drbr_enqueue(ifp, txr->br, next);
- break;
- }
- enq++;
- drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
- ETHER_BPF_MTAP(ifp, next);
- if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
- break;
- if (txr->tx_avail <= IGB_TX_OP_THRESHOLD) {
- ifp->if_drv_flags |= IFF_DRV_OACTIVE;
- break;
- }
- next = drbr_dequeue(ifp, txr->br);
- }
- if (enq > 0) {
- /* Set the watchdog */
- txr->watchdog_check = TRUE;
- txr->watchdog_time = ticks;
- }
- return (err);
-}
-
-/*
-** Flush all ring buffers
-*/
-static void
-igb_qflush(struct ifnet *ifp)
-{
- struct adapter *adapter = ifp->if_softc;
- struct tx_ring *txr = adapter->tx_rings;
- struct mbuf *m;
-
- for (int i = 0; i < adapter->num_queues; i++, txr++) {
- IGB_TX_LOCK(txr);
- while ((m = buf_ring_dequeue_sc(txr->br)) != NULL)
- m_freem(m);
- IGB_TX_UNLOCK(txr);
- }
- if_qflush(ifp);
-}
-#endif /* __FreeBSD_version >= 800000 */
-
/*********************************************************************
* Ioctl entry point
*
@@ -1026,6 +936,11 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
break;
case SIOCSIFMEDIA:
+ /*
+ ** As the speed/duplex settings are being
+ ** changed, we need toreset the PHY.
+ */
+ adapter->hw.phy.reset_disable = FALSE;
/* Check SOL/IDER usage */
IGB_CORE_LOCK(adapter);
if (e1000_check_reset_block(&adapter->hw)) {
@@ -1138,27 +1053,10 @@ igb_init_locked(struct adapter *adapter)
E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN);
- /* Use real VLAN Filter support? */
- if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
- if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
- /* Use real VLAN Filter support */
- igb_setup_vlan_hw_support(adapter);
- else {
- u32 ctrl;
- ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL);
- ctrl |= E1000_CTRL_VME;
- E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
- }
- }
-
/* Set hardware offload abilities */
ifp->if_hwassist = 0;
if (ifp->if_capenable & IFCAP_TXCSUM) {
ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
-#if __FreeBSD_version >= 800000
- if (adapter->hw.mac.type == e1000_82576)
- ifp->if_hwassist |= CSUM_SCTP;
-#endif
}
if (ifp->if_capenable & IFCAP_TSO4)
@@ -1178,10 +1076,12 @@ igb_init_locked(struct adapter *adapter)
** Figure out the desired mbuf pool
** for doing jumbo/packetsplit
*/
- if (ifp->if_mtu > ETHERMTU)
+ if (adapter->max_frame_size <= 2048)
+ adapter->rx_mbuf_sz = MCLBYTES;
+ else if (adapter->max_frame_size <= 4096)
adapter->rx_mbuf_sz = MJUMPAGESIZE;
else
- adapter->rx_mbuf_sz = MCLBYTES;
+ adapter->rx_mbuf_sz = MJUM9BYTES;
/* Prepare receive descriptors and buffers */
if (igb_setup_receive_structures(adapter)) {
@@ -1190,6 +1090,19 @@ igb_init_locked(struct adapter *adapter)
}
igb_initialize_receive_units(adapter);
+ /* Use real VLAN Filter support? */
+ if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
+ if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
+ /* Use real VLAN Filter support */
+ igb_setup_vlan_hw_support(adapter);
+ else {
+ u32 ctrl;
+ ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_VME;
+ E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
+ }
+ }
+
/* Don't lose promiscuous settings */
igb_set_promisc(adapter);
@@ -1202,9 +1115,6 @@ igb_init_locked(struct adapter *adapter)
if (adapter->msix > 1) /* Set up queue routing */
igb_configure_queues(adapter);
- /* Set up VLAN tag offload and filter */
- igb_setup_vlan_hw_support(adapter);
-
/* this clears any pending interrupts */
E1000_READ_REG(&adapter->hw, E1000_ICR);
#ifdef DEVICE_POLLING
@@ -1252,13 +1162,8 @@ igb_handle_que(void *context, int pending)
IGB_TX_LOCK(txr);
if (igb_txeof(txr))
more = TRUE;
-#if __FreeBSD_version >= 800000
- if (!drbr_empty(ifp, txr->br))
- igb_mq_start_locked(ifp, txr, NULL);
-#else
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
igb_start_locked(txr, ifp);
-#endif
IGB_TX_UNLOCK(txr);
if (more) {
taskqueue_enqueue(que->tq, &que->que_task);
@@ -1338,13 +1243,8 @@ igb_irq_fast(void *arg)
* multiqueue is not defined, ie, set igb_num_queues to 1.
*
*********************************************************************/
-#if __FreeBSD_version >= 800000
-#define POLL_RETURN_COUNT(a) (a)
-static int
-#else
#define POLL_RETURN_COUNT(a)
static void
-#endif
igb_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
{
struct adapter *adapter = ifp->if_softc;
@@ -1377,13 +1277,8 @@ igb_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
do {
more = igb_txeof(txr);
} while (loop-- && more);
-#if __FreeBSD_version >= 800000
- if (!drbr_empty(ifp, txr->br))
- igb_mq_start_locked(ifp, txr, NULL);
-#else
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
igb_start_locked(txr, ifp);
-#endif
IGB_TX_UNLOCK(txr);
return POLL_RETURN_COUNT(rx_done);
}
@@ -1604,11 +1499,6 @@ igb_media_change(struct ifnet *ifp)
device_printf(adapter->dev, "Unsupported media type\n");
}
- /* As the speed/duplex settings my have changed we need to
- * reset the PHY.
- */
- adapter->hw.phy.reset_disable = FALSE;
-
igb_init_locked(adapter);
IGB_CORE_UNLOCK(adapter);
@@ -1802,30 +1692,39 @@ static void
igb_set_promisc(struct adapter *adapter)
{
struct ifnet *ifp = adapter->ifp;
- uint32_t reg_rctl;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 reg;
- reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
+ if (hw->mac.type == e1000_vfadapt) {
+ e1000_promisc_set_vf(hw, e1000_promisc_enabled);
+ return;
+ }
+ reg = E1000_READ_REG(hw, E1000_RCTL);
if (ifp->if_flags & IFF_PROMISC) {
- reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
- E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
+ reg |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+ E1000_WRITE_REG(hw, E1000_RCTL, reg);
} else if (ifp->if_flags & IFF_ALLMULTI) {
- reg_rctl |= E1000_RCTL_MPE;
- reg_rctl &= ~E1000_RCTL_UPE;
- E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
+ reg |= E1000_RCTL_MPE;
+ reg &= ~E1000_RCTL_UPE;
+ E1000_WRITE_REG(hw, E1000_RCTL, reg);
}
}
static void
igb_disable_promisc(struct adapter *adapter)
{
- uint32_t reg_rctl;
-
- reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 reg;
- reg_rctl &= (~E1000_RCTL_UPE);
- reg_rctl &= (~E1000_RCTL_MPE);
- E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
+ if (hw->mac.type == e1000_vfadapt) {
+ e1000_promisc_set_vf(hw, e1000_promisc_disabled);
+ return;
+ }
+ reg = E1000_READ_REG(hw, E1000_RCTL);
+ reg &= (~E1000_RCTL_UPE);
+ reg &= (~E1000_RCTL_MPE);
+ E1000_WRITE_REG(hw, E1000_RCTL, reg);
}
@@ -1852,11 +1751,7 @@ igb_set_multi(struct adapter *adapter)
bzero(mta, sizeof(uint8_t) * ETH_ADDR_LEN *
MAX_NUM_MULTICAST_ADDRESSES);
-#if __FreeBSD_version < 800000
IF_ADDR_LOCK(ifp);
-#else
- if_maddr_rlock(ifp);
-#endif
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
@@ -1868,11 +1763,7 @@ igb_set_multi(struct adapter *adapter)
&mta[mcnt * ETH_ADDR_LEN], ETH_ADDR_LEN);
mcnt++;
}
-#if __FreeBSD_version < 800000
IF_ADDR_UNLOCK(ifp);
-#else
- if_maddr_runlock(ifp);
-#endif
if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) {
reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
@@ -1903,16 +1794,22 @@ igb_local_timer(void *arg)
igb_update_link_status(adapter);
igb_update_stats_counters(adapter);
+ /*
+ ** If flow control has paused us since last checking
+ ** it invalidates the watchdog timing, so dont run it.
+ */
+ if (adapter->pause_frames) {
+ adapter->pause_frames = 0;
+ goto out;
+ }
+
/*
** Watchdog: check for time since any descriptor was cleaned
*/
- for (int i = 0; i < adapter->num_queues; i++, txr++) {
- if (txr->watchdog_check == FALSE)
- continue;
- if ((ticks - txr->watchdog_time) > IGB_WATCHDOG)
+ for (int i = 0; i < adapter->num_queues; i++, txr++)
+ if (txr->queue_status == IGB_QUEUE_HUNG)
goto timeout;
- }
-
+out:
callout_reset(&adapter->timer, hz, igb_local_timer, adapter);
return;
@@ -1957,8 +1854,12 @@ igb_update_link_status(struct adapter *adapter)
e1000_check_for_link(hw);
link_check = adapter->hw.mac.serdes_has_link;
break;
- default:
+ /* VF device is type_unknown */
case e1000_media_type_unknown:
+ e1000_check_for_link(hw);
+ link_check = !hw->mac.get_link_status;
+ /* Fall thru */
+ default:
break;
}
@@ -1985,7 +1886,7 @@ igb_update_link_status(struct adapter *adapter)
if_link_state_change(ifp, LINK_STATE_DOWN);
/* Turn off watchdogs */
for (int i = 0; i < adapter->num_queues; i++, txr++)
- txr->watchdog_check = FALSE;
+ txr->queue_status = IGB_QUEUE_IDLE;
}
}
@@ -2017,7 +1918,7 @@ igb_stop(void *arg)
/* Unarm watchdog timer. */
for (int i = 0; i < adapter->num_queues; i++, txr++) {
IGB_TX_LOCK(txr);
- txr->watchdog_check = FALSE;
+ txr->queue_status = IGB_QUEUE_IDLE;
IGB_TX_UNLOCK(txr);
}
@@ -2043,8 +1944,8 @@ igb_identify_hardware(struct adapter *adapter)
adapter->hw.bus.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
if (!((adapter->hw.bus.pci_cmd_word & PCIM_CMD_BUSMASTEREN) &&
(adapter->hw.bus.pci_cmd_word & PCIM_CMD_MEMEN))) {
- device_printf(dev, "Memory Access and/or Bus Master bits "
- "were not set!\n");
+ INIT_DEBUGOUT("Memory Access and/or Bus Master "
+ "bits were not set!\n");
adapter->hw.bus.pci_cmd_word |=
(PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN);
pci_write_config(dev, PCIR_COMMAND,
@@ -2060,11 +1961,8 @@ igb_identify_hardware(struct adapter *adapter)
adapter->hw.subsystem_device_id =
pci_read_config(dev, PCIR_SUBDEV_0, 2);
- /* Do Shared Code Init and Setup */
- if (e1000_set_mac_type(&adapter->hw)) {
- device_printf(dev, "Setup init failure\n");
- return;
- }
+ /* Set MAC type early for PCI setup */
+ e1000_set_mac_type(&adapter->hw);
}
static int
@@ -2225,8 +2123,7 @@ igb_configure_queues(struct adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
struct igb_queue *que;
- u32 tmp, ivar = 0;
- u32 newitr = IGB_DEFAULT_ITR;
+ u32 tmp, ivar = 0, newitr = 0;
/* First turn on RSS capability */
if (adapter->hw.mac.type > e1000_82575)
@@ -2237,6 +2134,7 @@ igb_configure_queues(struct adapter *adapter)
/* Turn on MSIX */
switch (adapter->hw.mac.type) {
case e1000_82580:
+ case e1000_vfadapt:
/* RX entries */
for (int i = 0; i < adapter->num_queues; i++) {
u32 index = i >> 1;
@@ -2342,6 +2240,9 @@ igb_configure_queues(struct adapter *adapter)
}
/* Set the starting interrupt rate */
+ if (igb_max_interrupt_rate > 0)
+ newitr = (4000000 / igb_max_interrupt_rate) & 0x7FFC;
+
if (hw->mac.type == e1000_82575)
newitr |= newitr << 16;
else
@@ -2453,11 +2354,17 @@ igb_setup_msix(struct adapter *adapter)
/* Manual override */
if (igb_num_queues != 0)
queues = igb_num_queues;
+ if (queues > 8) /* max queues */
+ queues = 8;
/* Can have max of 4 queues on 82575 */
if ((adapter->hw.mac.type == e1000_82575) && (queues > 4))
queues = 4;
+ /* Limit the VF adapter to one queue */
+ if (adapter->hw.mac.type == e1000_vfadapt)
+ queues = 1;
+
/*
** One vector (RX/TX pair) per queue
** plus an additional for Link interrupt
@@ -2515,6 +2422,7 @@ igb_reset(struct adapter *adapter)
pba = E1000_PBA_32K;
break;
case e1000_82576:
+ case e1000_vfadapt:
pba = E1000_PBA_64K;
break;
case e1000_82580:
@@ -2575,7 +2483,7 @@ igb_reset(struct adapter *adapter)
fc->send_xon = TRUE;
/* Set Flow control, use the tunable location if sane */
- if ((igb_fc_setting >= 0) || (igb_fc_setting < 4))
+ if ((igb_fc_setting >= 0) && (igb_fc_setting < 4))
fc->requested_mode = igb_fc_setting;
else
fc->requested_mode = e1000_fc_none;
@@ -2652,10 +2560,6 @@ igb_setup_interface(device_t dev, struct adapter *adapter)
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = igb_ioctl;
ifp->if_start = igb_start;
-#if __FreeBSD_version >= 800000
- ifp->if_transmit = igb_mq_start;
- ifp->if_qflush = igb_qflush;
-#endif
IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 1);
ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 1;
IFQ_SET_READY(&ifp->if_snd);
@@ -2667,10 +2571,11 @@ igb_setup_interface(device_t dev, struct adapter *adapter)
ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
ifp->if_capabilities |= IFCAP_TSO4;
ifp->if_capabilities |= IFCAP_JUMBO_MTU;
- if (igb_header_split)
- ifp->if_capabilities |= IFCAP_LRO;
-
ifp->if_capenable = ifp->if_capabilities;
+
+ /* Don't enable LRO by default */
+ ifp->if_capabilities |= IFCAP_LRO;
+
#ifdef DEVICE_POLLING
ifp->if_capabilities |= IFCAP_POLLING;
#endif
@@ -2889,11 +2794,6 @@ igb_allocate_queues(struct adapter *adapter)
error = ENOMEM;
goto err_tx_desc;
}
-#if __FreeBSD_version >= 800000
- /* Allocate a buf ring */
- txr->br = buf_ring_alloc(IGB_BR_SIZE, M_DEVBUF,
- M_WAITOK, &txr->tx_mtx);
-#endif
}
/*
@@ -2950,9 +2850,6 @@ err_tx_desc:
igb_dma_free(adapter, &txr->txdma);
free(adapter->rx_rings, M_DEVBUF);
rx_fail:
-#if __FreeBSD_version >= 800000
- buf_ring_free(txr->br, M_DEVBUF);
-#endif
free(adapter->tx_rings, M_DEVBUF);
tx_fail:
free(adapter->queues, M_DEVBUF);
@@ -3089,7 +2986,8 @@ igb_initialize_transmit_units(struct adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 tctl, txdctl;
- INIT_DEBUGOUT("igb_initialize_transmit_units: begin");
+ INIT_DEBUGOUT("igb_initialize_transmit_units: begin");
+ tctl = txdctl = 0;
/* Setup the Tx Descriptor Rings */
for (int i = 0; i < adapter->num_queues; i++, txr++) {
@@ -3110,9 +3008,8 @@ igb_initialize_transmit_units(struct adapter *adapter)
E1000_READ_REG(hw, E1000_TDBAL(i)),
E1000_READ_REG(hw, E1000_TDLEN(i)));
- txr->watchdog_check = FALSE;
+ txr->queue_status = IGB_QUEUE_IDLE;
- txdctl = E1000_READ_REG(hw, E1000_TXDCTL(i));
txdctl |= IGB_TX_PTHRESH;
txdctl |= IGB_TX_HTHRESH << 8;
txdctl |= IGB_TX_WTHRESH << 16;
@@ -3120,14 +3017,17 @@ igb_initialize_transmit_units(struct adapter *adapter)
E1000_WRITE_REG(hw, E1000_TXDCTL(i), txdctl);
}
+ if (adapter->hw.mac.type == e1000_vfadapt)
+ return;
+
+ e1000_config_collision_dist(hw);
+
/* Program the Transmit Control Register */
tctl = E1000_READ_REG(hw, E1000_TCTL);
tctl &= ~E1000_TCTL_CT;
tctl |= (E1000_TCTL_PSP | E1000_TCTL_RTLC | E1000_TCTL_EN |
(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT));
- e1000_config_collision_dist(hw);
-
/* This write will effectively turn on the transmit unit. */
E1000_WRITE_REG(hw, E1000_TCTL, tctl);
}
@@ -3191,10 +3091,6 @@ igb_free_transmit_buffers(struct tx_ring *txr)
tx_buffer->map = NULL;
}
}
-#if __FreeBSD_version >= 800000
- if (txr->br != NULL)
- buf_ring_free(txr->br, M_DEVBUF);
-#endif
if (txr->tx_buffers != NULL) {
free(txr->tx_buffers, M_DEVBUF);
txr->tx_buffers = NULL;
@@ -3390,12 +3286,6 @@ 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)
- type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_SCTP;
- break;
-#endif
default:
offload = FALSE;
break;
@@ -3436,16 +3326,19 @@ static bool
igb_txeof(struct tx_ring *txr)
{
struct adapter *adapter = txr->adapter;
- int first, last, done;
+ int first, last, done, processed;
struct igb_tx_buffer *tx_buffer;
struct e1000_tx_desc *tx_desc, *eop_desc;
struct ifnet *ifp = adapter->ifp;
IGB_TX_LOCK_ASSERT(txr);
- if (txr->tx_avail == adapter->num_tx_desc)
+ if (txr->tx_avail == adapter->num_tx_desc) {
+ txr->queue_status = IGB_QUEUE_IDLE;
return FALSE;
+ }
+ processed = 0;
first = txr->next_to_clean;
tx_desc = &txr->tx_base[first];
tx_buffer = &txr->tx_buffers[first];
@@ -3472,6 +3365,7 @@ igb_txeof(struct tx_ring *txr)
tx_desc->lower.data = 0;
tx_desc->buffer_addr = 0;
++txr->tx_avail;
+ ++processed;
if (tx_buffer->m_head) {
txr->bytes +=
@@ -3511,6 +3405,15 @@ igb_txeof(struct tx_ring *txr)
txr->next_to_clean = first;
+ /*
+ ** Watchdog calculation, we know there's
+ ** work outstanding or the first return
+ ** would have been taken, so none processed
+ ** for too long indicates a hang.
+ */
+ if ((!processed) && ((ticks - txr->watchdog_time) > IGB_WATCHDOG))
+ txr->queue_status = IGB_QUEUE_HUNG;
+
/*
* If we have enough room, clear IFF_DRV_OACTIVE
* to tell the stack that it is OK to send packets.
@@ -3519,8 +3422,8 @@ igb_txeof(struct tx_ring *txr)
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
/* All clean, turn off the watchdog */
if (txr->tx_avail == adapter->num_tx_desc) {
- txr->watchdog_check = FALSE;
- return FALSE;
+ txr->queue_status = IGB_QUEUE_IDLE;
+ return (FALSE);
}
}
@@ -3551,51 +3454,59 @@ igb_refresh_mbufs(struct rx_ring *rxr, int limit)
cleaned = -1; /* Signify no completions */
while (i != limit) {
rxbuf = &rxr->rx_buffers[i];
- if ((rxbuf->m_head == NULL) && (rxr->hdr_split)) {
+ /* No hdr mbuf used with header split off */
+ if (rxr->hdr_split == FALSE)
+ goto no_split;
+ if (rxbuf->m_head == NULL) {
mh = m_gethdr(M_DONTWAIT, MT_DATA);
if (mh == NULL)
goto update;
- mh->m_pkthdr.len = mh->m_len = MHLEN;
- mh->m_len = MHLEN;
- mh->m_flags |= M_PKTHDR;
- m_adj(mh, ETHER_ALIGN);
- /* Get the memory mapping */
- error = bus_dmamap_load_mbuf_sg(rxr->htag,
- rxbuf->hmap, mh, hseg, &nsegs, BUS_DMA_NOWAIT);
- if (error != 0) {
- printf("GET BUF: dmamap load"
- " failure - %d\n", error);
- m_free(mh);
- goto update;
- }
- rxbuf->m_head = mh;
- bus_dmamap_sync(rxr->htag, rxbuf->hmap,
- BUS_DMASYNC_PREREAD);
- rxr->rx_base[i].read.hdr_addr =
- htole64(hseg[0].ds_addr);
- }
+ } else
+ mh = rxbuf->m_head;
+ mh->m_pkthdr.len = mh->m_len = MHLEN;
+ mh->m_len = MHLEN;
+ mh->m_flags |= M_PKTHDR;
+ /* Get the memory mapping */
+ error = bus_dmamap_load_mbuf_sg(rxr->htag,
+ rxbuf->hmap, mh, hseg, &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ printf("Refresh mbufs: hdr dmamap load"
+ " failure - %d\n", error);
+ m_free(mh);
+ rxbuf->m_head = NULL;
+ goto update;
+ }
+ rxbuf->m_head = mh;
+ bus_dmamap_sync(rxr->htag, rxbuf->hmap,
+ BUS_DMASYNC_PREREAD);
+ rxr->rx_base[i].read.hdr_addr =
+ htole64(hseg[0].ds_addr);
+no_split:
if (rxbuf->m_pack == NULL) {
mp = m_getjcl(M_DONTWAIT, MT_DATA,
M_PKTHDR, adapter->rx_mbuf_sz);
if (mp == NULL)
goto update;
- mp->m_pkthdr.len = mp->m_len = adapter->rx_mbuf_sz;
- /* Get the memory mapping */
- error = bus_dmamap_load_mbuf_sg(rxr->ptag,
- rxbuf->pmap, mp, pseg, &nsegs, BUS_DMA_NOWAIT);
- if (error != 0) {
- printf("GET BUF: dmamap load"
- " failure - %d\n", error);
- m_free(mp);
- goto update;
- }
- rxbuf->m_pack = mp;
- bus_dmamap_sync(rxr->ptag, rxbuf->pmap,
- BUS_DMASYNC_PREREAD);
- rxr->rx_base[i].read.pkt_addr =
- htole64(pseg[0].ds_addr);
+ } else
+ mp = rxbuf->m_pack;
+
+ mp->m_pkthdr.len = mp->m_len = adapter->rx_mbuf_sz;
+ /* Get the memory mapping */
+ error = bus_dmamap_load_mbuf_sg(rxr->ptag,
+ rxbuf->pmap, mp, pseg, &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ printf("Refresh mbufs: payload dmamap load"
+ " failure - %d\n", error);
+ m_free(mp);
+ rxbuf->m_pack = NULL;
+ goto update;
}
+ rxbuf->m_pack = mp;
+ bus_dmamap_sync(rxr->ptag, rxbuf->pmap,
+ BUS_DMASYNC_PREREAD);
+ rxr->rx_base[i].read.pkt_addr =
+ htole64(pseg[0].ds_addr);
cleaned = i;
/* Calculate next index */
@@ -3658,9 +3569,9 @@ igb_allocate_receive_buffers(struct rx_ring *rxr)
BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
- MJUMPAGESIZE, /* maxsize */
+ MJUM9BYTES, /* maxsize */
1, /* nsegments */
- MJUMPAGESIZE, /* maxsegsize */
+ MJUM9BYTES, /* maxsegsize */
0, /* flags */
NULL, /* lockfunc */
NULL, /* lockfuncarg */
@@ -3762,7 +3673,7 @@ igb_setup_receive_ring(struct rx_ring *rxr)
rxr->hdr_split = TRUE;
/* Now replenish the ring mbufs */
- for (int j = 0; j != adapter->num_rx_desc; ++j) {
+ for (int j = 0; j < adapter->num_rx_desc; ++j) {
struct mbuf *mh, *mp;
rxbuf = &rxr->rx_buffers[j];
@@ -3833,8 +3744,8 @@ skip_head:
** are undesireable in similar setups.
*/
if (ifp->if_capenable & IFCAP_LRO) {
- int err = tcp_lro_init(lro);
- if (err) {
+ error = tcp_lro_init(lro);
+ if (error) {
device_printf(dev, "LRO Initialization failed!\n");
goto fail;
}
@@ -3876,7 +3787,9 @@ fail:
*/
for (int j = 0; j > i; ++j) {
rxr = &adapter->rx_rings[i];
+ IGB_RX_LOCK(rxr);
igb_free_receive_ring(rxr);
+ IGB_RX_UNLOCK(rxr);
}
return (ENOBUFS);
@@ -3919,9 +3832,13 @@ igb_initialize_receive_units(struct adapter *adapter)
*/
if (ifp->if_mtu > ETHERMTU) {
rctl |= E1000_RCTL_LPE;
- srrctl |= 4096 >> E1000_SRRCTL_BSIZEPKT_SHIFT;
- rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX;
-
+ if (adapter->rx_mbuf_sz == MJUMPAGESIZE) {
+ srrctl |= 4096 >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+ rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX;
+ } else if (adapter->rx_mbuf_sz > MJUMPAGESIZE) {
+ srrctl |= 8192 >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+ rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX;
+ }
/* Set maximum packet len */
psize = adapter->max_frame_size;
/* are we on a vlan? */
@@ -4002,20 +3919,10 @@ igb_initialize_receive_units(struct adapter *adapter)
** still work.
*/
rxcsum |= E1000_RXCSUM_PCSD;
-#if __FreeBSD_version >= 800000
- /* For SCTP Offload */
- if ((hw->mac.type == e1000_82576)
- && (ifp->if_capenable & IFCAP_RXCSUM))
- rxcsum |= E1000_RXCSUM_CRCOFL;
-#endif
} else {
/* Non RSS setup */
if (ifp->if_capenable & IFCAP_RXCSUM) {
rxcsum |= E1000_RXCSUM_IPPCSE;
-#if __FreeBSD_version >= 800000
- if (adapter->hw.mac.type == e1000_82576)
- rxcsum |= E1000_RXCSUM_CRCOFL;
-#endif
} else
rxcsum &= ~E1000_RXCSUM_TUOFL;
}
@@ -4130,11 +4037,11 @@ igb_free_receive_buffers(struct rx_ring *rxr)
static __inline void
igb_rx_discard(struct rx_ring *rxr, int i)
{
- struct adapter *adapter = rxr->adapter;
struct igb_rx_buf *rbuf;
- struct mbuf *mh, *mp;
rbuf = &rxr->rx_buffers[i];
+
+ /* Partially received? Free the chain */
if (rxr->fmp != NULL) {
rxr->fmp->m_flags |= M_PKTHDR;
m_freem(rxr->fmp);
@@ -4142,17 +4049,23 @@ igb_rx_discard(struct rx_ring *rxr, int i)
rxr->lmp = NULL;
}
- mh = rbuf->m_head;
- mp = rbuf->m_pack;
+ /*
+ ** With advanced descriptors the writeback
+ ** clobbers the buffer addrs, so its easier
+ ** to just free the existing mbufs and take
+ ** the normal refresh path to get new buffers
+ ** and mapping.
+ */
+ if (rbuf->m_head) {
+ m_free(rbuf->m_head);
+ rbuf->m_head = NULL;
+ }
- /* Reuse loaded DMA map and just update mbuf chain */
- mh->m_len = MHLEN;
- mh->m_flags |= M_PKTHDR;
- mh->m_next = NULL;
+ if (rbuf->m_pack) {
+ m_free(rbuf->m_pack);
+ rbuf->m_pack = NULL;
+ }
- mp->m_len = mp->m_pkthdr.len = adapter->rx_mbuf_sz;
- mp->m_data = mp->m_ext.ext_buf;
- mp->m_next = NULL;
return;
}
@@ -4267,10 +4180,9 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
E1000_RXDADV_HDRBUFLEN_SHIFT;
if (hlen > IGB_HDR_BUF)
hlen = IGB_HDR_BUF;
- /* Handle the header mbuf */
mh = rxr->rx_buffers[i].m_head;
mh->m_len = hlen;
- /* clear buf info for refresh */
+ /* clear buf pointer for refresh */
rxbuf->m_head = NULL;
/*
** Get the payload length, this
@@ -4281,7 +4193,7 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
mp = rxr->rx_buffers[i].m_pack;
mp->m_len = plen;
mh->m_next = mp;
- /* clear buf info for refresh */
+ /* clear buf pointer */
rxbuf->m_pack = NULL;
rxr->rx_split_packets++;
}
@@ -4302,7 +4214,7 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
/* Initial frame - setup */
if (rxr->fmp == NULL) {
mh->m_pkthdr.len = mh->m_len;
- /* Store the first mbuf */
+ /* Save the head of the chain */
rxr->fmp = mh;
rxr->lmp = mh;
if (mp != NULL) {
@@ -4334,10 +4246,6 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
rxr->fmp->m_pkthdr.ether_vtag = vtag;
rxr->fmp->m_flags |= M_VLANTAG;
}
-#if __FreeBSD_version >= 800000
- rxr->fmp->m_pkthdr.flowid = que->msix;
- rxr->fmp->m_flags |= M_FLOWID;
-#endif
sendmp = rxr->fmp;
/* Make sure to set M_PKTHDR. */
sendmp->m_flags |= M_PKTHDR;
@@ -4437,10 +4345,6 @@ igb_rx_checksum(u32 staterr, struct mbuf *mp, u32 ptype)
if (status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS)) {
u16 type = (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
-#if __FreeBSD_version >= 800000
- if (sctp) /* reassign */
- type = CSUM_SCTP_VALID;
-#endif
/* Did it pass? */
if (!(errors & E1000_RXD_ERR_TCPE)) {
mp->m_pkthdr.csum_flags |= type;
@@ -4467,12 +4371,15 @@ igb_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
if ((vtag == 0) || (vtag > 4095)) /* Invalid */
return;
+ IGB_CORE_LOCK(adapter);
index = (vtag >> 5) & 0x7F;
bit = vtag & 0x1F;
- igb_shadow_vfta[index] |= (1 << bit);
+ adapter->shadow_vfta[index] |= (1 << bit);
++adapter->num_vlans;
/* Re-init to load the changes */
- igb_init(adapter);
+ if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
+ igb_init_locked(adapter);
+ IGB_CORE_UNLOCK(adapter);
}
/*
@@ -4491,12 +4398,15 @@ igb_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
if ((vtag == 0) || (vtag > 4095)) /* Invalid */
return;
+ IGB_CORE_LOCK(adapter);
index = (vtag >> 5) & 0x7F;
bit = vtag & 0x1F;
- igb_shadow_vfta[index] &= ~(1 << bit);
+ adapter->shadow_vfta[index] &= ~(1 << bit);
--adapter->num_vlans;
/* Re-init to load the changes */
- igb_init(adapter);
+ if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
+ igb_init_locked(adapter);
+ IGB_CORE_UNLOCK(adapter);
}
static void
@@ -4519,23 +4429,33 @@ igb_setup_vlan_hw_support(struct adapter *adapter)
** we need to repopulate it now.
*/
for (int i = 0; i < IGB_VFTA_SIZE; i++)
- if (igb_shadow_vfta[i] != 0)
- E1000_WRITE_REG_ARRAY(hw, E1000_VFTA,
- i, igb_shadow_vfta[i]);
+ if (adapter->shadow_vfta[i] != 0) {
+ if (hw->mac.type == e1000_vfadapt)
+ e1000_vfta_set_vf(hw,
+ adapter->shadow_vfta[i], TRUE);
+ else
+ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA,
+ i, adapter->shadow_vfta[i]);
+ }
- reg = E1000_READ_REG(hw, E1000_CTRL);
- reg |= E1000_CTRL_VME;
- E1000_WRITE_REG(hw, E1000_CTRL, reg);
+ if (hw->mac.type == e1000_vfadapt)
+ e1000_rlpml_set_vf(hw,
+ adapter->max_frame_size + VLAN_TAG_SIZE);
+ else {
+ reg = E1000_READ_REG(hw, E1000_CTRL);
+ reg |= E1000_CTRL_VME;
+ E1000_WRITE_REG(hw, E1000_CTRL, reg);
- /* Enable the Filter Table */
- reg = E1000_READ_REG(hw, E1000_RCTL);
- reg &= ~E1000_RCTL_CFIEN;
- reg |= E1000_RCTL_VFE;
- E1000_WRITE_REG(hw, E1000_RCTL, reg);
+ /* Enable the Filter Table */
+ reg = E1000_READ_REG(hw, E1000_RCTL);
+ reg &= ~E1000_RCTL_CFIEN;
+ reg |= E1000_RCTL_VFE;
+ E1000_WRITE_REG(hw, E1000_RCTL, reg);
- /* Update the frame size */
- E1000_WRITE_REG(&adapter->hw, E1000_RLPML,
- adapter->max_frame_size + VLAN_TAG_SIZE);
+ /* Update the frame size */
+ E1000_WRITE_REG(&adapter->hw, E1000_RLPML,
+ adapter->max_frame_size + VLAN_TAG_SIZE);
+ }
}
static void
@@ -4625,6 +4545,9 @@ igb_get_hw_control(struct adapter *adapter)
{
u32 ctrl_ext;
+ if (adapter->hw.mac.type == e1000_vfadapt)
+ return;
+
/* Let firmware know the driver has taken over */
ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT,
@@ -4642,6 +4565,9 @@ igb_release_hw_control(struct adapter *adapter)
{
u32 ctrl_ext;
+ if (adapter->hw.mac.type == e1000_vfadapt)
+ return;
+
/* Let firmware taken over control of h/w */
ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT,
@@ -4709,138 +4635,195 @@ igb_led_func(void *arg, int onoff)
static void
igb_update_stats_counters(struct adapter *adapter)
{
- struct ifnet *ifp;
+ struct ifnet *ifp;
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_hw_stats *stats;
- if (adapter->hw.phy.media_type == e1000_media_type_copper ||
- (E1000_READ_REG(&adapter->hw, E1000_STATUS) & E1000_STATUS_LU)) {
- adapter->stats.symerrs +=
- E1000_READ_REG(&adapter->hw, E1000_SYMERRS);
- adapter->stats.sec +=
- E1000_READ_REG(&adapter->hw, E1000_SEC);
+ /*
+ ** The virtual function adapter has only a
+ ** small controlled set of stats, do only
+ ** those and return.
+ */
+ if (adapter->hw.mac.type == e1000_vfadapt) {
+ igb_update_vf_stats_counters(adapter);
+ return;
}
- adapter->stats.crcerrs += E1000_READ_REG(&adapter->hw, E1000_CRCERRS);
- adapter->stats.mpc += E1000_READ_REG(&adapter->hw, E1000_MPC);
- adapter->stats.scc += E1000_READ_REG(&adapter->hw, E1000_SCC);
- adapter->stats.ecol += E1000_READ_REG(&adapter->hw, E1000_ECOL);
- adapter->stats.mcc += E1000_READ_REG(&adapter->hw, E1000_MCC);
- adapter->stats.latecol += E1000_READ_REG(&adapter->hw, E1000_LATECOL);
- adapter->stats.colc += E1000_READ_REG(&adapter->hw, E1000_COLC);
- adapter->stats.dc += E1000_READ_REG(&adapter->hw, E1000_DC);
- adapter->stats.rlec += E1000_READ_REG(&adapter->hw, E1000_RLEC);
- adapter->stats.xonrxc += E1000_READ_REG(&adapter->hw, E1000_XONRXC);
- adapter->stats.xontxc += E1000_READ_REG(&adapter->hw, E1000_XONTXC);
- adapter->stats.xoffrxc += E1000_READ_REG(&adapter->hw, E1000_XOFFRXC);
- adapter->stats.xofftxc += E1000_READ_REG(&adapter->hw, E1000_XOFFTXC);
- adapter->stats.fcruc += E1000_READ_REG(&adapter->hw, E1000_FCRUC);
- adapter->stats.prc64 += E1000_READ_REG(&adapter->hw, E1000_PRC64);
- adapter->stats.prc127 += E1000_READ_REG(&adapter->hw, E1000_PRC127);
- adapter->stats.prc255 += E1000_READ_REG(&adapter->hw, E1000_PRC255);
- adapter->stats.prc511 += E1000_READ_REG(&adapter->hw, E1000_PRC511);
- adapter->stats.prc1023 += E1000_READ_REG(&adapter->hw, E1000_PRC1023);
- adapter->stats.prc1522 += E1000_READ_REG(&adapter->hw, E1000_PRC1522);
- adapter->stats.gprc += E1000_READ_REG(&adapter->hw, E1000_GPRC);
- adapter->stats.bprc += E1000_READ_REG(&adapter->hw, E1000_BPRC);
- adapter->stats.mprc += E1000_READ_REG(&adapter->hw, E1000_MPRC);
- adapter->stats.gptc += E1000_READ_REG(&adapter->hw, E1000_GPTC);
+ stats = (struct e1000_hw_stats *)adapter->stats;
+
+ if(adapter->hw.phy.media_type == e1000_media_type_copper ||
+ (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
+ stats->symerrs +=
+ E1000_READ_REG(hw,E1000_SYMERRS);
+ stats->sec += E1000_READ_REG(hw, E1000_SEC);
+ }
+
+ stats->crcerrs += E1000_READ_REG(hw, E1000_CRCERRS);
+ stats->mpc += E1000_READ_REG(hw, E1000_MPC);
+ stats->scc += E1000_READ_REG(hw, E1000_SCC);
+ stats->ecol += E1000_READ_REG(hw, E1000_ECOL);
+
+ stats->mcc += E1000_READ_REG(hw, E1000_MCC);
+ stats->latecol += E1000_READ_REG(hw, E1000_LATECOL);
+ stats->colc += E1000_READ_REG(hw, E1000_COLC);
+ stats->dc += E1000_READ_REG(hw, E1000_DC);
+ stats->rlec += E1000_READ_REG(hw, E1000_RLEC);
+ stats->xonrxc += E1000_READ_REG(hw, E1000_XONRXC);
+ stats->xontxc += E1000_READ_REG(hw, E1000_XONTXC);
+ /*
+ ** For watchdog management we need to know if we have been
+ ** paused during the last interval, so capture that here.
+ */
+ adapter->pause_frames = E1000_READ_REG(&adapter->hw, E1000_XOFFRXC);
+ stats->xoffrxc += adapter->pause_frames;
+ stats->xofftxc += E1000_READ_REG(hw, E1000_XOFFTXC);
+ stats->fcruc += E1000_READ_REG(hw, E1000_FCRUC);
+ stats->prc64 += E1000_READ_REG(hw, E1000_PRC64);
+ stats->prc127 += E1000_READ_REG(hw, E1000_PRC127);
+ stats->prc255 += E1000_READ_REG(hw, E1000_PRC255);
+ stats->prc511 += E1000_READ_REG(hw, E1000_PRC511);
+ stats->prc1023 += E1000_READ_REG(hw, E1000_PRC1023);
+ stats->prc1522 += E1000_READ_REG(hw, E1000_PRC1522);
+ stats->gprc += E1000_READ_REG(hw, E1000_GPRC);
+ stats->bprc += E1000_READ_REG(hw, E1000_BPRC);
+ stats->mprc += E1000_READ_REG(hw, E1000_MPRC);
+ stats->gptc += E1000_READ_REG(hw, E1000_GPTC);
/* For the 64-bit byte counters the low dword must be read first. */
/* Both registers clear on the read of the high dword */
- adapter->stats.gorc += E1000_READ_REG(&adapter->hw, E1000_GORCL) +
- ((u64)E1000_READ_REG(&adapter->hw, E1000_GORCH) << 32);
- adapter->stats.gotc += E1000_READ_REG(&adapter->hw, E1000_GOTCL) +
- ((u64)E1000_READ_REG(&adapter->hw, E1000_GOTCH) << 32) ;
+ stats->gorc += E1000_READ_REG(hw, E1000_GORCL) +
+ ((u64)E1000_READ_REG(hw, E1000_GORCH) << 32);
+ stats->gotc += E1000_READ_REG(hw, E1000_GOTCL) +
+ ((u64)E1000_READ_REG(hw, E1000_GOTCH) << 32);
- adapter->stats.rnbc += E1000_READ_REG(&adapter->hw, E1000_RNBC);
- adapter->stats.ruc += E1000_READ_REG(&adapter->hw, E1000_RUC);
- adapter->stats.rfc += E1000_READ_REG(&adapter->hw, E1000_RFC);
- adapter->stats.roc += E1000_READ_REG(&adapter->hw, E1000_ROC);
- adapter->stats.rjc += E1000_READ_REG(&adapter->hw, E1000_RJC);
+ stats->rnbc += E1000_READ_REG(hw, E1000_RNBC);
+ stats->ruc += E1000_READ_REG(hw, E1000_RUC);
+ stats->rfc += E1000_READ_REG(hw, E1000_RFC);
+ stats->roc += E1000_READ_REG(hw, E1000_ROC);
+ stats->rjc += E1000_READ_REG(hw, E1000_RJC);
- adapter->stats.tor += E1000_READ_REG(&adapter->hw, E1000_TORH);
- adapter->stats.tot += E1000_READ_REG(&adapter->hw, E1000_TOTH);
+ stats->tor += E1000_READ_REG(hw, E1000_TORH);
+ stats->tot += E1000_READ_REG(hw, E1000_TOTH);
- adapter->stats.tpr += E1000_READ_REG(&adapter->hw, E1000_TPR);
- adapter->stats.tpt += E1000_READ_REG(&adapter->hw, E1000_TPT);
- adapter->stats.ptc64 += E1000_READ_REG(&adapter->hw, E1000_PTC64);
- adapter->stats.ptc127 += E1000_READ_REG(&adapter->hw, E1000_PTC127);
- adapter->stats.ptc255 += E1000_READ_REG(&adapter->hw, E1000_PTC255);
- adapter->stats.ptc511 += E1000_READ_REG(&adapter->hw, E1000_PTC511);
- adapter->stats.ptc1023 += E1000_READ_REG(&adapter->hw, E1000_PTC1023);
- adapter->stats.ptc1522 += E1000_READ_REG(&adapter->hw, E1000_PTC1522);
- adapter->stats.mptc += E1000_READ_REG(&adapter->hw, E1000_MPTC);
- adapter->stats.bptc += E1000_READ_REG(&adapter->hw, E1000_BPTC);
+ stats->tpr += E1000_READ_REG(hw, E1000_TPR);
+ stats->tpt += E1000_READ_REG(hw, E1000_TPT);
+ stats->ptc64 += E1000_READ_REG(hw, E1000_PTC64);
+ stats->ptc127 += E1000_READ_REG(hw, E1000_PTC127);
+ stats->ptc255 += E1000_READ_REG(hw, E1000_PTC255);
+ stats->ptc511 += E1000_READ_REG(hw, E1000_PTC511);
+ stats->ptc1023 += E1000_READ_REG(hw, E1000_PTC1023);
+ stats->ptc1522 += E1000_READ_REG(hw, E1000_PTC1522);
+ stats->mptc += E1000_READ_REG(hw, E1000_MPTC);
+ stats->bptc += E1000_READ_REG(hw, E1000_BPTC);
/* Interrupt Counts */
- adapter->stats.iac += E1000_READ_REG(&adapter->hw, E1000_IAC);
- adapter->stats.icrxptc += E1000_READ_REG(&adapter->hw, E1000_ICRXPTC);
- adapter->stats.icrxatc += E1000_READ_REG(&adapter->hw, E1000_ICRXATC);
- adapter->stats.ictxptc += E1000_READ_REG(&adapter->hw, E1000_ICTXPTC);
- adapter->stats.ictxatc += E1000_READ_REG(&adapter->hw, E1000_ICTXATC);
- adapter->stats.ictxqec += E1000_READ_REG(&adapter->hw, E1000_ICTXQEC);
- adapter->stats.ictxqmtc += E1000_READ_REG(&adapter->hw, E1000_ICTXQMTC);
- adapter->stats.icrxdmtc += E1000_READ_REG(&adapter->hw, E1000_ICRXDMTC);
- adapter->stats.icrxoc += E1000_READ_REG(&adapter->hw, E1000_ICRXOC);
+ stats->iac += E1000_READ_REG(hw, E1000_IAC);
+ stats->icrxptc += E1000_READ_REG(hw, E1000_ICRXPTC);
+ stats->icrxatc += E1000_READ_REG(hw, E1000_ICRXATC);
+ stats->ictxptc += E1000_READ_REG(hw, E1000_ICTXPTC);
+ stats->ictxatc += E1000_READ_REG(hw, E1000_ICTXATC);
+ stats->ictxqec += E1000_READ_REG(hw, E1000_ICTXQEC);
+ stats->ictxqmtc += E1000_READ_REG(hw, E1000_ICTXQMTC);
+ stats->icrxdmtc += E1000_READ_REG(hw, E1000_ICRXDMTC);
+ stats->icrxoc += E1000_READ_REG(hw, E1000_ICRXOC);
/* Host to Card Statistics */
- adapter->stats.cbtmpc += E1000_READ_REG(&adapter->hw, E1000_CBTMPC);
- adapter->stats.htdpmc += E1000_READ_REG(&adapter->hw, E1000_HTDPMC);
- adapter->stats.cbrdpc += E1000_READ_REG(&adapter->hw, E1000_CBRDPC);
- adapter->stats.cbrmpc += E1000_READ_REG(&adapter->hw, E1000_CBRMPC);
- adapter->stats.rpthc += E1000_READ_REG(&adapter->hw, E1000_RPTHC);
- adapter->stats.hgptc += E1000_READ_REG(&adapter->hw, E1000_HGPTC);
- adapter->stats.htcbdpc += E1000_READ_REG(&adapter->hw, E1000_HTCBDPC);
- adapter->stats.hgorc += (E1000_READ_REG(&adapter->hw, E1000_HGORCL) +
- ((u64)E1000_READ_REG(&adapter->hw,
- E1000_HGORCH) << 32));
+ stats->cbtmpc += E1000_READ_REG(hw, E1000_CBTMPC);
+ stats->htdpmc += E1000_READ_REG(hw, E1000_HTDPMC);
+ stats->cbrdpc += E1000_READ_REG(hw, E1000_CBRDPC);
+ stats->cbrmpc += E1000_READ_REG(hw, E1000_CBRMPC);
+ stats->rpthc += E1000_READ_REG(hw, E1000_RPTHC);
+ stats->hgptc += E1000_READ_REG(hw, E1000_HGPTC);
+ stats->htcbdpc += E1000_READ_REG(hw, E1000_HTCBDPC);
+ stats->hgorc += (E1000_READ_REG(hw, E1000_HGORCL) +
+ ((u64)E1000_READ_REG(hw, E1000_HGORCH) << 32));
+ stats->hgotc += (E1000_READ_REG(hw, E1000_HGOTCL) +
+ ((u64)E1000_READ_REG(hw, E1000_HGOTCH) << 32));
+ stats->lenerrs += E1000_READ_REG(hw, E1000_LENERRS);
+ stats->scvpc += E1000_READ_REG(hw, E1000_SCVPC);
+ stats->hrmpc += E1000_READ_REG(hw, E1000_HRMPC);
- adapter->stats.hgotc += (E1000_READ_REG(&adapter->hw, E1000_HGOTCL) +
- ((u64)E1000_READ_REG(&adapter->hw,
- E1000_HGOTCH) << 32));
- adapter->stats.lenerrs += E1000_READ_REG(&adapter->hw, E1000_LENERRS);
- adapter->stats.scvpc += E1000_READ_REG(&adapter->hw, E1000_SCVPC);
- adapter->stats.hrmpc += E1000_READ_REG(&adapter->hw, E1000_HRMPC);
+ stats->algnerrc += E1000_READ_REG(hw, E1000_ALGNERRC);
+ stats->rxerrc += E1000_READ_REG(hw, E1000_RXERRC);
+ stats->tncrs += E1000_READ_REG(hw, E1000_TNCRS);
+ stats->cexterr += E1000_READ_REG(hw, E1000_CEXTERR);
+ stats->tsctc += E1000_READ_REG(hw, E1000_TSCTC);
+ stats->tsctfc += E1000_READ_REG(hw, E1000_TSCTFC);
- adapter->stats.algnerrc +=
- E1000_READ_REG(&adapter->hw, E1000_ALGNERRC);
- adapter->stats.rxerrc +=
- E1000_READ_REG(&adapter->hw, E1000_RXERRC);
- adapter->stats.tncrs +=
- E1000_READ_REG(&adapter->hw, E1000_TNCRS);
- adapter->stats.cexterr +=
- E1000_READ_REG(&adapter->hw, E1000_CEXTERR);
- adapter->stats.tsctc +=
- E1000_READ_REG(&adapter->hw, E1000_TSCTC);
- adapter->stats.tsctfc +=
- E1000_READ_REG(&adapter->hw, E1000_TSCTFC);
ifp = adapter->ifp;
-
- ifp->if_collisions = adapter->stats.colc;
+ ifp->if_collisions = stats->colc;
/* Rx Errors */
- ifp->if_ierrors = adapter->dropped_pkts + adapter->stats.rxerrc +
- adapter->stats.crcerrs + adapter->stats.algnerrc +
- adapter->stats.ruc + adapter->stats.roc +
- adapter->stats.mpc + adapter->stats.cexterr;
+ ifp->if_ierrors = adapter->dropped_pkts + stats->rxerrc +
+ stats->crcerrs + stats->algnerrc +
+ stats->ruc + stats->roc + stats->mpc + stats->cexterr;
/* Tx Errors */
- ifp->if_oerrors = adapter->stats.ecol +
- adapter->stats.latecol + adapter->watchdog_events;
+ ifp->if_oerrors = stats->ecol +
+ stats->latecol + adapter->watchdog_events;
/* Driver specific counters */
- adapter->device_control = E1000_READ_REG(&adapter->hw, E1000_CTRL);
- adapter->rx_control = E1000_READ_REG(&adapter->hw, E1000_RCTL);
- adapter->int_mask = E1000_READ_REG(&adapter->hw, E1000_IMS);
- adapter->eint_mask = E1000_READ_REG(&adapter->hw, E1000_EIMS);
- adapter->packet_buf_alloc_tx = ((E1000_READ_REG(&adapter->hw, E1000_PBA)
- & 0xffff0000) >> 16);
+ adapter->device_control = E1000_READ_REG(hw, E1000_CTRL);
+ adapter->rx_control = E1000_READ_REG(hw, E1000_RCTL);
+ adapter->int_mask = E1000_READ_REG(hw, E1000_IMS);
+ adapter->eint_mask = E1000_READ_REG(hw, E1000_EIMS);
+ adapter->packet_buf_alloc_tx =
+ ((E1000_READ_REG(hw, E1000_PBA) & 0xffff0000) >> 16);
+ adapter->packet_buf_alloc_rx =
+ (E1000_READ_REG(hw, E1000_PBA) & 0xffff);
+}
- adapter->packet_buf_alloc_rx = (E1000_READ_REG(&adapter->hw, E1000_PBA)
- & 0xffff);
+/**********************************************************************
+ *
+ * Initialize the VF board statistics counters.
+ *
+ **********************************************************************/
+static void
+igb_vf_init_stats(struct adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_vf_stats *stats;
+
+ stats = (struct e1000_vf_stats *)adapter->stats;
+ if (stats == NULL)
+ return;
+ stats->last_gprc = E1000_READ_REG(hw, E1000_VFGPRC);
+ stats->last_gorc = E1000_READ_REG(hw, E1000_VFGORC);
+ stats->last_gptc = E1000_READ_REG(hw, E1000_VFGPTC);
+ stats->last_gotc = E1000_READ_REG(hw, E1000_VFGOTC);
+ stats->last_mprc = E1000_READ_REG(hw, E1000_VFMPRC);
+}
+
+/**********************************************************************
+ *
+ * Update the VF board statistics counters.
+ *
+ **********************************************************************/
+static void
+igb_update_vf_stats_counters(struct adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_vf_stats *stats;
+
+ if (adapter->link_speed == 0)
+ return;
+
+ stats = (struct e1000_vf_stats *)adapter->stats;
+
+ UPDATE_VF_REG(E1000_VFGPRC,
+ stats->last_gprc, stats->gprc);
+ UPDATE_VF_REG(E1000_VFGORC,
+ stats->last_gorc, stats->gorc);
+ UPDATE_VF_REG(E1000_VFGPTC,
+ stats->last_gptc, stats->gptc);
+ UPDATE_VF_REG(E1000_VFGOTC,
+ stats->last_gotc, stats->gotc);
+ UPDATE_VF_REG(E1000_VFMPRC,
+ stats->last_mprc, stats->mprc);
}
/* Export a single 32-bit register via a read-only sysctl. */
@@ -4856,6 +4839,28 @@ igb_sysctl_reg_handler(SYSCTL_HANDLER_ARGS)
}
/*
+** Tuneable interrupt rate handler
+*/
+static int
+igb_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
+{
+ struct igb_queue *que = ((struct igb_queue *)oidp->oid_arg1);
+ int error;
+ u32 reg, usec, rate;
+
+ reg = E1000_READ_REG(&que->adapter->hw, E1000_EITR(que->msix));
+ usec = ((reg & 0x7FFC) >> 2);
+ if (usec > 0)
+ rate = 1000000 / usec;
+ else
+ rate = 0;
+ error = sysctl_handle_int(oidp, &rate, 0, req);
+ if (error || !req->newptr)
+ return error;
+ return 0;
+}
+
+/*
* Add sysctl variables, one per statistic, to the system.
*/
static void
@@ -4869,7 +4874,7 @@ igb_add_hw_stats(struct adapter *adapter)
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
struct sysctl_oid *tree = device_get_sysctl_tree(dev);
struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
- struct e1000_hw_stats *stats = &adapter->stats;
+ struct e1000_hw_stats *stats = adapter->stats;
struct sysctl_oid *stat_node, *queue_node, *int_node, *host_node;
struct sysctl_oid_list *stat_list, *queue_list, *int_list, *host_list;
@@ -4927,6 +4932,12 @@ igb_add_hw_stats(struct adapter *adapter)
CTLFLAG_RD, NULL, "Queue Name");
queue_list = SYSCTL_CHILDREN(queue_node);
+ SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate",
+ CTLFLAG_RD, &adapter->queues[i],
+ sizeof(&adapter->queues[i]),
+ igb_sysctl_interrupt_rate_handler,
+ "IU", "Interrupt Rate");
+
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head",
CTLFLAG_RD, adapter, E1000_TDH(txr->me),
igb_sysctl_reg_handler, "IU",
@@ -4970,6 +4981,29 @@ igb_add_hw_stats(struct adapter *adapter)
CTLFLAG_RD, NULL, "MAC Statistics");
stat_list = SYSCTL_CHILDREN(stat_node);
+ /*
+ ** VF adapter has a very limited set of stats
+ ** since its not managing the metal, so to speak.
+ */
+ if (adapter->hw.mac.type == e1000_vfadapt) {
+ SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_pkts_recvd",
+ CTLFLAG_RD, &stats->gprc,
+ "Good Packets Received");
+ SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd",
+ CTLFLAG_RD, &stats->gptc,
+ "Good Packets Transmitted");
+ SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_recvd",
+ CTLFLAG_RD, &stats->gorc,
+ "Good Octets Received");
+ SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_txd",
+ CTLFLAG_RD, &stats->gotc,
+ "Good Octets Transmitted");
+ SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_recvd",
+ CTLFLAG_RD, &stats->mprc,
+ "Multicast Packets Received");
+ return;
+ }
+
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "excess_coll",
CTLFLAG_RD, &stats->ecol,
"Excessive collisions");
@@ -4986,137 +5020,131 @@ igb_add_hw_stats(struct adapter *adapter)
CTLFLAG_RD, &stats->colc,
"Collision Count");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "symbol_errors",
- CTLFLAG_RD, &adapter->stats.symerrs,
+ CTLFLAG_RD, &stats->symerrs,
"Symbol Errors");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "sequence_errors",
- CTLFLAG_RD, &adapter->stats.sec,
+ CTLFLAG_RD, &stats->sec,
"Sequence Errors");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "defer_count",
- CTLFLAG_RD, &adapter->stats.dc,
+ CTLFLAG_RD, &stats->dc,
"Defer Count");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "missed_packets",
- CTLFLAG_RD, &adapter->stats.mpc,
+ CTLFLAG_RD, &stats->mpc,
"Missed Packets");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_no_buff",
- CTLFLAG_RD, &adapter->stats.rnbc,
+ CTLFLAG_RD, &stats->rnbc,
"Receive No Buffers");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_undersize",
- CTLFLAG_RD, &adapter->stats.ruc,
+ CTLFLAG_RD, &stats->ruc,
"Receive Undersize");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_fragmented",
- CTLFLAG_RD, &adapter->stats.rfc,
+ CTLFLAG_RD, &stats->rfc,
"Fragmented Packets Received ");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_oversize",
- CTLFLAG_RD, &adapter->stats.roc,
+ CTLFLAG_RD, &stats->roc,
"Oversized Packets Received");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_jabber",
- CTLFLAG_RD, &adapter->stats.rjc,
+ CTLFLAG_RD, &stats->rjc,
"Recevied Jabber");
-
- /* RLEC is inaccurate on some hardware, calculate our own. */
-/* SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_len_errs", */
-/* CTLFLAG_RD, adapter->stats.roc + adapter->stats.ruc, */
-/* "Receive Length Errors"); */
-
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_errs",
- CTLFLAG_RD, &adapter->stats.rxerrc,
+ CTLFLAG_RD, &stats->rxerrc,
"Receive Errors");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "crc_errs",
- CTLFLAG_RD, &adapter->stats.crcerrs,
+ CTLFLAG_RD, &stats->crcerrs,
"CRC errors");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "alignment_errs",
- CTLFLAG_RD, &adapter->stats.algnerrc,
+ CTLFLAG_RD, &stats->algnerrc,
"Alignment Errors");
/* On 82575 these are collision counts */
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "coll_ext_errs",
- CTLFLAG_RD, &adapter->stats.cexterr,
+ CTLFLAG_RD, &stats->cexterr,
"Collision/Carrier extension errors");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xon_recvd",
- CTLFLAG_RD, &adapter->stats.xonrxc,
+ CTLFLAG_RD, &stats->xonrxc,
"XON Received");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xon_txd",
- CTLFLAG_RD, &adapter->stats.xontxc,
+ CTLFLAG_RD, &stats->xontxc,
"XON Transmitted");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xoff_recvd",
- CTLFLAG_RD, &adapter->stats.xoffrxc,
+ CTLFLAG_RD, &stats->xoffrxc,
"XOFF Received");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xoff_txd",
- CTLFLAG_RD, &adapter->stats.xofftxc,
+ CTLFLAG_RD, &stats->xofftxc,
"XOFF Transmitted");
/* Packet Reception Stats */
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "total_pkts_recvd",
- CTLFLAG_RD, &adapter->stats.tpr,
+ CTLFLAG_RD, &stats->tpr,
"Total Packets Received ");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_pkts_recvd",
- CTLFLAG_RD, &adapter->stats.gprc,
+ CTLFLAG_RD, &stats->gprc,
"Good Packets Received");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_recvd",
- CTLFLAG_RD, &adapter->stats.bprc,
+ CTLFLAG_RD, &stats->bprc,
"Broadcast Packets Received");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_recvd",
- CTLFLAG_RD, &adapter->stats.mprc,
+ CTLFLAG_RD, &stats->mprc,
"Multicast Packets Received");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_64",
- CTLFLAG_RD, &adapter->stats.prc64,
+ CTLFLAG_RD, &stats->prc64,
"64 byte frames received ");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127",
- CTLFLAG_RD, &adapter->stats.prc127,
+ CTLFLAG_RD, &stats->prc127,
"65-127 byte frames received");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255",
- CTLFLAG_RD, &adapter->stats.prc255,
+ CTLFLAG_RD, &stats->prc255,
"128-255 byte frames received");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511",
- CTLFLAG_RD, &adapter->stats.prc511,
+ CTLFLAG_RD, &stats->prc511,
"256-511 byte frames received");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023",
- CTLFLAG_RD, &adapter->stats.prc1023,
+ CTLFLAG_RD, &stats->prc1023,
"512-1023 byte frames received");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522",
- CTLFLAG_RD, &adapter->stats.prc1522,
+ CTLFLAG_RD, &stats->prc1522,
"1023-1522 byte frames received");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_recvd",
- CTLFLAG_RD, &adapter->stats.gorc,
+ CTLFLAG_RD, &stats->gorc,
"Good Octets Received");
/* Packet Transmission Stats */
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_txd",
- CTLFLAG_RD, &adapter->stats.gotc,
+ CTLFLAG_RD, &stats->gotc,
"Good Octets Transmitted");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd",
- CTLFLAG_RD, &adapter->stats.tpt,
+ CTLFLAG_RD, &stats->tpt,
"Total Packets Transmitted");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd",
- CTLFLAG_RD, &adapter->stats.gptc,
+ CTLFLAG_RD, &stats->gptc,
"Good Packets Transmitted");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd",
- CTLFLAG_RD, &adapter->stats.bptc,
+ CTLFLAG_RD, &stats->bptc,
"Broadcast Packets Transmitted");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd",
- CTLFLAG_RD, &adapter->stats.mptc,
+ CTLFLAG_RD, &stats->mptc,
"Multicast Packets Transmitted");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_64",
- CTLFLAG_RD, &adapter->stats.ptc64,
+ CTLFLAG_RD, &stats->ptc64,
"64 byte frames transmitted ");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127",
- CTLFLAG_RD, &adapter->stats.ptc127,
+ CTLFLAG_RD, &stats->ptc127,
"65-127 byte frames transmitted");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255",
- CTLFLAG_RD, &adapter->stats.ptc255,
+ CTLFLAG_RD, &stats->ptc255,
"128-255 byte frames transmitted");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511",
- CTLFLAG_RD, &adapter->stats.ptc511,
+ CTLFLAG_RD, &stats->ptc511,
"256-511 byte frames transmitted");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023",
- CTLFLAG_RD, &adapter->stats.ptc1023,
+ CTLFLAG_RD, &stats->ptc1023,
"512-1023 byte frames transmitted");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522",
- CTLFLAG_RD, &adapter->stats.ptc1522,
+ CTLFLAG_RD, &stats->ptc1522,
"1024-1522 byte frames transmitted");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tso_txd",
- CTLFLAG_RD, &adapter->stats.tsctc,
+ CTLFLAG_RD, &stats->tsctc,
"TSO Contexts Transmitted");
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tso_ctx_fail",
- CTLFLAG_RD, &adapter->stats.tsctfc,
+ CTLFLAG_RD, &stats->tsctfc,
"TSO Contexts Failed");
@@ -5127,39 +5155,39 @@ igb_add_hw_stats(struct adapter *adapter)
int_list = SYSCTL_CHILDREN(int_node);
SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "asserts",
- CTLFLAG_RD, &adapter->stats.iac,
+ CTLFLAG_RD, &stats->iac,
"Interrupt Assertion Count");
SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "rx_pkt_timer",
- CTLFLAG_RD, &adapter->stats.icrxptc,
+ CTLFLAG_RD, &stats->icrxptc,
"Interrupt Cause Rx Pkt Timer Expire Count");
SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "rx_abs_timer",
- CTLFLAG_RD, &adapter->stats.icrxatc,
+ CTLFLAG_RD, &stats->icrxatc,
"Interrupt Cause Rx Abs Timer Expire Count");
SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "tx_pkt_timer",
- CTLFLAG_RD, &adapter->stats.ictxptc,
+ CTLFLAG_RD, &stats->ictxptc,
"Interrupt Cause Tx Pkt Timer Expire Count");
SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "tx_abs_timer",
- CTLFLAG_RD, &adapter->stats.ictxatc,
+ CTLFLAG_RD, &stats->ictxatc,
"Interrupt Cause Tx Abs Timer Expire Count");
SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "tx_queue_empty",
- CTLFLAG_RD, &adapter->stats.ictxqec,
+ CTLFLAG_RD, &stats->ictxqec,
"Interrupt Cause Tx Queue Empty Count");
SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "tx_queue_min_thresh",
- CTLFLAG_RD, &adapter->stats.ictxqmtc,
+ CTLFLAG_RD, &stats->ictxqmtc,
"Interrupt Cause Tx Queue Min Thresh Count");
SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "rx_desc_min_thresh",
- CTLFLAG_RD, &adapter->stats.icrxdmtc,
+ CTLFLAG_RD, &stats->icrxdmtc,
"Interrupt Cause Rx Desc Min Thresh Count");
SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "rx_overrun",
- CTLFLAG_RD, &adapter->stats.icrxoc,
+ CTLFLAG_RD, &stats->icrxoc,
"Interrupt Cause Receiver Overrun Count");
/* Host to Card Stats */
@@ -5171,55 +5199,55 @@ igb_add_hw_stats(struct adapter *adapter)
host_list = SYSCTL_CHILDREN(host_node);
SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "breaker_tx_pkt",
- CTLFLAG_RD, &adapter->stats.cbtmpc,
+ CTLFLAG_RD, &stats->cbtmpc,
"Circuit Breaker Tx Packet Count");
SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "host_tx_pkt_discard",
- CTLFLAG_RD, &adapter->stats.htdpmc,
+ CTLFLAG_RD, &stats->htdpmc,
"Host Transmit Discarded Packets");
SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "rx_pkt",
- CTLFLAG_RD, &adapter->stats.rpthc,
+ CTLFLAG_RD, &stats->rpthc,
"Rx Packets To Host");
SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "breaker_rx_pkts",
- CTLFLAG_RD, &adapter->stats.cbrmpc,
+ CTLFLAG_RD, &stats->cbrmpc,
"Circuit Breaker Rx Packet Count");
SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "breaker_rx_pkt_drop",
- CTLFLAG_RD, &adapter->stats.cbrdpc,
+ CTLFLAG_RD, &stats->cbrdpc,
"Circuit Breaker Rx Dropped Count");
SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "tx_good_pkt",
- CTLFLAG_RD, &adapter->stats.hgptc,
+ CTLFLAG_RD, &stats->hgptc,
"Host Good Packets Tx Count");
SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "breaker_tx_pkt_drop",
- CTLFLAG_RD, &adapter->stats.htcbdpc,
+ CTLFLAG_RD, &stats->htcbdpc,
"Host Tx Circuit Breaker Dropped Count");
SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "rx_good_bytes",
- CTLFLAG_RD, &adapter->stats.hgorc,
+ CTLFLAG_RD, &stats->hgorc,
"Host Good Octets Received Count");
SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "tx_good_bytes",
- CTLFLAG_RD, &adapter->stats.hgotc,
+ CTLFLAG_RD, &stats->hgotc,
"Host Good Octets Transmit Count");
SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "length_errors",
- CTLFLAG_RD, &adapter->stats.lenerrs,
+ CTLFLAG_RD, &stats->lenerrs,
"Length Errors");
SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "serdes_violation_pkt",
- CTLFLAG_RD, &adapter->stats.scvpc,
+ CTLFLAG_RD, &stats->scvpc,
"SerDes/SGMII Code Violation Pkt Count");
SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "header_redir_missed",
- CTLFLAG_RD, &adapter->stats.hrmpc,
+ CTLFLAG_RD, &stats->hrmpc,
"Header Redirection Missed Packet Count");
+}
-}
/**********************************************************************
*
* This routine provides a way to dump out the adapter eeprom,
diff --git a/sys/dev/e1000/if_igb.h b/sys/dev/e1000/if_igb.h
index d896c41dd3fd..0e5b1b008bbf 100644
--- a/sys/dev/e1000/if_igb.h
+++ b/sys/dev/e1000/if_igb.h
@@ -180,7 +180,8 @@
#define IGB_TX_PTHRESH 8
#define IGB_TX_HTHRESH 1
-#define IGB_TX_WTHRESH ((hw->mac.type == e1000_82576 && \
+#define IGB_TX_WTHRESH (((hw->mac.type == e1000_82576 || \
+ hw->mac.type == e1000_vfadapt) && \
adapter->msix_mem) ? 1 : 16)
#define MAX_NUM_MULTICAST_ADDRESSES 128
@@ -189,6 +190,9 @@
#define IGB_TX_BUFFER_SIZE ((uint32_t) 1514)
#define IGB_FC_PAUSE_TIME 0x0680
#define IGB_EEPROM_APME 0x400;
+#define IGB_QUEUE_IDLE 0
+#define IGB_QUEUE_WORKING 1
+#define IGB_QUEUE_HUNG 2
/*
* TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be
@@ -202,14 +206,6 @@
/* PCI Config defines */
#define IGB_MSIX_BAR 3
-/*
-** This is the total number of MSIX vectors you wish
-** to use, it also controls the size of resources.
-** The 82575 has a total of 10, 82576 has 25. Set this
-** to the real amount you need to streamline data storage.
-*/
-#define IGB_MSIX_VEC 6 /* MSIX vectors configured */
-
/* Defines for printing debug information */
#define DEBUG_INIT 0
#define DEBUG_IOCTL 0
@@ -244,13 +240,7 @@
/* Define the starting Interrupt rate per Queue */
#define IGB_INTS_PER_SEC 8000
-#define IGB_DEFAULT_ITR 1000000000/(IGB_INTS_PER_SEC * 256)
-
-
-/* Header split codes for get_buf */
-#define IGB_CLEAN_HEADER 0x01
-#define IGB_CLEAN_PAYLOAD 0x02
-#define IGB_CLEAN_BOTH (IGB_CLEAN_HEADER | IGB_CLEAN_PAYLOAD)
+#define IGB_DEFAULT_ITR ((1000000/IGB_INTS_PER_SEC) << 2)
#define IGB_LINK_ITR 2000
@@ -313,13 +303,12 @@ struct tx_ring {
u32 bytes;
u32 packets;
- bool watchdog_check;
+ int queue_status;
int watchdog_time;
+ int tdt;
+ int tdh;
u64 no_desc_avail;
u64 tx_packets;
- /* Statistics for reporting, ONLY. */
- u32 tdh; /* Transmit Descriptor Head */
- u32 tdt; /* Transmit Descriptor Tail */
};
/*
@@ -350,15 +339,14 @@ struct rx_ring {
u32 bytes;
u32 packets;
+ int rdt;
+ int rdh;
/* Soft stats */
u64 rx_split_packets;
u64 rx_discarded;
u64 rx_packets;
u64 rx_bytes;
- /* Statistics for reporting, ONLY. */
- u32 rdh; /* Transmit Descriptor Head */
- u32 rdt; /* Transmit Descriptor Tail */
};
struct adapter {
@@ -386,6 +374,7 @@ struct adapter {
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;
@@ -398,7 +387,15 @@ struct adapter {
int wol;
int has_manage;
- /* Info about the board itself */
+ /*
+ ** Shadow VFTA table, this is needed because
+ ** the real vlan filter table gets cleared during
+ ** a soft reset and the driver needs to be able
+ ** to repopulate it.
+ */
+ u32 shadow_vfta[IGB_VFTA_SIZE];
+
+ /* Info about the interface */
u8 link_active;
u16 link_speed;
u16 link_duplex;
@@ -413,6 +410,9 @@ struct adapter {
struct tx_ring *tx_rings;
u16 num_tx_desc;
+ /* Multicast array pointer */
+ u8 *mta;
+
/*
* Receive rings
*/
@@ -423,8 +423,6 @@ struct adapter {
u32 rx_mbuf_sz;
u32 rx_mask;
- /* Multicast array memory */
- u8 *mta;
/* Misc stats maintained by the driver */
unsigned long dropped_pkts;
unsigned long mbuf_defrag_failed;
@@ -451,7 +449,7 @@ struct adapter {
struct hwtstamp_ctrl hwtstamp;
#endif
- struct e1000_hw_stats stats;
+ void *stats;
};
/* ******************************************************************************
@@ -499,7 +497,17 @@ struct igb_rx_buf {
#define IGB_RX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rx_mtx)
#define IGB_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_mtx)
#define IGB_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->rx_mtx)
-#define IGB_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_mtx, MA_OWNED)
+#define IGB_RX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rx_mtx, MA_OWNED)
+
+#define UPDATE_VF_REG(reg, last, cur) \
+{ \
+ u32 new = E1000_READ_REG(hw, reg); \
+ if (new < last) \
+ cur += 0x100000000LL; \
+ last = new; \
+ cur &= 0xFFFFFFFF00000000LL; \
+ cur |= new; \
+}
#endif /* _IGB_H_DEFINED_ */
diff --git a/sys/dev/e1000/if_lem.c b/sys/dev/e1000/if_lem.c
index 5cd617109842..2629328bd66d 100644
--- a/sys/dev/e1000/if_lem.c
+++ b/sys/dev/e1000/if_lem.c
@@ -51,9 +51,7 @@
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/taskqueue.h>
-#if __FreeBSD_version >= 700029
#include <sys/eventhandler.h>
-#endif
#include <machine/bus.h>
#include <machine/resource.h>
@@ -86,8 +84,7 @@
/*********************************************************************
* Legacy Em Driver version:
*********************************************************************/
-char lem_driver_version[] = "1.0.1";
-
+char lem_driver_version[] = "1.0.3";
/*********************************************************************
* PCI Device ID Table
@@ -209,11 +206,9 @@ static void lem_disable_promisc(struct adapter *);
static void lem_set_multi(struct adapter *);
static void lem_update_link_status(struct adapter *);
static int lem_get_buf(struct adapter *, int);
-#if __FreeBSD_version >= 700029
static void lem_register_vlan(void *, struct ifnet *, u16);
static void lem_unregister_vlan(void *, struct ifnet *, u16);
static void lem_setup_vlan_hw_support(struct adapter *);
-#endif
static int lem_xmit(struct adapter *, struct mbuf **);
static void lem_smartspeed(struct adapter *);
static int lem_82547_fifo_workaround(struct adapter *, int);
@@ -231,6 +226,8 @@ static u32 lem_fill_descriptors (bus_addr_t address, u32 length,
static int lem_sysctl_int_delay(SYSCTL_HANDLER_ARGS);
static void lem_add_int_delay_sysctl(struct adapter *, const char *,
const char *, struct em_int_delay_info *, int, int);
+static void lem_set_flow_cntrl(struct adapter *, const char *,
+ const char *, int *, int);
/* Management and WOL Support */
static void lem_init_manageability(struct adapter *);
static void lem_release_manageability(struct adapter *);
@@ -244,11 +241,7 @@ static void lem_led_func(void *, int);
#ifdef EM_LEGACY_IRQ
static void lem_intr(void *);
#else /* FAST IRQ */
-#if __FreeBSD_version < 700000
-static void lem_irq_fast(void *);
-#else
static int lem_irq_fast(void *);
-#endif
static void lem_handle_rxtx(void *context, int pending);
static void lem_handle_link(void *context, int pending);
static void lem_add_rx_process_limit(struct adapter *, const char *,
@@ -320,14 +313,6 @@ TUNABLE_INT("hw.em.rx_process_limit", &lem_rx_process_limit);
static int lem_fc_setting = e1000_fc_full;
TUNABLE_INT("hw.em.fc_setting", &lem_fc_setting);
-/*
-** Shadow VFTA table, this is needed because
-** the real vlan filter table gets cleared during
-** a soft reset and the driver needs to be able
-** to repopulate it.
-*/
-static u32 lem_shadow_vfta[EM_VFTA_SIZE];
-
/* Global used in WOL setup with multiport cards */
static int global_quad_port_a = 0;
@@ -462,6 +447,11 @@ lem_attach(device_t dev)
lem_rx_process_limit);
#endif
+ /* Sysctl for setting the interface flow control */
+ lem_set_flow_cntrl(adapter, "flow_control",
+ "max number of rx packets to process",
+ &adapter->fc_setting, lem_fc_setting);
+
/*
* Validate number of transmit and receive descriptors. It
* must not exceed hardware maximum, and must be multiple
@@ -638,13 +628,11 @@ lem_attach(device_t dev)
else
adapter->pcix_82544 = FALSE;
-#if __FreeBSD_version >= 700029
/* Register for VLAN events */
adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
lem_register_vlan, adapter, EVENTHANDLER_PRI_FIRST);
adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
lem_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST);
-#endif
lem_add_hw_stats(adapter);
@@ -702,11 +690,7 @@ lem_detach(device_t dev)
INIT_DEBUGOUT("em_detach: begin");
/* Make sure VLANS are not using driver */
-#if __FreeBSD_version >= 700000
if (adapter->ifp->if_vlantrunk != NULL) {
-#else
- if (adapter->ifp->if_nvlans != 0) {
-#endif
device_printf(dev,"Vlan in use, detach first\n");
return (EBUSY);
}
@@ -730,13 +714,11 @@ lem_detach(device_t dev)
EM_TX_UNLOCK(adapter);
EM_CORE_UNLOCK(adapter);
-#if __FreeBSD_version >= 700029
/* Unregister VLAN events */
if (adapter->vlan_attach != NULL)
EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach);
if (adapter->vlan_detach != NULL)
EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach);
-#endif
ether_ifdetach(adapter->ifp);
callout_drain(&adapter->timer);
@@ -831,6 +813,19 @@ lem_start_locked(struct ifnet *ifp)
if (!adapter->link_active)
return;
+ /*
+ * Force a cleanup if number of TX descriptors
+ * available hits the threshold
+ */
+ if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
+ lem_txeof(adapter);
+ /* Now do we at least have a minimal? */
+ if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) {
+ adapter->no_tx_desc_avail1++;
+ return;
+ }
+ }
+
while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
@@ -1043,9 +1038,7 @@ lem_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
if (reinit && (ifp->if_drv_flags & IFF_DRV_RUNNING))
lem_init(adapter);
-#if __FreeBSD_version >= 700000
VLAN_CAPABILITIES(ifp);
-#endif
break;
}
@@ -1135,18 +1128,6 @@ lem_init_locked(struct adapter *adapter)
/* Setup VLAN support, basic and offload if available */
E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN);
-#if __FreeBSD_version < 700029
- if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
- u32 ctrl;
- ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL);
- ctrl |= E1000_CTRL_VME;
- E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
- }
-#else
- /* Use real VLAN Filter support */
- lem_setup_vlan_hw_support(adapter);
-#endif
-
/* Set hardware offload abilities */
ifp->if_hwassist = 0;
if (adapter->hw.mac.type >= e1000_82543) {
@@ -1174,6 +1155,19 @@ lem_init_locked(struct adapter *adapter)
}
lem_initialize_receive_unit(adapter);
+ /* Use real VLAN Filter support? */
+ if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
+ if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
+ /* Use real VLAN Filter support */
+ lem_setup_vlan_hw_support(adapter);
+ else {
+ u32 ctrl;
+ ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_VME;
+ E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
+ }
+ }
+
/* Don't lose promiscuous settings */
lem_set_promisc(adapter);
@@ -1235,7 +1229,7 @@ lem_init(void *arg)
* Legacy polling routine
*
*********************************************************************/
-static void
+static int
lem_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
{
struct adapter *adapter = ifp->if_softc;
@@ -1244,7 +1238,7 @@ lem_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
EM_CORE_LOCK(adapter);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
EM_CORE_UNLOCK(adapter);
- return;
+ return (rx_done);
}
if (cmd == POLL_AND_CHECK_STATUS) {
@@ -1266,6 +1260,7 @@ lem_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
lem_start_locked(ifp);
EM_TX_UNLOCK(adapter);
+ return (rx_done);
}
#endif /* DEVICE_POLLING */
@@ -1275,7 +1270,6 @@ lem_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
* Legacy Interrupt Service routine
*
*********************************************************************/
-
static void
lem_intr(void *arg)
{
@@ -1310,7 +1304,6 @@ lem_intr(void *arg)
}
EM_TX_LOCK(adapter);
- lem_txeof(adapter);
lem_rxeof(adapter, -1, NULL);
lem_txeof(adapter);
if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
@@ -1353,8 +1346,7 @@ lem_handle_rxtx(void *context, int pending)
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- if (lem_rxeof(adapter, adapter->rx_process_limit, NULL) != 0)
- taskqueue_enqueue(adapter->tq, &adapter->rxtx_task);
+ lem_rxeof(adapter, adapter->rx_process_limit, NULL);
EM_TX_LOCK(adapter);
lem_txeof(adapter);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
@@ -1362,7 +1354,8 @@ lem_handle_rxtx(void *context, int pending)
EM_TX_UNLOCK(adapter);
}
- lem_enable_intr(adapter);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ lem_enable_intr(adapter);
}
/*********************************************************************
@@ -1370,13 +1363,7 @@ lem_handle_rxtx(void *context, int pending)
* Fast Legacy/MSI Combined Interrupt Service routine
*
*********************************************************************/
-#if __FreeBSD_version < 700000
-#define FILTER_STRAY
-#define FILTER_HANDLED
-static void
-#else
static int
-#endif
lem_irq_fast(void *arg)
{
struct adapter *adapter = arg;
@@ -1549,25 +1536,10 @@ lem_xmit(struct adapter *adapter, struct mbuf **m_headp)
struct mbuf *m_head;
u32 txd_upper, txd_lower, txd_used, txd_saved;
int error, nsegs, i, j, first, last = 0;
-#if __FreeBSD_version < 700000
- struct m_tag *mtag;
-#endif
+
m_head = *m_headp;
txd_upper = txd_lower = txd_used = txd_saved = 0;
- /*
- * Force a cleanup if number of TX descriptors
- * available hits the threshold
- */
- if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
- lem_txeof(adapter);
- /* Now do we at least have a minimal? */
- if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) {
- adapter->no_tx_desc_avail1++;
- return (ENOBUFS);
- }
- }
-
/*
** When doing checksum offload, it is critical to
** make sure the first mbuf has more than header,
@@ -1711,20 +1683,6 @@ lem_xmit(struct adapter *adapter, struct mbuf **m_headp)
else
adapter->num_tx_desc_avail -= nsegs;
- /*
- ** Handle VLAN tag, this is the
- ** biggest difference between
- ** 6.x and 7
- */
-#if __FreeBSD_version < 700000
- /* Find out if we are in vlan mode. */
- mtag = VLAN_OUTPUT_TAG(ifp, m_head);
- if (mtag != NULL) {
- ctxd->upper.fields.special =
- htole16(VLAN_TAG_VALUE(mtag));
- ctxd->lower.data |= htole32(E1000_TXD_CMD_VLE);
- }
-#else /* FreeBSD 7 */
if (m_head->m_flags & M_VLANTAG) {
/* Set the vlan id. */
ctxd->upper.fields.special =
@@ -1732,7 +1690,6 @@ lem_xmit(struct adapter *adapter, struct mbuf **m_headp)
/* Tell hardware to add tag */
ctxd->lower.data |= htole32(E1000_TXD_CMD_VLE);
}
-#endif
tx_buffer->m_head = m_head;
tx_buffer_mapped->map = tx_buffer->map;
@@ -1752,6 +1709,7 @@ lem_xmit(struct adapter *adapter, struct mbuf **m_headp)
*/
tx_buffer = &adapter->tx_buffer_area[first];
tx_buffer->next_eop = last;
+ adapter->watchdog_time = ticks;
/*
* Advance the Transmit Descriptor Tail (TDT), this tells the E1000
@@ -1955,11 +1913,7 @@ lem_set_multi(struct adapter *adapter)
msec_delay(5);
}
-#if __FreeBSD_version < 800000
IF_ADDR_LOCK(ifp);
-#else
- if_maddr_rlock(ifp);
-#endif
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
@@ -1971,11 +1925,7 @@ lem_set_multi(struct adapter *adapter)
&mta[mcnt * ETH_ADDR_LEN], ETH_ADDR_LEN);
mcnt++;
}
-#if __FreeBSD_version < 800000
IF_ADDR_UNLOCK(ifp);
-#else
- if_maddr_runlock(ifp);
-#endif
if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) {
reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
reg_rctl |= E1000_RCTL_MPE;
@@ -2009,8 +1959,6 @@ lem_local_timer(void *arg)
EM_CORE_LOCK_ASSERT(adapter);
- taskqueue_enqueue(adapter->tq,
- &adapter->rxtx_task);
lem_update_link_status(adapter);
lem_update_stats_counters(adapter);
@@ -2249,11 +2197,7 @@ lem_allocate_irq(struct adapter *adapter)
#ifdef EM_LEGACY_IRQ
/* We do Legacy setup */
if ((error = bus_setup_intr(dev, adapter->res[0],
-#if __FreeBSD_version > 700000
INTR_TYPE_NET | INTR_MPSAFE, NULL, lem_intr, adapter,
-#else /* 6.X */
- INTR_TYPE_NET | INTR_MPSAFE, lem_intr, adapter,
-#endif
&adapter->tag[0])) != 0) {
device_printf(dev, "Failed to register interrupt handler");
return (error);
@@ -2270,13 +2214,8 @@ lem_allocate_irq(struct adapter *adapter)
taskqueue_thread_enqueue, &adapter->tq);
taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s taskq",
device_get_nameunit(adapter->dev));
-#if __FreeBSD_version < 700000
- if ((error = bus_setup_intr(dev, adapter->res[0],
- INTR_TYPE_NET | INTR_FAST, lem_irq_fast, adapter,
-#else
if ((error = bus_setup_intr(dev, adapter->res[0],
INTR_TYPE_NET, lem_irq_fast, NULL, adapter,
-#endif
&adapter->tag[0])) != 0) {
device_printf(dev, "Failed to register fast interrupt "
"handler: %d\n", error);
@@ -2362,7 +2301,7 @@ lem_hardware_init(struct adapter *adapter)
adapter->hw.fc.send_xon = TRUE;
/* Set Flow control, use the tunable location if sane */
- if ((lem_fc_setting >= 0) || (lem_fc_setting < 4))
+ if ((lem_fc_setting >= 0) && (lem_fc_setting < 4))
adapter->hw.fc.requested_mode = lem_fc_setting;
else
adapter->hw.fc.requested_mode = e1000_fc_none;
@@ -2410,14 +2349,8 @@ lem_setup_interface(device_t dev, struct adapter *adapter)
ifp->if_capabilities = ifp->if_capenable = 0;
if (adapter->hw.mac.type >= e1000_82543) {
- int version_cap;
-#if __FreeBSD_version < 700000
- version_cap = IFCAP_HWCSUM;
-#else
- version_cap = IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
-#endif
- ifp->if_capabilities |= version_cap;
- ifp->if_capenable |= version_cap;
+ ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
+ ifp->if_capenable |= IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
}
/*
@@ -2427,6 +2360,16 @@ lem_setup_interface(device_t dev, struct adapter *adapter)
ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
ifp->if_capenable |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
+ /*
+ ** Dont turn this on by default, if vlans are
+ ** created on another pseudo device (eg. lagg)
+ ** then vlan events are not passed thru, breaking
+ ** operation, but with HW FILTER off it works. If
+ ** using vlans directly on the em driver you can
+ ** enable this and get full hardware tag filtering.
+ */
+ ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
+
#ifdef DEVICE_POLLING
ifp->if_capabilities |= IFCAP_POLLING;
#endif
@@ -2551,11 +2494,7 @@ lem_dma_malloc(struct adapter *adapter, bus_size_t size,
{
int error;
-#if __FreeBSD_version >= 700000
error = bus_dma_tag_create(bus_get_dma_tag(adapter->dev), /* parent */
-#else
- error = bus_dma_tag_create(NULL, /* parent */
-#endif
EM_DBA_ALIGN, 0, /* alignment, bounds */
BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
@@ -2640,21 +2579,17 @@ lem_allocate_transmit_structures(struct adapter *adapter)
/*
* Create DMA tags for tx descriptors
*/
-#if __FreeBSD_version >= 700000
if ((error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
-#else
- if ((error = bus_dma_tag_create(NULL, /* parent */
-#endif
1, 0, /* alignment, bounds */
BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
- EM_TSO_SIZE, /* maxsize */
+ MCLBYTES * EM_MAX_SCATTER, /* maxsize */
EM_MAX_SCATTER, /* nsegments */
- EM_TSO_SEG_SIZE, /* maxsegsize */
+ MCLBYTES, /* maxsegsize */
0, /* flags */
- NULL, /* lockfunc */
- NULL, /* lockarg */
+ NULL, /* lockfunc */
+ NULL, /* lockarg */
&adapter->txtag)) != 0) {
device_printf(dev, "Unable to allocate TX DMA tag\n");
goto fail;
@@ -2829,10 +2764,6 @@ lem_free_transmit_structures(struct adapter *adapter)
bus_dma_tag_destroy(adapter->txtag);
adapter->txtag = NULL;
}
-#if __FreeBSD_version >= 800000
- if (adapter->br != NULL)
- buf_ring_free(adapter->br, M_DEVBUF);
-#endif
}
/*********************************************************************
@@ -3072,23 +3003,20 @@ lem_txeof(struct adapter *adapter)
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
adapter->next_tx_to_clean = first;
+ adapter->num_tx_desc_avail = num_avail;
/*
* If we have enough room, clear IFF_DRV_OACTIVE to
* tell the stack that it is OK to send packets.
* If there are no pending descriptors, clear the watchdog.
*/
- if (num_avail > EM_TX_CLEANUP_THRESHOLD) {
+ if (adapter->num_tx_desc_avail > EM_TX_CLEANUP_THRESHOLD) {
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- if (num_avail == adapter->num_tx_desc) {
+ if (adapter->num_tx_desc_avail == adapter->num_tx_desc) {
adapter->watchdog_check = FALSE;
- adapter->num_tx_desc_avail = num_avail;
return;
}
}
-
- adapter->num_tx_desc_avail = num_avail;
- return;
}
/*********************************************************************
@@ -3185,11 +3113,7 @@ lem_allocate_receive_structures(struct adapter *adapter)
return (ENOMEM);
}
-#if __FreeBSD_version >= 700000
error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
-#else
- error = bus_dma_tag_create(NULL, /* parent */
-#endif
1, 0, /* alignment, bounds */
BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
@@ -3459,7 +3383,7 @@ lem_rxeof(struct adapter *adapter, int count, int *done)
{
struct ifnet *ifp = adapter->ifp;;
struct mbuf *mp;
- u8 status, accept_frame = 0, eop = 0;
+ u8 status = 0, accept_frame = 0, eop = 0;
u16 len, desc_len, prev_len_adj;
int i, rx_sent = 0;
struct e1000_rx_desc *current_desc;
@@ -3477,11 +3401,13 @@ lem_rxeof(struct adapter *adapter, int count, int *done)
return (FALSE);
}
- while ((current_desc->status & E1000_RXD_STAT_DD) &&
- (count != 0) &&
- (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+ while (count != 0 && ifp->if_drv_flags & IFF_DRV_RUNNING) {
struct mbuf *m = NULL;
+ status = current_desc->status;
+ if ((status & E1000_RXD_STAT_DD) == 0)
+ break;
+
mp = adapter->rx_buffer_area[i].m_head;
/*
* Can't defer bus_dmamap_sync(9) because TBI_ACCEPT
@@ -3493,7 +3419,6 @@ lem_rxeof(struct adapter *adapter, int count, int *done)
accept_frame = 1;
prev_len_adj = 0;
desc_len = le16toh(current_desc->length);
- status = current_desc->status;
if (status & E1000_RXD_STAT_EOP) {
count--;
eop = 1;
@@ -3571,16 +3496,10 @@ lem_rxeof(struct adapter *adapter, int count, int *done)
goto skip;
#endif
if (status & E1000_RXD_STAT_VP) {
-#if __FreeBSD_version < 700000
- VLAN_INPUT_TAG_NEW(ifp, adapter->fmp,
- (le16toh(current_desc->special) &
- E1000_RXD_SPC_VLAN_MASK));
-#else
adapter->fmp->m_pkthdr.ether_vtag =
(le16toh(current_desc->special) &
E1000_RXD_SPC_VLAN_MASK);
adapter->fmp->m_flags |= M_VLANTAG;
-#endif
}
#ifndef __NO_STRICT_ALIGNMENT
skip:
@@ -3636,7 +3555,7 @@ discard:
if (done != NULL)
*done = rx_sent;
EM_RX_UNLOCK(adapter);
- return (current_desc->status & E1000_RXD_STAT_DD);
+ return ((status & E1000_RXD_STAT_DD) ? TRUE : FALSE);
}
#ifndef __NO_STRICT_ALIGNMENT
@@ -3728,7 +3647,6 @@ lem_receive_checksum(struct adapter *adapter,
}
}
-#if __FreeBSD_version >= 700029
/*
* This routine is run via an vlan
* config EVENT
@@ -3745,12 +3663,15 @@ lem_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
if ((vtag == 0) || (vtag > 4095)) /* Invalid ID */
return;
+ EM_CORE_LOCK(adapter);
index = (vtag >> 5) & 0x7F;
bit = vtag & 0x1F;
- lem_shadow_vfta[index] |= (1 << bit);
+ adapter->shadow_vfta[index] |= (1 << bit);
++adapter->num_vlans;
/* Re-init to load the changes */
- lem_init(adapter);
+ if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
+ lem_init_locked(adapter);
+ EM_CORE_UNLOCK(adapter);
}
/*
@@ -3769,12 +3690,15 @@ lem_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
if ((vtag == 0) || (vtag > 4095)) /* Invalid */
return;
+ EM_CORE_LOCK(adapter);
index = (vtag >> 5) & 0x7F;
bit = vtag & 0x1F;
- lem_shadow_vfta[index] &= ~(1 << bit);
+ adapter->shadow_vfta[index] &= ~(1 << bit);
--adapter->num_vlans;
/* Re-init to load the changes */
- lem_init(adapter);
+ if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
+ lem_init_locked(adapter);
+ EM_CORE_UNLOCK(adapter);
}
static void
@@ -3797,9 +3721,9 @@ lem_setup_vlan_hw_support(struct adapter *adapter)
** we need to repopulate it now.
*/
for (int i = 0; i < EM_VFTA_SIZE; i++)
- if (lem_shadow_vfta[i] != 0)
+ if (adapter->shadow_vfta[i] != 0)
E1000_WRITE_REG_ARRAY(hw, E1000_VFTA,
- i, lem_shadow_vfta[i]);
+ i, adapter->shadow_vfta[i]);
reg = E1000_READ_REG(hw, E1000_CTRL);
reg |= E1000_CTRL_VME;
@@ -3815,7 +3739,6 @@ lem_setup_vlan_hw_support(struct adapter *adapter)
E1000_WRITE_REG(&adapter->hw, E1000_RLPML,
adapter->max_frame_size + VLAN_TAG_SIZE);
}
-#endif
static void
lem_enable_intr(struct adapter *adapter)
@@ -4661,6 +4584,16 @@ lem_add_int_delay_sysctl(struct adapter *adapter, const char *name,
info, 0, lem_sysctl_int_delay, "I", description);
}
+static void
+lem_set_flow_cntrl(struct adapter *adapter, const char *name,
+ const char *description, int *limit, int value)
+{
+ *limit = value;
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)),
+ OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description);
+}
+
#ifndef EM_LEGACY_IRQ
static void
lem_add_rx_process_limit(struct adapter *adapter, const char *name,
@@ -4672,5 +4605,3 @@ lem_add_rx_process_limit(struct adapter *adapter, const char *name,
OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description);
}
#endif
-
-
diff --git a/sys/dev/e1000/if_lem.h b/sys/dev/e1000/if_lem.h
index 2f76aa8041b1..350df02b31f1 100644
--- a/sys/dev/e1000/if_lem.h
+++ b/sys/dev/e1000/if_lem.h
@@ -285,9 +285,6 @@ struct em_int_delay_info {
/* Our adapter structure */
struct adapter {
struct ifnet *ifp;
-#if __FreeBSD_version >= 800000
- struct buf_ring *br;
-#endif
struct e1000_hw hw;
/* FreeBSD operating-system-specific structures. */
@@ -328,11 +325,9 @@ struct adapter {
struct task tx_task;
struct taskqueue *tq; /* private task queue */
-#if __FreeBSD_version >= 700029
eventhandler_tag vlan_attach;
eventhandler_tag vlan_detach;
u32 num_vlans;
-#endif
/* Management and WOL features */
u32 wol;
@@ -341,11 +336,22 @@ struct adapter {
/* Multicast array memory */
u8 *mta;
- /* Info about the board itself */
+
+ /*
+ ** Shadow VFTA table, this is needed because
+ ** the real vlan filter table gets cleared during
+ ** a soft reset and the driver needs to be able
+ ** to repopulate it.
+ */
+ u32 shadow_vfta[EM_VFTA_SIZE];
+
+ /* Info about the interface */
uint8_t link_active;
uint16_t link_speed;
uint16_t link_duplex;
uint32_t smartspeed;
+ uint32_t fc_setting;
+
struct em_int_delay_info tx_int_delay;
struct em_int_delay_info tx_abs_int_delay;
struct em_int_delay_info rx_int_delay;
@@ -407,6 +413,9 @@ struct adapter {
unsigned long no_tx_dma_setup;
unsigned long watchdog_events;
unsigned long rx_overruns;
+ unsigned long rx_irq;
+ unsigned long tx_irq;
+ unsigned long link_irq;
/* 82547 workaround */
uint32_t tx_fifo_size;