diff options
| author | Jack F Vogel <jfv@FreeBSD.org> | 2010-11-27 01:09:54 +0000 |
|---|---|---|
| committer | Jack F Vogel <jfv@FreeBSD.org> | 2010-11-27 01:09:54 +0000 |
| commit | 560747b6289d5d0ebee983e11e3d46dabf190653 (patch) | |
| tree | ea58a4c9dd7d73a9e0831a48f1148c17e6ceb169 /sys/dev | |
| parent | c3b293be2011147fe82ec036f0908ac0c2bb56e8 (diff) | |
Notes
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/e1000/e1000_82571.c | 269 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_82571.h | 8 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_82575.c | 160 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_82575.h | 12 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_api.c | 78 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_api.h | 4 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_defines.h | 37 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_hw.h | 80 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_ich8lan.c | 831 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_ich8lan.h | 40 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_mac.c | 10 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_nvm.c | 186 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_nvm.h | 5 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_osdep.h | 10 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_phy.c | 22 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_phy.h | 2 | ||||
| -rw-r--r-- | sys/dev/e1000/e1000_regs.h | 15 | ||||
| -rw-r--r-- | sys/dev/e1000/if_em.c | 1317 | ||||
| -rw-r--r-- | sys/dev/e1000/if_em.h | 39 | ||||
| -rw-r--r-- | sys/dev/e1000/if_igb.c | 1064 | ||||
| -rw-r--r-- | sys/dev/e1000/if_igb.h | 64 | ||||
| -rw-r--r-- | sys/dev/e1000/if_lem.c | 251 | ||||
| -rw-r--r-- | sys/dev/e1000/if_lem.h | 21 |
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, ®); /* 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, ®); - 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; |
