summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/em/e1000_82571.c59
-rw-r--r--sys/dev/em/e1000_82571.h8
-rw-r--r--sys/dev/em/e1000_api.c19
-rw-r--r--sys/dev/em/e1000_api.h2
-rw-r--r--sys/dev/em/e1000_defines.h21
-rw-r--r--sys/dev/em/e1000_hw.h9
-rw-r--r--sys/dev/em/e1000_ich8lan.c90
-rw-r--r--sys/dev/em/e1000_ich8lan.h12
-rw-r--r--sys/dev/em/e1000_osdep.h4
-rw-r--r--sys/dev/em/e1000_phy.c103
-rw-r--r--sys/dev/em/e1000_phy.h2
-rw-r--r--sys/dev/em/if_em.c470
-rw-r--r--sys/dev/em/if_em.h109
-rw-r--r--sys/dev/igb/e1000_82575.c29
-rw-r--r--sys/dev/igb/e1000_api.c9
-rw-r--r--sys/dev/igb/e1000_api.h2
-rw-r--r--sys/dev/igb/e1000_defines.h1
-rw-r--r--sys/dev/igb/e1000_hw.h6
-rw-r--r--sys/dev/igb/e1000_mac.c3
-rw-r--r--sys/dev/igb/e1000_manage.h1
-rw-r--r--sys/dev/igb/e1000_osdep.c14
-rw-r--r--sys/dev/igb/e1000_osdep.h12
-rw-r--r--sys/dev/igb/e1000_phy.c15
-rw-r--r--sys/dev/igb/if_igb.c75
-rw-r--r--sys/dev/igb/if_igb.h10
-rw-r--r--sys/modules/em/Makefile11
26 files changed, 864 insertions, 232 deletions
diff --git a/sys/dev/em/e1000_82571.c b/sys/dev/em/e1000_82571.c
index 7a2e209..b4edaae 100644
--- a/sys/dev/em/e1000_82571.c
+++ b/sys/dev/em/e1000_82571.c
@@ -150,6 +150,25 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
goto out;
}
break;
+ case e1000_82574:
+ phy->type = e1000_phy_bm;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ 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;
+
+ /* This uses above function pointers */
+ ret_val = e1000_get_phy_id_82571(hw);
+ /* Verify PHY ID */
+ if (phy->id != BME1000_E_PHY_ID_R2) {
+ ret_val = -E1000_ERR_PHY;
+ DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id);
+ goto out;
+ }
+ break;
default:
ret_val = -E1000_ERR_PHY;
goto out;
@@ -193,6 +212,7 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
switch (hw->mac.type) {
case e1000_82573:
+ case e1000_82574:
if (((eecd >> 15) & 0x3) == 0x3) {
nvm->type = e1000_nvm_flash_hw;
nvm->word_size = 2048;
@@ -374,6 +394,7 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val = E1000_SUCCESS;
+ u16 phy_id = 0;
DEBUGFUNC("e1000_get_phy_id_82571");
@@ -391,11 +412,26 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
case e1000_82573:
ret_val = e1000_get_phy_id(hw);
break;
+ case e1000_82574:
+ ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
+ if (ret_val)
+ goto out;
+
+ phy->id = (u32)(phy_id << 16);
+ usec_delay(20);
+ ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
+ if (ret_val)
+ goto out;
+
+ phy->id |= (u32)(phy_id);
+ phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+ break;
default:
ret_val = -E1000_ERR_PHY;
break;
}
+out:
return ret_val;
}
@@ -476,7 +512,7 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
if (ret_val)
goto out;
- if (hw->mac.type != e1000_82573)
+ if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574)
ret_val = e1000_acquire_nvm_generic(hw);
if (ret_val)
@@ -521,6 +557,7 @@ static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
switch (hw->mac.type) {
case e1000_82573:
+ case e1000_82574:
ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
break;
case e1000_82571:
@@ -825,7 +862,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
* Must acquire the MDIO ownership before MAC reset.
* Ownership defaults to firmware after a reset.
*/
- if (hw->mac.type == e1000_82573) {
+ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
@@ -866,7 +903,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
* Need to wait for Phy configuration completion before accessing
* NVM and Phy.
*/
- if (hw->mac.type == e1000_82573)
+ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574)
msec_delay(25);
/* Clear any pending interrupt events. */
@@ -934,7 +971,7 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw)
E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data);
/* ...for both queues. */
- if (mac->type != e1000_82573) {
+ if (mac->type != e1000_82573 && mac->type != e1000_82574) {
reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1));
reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
E1000_TXDCTL_FULL_TX_DESC_WB |
@@ -1014,14 +1051,14 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
}
/* Device Control */
- if (hw->mac.type == e1000_82573) {
+ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
reg = E1000_READ_REG(hw, E1000_CTRL);
reg &= ~(1 << 29);
E1000_WRITE_REG(hw, E1000_CTRL, reg);
}
/* Extended Device Control */
- if (hw->mac.type == e1000_82573) {
+ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
reg &= ~(1 << 23);
reg |= (1 << 22);
@@ -1048,7 +1085,7 @@ static void e1000_clear_vfta_82571(struct e1000_hw *hw)
DEBUGFUNC("e1000_clear_vfta_82571");
- if (hw->mac.type == e1000_82573) {
+ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
if (hw->mng_cookie.vlan_id != 0) {
/*
* The VFTA is a 4096b bit-field, each identifying
@@ -1121,7 +1158,8 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw)
* the default flow control setting, so we explicitly
* set it to full.
*/
- if (hw->mac.type == e1000_82573 && hw->fc.type == e1000_fc_default)
+ if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
+ hw->fc.type == e1000_fc_default)
hw->fc.type = e1000_fc_full;
return e1000_setup_link_generic(hw);
@@ -1224,11 +1262,10 @@ static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
goto out;
}
- if (hw->mac.type == e1000_82573 &&
+ if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
*data == ID_LED_RESERVED_F746)
*data = ID_LED_DEFAULT_82573;
- else if (*data == ID_LED_RESERVED_0000 ||
- *data == ID_LED_RESERVED_FFFF)
+ else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
*data = ID_LED_DEFAULT;
out:
return ret_val;
diff --git a/sys/dev/em/e1000_82571.h b/sys/dev/em/e1000_82571.h
index e6469ea..ceb0ab0 100644
--- a/sys/dev/em/e1000_82571.h
+++ b/sys/dev/em/e1000_82571.h
@@ -43,4 +43,12 @@
#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+/* Intr Throttling - RW */
+#define E1000_EITR_82574(_n) (0x000E8 + (0x4 * (_n)))
+
+#define E1000_EIAC_82574 0x000DC /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAC_MASK_82574 0x01500000
+
+#define E1000_RXCFGL 0x0B634 /* TimeSync Rx EtherType & Msg Type Reg - RW */
+
#endif
diff --git a/sys/dev/em/e1000_api.c b/sys/dev/em/e1000_api.c
index ead54d6..fee0e4e 100644
--- a/sys/dev/em/e1000_api.c
+++ b/sys/dev/em/e1000_api.c
@@ -216,6 +216,9 @@ s32 e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82573L:
mac->type = e1000_82573;
break;
+ case E1000_DEV_ID_82574L:
+ mac->type = e1000_82574;
+ break;
case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
@@ -238,14 +241,24 @@ s32 e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_ICH9_IGP_M_AMT:
case E1000_DEV_ID_ICH9_IGP_M_V:
case E1000_DEV_ID_ICH9_IGP_AMT:
+ case E1000_DEV_ID_ICH9_BM:
case E1000_DEV_ID_ICH9_IGP_C:
+ case E1000_DEV_ID_ICH10_R_BM_LM:
+ case E1000_DEV_ID_ICH10_R_BM_LF:
+ case E1000_DEV_ID_ICH10_R_BM_V:
mac->type = e1000_ich9lan;
break;
+ case E1000_DEV_ID_ICH10_D_BM_LM:
+ case E1000_DEV_ID_ICH10_D_BM_LF:
+ mac->type = e1000_ich10lan;
+ break;
+#ifndef NO_82575_SUPPORT
case E1000_DEV_ID_82575EB_COPPER:
case E1000_DEV_ID_82575EB_FIBER_SERDES:
case E1000_DEV_ID_82575GB_QUAD_COPPER:
mac->type = e1000_82575;
break;
+#endif
default:
/* Should never have loaded on this device */
ret_val = -E1000_ERR_MAC_INIT;
@@ -323,6 +336,7 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device)
case e1000_82571:
case e1000_82572:
case e1000_82573:
+ case e1000_82574:
e1000_init_function_pointers_82571(hw);
break;
case e1000_80003es2lan:
@@ -330,11 +344,14 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device)
break;
case e1000_ich8lan:
case e1000_ich9lan:
+ case e1000_ich10lan:
e1000_init_function_pointers_ich8lan(hw);
break;
+#ifndef NO_82575_SUPPORT
case e1000_82575:
e1000_init_function_pointers_82575(hw);
break;
+#endif
default:
DEBUGOUT("Hardware not supported\n");
ret_val = -E1000_ERR_CONFIG;
@@ -403,7 +420,7 @@ s32 e1000_get_bus_info(struct e1000_hw *hw)
void e1000_clear_vfta(struct e1000_hw *hw)
{
if (hw->mac.ops.clear_vfta)
- hw->mac.ops.clear_vfta (hw);
+ hw->mac.ops.clear_vfta(hw);
}
/**
diff --git a/sys/dev/em/e1000_api.h b/sys/dev/em/e1000_api.h
index 921b194..84f261b 100644
--- a/sys/dev/em/e1000_api.h
+++ b/sys/dev/em/e1000_api.h
@@ -46,7 +46,9 @@ extern void e1000_init_function_pointers_82571(struct e1000_hw *hw);
extern void e1000_init_function_pointers_82541(struct e1000_hw *hw);
extern void e1000_init_function_pointers_80003es2lan(struct e1000_hw *hw);
extern void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw);
+#ifndef NO_82575_SUPPORT
extern void e1000_init_function_pointers_82575(struct e1000_hw *hw);
+#endif
s32 e1000_set_mac_type(struct e1000_hw *hw);
s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device);
diff --git a/sys/dev/em/e1000_defines.h b/sys/dev/em/e1000_defines.h
index 516db57..72aa978 100644
--- a/sys/dev/em/e1000_defines.h
+++ b/sys/dev/em/e1000_defines.h
@@ -154,6 +154,7 @@
#define E1000_CTRL_EXT_DF_PAREN 0x02000000 /* descriptor FIFO parity error detection enable */
#define E1000_CTRL_EXT_GHOST_PAREN 0x40000000
#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
+#define E1000_CTRL_EXT_LSECCK 0x00001000
#define E1000_I2CCMD_REG_ADDR_SHIFT 16
#define E1000_I2CCMD_REG_ADDR 0x00FF0000
#define E1000_I2CCMD_PHY_ADDR_SHIFT 24
@@ -202,6 +203,13 @@
#define E1000_RXDEXT_STATERR_IPE 0x40000000
#define E1000_RXDEXT_STATERR_RXE 0x80000000
+#define E1000_RXDEXT_LSECH 0x01000000
+#define E1000_RXDEXT_LSECE_MASK 0x60000000
+#define E1000_RXDEXT_LSECE_NO_ERROR 0x00000000
+#define E1000_RXDEXT_LSECE_NO_SA_MATCH 0x20000000
+#define E1000_RXDEXT_LSECE_REPLAY_DETECT 0x40000000
+#define E1000_RXDEXT_LSECE_BAD_SIG 0x60000000
+
/* mask to determine if packets should be dropped due to frame errors */
#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
E1000_RXD_ERR_CE | \
@@ -397,6 +405,7 @@
#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA
#define E1000_CONNSW_ENRGSRC 0x4
+#define E1000_PCS_CFG_PCS_EN 8
#define E1000_PCS_LCTL_FLV_LINK_UP 1
#define E1000_PCS_LCTL_FSV_10 0
#define E1000_PCS_LCTL_FSV_100 2
@@ -556,6 +565,8 @@
#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
/* Extended desc bits for Linksec and timesync */
+#define E1000_TXD_CMD_LINKSEC 0x10000000 /* Apply LinkSec on packet */
+#define E1000_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
/* Transmit Control */
#define E1000_TCTL_RST 0x00000001 /* software reset */
@@ -715,6 +726,11 @@
#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */
#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */
#define E1000_ICR_EPRST 0x00100000 /* ME hardware reset occurs */
+#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */
+#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */
+#define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */
+#define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */
+#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */
/* Extended Interrupt Cause Read */
#define E1000_EICR_RX_QUEUE0 0x00000001 /* Rx Queue 0 Interrupt */
@@ -787,6 +803,11 @@
#define E1000_IMS_DSW E1000_ICR_DSW
#define E1000_IMS_PHYINT E1000_ICR_PHYINT
#define E1000_IMS_EPRST E1000_ICR_EPRST
+#define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */
+#define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */
+#define E1000_IMS_TXQ0 E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */
+#define E1000_IMS_TXQ1 E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */
+#define E1000_IMS_OTHER E1000_ICR_OTHER /* Other Interrupts */
/* Extended Interrupt Mask Set */
#define E1000_EIMS_RX_QUEUE0 E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */
diff --git a/sys/dev/em/e1000_hw.h b/sys/dev/em/e1000_hw.h
index ebc20bf..ea32a05 100644
--- a/sys/dev/em/e1000_hw.h
+++ b/sys/dev/em/e1000_hw.h
@@ -95,6 +95,7 @@ struct e1000_hw;
#define E1000_DEV_ID_82573E 0x108B
#define E1000_DEV_ID_82573E_IAMT 0x108C
#define E1000_DEV_ID_82573L 0x109A
+#define E1000_DEV_ID_82574L 0x10D3
#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
@@ -110,10 +111,16 @@ struct e1000_hw;
#define E1000_DEV_ID_ICH9_IGP_M_AMT 0x10F5
#define E1000_DEV_ID_ICH9_IGP_M_V 0x10CB
#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD
+#define E1000_DEV_ID_ICH9_BM 0x10E5
#define E1000_DEV_ID_ICH9_IGP_C 0x294C
#define E1000_DEV_ID_ICH9_IFE 0x10C0
#define E1000_DEV_ID_ICH9_IFE_GT 0x10C3
#define E1000_DEV_ID_ICH9_IFE_G 0x10C2
+#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_D_BM_LM 0x10DE
+#define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF
#define E1000_DEV_ID_82575EB_COPPER 0x10A7
#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9
#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6
@@ -146,9 +153,11 @@ typedef enum {
e1000_82571,
e1000_82572,
e1000_82573,
+ e1000_82574,
e1000_80003es2lan,
e1000_ich8lan,
e1000_ich9lan,
+ e1000_ich10lan,
e1000_82575,
e1000_num_macs /* List is 1-based, so subtract 1 for TRUE count. */
} e1000_mac_type;
diff --git a/sys/dev/em/e1000_ich8lan.c b/sys/dev/em/e1000_ich8lan.c
index 149d66b..d8c9e50 100644
--- a/sys/dev/em/e1000_ich8lan.c
+++ b/sys/dev/em/e1000_ich8lan.c
@@ -79,6 +79,8 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw);
static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw);
static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
+static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
+ u32 offset, u8* data);
static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
u8 size, u16* data);
static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
@@ -1020,10 +1022,46 @@ out:
static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
{
s32 ret_val = E1000_SUCCESS;
- if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_SEC1VAL)
- *bank = 1;
- else
- *bank = 0;
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ /* flash bank size is in words */
+ u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
+ u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
+ u8 bank_high_byte = 0;
+
+ if (hw->mac.type != e1000_ich10lan) {
+ if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_SEC1VAL)
+ *bank = 1;
+ else
+ *bank = 0;
+ } else if (hw->dev_spec != NULL) {
+ /*
+ * Make sure the signature for bank 0 is valid,
+ * if not check for bank1
+ */
+ e1000_read_flash_byte_ich8lan(hw, act_offset, &bank_high_byte);
+ if ((bank_high_byte & 0xC0) == 0x80) {
+ *bank = 0;
+ } else {
+ /*
+ * find if segment 1 is valid by verifying
+ * bit 15:14 = 10b in word 0x13
+ */
+ e1000_read_flash_byte_ich8lan(hw,
+ act_offset + bank1_offset,
+ &bank_high_byte);
+
+ /* bank1 has a valid signature equivalent to SEC1V */
+ if ((bank_high_byte & 0xC0) == 0x80) {
+ *bank = 1;
+ } else {
+ DEBUGOUT("ERROR: EEPROM not present\n");
+ ret_val = -E1000_ERR_NVM;
+ }
+ }
+ } else {
+ DEBUGOUT("DEV SPEC is NULL\n");
+ ret_val = -E1000_ERR_NVM;
+ }
return ret_val;
}
@@ -1241,6 +1279,30 @@ out:
}
/**
+ * e1000_read_flash_byte_ich8lan - Read byte from flash
+ * @hw: pointer to the HW structure
+ * @offset: The offset of the byte to read.
+ * @data: Pointer to a byte to store the value read.
+ *
+ * Reads a single byte from the NVM using the flash access registers.
+ **/
+static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
+ u8* data)
+{
+ s32 ret_val = E1000_SUCCESS;
+ u16 word = 0;
+
+ ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
+ if (ret_val)
+ goto out;
+
+ *data = (u8)word;
+
+out:
+ return ret_val;
+}
+
+/**
* e1000_read_flash_data_ich8lan - Read byte or word from NVM
* @hw: pointer to the HW structure
* @offset: The offset (in bytes) of the byte or word to read.
@@ -2483,13 +2545,14 @@ out:
* 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
* to a lower speed.
*
- * Should only be called for ICH9.
+ * Should only be called for ICH9 and ICH10 devices.
**/
void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw)
{
u32 phy_ctrl;
- if (hw->mac.type == e1000_ich9lan) {
+ if ((hw->mac.type == e1000_ich10lan) ||
+ (hw->mac.type == e1000_ich9lan)) {
phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
E1000_PHY_CTRL_GBE_DISABLE;
@@ -2578,13 +2641,22 @@ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
{
s32 ret_val = E1000_SUCCESS;
+ u32 bank = 0;
e1000_get_cfg_done_generic(hw);
/* If EEPROM is not marked present, init the IGP 3 PHY manually */
- if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
- (hw->phy.type == e1000_phy_igp_3)) {
- e1000_phy_init_script_igp3(hw);
+ if (hw->mac.type != e1000_ich10lan) {
+ if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
+ (hw->phy.type == e1000_phy_igp_3)) {
+ e1000_phy_init_script_igp3(hw);
+ }
+ } else {
+ if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
+ /* Maybe we should do a basic Boazman config */
+ DEBUGOUT("EEPROM not present\n");
+ ret_val = -E1000_ERR_CONFIG;
+ }
}
return ret_val;
diff --git a/sys/dev/em/e1000_ich8lan.h b/sys/dev/em/e1000_ich8lan.h
index caa23a0..8de854a 100644
--- a/sys/dev/em/e1000_ich8lan.h
+++ b/sys/dev/em/e1000_ich8lan.h
@@ -112,4 +112,16 @@
E1000_IMS_PHYINT | \
E1000_IMS_EPRST)
+/* Additional interrupt register bit definitions */
+#define E1000_ICR_LSECPNC 0x00004000 /* PN threshold - client */
+#define E1000_IMS_LSECPNC E1000_ICR_LSECPNC /* PN threshold - client */
+#define E1000_ICS_LSECPNC E1000_ICR_LSECPNC /* PN threshold - client */
+
+/* Security Processing bit Indication */
+#define E1000_RXDEXT_LINKSEC_STATUS_LSECH 0x01000000
+#define E1000_RXDEXT_LINKSEC_ERROR_BIT_MASK 0x60000000
+#define E1000_RXDEXT_LINKSEC_ERROR_NO_SA_MATCH 0x20000000
+#define E1000_RXDEXT_LINKSEC_ERROR_REPLAY_ERROR 0x40000000
+#define E1000_RXDEXT_LINKSEC_ERROR_BAD_SIG 0x60000000
+
#endif
diff --git a/sys/dev/em/e1000_osdep.h b/sys/dev/em/e1000_osdep.h
index 8a63950..a4be0cd 100644
--- a/sys/dev/em/e1000_osdep.h
+++ b/sys/dev/em/e1000_osdep.h
@@ -104,8 +104,12 @@ struct e1000_osdep
struct device *dev;
};
+#ifdef NO_82542_SUPPORT
+#define E1000_REGISTER(hw, reg) reg
+#else
#define E1000_REGISTER(hw, reg) (((hw)->mac.type >= e1000_82543) \
? reg : e1000_translate_register_82542(reg))
+#endif
#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, E1000_STATUS)
diff --git a/sys/dev/em/e1000_phy.c b/sys/dev/em/e1000_phy.c
index af0f663..713ba3a 100644
--- a/sys/dev/em/e1000_phy.c
+++ b/sys/dev/em/e1000_phy.c
@@ -614,7 +614,9 @@ s32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
if (ret_val)
goto out;
- if ((phy->type == e1000_phy_m88) && (phy->revision < E1000_REVISION_4)) {
+ if ((phy->type == e1000_phy_m88) &&
+ (phy->revision < E1000_REVISION_4) &&
+ (phy->id != BME1000_E_PHY_ID_R2)) {
/*
* Force TX_CLK in the Extended PHY Specific Control Register
* to 25MHz clock.
@@ -2305,6 +2307,105 @@ out:
}
/**
+ * e1000_read_phy_reg_bm2 - Read BM PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting.
+ **/
+s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ s32 ret_val;
+ u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
+
+ DEBUGFUNC("e1000_write_phy_reg_bm2");
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
+ TRUE);
+ goto out;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ hw->phy.addr = 1;
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+ page);
+
+ if (ret_val) {
+ hw->phy.ops.release(hw);
+ goto out;
+ }
+ }
+
+ ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_bm2 - Write BM PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ s32 ret_val;
+ u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
+
+ DEBUGFUNC("e1000_write_phy_reg_bm2");
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
+ FALSE);
+ goto out;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ hw->phy.addr = 1;
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+ page);
+
+ if (ret_val) {
+ hw->phy.ops.release(hw);
+ goto out;
+ }
+ }
+
+ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
* e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register
* @hw: pointer to the HW structure
* @offset: register offset to be read or written
diff --git a/sys/dev/em/e1000_phy.h b/sys/dev/em/e1000_phy.h
index 16d3d70..4473730 100644
--- a/sys/dev/em/e1000_phy.h
+++ b/sys/dev/em/e1000_phy.h
@@ -92,6 +92,8 @@ s32 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
s32 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data,
bool read);
+s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
void e1000_power_up_phy_copper(struct e1000_hw *hw);
void e1000_power_down_phy_copper(struct e1000_hw *hw);
s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c
index 584b4be..506d2de 100644
--- a/sys/dev/em/if_em.c
+++ b/sys/dev/em/if_em.c
@@ -50,6 +50,10 @@
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/taskqueue.h>
+#ifdef EM_TIMESYNC
+#include <sys/ioccom.h>
+#include <sys/time.h>
+#endif
#include <machine/bus.h>
#include <machine/resource.h>
@@ -76,6 +80,7 @@
#include <dev/pci/pcireg.h>
#include "e1000_api.h"
+#include "e1000_82571.h" /* For Hartwell */
#include "if_em.h"
/*********************************************************************
@@ -86,7 +91,7 @@ int em_display_debug_stats = 0;
/*********************************************************************
* Driver version:
*********************************************************************/
-char em_driver_version[] = "6.8.8";
+char em_driver_version[] = "6.9.0";
/*********************************************************************
@@ -187,6 +192,9 @@ static em_vendor_info_t em_vendor_info_array[] =
{ 0x8086, E1000_DEV_ID_ICH9_IFE, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_ICH9_IFE_GT, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_ICH9_IFE_G, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82574L, 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},
/* required last entry */
{ 0, 0, 0, 0, 0}
};
@@ -284,6 +292,11 @@ static void em_get_hw_control(struct adapter *);
static void em_release_hw_control(struct adapter *);
static void em_enable_wakeup(device_t);
+#ifdef EM_TIMESYNC
+/* Precision Time sync support */
+static int em_tsync_init(struct adapter *);
+static void em_tsync_disable(struct adapter *);
+#endif
#ifdef EM_LEGACY_IRQ
static void em_intr(void *);
@@ -293,9 +306,10 @@ static void em_irq_fast(void *);
#else
static int em_irq_fast(void *);
#endif
-static int em_tx_fast(void *);
-static int em_rx_fast(void *);
-static int em_link_fast(void *);
+/* MSIX handlers */
+static void em_msix_tx(void *);
+static void em_msix_rx(void *);
+static void em_msix_link(void *);
static void em_add_rx_process_limit(struct adapter *, const char *,
const char *, int *, int);
static void em_handle_rxtx(void *context, int pending);
@@ -352,6 +366,10 @@ static int em_rx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_RADV);
static int em_rxd = EM_DEFAULT_RXD;
static int em_txd = EM_DEFAULT_TXD;
static int em_smart_pwr_down = FALSE;
+/* Controls whether promiscuous also shows bad packets */
+static int em_debug_sbp = FALSE;
+/* Local switch for MSI/MSIX */
+static int em_enable_msi = TRUE;
TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt);
TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt);
@@ -360,6 +378,8 @@ TUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt);
TUNABLE_INT("hw.em.rxd", &em_rxd);
TUNABLE_INT("hw.em.txd", &em_txd);
TUNABLE_INT("hw.em.smart_pwr_down", &em_smart_pwr_down);
+TUNABLE_INT("hw.em.sbp", &em_debug_sbp);
+TUNABLE_INT("hw.em.enable_msi", &em_enable_msi);
#ifndef EM_LEGACY_IRQ
/* How many packets rxeof tries to clean at a time */
@@ -445,6 +465,7 @@ em_attach(device_t dev)
adapter->dev = adapter->osdep.dev = dev;
EM_CORE_LOCK_INIT(adapter, device_get_nameunit(dev));
EM_TX_LOCK_INIT(adapter, device_get_nameunit(dev));
+ EM_RX_LOCK_INIT(adapter, device_get_nameunit(dev));
/* SYSCTL stuff */
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
@@ -477,6 +498,7 @@ em_attach(device_t dev)
** identified
*/
if ((adapter->hw.mac.type == e1000_ich8lan) ||
+ (adapter->hw.mac.type == e1000_ich10lan) ||
(adapter->hw.mac.type == e1000_ich9lan)) {
int rid = EM_BAR_TYPE_FLASH;
adapter->flash = bus_alloc_resource_any(dev,
@@ -770,6 +792,7 @@ err_tx_desc:
err_pci:
em_free_pci_resources(adapter);
EM_TX_LOCK_DESTROY(adapter);
+ EM_RX_LOCK_DESTROY(adapter);
EM_CORE_LOCK_DESTROY(adapter);
return (error);
@@ -818,6 +841,7 @@ em_detach(device_t dev)
if (((adapter->hw.mac.type == e1000_82573) ||
(adapter->hw.mac.type == e1000_ich8lan) ||
+ (adapter->hw.mac.type == e1000_ich10lan) ||
(adapter->hw.mac.type == e1000_ich9lan)) &&
e1000_check_mng_mode(&adapter->hw))
em_release_hw_control(adapter);
@@ -856,6 +880,7 @@ em_detach(device_t dev)
}
EM_TX_LOCK_DESTROY(adapter);
+ EM_RX_LOCK_DESTROY(adapter);
EM_CORE_LOCK_DESTROY(adapter);
return (0);
@@ -891,6 +916,7 @@ em_suspend(device_t dev)
if (((adapter->hw.mac.type == e1000_82573) ||
(adapter->hw.mac.type == e1000_ich8lan) ||
+ (adapter->hw.mac.type == e1000_ich10lan) ||
(adapter->hw.mac.type == e1000_ich9lan)) &&
e1000_check_mng_mode(&adapter->hw))
em_release_hw_control(adapter);
@@ -915,12 +941,8 @@ em_resume(device_t dev)
EM_CORE_LOCK(adapter);
em_init_locked(adapter);
em_init_manageability(adapter);
-
- if ((ifp->if_flags & IFF_UP) &&
- (ifp->if_drv_flags & IFF_DRV_RUNNING))
- em_start_locked(ifp);
-
EM_CORE_UNLOCK(adapter);
+ em_start(ifp);
return bus_generic_resume(dev);
}
@@ -1050,6 +1072,8 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
case e1000_82571:
case e1000_82572:
case e1000_ich9lan:
+ case e1000_ich10lan:
+ case e1000_82574:
case e1000_80003es2lan: /* Limit Jumbo Frame size */
max_frame_size = 9234;
break;
@@ -1082,7 +1106,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
if (ifp->if_flags & IFF_UP) {
if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
if ((ifp->if_flags ^ adapter->if_flags) &
- IFF_PROMISC) {
+ (IFF_PROMISC | IFF_ALLMULTI)) {
em_disable_promisc(adapter);
em_set_promisc(adapter);
}
@@ -1180,6 +1204,69 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
break;
}
+#ifdef EM_TIMESYNC
+ /*
+ ** IOCTL support for Precision Time (IEEE 1588) Support
+ */
+ case EM_TIMESYNC_READTS:
+ {
+ u32 rx_ctl, tx_ctl;
+ struct em_tsync_read *tdata;
+
+ tdata = (struct em_tsync_read *) ifr->ifr_data;
+
+ IOCTL_DEBUGOUT("Reading Timestamp\n");
+
+ if (tdata->read_current_time) {
+ getnanotime(&tdata->system_time);
+ tdata->network_time = E1000_READ_REG(&adapter->hw, E1000_SYSTIML);
+ tdata->network_time |=
+ (u64)E1000_READ_REG(&adapter->hw, E1000_SYSTIMH ) << 32;
+ }
+
+ rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL);
+ tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL);
+
+ IOCTL_DEBUGOUT1("RX_CTL value = %u\n", rx_ctl);
+ IOCTL_DEBUGOUT1("TX_CTL value = %u\n", tx_ctl);
+
+ if (rx_ctl & 0x1) {
+ IOCTL_DEBUGOUT("RX timestamp is valid\n");
+ u32 tmp;
+ unsigned char *tmp_cp;
+
+ tdata->rx_valid = 1;
+ tdata->rx_stamp = E1000_READ_REG(&adapter->hw, E1000_RXSTMPL);
+ tdata->rx_stamp |= (u64)E1000_READ_REG(&adapter->hw,
+ E1000_RXSTMPH) << 32;
+
+ tmp = E1000_READ_REG(&adapter->hw, E1000_RXSATRL);
+ tmp_cp = (unsigned char *) &tmp;
+ tdata->srcid[0] = tmp_cp[0];
+ tdata->srcid[1] = tmp_cp[1];
+ tdata->srcid[2] = tmp_cp[2];
+ tdata->srcid[3] = tmp_cp[3];
+ tmp = E1000_READ_REG(&adapter->hw, E1000_RXSATRH);
+ tmp_cp = (unsigned char *) &tmp;
+ tdata->srcid[4] = tmp_cp[0];
+ tdata->srcid[5] = tmp_cp[1];
+ tdata->seqid = tmp >> 16;
+ tdata->seqid = htons(tdata->seqid);
+ } else
+ tdata->rx_valid = 0;
+
+ if (tx_ctl & 0x1) {
+ IOCTL_DEBUGOUT("TX timestamp is valid\n");
+ tdata->tx_valid = 1;
+ tdata->tx_stamp = E1000_READ_REG(&adapter->hw, E1000_TXSTMPL);
+ tdata->tx_stamp |= (u64) E1000_READ_REG(&adapter->hw,
+ E1000_TXSTMPH) << 32;
+ } else
+ tdata->tx_valid = 0;
+
+ return (0);
+ }
+#endif /* EM_TIMESYNC */
default:
error = ether_ioctl(ifp, command, data);
@@ -1294,7 +1381,11 @@ em_init_locked(struct adapter *adapter)
case e1000_82573: /* 82573: Total Packet Buffer is 32K */
pba = E1000_PBA_12K; /* 12K for Rx, 20K for Tx */
break;
+ case e1000_82574:
+ pba = E1000_PBA_20K; /* 20K for Rx, 20K for Tx */
+ break;
case e1000_ich9lan:
+ case e1000_ich10lan:
#define E1000_PBA_10K 0x000A
pba = E1000_PBA_10K;
break;
@@ -1383,6 +1474,21 @@ em_init_locked(struct adapter *adapter)
callout_reset(&adapter->timer, hz, em_local_timer, adapter);
e1000_clear_hw_cntrs_base_generic(&adapter->hw);
+ /* MSI/X configuration for 82574 */
+ if (adapter->hw.mac.type == e1000_82574) {
+ int tmp;
+ tmp = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
+ tmp |= E1000_CTRL_EXT_PBA_CLR;
+ E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, tmp);
+ /*
+ ** Set the IVAR - interrupt vector routing.
+ ** Each nibble represents a vector, high bit
+ ** is enable, other 3 bits are the MSIX table
+ ** entry, we map RXQ0 to 0, TXQ0 to 1, and
+ ** Link (other) to 2, hence the magic number.
+ */
+ E1000_WRITE_REG(&adapter->hw, E1000_IVAR, 0x800A0908);
+ }
#ifdef DEVICE_POLLING
/*
@@ -1395,6 +1501,12 @@ em_init_locked(struct adapter *adapter)
#endif /* DEVICE_POLLING */
em_enable_intr(adapter);
+#ifdef EM_TIMESYNC
+ /* Initializae IEEE 1588 Precision Time hardware */
+ if ((adapter->hw.mac.type == e1000_82574) ||
+ (adapter->hw.mac.type == e1000_ich10lan))
+ em_tsync_init(adapter);
+#endif
/* Don't reset the phy next time init gets called */
adapter->hw.phy.reset_disable = TRUE;
@@ -1439,9 +1551,10 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
em_local_timer, adapter);
}
}
- em_rxeof(adapter, count);
EM_CORE_UNLOCK(adapter);
+ em_rxeof(adapter, count);
+
EM_TX_LOCK(adapter);
em_txeof(adapter);
@@ -1462,17 +1575,14 @@ static void
em_intr(void *arg)
{
struct adapter *adapter = arg;
- struct ifnet *ifp;
+ struct ifnet *ifp = adapter->ifp;
u32 reg_icr;
- EM_CORE_LOCK(adapter);
- ifp = adapter->ifp;
- if (ifp->if_capenable & IFCAP_POLLING) {
- EM_CORE_UNLOCK(adapter);
+ if (ifp->if_capenable & IFCAP_POLLING)
return;
- }
+ EM_CORE_LOCK(adapter);
for (;;) {
reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR);
@@ -1491,12 +1601,14 @@ em_intr(void *arg)
if (reg_icr == 0xffffffff)
break;
+ EM_CORE_UNLOCK(adapter);
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
em_rxeof(adapter, -1);
EM_TX_LOCK(adapter);
em_txeof(adapter);
EM_TX_UNLOCK(adapter);
}
+ EM_CORE_LOCK(adapter);
/* Link status change */
if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
@@ -1525,9 +1637,7 @@ static void
em_handle_link(void *context, int pending)
{
struct adapter *adapter = context;
- struct ifnet *ifp;
-
- ifp = adapter->ifp;
+ struct ifnet *ifp = adapter->ifp;
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
return;
@@ -1564,19 +1674,16 @@ em_handle_rxtx(void *context, int pending)
em_enable_intr(adapter);
}
-/* RX deferred handler: used with MSIX */
static void
em_handle_rx(void *context, int pending)
{
struct adapter *adapter = context;
struct ifnet *ifp = adapter->ifp;
- ++adapter->rx_irq;
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
(em_rxeof(adapter, adapter->rx_process_limit) != 0))
taskqueue_enqueue(adapter->tq, &adapter->rx_task);
- em_enable_intr(adapter);
}
static void
@@ -1585,17 +1692,13 @@ em_handle_tx(void *context, int pending)
struct adapter *adapter = context;
struct ifnet *ifp = adapter->ifp;
- ++adapter->tx_irq;
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
EM_TX_LOCK(adapter);
em_txeof(adapter);
-
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
em_start_locked(ifp);
EM_TX_UNLOCK(adapter);
}
-
- em_enable_intr(adapter);
}
/*********************************************************************
@@ -1657,52 +1760,50 @@ em_irq_fast(void *arg)
/*********************************************************************
*
- * MSIX TX Fast Interrupt Service routine
+ * MSIX Interrupt Service Routines
*
**********************************************************************/
+#define EM_MSIX_TX 0x00040000
+#define EM_MSIX_RX 0x00010000
+#define EM_MSIX_LINK 0x00100000
-static int
-em_tx_fast(void *arg)
+static void
+em_msix_tx(void *arg)
{
struct adapter *adapter = arg;
- u32 reg_icr;
-
- reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR);
- /*
- * Mask interrupts until the taskqueue is finished running. This is
- * cheap, just assume that it is needed. This also works around the
- * MSI message reordering errata on certain systems.
- */
- em_disable_intr(adapter);
- taskqueue_enqueue(adapter->tq, &adapter->tx_task);
+ struct ifnet *ifp = adapter->ifp;
- return FILTER_HANDLED;
+ ++adapter->tx_irq;
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ EM_TX_LOCK(adapter);
+ em_txeof(adapter);
+ EM_TX_UNLOCK(adapter);
+ taskqueue_enqueue(adapter->tq, &adapter->tx_task);
+ }
+ /* Reenable this interrupt */
+ E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_TX);
+ return;
}
/*********************************************************************
*
- * MSIX RX Fast Interrupt Service routine
+ * MSIX RX Interrupt Service routine
*
**********************************************************************/
-static int
-em_rx_fast(void *arg)
+static void
+em_msix_rx(void *arg)
{
struct adapter *adapter = arg;
- u32 reg_icr;
-
- reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR);
- /*
- * Mask interrupts until the taskqueue is finished running. This is
- * cheap, just assume that it is needed. This also works around the
- * MSI message reordering errata on certain systems.
- */
- em_disable_intr(adapter);
- taskqueue_enqueue(adapter->tq, &adapter->rx_task);
- if (reg_icr & E1000_ICR_RXO)
- adapter->rx_overruns++;
+ struct ifnet *ifp = adapter->ifp;
- return FILTER_HANDLED;
+ ++adapter->rx_irq;
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
+ (em_rxeof(adapter, adapter->rx_process_limit) != 0))
+ taskqueue_enqueue(adapter->tq, &adapter->rx_task);
+ /* Reenable this interrupt */
+ E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_RX);
+ return;
}
/*********************************************************************
@@ -1711,19 +1812,22 @@ em_rx_fast(void *arg)
*
**********************************************************************/
-static int
-em_link_fast(void *arg)
+static void
+em_msix_link(void *arg)
{
struct adapter *adapter = arg;
- u32 reg_eicr;
+ u32 reg_icr;
- reg_eicr = E1000_READ_REG(&adapter->hw, E1000_ICR);
+ ++adapter->link_irq;
+ reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR);
- if (reg_eicr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))
+ if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+ adapter->hw.mac.get_link_status = 1;
taskqueue_enqueue(taskqueue_fast, &adapter->link_task);
-
- E1000_WRITE_REG(&adapter->hw, E1000_IMS, E1000_IMS_LSC);
- return FILTER_HANDLED;
+ }
+ E1000_WRITE_REG(&adapter->hw, E1000_IMS,
+ EM_MSIX_LINK | E1000_IMS_LSC);
+ return;
}
#endif /* EM_FAST_IRQ */
@@ -1988,12 +2092,14 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp)
tso_desc = TRUE;
} else
#endif
+#ifndef EM_TIMESYNC
/*
** Timesync needs to check the packet header
** so call checksum code to do so, but don't
** penalize the code if not defined.
*/
if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD)
+#endif
em_transmit_checksum_setup(adapter, m_head,
&txd_upper, &txd_lower);
@@ -2150,6 +2256,11 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp)
m_head->m_pkthdr.len);
}
+#ifdef EM_TIMESYNC
+ if (ctxd->upper.data & E1000_TXD_EXTCMD_TSTAMP) {
+ HW_DEBUGOUT( "@@@ Timestamp bit is set in transmit descriptor\n" );
+ }
+#endif
return (0);
}
@@ -2280,6 +2391,9 @@ em_set_promisc(struct adapter *adapter)
if (ifp->if_flags & IFF_PROMISC) {
reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+ /* Turn this on if you want to see bad packets */
+ if (em_debug_sbp)
+ reg_rctl |= E1000_RCTL_SBP;
E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
} else if (ifp->if_flags & IFF_ALLMULTI) {
reg_rctl |= E1000_RCTL_MPE;
@@ -2297,6 +2411,7 @@ em_disable_promisc(struct adapter *adapter)
reg_rctl &= (~E1000_RCTL_UPE);
reg_rctl &= (~E1000_RCTL_MPE);
+ reg_rctl &= (~E1000_RCTL_SBP);
E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
}
@@ -2493,6 +2608,12 @@ em_stop(void *arg)
/* Tell the stack that the interface is no longer active */
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+#ifdef EM_TIMESYNC
+ /* Disable IEEE 1588 Time hardware */
+ if ((adapter->hw.mac.type == e1000_82574) ||
+ (adapter->hw.mac.type == e1000_ich10lan))
+ em_tsync_disable(adapter);
+#endif
e1000_reset_hw(&adapter->hw);
if (adapter->hw.mac.type >= e1000_82544)
@@ -2603,7 +2724,8 @@ em_allocate_pci_resources(struct adapter *adapter)
/*
* Setup MSI/X or MSI if PCI Express
*/
- adapter->msi = em_setup_msix(adapter);
+ if (em_enable_msi)
+ adapter->msi = em_setup_msix(adapter);
adapter->hw.back = &adapter->osdep;
@@ -2725,7 +2847,7 @@ em_allocate_msix(struct adapter *adapter)
/* First slot to RX */
if ((error = bus_setup_intr(dev, adapter->res[0],
- INTR_TYPE_NET, em_rx_fast, NULL, adapter,
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, em_msix_rx, adapter,
&adapter->tag[0])) != 0) {
device_printf(dev, "Failed to register RX handler");
return (error);
@@ -2733,7 +2855,7 @@ em_allocate_msix(struct adapter *adapter)
/* Next TX */
if ((error = bus_setup_intr(dev, adapter->res[1],
- INTR_TYPE_NET, em_tx_fast, NULL, adapter,
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, em_msix_tx, adapter,
&adapter->tag[1])) != 0) {
device_printf(dev, "Failed to register TX handler");
return (error);
@@ -2741,7 +2863,7 @@ em_allocate_msix(struct adapter *adapter)
/* And Link */
if ((error = bus_setup_intr(dev, adapter->res[2],
- INTR_TYPE_NET, em_link_fast, NULL, adapter,
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, em_msix_link, adapter,
&adapter->tag[2])) != 0) {
device_printf(dev, "Failed to register TX handler");
return (error);
@@ -2809,6 +2931,30 @@ em_setup_msix(struct adapter *adapter)
if (adapter->hw.mac.type < e1000_82571)
return (0);
+ /* Setup MSI/X for Hartwell */
+ if (adapter->hw.mac.type == e1000_82574) {
+ /* Map the MSIX BAR */
+ int rid = PCIR_BAR(EM_MSIX_BAR);
+ adapter->msix = bus_alloc_resource_any(dev,
+ SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (!adapter->msix) {
+ /* May not be enabled */
+ device_printf(adapter->dev,
+ "Unable to map MSIX table \n");
+ goto msi;
+ }
+ val = pci_msix_count(dev);
+ /*
+ ** 82574 can be configured for 5 but
+ ** we limit use to 3.
+ */
+ if (val > 3) val = 3;
+ if ((val) && pci_alloc_msix(dev, &val) == 0) {
+ device_printf(adapter->dev,"Using MSIX interrupts\n");
+ return (val);
+ }
+ }
+msi:
val = pci_msi_count(dev);
if (val == 1 && pci_alloc_msi(dev, &val) == 0) {
adapter->msi = 1;
@@ -2838,6 +2984,7 @@ em_hardware_init(struct adapter *adapter)
/* Get control from any management/hw control */
if (((adapter->hw.mac.type == e1000_82573) ||
(adapter->hw.mac.type == e1000_ich8lan) ||
+ (adapter->hw.mac.type == e1000_ich10lan) ||
(adapter->hw.mac.type == e1000_ich9lan)) &&
e1000_check_mng_mode(&adapter->hw))
em_get_hw_control(adapter);
@@ -3463,6 +3610,11 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp,
ipproto = ip6->ip6_nxt;
break;
+#ifdef EM_TIMESYNC
+ case ETHERTYPE_IEEE1588:
+ *txd_upper |= E1000_TXD_EXTCMD_TSTAMP;
+ break;
+#endif
default:
*txd_upper = 0;
*txd_lower = 0;
@@ -3488,6 +3640,15 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp,
break;
case IPPROTO_UDP:
{
+#ifdef EM_TIMESYNC
+ void *hdr = (caddr_t) ip + ip_hlen;
+ struct udphdr *uh = (struct udphdr *)hdr;
+
+ if (uh->uh_dport == htons(TSYNC_PORT)) {
+ *txd_upper |= E1000_TXD_EXTCMD_TSTAMP;
+ IOCTL_DEBUGOUT("@@@ Sending Event Packet\n");
+ }
+#endif
if (mp->m_pkthdr.csum_flags & CSUM_UDP) {
/*
* Start offset for header checksum calculation.
@@ -3506,6 +3667,15 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp,
break;
}
+#ifdef EM_TIMESYNC
+ /*
+ ** We might be here just for TIMESYNC
+ ** which means we don't need the context
+ ** descriptor.
+ */
+ if (!mp->m_pkthdr.csum_flags & CSUM_OFFLOAD)
+ return;
+#endif
*txd_lower = E1000_TXD_CMD_DEXT | /* Extended descr type */
E1000_TXD_DTYP_D; /* Data descr */
TXD->tcp_seg_setup.data = htole32(0);
@@ -3968,6 +4138,9 @@ em_setup_receive_structures(struct adapter *adapter)
* Enable receive unit.
*
**********************************************************************/
+#define MAX_INTS_PER_SEC 8000
+#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256)
+
static void
em_initialize_receive_unit(struct adapter *adapter)
{
@@ -3984,18 +4157,30 @@ em_initialize_receive_unit(struct adapter *adapter)
rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);
- if(adapter->hw.mac.type >= e1000_82540) {
+ if (adapter->hw.mac.type >= e1000_82540) {
E1000_WRITE_REG(&adapter->hw, E1000_RADV,
adapter->rx_abs_int_delay.value);
/*
* Set the interrupt throttling rate. Value is calculated
* as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns)
*/
-#define MAX_INTS_PER_SEC 8000
-#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256)
E1000_WRITE_REG(&adapter->hw, E1000_ITR, DEFAULT_ITR);
}
+ /*
+ ** When using MSIX interrupts we need to throttle
+ ** using the EITR register (82574 only)
+ */
+ if (adapter->msix)
+ for (int i = 0; i < 4; i++)
+ E1000_WRITE_REG(&adapter->hw,
+ E1000_EITR_82574(i), DEFAULT_ITR);
+
+ /* Disable accelerated ackknowledge */
+ if (adapter->hw.mac.type == e1000_82574)
+ E1000_WRITE_REG(&adapter->hw,
+ E1000_RFCTL, E1000_RFCTL_ACK_DIS);
+
/* Setup the Base and Length of the Rx Descriptor Ring */
bus_addr = adapter->rxdma.dma_paddr;
E1000_WRITE_REG(&adapter->hw, E1000_RDLEN(0),
@@ -4138,21 +4323,23 @@ em_free_receive_structures(struct adapter *adapter)
static int
em_rxeof(struct adapter *adapter, int count)
{
- struct ifnet *ifp;
+ struct ifnet *ifp = adapter->ifp;;
struct mbuf *mp;
u8 status, accept_frame = 0, eop = 0;
u16 len, desc_len, prev_len_adj;
int i;
struct e1000_rx_desc *current_desc;
- ifp = adapter->ifp;
+ EM_RX_LOCK(adapter);
i = adapter->next_rx_desc_to_check;
current_desc = &adapter->rx_desc_base[i];
bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
BUS_DMASYNC_POSTREAD);
- if (!((current_desc->status) & E1000_RXD_STAT_DD))
+ if (!((current_desc->status) & E1000_RXD_STAT_DD)) {
+ EM_RX_UNLOCK(adapter);
return (0);
+ }
while ((current_desc->status & E1000_RXD_STAT_DD) &&
(count != 0) &&
@@ -4295,14 +4482,10 @@ discard:
i = 0;
if (m != NULL) {
adapter->next_rx_desc_to_check = i;
-#ifdef EM_LEGACY_IRQ
- EM_CORE_UNLOCK(adapter);
+ /* Unlock for call into stack */
+ EM_RX_UNLOCK(adapter);
(*ifp->if_input)(ifp, m);
- EM_CORE_LOCK(adapter);
-#else
- /* Already running unlocked */
- (*ifp->if_input)(ifp, m);
-#endif
+ EM_RX_LOCK(adapter);
i = adapter->next_rx_desc_to_check;
}
current_desc = &adapter->rx_desc_base[i];
@@ -4313,6 +4496,7 @@ discard:
if (--i < 0)
i = adapter->num_rx_desc - 1;
E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), i);
+ EM_RX_UNLOCK(adapter);
if (!((current_desc->status) & E1000_RXD_STAT_DD))
return (0);
@@ -4422,28 +4606,26 @@ em_enable_hw_vlans(struct adapter *adapter)
E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
}
-#define QUEUE_MASK 0x01500000
-
static void
em_enable_intr(struct adapter *adapter)
{
+ struct e1000_hw *hw = &adapter->hw;
u32 ims_mask = IMS_ENABLE_MASK;
if (adapter->msix) {
- E1000_WRITE_REG(&adapter->hw, E1000_EIMS, QUEUE_MASK);
- E1000_WRITE_REG(&adapter->hw, E1000_EIAC, QUEUE_MASK);
- ims_mask |= QUEUE_MASK;
+ E1000_WRITE_REG(hw, EM_EIAC, EM_MSIX_MASK);
+ ims_mask |= EM_MSIX_MASK;
}
- E1000_WRITE_REG(&adapter->hw, E1000_IMS, ims_mask);
+ E1000_WRITE_REG(hw, E1000_IMS, ims_mask);
}
static void
em_disable_intr(struct adapter *adapter)
{
- if (adapter->msix) {
- E1000_WRITE_REG(&adapter->hw, E1000_EIMC, ~0);
- E1000_WRITE_REG(&adapter->hw, E1000_EIAC, 0);
- }
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (adapter->msix)
+ E1000_WRITE_REG(hw, EM_EIAC, 0);
E1000_WRITE_REG(&adapter->hw, E1000_IMC, 0xffffffff);
}
@@ -4522,6 +4704,7 @@ em_get_hw_control(struct adapter *adapter)
case e1000_80003es2lan:
case e1000_ich8lan:
case e1000_ich9lan:
+ case e1000_ich10lan:
ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT,
ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
@@ -4555,6 +4738,7 @@ em_release_hw_control(struct adapter *adapter)
case e1000_80003es2lan:
case e1000_ich8lan:
case e1000_ich9lan:
+ case e1000_ich10lan:
ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT,
ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
@@ -4841,8 +5025,9 @@ em_print_hw_stats(struct adapter *adapter)
device_printf(dev, "RX overruns = %ld\n", adapter->rx_overruns);
device_printf(dev, "watchdog timeouts = %ld\n",
adapter->watchdog_events);
- device_printf(dev, "TX Interrupts = %ld ", adapter->tx_irq);
- device_printf(dev, "RX Interrupts = %ld\n", adapter->rx_irq);
+ device_printf(dev, "RX MSIX IRQ = %ld TX MSIX IRQ = %ld"
+ " LINK MSIX IRQ = %ld\n", adapter->rx_irq,
+ adapter->tx_irq , adapter->link_irq);
device_printf(dev, "XON Rcvd = %lld\n",
(long long)adapter->stats.xonrxc);
device_printf(dev, "XON Xmtd = %lld\n",
@@ -5009,3 +5194,100 @@ em_add_rx_process_limit(struct adapter *adapter, const char *name,
}
#endif
+#ifdef EM_TIMESYNC
+/*
+ * Initialize the Time Sync Feature
+ */
+static int
+em_tsync_init(struct adapter *adapter)
+{
+ device_t dev = adapter->dev;
+ u32 tx_ctl, rx_ctl;
+
+
+ E1000_WRITE_REG(&adapter->hw, E1000_TIMINCA, (1<<24) |
+ 20833/PICOSECS_PER_TICK);
+
+ adapter->last_stamp = E1000_READ_REG(&adapter->hw, E1000_SYSTIML);
+ adapter->last_stamp |= (u64)E1000_READ_REG(&adapter->hw,
+ E1000_SYSTIMH) << 32ULL;
+
+ /* Enable the TX side */
+ tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL);
+ tx_ctl |= 0x10;
+ E1000_WRITE_REG(&adapter->hw, E1000_TSYNCTXCTL, tx_ctl);
+ E1000_WRITE_FLUSH(&adapter->hw);
+
+ tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL);
+ if ((tx_ctl & 0x10) == 0) {
+ device_printf(dev, "Failed to enable TX timestamping\n");
+ return (ENXIO);
+ }
+
+ /* Enable RX */
+ rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL);
+ rx_ctl |= 0x10; /* Enable the feature */
+ rx_ctl |= 0x0a; /* This value turns on Ver 1 and 2 */
+ E1000_WRITE_REG(&adapter->hw, E1000_TSYNCRXCTL, rx_ctl);
+
+ /*
+ * Ethertype Stamping (Ethertype = 0x88F7)
+ */
+ E1000_WRITE_REG(&adapter->hw, E1000_RXMTRL, htonl(0x440088f7));
+
+ /*
+ * Source Port Queue Filter Setup:
+ * this is for UDP port filtering
+ */
+ E1000_WRITE_REG(&adapter->hw, E1000_RXUDP, htons(TSYNC_PORT));
+ /* Protocol = UDP, enable Timestamp, and filter on source/protocol */
+
+ E1000_WRITE_FLUSH(&adapter->hw);
+
+ rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL);
+ if ((rx_ctl & 0x10) == 0) {
+ device_printf(dev, "Failed to enable RX timestamping\n");
+ return (ENXIO);
+ }
+
+ device_printf(dev, "IEEE 1588 Precision Time Protocol enabled\n");
+
+ return (0);
+}
+
+/*
+ * Disable the Time Sync Feature
+ */
+static void
+em_tsync_disable(struct adapter *adapter)
+{
+ u32 tx_ctl, rx_ctl;
+
+ tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL);
+ tx_ctl &= ~0x10;
+ E1000_WRITE_REG(&adapter->hw, E1000_TSYNCTXCTL, tx_ctl);
+ E1000_WRITE_FLUSH(&adapter->hw);
+
+ /* Invalidate TX Timestamp */
+ E1000_READ_REG(&adapter->hw, E1000_TXSTMPH);
+
+ tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL);
+ if (tx_ctl & 0x10)
+ HW_DEBUGOUT("Failed to disable TX timestamping\n");
+
+ rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL);
+ rx_ctl &= ~0x10;
+
+ E1000_WRITE_REG(&adapter->hw, E1000_TSYNCRXCTL, rx_ctl);
+ E1000_WRITE_FLUSH(&adapter->hw);
+
+ /* Invalidate RX Timestamp */
+ E1000_READ_REG(&adapter->hw, E1000_RXSATRH);
+
+ rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL);
+ if (rx_ctl & 0x10)
+ HW_DEBUGOUT("Failed to disable RX timestamping\n");
+
+ return;
+}
+#endif /* EM_TIMESYNC */
diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h
index 9a3b0b4..8fa2a43 100644
--- a/sys/dev/em/if_em.h
+++ b/sys/dev/em/if_em.h
@@ -1,36 +1,37 @@
-/**************************************************************************
+/******************************************************************************
+
+ Copyright (c) 2001-2008, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+/*$FreeBSD$*/
-Copyright (c) 2001-2008, Intel Corporation
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- 3. Neither the name of the Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-***************************************************************************/
-/* $FreeBSD$ */
#ifndef _EM_H_DEFINED_
#define _EM_H_DEFINED_
@@ -232,10 +233,19 @@ POSSIBILITY OF SUCH DAMAGE.
#define EM_MAX_SCATTER 64
#define EM_TSO_SIZE (65535 + sizeof(struct ether_vlan_header))
#define EM_TSO_SEG_SIZE 4096 /* Max dma segment size */
+#define EM_MSIX_MASK 0x01F00000 /* For 82574 use */
#define ETH_ZLEN 60
#define ETH_ADDR_LEN 6
#define CSUM_OFFLOAD 7 /* Offload bits in mbuf flag */
+/*
+ * 82574 has a nonstandard address for EIAC
+ * and since its only used in MSIX, and in
+ * the em driver only 82574 uses MSIX we can
+ * solve it just using this define.
+ */
+#define EM_EIAC 0x000DC
+
/* Used in for 82547 10Mb Half workaround */
#define EM_PBA_BYTES_SHIFT 0xA
#define EM_TX_HEAD_ADDR_SHIFT 7
@@ -243,6 +253,29 @@ POSSIBILITY OF SUCH DAMAGE.
#define EM_FIFO_HDR 0x10
#define EM_82547_PKT_THRESH 0x3e0
+#ifdef EM_TIMESYNC
+/* Precision Time Sync (IEEE 1588) defines */
+#define ETHERTYPE_IEEE1588 0x88F7
+#define PICOSECS_PER_TICK 20833
+#define TSYNC_PORT 319 /* UDP port for the protocol */
+
+/* TIMESYNC IOCTL defines */
+#define EM_TIMESYNC_READTS _IOWR('i', 127, struct em_tsync_read)
+
+/* Used in the READTS IOCTL */
+struct em_tsync_read {
+ int read_current_time;
+ struct timespec system_time;
+ u64 network_time;
+ u64 rx_stamp;
+ u64 tx_stamp;
+ u16 seqid;
+ unsigned char srcid[6];
+ int rx_valid;
+ int tx_valid;
+};
+
+#endif /* EM_TIMESYNC */
struct adapter;
@@ -296,6 +329,7 @@ struct adapter {
int min_frame_size;
struct mtx core_mtx;
struct mtx tx_mtx;
+ struct mtx rx_mtx;
int em_insert_vlan_header;
/* Task for FAST handling */
@@ -376,6 +410,7 @@ struct adapter {
unsigned long rx_overruns;
unsigned long rx_irq;
unsigned long tx_irq;
+ unsigned long link_irq;
/* 82547 workaround */
uint32_t tx_fifo_size;
@@ -389,6 +424,11 @@ struct adapter {
boolean_t pcix_82544;
boolean_t in_detach;
+#ifdef EM_TIMESYNC
+ u64 last_stamp;
+ u64 last_sec;
+ u32 last_ns;
+#endif
struct e1000_hw_stats stats;
};
@@ -432,12 +472,17 @@ typedef struct _DESCRIPTOR_PAIR
mtx_init(&(_sc)->core_mtx, _name, "EM Core Lock", MTX_DEF)
#define EM_TX_LOCK_INIT(_sc, _name) \
mtx_init(&(_sc)->tx_mtx, _name, "EM TX Lock", MTX_DEF)
+#define EM_RX_LOCK_INIT(_sc, _name) \
+ mtx_init(&(_sc)->rx_mtx, _name, "EM RX Lock", MTX_DEF)
#define EM_CORE_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->core_mtx)
#define EM_TX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->tx_mtx)
+#define EM_RX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rx_mtx)
#define EM_CORE_LOCK(_sc) mtx_lock(&(_sc)->core_mtx)
#define EM_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_mtx)
+#define EM_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_mtx)
#define EM_CORE_UNLOCK(_sc) mtx_unlock(&(_sc)->core_mtx)
#define EM_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->tx_mtx)
+#define EM_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->rx_mtx)
#define EM_CORE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->core_mtx, MA_OWNED)
#define EM_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_mtx, MA_OWNED)
diff --git a/sys/dev/igb/e1000_82575.c b/sys/dev/igb/e1000_82575.c
index eb99282..9b6a28b 100644
--- a/sys/dev/igb/e1000_82575.c
+++ b/sys/dev/igb/e1000_82575.c
@@ -37,7 +37,6 @@
*/
#include "e1000_api.h"
-#include "e1000_82575.h"
static s32 e1000_init_phy_params_82575(struct e1000_hw *hw);
static s32 e1000_init_nvm_params_82575(struct e1000_hw *hw);
@@ -554,7 +553,7 @@ static s32 e1000_phy_hw_reset_sgmii_82575(struct e1000_hw *hw)
DEBUGFUNC("e1000_phy_hw_reset_sgmii_82575");
/*
- * This isn't a true "hard" reset, but is the only reset
+ * This isn't a TRUE "hard" reset, but is the only reset
* available to us at this time.
*/
@@ -1303,25 +1302,25 @@ static s32 e1000_reset_init_script_82575(struct e1000_hw* hw)
if (hw->mac.type == e1000_82575) {
DEBUGOUT("Running reset init script for 82575\n");
/* SerDes configuration via SERDESCTRL */
- e1000_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x00, 0x0C);
- e1000_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x01, 0x78);
- e1000_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x1B, 0x23);
- e1000_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x23, 0x15);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x00, 0x0C);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x01, 0x78);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x1B, 0x23);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x23, 0x15);
/* CCM configuration via CCMCTL register */
- e1000_write_8bit_ctrl_reg(hw, E1000_CCMCTL, 0x14, 0x00);
- e1000_write_8bit_ctrl_reg(hw, E1000_CCMCTL, 0x10, 0x00);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x14, 0x00);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x10, 0x00);
/* PCIe lanes configuration */
- e1000_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x00, 0xEC);
- e1000_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x61, 0xDF);
- e1000_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x34, 0x05);
- e1000_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x2F, 0x81);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x00, 0xEC);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x61, 0xDF);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x34, 0x05);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x2F, 0x81);
/* PCIe PLL Configuration */
- e1000_write_8bit_ctrl_reg(hw, E1000_SCCTL, 0x02, 0x47);
- e1000_write_8bit_ctrl_reg(hw, E1000_SCCTL, 0x14, 0x00);
- e1000_write_8bit_ctrl_reg(hw, E1000_SCCTL, 0x10, 0x00);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x02, 0x47);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x14, 0x00);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x10, 0x00);
}
return E1000_SUCCESS;
diff --git a/sys/dev/igb/e1000_api.c b/sys/dev/igb/e1000_api.c
index 2438b3f..b8298f8 100644
--- a/sys/dev/igb/e1000_api.c
+++ b/sys/dev/igb/e1000_api.c
@@ -33,9 +33,6 @@
/*$FreeBSD$*/
#include "e1000_api.h"
-#include "e1000_mac.h"
-#include "e1000_nvm.h"
-#include "e1000_phy.h"
/**
* e1000_init_mac_params - Initialize MAC function pointers
@@ -260,7 +257,7 @@ s32 e1000_get_bus_info(struct e1000_hw *hw)
void e1000_clear_vfta(struct e1000_hw *hw)
{
if (hw->mac.ops.clear_vfta)
- hw->mac.ops.clear_vfta (hw);
+ hw->mac.ops.clear_vfta(hw);
}
/**
@@ -871,7 +868,7 @@ s32 e1000_phy_commit(struct e1000_hw *hw)
* Success returns 0, Failure returns 1
*
* The low power link up (lplu) state is set to the power management level D0
- * and SmartSpeed is disabled when active is true, else clear lplu for D0
+ * and SmartSpeed is disabled when active is TRUE, else clear lplu for D0
* and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
* is used during Dx states where the power conservation is most important.
* During driver activity, SmartSpeed should be enabled so performance is
@@ -893,7 +890,7 @@ s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
* Success returns 0, Failure returns 1
*
* The low power link up (lplu) state is set to the power management level D3
- * and SmartSpeed is disabled when active is true, else clear lplu for D3
+ * and SmartSpeed is disabled when active is TRUE, else clear lplu for D3
* and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
* is used during Dx states where the power conservation is most important.
* During driver activity, SmartSpeed should be enabled so performance is
diff --git a/sys/dev/igb/e1000_api.h b/sys/dev/igb/e1000_api.h
index 93e49f0..728588a 100644
--- a/sys/dev/igb/e1000_api.h
+++ b/sys/dev/igb/e1000_api.h
@@ -98,7 +98,6 @@ s32 e1000_wait_autoneg(struct e1000_hw *hw);
s32 e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active);
s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active);
bool e1000_check_mng_mode(struct e1000_hw *hw);
-bool e1000_enable_mng_pass_thru(struct e1000_hw *hw);
bool e1000_enable_tx_pkt_filtering(struct e1000_hw *hw);
s32 e1000_mng_enable_host_if(struct e1000_hw *hw);
s32 e1000_mng_host_if_write(struct e1000_hw *hw,
@@ -108,7 +107,6 @@ s32 e1000_mng_write_cmd_header(struct e1000_hw *hw,
s32 e1000_mng_write_dhcp_info(struct e1000_hw * hw,
u8 *buffer, u16 length);
-
/*
* TBI_ACCEPT macro definition:
*
diff --git a/sys/dev/igb/e1000_defines.h b/sys/dev/igb/e1000_defines.h
index 7fd6923..6f23fc3 100644
--- a/sys/dev/igb/e1000_defines.h
+++ b/sys/dev/igb/e1000_defines.h
@@ -384,6 +384,7 @@
#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA
#define E1000_CONNSW_ENRGSRC 0x4
+#define E1000_PCS_CFG_PCS_EN 8
#define E1000_PCS_LCTL_FLV_LINK_UP 1
#define E1000_PCS_LCTL_FSV_10 0
#define E1000_PCS_LCTL_FSV_100 2
diff --git a/sys/dev/igb/e1000_hw.h b/sys/dev/igb/e1000_hw.h
index f3b339b..9b46b37 100644
--- a/sys/dev/igb/e1000_hw.h
+++ b/sys/dev/igb/e1000_hw.h
@@ -57,7 +57,7 @@ struct e1000_hw;
typedef enum {
e1000_undefined = 0,
e1000_82575,
- e1000_num_macs /* List is 1-based, so subtract 1 for true count. */
+ e1000_num_macs /* List is 1-based, so subtract 1 for TRUE count. */
} e1000_mac_type;
typedef enum {
@@ -615,9 +615,9 @@ struct e1000_hw {
u8 revision_id;
};
+#include "e1000_82575.h"
+
/* These functions must be implemented by drivers */
-void e1000_pci_clear_mwi(struct e1000_hw *hw);
-void e1000_pci_set_mwi(struct e1000_hw *hw);
s32 e1000_alloc_zeroed_dev_spec_struct(struct e1000_hw *hw, u32 size);
s32 e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
void e1000_free_dev_spec_struct(struct e1000_hw *hw);
diff --git a/sys/dev/igb/e1000_mac.c b/sys/dev/igb/e1000_mac.c
index fa50d81..df56ddc 100644
--- a/sys/dev/igb/e1000_mac.c
+++ b/sys/dev/igb/e1000_mac.c
@@ -33,7 +33,6 @@
/*$FreeBSD$*/
#include "e1000_api.h"
-#include "e1000_mac.h"
/**
* e1000_init_mac_ops_generic - Initialize MAC function pointers
@@ -526,7 +525,7 @@ void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
/* Load any remaining multicast addresses into the hash table. */
for (; mc_addr_count > 0; mc_addr_count--) {
- hash_value = e1000_hash_mc_addr(hw, mc_addr_list);
+ hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list);
DEBUGOUT1("Hash value = 0x%03X\n", hash_value);
hw->mac.ops.mta_set(hw, hash_value);
mc_addr_list += ETH_ADDR_LEN;
diff --git a/sys/dev/igb/e1000_manage.h b/sys/dev/igb/e1000_manage.h
index 97b5188..32aee30 100644
--- a/sys/dev/igb/e1000_manage.h
+++ b/sys/dev/igb/e1000_manage.h
@@ -44,6 +44,7 @@ s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
struct e1000_host_mng_command_header *hdr);
s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw,
u8 *buffer, u16 length);
+bool e1000_enable_mng_pass_thru(struct e1000_hw *hw);
typedef enum {
e1000_mng_mode_none = 0,
diff --git a/sys/dev/igb/e1000_osdep.c b/sys/dev/igb/e1000_osdep.c
index 60be867..daa6781 100644
--- a/sys/dev/igb/e1000_osdep.c
+++ b/sys/dev/igb/e1000_osdep.c
@@ -52,20 +52,6 @@ e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
*value = pci_read_config(((struct e1000_osdep *)hw->back)->dev, reg, 2);
}
-void
-e1000_pci_set_mwi(struct e1000_hw *hw)
-{
- pci_write_config(((struct e1000_osdep *)hw->back)->dev, PCIR_COMMAND,
- (hw->bus.pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2);
-}
-
-void
-e1000_pci_clear_mwi(struct e1000_hw *hw)
-{
- pci_write_config(((struct e1000_osdep *)hw->back)->dev, PCIR_COMMAND,
- (hw->bus.pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE), 2);
-}
-
/*
* Read the PCI Express capabilities
*/
diff --git a/sys/dev/igb/e1000_osdep.h b/sys/dev/igb/e1000_osdep.h
index 0d3d9a8..432863e 100644
--- a/sys/dev/igb/e1000_osdep.h
+++ b/sys/dev/igb/e1000_osdep.h
@@ -71,11 +71,13 @@
#define DEBUGOUT3(S,A,B,C)
#define DEBUGOUT7(S,A,B,C,D,E,F,G)
-#define STATIC static
-#define FALSE 0
-#define TRUE 1
-#define CMD_MEM_WRT_INVALIDATE 0x0010 /* BIT_4 */
-#define PCI_COMMAND_REGISTER PCIR_COMMAND
+#define STATIC static
+#define FALSE 0
+#define false FALSE /* shared code stupidity */
+#define TRUE 1
+#define true TRUE
+#define CMD_MEM_WRT_INVALIDATE 0x0010 /* BIT_4 */
+#define PCI_COMMAND_REGISTER PCIR_COMMAND
/*
** These typedefs are necessary due to the new
diff --git a/sys/dev/igb/e1000_phy.c b/sys/dev/igb/e1000_phy.c
index d55a4e4..c0b33de 100644
--- a/sys/dev/igb/e1000_phy.c
+++ b/sys/dev/igb/e1000_phy.c
@@ -33,7 +33,6 @@
/*$FreeBSD$*/
#include "e1000_api.h"
-#include "e1000_phy.h"
/* Cable length tables */
static const u16 e1000_m88_cable_length_table[] =
@@ -670,7 +669,7 @@ s32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
goto out;
}
- ret_val = e1000_phy_hw_reset(hw);
+ ret_val = hw->phy.ops.reset(hw);
if (ret_val) {
DEBUGOUT("Error resetting the PHY.\n");
goto out;
@@ -688,7 +687,7 @@ s32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
*/
if (phy->type == e1000_phy_igp) {
/* disable lplu d3 during driver init */
- ret_val = e1000_set_d3_lplu_state(hw, FALSE);
+ ret_val = hw->phy.ops.set_d3_lplu_state(hw, FALSE);
if (ret_val) {
DEBUGOUT("Error Disabling LPLU D3\n");
goto out;
@@ -696,7 +695,7 @@ s32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
}
/* disable lplu d0 during driver init */
- ret_val = e1000_set_d0_lplu_state(hw, FALSE);
+ ret_val = hw->phy.ops.set_d0_lplu_state(hw, FALSE);
if (ret_val) {
DEBUGOUT("Error Disabling LPLU D0\n");
goto out;
@@ -846,7 +845,7 @@ s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
* check at a later time (for example, callback routine).
*/
if (phy->autoneg_wait_to_complete) {
- ret_val = e1000_wait_autoneg(hw);
+ ret_val = hw->mac.ops.wait_autoneg(hw);
if (ret_val) {
DEBUGOUT("Error while waiting for "
"autoneg to complete\n");
@@ -1343,7 +1342,7 @@ void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
* Success returns 0, Failure returns 1
*
* The low power link up (lplu) state is set to the power management level D3
- * and SmartSpeed is disabled when active is true, else clear lplu for D3
+ * and SmartSpeed is disabled when active is TRUE, else clear lplu for D3
* and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
* is used during Dx states where the power conservation is most important.
* During driver activity, SmartSpeed should be enabled so performance is
@@ -1798,7 +1797,7 @@ s32 e1000_get_phy_info_m88(struct e1000_hw *hw)
phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? TRUE : FALSE;
if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
- ret_val = e1000_get_cable_length(hw);
+ ret_val = hw->phy.ops.get_cable_length(hw);
if (ret_val)
goto out;
@@ -1866,7 +1865,7 @@ s32 e1000_get_phy_info_igp(struct e1000_hw *hw)
if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
IGP01E1000_PSSR_SPEED_1000MBPS) {
- ret_val = e1000_get_cable_length(hw);
+ ret_val = hw->phy.ops.get_cable_length(hw);
if (ret_val)
goto out;
diff --git a/sys/dev/igb/if_igb.c b/sys/dev/igb/if_igb.c
index 2d32255..946e43c 100644
--- a/sys/dev/igb/if_igb.c
+++ b/sys/dev/igb/if_igb.c
@@ -88,7 +88,7 @@ int igb_display_debug_stats = 0;
/*********************************************************************
* Driver version:
*********************************************************************/
-char igb_driver_version[] = "version - 1.1.6";
+char igb_driver_version[] = "version - 1.1.9";
/*********************************************************************
@@ -271,13 +271,18 @@ TUNABLE_INT("hw.igb.rxd", &igb_rxd);
TUNABLE_INT("hw.igb.txd", &igb_txd);
TUNABLE_INT("hw.igb.smart_pwr_down", &igb_smart_pwr_down);
-/* These auto configure if set to 0, based on number of cpus */
-extern int mp_ncpus;
+/*
+** IF YOU CHANGE THESE: be sure and change IGB_MSIX_VEC in
+** if_igb.h to match. These can be autoconfigured if set to
+** 0, it will then be based on number of cpus.
+*/
static int igb_tx_queues = 1;
static int igb_rx_queues = 1;
TUNABLE_INT("hw.igb.tx_queues", &igb_tx_queues);
TUNABLE_INT("hw.igb.rx_queues", &igb_rx_queues);
+extern int mp_ncpus;
+
/* How many packets rxeof tries to clean at a time */
static int igb_rx_process_limit = 100;
TUNABLE_INT("hw.igb.rx_process_limit", &igb_rx_process_limit);
@@ -605,11 +610,11 @@ igb_detach(device_t dev)
callout_drain(&adapter->timer);
+ e1000_remove_device(&adapter->hw);
igb_free_pci_resources(adapter);
bus_generic_detach(dev);
if_free(ifp);
- e1000_remove_device(&adapter->hw);
igb_free_transmit_structures(adapter);
igb_free_receive_structures(adapter);
@@ -819,7 +824,7 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
if (ifp->if_flags & IFF_UP) {
if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
if ((ifp->if_flags ^ adapter->if_flags) &
- IFF_PROMISC) {
+ (IFF_PROMISC | IFF_ALLMULTI)) {
igb_disable_promisc(adapter);
igb_set_promisc(adapter);
}
@@ -1090,8 +1095,10 @@ igb_init_locked(struct adapter *adapter)
else
#endif /* DEVICE_POLLING */
{
+ /* this clears any pending interrupts */
E1000_READ_REG(&adapter->hw, E1000_ICR);
igb_enable_intr(adapter);
+ E1000_WRITE_REG(&adapter->hw, E1000_ICS, E1000_ICS_LSC);
}
@@ -1268,7 +1275,7 @@ igb_irq_fast(void *arg)
/* Link status change */
if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
adapter->hw.mac.get_link_status = 1;
- taskqueue_enqueue(taskqueue_fast, &adapter->link_task);
+ taskqueue_enqueue(adapter->tq, &adapter->link_task);
}
if (reg_icr & E1000_ICR_RXO)
@@ -1341,11 +1348,12 @@ igb_msix_link(void *arg)
if (!(icr & E1000_ICR_LSC))
goto spurious;
adapter->hw.mac.get_link_status = 1;
- taskqueue_enqueue(taskqueue_fast, &adapter->link_task);
+ taskqueue_enqueue(adapter->tq, &adapter->link_task);
spurious:
+ /* Rearm */
E1000_WRITE_REG(&adapter->hw, E1000_IMS, E1000_IMS_LSC);
- E1000_WRITE_REG(&adapter->hw, E1000_EIMS, E1000_EIMS_OTHER);
+ E1000_WRITE_REG(&adapter->hw, E1000_EIMS, adapter->link_mask);
return;
}
@@ -2094,7 +2102,7 @@ igb_configure_queues(struct adapter *adapter)
E1000_WRITE_REG(hw, E1000_CTRL_EXT, tmp);
/* Set the interrupt throttling rate. */
- for (int i = 0; i < 10; i++)
+ for (int i = 0; i < IGB_MSIX_VEC; i++)
E1000_WRITE_REG(&adapter->hw,
E1000_EITR(i), DEFAULT_ITR);
@@ -2117,7 +2125,8 @@ igb_configure_queues(struct adapter *adapter)
/* Link */
E1000_WRITE_REG(hw, E1000_MSIXBM(adapter->linkvec),
E1000_EIMS_OTHER);
- adapter->eims_mask |= E1000_EIMS_OTHER;
+ adapter->link_mask |= E1000_EIMS_OTHER;
+ adapter->eims_mask |= adapter->link_mask;
}
return;
}
@@ -2191,6 +2200,10 @@ igb_setup_msix(struct adapter *adapter)
goto msi;
}
+ /* Limit by the number set in header */
+ if (msgs > IGB_MSIX_VEC)
+ msgs = IGB_MSIX_VEC;
+
/* Figure out a reasonable auto config value */
queues = (mp_ncpus > ((msgs-1)/2)) ? (msgs-1)/2 : mp_ncpus;
@@ -2204,7 +2217,7 @@ igb_setup_msix(struct adapter *adapter)
else {
device_printf(adapter->dev,
"MSIX Configuration Problem, "
- "%d vectors but %d queues wanted!\n",
+ "%d vectors configured, but %d queues wanted!\n",
msgs, want);
return (ENXIO);
}
@@ -2860,7 +2873,6 @@ igb_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *hdrlen)
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;
th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
@@ -3813,7 +3825,7 @@ igb_fixup_rx(struct rx_ring *rxr)
rxr->fmp = n;
} else {
adapter->dropped_pkts++;
- m_freem(rxr->fmp);
+ m_freem(adapter->fmp);
rxr->fmp = NULL;
error = ENOMEM;
}
@@ -3885,6 +3897,8 @@ igb_enable_intr(struct adapter *adapter)
if (adapter->msix_mem) {
E1000_WRITE_REG(&adapter->hw, E1000_EIAC,
adapter->eims_mask);
+ E1000_WRITE_REG(&adapter->hw, E1000_EIAM,
+ adapter->eims_mask);
E1000_WRITE_REG(&adapter->hw, E1000_EIMS,
adapter->eims_mask);
E1000_WRITE_REG(&adapter->hw, E1000_IMS,
@@ -3905,7 +3919,7 @@ igb_disable_intr(struct adapter *adapter)
E1000_WRITE_REG(&adapter->hw, E1000_EIMC, ~0);
E1000_WRITE_REG(&adapter->hw, E1000_EIAC, 0);
}
- E1000_WRITE_REG(&adapter->hw, E1000_IMC, ~0);
+ E1000_WRITE_REG(&adapter->hw, E1000_IMC, ~0);
E1000_WRITE_FLUSH(&adapter->hw);
return;
}
@@ -4143,9 +4157,18 @@ igb_print_debug_info(struct adapter *adapter)
device_printf(dev, "CTRL = 0x%x RCTL = 0x%x \n",
E1000_READ_REG(&adapter->hw, E1000_CTRL),
E1000_READ_REG(&adapter->hw, E1000_RCTL));
+
+#if (DEBUG_HW > 0) /* Dont output these errors normally */
device_printf(dev, "IMS = 0x%x EIMS = 0x%x \n",
E1000_READ_REG(&adapter->hw, E1000_IMS),
E1000_READ_REG(&adapter->hw, E1000_EIMS));
+ /* Kawela only */
+ device_printf(dev, "IVAR0 = 0x%x IVAR1 = 0x%x IVAR_MISC = 0x%x\n",
+ E1000_READ_REG_ARRAY(&adapter->hw, E1000_IVAR0, 0),
+ E1000_READ_REG_ARRAY(&adapter->hw, E1000_IVAR0, 1),
+ E1000_READ_REG(&adapter->hw, E1000_IVAR_MISC));
+#endif
+
device_printf(dev, "Packet buffer = Tx=%dk Rx=%dk \n",
((E1000_READ_REG(&adapter->hw, E1000_PBA) & 0xffff0000) >> 16),\
(E1000_READ_REG(&adapter->hw, E1000_PBA) & 0xffff) );
@@ -4163,24 +4186,24 @@ igb_print_debug_info(struct adapter *adapter)
device_printf(dev, "Queue(%d) tdh = %d, tdt = %d\n", i,
E1000_READ_REG(&adapter->hw, E1000_TDH(i)),
E1000_READ_REG(&adapter->hw, E1000_TDT(i)));
- device_printf(dev, "no descriptors avail event = %lld\n",
- (long long)txr->no_desc_avail);
- device_printf(dev, "TX(%d) MSIX IRQ Handled = %lld\n", txr->me,
- (long long)txr->tx_irq);
- device_printf(dev, "TX(%d) Packets sent = %lld\n", txr->me,
- (long long)txr->tx_packets);
+ device_printf(dev, "no descriptors avail event = %lu\n",
+ txr->no_desc_avail);
+ device_printf(dev, "TX(%d) MSIX IRQ Handled = %lu\n", txr->me,
+ txr->tx_irq);
+ device_printf(dev, "TX(%d) Packets sent = %lu\n", txr->me,
+ txr->tx_packets);
}
for (int i = 0; i < adapter->num_rx_queues; i++, rxr++) {
device_printf(dev, "Queue(%d) rdh = %d, rdt = %d\n", i,
E1000_READ_REG(&adapter->hw, E1000_RDH(i)),
E1000_READ_REG(&adapter->hw, E1000_RDT(i)));
- device_printf(dev, "RX(%d) Packets received = %lld\n", rxr->me,
- (long long)rxr->rx_packets);
- device_printf(dev, "RX(%d) Byte count = %lld\n", rxr->me,
- (long long)rxr->rx_bytes);
- device_printf(dev, "RX(%d) MSIX IRQ Handled = %lld\n", rxr->me,
- (long long)rxr->rx_irq);
+ device_printf(dev, "RX(%d) Packets received = %lu\n", rxr->me,
+ rxr->rx_packets);
+ device_printf(dev, "RX(%d) Byte count = %lu\n", rxr->me,
+ rxr->rx_bytes);
+ device_printf(dev, "RX(%d) MSIX IRQ Handled = %lu\n", rxr->me,
+ rxr->rx_irq);
}
device_printf(dev, "LINK MSIX IRQ Handled = %u\n", adapter->link_irq);
diff --git a/sys/dev/igb/if_igb.h b/sys/dev/igb/if_igb.h
index 134eff1..03699dc 100644
--- a/sys/dev/igb/if_igb.h
+++ b/sys/dev/igb/if_igb.h
@@ -203,7 +203,14 @@
/* PCI Config defines */
#define IGB_MSIX_BAR 3
-#define IGB_MSIX_VEC 10 /* Max vectors supported */
+
+/*
+** 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 5 /* MSIX vectors configured */
/* Defines for printing debug information */
#define DEBUG_INIT 0
@@ -318,6 +325,7 @@ struct adapter {
u32 eims_mask;
int linkvec;
+ int link_mask;
int link_irq;
struct ifmedia media;
diff --git a/sys/modules/em/Makefile b/sys/modules/em/Makefile
index 6fe050b..8a2dbdd 100644
--- a/sys/modules/em/Makefile
+++ b/sys/modules/em/Makefile
@@ -7,9 +7,16 @@ SHARED_SRCS = e1000_api.c e1000_phy.c e1000_nvm.c e1000_mac.c e1000_manage.c
SHARED_SRCS += e1000_80003es2lan.c e1000_82542.c e1000_82541.c e1000_82543.c
SHARED_SRCS += e1000_82540.c e1000_ich8lan.c e1000_82571.c e1000_osdep.c
-CFLAGS+= -I${.CURDIR}/../../dev/em
+CFLAGS+= -DNO_82575_SUPPORT -I${.CURDIR}/../../dev/em
-# DEVICE_POLLING gives you Legacy interrupt handling
+# Uncomment this to disable Fast interrupt handling.
+# and enable legacy interrupt handling
+#CFLAGS += -DEM_LEGACY_IRQ
+
+# This option enables IEEE 1588 Precision Time Protocol
+#CFLAGS += -DEM_TIMESYNC
+
+# DEVICE_POLLING for a non-interrupt-driven method
#CFLAGS += -DDEVICE_POLLING
clean:
OpenPOWER on IntegriCloud