summaryrefslogtreecommitdiffstats
path: root/sys/dev/em
diff options
context:
space:
mode:
authorjfv <jfv@FreeBSD.org>2008-04-25 21:19:41 +0000
committerjfv <jfv@FreeBSD.org>2008-04-25 21:19:41 +0000
commitb504776a58ec435e17a4e3c2dbb82849593dc2b0 (patch)
treeba89bf27aac0358813a723b89ba73f0917631cec /sys/dev/em
parent69e5e2aed2db0e4c5f9b33170d1b901503485a2b (diff)
downloadFreeBSD-src-b504776a58ec435e17a4e3c2dbb82849593dc2b0.zip
FreeBSD-src-b504776a58ec435e17a4e3c2dbb82849593dc2b0.tar.gz
This delta has a few important items:
PR 122839 is fixed in both em and in igb Second, the issue on building modules since the static kernel build changes is now resolved. I was not able to get the fancier directory hierarchy working, but this works, both em and igb build as modules now. Third, there is now support in em for two new NICs, Hartwell (or 82574) is a low cost PCIE dual port adapter that has MSIX, for this release it uses 3 vectors only, RX, TX, and LINK. In the next release I will add a second TX and RX queue. Also, there is support here for ICH10, the followon to ICH9. Both of these are early releases, general availability will follow soon. Fourth: On Hartwell and ICH10 we now have IEEE 1588 PTP support, I have implemented this in a provisional way so that early adopters may try and comment on the functionality. The IOCTL structure may change. This feature is off by default, you need to edit the Makefile and add the EM_TIMESYNC define to get the code. Enjoy all!!
Diffstat (limited to 'sys/dev/em')
-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
13 files changed, 760 insertions, 148 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)
OpenPOWER on IntegriCloud