aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/e1000
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/e1000')
-rw-r--r--sys/dev/e1000/e1000_82542.c39
-rw-r--r--sys/dev/e1000/e1000_82575.h3
-rw-r--r--sys/dev/e1000/e1000_hw.h3
-rw-r--r--sys/dev/e1000/e1000_mbx.c107
-rw-r--r--sys/dev/e1000/e1000_mbx.h5
-rw-r--r--sys/dev/e1000/e1000_osdep.h114
-rw-r--r--sys/dev/e1000/e1000_regs.h1
-rw-r--r--sys/dev/e1000/e1000_vf.c96
-rw-r--r--sys/dev/e1000/e1000_vf.h6
-rw-r--r--sys/dev/e1000/em_txrx.c42
-rw-r--r--sys/dev/e1000/if_em.c2142
-rw-r--r--sys/dev/e1000/if_em.h209
-rw-r--r--sys/dev/e1000/if_igb_iov.c2261
-rw-r--r--sys/dev/e1000/if_igb_iov.h60
-rw-r--r--sys/dev/e1000/if_igbv.c836
-rw-r--r--sys/dev/e1000/igb_txrx.c91
16 files changed, 5343 insertions, 672 deletions
diff --git a/sys/dev/e1000/e1000_82542.c b/sys/dev/e1000/e1000_82542.c
index e8de9086d05d..0656c6408b30 100644
--- a/sys/dev/e1000/e1000_82542.c
+++ b/sys/dev/e1000/e1000_82542.c
@@ -317,18 +317,43 @@ static s32 e1000_init_hw_82542(struct e1000_hw *hw)
static s32 e1000_setup_link_82542(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
- s32 ret_val;
+ s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_setup_link_82542");
- ret_val = e1000_set_default_fc_generic(hw);
- if (ret_val)
- goto out;
+ if (hw->fc.requested_mode == e1000_fc_default) {
+ ret_val = e1000_set_default_fc_generic(hw);
+ if (ret_val)
+ goto out;
+ }
- hw->fc.requested_mode &= ~e1000_fc_tx_pause;
+ /* 82542 rev 2.0 cannot transmit PAUSE frames. */
+ if (hw->revision_id == E1000_REVISION_2) {
+ switch (hw->fc.requested_mode) {
+ case e1000_fc_tx_pause:
+ hw->fc.requested_mode = e1000_fc_none;
+ break;
+ case e1000_fc_full:
+ hw->fc.requested_mode = e1000_fc_rx_pause;
+ break;
+ default:
+ break;
+ }
+ }
- if (mac->report_tx_early)
- hw->fc.requested_mode &= ~e1000_fc_rx_pause;
+ /* Early transmit reporting is incompatible with receiving PAUSE. */
+ if (mac->report_tx_early) {
+ switch (hw->fc.requested_mode) {
+ case e1000_fc_rx_pause:
+ hw->fc.requested_mode = e1000_fc_none;
+ break;
+ case e1000_fc_full:
+ hw->fc.requested_mode = e1000_fc_tx_pause;
+ break;
+ default:
+ break;
+ }
+ }
/*
* Save off the requested flow control mode for use later. Depending
diff --git a/sys/dev/e1000/e1000_82575.h b/sys/dev/e1000/e1000_82575.h
index 91ac3fe9fcbf..c919a8064476 100644
--- a/sys/dev/e1000/e1000_82575.h
+++ b/sys/dev/e1000/e1000_82575.h
@@ -402,9 +402,10 @@ enum e1000_promisc_type {
e1000_num_promisc_types
};
-void e1000_vfta_set_vf(struct e1000_hw *, u16, bool);
+s32 e1000_vfta_set_vf(struct e1000_hw *, u16, bool);
void e1000_rlpml_set_vf(struct e1000_hw *, u16);
s32 e1000_promisc_set_vf(struct e1000_hw *, enum e1000_promisc_type type);
+s32 e1000_set_uc_addr_vf(struct e1000_hw *, u32, u8 *);
void e1000_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value);
u16 e1000_rxpbs_adjust_82580(u32 data);
s32 e1000_read_emi_reg(struct e1000_hw *hw, u16 addr, u16 *data);
diff --git a/sys/dev/e1000/e1000_hw.h b/sys/dev/e1000/e1000_hw.h
index b4a9592cd89b..5e918ef83263 100644
--- a/sys/dev/e1000/e1000_hw.h
+++ b/sys/dev/e1000/e1000_hw.h
@@ -938,13 +938,14 @@ struct e1000_fc_info {
struct e1000_mbx_operations {
s32 (*init_params)(struct e1000_hw *hw);
- s32 (*read)(struct e1000_hw *, u32 *, u16, u16);
+ s32 (*read)(struct e1000_hw *, u32 *, u16, u16, bool);
s32 (*write)(struct e1000_hw *, u32 *, u16, u16);
s32 (*read_posted)(struct e1000_hw *, u32 *, u16, u16);
s32 (*write_posted)(struct e1000_hw *, u32 *, u16, u16);
s32 (*check_for_msg)(struct e1000_hw *, u16);
s32 (*check_for_ack)(struct e1000_hw *, u16);
s32 (*check_for_rst)(struct e1000_hw *, u16);
+ s32 (*unlock)(struct e1000_hw *, u16);
};
struct e1000_mbx_stats {
diff --git a/sys/dev/e1000/e1000_mbx.c b/sys/dev/e1000/e1000_mbx.c
index 97097fd777a1..985d315d527e 100644
--- a/sys/dev/e1000/e1000_mbx.c
+++ b/sys/dev/e1000/e1000_mbx.c
@@ -64,6 +64,17 @@ static s32 e1000_null_mbx_transact(struct e1000_hw E1000_UNUSEDARG *hw,
return E1000_SUCCESS;
}
+static s32 e1000_null_mbx_read(struct e1000_hw E1000_UNUSEDARG *hw,
+ u32 E1000_UNUSEDARG *msg,
+ u16 E1000_UNUSEDARG size,
+ u16 E1000_UNUSEDARG mbx_id,
+ bool E1000_UNUSEDARG unlock)
+{
+ DEBUGFUNC("e1000_null_mbx_read");
+
+ return E1000_SUCCESS;
+}
+
/**
* e1000_read_mbx - Reads a message from the mailbox
* @hw: pointer to the HW structure
@@ -73,7 +84,8 @@ static s32 e1000_null_mbx_transact(struct e1000_hw E1000_UNUSEDARG *hw,
*
* returns SUCCESS if it successfully read message from buffer
**/
-s32 e1000_read_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+s32 e1000_read_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id,
+ bool unlock)
{
struct e1000_mbx_info *mbx = &hw->mbx;
s32 ret_val = -E1000_ERR_MBX;
@@ -85,7 +97,7 @@ s32 e1000_read_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
size = mbx->size;
if (mbx->ops.read)
- ret_val = mbx->ops.read(hw, msg, size, mbx_id);
+ ret_val = mbx->ops.read(hw, msg, size, mbx_id, unlock);
return ret_val;
}
@@ -176,6 +188,24 @@ s32 e1000_check_for_rst(struct e1000_hw *hw, u16 mbx_id)
}
/**
+ * e1000_unlock_mbx - release mailbox ownership
+ * @hw: pointer to the HW structure
+ * @mbx_id: id of mailbox to unlock
+ **/
+s32 e1000_unlock_mbx(struct e1000_hw *hw, u16 mbx_id)
+{
+ struct e1000_mbx_info *mbx = &hw->mbx;
+ s32 ret_val = -E1000_ERR_MBX;
+
+ DEBUGFUNC("e1000_unlock_mbx");
+
+ if (mbx->ops.unlock)
+ ret_val = mbx->ops.unlock(hw, mbx_id);
+
+ return (ret_val);
+}
+
+/**
* e1000_poll_for_msg - Wait for message notification
* @hw: pointer to the HW structure
* @mbx_id: id of mailbox to write
@@ -261,7 +291,7 @@ s32 e1000_read_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
/* if ack received read message, otherwise we timed out */
if (!ret_val)
- ret_val = mbx->ops.read(hw, msg, size, mbx_id);
+ ret_val = mbx->ops.read(hw, msg, size, mbx_id, true);
out:
return ret_val;
}
@@ -307,11 +337,12 @@ void e1000_init_mbx_ops_generic(struct e1000_hw *hw)
{
struct e1000_mbx_info *mbx = &hw->mbx;
mbx->ops.init_params = e1000_null_ops_generic;
- mbx->ops.read = e1000_null_mbx_transact;
+ mbx->ops.read = e1000_null_mbx_read;
mbx->ops.write = e1000_null_mbx_transact;
mbx->ops.check_for_msg = e1000_null_mbx_check_for_flag;
mbx->ops.check_for_ack = e1000_null_mbx_check_for_flag;
mbx->ops.check_for_rst = e1000_null_mbx_check_for_flag;
+ mbx->ops.unlock = e1000_null_mbx_check_for_flag;
mbx->ops.read_posted = e1000_read_posted_mbx;
mbx->ops.write_posted = e1000_write_posted_mbx;
}
@@ -500,7 +531,8 @@ out_no_write:
* returns SUCCESS if it successfully read message from buffer
**/
static s32 e1000_read_mbx_vf(struct e1000_hw *hw, u32 *msg, u16 size,
- u16 E1000_UNUSEDARG mbx_id)
+ u16 E1000_UNUSEDARG mbx_id,
+ bool E1000_UNUSEDARG unlock)
{
s32 ret_val = E1000_SUCCESS;
u16 i;
@@ -649,28 +681,37 @@ static s32 e1000_obtain_mbx_lock_pf(struct e1000_hw *hw, u16 vf_number)
{
s32 ret_val = -E1000_ERR_MBX;
u32 p2v_mailbox;
- int count = 10;
DEBUGFUNC("e1000_obtain_mbx_lock_pf");
- do {
- /* Take ownership of the buffer */
- E1000_WRITE_REG(hw, E1000_P2VMAILBOX(vf_number),
- E1000_P2VMAILBOX_PFU);
-
- /* reserve mailbox for pf use */
- p2v_mailbox = E1000_READ_REG(hw, E1000_P2VMAILBOX(vf_number));
- if (p2v_mailbox & E1000_P2VMAILBOX_PFU) {
- ret_val = E1000_SUCCESS;
- break;
- }
- usec_delay(1000);
- } while (count-- > 0);
+ /*
+ * A VF request releases VFU as it raises REQ. If the VF still owns
+ * the buffer, leave the request for a later admin pass rather than
+ * sleeping under the PF's context lock and delaying every other VF.
+ */
+ E1000_WRITE_REG(hw, E1000_P2VMAILBOX(vf_number),
+ E1000_P2VMAILBOX_PFU);
+ p2v_mailbox = E1000_READ_REG(hw, E1000_P2VMAILBOX(vf_number));
+ if (p2v_mailbox & E1000_P2VMAILBOX_PFU)
+ ret_val = E1000_SUCCESS;
return ret_val;
}
+static s32
+e1000_release_mbx_lock_pf(struct e1000_hw *hw, u16 vf_number)
+{
+ u32 p2v_mailbox;
+
+ p2v_mailbox = E1000_READ_REG(hw, E1000_P2VMAILBOX(vf_number));
+ if (p2v_mailbox & E1000_P2VMAILBOX_PFU)
+ E1000_WRITE_REG(hw, E1000_P2VMAILBOX(vf_number),
+ p2v_mailbox & ~E1000_P2VMAILBOX_PFU);
+
+ return (E1000_SUCCESS);
+}
+
/**
* e1000_write_mbx_pf - Places a message in the mailbox
* @hw: pointer to the HW structure
@@ -693,6 +734,17 @@ static s32 e1000_write_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size,
if (ret_val)
goto out_no_write;
+ /*
+ * A VF request wins over an asynchronous PF message. Do not clear
+ * VFREQ here: the PF mailbox handler still needs to consume it.
+ */
+ if (E1000_READ_REG(hw, E1000_MBVFICR) &
+ (E1000_MBVFICR_VFREQ_VF1 << vf_number)) {
+ e1000_release_mbx_lock_pf(hw, vf_number);
+ ret_val = -E1000_ERR_MBX;
+ goto out_no_write;
+ }
+
/* flush msg and acks as we are overwriting the message buffer */
e1000_check_for_msg_pf(hw, vf_number);
e1000_check_for_ack_pf(hw, vf_number);
@@ -724,7 +776,7 @@ out_no_write:
* a message due to a VF request so no polling for message is needed.
**/
static s32 e1000_read_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size,
- u16 vf_number)
+ u16 vf_number, bool unlock)
{
s32 ret_val;
u16 i;
@@ -736,12 +788,21 @@ static s32 e1000_read_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size,
if (ret_val)
goto out_no_read;
+ /*
+ * A second VF request can arrive while the PF retries ownership. PFU
+ * now keeps VMBMEM stable, so consume any reasserted VFREQ before
+ * reading the request that it describes.
+ */
+ (void)e1000_check_for_msg_pf(hw, vf_number);
+
/* copy the message to the mailbox memory buffer */
for (i = 0; i < size; i++)
msg[i] = E1000_READ_REG_ARRAY(hw, E1000_VMBMEM(vf_number), i);
- /* Acknowledge the message and release buffer */
- E1000_WRITE_REG(hw, E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_ACK);
+ /* Acknowledge the message and optionally retain PF ownership. */
+ E1000_WRITE_REG(hw, E1000_P2VMAILBOX(vf_number),
+ E1000_P2VMAILBOX_ACK |
+ (unlock ? 0 : E1000_P2VMAILBOX_PFU));
/* update stats */
hw->mbx.stats.msgs_rx++;
@@ -776,6 +837,7 @@ s32 e1000_init_mbx_params_pf(struct e1000_hw *hw)
mbx->ops.check_for_msg = e1000_check_for_msg_pf;
mbx->ops.check_for_ack = e1000_check_for_ack_pf;
mbx->ops.check_for_rst = e1000_check_for_rst_pf;
+ mbx->ops.unlock = e1000_release_mbx_lock_pf;
mbx->stats.msgs_tx = 0;
mbx->stats.msgs_rx = 0;
@@ -787,4 +849,3 @@ s32 e1000_init_mbx_params_pf(struct e1000_hw *hw)
return E1000_SUCCESS;
}
}
-
diff --git a/sys/dev/e1000/e1000_mbx.h b/sys/dev/e1000/e1000_mbx.h
index 61f8d5cbe265..edd74a49f00b 100644
--- a/sys/dev/e1000/e1000_mbx.h
+++ b/sys/dev/e1000/e1000_mbx.h
@@ -77,6 +77,8 @@
#define E1000_VF_RESET 0x01 /* VF requests reset */
#define E1000_VF_SET_MAC_ADDR 0x02 /* VF requests to set MAC addr */
+#define E1000_VF_MAC_FILTER_CLR (0x01 << E1000_VT_MSGINFO_SHIFT)
+#define E1000_VF_MAC_FILTER_ADD (0x02 << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_SET_MULTICAST 0x03 /* VF requests to set MC addr */
#define E1000_VF_SET_MULTICAST_COUNT_MASK (0x1F << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_SET_MULTICAST_OVERFLOW (0x80 << E1000_VT_MSGINFO_SHIFT)
@@ -92,13 +94,14 @@
#define E1000_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */
#define E1000_VF_MBX_INIT_DELAY 500 /* microseconds between retries */
-s32 e1000_read_mbx(struct e1000_hw *, u32 *, u16, u16);
+s32 e1000_read_mbx(struct e1000_hw *, u32 *, u16, u16, bool);
s32 e1000_write_mbx(struct e1000_hw *, u32 *, u16, u16);
s32 e1000_read_posted_mbx(struct e1000_hw *, u32 *, u16, u16);
s32 e1000_write_posted_mbx(struct e1000_hw *, u32 *, u16, u16);
s32 e1000_check_for_msg(struct e1000_hw *, u16);
s32 e1000_check_for_ack(struct e1000_hw *, u16);
s32 e1000_check_for_rst(struct e1000_hw *, u16);
+s32 e1000_unlock_mbx(struct e1000_hw *, u16);
void e1000_init_mbx_ops_generic(struct e1000_hw *hw);
s32 e1000_init_mbx_params_vf(struct e1000_hw *);
s32 e1000_init_mbx_params_pf(struct e1000_hw *);
diff --git a/sys/dev/e1000/e1000_osdep.h b/sys/dev/e1000/e1000_osdep.h
index ba1c8a16fad1..1226c0264333 100644
--- a/sys/dev/e1000/e1000_osdep.h
+++ b/sys/dev/e1000/e1000_osdep.h
@@ -161,8 +161,111 @@ struct e1000_osdep
bus_space_handle_t flash_bus_space_handle;
device_t dev;
if_ctx_t ctx;
+ bool vf;
+ bool vf_82576;
};
+#ifdef INVARIANTS
+/*
+ * 82576 and I350 VFs expose a sparse register file. Keep this list local to
+ * the OS accessors so a PF-only register that leaks into the shared VF path
+ * fails at its first access instead of returning reserved-register garbage.
+ *
+ * The driver intentionally uses only queue pair zero. It also clears the
+ * retained configuration of the unused second 82576 queue pair after VFLR.
+ * Expanding VF data-path queue support must extend this predicate from the
+ * applicable device CSR map.
+ */
+static __inline bool
+e1000_vf_reg_valid(uint32_t reg, bool write, bool vf_82576)
+{
+ /* VF mailbox memory: 16 dwords beginning at 0x800. */
+ if (reg >= 0x00800 && reg <= 0x0083c && (reg & 3) == 0)
+ return (true);
+
+ /* The three VF MSI-X interrupt-throttling registers. */
+ if (reg >= 0x01680 && reg <= 0x01688 && (reg & 3) == 0)
+ return (true);
+
+ /* Receive queue zero. */
+ switch (reg) {
+ case 0x02800: /* RDBAL */
+ case 0x02804: /* RDBAH */
+ case 0x02808: /* RDLEN */
+ case 0x0280c: /* SRRCTL */
+ case 0x02810: /* RDH */
+ case 0x02814: /* RXCTL */
+ case 0x02818: /* RDT */
+ case 0x02828: /* RXDCTL */
+ return (true);
+ }
+
+ /* Transmit queue zero. */
+ switch (reg) {
+ case 0x03800: /* TDBAL */
+ case 0x03804: /* TDBAH */
+ case 0x03808: /* TDLEN */
+ case 0x03810: /* TDH */
+ case 0x03814: /* TXCTL */
+ case 0x03818: /* TDT */
+ case 0x03828: /* TXDCTL */
+ case 0x03838: /* TDWBAL */
+ case 0x0383c: /* TDWBAH */
+ return (true);
+ }
+
+ /* Retained configuration from 82576 virtual queue one. */
+ if (vf_82576) {
+ switch (reg) {
+ case 0x0290c: /* SRRCTL(1) */
+ case 0x02914: /* RXCTL(1) */
+ case 0x02928: /* RXDCTL(1) */
+ case 0x03914: /* TXCTL(1) */
+ case 0x03928: /* TXDCTL(1) */
+ case 0x03938: /* TDWBAL(1) */
+ case 0x0393c: /* TDWBAH(1) */
+ return (true);
+ }
+ }
+
+ /*
+ * 82576 exposes VFMPRC at 0xf3c. I350 erratum 31 makes
+ * its corrected 0xf38 address inaccessible to a VF.
+ */
+ if (vf_82576 && reg == 0x00f3c)
+ return (!write);
+
+ switch (reg) {
+ case 0x00000: /* CTRL */
+ case 0x000c4: /* Legacy ITR, listed but unused by igb VFs */
+ case 0x00c40: /* V2PMAILBOX(0) */
+ case 0x00f0c: /* VFPSRTYPE */
+ case 0x01524: /* EIMS */
+ case 0x0152c: /* EIAC */
+ case 0x01530: /* EIAM */
+ case 0x01700: /* IVAR0 */
+ case 0x01740: /* IVAR_MISC */
+ return (true);
+ case 0x01520: /* EICS */
+ case 0x01528: /* EIMC */
+ return (write);
+ case 0x00008: /* STATUS */
+ case 0x00f10: /* VFGPRC */
+ case 0x00f14: /* VFGPTC */
+ case 0x00f18: /* VFGORC */
+ case 0x00f34: /* VFGOTC */
+ case 0x00f40: /* VFGPRLBC */
+ case 0x00f44: /* VFGPTLBC */
+ case 0x00f48: /* VFGORLBC */
+ case 0x00f50: /* VFGOTLBC */
+ case 0x01580: /* EICR */
+ return (!write);
+ default:
+ return (false);
+ }
+}
+#endif
+
#define E1000_REGISTER(hw, reg) (((hw)->mac.type >= e1000_82543) \
? reg : e1000_translate_register_82542(reg))
@@ -185,6 +288,11 @@ e1000_rd32(struct e1000_osdep *osdep, uint32_t reg)
KASSERT(reg < osdep->mem_bus_space_size,
("e1000: register offset %#jx too large (max is %#jx)",
(uintmax_t)reg, (uintmax_t)osdep->mem_bus_space_size));
+#ifdef INVARIANTS
+ KASSERT(!osdep->vf ||
+ e1000_vf_reg_valid(reg, false, osdep->vf_82576),
+ ("e1000: invalid VF register read at %#x", reg));
+#endif
return (bus_space_read_4(osdep->mem_bus_space_tag,
osdep->mem_bus_space_handle, reg));
@@ -198,6 +306,11 @@ e1000_wr32(struct e1000_osdep *osdep, uint32_t reg, uint32_t value)
KASSERT(reg < osdep->mem_bus_space_size,
("e1000: register offset %#jx too large (max is %#jx)",
(uintmax_t)reg, (uintmax_t)osdep->mem_bus_space_size));
+#ifdef INVARIANTS
+ KASSERT(!osdep->vf ||
+ e1000_vf_reg_valid(reg, true, osdep->vf_82576),
+ ("e1000: invalid VF register write at %#x", reg));
+#endif
bus_space_write_4(osdep->mem_bus_space_tag,
osdep->mem_bus_space_handle, reg, value);
@@ -277,4 +390,3 @@ e1000_wr32(struct e1000_osdep *osdep, uint32_t reg, uint32_t value)
#endif
#endif /* _FREEBSD_OS_H_ */
-
diff --git a/sys/dev/e1000/e1000_regs.h b/sys/dev/e1000/e1000_regs.h
index 5af1142a1ff0..138155cfc5bc 100644
--- a/sys/dev/e1000/e1000_regs.h
+++ b/sys/dev/e1000/e1000_regs.h
@@ -286,6 +286,7 @@
#define E1000_TXDMAC 0x03000 /* Tx DMA Control - RW */
#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */
#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4))
+#define E1000_VFPSRTYPE 0x00F0C
#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
(0x054E0 + ((_i - 16) * 8)))
#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
diff --git a/sys/dev/e1000/e1000_vf.c b/sys/dev/e1000/e1000_vf.c
index 9bcd2798e486..2394c240d18d 100644
--- a/sys/dev/e1000/e1000_vf.c
+++ b/sys/dev/e1000/e1000_vf.c
@@ -275,24 +275,26 @@ static s32 e1000_reset_hw_vf(struct e1000_hw *hw)
usec_delay(5);
}
- if (timeout) {
- /* mailbox timeout can now become active */
- mbx->timeout = E1000_VF_MBX_INIT_TIMEOUT;
+ if (!timeout)
+ return -E1000_ERR_RESET;
- msgbuf[0] = E1000_VF_RESET;
- mbx->ops.write_posted(hw, msgbuf, 1, 0);
+ /* mailbox timeout can now become active */
+ mbx->timeout = E1000_VF_MBX_INIT_TIMEOUT;
- msec_delay(10);
+ msgbuf[0] = E1000_VF_RESET;
+ ret_val = mbx->ops.write_posted(hw, msgbuf, 1, 0);
+ if (ret_val)
+ return ret_val;
- /* set our "perm_addr" based on info provided by PF */
- ret_val = mbx->ops.read_posted(hw, msgbuf, 3, 0);
- if (!ret_val) {
- if (msgbuf[0] == (E1000_VF_RESET |
- E1000_VT_MSGTYPE_ACK))
- memcpy(hw->mac.perm_addr, addr, 6);
- else
- ret_val = -E1000_ERR_MAC_INIT;
- }
+ msec_delay(10);
+
+ /* set our "perm_addr" based on info provided by PF */
+ ret_val = mbx->ops.read_posted(hw, msgbuf, 3, 0);
+ if (!ret_val) {
+ if (msgbuf[0] == (E1000_VF_RESET | E1000_VT_MSGTYPE_ACK))
+ memcpy(hw->mac.perm_addr, addr, 6);
+ else
+ ret_val = -E1000_ERR_MAC_INIT;
}
return ret_val;
@@ -389,6 +391,41 @@ static void e1000_write_msg_read_ack(struct e1000_hw *hw,
}
/**
+ * e1000_set_uc_addr_vf - Add or clear secondary unicast addresses
+ * @hw: pointer to the HW structure
+ * @sub_cmd: E1000_VF_MAC_FILTER_ADD or E1000_VF_MAC_FILTER_CLR
+ * @addr: address to add, or a valid compatibility address when clearing
+ *
+ * Uses the secondary-MAC mailbox subprotocol implemented by Linux igbvf.
+ * Linux igb PFs validate this field before dispatching the clear subcommand,
+ * even though they do not otherwise use it for a clear request.
+ **/
+s32
+e1000_set_uc_addr_vf(struct e1000_hw *hw, u32 sub_cmd, u8 *addr)
+{
+ struct e1000_mbx_info *mbx = &hw->mbx;
+ u32 msgbuf[3] = {};
+ u32 request;
+ s32 ret_val;
+
+ msgbuf[0] = E1000_VF_SET_MAC_ADDR | sub_cmd;
+ request = msgbuf[0];
+ if (addr != NULL)
+ memcpy(&msgbuf[1], addr, ETHER_ADDR_LEN);
+
+ ret_val = mbx->ops.write_posted(hw, msgbuf, 3, 0);
+ if (ret_val == E1000_SUCCESS)
+ ret_val = mbx->ops.read_posted(hw, msgbuf, 3, 0);
+
+ msgbuf[0] &= ~E1000_VT_MSGTYPE_CTS;
+ if (ret_val == E1000_SUCCESS &&
+ msgbuf[0] == (request | E1000_VT_MSGTYPE_NACK))
+ ret_val = -E1000_ERR_NO_SPACE;
+
+ return (ret_val);
+}
+
+/**
* e1000_update_mc_addr_list_vf - Update Multicast addresses
* @hw: pointer to the HW structure
* @mc_addr_list: array of multicast addresses to program
@@ -400,7 +437,7 @@ static void e1000_write_msg_read_ack(struct e1000_hw *hw,
void e1000_update_mc_addr_list_vf(struct e1000_hw *hw,
u8 *mc_addr_list, u32 mc_addr_count)
{
- u32 msgbuf[E1000_VFMAILBOX_SIZE];
+ u32 msgbuf[E1000_VFMAILBOX_SIZE] = {};
u16 *hash_list = (u16 *)&msgbuf[1];
u32 hash_value;
u32 i;
@@ -442,10 +479,14 @@ void e1000_update_mc_addr_list_vf(struct e1000_hw *hw,
* @hw: pointer to the HW structure
* @vid: determines the vfta register and bit to set/unset
* @set: if true then set bit, else clear bit
+ *
+ * Returns success if the PF accepted the request, or an error otherwise.
**/
-void e1000_vfta_set_vf(struct e1000_hw *hw, u16 vid, bool set)
+s32 e1000_vfta_set_vf(struct e1000_hw *hw, u16 vid, bool set)
{
+ struct e1000_mbx_info *mbx = &hw->mbx;
u32 msgbuf[2];
+ s32 ret_val;
msgbuf[0] = E1000_VF_SET_VLAN;
msgbuf[1] = vid;
@@ -453,7 +494,15 @@ void e1000_vfta_set_vf(struct e1000_hw *hw, u16 vid, bool set)
if (set)
msgbuf[0] |= E1000_VF_SET_VLAN_ADD;
- e1000_write_msg_read_ack(hw, msgbuf, 2);
+ ret_val = mbx->ops.write_posted(hw, msgbuf, 2, 0);
+ if (!ret_val)
+ ret_val = mbx->ops.read_posted(hw, msgbuf, 1, 0);
+ if (!ret_val &&
+ ((msgbuf[0] & 0xffff) != E1000_VF_SET_VLAN ||
+ !(msgbuf[0] & E1000_VT_MSGTYPE_ACK)))
+ ret_val = -E1000_ERR_MAC_INIT;
+
+ return (ret_val);
}
/** e1000_rlpml_set_vf - Set the maximum receive packet length
@@ -559,13 +608,17 @@ static s32 e1000_check_for_link_vf(struct e1000_hw *hw)
/* if the read failed it could just be a mailbox collision, best wait
* until we are called again and don't report an error */
- if (mbx->ops.read(hw, &in_msg, 1, 0))
+ if (mbx->ops.read(hw, &in_msg, 1, 0, true))
goto out;
/* if incoming message isn't clear to send we are waiting on response */
if (!(in_msg & E1000_VT_MSGTYPE_CTS)) {
- /* message is not CTS and is NACK we have lost CTS status */
- if (in_msg & E1000_VT_MSGTYPE_NACK)
+ /*
+ * A NACK or a PF control message without CTS means that the PF
+ * discarded our state and requires a new VF reset handshake.
+ */
+ if ((in_msg & E1000_VT_MSGTYPE_NACK) != 0 ||
+ (in_msg & 0xffff) == E1000_PF_CONTROL_MSG)
ret_val = -E1000_ERR_MAC_INIT;
goto out;
}
@@ -585,4 +638,3 @@ static s32 e1000_check_for_link_vf(struct e1000_hw *hw)
out:
return ret_val;
}
-
diff --git a/sys/dev/e1000/e1000_vf.h b/sys/dev/e1000/e1000_vf.h
index aace8e78ed6a..17116a86b084 100644
--- a/sys/dev/e1000/e1000_vf.h
+++ b/sys/dev/e1000/e1000_vf.h
@@ -227,13 +227,14 @@ struct e1000_mac_info {
struct e1000_mbx_operations {
s32 (*init_params)(struct e1000_hw *hw);
- s32 (*read)(struct e1000_hw *, u32 *, u16, u16);
+ s32 (*read)(struct e1000_hw *, u32 *, u16, u16, bool);
s32 (*write)(struct e1000_hw *, u32 *, u16, u16);
s32 (*read_posted)(struct e1000_hw *, u32 *, u16, u16);
s32 (*write_posted)(struct e1000_hw *, u32 *, u16, u16);
s32 (*check_for_msg)(struct e1000_hw *, u16);
s32 (*check_for_ack)(struct e1000_hw *, u16);
s32 (*check_for_rst)(struct e1000_hw *, u16);
+ s32 (*unlock)(struct e1000_hw *, u16);
};
struct e1000_mbx_stats {
@@ -290,7 +291,8 @@ enum e1000_promisc_type {
/* These functions must be implemented by drivers */
s32 e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
-void e1000_vfta_set_vf(struct e1000_hw *, u16, bool);
+s32 e1000_vfta_set_vf(struct e1000_hw *, u16, bool);
void e1000_rlpml_set_vf(struct e1000_hw *, u16);
s32 e1000_promisc_set_vf(struct e1000_hw *, enum e1000_promisc_type);
+s32 e1000_set_uc_addr_vf(struct e1000_hw *, u32, u8 *);
#endif /* _E1000_VF_H_ */
diff --git a/sys/dev/e1000/em_txrx.c b/sys/dev/e1000/em_txrx.c
index 647255417b3e..dced12770c40 100644
--- a/sys/dev/e1000/em_txrx.c
+++ b/sys/dev/e1000/em_txrx.c
@@ -96,6 +96,11 @@ em_dump_rs(struct e1000_softc *sc)
int16_t rs_cidx;
uint8_t status;
+ if (sc->tx_queues == NULL) {
+ device_printf(sc->dev, "queue state is unavailable\n");
+ return;
+ }
+
printf("\n");
ntxd = scctx->isc_ntxd[0];
for (qid = 0; qid < sc->tx_num_queues; qid++) {
@@ -461,10 +466,27 @@ em_isc_txd_encap(void *arg, if_pkt_info_t pi)
first, pidx_last, i);
pi->ipi_new_pidx = i;
- /* Sent data accounting for AIM */
+ /*
+ * Sent data accounting for AIM. For TSO, ipi_len is the whole
+ * unsegmented payload, which is not a size the moderation
+ * calculation can use. Count the segments the hardware will put on
+ * the wire and the header each of them carries, so that the average
+ * it sees is a wire packet.
+ */
+ if (do_tso && pi->ipi_tso_segsz != 0) {
+ u32 hdrlen, segs;
+
+ hdrlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen;
+ if (pi->ipi_len > hdrlen) {
+ segs = howmany(pi->ipi_len - hdrlen, pi->ipi_tso_segsz);
+ txr->tx_bytes += pi->ipi_len + (segs - 1) * hdrlen;
+ txr->tx_packets += segs;
+ return (0);
+ }
+ }
+
txr->tx_bytes += pi->ipi_len;
++txr->tx_packets;
-
return (0);
}
@@ -476,6 +498,8 @@ em_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx)
struct tx_ring *txr = &que->txr;
E1000_WRITE_REG(&sc->hw, E1000_TDT(txr->me), pidx);
+ if (sc->hw.mac.type >= e1000_82540)
+ em_aim_publish(txr);
}
static int
@@ -601,6 +625,8 @@ em_isc_rxd_flush(void *arg, uint16_t rxqid, uint8_t flid __unused,
struct rx_ring *rxr = &que->rxr;
E1000_WRITE_REG(&sc->hw, E1000_RDT(rxr->me), pidx);
+ if (sc->hw.mac.type >= e1000_82540)
+ em_aim_publish_rx(rxr);
}
static int
@@ -679,7 +705,6 @@ lem_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
len = le16toh(rxd->length);
ri->iri_len += len;
- rxr->rx_bytes += ri->iri_len;
eop = (status & E1000_RXD_STAT_EOP) != 0;
@@ -701,6 +726,7 @@ lem_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
i++;
} while (!eop);
+ rxr->rx_bytes += ri->iri_len;
rxr->rx_packets++;
if (scctx->isc_capenable & IFCAP_RXCSUM)
@@ -745,7 +771,6 @@ em_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
len = le16toh(rxd->wb.upper.length);
ri->iri_len += len;
- rxr->rx_bytes += ri->iri_len;
eop = (staterr & E1000_RXD_STAT_EOP) != 0;
@@ -766,6 +791,7 @@ em_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
i++;
} while (!eop);
+ rxr->rx_bytes += ri->iri_len;
rxr->rx_packets++;
if (scctx->isc_capenable & IFCAP_RXCSUM)
@@ -835,7 +861,13 @@ em_determine_rsstype(uint32_t pkt_info)
return M_HASHTYPE_RSS_IPV6;
case E1000_RXDADV_RSSTYPE_IPV6_TCP_EX:
return M_HASHTYPE_RSS_TCP_IPV6_EX;
+ case E1000_RXDADV_RSSTYPE_IPV4_UDP:
+ return M_HASHTYPE_RSS_UDP_IPV4;
+ case E1000_RXDADV_RSSTYPE_IPV6_UDP:
+ return M_HASHTYPE_RSS_UDP_IPV6;
+ case E1000_RXDADV_RSSTYPE_IPV6_UDP_EX:
+ return M_HASHTYPE_RSS_UDP_IPV6_EX;
default:
- return M_HASHTYPE_OPAQUE;
+ return M_HASHTYPE_NONE;
}
}
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 7d7655a7ae6f..a3523315d5c7 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -28,6 +28,7 @@
*/
#include "if_em.h"
+#include "if_igb_iov.h"
#include <sys/sbuf.h>
#include <machine/_inttypes.h>
@@ -342,8 +343,6 @@ static const pci_vendor_info_t igb_vendor_info_array[] =
"Intel(R) PRO/1000 ET 82576 (Quad Copper)"),
PVID(0x8086, E1000_DEV_ID_82576_QUAD_COPPER_ET2,
"Intel(R) PRO/1000 ET(2) 82576 (Quad Copper)"),
- PVID(0x8086, E1000_DEV_ID_82576_VF,
- "Intel(R) PRO/1000 82576 Virtual Function"),
PVID(0x8086, E1000_DEV_ID_82580_COPPER,
"Intel(R) I340 82580 (Copper)"),
PVID(0x8086, E1000_DEV_ID_82580_FIBER, "Intel(R) I340 82580 (Fiber)"),
@@ -365,7 +364,6 @@ static const pci_vendor_info_t igb_vendor_info_array[] =
PVID(0x8086, E1000_DEV_ID_I350_FIBER, "Intel(R) I350 (Fiber)"),
PVID(0x8086, E1000_DEV_ID_I350_SERDES, "Intel(R) I350 (SERDES)"),
PVID(0x8086, E1000_DEV_ID_I350_SGMII, "Intel(R) I350 (SGMII)"),
- PVID(0x8086, E1000_DEV_ID_I350_VF, "Intel(R) I350 Virtual Function"),
PVID(0x8086, E1000_DEV_ID_I210_COPPER, "Intel(R) I210 (Copper)"),
PVID(0x8086, E1000_DEV_ID_I210_COPPER_IT,
"Intel(R) I210 IT (Copper)"),
@@ -389,13 +387,29 @@ static const pci_vendor_info_t igb_vendor_info_array[] =
PVID_END
};
+static const pci_vendor_info_t igbv_vendor_info_array[] = {
+ PVID(0x8086, E1000_DEV_ID_82576_VF,
+ "Intel(R) PRO/1000 82576 Virtual Function"),
+ PVID(0x8086, E1000_DEV_ID_82576_VF_HV,
+ "Intel(R) PRO/1000 82576 Virtual Function"),
+ PVID(0x8086, E1000_DEV_ID_I350_VF,
+ "Intel(R) I350 Virtual Function"),
+ PVID(0x8086, E1000_DEV_ID_I350_VF_HV,
+ "Intel(R) I350 Virtual Function"),
+ PVID_END
+};
+
/*********************************************************************
* Function prototypes
*********************************************************************/
static void *em_register(device_t);
static void *igb_register(device_t);
-static int em_if_attach_pre(if_ctx_t);
-static int em_if_attach_post(if_ctx_t);
+static void *igbv_register(device_t);
+static int igb_device_attach(device_t);
+#ifdef PCI_IOV
+static int igb_device_iov_init(device_t, uint16_t, const nvlist_t *);
+static void igb_device_iov_uninit(device_t);
+#endif
static int em_if_detach(if_ctx_t);
static int em_if_shutdown(if_ctx_t);
static int em_if_suspend(if_ctx_t);
@@ -417,7 +431,6 @@ static int em_if_mtu_set(if_ctx_t, uint32_t);
static void em_if_timer(if_ctx_t, uint16_t);
static void em_if_vlan_register(if_ctx_t, u16);
static void em_if_vlan_unregister(if_ctx_t, u16);
-static void em_if_watchdog_reset(if_ctx_t);
static bool em_if_needs_restart(if_ctx_t, enum iflib_restart_event);
static void em_identify_hardware(if_ctx_t);
@@ -441,15 +454,17 @@ static int igb_if_tx_queue_intr_enable(if_ctx_t, uint16_t);
static void em_if_multi_set(if_ctx_t);
static void em_if_update_admin_status(if_ctx_t);
static void em_if_debug(if_ctx_t);
+static void em_initialize_vf_stats(struct e1000_softc *);
+static void em_rebase_vf_stats(struct e1000_softc *);
static void em_update_vf_stats_counters(struct e1000_softc *);
-static void em_update_stats_counters(struct e1000_softc *);
static void em_add_hw_stats(struct e1000_softc *);
static int em_if_set_promisc(if_ctx_t, int);
+static bool em_if_defer_promisc(struct e1000_softc *);
static bool em_if_vlan_filter_capable(if_ctx_t);
static bool em_if_vlan_filter_used(if_ctx_t);
static void em_if_vlan_filter_enable(struct e1000_softc *);
static void em_if_vlan_filter_disable(struct e1000_softc *);
-static void em_if_vlan_filter_write(struct e1000_softc *);
+static void em_if_vlan_filter_write(struct e1000_softc *, int);
static void em_setup_vlan_hw_support(if_ctx_t ctx);
static int em_sysctl_nvm_info(SYSCTL_HANDLER_ARGS);
static void em_print_nvm_info(struct e1000_softc *);
@@ -460,9 +475,8 @@ static int em_sysctl_print_fw_version(SYSCTL_HANDLER_ARGS);
static int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
static int em_get_rs(SYSCTL_HANDLER_ARGS);
static void em_print_debug_info(struct e1000_softc *);
-static int em_is_valid_ether_addr(u8 *);
static void em_newitr(struct e1000_softc *, struct em_rx_queue *,
- struct tx_ring *, struct rx_ring *);
+ struct rx_ring *);
static bool em_automask_tso(if_ctx_t);
static int em_sysctl_tso_tcp_flags_mask(SYSCTL_HANDLER_ARGS);
static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS);
@@ -493,9 +507,9 @@ static int igb_sysctl_dmac(SYSCTL_HANDLER_ARGS);
static void em_if_led_func(if_ctx_t, int);
static int em_get_regs(SYSCTL_HANDLER_ARGS);
-
static void lem_smartspeed(struct e1000_softc *);
static void igb_configure_queues(struct e1000_softc *);
+static void igb_initialize_interrupt_rate(struct e1000_softc *);
static void em_flush_desc_rings(struct e1000_softc *);
@@ -518,6 +532,23 @@ static device_method_t igb_methods[] = {
/* Device interface */
DEVMETHOD(device_register, igb_register),
DEVMETHOD(device_probe, iflib_device_probe),
+ DEVMETHOD(device_attach, igb_device_attach),
+ DEVMETHOD(device_detach, iflib_device_detach),
+ DEVMETHOD(device_shutdown, iflib_device_shutdown),
+ DEVMETHOD(device_suspend, iflib_device_suspend),
+ DEVMETHOD(device_resume, iflib_device_resume),
+#ifdef PCI_IOV
+ DEVMETHOD(pci_iov_init, igb_device_iov_init),
+ DEVMETHOD(pci_iov_uninit, igb_device_iov_uninit),
+ DEVMETHOD(pci_iov_add_vf, iflib_device_iov_add_vf),
+#endif
+ DEVMETHOD_END
+};
+
+static device_method_t igbv_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_register, igbv_register),
+ DEVMETHOD(device_probe, iflib_device_probe),
DEVMETHOD(device_attach, iflib_device_attach),
DEVMETHOD(device_detach, iflib_device_detach),
DEVMETHOD(device_shutdown, iflib_device_shutdown),
@@ -551,6 +582,18 @@ MODULE_DEPEND(igb, iflib, 1, 1, 1);
IFLIB_PNP_INFO(pci, igb, igb_vendor_info_array);
+static driver_t igbv_driver = {
+ "igbv", igbv_methods, sizeof(struct e1000_softc),
+};
+
+DRIVER_MODULE(igbv, pci, igbv_driver, 0, 0);
+
+MODULE_DEPEND(igbv, pci, 1, 1, 1);
+MODULE_DEPEND(igbv, ether, 1, 1, 1);
+MODULE_DEPEND(igbv, iflib, 1, 1, 1);
+
+IFLIB_PNP_INFO(pci, igbv_driver, igbv_vendor_info_array);
+
static device_method_t em_if_methods[] = {
DEVMETHOD(ifdi_attach_pre, em_if_attach_pre),
DEVMETHOD(ifdi_attach_post, em_if_attach_post),
@@ -573,7 +616,6 @@ static device_method_t em_if_methods[] = {
DEVMETHOD(ifdi_mtu_set, em_if_mtu_set),
DEVMETHOD(ifdi_promisc_set, em_if_set_promisc),
DEVMETHOD(ifdi_timer, em_if_timer),
- DEVMETHOD(ifdi_watchdog_reset, em_if_watchdog_reset),
DEVMETHOD(ifdi_vlan_register, em_if_vlan_register),
DEVMETHOD(ifdi_vlan_unregister, em_if_vlan_unregister),
DEVMETHOD(ifdi_get_counter, em_if_get_counter),
@@ -611,7 +653,6 @@ static device_method_t igb_if_methods[] = {
DEVMETHOD(ifdi_mtu_set, em_if_mtu_set),
DEVMETHOD(ifdi_promisc_set, em_if_set_promisc),
DEVMETHOD(ifdi_timer, em_if_timer),
- DEVMETHOD(ifdi_watchdog_reset, em_if_watchdog_reset),
DEVMETHOD(ifdi_vlan_register, em_if_vlan_register),
DEVMETHOD(ifdi_vlan_unregister, em_if_vlan_unregister),
DEVMETHOD(ifdi_get_counter, em_if_get_counter),
@@ -620,6 +661,12 @@ static device_method_t igb_if_methods[] = {
DEVMETHOD(ifdi_tx_queue_intr_enable, igb_if_tx_queue_intr_enable),
DEVMETHOD(ifdi_debug, em_if_debug),
DEVMETHOD(ifdi_needs_restart, em_if_needs_restart),
+#ifdef PCI_IOV
+ DEVMETHOD(ifdi_iov_init, igb_if_iov_init),
+ DEVMETHOD(ifdi_iov_uninit, igb_if_iov_uninit),
+ DEVMETHOD(ifdi_iov_vf_add, igb_if_iov_vf_add),
+ DEVMETHOD(ifdi_vf_status, igb_if_vf_status),
+#endif
DEVMETHOD_END
};
@@ -627,6 +674,42 @@ static driver_t igb_if_driver = {
"igb_if", igb_if_methods, sizeof(struct e1000_softc)
};
+static device_method_t igbv_if_methods[] = {
+ DEVMETHOD(ifdi_attach_pre, igbv_if_attach_pre),
+ DEVMETHOD(ifdi_attach_post, igbv_if_attach_post),
+ DEVMETHOD(ifdi_detach, em_if_detach),
+ DEVMETHOD(ifdi_shutdown, em_if_shutdown),
+ DEVMETHOD(ifdi_suspend, em_if_suspend),
+ DEVMETHOD(ifdi_resume, em_if_resume),
+ DEVMETHOD(ifdi_init, em_if_init),
+ DEVMETHOD(ifdi_stop, em_if_stop),
+ DEVMETHOD(ifdi_msix_intr_assign, em_if_msix_intr_assign),
+ DEVMETHOD(ifdi_intr_enable, igbv_if_intr_enable),
+ DEVMETHOD(ifdi_intr_disable, igbv_if_intr_disable),
+ DEVMETHOD(ifdi_tx_queues_alloc, em_if_tx_queues_alloc),
+ DEVMETHOD(ifdi_rx_queues_alloc, em_if_rx_queues_alloc),
+ DEVMETHOD(ifdi_queues_free, em_if_queues_free),
+ DEVMETHOD(ifdi_update_admin_status, igbv_if_update_admin_status),
+ DEVMETHOD(ifdi_multi_set, em_if_multi_set),
+ DEVMETHOD(ifdi_media_status, em_if_media_status),
+ DEVMETHOD(ifdi_media_change, igbv_if_media_change),
+ DEVMETHOD(ifdi_mtu_set, em_if_mtu_set),
+ DEVMETHOD(ifdi_promisc_set, em_if_set_promisc),
+ DEVMETHOD(ifdi_timer, em_if_timer),
+ DEVMETHOD(ifdi_vlan_register, em_if_vlan_register),
+ DEVMETHOD(ifdi_vlan_unregister, em_if_vlan_unregister),
+ DEVMETHOD(ifdi_get_counter, em_if_get_counter),
+ DEVMETHOD(ifdi_rx_queue_intr_enable, igb_if_rx_queue_intr_enable),
+ DEVMETHOD(ifdi_tx_queue_intr_enable, igb_if_tx_queue_intr_enable),
+ DEVMETHOD(ifdi_debug, em_if_debug),
+ DEVMETHOD(ifdi_needs_restart, em_if_needs_restart),
+ DEVMETHOD_END
+};
+
+static driver_t igbv_if_driver = {
+ "igbv_if", igbv_if_methods, sizeof(struct e1000_softc)
+};
+
/*********************************************************************
* Tunable default values.
*********************************************************************/
@@ -760,6 +843,40 @@ static struct if_shared_ctx igb_sctx_init = {
.isc_ntxd_default = {EM_DEFAULT_TXD},
};
+/*
+ * igb PFs and igbv VFs share the common datapath implementation. Keep a
+ * separate ifdi policy for VFs so they cannot inherit PF-only callbacks or
+ * interrupt modes.
+ */
+static struct if_shared_ctx igbv_sctx_init = {
+ .isc_magic = IFLIB_MAGIC,
+ .isc_q_align = PAGE_SIZE,
+ .isc_tx_maxsize = EM_TSO_SIZE + sizeof(struct ether_vlan_header),
+ .isc_tx_maxsegsize = PAGE_SIZE,
+ .isc_tso_maxsize = EM_TSO_SIZE + sizeof(struct ether_vlan_header),
+ .isc_tso_maxsegsize = EM_TSO_SEG_SIZE,
+ .isc_rx_maxsize = MJUM9BYTES,
+ .isc_rx_nsegments = 1,
+ .isc_rx_maxsegsize = MJUM9BYTES,
+ .isc_nfl = 1,
+ .isc_nrxqs = 1,
+ .isc_ntxqs = 1,
+ .isc_admin_intrcnt = 1,
+ .isc_vendor_info = igbv_vendor_info_array,
+ .isc_driver_version = igb_driver_version,
+ .isc_driver = &igbv_if_driver,
+ .isc_flags =
+ IFLIB_NEED_SCRATCH | IFLIB_TSO_INIT_IP | IFLIB_NEED_ZERO_CSUM |
+ IFLIB_IS_VF,
+
+ .isc_nrxd_min = {EM_MIN_RXD},
+ .isc_ntxd_min = {EM_MIN_TXD},
+ .isc_nrxd_max = {IGB_MAX_RXD},
+ .isc_ntxd_max = {IGB_MAX_TXD},
+ .isc_nrxd_default = {EM_DEFAULT_RXD},
+ .isc_ntxd_default = {EM_DEFAULT_TXD},
+};
+
/*****************************************************************
*
* Dump Registers
@@ -774,9 +891,19 @@ static int em_get_regs(SYSCTL_HANDLER_ARGS)
struct sbuf *sb;
u32 *regs_buff;
int rc;
+ uint32_t rxqid, txqid;
+
+ /*
+ * This sysctl is registered before iflib allocates the queue arrays,
+ * and remains registered while iflib tears them down.
+ */
+ if (sc->rx_queues == NULL || sc->tx_queues == NULL)
+ return (ENXIO);
regs_buff = malloc(sizeof(u32) * IGB_REGS_LEN, M_DEVBUF, M_WAITOK);
memset(regs_buff, 0, IGB_REGS_LEN * sizeof(u32));
+ rxqid = sc->rx_queues[0].rxr.me;
+ txqid = sc->tx_queues[0].txr.me;
rc = sysctl_wire_old_buffer(req, 0);
MPASS(rc == 0);
@@ -798,19 +925,19 @@ static int em_get_regs(SYSCTL_HANDLER_ARGS)
regs_buff[2] = E1000_READ_REG(hw, E1000_CTRL_EXT);
regs_buff[3] = E1000_READ_REG(hw, E1000_ICR);
regs_buff[4] = E1000_READ_REG(hw, E1000_RCTL);
- regs_buff[5] = E1000_READ_REG(hw, E1000_RDLEN(0));
- regs_buff[6] = E1000_READ_REG(hw, E1000_RDH(0));
- regs_buff[7] = E1000_READ_REG(hw, E1000_RDT(0));
- regs_buff[8] = E1000_READ_REG(hw, E1000_RXDCTL(0));
- regs_buff[9] = E1000_READ_REG(hw, E1000_RDBAL(0));
- regs_buff[10] = E1000_READ_REG(hw, E1000_RDBAH(0));
+ regs_buff[5] = E1000_READ_REG(hw, E1000_RDLEN(rxqid));
+ regs_buff[6] = E1000_READ_REG(hw, E1000_RDH(rxqid));
+ regs_buff[7] = E1000_READ_REG(hw, E1000_RDT(rxqid));
+ regs_buff[8] = E1000_READ_REG(hw, E1000_RXDCTL(rxqid));
+ regs_buff[9] = E1000_READ_REG(hw, E1000_RDBAL(rxqid));
+ regs_buff[10] = E1000_READ_REG(hw, E1000_RDBAH(rxqid));
regs_buff[11] = E1000_READ_REG(hw, E1000_TCTL);
- regs_buff[12] = E1000_READ_REG(hw, E1000_TDBAL(0));
- regs_buff[13] = E1000_READ_REG(hw, E1000_TDBAH(0));
- regs_buff[14] = E1000_READ_REG(hw, E1000_TDLEN(0));
- regs_buff[15] = E1000_READ_REG(hw, E1000_TDH(0));
- regs_buff[16] = E1000_READ_REG(hw, E1000_TDT(0));
- regs_buff[17] = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ regs_buff[12] = E1000_READ_REG(hw, E1000_TDBAL(txqid));
+ regs_buff[13] = E1000_READ_REG(hw, E1000_TDBAH(txqid));
+ regs_buff[14] = E1000_READ_REG(hw, E1000_TDLEN(txqid));
+ regs_buff[15] = E1000_READ_REG(hw, E1000_TDH(txqid));
+ regs_buff[16] = E1000_READ_REG(hw, E1000_TDT(txqid));
+ regs_buff[17] = E1000_READ_REG(hw, E1000_TXDCTL(txqid));
regs_buff[18] = E1000_READ_REG(hw, E1000_TDFH);
regs_buff[19] = E1000_READ_REG(hw, E1000_TDFT);
regs_buff[20] = E1000_READ_REG(hw, E1000_TDFHS);
@@ -897,6 +1024,65 @@ igb_register(device_t dev)
return (&igb_sctx_init);
}
+static void *
+igbv_register(device_t dev)
+{
+ return (&igbv_sctx_init);
+}
+
+static int
+igb_device_attach(device_t dev)
+{
+ struct e1000_softc *sc;
+ if_ctx_t ctx;
+ int error;
+
+ error = iflib_device_attach(dev);
+ if (error != 0)
+ return (error);
+
+ ctx = device_get_softc(dev);
+ sc = iflib_get_softc(ctx);
+ (void)igb_iov_attach(sc);
+ return (0);
+}
+
+#ifdef PCI_IOV
+static int
+igb_device_iov_init(device_t dev, uint16_t num_vfs,
+ const nvlist_t *params)
+{
+ struct e1000_softc *sc;
+ if_ctx_t ctx;
+ int error;
+
+ ctx = device_get_softc(dev);
+ sc = iflib_get_softc(ctx);
+ error = igb_iov_validate(sc, num_vfs);
+ if (error != 0)
+ return (error);
+ return (iflib_device_iov_init_restart(dev, num_vfs, params));
+}
+
+static void
+igb_device_iov_uninit(device_t dev)
+{
+ struct e1000_softc *sc;
+ if_ctx_t ctx;
+
+ ctx = device_get_softc(dev);
+ sc = iflib_get_softc(ctx);
+ /*
+ * pci_iov(4) has already detached the VF devices. Tell the stop
+ * half of iflib's restart transaction not to wait for acknowledgements
+ * from VFs which can no longer service their mailbox vectors.
+ */
+ atomic_store_rel_32(&sc->iov_teardown, 1);
+ iflib_device_iov_uninit_restart(dev);
+}
+
+#endif
+
static int
em_set_num_queues(if_ctx_t ctx)
{
@@ -919,6 +1105,11 @@ em_set_num_queues(if_ctx_t ctx)
case e1000_82574:
maxqueues = 2;
break;
+ case e1000_vfadapt:
+ /* Keep 82576 VFs at one RX/TX queue for mixed-driver safety. */
+ case e1000_vfadapt_i350:
+ maxqueues = 1;
+ break;
default:
maxqueues = 1;
break;
@@ -927,90 +1118,75 @@ em_set_num_queues(if_ctx_t ctx)
return (maxqueues);
}
-#define LEM_CAPS \
+#define LEM_CAPS ( \
IFCAP_HWCSUM | IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | \
IFCAP_VLAN_HWCSUM | IFCAP_WOL | IFCAP_VLAN_HWFILTER | IFCAP_TSO4 | \
- IFCAP_LRO | IFCAP_VLAN_HWTSO | IFCAP_JUMBO_MTU | IFCAP_HWCSUM_IPV6
+ IFCAP_LRO | IFCAP_VLAN_HWTSO | IFCAP_JUMBO_MTU | IFCAP_HWCSUM_IPV6)
-#define EM_CAPS \
+#define EM_CAPS ( \
IFCAP_HWCSUM | IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | \
IFCAP_VLAN_HWCSUM | IFCAP_WOL | IFCAP_VLAN_HWFILTER | IFCAP_TSO4 | \
IFCAP_LRO | IFCAP_VLAN_HWTSO | IFCAP_JUMBO_MTU | IFCAP_HWCSUM_IPV6 | \
- IFCAP_TSO6
+ IFCAP_TSO6)
-#define IGB_CAPS \
+#define IGB_CAPS ( \
IFCAP_HWCSUM | IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | \
IFCAP_VLAN_HWCSUM | IFCAP_WOL | IFCAP_VLAN_HWFILTER | IFCAP_TSO4 | \
IFCAP_LRO | IFCAP_VLAN_HWTSO | IFCAP_JUMBO_MTU | IFCAP_HWCSUM_IPV6 | \
- IFCAP_TSO6
+ IFCAP_TSO6)
-/*********************************************************************
- * Device initialization routine
- *
- * The attach entry point is called when the driver is being loaded.
- * This routine identifies the type of hardware, allocates all resources
- * and initializes the hardware.
- *
- * return 0 on success, positive on failure
- *********************************************************************/
-static int
-em_if_attach_pre(if_ctx_t ctx)
+/*
+ * VLAN filtering is an effective VF capability, but its policy is owned by
+ * the PF and cannot be disabled from the VF. vlan(4) registration callbacks
+ * are independent of this capability bit.
+ */
+#define IGBV_CAPS (IGB_CAPS & ~IFCAP_WOL)
+
+void
+em_add_device_sysctls(struct e1000_softc *sc)
{
- struct e1000_softc *sc;
- if_softc_ctx_t scctx;
- device_t dev;
struct e1000_hw *hw;
struct sysctl_oid_list *child;
struct sysctl_ctx_list *ctx_list;
- int error = 0;
- INIT_DEBUGOUT("em_if_attach_pre: begin");
- dev = iflib_get_dev(ctx);
- sc = iflib_get_softc(ctx);
-
- sc->ctx = sc->osdep.ctx = ctx;
- sc->dev = sc->osdep.dev = dev;
- scctx = sc->shared = iflib_get_softc_ctx(ctx);
- sc->media = iflib_get_media(ctx);
hw = &sc->hw;
-
- /* Determine hardware and mac info */
- em_identify_hardware(ctx);
-
- /* SYSCTL stuff */
- ctx_list = device_get_sysctl_ctx(dev);
- child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
-
- SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "nvm",
- CTLTYPE_INT | CTLFLAG_RW, sc, 0,
- em_sysctl_nvm_info, "I", "NVM Information");
+ ctx_list = device_get_sysctl_ctx(sc->dev);
+ child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
sc->enable_aim = em_enable_aim;
SYSCTL_ADD_INT(ctx_list, child, OID_AUTO, "enable_aim",
CTLFLAG_RW, &sc->enable_aim, 0,
"Interrupt Moderation (1=normal, 2=lowlatency)");
- SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "fw_version",
- CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
- em_sysctl_print_fw_version, "A",
- "Prints FW/NVM Versions");
-
SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "debug",
CTLTYPE_INT | CTLFLAG_RW, sc, 0,
em_sysctl_debug_info, "I", "Debug Information");
+ SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "rs_dump",
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
+ em_get_rs, "I", "Dump RS indexes");
+
+ if (sc->vf_ifp) {
+ SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "reg_dump",
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,
+ igbv_get_regs, "A", "Dump VF registers");
+ return;
+ }
+
+ SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "nvm",
+ CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ em_sysctl_nvm_info, "I", "NVM Information");
+ SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "fw_version",
+ CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
+ em_sysctl_print_fw_version, "A",
+ "Prints FW/NVM Versions");
SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "fc",
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
em_set_flowcntl, "I", "Flow Control");
-
SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "reg_dump",
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,
em_get_regs, "A", "Dump Registers");
- SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "rs_dump",
- CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
- em_get_rs, "I", "Dump RS indexes");
-
if (hw->mac.type >= e1000_i350) {
SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "dmac",
CTLTYPE_INT | CTLFLAG_RW, sc, 0,
@@ -1022,18 +1198,67 @@ em_if_attach_pre(if_ctx_t ctx)
CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
sc, 0, em_sysctl_tso_tcp_flags_mask, "IU",
"TSO TCP flags mask for first segment");
-
SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO,
"tso_tcp_flags_mask_middle_segment",
CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
sc, 1, em_sysctl_tso_tcp_flags_mask, "IU",
"TSO TCP flags mask for middle segment");
-
SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO,
"tso_tcp_flags_mask_last_segment",
CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
sc, 2, em_sysctl_tso_tcp_flags_mask, "IU",
"TSO TCP flags mask for last segment");
+}
+
+/*********************************************************************
+ * Device initialization routine
+ *
+ * The attach entry point is called when the driver is being loaded.
+ * This routine identifies the type of hardware, allocates all resources
+ * and initializes the hardware.
+ *
+ * return 0 on success, positive on failure
+ *********************************************************************/
+int
+em_if_attach_pre(if_ctx_t ctx)
+{
+ struct e1000_softc *sc;
+ if_softc_ctx_t scctx;
+ device_t dev;
+ struct e1000_hw *hw;
+ struct sysctl_oid_list *child;
+ struct sysctl_ctx_list *ctx_list;
+ int error = 0;
+
+ INIT_DEBUGOUT("em_if_attach_pre: begin");
+ dev = iflib_get_dev(ctx);
+ sc = iflib_get_softc(ctx);
+
+ if (em_max_interrupt_rate <= 0) {
+ device_printf(dev,
+ "Invalid max_interrupt_rate %d; using default %d\n",
+ em_max_interrupt_rate, EM_INTS_DEFAULT);
+ em_max_interrupt_rate = EM_INTS_DEFAULT;
+ }
+
+ sc->ctx = sc->osdep.ctx = ctx;
+ sc->dev = sc->osdep.dev = dev;
+ scctx = sc->shared = iflib_get_softc_ctx(ctx);
+ sc->media = iflib_get_media(ctx);
+ hw = &sc->hw;
+ sc->vf_ifp =
+ (iflib_get_sctx(ctx)->isc_flags & IFLIB_IS_VF) != 0;
+ sc->osdep.vf = sc->vf_ifp;
+
+ /* Determine hardware and mac info */
+ em_identify_hardware(ctx);
+ sc->osdep.vf_82576 = sc->hw.mac.type == e1000_vfadapt;
+
+ /* VF sysctls are deferred until attach-post confirms MSI-X. */
+ ctx_list = device_get_sysctl_ctx(dev);
+ child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
+ if (!sc->vf_ifp)
+ em_add_device_sysctls(sc);
scctx->isc_tx_nsegments = EM_MAX_SCATTER;
scctx->isc_nrxqsets_max =
@@ -1053,7 +1278,8 @@ em_if_attach_pre(if_ctx_t ctx)
scctx->isc_tx_tso_segments_max = EM_MAX_SCATTER;
scctx->isc_tx_tso_size_max = EM_TSO_SIZE;
scctx->isc_tx_tso_segsize_max = EM_TSO_SEG_SIZE;
- scctx->isc_capabilities = scctx->isc_capenable = IGB_CAPS;
+ scctx->isc_capabilities = scctx->isc_capenable =
+ sc->vf_ifp ? IGBV_CAPS : IGB_CAPS;
scctx->isc_tx_csum_flags = CSUM_TCP | CSUM_UDP | CSUM_TSO |
CSUM_IP6_TCP | CSUM_IP6_UDP;
if (hw->mac.type != e1000_82575)
@@ -1218,6 +1444,27 @@ em_if_attach_pre(if_ctx_t ctx)
em_setup_msix(ctx);
e1000_get_bus_info(hw);
+ /*
+ * Some conventional PCI systems hang when e1000 devices use
+ * DMA addresses above 4 GB. Keep PCI-mode DMA below that boundary
+ * by default; PCI-X and PCIe retain 64-bit DMA.
+ */
+ if (hw->bus.type == e1000_bus_type_pci) {
+ SYSCTL_ADD_BOOL(ctx_list, child, OID_AUTO, "allow_64bit_dma",
+ CTLFLAG_RDTUN, &sc->allow_64bit_dma, 0,
+ "Allow 64-bit DMA in conventional PCI mode");
+ if (sc->allow_64bit_dma)
+ device_printf(dev, "64-bit DMA in conventional PCI mode. "
+ "Some chipsets are unstable.\n");
+ else {
+ scctx->isc_dma_width = 32;
+ device_printf(dev, "32-bit DMA in conventional PCI mode. "
+ "Set dev.%s.%d.allow_64bit_dma=1 at boot to enable "
+ "64-bit DMA if the chipset is stable with it.\n",
+ device_get_name(dev), device_get_unit(dev));
+ }
+ }
+
/* Set up some sysctls for the tunable interrupt delays */
if (hw->mac.type < igb_mac_min) {
em_add_int_delay_sysctl(sc, "rx_int_delay",
@@ -1279,29 +1526,37 @@ em_if_attach_pre(if_ctx_t ctx)
/* Clear the IFCAP_TSO auto mask */
sc->tso_automasked = 0;
- /* Check SOL/IDER usage */
- if (e1000_check_reset_block(hw))
+ /* Check SOL/IDER usage on physical functions. */
+ if (!sc->vf_ifp && e1000_check_reset_block(hw))
device_printf(dev,
"PHY reset is blocked due to SOL/IDER session.\n");
/* Sysctl for setting Energy Efficient Ethernet */
- if (hw->mac.type < igb_mac_min)
- hw->dev_spec.ich8lan.eee_disable = eee_setting;
- else
- hw->dev_spec._82575.eee_disable = eee_setting;
- SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "eee_control",
- CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
- em_sysctl_eee, "I", "Disable Energy Efficient Ethernet");
+ if (!sc->vf_ifp) {
+ if (hw->mac.type < igb_mac_min)
+ hw->dev_spec.ich8lan.eee_disable = eee_setting;
+ else
+ hw->dev_spec._82575.eee_disable = eee_setting;
+ SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "eee_control",
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
+ em_sysctl_eee, "I", "Disable Energy Efficient Ethernet");
+ }
/*
** Start from a known state, this is
** important in reading the nvm and
** mac from that.
*/
- e1000_reset_hw(hw);
+ error = e1000_reset_hw(hw);
+ if (sc->vf_ifp) {
+ atomic_store_rel_32(&sc->vf_mbx_ready,
+ error == E1000_SUCCESS);
+ if (error != E1000_SUCCESS)
+ igbv_log_reset_failure(sc, error, true);
+ }
- /* Make sure we have a good EEPROM before we read from it */
- if (e1000_validate_nvm_checksum(hw) < 0) {
+ /* Make sure a PF has a good EEPROM before we read from it. */
+ if (!sc->vf_ifp && e1000_validate_nvm_checksum(hw) < 0) {
/*
** Some PCI-E parts fail the first check due to
** the link being in sleep state, call it again,
@@ -1325,6 +1580,9 @@ em_if_attach_pre(if_ctx_t ctx)
if (!em_is_valid_ether_addr(hw->mac.addr)) {
if (sc->vf_ifp) {
+ device_printf(dev,
+ "PF did not assign a MAC address; using a "
+ "locally generated address\n");
ether_gen_addr(iflib_get_ifp(ctx),
(struct ether_addr *)hw->mac.addr);
} else {
@@ -1334,20 +1592,23 @@ em_if_attach_pre(if_ctx_t ctx)
}
}
- /* Save the EEPROM/NVM versions, must be done under IFLIB_CTX_LOCK */
- em_fw_version_locked(ctx);
-
- em_print_fw_version(sc);
+ if (!sc->vf_ifp) {
+ /* Save NVM versions while holding the IFLIB context lock. */
+ em_fw_version_locked(ctx);
+ em_print_fw_version(sc);
+ }
/*
* Get Wake-on-Lan and Management info for later use
*/
- em_get_wakeup(ctx);
+ if (!sc->vf_ifp) {
+ em_get_wakeup(ctx);
- /* Enable only WOL MAGIC by default */
- scctx->isc_capenable &= ~IFCAP_WOL;
- if (sc->wol != 0)
- scctx->isc_capenable |= IFCAP_WOL_MAGIC;
+ /* Enable only WOL MAGIC by default. */
+ scctx->isc_capenable &= ~IFCAP_WOL;
+ if (sc->wol != 0)
+ scctx->isc_capenable |= IFCAP_WOL_MAGIC;
+ }
iflib_set_mac(ctx, hw->mac.addr);
@@ -1358,11 +1619,12 @@ err_late:
err_pci:
em_free_pci_resources(ctx);
free(sc->mta, M_DEVBUF);
+ sc->mta = NULL;
return (error);
}
-static int
+int
em_if_attach_post(if_ctx_t ctx)
{
struct e1000_softc *sc = iflib_get_softc(ctx);
@@ -1376,17 +1638,24 @@ em_if_attach_post(if_ctx_t ctx)
goto err_late;
}
- em_reset(ctx);
+ if (sc->vf_ifp)
+ (void)igbv_reset(ctx);
+ else
+ em_reset(ctx);
/* Initialize statistics */
if (sc->vf_ifp)
- sc->ustats.vf_stats = (struct e1000_vf_stats){};
+ em_initialize_vf_stats(sc);
else
sc->ustats.stats = (struct e1000_hw_stats){};
em_update_stats_counters(sc);
+ atomic_readandclear_32(&sc->stats_pending);
hw->mac.get_link_status = 1;
- em_if_update_admin_status(ctx);
+ if (sc->vf_ifp)
+ igbv_if_update_admin_status(ctx);
+ else
+ em_if_update_admin_status(ctx);
em_add_hw_stats(sc);
/* Non-AMT based hardware can now take control from firmware */
@@ -1421,7 +1690,13 @@ em_if_detach(if_ctx_t ctx)
INIT_DEBUGOUT("em_if_detach: begin");
- e1000_phy_hw_reset(&sc->hw);
+ igb_iov_detach(sc);
+ if (sc->vf_ifp) {
+ igbv_queue_retry_detach(sc);
+ igbv_mbx_retry_detach(sc);
+ } else {
+ e1000_phy_hw_reset(&sc->hw);
+ }
em_release_manageability(sc);
em_release_hw_control(sc);
@@ -1452,6 +1727,10 @@ em_if_suspend(if_ctx_t ctx)
{
struct e1000_softc *sc = iflib_get_softc(ctx);
+ if (sc->vf_ifp) {
+ igbv_queue_retry_stop(sc);
+ igbv_mbx_retry_stop(sc);
+ }
em_release_manageability(sc);
em_release_hw_control(sc);
em_enable_wakeup(ctx);
@@ -1465,8 +1744,6 @@ em_if_resume(if_ctx_t ctx)
if (sc->hw.mac.type == e1000_pch2lan)
e1000_resume_workarounds_pchlan(&sc->hw);
- em_if_init(ctx);
- em_init_manageability(sc);
return(0);
}
@@ -1509,7 +1786,7 @@ em_if_mtu_set(if_ctx_t ctx, uint32_t mtu)
break;
default:
if (sc->hw.mac.type >= igb_mac_min)
- max_frame_size = 9234;
+ max_frame_size = IGB_MAX_FRAME_SIZE;
else /* lem */
max_frame_size = MAX_JUMBO_FRAME_SIZE;
}
@@ -1541,12 +1818,21 @@ em_if_init(if_ctx_t ctx)
int i;
INIT_DEBUGOUT("em_if_init: begin");
+ if (sc->vf_ifp) {
+ igbv_queue_retry_prepare(sc);
+ igbv_mbx_retry_prepare(sc);
+ sc->vf_reset_pending = true;
+ }
/* Get the latest mac address, User can use a LAA */
bcopy(if_getlladdr(ifp), sc->hw.mac.addr, ETHER_ADDR_LEN);
- /* Put the address into the Receive Address Array */
- e1000_rar_set(&sc->hw, sc->hw.mac.addr, 0);
+ /*
+ * A VF restores its address only after its reset handshake establishes
+ * CTS. The PF path programs RAR[0] directly here.
+ */
+ if (!sc->vf_ifp)
+ e1000_rar_set(&sc->hw, sc->hw.mac.addr, 0);
/*
* With the 82571 adapter, RAR[0] may be overwritten
@@ -1561,8 +1847,38 @@ em_if_init(if_ctx_t ctx)
}
/* Initialize the hardware */
- em_reset(ctx);
- em_if_update_admin_status(ctx);
+ igb_iov_reset_prepare(sc);
+ if (sc->vf_ifp) {
+ (void)igbv_reset(ctx);
+ em_rebase_vf_stats(sc);
+ } else {
+ em_reset(ctx);
+ }
+ if (sc->vf_ifp && !sc->vf_queues_sanitized) {
+ /*
+ * Do not program or enable rings while retained queue state
+ * might still contain a previous VF owner's DMA address. A
+ * bounded callout retries initialization after iflib leaves the
+ * failed initialization stopped.
+ */
+ igbv_queue_retry_failed(ctx);
+ return;
+ }
+ if (sc->vf_ifp &&
+ atomic_load_acq_32(&sc->vf_mbx_ready) == 0) {
+ igbv_mbx_retry_failed(ctx);
+ return;
+ }
+ if (sc->vf_ifp)
+ igbv_reconcile_mac(sc, ifp);
+ /* Re-arm a link-up transition deferred for this reset. */
+ if (sc->link_state == EM_LINK_STATE_DOWN_RESET_PENDING ||
+ sc->link_state == EM_LINK_STATE_UP_RESET_PENDING)
+ sc->link_state = EM_LINK_STATE_DOWN;
+ if (sc->vf_ifp)
+ igbv_if_update_admin_status(ctx);
+ else
+ em_if_update_admin_status(ctx);
for (i = 0, tx_que = sc->tx_queues; i < sc->tx_num_queues;
i++, tx_que++) {
@@ -1578,8 +1894,9 @@ em_if_init(if_ctx_t ctx)
txr->tx_cidx_processed = scctx->isc_ntxd[0] - 1;
}
- /* Setup VLAN support, basic and offload if available */
- E1000_WRITE_REG(&sc->hw, E1000_VET, ETHERTYPE_VLAN);
+ /* The VF VLAN EtherType is fixed and has no VET register. */
+ if (!sc->vf_ifp)
+ E1000_WRITE_REG(&sc->hw, E1000_VET, ETHERTYPE_VLAN);
/* Clear bad data from Rx FIFOs */
if (sc->hw.mac.type >= igb_mac_min && !sc->vf_ifp)
@@ -1589,19 +1906,33 @@ em_if_init(if_ctx_t ctx)
em_init_manageability(sc);
/* Prepare transmit descriptors and buffers */
- em_initialize_transmit_unit(ctx);
+ if (sc->vf_ifp)
+ igbv_initialize_transmit_unit(ctx);
+ else
+ em_initialize_transmit_unit(ctx);
- /* Setup Multicast table */
+ /*
+ * A failed VF reset has no CTS channel on which to restore mailbox
+ * state. The reset detector schedules another complete init, which
+ * replays these interface-owned lists after the handshake succeeds.
+ */
em_if_multi_set(ctx);
sc->rx_mbuf_sz = iflib_get_rx_mbuf_sz(ctx);
- em_initialize_receive_unit(ctx);
+ if (sc->vf_ifp)
+ igbv_initialize_receive_unit(ctx);
+ else
+ em_initialize_receive_unit(ctx);
- /* Set up VLAN support and filter */
+ /* Set up VLAN support and filter. */
em_setup_vlan_hw_support(ctx);
- /* Don't lose promiscuous settings */
- em_if_set_promisc(ctx, if_getflags(ifp));
+ /* Don't lose promiscuous settings. */
+ em_if_set_promisc_impl(ctx, if_getflags(ifp));
+ atomic_readandclear_32(&sc->promisc_pending);
+
+ /* Restore PF/VF pool configuration after the global reset. */
+ igb_iov_initialize(sc);
if (sc->hw.mac.ops.clear_hw_cntrs != NULL)
sc->hw.mac.ops.clear_hw_cntrs(&sc->hw);
@@ -1618,10 +1949,14 @@ em_if_init(if_ctx_t ctx)
/* Set up queue routing */
igb_configure_queues(sc);
}
+ if (sc->hw.mac.type >= igb_mac_min)
+ igb_initialize_interrupt_rate(sc);
- /* this clears any pending interrupts */
- E1000_READ_REG(&sc->hw, E1000_ICR);
- E1000_WRITE_REG(&sc->hw, E1000_ICS, E1000_ICS_LSC);
+ if (!sc->vf_ifp) {
+ /* Clear pending PF interrupts and request a link check. */
+ E1000_READ_REG(&sc->hw, E1000_ICR);
+ E1000_WRITE_REG(&sc->hw, E1000_ICS, E1000_ICS_LSC);
+ }
/* AMT based hardware can now take control from firmware */
if (sc->has_manage && sc->has_amt)
@@ -1635,14 +1970,105 @@ em_if_init(if_ctx_t ctx)
else
e1000_set_eee_i350(&sc->hw, true, true);
}
+ if (sc->vf_ifp)
+ sc->vf_reset_pending = false;
+}
+
+/*
+ * RX publishes its byte and packet counters as one snapshot when iflib
+ * returns descriptors to hardware. This also covers watchdog-driven RX
+ * processing, which can run while the interrupt vector is unmasked.
+ */
+static __inline void
+em_aim_rx_delta(struct rx_ring *rxr, u32 *bytes, u32 *packets)
+{
+ uint64_t snapshot;
+ u32 now_bytes, now_packets;
+
+ snapshot = atomic_load_acq_64(&rxr->rx_aim_snapshot);
+ now_bytes = snapshot >> 32;
+ now_packets = (u32)snapshot;
+ *bytes = now_bytes - rxr->rx_bytes_last;
+ *packets = now_packets - rxr->rx_packets_last;
+ rxr->rx_bytes_last = now_bytes;
+ rxr->rx_packets_last = now_packets;
+}
+
+/*
+ * TX publishes its byte and packet counters as one snapshot at the doorbell,
+ * because encapsulation can overlap the interrupt filter. The two halves
+ * remain independent free running u32 counters, so their deltas are correct
+ * across wrap.
+ */
+static __inline void
+em_aim_tx_delta(struct tx_ring *txr, u32 *bytes, u32 *packets)
+{
+ uint64_t snapshot;
+ u32 now_bytes, now_packets;
+
+ snapshot = atomic_load_acq_64(&txr->tx_aim_snapshot);
+ now_bytes = snapshot >> 32;
+ now_packets = (u32)snapshot;
+ *bytes = now_bytes - txr->tx_bytes_last;
+ *packets = now_packets - txr->tx_packets_last;
+ txr->tx_bytes_last = now_bytes;
+ txr->tx_packets_last = now_packets;
+}
+
+/*********************************************************************
+ *
+ * Do Adaptive Interrupt Moderation:
+ * - Calculate based on average size over the last interval
+ *
+ * Returns interrupts per second rather than a register value, so that the
+ * caller's EM_INTS_TO_ITR()/IGB_INTS_TO_EITR() conversion applies, or zero
+ * if the interval carried no packet to measure.
+ *
+ *********************************************************************/
+static u32
+em_ring_itr(struct e1000_softc *sc, u32 rxbytes, u32 rxpackets, u32 txbytes,
+ u32 txpackets)
+{
+ u32 newitr = 0;
+
+ if (txbytes && txpackets)
+ newitr = txbytes / txpackets;
+ if (rxbytes && rxpackets)
+ newitr = max(newitr, rxbytes / rxpackets);
+
+ /*
+ * No packet was observed, so there is no size to work from. Report no
+ * observation and let the caller keep the rate it already has.
+ */
+ if (newitr == 0)
+ return (0);
+
+ newitr += 24; /* account for hardware frame, crc */
+ /* set an upper boundary */
+ newitr = min(newitr, 3000);
+ /* Be nice to the mid range */
+ if ((newitr > 300) && (newitr < 1200))
+ newitr = (newitr / 3);
+ else
+ newitr = (newitr / 2);
+
+ /* The value above was written straight to EITR; make it a rate */
+ newitr = EM_AIM_DIVIDEND / newitr;
+
+ /*
+ * Cap the rate: enable_aim=1 is the normal setting, enable_aim=2 opts
+ * into the low latency end. The original was unbounded and would ask
+ * for ~95k ints/s on minimum sized frames. There is deliberately no
+ * floor, so jumbo traffic settles near 2.7k ints/s.
+ */
+ if (sc->enable_aim == 1)
+ newitr = min(newitr, EM_INTS_20K);
+ else
+ newitr = min(newitr, EM_INTS_70K);
+
+ return (newitr);
}
-enum itr_latency_target {
- itr_latency_disabled = 0,
- itr_latency_lowest = 1,
- itr_latency_low = 2,
- itr_latency_bulk = 3
-};
/*********************************************************************
*
* Helper to calculate next (E)ITR value for AIM
@@ -1650,126 +2076,52 @@ enum itr_latency_target {
*********************************************************************/
static void
em_newitr(struct e1000_softc *sc, struct em_rx_queue *que,
- struct tx_ring *txr, struct rx_ring *rxr)
+ struct rx_ring *rxr)
{
struct e1000_hw *hw = &sc->hw;
- unsigned long bytes, bytes_per_packet, packets;
- unsigned long rxbytes, rxpackets, txbytes, txpackets;
+ struct em_tx_queue *tx_que;
+ u32 ringbytes, ringpackets, rxbytes, rxpackets, txbytes, txpackets;
u32 newitr;
- u8 nextlatency;
+ int i;
- rxbytes = atomic_load_long(&rxr->rx_bytes);
- txbytes = atomic_load_long(&txr->tx_bytes);
+ em_aim_rx_delta(rxr, &rxbytes, &rxpackets);
+
+ /*
+ * A vector can service more than one TX ring when iflib is configured
+ * with unequal RX and TX queue counts. Sample every ring routed to
+ * this vector rather than treating the vector as a TX queue index.
+ */
+ txbytes = txpackets = 0;
+ for (i = 0; i < sc->tx_num_queues; i++) {
+ tx_que = &sc->tx_queues[i];
+ if (tx_que->msix != que->msix)
+ continue;
+ em_aim_tx_delta(&tx_que->txr, &ringbytes, &ringpackets);
+ txbytes += ringbytes;
+ txpackets += ringpackets;
+ }
/* Idle, do nothing */
if (txbytes == 0 && rxbytes == 0)
return;
- newitr = 0;
-
- if (sc->enable_aim) {
- nextlatency = rxr->rx_nextlatency;
-
+ if (sc->enable_aim == 0) {
+ newitr = em_max_interrupt_rate;
+ } else if (sc->link_speed < SPEED_1000) {
/* Use half default (4K) ITR if sub-gig */
- if (sc->link_speed != 1000) {
- newitr = EM_INTS_4K;
- goto em_set_next_itr;
- }
- /* Want at least enough packet buffer for two frames to AIM */
- if (sc->shared->isc_max_frame_size * 2 > (sc->pba << 10)) {
- newitr = em_max_interrupt_rate;
- sc->enable_aim = 0;
- goto em_set_next_itr;
- }
-
- bytes = bytes_per_packet = 0;
- /* Get largest values from the associated tx and rx ring */
- txpackets = atomic_load_long(&txr->tx_packets);
- if (txpackets != 0) {
- bytes = txbytes;
- bytes_per_packet = txbytes / txpackets;
- packets = txpackets;
- }
- rxpackets = atomic_load_long(&rxr->rx_packets);
- if (rxpackets != 0) {
- bytes = lmax(bytes, rxbytes);
- bytes_per_packet =
- lmax(bytes_per_packet, rxbytes / rxpackets);
- packets = lmax(packets, rxpackets);
- }
-
- /* Latency state machine */
- switch (nextlatency) {
- case itr_latency_disabled: /* Bootstrapping */
- nextlatency = itr_latency_low;
- break;
- case itr_latency_lowest: /* 70k ints/s */
- /* TSO and jumbo frames */
- if (bytes_per_packet > 8000)
- nextlatency = itr_latency_bulk;
- else if ((packets < 5) && (bytes > 512))
- nextlatency = itr_latency_low;
- break;
- case itr_latency_low: /* 20k ints/s */
- if (bytes > 10000) {
- /* Handle TSO */
- if (bytes_per_packet > 8000)
- nextlatency = itr_latency_bulk;
- else if ((packets < 10) ||
- (bytes_per_packet > 1200))
- nextlatency = itr_latency_bulk;
- else if (packets > 35)
- nextlatency = itr_latency_lowest;
- } else if (bytes_per_packet > 2000) {
- nextlatency = itr_latency_bulk;
- } else if (packets < 3 && bytes < 512) {
- nextlatency = itr_latency_lowest;
- }
- break;
- case itr_latency_bulk: /* 4k ints/s */
- if (bytes > 25000) {
- if (packets > 35)
- nextlatency = itr_latency_low;
- } else if (bytes < 1500)
- nextlatency = itr_latency_low;
- break;
- default:
- nextlatency = itr_latency_low;
- device_printf(sc->dev,
- "Unexpected newitr transition %d\n", nextlatency);
- break;
- }
-
- /* Trim itr_latency_lowest for default AIM setting */
- if (sc->enable_aim == 1 && nextlatency == itr_latency_lowest)
- nextlatency = itr_latency_low;
-
- /* Request new latency */
- rxr->rx_nextlatency = nextlatency;
- } else {
- /* We may have toggled to AIM disabled */
- nextlatency = itr_latency_disabled;
- rxr->rx_nextlatency = nextlatency;
- }
-
- /* ITR state machine */
- switch(nextlatency) {
- case itr_latency_lowest:
- newitr = EM_INTS_70K;
- break;
- case itr_latency_low:
- newitr = EM_INTS_20K;
- break;
- case itr_latency_bulk:
newitr = EM_INTS_4K;
- break;
- case itr_latency_disabled:
- default:
+ } else if (!sc->vf_ifp &&
+ sc->shared->isc_max_frame_size * 2 > (sc->pba << 10)) {
+ /* Want at least enough packet buffer for two frames to AIM */
newitr = em_max_interrupt_rate;
- break;
+ } else {
+ newitr = em_ring_itr(sc, rxbytes, rxpackets, txbytes,
+ txpackets);
+ /* No usable observation; leave the rate where it is */
+ if (newitr == 0)
+ return;
}
-em_set_next_itr:
if (hw->mac.type >= igb_mac_min) {
newitr = IGB_INTS_TO_EITR(newitr);
@@ -1788,7 +2140,8 @@ em_set_next_itr:
if (newitr != que->itr_setting) {
que->itr_setting = newitr;
- if (hw->mac.type == e1000_82574 && que->msix) {
+ if (hw->mac.type == e1000_82574 &&
+ sc->intr_type == IFLIB_INTR_MSIX) {
E1000_WRITE_REG(hw,
E1000_EITR_82574(que->msix),
que->itr_setting);
@@ -1811,7 +2164,6 @@ em_intr(void *arg)
struct e1000_softc *sc = arg;
struct e1000_hw *hw = &sc->hw;
struct em_rx_queue *que = &sc->rx_queues[0];
- struct tx_ring *txr = &sc->tx_queues[0].txr;
struct rx_ring *rxr = &que->rxr;
if_ctx_t ctx = sc->ctx;
u32 reg_icr;
@@ -1850,13 +2202,7 @@ em_intr(void *arg)
sc->rx_overruns++;
if (hw->mac.type >= e1000_82540)
- em_newitr(sc, que, txr, rxr);
-
- /* Reset state */
- txr->tx_bytes = 0;
- txr->tx_packets = 0;
- rxr->rx_bytes = 0;
- rxr->rx_packets = 0;
+ em_newitr(sc, que, rxr);
return (FILTER_SCHEDULE_THREAD);
}
@@ -1911,18 +2257,11 @@ em_msix_que(void *arg)
{
struct em_rx_queue *que = arg;
struct e1000_softc *sc = que->sc;
- struct tx_ring *txr = &sc->tx_queues[que->msix].txr;
struct rx_ring *rxr = &que->rxr;
++que->irqs;
- em_newitr(sc, que, txr, rxr);
-
- /* Reset state */
- txr->tx_bytes = 0;
- txr->tx_packets = 0;
- rxr->rx_bytes = 0;
- rxr->rx_packets = 0;
+ em_newitr(sc, que, rxr);
return (FILTER_SCHEDULE_THREAD);
}
@@ -1940,17 +2279,43 @@ em_msix_link(void *arg)
++sc->link_irq;
MPASS(sc->hw.back != NULL);
+ /*
+ * The VF's admin vector represents mailbox and link activity. It has
+ * no PF ICR at E1000_ICR, so process every admin-vector interrupt,
+ * matching the igbvf misc-vector model.
+ */
+ if (sc->vf_ifp) {
+ sc->hw.mac.get_link_status = true;
+ iflib_admin_intr_deferred(sc->ctx);
+ E1000_WRITE_REG(&sc->hw, E1000_EIMS, sc->link_mask);
+ return (FILTER_HANDLED);
+ }
+
reg_icr = E1000_READ_REG(&sc->hw, E1000_ICR);
+ /*
+ * Enabling or disabling SR-IOV can briefly make PF MMIO reads return
+ * all ones. This is not an interrupt cause; in particular, do not
+ * turn it into a malicious-driver event.
+ */
+ if (__predict_false(reg_icr == 0xffffffff))
+ goto rearm;
+
if (reg_icr & E1000_ICR_RXO)
sc->rx_overruns++;
if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))
em_handle_link(sc->ctx);
+ if (reg_icr & E1000_ICR_MDDET)
+ igb_iov_mdd_event(sc);
+ if (reg_icr & E1000_ICR_VMMB)
+ iflib_admin_intr_deferred(sc->ctx);
+rearm:
/* Re-arm unconditionally */
if (sc->hw.mac.type >= igb_mac_min) {
- E1000_WRITE_REG(&sc->hw, E1000_IMS, E1000_IMS_LSC);
+ E1000_WRITE_REG(&sc->hw, E1000_IMS,
+ E1000_IMS_LSC | igb_iov_intr_mask(sc));
E1000_WRITE_REG(&sc->hw, E1000_EIMS, sc->link_mask);
} else if (sc->hw.mac.type == e1000_82574) {
E1000_WRITE_REG(&sc->hw, E1000_IMS,
@@ -1999,7 +2364,8 @@ em_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr)
ifmr->ifm_status = IFM_AVALID;
ifmr->ifm_active = IFM_ETHER;
- if (!sc->link_active) {
+ if (sc->link_state == EM_LINK_STATE_DOWN ||
+ sc->link_state == EM_LINK_STATE_DOWN_RESET_PENDING) {
return;
}
@@ -2079,19 +2445,70 @@ em_if_media_change(if_ctx_t ctx)
device_printf(sc->dev, "Unsupported media type\n");
}
- em_if_init(ctx);
-
return (0);
}
static int
em_if_set_promisc(if_ctx_t ctx, int flags)
{
+ struct e1000_softc *sc;
+
+ sc = iflib_get_softc(ctx);
+ if (em_if_defer_promisc(sc))
+ return (0);
+ return (em_if_set_promisc_impl(ctx, flags));
+}
+
+static bool
+em_if_defer_promisc(struct e1000_softc *sc)
+{
+ switch (sc->hw.mac.type) {
+ case e1000_82576:
+ case e1000_i350:
+ case e1000_vfadapt:
+ case e1000_vfadapt_i350:
+ break;
+ default:
+ return (false);
+ }
+
+ /*
+ * iflib drops its context lock around IFDI_PROMISC_SET. Run mailbox
+ * and IOV register operations later from the locked admin task.
+ * A deferred VF mailbox rejection cannot be returned to ifconfig; the
+ * admin task logs it instead.
+ */
+ atomic_set_32(&sc->promisc_pending, 1);
+ iflib_admin_intr_deferred(sc->ctx);
+ return (true);
+}
+
+int
+em_if_set_promisc_impl(if_ctx_t ctx, int flags)
+{
struct e1000_softc *sc = iflib_get_softc(ctx);
if_t ifp = iflib_get_ifp(ctx);
+ enum e1000_promisc_type type;
+ s32 error;
u32 reg_rctl;
int mcnt = 0;
+ if (sc->vf_ifp) {
+ if (flags & IFF_PROMISC)
+ type = e1000_promisc_enabled;
+ else if (flags & IFF_ALLMULTI)
+ type = e1000_promisc_multicast;
+ else
+ type = e1000_promisc_disabled;
+ error = e1000_promisc_set_vf(&sc->hw, type);
+ if (error != E1000_SUCCESS) {
+ device_printf(sc->dev,
+ "VF promiscuous-mode request failed\n");
+ return (EPERM);
+ }
+ return (0);
+ }
+
reg_rctl = E1000_READ_REG(&sc->hw, E1000_RCTL);
reg_rctl &= ~(E1000_RCTL_SBP | E1000_RCTL_UPE);
if (flags & IFF_ALLMULTI)
@@ -2106,20 +2523,25 @@ em_if_set_promisc(if_ctx_t ctx, int flags)
if (flags & IFF_PROMISC) {
reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
- em_if_vlan_filter_disable(sc);
/* Turn this on if you want to see bad packets */
if (em_debug_sbp)
reg_rctl |= E1000_RCTL_SBP;
E1000_WRITE_REG(&sc->hw, E1000_RCTL, reg_rctl);
+ if (igb_iov_enabled(sc))
+ em_if_vlan_filter_enable(sc);
+ else
+ em_if_vlan_filter_disable(sc);
} else {
if (flags & IFF_ALLMULTI) {
reg_rctl |= E1000_RCTL_MPE;
reg_rctl &= ~E1000_RCTL_UPE;
E1000_WRITE_REG(&sc->hw, E1000_RCTL, reg_rctl);
}
- if (em_if_vlan_filter_used(ctx))
+ if (igb_iov_enabled(sc) || em_if_vlan_filter_used(ctx))
em_if_vlan_filter_enable(sc);
}
+ igb_iov_update_pf_vmolr(sc);
+ igb_iov_rebuild_vlan(sc);
return (0);
}
@@ -2168,7 +2590,14 @@ em_if_multi_set(if_ctx_t ctx)
mcnt = if_foreach_llmaddr(ifp, em_copy_maddr, mta);
- if (mcnt < MAX_NUM_MULTICAST_ADDRESSES)
+ if (sc->vf_ifp) {
+ e1000_update_mc_addr_list(&sc->hw, mta, mcnt);
+ igbv_update_uc_addr_list(sc, ifp);
+ return;
+ }
+
+ if (mcnt < MAX_NUM_MULTICAST_ADDRESSES &&
+ !igb_iov_enabled(sc))
e1000_update_mc_addr_list(&sc->hw, mta, mcnt);
reg_rctl = E1000_READ_REG(&sc->hw, E1000_RCTL);
@@ -2193,6 +2622,8 @@ em_if_multi_set(if_ctx_t ctx)
if (sc->hw.bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
e1000_pci_set_mwi(&sc->hw);
}
+ igb_iov_rebuild_mta(sc);
+ igb_iov_update_pf_vmolr(sc);
}
/*********************************************************************
@@ -2206,9 +2637,13 @@ em_if_multi_set(if_ctx_t ctx)
static void
em_if_timer(if_ctx_t ctx, uint16_t qid)
{
+ struct e1000_softc *sc;
+
if (qid != 0)
return;
+ sc = iflib_get_softc(ctx);
+ atomic_set_32(&sc->stats_pending, 1);
iflib_admin_intr_deferred(ctx);
}
@@ -2219,7 +2654,15 @@ em_if_update_admin_status(if_ctx_t ctx)
struct e1000_hw *hw = &sc->hw;
device_t dev = iflib_get_dev(ctx);
u32 link_check, thstat, ctrl;
- bool automasked = false;
+ bool reset_requested = false;
+
+ KASSERT(!sc->vf_ifp, ("%s called for a VF", __func__));
+
+ if (atomic_readandclear_32(&sc->promisc_pending) != 0)
+ (void)em_if_set_promisc_impl(ctx,
+ if_getflags(iflib_get_ifp(ctx)));
+ igb_iov_handle_mdd(sc);
+ igb_iov_handle_mbx(sc);
link_check = thstat = ctrl = 0;
/* Get the cached link value or read phy for real */
@@ -2246,11 +2689,6 @@ em_if_update_admin_status(if_ctx_t ctx)
e1000_check_for_link(hw);
link_check = hw->mac.serdes_has_link;
break;
- /* VF device is type_unknown */
- case e1000_media_type_unknown:
- e1000_check_for_link(hw);
- link_check = !hw->mac.get_link_status;
- /* FALLTHROUGH */
default:
break;
}
@@ -2262,7 +2700,13 @@ em_if_update_admin_status(if_ctx_t ctx)
}
/* Now check for a transition */
- if (link_check && (sc->link_active == 0)) {
+ if (link_check &&
+ (sc->link_state == EM_LINK_STATE_DOWN ||
+ sc->link_state == EM_LINK_STATE_DOWN_RESET_PENDING)) {
+ bool reset_pending;
+
+ reset_pending =
+ sc->link_state == EM_LINK_STATE_DOWN_RESET_PENDING;
e1000_get_speed_and_duplex(hw, &sc->link_speed,
&sc->link_duplex);
/* Check if we must disable SPEED_MODE bit on PCI-E */
@@ -2279,9 +2723,10 @@ em_if_update_admin_status(if_ctx_t ctx)
sc->link_speed,
((sc->link_duplex == FULL_DUPLEX) ?
"Full Duplex" : "Half Duplex"));
- sc->link_active = 1;
+ sc->link_state = EM_LINK_STATE_UP;
sc->smartspeed = 0;
- if ((ctrl & E1000_CTRL_EXT_LINK_MODE_MASK) ==
+ if (hw->mac.type == e1000_i350 &&
+ (ctrl & E1000_CTRL_EXT_LINK_MODE_MASK) ==
E1000_CTRL_EXT_LINK_MODE_GMII &&
(thstat & E1000_THSTAT_LINK_THROTTLE))
device_printf(dev, "Link: thermal downshift\n");
@@ -2295,23 +2740,54 @@ em_if_update_admin_status(if_ctx_t ctx)
hw->mac.type >= igb_mac_min) {
hw->dev_spec._82575.media_changed = false;
sc->flags |= IGB_MEDIA_RESET;
- em_reset(ctx);
+ if (igb_iov_enabled(sc)) {
+ iflib_request_reset(ctx);
+ iflib_admin_intr_deferred(ctx);
+ reset_requested = true;
+ } else
+ em_reset(ctx);
}
/* Only do TSO on gigabit for older chips due to errata */
if (hw->mac.type < igb_mac_min)
- automasked = em_automask_tso(ctx);
+ reset_requested = em_automask_tso(ctx);
- /* Automasking resets the interface so don't mark it up yet */
- if (!automasked)
+ if (reset_pending || reset_requested) {
+ /*
+ * The PHY is up, but publish it only after the TSO
+ * capability-change reset.
+ */
+ sc->link_state = EM_LINK_STATE_UP_RESET_PENDING;
+ } else {
iflib_link_state_change(ctx, LINK_STATE_UP,
IF_Mbps(sc->link_speed));
- } else if (!link_check && (sc->link_active == 1)) {
+ }
+ igb_iov_ping_all_vfs(sc);
+ } else if (!link_check &&
+ (sc->link_state == EM_LINK_STATE_UP ||
+ sc->link_state == EM_LINK_STATE_UP_RESET_PENDING)) {
+ bool link_was_published;
+ bool reset_pending;
+
+ link_was_published = sc->link_state == EM_LINK_STATE_UP;
+ reset_pending =
+ sc->link_state == EM_LINK_STATE_UP_RESET_PENDING;
sc->link_speed = 0;
sc->link_duplex = 0;
- sc->link_active = 0;
- iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
+ sc->link_state = reset_pending ?
+ EM_LINK_STATE_DOWN_RESET_PENDING : EM_LINK_STATE_DOWN;
+ if (link_was_published)
+ iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
+ igb_iov_ping_all_vfs(sc);
}
- em_update_stats_counters(sc);
+ /*
+ * Mailbox, link, and timer events share this admin task. The PF
+ * statistics sweep performs 66 MMIO reads, so run it only when the
+ * ordinary iflib timer requests a sample rather than once per mailbox
+ * message. Exported counters can consequently trail hardware by the
+ * timer interval (normally 500 ms).
+ */
+ if (atomic_readandclear_32(&sc->stats_pending) != 0)
+ em_update_stats_counters(sc);
/* Reset LAA into RAR[0] on 82571 */
if (hw->mac.type == e1000_82571 && e1000_get_laa_state_82571(hw))
@@ -2321,18 +2797,6 @@ em_if_update_admin_status(if_ctx_t ctx)
lem_smartspeed(sc);
}
-static void
-em_if_watchdog_reset(if_ctx_t ctx)
-{
- struct e1000_softc *sc = iflib_get_softc(ctx);
-
- /*
- * Just count the event; iflib(4) will already trigger a
- * sufficient reset of the controller.
- */
- sc->watchdog_events++;
-}
-
/*********************************************************************
*
* This routine disables all traffic on the adapter by issuing a
@@ -2346,16 +2810,36 @@ em_if_stop(if_ctx_t ctx)
INIT_DEBUGOUT("em_if_stop: begin");
+ if (sc->vf_ifp) {
+ igbv_queue_retry_stop(sc);
+ igbv_mbx_retry_stop(sc);
+ }
+
/* I219 needs special flushing to avoid hangs */
if (sc->hw.mac.type >= e1000_pch_spt && sc->hw.mac.type < igb_mac_min)
em_flush_desc_rings(sc);
- e1000_reset_hw(&sc->hw);
+ igb_iov_reset_prepare(sc);
+ if (!sc->vf_ifp ||
+ (atomic_load_acq_32(&sc->vf_mbx_ready) != 0 &&
+ (if_getflags(iflib_get_ifp(ctx)) & IFF_UP) == 0))
+ e1000_reset_hw(&sc->hw);
+ if (sc->vf_ifp)
+ atomic_store_rel_32(&sc->vf_mbx_ready, 0);
if (sc->hw.mac.type >= e1000_82544 && !sc->vf_ifp)
E1000_WRITE_REG(&sc->hw, E1000_WUFC, 0);
- e1000_led_off(&sc->hw);
- e1000_cleanup_led(&sc->hw);
+ if (!sc->vf_ifp) {
+ e1000_led_off(&sc->hw);
+ e1000_cleanup_led(&sc->hw);
+ } else {
+ sc->link_speed = 0;
+ sc->link_duplex = 0;
+ if (sc->link_state != EM_LINK_STATE_DOWN) {
+ sc->link_state = EM_LINK_STATE_DOWN;
+ iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
+ }
+ }
}
/*********************************************************************
@@ -2385,12 +2869,15 @@ em_identify_hardware(if_ctx_t ctx)
return;
}
- /* Are we a VF device? */
- if ((sc->hw.mac.type == e1000_vfadapt) ||
- (sc->hw.mac.type == e1000_vfadapt_i350))
- sc->vf_ifp = 1;
- else
- sc->vf_ifp = 0;
+ /*
+ * Function type comes from the selected iflib shared context, not from
+ * enum ordering. Keep the detected MAC type as an independent check
+ * that the igb/igbv probe tables selected the right policy.
+ */
+ KASSERT(sc->vf_ifp ==
+ (sc->hw.mac.type == e1000_vfadapt ||
+ sc->hw.mac.type == e1000_vfadapt_i350),
+ ("%s: iflib function type and MAC type disagree", __func__));
}
static int
@@ -2558,10 +3045,18 @@ igb_configure_queues(struct e1000_softc *sc)
struct e1000_hw *hw = &sc->hw;
struct em_rx_queue *rx_que;
struct em_tx_queue *tx_que;
- u32 tmp, ivar = 0, newitr = 0;
+ u32 tmp, ivar = 0;
- /* First turn on RSS capability */
- if (hw->mac.type != e1000_82575)
+ /*
+ * Queue ownership can change when SR-IOV is enabled or disabled.
+ * Rebuild the interrupt mask for the current layout instead of
+ * retaining vectors from a previous initialization.
+ */
+ sc->que_mask = 0;
+ sc->link_mask = 0;
+
+ /* GPIE controls the PF interrupt block and is not in the VF BAR. */
+ if (!sc->vf_ifp && hw->mac.type != e1000_82575)
E1000_WRITE_REG(hw, E1000_GPIE,
E1000_GPIE_MSIX_MODE | E1000_GPIE_EIAME |
E1000_GPIE_PBA | E1000_GPIE_NSICR);
@@ -2577,10 +3072,13 @@ igb_configure_queues(struct e1000_softc *sc)
case e1000_vfadapt_i350:
/* RX entries */
for (int i = 0; i < sc->rx_num_queues; i++) {
- u32 index = i >> 1;
- ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
+ uint32_t index, qid;
+
rx_que = &sc->rx_queues[i];
- if (i & 1) {
+ qid = rx_que->rxr.me;
+ index = qid >> 1;
+ ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
+ if (qid & 1) {
ivar &= 0xFF00FFFF;
ivar |= (rx_que->msix | E1000_IVAR_VALID) <<
16;
@@ -2589,13 +3087,17 @@ igb_configure_queues(struct e1000_softc *sc)
ivar |= rx_que->msix | E1000_IVAR_VALID;
}
E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar);
+ sc->que_mask |= rx_que->eims;
}
/* TX entries */
for (int i = 0; i < sc->tx_num_queues; i++) {
- u32 index = i >> 1;
- ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
+ uint32_t index, qid;
+
tx_que = &sc->tx_queues[i];
- if (i & 1) {
+ qid = tx_que->txr.me;
+ index = qid >> 1;
+ ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
+ if (qid & 1) {
ivar &= 0x00FFFFFF;
ivar |= (tx_que->msix | E1000_IVAR_VALID) <<
24;
@@ -2609,17 +3111,27 @@ igb_configure_queues(struct e1000_softc *sc)
}
/* And for the link interrupt */
- ivar = (sc->linkvec | E1000_IVAR_VALID) << 8;
+ if (sc->vf_ifp) {
+ /*
+ * VTIVAR_MISC maps the VF mailbox in bits 7:0.
+ * The PF IVAR_MISC maps other causes in bits 15:8.
+ */
+ ivar = sc->linkvec | E1000_IVAR_VALID;
+ } else
+ ivar = (sc->linkvec | E1000_IVAR_VALID) << 8;
sc->link_mask = 1 << sc->linkvec;
E1000_WRITE_REG(hw, E1000_IVAR_MISC, ivar);
break;
case e1000_82576:
/* RX entries */
for (int i = 0; i < sc->rx_num_queues; i++) {
- u32 index = i & 0x7; /* Each IVAR has two entries */
- ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
+ uint32_t index, qid;
+
rx_que = &sc->rx_queues[i];
- if (i < 8) {
+ qid = rx_que->rxr.me;
+ index = qid & 0x7; /* Each IVAR has two entries */
+ ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
+ if (qid < 8) {
ivar &= 0xFFFFFF00;
ivar |= rx_que->msix | E1000_IVAR_VALID;
} else {
@@ -2632,10 +3144,13 @@ igb_configure_queues(struct e1000_softc *sc)
}
/* TX entries */
for (int i = 0; i < sc->tx_num_queues; i++) {
- u32 index = i & 0x7; /* Each IVAR has two entries */
- ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
+ uint32_t index, qid;
+
tx_que = &sc->tx_queues[i];
- if (i < 8) {
+ qid = tx_que->txr.me;
+ index = qid & 0x7; /* Each IVAR has two entries */
+ ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
+ if (qid < 8) {
ivar &= 0xFFFF00FF;
ivar |= (tx_que->msix | E1000_IVAR_VALID) <<
8;
@@ -2682,22 +3197,30 @@ igb_configure_queues(struct e1000_softc *sc)
break;
}
- /* Set the igb starting interrupt rate */
- if (em_max_interrupt_rate > 0) {
- newitr = IGB_INTS_TO_EITR(em_max_interrupt_rate);
+ return;
+}
- if (hw->mac.type == e1000_82575)
- newitr |= newitr << 16;
- else
- newitr |= E1000_EITR_CNT_IGNR;
+static void
+igb_initialize_interrupt_rate(struct e1000_softc *sc)
+{
+ struct e1000_hw *hw = &sc->hw;
+ struct em_rx_queue *rx_que;
+ u32 newitr;
- for (int i = 0; i < sc->rx_num_queues; i++) {
- rx_que = &sc->rx_queues[i];
- E1000_WRITE_REG(hw, E1000_EITR(rx_que->msix), newitr);
- }
- }
+ newitr = IGB_INTS_TO_EITR(em_max_interrupt_rate);
+ if (hw->mac.type == e1000_82575)
+ newitr |= newitr << 16;
+ else
+ newitr |= E1000_EITR_CNT_IGNR;
- return;
+ for (int i = 0; i < sc->rx_num_queues; i++) {
+ rx_que = &sc->rx_queues[i];
+ rx_que->itr_setting = newitr;
+ E1000_WRITE_REG(hw, E1000_EITR(rx_que->msix),
+ rx_que->itr_setting);
+ }
+ if (sc->intr_type == IFLIB_INTR_MSIX)
+ E1000_WRITE_REG(hw, E1000_EITR(sc->linkvec), newitr);
}
static void
@@ -2758,7 +3281,9 @@ lem_smartspeed(struct e1000_softc *sc)
{
u16 phy_tmp;
- if (sc->link_active || (sc->hw.phy.type != e1000_phy_igp) ||
+ if (sc->link_state == EM_LINK_STATE_UP ||
+ sc->link_state == EM_LINK_STATE_UP_RESET_PENDING ||
+ (sc->hw.phy.type != e1000_phy_igp) ||
sc->hw.mac.autoneg == 0 ||
(sc->hw.phy.autoneg_advertised & ADVERTISE_1000_FULL) == 0)
return;
@@ -2822,9 +3347,22 @@ igb_init_dmac(struct e1000_softc *sc, u32 pba)
u16 hwm;
u16 max_frame_size;
+ KASSERT(!sc->vf_ifp, ("%s: DMA coalescing requested for a VF",
+ __func__));
+
if (hw->mac.type == e1000_i211)
return;
+ /*
+ * I350 DMA coalescing and SR-IOV are mutually exclusive. Preserve
+ * the configured value so it can be restored after IOV is disabled.
+ */
+ if (igb_iov_enabled(sc)) {
+ if (hw->mac.type > e1000_82580)
+ E1000_WRITE_REG(hw, E1000_DMACR, 0);
+ return;
+ }
+
max_frame_size = sc->shared->isc_max_frame_size;
if (hw->mac.type > e1000_82580) {
@@ -3042,6 +3580,8 @@ em_reset(if_ctx_t ctx)
u32 pba;
INIT_DEBUGOUT("em_reset: begin");
+ KASSERT(!sc->vf_ifp, ("%s called for a VF", __func__));
+
/* Let the firmware know the OS is in control */
em_get_hw_control(sc);
@@ -3114,14 +3654,12 @@ em_reset(if_ctx_t ctx)
pba = E1000_PBA_32K;
break;
case e1000_82576:
- case e1000_vfadapt:
pba = E1000_READ_REG(hw, E1000_RXPBS);
pba &= E1000_RXPBS_SIZE_MASK_82576;
break;
case e1000_82580:
case e1000_i350:
case e1000_i354:
- case e1000_vfadapt_i350:
pba = E1000_READ_REG(hw, E1000_RXPBS);
pba = e1000_rxpbs_adjust_82580(pba);
break;
@@ -3166,7 +3704,7 @@ em_reset(if_ctx_t ctx)
if (hw->mac.type < igb_mac_min)
E1000_WRITE_REG(hw, E1000_PBA, pba);
- INIT_DEBUGOUT1("em_reset: pba=%dK",pba);
+ INIT_DEBUGOUT1("em_reset: pba=%dK", pba);
/*
* These parameters control the automatic generation (Tx) and
@@ -3225,13 +3763,14 @@ em_reset(if_ctx_t ctx)
case e1000_pch_ptp:
hw->fc.high_water = 0x5C20;
hw->fc.low_water = 0x5048;
- hw->fc.pause_time = 0x0650;
- hw->fc.refresh_time = 0x0400;
+ hw->fc.pause_time = 0xFFFF;
+ hw->fc.refresh_time = 0xFFFF;
/* Jumbos need adjusted PBA */
if (if_getmtu(ifp) > ETHERMTU)
- E1000_WRITE_REG(hw, E1000_PBA, 12);
+ pba = E1000_PBA_12K;
else
- E1000_WRITE_REG(hw, E1000_PBA, 26);
+ pba = E1000_PBA_26K;
+ E1000_WRITE_REG(hw, E1000_PBA, pba);
break;
case e1000_82575:
case e1000_82576:
@@ -3243,8 +3782,6 @@ em_reset(if_ctx_t ctx)
case e1000_i354:
case e1000_i210:
case e1000_i211:
- case e1000_vfadapt:
- case e1000_vfadapt_i350:
/* 16-byte granularity */
hw->fc.low_water = hw->fc.high_water - 16;
break;
@@ -3268,13 +3805,11 @@ em_reset(if_ctx_t ctx)
/* Issue a global reset */
e1000_reset_hw(hw);
- if (!sc->vf_ifp) {
- if (hw->mac.type >= igb_mac_min) {
- E1000_WRITE_REG(hw, E1000_WUC, 0);
- } else {
- E1000_WRITE_REG(hw, E1000_WUFC, 0);
- em_disable_aspm(sc);
- }
+ if (hw->mac.type >= igb_mac_min) {
+ E1000_WRITE_REG(hw, E1000_WUC, 0);
+ } else {
+ E1000_WRITE_REG(hw, E1000_WUFC, 0);
+ em_disable_aspm(sc);
}
if (sc->flags & IGB_MEDIA_RESET) {
e1000_setup_init_funcs(hw, true);
@@ -3289,7 +3824,7 @@ em_reset(if_ctx_t ctx)
if (hw->mac.type >= igb_mac_min)
igb_init_dmac(sc, pba);
- /* Save the final PBA off if it needs to be used elsewhere i.e. AIM */
+ /* Save the receive packet-buffer allocation for AIM. */
sc->pba = pba;
E1000_WRITE_REG(hw, E1000_VET, ETHERTYPE_VLAN);
@@ -3459,6 +3994,14 @@ em_setup_interface(if_ctx_t ctx)
* Specify the media types supported by this adapter and register
* callbacks to update media and link information
*/
+ if (sc->vf_ifp) {
+ ifmedia_add(sc->media,
+ IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
+ ifmedia_set(sc->media,
+ IFM_ETHER | IFM_1000_T | IFM_FDX);
+ return (0);
+ }
+
if (sc->hw.phy.media_type == e1000_media_type_fiber ||
sc->hw.phy.media_type == e1000_media_type_internal_serdes) {
u_char fiber_type = IFM_1000_SX; /* default type */
@@ -3513,6 +4056,9 @@ em_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
/* Set up some basics */
struct tx_ring *txr = &que->txr;
+ KASSERT(__is_aligned(&txr->tx_aim_snapshot, sizeof(uint64_t)),
+ ("%s: misaligned TX AIM snapshot %p", __func__,
+ &txr->tx_aim_snapshot));
txr->sc = que->sc = sc;
que->me = txr->me = i;
@@ -3566,6 +4112,9 @@ em_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
for (i = 0, que = sc->rx_queues; i < nrxqsets; i++, que++) {
/* Set up some basics */
struct rx_ring *rxr = &que->rxr;
+ KASSERT(__is_aligned(&rxr->rx_aim_snapshot, sizeof(uint64_t)),
+ ("%s: misaligned RX AIM snapshot %p", __func__,
+ &rxr->rx_aim_snapshot));
rxr->sc = que->sc = sc;
rxr->que = que;
que->me = rxr->me = i;
@@ -3612,59 +4161,174 @@ em_if_queues_free(if_ctx_t ctx)
}
}
+static u32
+em_legacy_txdctl(struct e1000_hw *hw)
+{
+ u32 txdctl;
+
+ /*
+ * Start with the established full-descriptor writeback policy.
+ * Several generations have descriptor-queue errata for which it is
+ * a documented workaround. The unsafe early controllers are
+ * overridden below.
+ */
+ txdctl = EM_TX_PTHRESH | (EM_TX_HTHRESH << 8) |
+ (EM_TX_WTHRESH << 16) | E1000_TXDCTL_GRAN;
+
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ case e1000_82573:
+ case e1000_82574:
+ case e1000_82583:
+ case e1000_80003es2lan:
+ /* Match the Intel shared-code policy for these families. */
+ txdctl |= E1000_TXDCTL_COUNT_DESC;
+ break;
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+ case e1000_ich10lan:
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ case e1000_pch_lpt:
+ case e1000_pch_spt:
+ case e1000_pch_cnp:
+ case e1000_pch_tgp:
+ case e1000_pch_adp:
+ case e1000_pch_mtp:
+ case e1000_pch_ptp:
+ /* Preserve the required bit set by the integrated shared code. */
+ txdctl |= (1U << 22);
+ break;
+ case e1000_82542:
+ case e1000_82543:
+ case e1000_82544:
+ /*
+ * 82543 erratum 35 and 82544 erratum 20 require
+ * WTHRESH=0. Leave all descriptor-control thresholds at
+ * their reset values on these early controllers.
+ */
+ txdctl = 0;
+ break;
+ case e1000_82540:
+ case e1000_82545:
+ case e1000_82545_rev_3:
+ case e1000_82546:
+ case e1000_82546_rev_3:
+ case e1000_82541:
+ case e1000_82541_rev_2:
+ case e1000_82547:
+ case e1000_82547_rev_2:
+ break;
+ default:
+ KASSERT(0, ("%s: unsupported MAC type %d", __func__,
+ hw->mac.type));
+ break;
+ }
+
+ return (txdctl);
+}
+
+static u32
+igb_txdctl(struct e1000_hw *hw)
+{
+ u32 pthresh;
+
+ switch (hw->mac.type) {
+ case e1000_i354:
+ pthresh = I354_TX_PTHRESH;
+ break;
+ case e1000_82575:
+ case e1000_82576:
+ case e1000_82580:
+ case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
+ case e1000_vfadapt:
+ case e1000_vfadapt_i350:
+ pthresh = IGB_TX_PTHRESH;
+ break;
+ default:
+ KASSERT(0, ("%s: unsupported MAC type %d", __func__,
+ hw->mac.type));
+ pthresh = IGB_TX_PTHRESH;
+ break;
+ }
+
+ return (pthresh | (IGB_TX_HTHRESH << 8) |
+ E1000_TXDCTL_QUEUE_ENABLE);
+}
+
/*********************************************************************
*
* Enable transmit unit.
*
**********************************************************************/
-static void
-em_initialize_transmit_unit(if_ctx_t ctx)
+void
+em_initialize_transmit_rings(if_ctx_t ctx)
{
struct e1000_softc *sc = iflib_get_softc(ctx);
if_softc_ctx_t scctx = sc->shared;
struct em_tx_queue *que;
struct tx_ring *txr;
struct e1000_hw *hw = &sc->hw;
- u32 tctl, txdctl = 0, tarc, tipg = 0;
+ u32 txdctl;
- INIT_DEBUGOUT("em_initialize_transmit_unit: begin");
-
- for (int i = 0; i < sc->tx_num_queues; i++, txr++) {
+ for (int i = 0; i < sc->tx_num_queues; i++) {
u64 bus_addr;
caddr_t offp, endp;
+ uint32_t qid;
que = &sc->tx_queues[i];
txr = &que->txr;
+ qid = txr->me;
bus_addr = txr->tx_paddr;
/* Clear checksum offload context. */
offp = (caddr_t)txr + offsetof(struct tx_ring, csum_flags);
endp = (caddr_t)(txr + 1);
- bzero(offp, endp - offp);
+ memset(offp, 0, endp - offp);
+
+ if (hw->mac.type >= igb_mac_min) {
+ txdctl = E1000_READ_REG(hw, E1000_TXDCTL(qid));
+ E1000_WRITE_REG(hw, E1000_TXDCTL(qid),
+ txdctl & ~E1000_TXDCTL_QUEUE_ENABLE);
+ E1000_WRITE_FLUSH(hw);
+ }
/* Base and Len of TX Ring */
- E1000_WRITE_REG(hw, E1000_TDLEN(i),
+ E1000_WRITE_REG(hw, E1000_TDLEN(qid),
scctx->isc_ntxd[0] * sizeof(struct e1000_tx_desc));
- E1000_WRITE_REG(hw, E1000_TDBAH(i), (u32)(bus_addr >> 32));
- E1000_WRITE_REG(hw, E1000_TDBAL(i), (u32)bus_addr);
+ E1000_WRITE_REG(hw, E1000_TDBAH(qid), (u32)(bus_addr >> 32));
+ E1000_WRITE_REG(hw, E1000_TDBAL(qid), (u32)bus_addr);
/* Init the HEAD/TAIL indices */
- E1000_WRITE_REG(hw, E1000_TDT(i), 0);
- E1000_WRITE_REG(hw, E1000_TDH(i), 0);
+ E1000_WRITE_REG(hw, E1000_TDT(qid), 0);
+ E1000_WRITE_REG(hw, E1000_TDH(qid), 0);
HW_DEBUGOUT2("Base = %x, Length = %x\n",
- E1000_READ_REG(hw, E1000_TDBAL(i)),
- E1000_READ_REG(hw, E1000_TDLEN(i)));
+ E1000_READ_REG(hw, E1000_TDBAL(qid)),
+ E1000_READ_REG(hw, E1000_TDLEN(qid)));
- txdctl = 0; /* clear txdctl */
- txdctl |= 0x1f; /* PTHRESH */
- txdctl |= 1 << 8; /* HTHRESH */
- txdctl |= 1 << 16;/* WTHRESH */
- txdctl |= 1 << 22; /* Reserved bit 22 must always be 1 */
- txdctl |= E1000_TXDCTL_GRAN;
- txdctl |= 1 << 25; /* LWTHRESH */
+ if (hw->mac.type < igb_mac_min)
+ txdctl = em_legacy_txdctl(hw);
+ else
+ txdctl = igb_txdctl(hw);
- E1000_WRITE_REG(hw, E1000_TXDCTL(i), txdctl);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(qid), txdctl);
}
+}
+
+static void
+em_initialize_transmit_unit(if_ctx_t ctx)
+{
+ struct e1000_softc *sc = iflib_get_softc(ctx);
+ struct e1000_hw *hw = &sc->hw;
+ u32 tctl, tarc, tipg = 0;
+
+ INIT_DEBUGOUT("em_initialize_transmit_unit: begin");
+ KASSERT(!sc->vf_ifp, ("%s called for a VF", __func__));
+
+ em_initialize_transmit_rings(ctx);
/* Set the default values for the Tx Inter Packet Gap timer */
switch (hw->mac.type) {
@@ -3696,7 +4360,7 @@ em_initialize_transmit_unit(if_ctx_t ctx)
sc->txd_cmd |= E1000_TXD_CMD_IDE;
}
- if (hw->mac.type >= e1000_82540)
+ if (hw->mac.type >= e1000_82540 && hw->mac.type < igb_mac_min)
E1000_WRITE_REG(hw, E1000_TADV, sc->tx_abs_int_delay.value);
if (hw->mac.type == e1000_82571 || hw->mac.type == e1000_82572) {
@@ -3755,6 +4419,122 @@ em_initialize_transmit_unit(if_ctx_t ctx)
**********************************************************************/
#define BSIZEPKT_ROUNDUP ((1<<E1000_SRRCTL_BSIZEPKT_SHIFT)-1)
+static u32
+igb_rxdctl(struct e1000_softc *sc, u32 rxdctl)
+{
+ struct e1000_hw *hw;
+ u32 mask, pthresh, wthresh;
+
+ hw = &sc->hw;
+ mask = IGB_RXDCTL_THRESH_MASK;
+ switch (hw->mac.type) {
+ case e1000_82575:
+ mask = IGB_82575_RXDCTL_THRESH_MASK;
+ pthresh = IGB_RX_PTHRESH;
+ wthresh = IGB_RX_WTHRESH;
+ break;
+ case e1000_82576:
+ pthresh = IGB_RX_PTHRESH;
+ wthresh = sc->intr_type == IFLIB_INTR_MSIX ?
+ IGB_82576_RX_WTHRESH : IGB_RX_WTHRESH;
+ break;
+ case e1000_vfadapt:
+ /* 82576 VFs always need the MSI-X writeback workaround. */
+ pthresh = IGB_RX_PTHRESH;
+ wthresh = IGB_82576_RX_WTHRESH;
+ break;
+ case e1000_i354:
+ pthresh = I354_RX_PTHRESH;
+ wthresh = IGB_RX_WTHRESH;
+ break;
+ case e1000_82580:
+ case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
+ case e1000_vfadapt_i350:
+ pthresh = IGB_RX_PTHRESH;
+ wthresh = IGB_RX_WTHRESH;
+ break;
+ default:
+ KASSERT(0, ("%s: unsupported MAC type %d", __func__,
+ hw->mac.type));
+ pthresh = IGB_RX_PTHRESH;
+ wthresh = IGB_RX_WTHRESH;
+ break;
+ }
+
+ rxdctl &= ~mask;
+ rxdctl |= pthresh | (IGB_RX_HTHRESH << 8) |
+ (wthresh << 16) | E1000_RXDCTL_QUEUE_ENABLE;
+ return (rxdctl);
+}
+
+void
+igb_initialize_receive_rings(if_ctx_t ctx, bool drop)
+{
+ struct e1000_softc *sc = iflib_get_softc(ctx);
+ if_softc_ctx_t scctx = sc->shared;
+ struct e1000_hw *hw = &sc->hw;
+ struct em_rx_queue *que;
+ u32 srrctl;
+
+ srrctl = (sc->rx_mbuf_sz + BSIZEPKT_ROUNDUP) >>
+ E1000_SRRCTL_BSIZEPKT_SHIFT;
+ srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
+ if (drop)
+ srrctl |= E1000_SRRCTL_DROP_EN;
+
+ for (int i = 0; i < sc->rx_num_queues; i++) {
+ struct rx_ring *rxr;
+ u64 bus_addr;
+ u32 rxdctl;
+ uint32_t qid;
+
+ que = &sc->rx_queues[i];
+ rxr = &que->rxr;
+ bus_addr = rxr->rx_paddr;
+ qid = rxr->me;
+
+ rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(qid));
+ E1000_WRITE_REG(hw, E1000_RXDCTL(qid),
+ rxdctl & ~E1000_RXDCTL_QUEUE_ENABLE);
+ E1000_WRITE_FLUSH(hw);
+
+ E1000_WRITE_REG(hw, E1000_RDLEN(qid),
+ scctx->isc_nrxd[0] * sizeof(struct e1000_rx_desc));
+ E1000_WRITE_REG(hw, E1000_RDBAH(qid),
+ (uint32_t)(bus_addr >> 32));
+ E1000_WRITE_REG(hw, E1000_RDBAL(qid), (uint32_t)bus_addr);
+ E1000_WRITE_REG(hw, E1000_RDH(qid), 0);
+ E1000_WRITE_REG(hw, E1000_RDT(qid), 0);
+ E1000_WRITE_REG(hw, E1000_SRRCTL(qid), srrctl);
+
+ rxdctl = igb_rxdctl(sc, rxdctl);
+ E1000_WRITE_REG(hw, E1000_RXDCTL(qid), rxdctl);
+ }
+}
+
+static bool
+em_integrated_jumbo_rx(struct e1000_hw *hw)
+{
+ switch (hw->mac.type) {
+ case e1000_ich9lan:
+ case e1000_ich10lan:
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ case e1000_pch_lpt:
+ case e1000_pch_spt:
+ case e1000_pch_cnp:
+ case e1000_pch_tgp:
+ case e1000_pch_adp:
+ case e1000_pch_mtp:
+ case e1000_pch_ptp:
+ return (true);
+ default:
+ return (false);
+ }
+}
+
static void
em_initialize_receive_unit(if_ctx_t ctx)
{
@@ -3767,32 +4547,29 @@ em_initialize_receive_unit(if_ctx_t ctx)
uint32_t rctl, rxcsum;
INIT_DEBUGOUT("em_initialize_receive_units: begin");
+ KASSERT(!sc->vf_ifp, ("%s called for a VF", __func__));
/*
- * Make sure receives are disabled while setting
- * up the descriptor ring
+ * Make sure receives are disabled while setting up the descriptor
+ * ring.
*/
rctl = E1000_READ_REG(hw, E1000_RCTL);
- /* Do not disable if ever enabled on this hardware */
- if ((hw->mac.type != e1000_82574) && (hw->mac.type != e1000_82583))
+ /* Do not disable if ever enabled on this hardware. */
+ if (hw->mac.type != e1000_82574 &&
+ hw->mac.type != e1000_82583)
E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);
- /* Setup the Receive Control Register */
+ /* Setup the Receive Control Register. */
rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
(hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
-
- /* Do not store bad packets */
rctl &= ~E1000_RCTL_SBP;
- /* Enable Long Packet receive */
- if (if_getmtu(ifp) > ETHERMTU)
+ if (igb_iov_enabled(sc) || if_getmtu(ifp) > ETHERMTU)
rctl |= E1000_RCTL_LPE;
else
rctl &= ~E1000_RCTL_LPE;
-
- /* Strip the CRC */
if (!em_disable_crc_stripping)
rctl |= E1000_RCTL_SECRC;
@@ -3805,6 +4582,19 @@ em_initialize_receive_unit(if_ctx_t ctx)
/* Set the default interrupt throttling rate */
E1000_WRITE_REG(hw, E1000_ITR,
EM_INTS_TO_ITR(em_max_interrupt_rate));
+
+ /*
+ * The 82574 MSI-X EITR registers are programmed
+ * with the same value further below. Either way
+ * the hardware now holds the default rate, so seed
+ * the software copy to match; otherwise a stale
+ * itr_setting left over from AIM makes em_newitr()
+ * skip the write that would restore it.
+ */
+ for (i = 0, que = sc->rx_queues; i < sc->rx_num_queues;
+ i++, que++)
+ que->itr_setting =
+ EM_INTS_TO_ITR(em_max_interrupt_rate);
}
/* XXX TEMPORARY WORKAROUND: on some systems with 82573
@@ -3820,7 +4610,7 @@ em_initialize_receive_unit(if_ctx_t ctx)
sc->rx_int_delay.value);
}
- if (hw->mac.type >= em_mac_min && !sc->vf_ifp) {
+ if (hw->mac.type >= em_mac_min) {
uint32_t rfctl;
/* Use extended rx descriptor formats */
rfctl = E1000_READ_REG(hw, E1000_RFCTL);
@@ -3840,96 +4630,91 @@ em_initialize_receive_unit(if_ctx_t ctx)
E1000_WRITE_REG(hw, E1000_RFCTL, rfctl);
}
- /*
- * Set up L3 and L4 csum Rx descriptor offloads only on Physical
- * Functions. Virtual Functions have no access to this register.
- */
- if (!sc->vf_ifp) {
- rxcsum = E1000_READ_REG(hw, E1000_RXCSUM);
- if (if_getcapenable(ifp) & IFCAP_RXCSUM) {
- rxcsum |= E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPOFL;
- if (hw->mac.type > e1000_82575)
- rxcsum |= E1000_RXCSUM_CRCOFL;
- else if (hw->mac.type < em_mac_min &&
- if_getcapenable(ifp) & IFCAP_HWCSUM_IPV6)
- rxcsum |= E1000_RXCSUM_IPV6OFL;
- } else {
- rxcsum &= ~(E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL);
- if (hw->mac.type > e1000_82575)
- rxcsum &= ~E1000_RXCSUM_CRCOFL;
- else if (hw->mac.type < em_mac_min)
- rxcsum &= ~E1000_RXCSUM_IPV6OFL;
- }
+ rxcsum = E1000_READ_REG(hw, E1000_RXCSUM);
+ if (if_getcapenable(ifp) & IFCAP_RXCSUM) {
+ rxcsum |= E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPOFL;
+ if (hw->mac.type > e1000_82575)
+ rxcsum |= E1000_RXCSUM_CRCOFL;
+ else if (hw->mac.type < em_mac_min &&
+ if_getcapenable(ifp) & IFCAP_HWCSUM_IPV6)
+ rxcsum |= E1000_RXCSUM_IPV6OFL;
+ } else {
+ rxcsum &= ~(E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL);
+ if (hw->mac.type > e1000_82575)
+ rxcsum &= ~E1000_RXCSUM_CRCOFL;
+ else if (hw->mac.type < em_mac_min)
+ rxcsum &= ~E1000_RXCSUM_IPV6OFL;
+ }
- if (sc->rx_num_queues > 1) {
- /* RSS hash needed in the Rx descriptor */
- rxcsum |= E1000_RXCSUM_PCSD;
+ if (sc->rx_num_queues > 1) {
+ /* RSS hash needed in the Rx descriptor */
+ rxcsum |= E1000_RXCSUM_PCSD;
- if (hw->mac.type >= igb_mac_min)
- igb_initialize_rss_mapping(sc);
- else
- em_initialize_rss_mapping(sc);
- }
- E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum);
+ if (hw->mac.type >= igb_mac_min)
+ igb_initialize_rss_mapping(sc);
+ else
+ em_initialize_rss_mapping(sc);
}
+ E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum);
- for (i = 0, que = sc->rx_queues; i < sc->rx_num_queues; i++, que++) {
+ for (i = 0, que = sc->rx_queues;
+ hw->mac.type < igb_mac_min && i < sc->rx_num_queues;
+ i++, que++) {
struct rx_ring *rxr = &que->rxr;
/* Setup the Base and Length of the Rx Descriptor Ring */
u64 bus_addr = rxr->rx_paddr;
+ uint32_t qid = rxr->me;
#if 0
u32 rdt = sc->rx_num_queues -1; /* default */
#endif
- E1000_WRITE_REG(hw, E1000_RDLEN(i),
+ E1000_WRITE_REG(hw, E1000_RDLEN(qid),
scctx->isc_nrxd[0] *
sizeof(union e1000_rx_desc_extended));
- E1000_WRITE_REG(hw, E1000_RDBAH(i), (u32)(bus_addr >> 32));
- E1000_WRITE_REG(hw, E1000_RDBAL(i), (u32)bus_addr);
+ E1000_WRITE_REG(hw, E1000_RDBAH(qid), (u32)(bus_addr >> 32));
+ E1000_WRITE_REG(hw, E1000_RDBAL(qid), (u32)bus_addr);
/* Setup the Head and Tail Descriptor Pointers */
- E1000_WRITE_REG(hw, E1000_RDH(i), 0);
- E1000_WRITE_REG(hw, E1000_RDT(i), 0);
+ E1000_WRITE_REG(hw, E1000_RDH(qid), 0);
+ E1000_WRITE_REG(hw, E1000_RDT(qid), 0);
}
- /*
- * Set PTHRESH for improved jumbo performance
- * According to 10.2.5.11 of Intel 82574 Datasheet,
- * RXDCTL(1) is written whenever RXDCTL(0) is written.
- * Only write to RXDCTL(1) if there is a need for different
- * settings.
- */
- if ((hw->mac.type == e1000_ich9lan || hw->mac.type == e1000_pch2lan ||
- hw->mac.type == e1000_ich10lan) && if_getmtu(ifp) > ETHERMTU) {
+ /* Increase receive-descriptor prefetching for integrated jumbo MACs. */
+ if (em_integrated_jumbo_rx(hw) && if_getmtu(ifp) > ETHERMTU) {
u32 rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(0));
- E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl | 3);
+
+ rxdctl &= ~(EM_RXDCTL_PTHRESH_MASK |
+ EM_RXDCTL_HTHRESH_MASK);
+ rxdctl |= EM_JUMBO_RX_PTHRESH |
+ (EM_JUMBO_RX_HTHRESH << 8);
+ E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl);
} else if (hw->mac.type == e1000_82574) {
+ /* RXDCTL(0) writes are mirrored to RXDCTL(1) on 82574. */
for (int i = 0; i < sc->rx_num_queues; i++) {
u32 rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(i));
- rxdctl |= 0x20; /* PTHRESH */
- rxdctl |= 4 << 8; /* HTHRESH */
- rxdctl |= 4 << 16;/* WTHRESH */
- rxdctl |= 1 << 24; /* Switch to granularity */
+
+ rxdctl &= ~EM_RXDCTL_THRESH_MASK;
+ rxdctl |= EM_82574_RX_PTHRESH |
+ (EM_82574_RX_HTHRESH << 8) |
+ (EM_82574_RX_WTHRESH << 16) |
+ E1000_RXDCTL_THRESH_UNIT_DESC;
E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl);
}
} else if (hw->mac.type >= igb_mac_min) {
- u32 psize, srrctl = 0;
+ bool drop;
+ u32 psize;
- if (if_getmtu(ifp) > ETHERMTU) {
+ if (igb_iov_enabled(sc)) {
+ E1000_WRITE_REG(hw, E1000_RLPML,
+ IGB_IOV_MAX_FRAME_SIZE);
+ } else if (if_getmtu(ifp) > ETHERMTU) {
psize = scctx->isc_max_frame_size;
/* are we on a vlan? */
if (if_vlantrunkinuse(ifp))
psize += VLAN_TAG_SIZE;
- if (sc->vf_ifp)
- e1000_rlpml_set_vf(hw, psize);
- else
- E1000_WRITE_REG(hw, E1000_RLPML, psize);
+ E1000_WRITE_REG(hw, E1000_RLPML, psize);
}
- /* Set maximum packet buffer len */
- srrctl |= (sc->rx_mbuf_sz + BSIZEPKT_ROUNDUP) >>
- E1000_SRRCTL_BSIZEPKT_SHIFT;
-
/*
* If TX flow control is disabled and there's >1 queue
* defined, enable DROP.
@@ -3937,42 +4722,11 @@ em_initialize_receive_unit(if_ctx_t ctx)
* This drops frames rather than hanging the RX MAC for all
* queues.
*/
- if ((sc->rx_num_queues > 1) &&
+ drop = igb_iov_enabled(sc) ||
+ ((sc->rx_num_queues > 1) &&
(sc->fc == e1000_fc_none ||
- sc->fc == e1000_fc_rx_pause)) {
- srrctl |= E1000_SRRCTL_DROP_EN;
- }
- /* Setup the Base and Length of the Rx Descriptor Rings */
- for (i = 0, que = sc->rx_queues; i < sc->rx_num_queues;
- i++, que++) {
- struct rx_ring *rxr = &que->rxr;
- u64 bus_addr = rxr->rx_paddr;
- u32 rxdctl;
-
-#ifdef notyet
- /* Configure for header split? -- ignore for now */
- rxr->hdr_split = igb_header_split;
-#else
- srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
-#endif
-
- E1000_WRITE_REG(hw, E1000_RDLEN(i),
- scctx->isc_nrxd[0] *
- sizeof(struct e1000_rx_desc));
- E1000_WRITE_REG(hw, E1000_RDBAH(i),
- (uint32_t)(bus_addr >> 32));
- E1000_WRITE_REG(hw, E1000_RDBAL(i),
- (uint32_t)bus_addr);
- E1000_WRITE_REG(hw, E1000_SRRCTL(i), srrctl);
- /* Enable this Queue */
- rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(i));
- rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
- rxdctl &= 0xFFF00000;
- rxdctl |= IGB_RX_PTHRESH;
- rxdctl |= IGB_RX_HTHRESH << 8;
- rxdctl |= IGB_RX_WTHRESH << 16;
- E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl);
- }
+ sc->fc == e1000_fc_rx_pause));
+ igb_initialize_receive_rings(ctx, drop);
} else if (hw->mac.type >= e1000_pch2lan) {
if (if_getmtu(ifp) > ETHERMTU)
e1000_lv_jumbo_workaround_ich8lan(hw, true);
@@ -4017,37 +4771,68 @@ static void
em_if_vlan_register(if_ctx_t ctx, u16 vtag)
{
struct e1000_softc *sc = iflib_get_softc(ctx);
- u32 index, bit;
+ bool present;
+ u32 index, mask;
index = (vtag >> 5) & 0x7F;
- bit = vtag & 0x1F;
- sc->shadow_vfta[index] |= (1 << bit);
- ++sc->num_vlans;
- if (!sc->vf_ifp)
- em_if_vlan_filter_write(sc);
- else
- /*
- * Physical funtion may reject registering VLAN
- * but we have no way to inform the stack
- * about that.
- */
- e1000_vfta_set_vf(&sc->hw, vtag, true);
+ mask = 1U << (vtag & 0x1F);
+ present = (sc->shadow_vfta[index] & mask) != 0;
+ /*
+ * On a VF, record registration intent for replay even if the PF is not
+ * ready to accept it yet.
+ */
+ sc->shadow_vfta[index] |= mask;
+ sc->vf_vfta_stale[index] &= ~mask;
+ if (!present)
+ ++sc->num_vlans;
+ if (sc->vf_ifp &&
+ e1000_vfta_set_vf(&sc->hw, vtag, true) != E1000_SUCCESS) {
+ igbv_vlan_retry_add(sc, vtag);
+ device_printf(sc->dev,
+ "VF VLAN %u add request failed\n", vtag);
+ } else if (sc->vf_ifp)
+ igbv_vlan_retry_clear(sc, vtag);
+ if (!sc->vf_ifp) {
+ if (igb_iov_enabled(sc))
+ igb_iov_rebuild_vlan(sc);
+ else
+ em_if_vlan_filter_write(sc, index);
+ }
}
static void
em_if_vlan_unregister(if_ctx_t ctx, u16 vtag)
{
struct e1000_softc *sc = iflib_get_softc(ctx);
- u32 index, bit;
+ bool present;
+ u32 index, mask;
index = (vtag >> 5) & 0x7F;
- bit = vtag & 0x1F;
- sc->shadow_vfta[index] &= ~(1 << bit);
- --sc->num_vlans;
- if (!sc->vf_ifp)
- em_if_vlan_filter_write(sc);
- else
- e1000_vfta_set_vf(&sc->hw, vtag, false);
+ mask = 1U << (vtag & 0x1F);
+ present = (sc->shadow_vfta[index] & mask) != 0;
+ if (sc->vf_ifp)
+ igbv_vlan_retry_clear(sc, vtag);
+ if (sc->vf_ifp &&
+ e1000_vfta_set_vf(&sc->hw, vtag, false) != E1000_SUCCESS) {
+ device_printf(sc->dev,
+ "VF VLAN %u remove request failed\n", vtag);
+ /*
+ * Hardware might still admit this VID. Preserve its receive
+ * tag until a successful VF reset proves the stale filter gone.
+ */
+ sc->vf_vfta_stale[index] |= mask;
+ } else {
+ sc->vf_vfta_stale[index] &= ~mask;
+ }
+ sc->shadow_vfta[index] &= ~mask;
+ if (present)
+ --sc->num_vlans;
+ if (!sc->vf_ifp) {
+ if (igb_iov_enabled(sc))
+ igb_iov_rebuild_vlan(sc);
+ else
+ em_if_vlan_filter_write(sc, index);
+ }
}
static bool
@@ -4101,7 +4886,7 @@ em_if_vlan_filter_disable(struct e1000_softc *sc)
}
static void
-em_if_vlan_filter_write(struct e1000_softc *sc)
+em_if_vlan_filter_write(struct e1000_softc *sc, int changed_index)
{
struct e1000_hw *hw = &sc->hw;
@@ -4111,8 +4896,13 @@ em_if_vlan_filter_write(struct e1000_softc *sc)
if (hw->mac.type < em_mac_min)
em_if_intr_disable(sc->ctx);
+ /*
+ * Restore every retained VLAN after reset. Also write the changed
+ * word when its final VLAN was removed so stale hardware membership
+ * does not survive a zero shadow value.
+ */
for (int i = 0; i < EM_VFTA_SIZE; i++)
- if (sc->shadow_vfta[i] != 0)
+ if (sc->shadow_vfta[i] != 0 || i == changed_index)
e1000_write_vfta(hw, i, sc->shadow_vfta[i]);
/* Re-enable interrupts for lem-class devices */
@@ -4126,15 +4916,42 @@ em_setup_vlan_hw_support(if_ctx_t ctx)
struct e1000_softc *sc = iflib_get_softc(ctx);
struct e1000_hw *hw = &sc->hw;
if_t ifp = iflib_get_ifp(ctx);
- u32 reg;
+ s32 error;
+ u32 max_frame_size, reg;
+ u16 vid;
+ int restore_failures;
/*
* Only PFs have control over VLAN HW filtering
* configuration. VFs have to act as if it's always
* enabled.
*/
- if (sc->vf_ifp)
+ if (sc->vf_ifp) {
+ max_frame_size = min(sc->shared->isc_max_frame_size +
+ VLAN_TAG_SIZE, IGB_IOV_MAX_FRAME_SIZE);
+ e1000_rlpml_set_vf(hw, max_frame_size);
+ restore_failures = 0;
+ for (vid = 0; vid < 4096; vid++) {
+ if ((sc->shadow_vfta[vid >> 5] &
+ (1U << (vid & 0x1f))) == 0)
+ continue;
+ /*
+ * Desired state remains in shadow_vfta for the next
+ * replay if the PF mailbox is absent during reset.
+ */
+ error = e1000_vfta_set_vf(hw, vid, true);
+ if (error != E1000_SUCCESS) {
+ igbv_vlan_retry_add(sc, vid);
+ restore_failures++;
+ } else
+ igbv_vlan_retry_clear(sc, vid);
+ }
+ if (restore_failures != 0)
+ device_printf(sc->dev,
+ "VF VLAN restore failed for %d VIDs; retrying\n",
+ restore_failures);
return;
+ }
if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING &&
!em_disable_crc_stripping) {
@@ -4147,11 +4964,25 @@ em_setup_vlan_hw_support(if_ctx_t ctx)
E1000_WRITE_REG(hw, E1000_CTRL, reg);
}
- /* If we aren't doing HW filtering, we're done */
+ /*
+ * SR-IOV always needs VFE for VF isolation. When PF hardware VLAN
+ * filtering is disabled, the IOV VLAN rebuild instead makes the PF
+ * VLAN-promiscuous without disabling the global filter.
+ */
if (!em_if_vlan_filter_capable(ctx)) {
- em_if_vlan_filter_disable(sc);
+ if (igb_iov_enabled(sc)) {
+#ifdef PCI_IOV
+ sc->iov_pf_vlan_promisc = true;
+#endif
+ em_if_vlan_filter_enable(sc);
+ } else
+ em_if_vlan_filter_disable(sc);
return;
}
+#ifdef PCI_IOV
+ if (igb_iov_enabled(sc))
+ sc->iov_pf_vlan_promisc = false;
+#endif
/*
* A soft reset zero's out the VFTA, so
@@ -4198,14 +5029,22 @@ igb_if_intr_enable(if_ctx_t ctx)
{
struct e1000_softc *sc = iflib_get_softc(ctx);
struct e1000_hw *hw = &sc->hw;
- u32 mask;
+ u32 mask, reg;
if (__predict_true(sc->intr_type == IFLIB_INTR_MSIX)) {
mask = (sc->que_mask | sc->link_mask);
- E1000_WRITE_REG(hw, E1000_EIAC, mask);
- E1000_WRITE_REG(hw, E1000_EIAM, mask);
+ /*
+ * VF interrupt controls are also mapped into these registers.
+ * Preserve them and change only the PF vectors we own.
+ */
+ reg = E1000_READ_REG(hw, E1000_EIAC);
+ E1000_WRITE_REG(hw, E1000_EIAC, reg | mask);
+ reg = E1000_READ_REG(hw, E1000_EIAM);
+ E1000_WRITE_REG(hw, E1000_EIAM, reg | mask);
+ igb_iov_intr_drain_stale(sc);
E1000_WRITE_REG(hw, E1000_EIMS, mask);
- E1000_WRITE_REG(hw, E1000_IMS, E1000_IMS_LSC);
+ E1000_WRITE_REG(hw, E1000_IMS,
+ E1000_IMS_LSC | igb_iov_intr_mask(sc));
} else
E1000_WRITE_REG(hw, E1000_IMS, IMS_ENABLE_MASK);
E1000_WRITE_FLUSH(hw);
@@ -4216,10 +5055,22 @@ igb_if_intr_disable(if_ctx_t ctx)
{
struct e1000_softc *sc = iflib_get_softc(ctx);
struct e1000_hw *hw = &sc->hw;
+ u32 mask, reg;
if (__predict_true(sc->intr_type == IFLIB_INTR_MSIX)) {
- E1000_WRITE_REG(hw, E1000_EIMC, 0xffffffff);
- E1000_WRITE_REG(hw, E1000_EIAC, 0);
+ /*
+ * Do not use a blanket EIMC write here. VF interrupt controls
+ * are mapped into the same PF register space, so clearing bits
+ * we do not own can leave running VFs with interrupts masked.
+ * Before initial queue configuration the owned mask is zero
+ * because this driver has not enabled a vector yet.
+ */
+ mask = (sc->que_mask | sc->link_mask);
+ reg = E1000_READ_REG(hw, E1000_EIAM);
+ E1000_WRITE_REG(hw, E1000_EIAM, reg & ~mask);
+ E1000_WRITE_REG(hw, E1000_EIMC, mask);
+ reg = E1000_READ_REG(hw, E1000_EIAC);
+ E1000_WRITE_REG(hw, E1000_EIAC, reg & ~mask);
}
E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
E1000_WRITE_FLUSH(hw);
@@ -4324,16 +5175,13 @@ em_release_hw_control(struct e1000_softc *sc)
return;
}
-static int
-em_is_valid_ether_addr(u8 *addr)
+bool
+em_is_valid_ether_addr(const u8 *addr)
{
- char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
+ static const u8 zero_addr[ETHER_ADDR_LEN];
- if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN))) {
- return (false);
- }
-
- return (true);
+ return (!ETHER_IS_MULTICAST(addr) &&
+ memcmp(addr, zero_addr, ETHER_ADDR_LEN) != 0);
}
static bool
@@ -4342,6 +5190,8 @@ em_automask_tso(if_ctx_t ctx)
struct e1000_softc *sc = iflib_get_softc(ctx);
if_softc_ctx_t scctx = iflib_get_softc_ctx(ctx);
if_t ifp = iflib_get_ifp(ctx);
+ bool reset_needed;
+ int drvflags;
if (!em_unsupported_tso && sc->link_speed &&
sc->link_speed != SPEED_1000 &&
@@ -4351,20 +5201,32 @@ em_automask_tso(if_ctx_t ctx)
sc->tso_automasked = scctx->isc_capenable & IFCAP_TSO;
scctx->isc_capenable &= ~IFCAP_TSO;
if_setcapenablebit(ifp, 0, IFCAP_TSO);
- /* iflib_init_locked handles ifnet hwassistbits */
- iflib_request_reset(ctx);
- return true;
} else if (sc->link_speed == SPEED_1000 && sc->tso_automasked) {
device_printf(sc->dev, "Re-enabling TSO for GbE.\n");
scctx->isc_capenable |= sc->tso_automasked;
if_setcapenablebit(ifp, sc->tso_automasked, 0);
sc->tso_automasked = 0;
- /* iflib_init_locked handles ifnet hwassistbits */
- iflib_request_reset(ctx);
- return true;
+ } else {
+ return (false);
}
- return false;
+ /*
+ * Reset a running interface, or one being initialized while
+ * administratively up. OACTIVE remains set after iflib_stop(), so
+ * it alone cannot distinguish initialization from an interface that
+ * is down. In other states, the next initialization will apply the
+ * updated capabilities.
+ */
+ drvflags = if_getdrvflags(ifp);
+ reset_needed = (drvflags & IFF_DRV_RUNNING) != 0 ||
+ ((drvflags & IFF_DRV_OACTIVE) != 0 &&
+ (if_getflags(ifp) & IFF_UP) != 0);
+ if (!reset_needed)
+ return (false);
+
+ /* iflib_init_locked handles ifnet hwassistbits */
+ iflib_request_reset(ctx);
+ return (true);
}
/*
@@ -4385,8 +5247,6 @@ em_get_wakeup(if_ctx_t ctx)
switch (sc->hw.mac.type) {
case e1000_82542:
case e1000_82543:
- case e1000_vfadapt:
- case e1000_vfadapt_i350:
break;
case e1000_82544:
e1000_read_nvm(&sc->hw,
@@ -4502,6 +5362,8 @@ em_enable_wakeup(if_ctx_t ctx)
int error = 0;
u32 ctrl, ctrl_ext, rctl;
+ if (sc->vf_ifp)
+ return;
if (!pci_has_pm(dev))
return;
@@ -4689,7 +5551,7 @@ em_disable_aspm(struct e1000_softc *sc)
* Update the board statistics counters.
*
**********************************************************************/
-static void
+void
em_update_stats_counters(struct e1000_softc *sc)
{
struct e1000_hw_stats *stats;
@@ -4801,15 +5663,60 @@ em_update_stats_counters(struct e1000_softc *sc)
}
static void
-em_update_vf_stats_counters(struct e1000_softc *sc)
+em_initialize_vf_stats(struct e1000_softc *sc)
{
struct e1000_vf_stats *stats;
- if (sc->link_speed == 0)
- return;
+ stats = &sc->ustats.vf_stats;
+ *stats = (struct e1000_vf_stats){};
+ em_rebase_vf_stats(sc);
+}
+static void
+em_rebase_vf_stats(struct e1000_softc *sc)
+{
+ struct e1000_vf_stats *stats;
+
+ /*
+ * A PF reset starts a new VF counter epoch. Preserve the accumulated
+ * totals while establishing a new raw baseline so the reset is not
+ * mistaken for a 32-bit wrap.
+ */
stats = &sc->ustats.vf_stats;
+#define INIT_VF_REG(reg, name) do { \
+ stats->last_##name = E1000_READ_REG(&sc->hw, reg); \
+} while (0)
+ INIT_VF_REG(E1000_VFGPRC, gprc);
+ INIT_VF_REG(E1000_VFGORC, gorc);
+ INIT_VF_REG(E1000_VFGPTC, gptc);
+ INIT_VF_REG(E1000_VFGOTC, gotc);
+ /*
+ * I350 specification update erratum 31 says VFMPRC is not
+ * accessible from VF memory. The 0xf3c register remains valid on
+ * 82576 VFs, but must not be read on vfadapt_i350.
+ */
+ if (sc->hw.mac.type == e1000_vfadapt)
+ INIT_VF_REG(E1000_VFMPRC, mprc);
+ else
+ stats->last_mprc = 0;
+ INIT_VF_REG(E1000_VFGOTLBC, gotlbc);
+ INIT_VF_REG(E1000_VFGPTLBC, gptlbc);
+ INIT_VF_REG(E1000_VFGORLBC, gorlbc);
+ INIT_VF_REG(E1000_VFGPRLBC, gprlbc);
+#undef INIT_VF_REG
+}
+static void
+em_update_vf_stats_counters(struct e1000_softc *sc)
+{
+ struct e1000_vf_stats *stats;
+
+ stats = &sc->ustats.vf_stats;
+
+ /*
+ * Internal VF loopback traffic can continue without physical link,
+ * so sample the counters regardless of link state.
+ */
UPDATE_VF_REG(E1000_VFGPRC,
stats->last_gprc, stats->gprc);
UPDATE_VF_REG(E1000_VFGORC,
@@ -4818,8 +5725,17 @@ em_update_vf_stats_counters(struct e1000_softc *sc)
stats->last_gptc, stats->gptc);
UPDATE_VF_REG(E1000_VFGOTC,
stats->last_gotc, stats->gotc);
- UPDATE_VF_REG(E1000_VFMPRC,
- stats->last_mprc, stats->mprc);
+ if (sc->hw.mac.type == e1000_vfadapt)
+ UPDATE_VF_REG(E1000_VFMPRC,
+ stats->last_mprc, stats->mprc);
+ UPDATE_VF_REG(E1000_VFGOTLBC,
+ stats->last_gotlbc, stats->gotlbc);
+ UPDATE_VF_REG(E1000_VFGPTLBC,
+ stats->last_gptlbc, stats->gptlbc);
+ UPDATE_VF_REG(E1000_VFGORLBC,
+ stats->last_gorlbc, stats->gorlbc);
+ UPDATE_VF_REG(E1000_VFGPRLBC,
+ stats->last_gprlbc, stats->gprlbc);
}
static uint64_t
@@ -4831,9 +5747,6 @@ em_if_get_vf_counter(if_ctx_t ctx, ift_counter cnt)
switch (cnt) {
case IFCOUNTER_IERRORS:
return sc->dropped_pkts;
- case IFCOUNTER_OERRORS:
- return (if_get_counter_default(ifp, cnt) +
- sc->watchdog_events);
default:
return (if_get_counter_default(ifp, cnt));
}
@@ -4861,7 +5774,7 @@ em_if_get_counter(if_ctx_t ctx, ift_counter cnt)
stats->mpc + stats->cexterr);
case IFCOUNTER_OERRORS:
return (if_get_counter_default(ifp, cnt) +
- stats->ecol + stats->latecol + sc->watchdog_events);
+ stats->ecol + stats->latecol);
default:
return (if_get_counter_default(ifp, cnt));
}
@@ -4897,6 +5810,38 @@ em_sysctl_reg_handler(SYSCTL_HANDLER_ARGS)
return (sysctl_handle_int(oidp, &val, 0, req));
}
+enum em_ring_register {
+ EM_RING_HEAD,
+ EM_RING_TAIL,
+};
+
+/* Queue register addresses can change when the PF enters IOV mode. */
+static int
+em_sysctl_tx_ring_handler(SYSCTL_HANDLER_ARGS)
+{
+ struct tx_ring *txr;
+ u_int reg, val;
+
+ txr = oidp->oid_arg1;
+ reg = oidp->oid_arg2 == EM_RING_HEAD ? E1000_TDH(txr->me) :
+ E1000_TDT(txr->me);
+ val = E1000_READ_REG(&txr->sc->hw, reg);
+ return (sysctl_handle_int(oidp, &val, 0, req));
+}
+
+static int
+em_sysctl_rx_ring_handler(SYSCTL_HANDLER_ARGS)
+{
+ struct rx_ring *rxr;
+ u_int reg, val;
+
+ rxr = oidp->oid_arg1;
+ reg = oidp->oid_arg2 == EM_RING_HEAD ? E1000_RDH(rxr->me) :
+ E1000_RDT(rxr->me);
+ val = E1000_READ_REG(&rxr->sc->hw, reg);
+ return (sysctl_handle_int(oidp, &val, 0, req));
+}
+
/* Per queue holdoff interrupt rate handler */
static int
em_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
@@ -4913,9 +5858,10 @@ em_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
tque = oidp->oid_arg1;
hw = &tque->sc->hw;
if (hw->mac.type >= igb_mac_min)
- reg = E1000_READ_REG(hw, E1000_EITR(tque->me));
- else if (hw->mac.type == e1000_82574 && tque->msix)
- reg = E1000_READ_REG(hw, E1000_EITR_82574(tque->me));
+ reg = E1000_READ_REG(hw, E1000_EITR(tque->msix));
+ else if (hw->mac.type == e1000_82574 &&
+ tque->sc->intr_type == IFLIB_INTR_MSIX)
+ reg = E1000_READ_REG(hw, E1000_EITR_82574(tque->msix));
else
reg = E1000_READ_REG(hw, E1000_ITR);
} else {
@@ -4923,7 +5869,8 @@ em_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
hw = &rque->sc->hw;
if (hw->mac.type >= igb_mac_min)
reg = E1000_READ_REG(hw, E1000_EITR(rque->msix));
- else if (hw->mac.type == e1000_82574 && rque->msix)
+ else if (hw->mac.type == e1000_82574 &&
+ rque->sc->intr_type == IFLIB_INTR_MSIX)
reg = E1000_READ_REG(hw,
E1000_EITR_82574(rque->msix));
else
@@ -4938,7 +5885,7 @@ em_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
} else {
usec = (reg & IGB_QVECTOR_MASK);
if (usec > 0)
- rate = IGB_INTS_TO_EITR(usec);
+ rate = IGB_EITR_TO_INTS(usec);
else
rate = 0;
}
@@ -4980,23 +5927,22 @@ em_add_hw_stats(struct e1000_softc *sc)
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "rx_overruns",
CTLFLAG_RD, &sc->rx_overruns,
"RX overruns");
- SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_timeouts",
- CTLFLAG_RD, &sc->watchdog_events,
- "Watchdog timeouts");
- SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "device_control",
- CTLTYPE_UINT | CTLFLAG_RD,
- sc, E1000_CTRL, em_sysctl_reg_handler, "IU",
- "Device Control Register");
- SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_control",
- CTLTYPE_UINT | CTLFLAG_RD,
- sc, E1000_RCTL, em_sysctl_reg_handler, "IU",
- "Receiver Control Register");
- SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "fc_high_water",
- CTLFLAG_RD, &sc->hw.fc.high_water, 0,
- "Flow Control High Watermark");
- SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "fc_low_water",
- CTLFLAG_RD, &sc->hw.fc.low_water, 0,
- "Flow Control Low Watermark");
+ if (!sc->vf_ifp) {
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "device_control",
+ CTLTYPE_UINT | CTLFLAG_RD,
+ sc, E1000_CTRL, em_sysctl_reg_handler, "IU",
+ "Device Control Register");
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_control",
+ CTLTYPE_UINT | CTLFLAG_RD,
+ sc, E1000_RCTL, em_sysctl_reg_handler, "IU",
+ "Receiver Control Register");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "fc_high_water",
+ CTLFLAG_RD, &sc->hw.fc.high_water, 0,
+ "Flow Control High Watermark");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "fc_low_water",
+ CTLFLAG_RD, &sc->hw.fc.low_water, 0,
+ "Flow Control Low Watermark");
+ }
for (int i = 0; i < sc->tx_num_queues; i++, tx_que++) {
struct tx_ring *txr = &tx_que->txr;
@@ -5011,12 +5957,12 @@ em_add_hw_stats(struct e1000_softc *sc)
"IU", "Interrupt Rate");
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head",
- CTLTYPE_UINT | CTLFLAG_RD, sc,
- E1000_TDH(txr->me), em_sysctl_reg_handler, "IU",
+ CTLTYPE_UINT | CTLFLAG_RD, txr, EM_RING_HEAD,
+ em_sysctl_tx_ring_handler, "IU",
"Transmit Descriptor Head");
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail",
- CTLTYPE_UINT | CTLFLAG_RD, sc,
- E1000_TDT(txr->me), em_sysctl_reg_handler, "IU",
+ CTLTYPE_UINT | CTLFLAG_RD, txr, EM_RING_TAIL,
+ em_sysctl_tx_ring_handler, "IU",
"Transmit Descriptor Tail");
SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tx_irq",
CTLFLAG_RD, &txr->tx_irq,
@@ -5036,12 +5982,12 @@ em_add_hw_stats(struct e1000_softc *sc)
"IU", "Interrupt Rate");
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head",
- CTLTYPE_UINT | CTLFLAG_RD, sc,
- E1000_RDH(rxr->me), em_sysctl_reg_handler, "IU",
+ CTLTYPE_UINT | CTLFLAG_RD, rxr, EM_RING_HEAD,
+ em_sysctl_rx_ring_handler, "IU",
"Receive Descriptor Head");
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail",
- CTLTYPE_UINT | CTLFLAG_RD, sc,
- E1000_RDT(rxr->me), em_sysctl_reg_handler, "IU",
+ CTLTYPE_UINT | CTLFLAG_RD, rxr, EM_RING_TAIL,
+ em_sysctl_rx_ring_handler, "IU",
"Receive Descriptor Tail");
SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "rx_irq",
CTLFLAG_RD, &rxr->rx_irq,
@@ -5072,9 +6018,35 @@ em_add_hw_stats(struct e1000_softc *sc)
SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_txd",
CTLFLAG_RD, &vfstats->gotc,
"Good Octets Transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_recvd",
- CTLFLAG_RD, &vfstats->mprc,
- "Multicast Packets Received");
+ if (sc->hw.mac.type == e1000_vfadapt) {
+ SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO,
+ "mcast_pkts_recvd", CTLFLAG_RD, &vfstats->mprc,
+ "Multicast Packets Received");
+ }
+ SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO,
+ "loopback_good_pkts_recvd",
+ CTLFLAG_RD, &vfstats->gprlbc,
+ "Good Loopback Packets Received");
+ SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO,
+ "loopback_good_pkts_txd",
+ CTLFLAG_RD, &vfstats->gptlbc,
+ "Good Loopback Packets Transmitted");
+ SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO,
+ "loopback_good_octets_recvd",
+ CTLFLAG_RD, &vfstats->gorlbc,
+ "Good Loopback Octets Received");
+ SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO,
+ "loopback_good_octets_txd",
+ CTLFLAG_RD, &vfstats->gotlbc,
+ "Good Loopback Octets Transmitted");
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO,
+ "rx_csum_offload_good",
+ CTLFLAG_RD, &sc->rx_csum_good,
+ "Receive Checksum Offload Successes");
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO,
+ "rx_csum_offload_errors",
+ CTLFLAG_RD, &sc->rx_csum_errors,
+ "Receive Checksum Offload Errors");
return;
}
@@ -5449,7 +6421,12 @@ em_print_nvm_info(struct e1000_softc *sc)
j = 0; ++row;
printf("\n0x00%x0 ",row);
}
- e1000_read_nvm(hw, i, 1, &eeprom_data);
+ eeprom_data = 0;
+ if (e1000_read_nvm(hw, i, 1, &eeprom_data) !=
+ E1000_SUCCESS) {
+ printf("\nNVM read failed at offset %#x\n", i);
+ break;
+ }
printf("%04x ", eeprom_data);
}
sx_xunlock(iflib_ctx_lock);
@@ -5587,6 +6564,16 @@ em_set_flowcntl(SYSCTL_HANDLER_ARGS)
return (error);
}
+static void
+em_sysctl_request_reinit(struct e1000_softc *sc)
+{
+ if ((if_getflags(iflib_get_ifp(sc->ctx)) & IFF_UP) == 0)
+ return;
+
+ iflib_request_reset(sc->ctx);
+ iflib_admin_intr_deferred(sc->ctx);
+}
+
/*
* Manage DMA Coalesce:
* Control values:
@@ -5632,7 +6619,7 @@ igb_sysctl_dmac(SYSCTL_HANDLER_ARGS)
return (EINVAL);
}
/* Reinit the interface */
- em_if_init(sc->ctx);
+ em_sysctl_request_reinit(sc);
return (error);
}
@@ -5658,7 +6645,7 @@ em_sysctl_eee(SYSCTL_HANDLER_ARGS)
sc->hw.dev_spec.ich8lan.eee_disable = (value != 0);
else
sc->hw.dev_spec._82575.eee_disable = (value != 0);
- em_if_init(sc->ctx);
+ em_sysctl_request_reinit(sc);
return (0);
}
@@ -5716,8 +6703,15 @@ em_print_debug_info(struct e1000_softc *sc)
{
device_t dev = iflib_get_dev(sc->ctx);
if_t ifp = iflib_get_ifp(sc->ctx);
- struct tx_ring *txr = &sc->tx_queues->txr;
- struct rx_ring *rxr = &sc->rx_queues->rxr;
+ struct tx_ring *txr;
+ struct rx_ring *rxr;
+
+ if (sc->tx_queues == NULL || sc->rx_queues == NULL) {
+ device_printf(dev, "queue state is unavailable\n");
+ return;
+ }
+ txr = &sc->tx_queues->txr;
+ rxr = &sc->rx_queues->rxr;
if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
printf("Interface is RUNNING ");
@@ -5732,15 +6726,15 @@ em_print_debug_info(struct e1000_softc *sc)
for (int i = 0; i < sc->tx_num_queues; i++, txr++) {
device_printf(dev, "TX Queue %d ------\n", i);
device_printf(dev, "hw tdh = %d, hw tdt = %d\n",
- E1000_READ_REG(&sc->hw, E1000_TDH(i)),
- E1000_READ_REG(&sc->hw, E1000_TDT(i)));
+ E1000_READ_REG(&sc->hw, E1000_TDH(txr->me)),
+ E1000_READ_REG(&sc->hw, E1000_TDT(txr->me)));
}
for (int j=0; j < sc->rx_num_queues; j++, rxr++) {
device_printf(dev, "RX Queue %d ------\n", j);
device_printf(dev, "hw rdh = %d, hw rdt = %d\n",
- E1000_READ_REG(&sc->hw, E1000_RDH(j)),
- E1000_READ_REG(&sc->hw, E1000_RDT(j)));
+ E1000_READ_REG(&sc->hw, E1000_RDH(rxr->me)),
+ E1000_READ_REG(&sc->hw, E1000_RDT(rxr->me)));
}
}
diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h
index 4c80c7696952..7116ff11c371 100644
--- a/sys/dev/e1000/if_em.h
+++ b/sys/dev/e1000/if_em.h
@@ -48,6 +48,7 @@
#endif
#include <sys/buf_ring.h>
#include <sys/bus.h>
+#include <sys/callout.h>
#include <sys/endian.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
@@ -95,6 +96,9 @@
#include "e1000_82571.h"
#include "ifdi_if.h"
+struct igb_vf;
+struct igb_vf_mac_filter;
+
/* Tunables */
/*
@@ -133,6 +137,7 @@
#define EM_DEFAULT_RXD 1024
#define EM_DEFAULT_MULTI_RXD 4096
#define IGB_MAX_RXD 4096
+#define IGB_MAX_FRAME_SIZE 9234
/*
* EM_TIDV - Transmit Interrupt Delay Value
@@ -253,8 +258,18 @@
#define IGB_EITR_DIVIDEND 1000000
#define IGB_EITR_SHIFT 2
#define IGB_QVECTOR_MASK 0x7FFC
-#define IGB_INTS_TO_EITR(i) (((IGB_EITR_DIVIDEND/i) & IGB_QVECTOR_MASK) << \
- IGB_EITR_SHIFT)
+#define IGB_INTS_TO_EITR(i) \
+ (((IGB_EITR_DIVIDEND / (i)) << IGB_EITR_SHIFT) & IGB_QVECTOR_MASK)
+#define IGB_EITR_TO_INTS(i) ((IGB_EITR_DIVIDEND << IGB_EITR_SHIFT) / \
+ ((i) & IGB_QVECTOR_MASK))
+
+/*
+ * The average packet size calculation in em_ring_itr() yields an EITR
+ * interval field value. That field is quarter microsecond granular (see
+ * IGB_EITR_SHIFT), so an interval of V is 1000000 / (V / 4) interrupts per
+ * second.
+ */
+#define EM_AIM_DIVIDEND (IGB_EITR_DIVIDEND << IGB_EITR_SHIFT)
#define IGB_LINK_ITR 2000
#define I210_LINK_DELAY 1000
@@ -281,17 +296,40 @@
#define PCICFG_DESC_RING_STATUS 0xe4
#define FLUSH_DESC_REQUIRED 0x100
+#define EM_TX_PTHRESH 31
+#define EM_TX_HTHRESH 1
+#define EM_TX_WTHRESH 1
+
+#define EM_RXDCTL_PTHRESH_MASK 0x0000003F
+#define EM_RXDCTL_HTHRESH_MASK 0x00003F00
+#define EM_RXDCTL_WTHRESH_MASK 0x003F0000
+#define EM_RXDCTL_THRESH_MASK (EM_RXDCTL_PTHRESH_MASK | \
+ EM_RXDCTL_HTHRESH_MASK | \
+ EM_RXDCTL_WTHRESH_MASK)
+
+#define EM_JUMBO_RX_PTHRESH 3
+#define EM_JUMBO_RX_HTHRESH 1
+#define EM_82574_RX_PTHRESH 32
+#define EM_82574_RX_HTHRESH 4
+#define EM_82574_RX_WTHRESH 4
-#define IGB_RX_PTHRESH ((hw->mac.type == e1000_i354) ? 12 : \
- ((hw->mac.type <= e1000_82576) ? 16 : 8))
-#define IGB_RX_HTHRESH 8
-#define IGB_RX_WTHRESH ((hw->mac.type == e1000_82576 && \
- (sc->intr_type == IFLIB_INTR_MSIX)) ? 1 : 4)
+#define IGB_RXDCTL_PTHRESH_MASK 0x0000001F
+#define IGB_RXDCTL_HTHRESH_MASK 0x00001F00
+#define IGB_RXDCTL_WTHRESH_MASK 0x001F0000
+#define IGB_RXDCTL_THRESH_MASK (IGB_RXDCTL_PTHRESH_MASK | \
+ IGB_RXDCTL_HTHRESH_MASK | \
+ IGB_RXDCTL_WTHRESH_MASK)
+#define IGB_82575_RXDCTL_THRESH_MASK 0x003F3F3F
-#define IGB_TX_PTHRESH ((hw->mac.type == e1000_i354) ? 20 : 8)
-#define IGB_TX_HTHRESH 1
-#define IGB_TX_WTHRESH ((hw->mac.type != e1000_82575 && \
- sc->intr_type == IFLIB_INTR_MSIX) ? 1 : 16)
+#define IGB_RX_PTHRESH 8
+#define I354_RX_PTHRESH 12
+#define IGB_RX_HTHRESH 8
+#define IGB_RX_WTHRESH 4
+#define IGB_82576_RX_WTHRESH 1
+
+#define IGB_TX_PTHRESH 8
+#define I354_TX_PTHRESH 20
+#define IGB_TX_HTHRESH 1
/*
* TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be
@@ -374,11 +412,8 @@
#define UPDATE_VF_REG(reg, last, cur) \
do { \
u32 new = E1000_READ_REG(&sc->hw, reg); \
- if (new < last) \
- cur += 0x100000000LL; \
+ cur += (u32)(new - last); \
last = new; \
- cur &= 0xFFFFFFFF00000000LL; \
- cur |= new; \
} while (0)
struct e1000_softc;
@@ -408,8 +443,18 @@ struct tx_ring {
/* Soft stats */
unsigned long tx_irq;
- unsigned long tx_packets;
- unsigned long tx_bytes;
+
+ /*
+ * Free running AIM counters. The producer updates these while
+ * encapsulating packets, then publishes both together at the TX
+ * doorbell. The interrupt handler samples only the published value,
+ * so it cannot observe one counter without the other.
+ */
+ u32 tx_packets;
+ u32 tx_bytes;
+ uint64_t tx_aim_snapshot __aligned(8);
+ u32 tx_packets_last;
+ u32 tx_bytes_last;
/* Saved csum offloading context information */
int csum_flags;
@@ -424,6 +469,15 @@ struct tx_ring {
uint32_t csum_txd_lower; /* last field */
};
+static __inline void
+em_aim_publish(struct tx_ring *txr)
+{
+ uint64_t snapshot;
+
+ snapshot = ((uint64_t)txr->tx_bytes << 32) | txr->tx_packets;
+ atomic_store_rel_64(&txr->tx_aim_snapshot, snapshot);
+}
+
/*
* The Receive ring, one per rx queue
*/
@@ -443,13 +497,29 @@ struct rx_ring {
/* Soft stats */
unsigned long rx_irq;
unsigned long rx_discarded;
- unsigned long rx_packets;
- unsigned long rx_bytes;
- /* Next requested ITR latency */
- u8 rx_nextlatency;
+ /*
+ * Free running AIM counters. RX publishes both together when iflib
+ * returns descriptors to hardware. The interrupt handler samples only
+ * the published value, so watchdog-driven RX processing cannot expose
+ * one counter without the other.
+ */
+ u32 rx_packets;
+ u32 rx_bytes;
+ uint64_t rx_aim_snapshot __aligned(8);
+ u32 rx_packets_last;
+ u32 rx_bytes_last;
};
+static __inline void
+em_aim_publish_rx(struct rx_ring *rxr)
+{
+ uint64_t snapshot;
+
+ snapshot = ((uint64_t)rxr->rx_bytes << 32) | rxr->rx_packets;
+ atomic_store_rel_64(&rxr->rx_aim_snapshot, snapshot);
+}
+
struct em_tx_queue {
struct e1000_softc *sc;
u32 msix;
@@ -469,6 +539,14 @@ struct em_rx_queue {
struct if_irq que_irq;
};
+/* Driver-observed link state and its publication barrier. */
+enum em_link_state {
+ EM_LINK_STATE_DOWN = 0,
+ EM_LINK_STATE_DOWN_RESET_PENDING,
+ EM_LINK_STATE_UP,
+ EM_LINK_STATE_UP_RESET_PENDING,
+};
+
/* Our softc structure */
struct e1000_softc {
struct e1000_hw hw;
@@ -501,6 +579,7 @@ struct e1000_softc {
int if_flags;
int em_insert_vlan_header;
u32 ims;
+ bool allow_64bit_dma;
bool in_detach;
u32 flags;
@@ -528,9 +607,13 @@ struct e1000_softc {
** to repopulate it.
*/
u32 shadow_vfta[EM_VFTA_SIZE];
+ u32 vf_vfta_stale[EM_VFTA_SIZE];
+ u32 vf_vfta_retry[EM_VFTA_SIZE];
+ sbintime_t vf_vlan_retry_deadline;
+ u16 vf_vlan_retry_cursor;
/* Info about the interface */
- u16 link_active;
+ enum em_link_state link_state;
u16 fc;
u16 link_speed;
u16 link_duplex;
@@ -539,6 +622,31 @@ struct e1000_softc {
u32 pba;
int link_mask;
int tso_automasked;
+ u32 promisc_pending;
+ u32 stats_pending;
+
+#ifdef PCI_IOV
+ struct igb_vf *vfs;
+ struct igb_vf_mac_filter *vf_mac_filters;
+ struct callout iov_mbx_retry;
+ u32 iov_vfta[EM_VFTA_SIZE];
+ u32 iov_mdd_cause;
+ u32 iov_pending;
+ u32 iov_spoof_pending;
+ u32 iov_blocked_pending;
+ u32 iov_intr_drain_pending;
+ u32 iov_teardown;
+ struct timeval iov_last_mdd_log;
+ u16 num_vfs;
+ u16 num_vf_mac_filters;
+ u16 pool;
+ bool iov_hw_active;
+ bool iov_mta_valid;
+ bool iov_mbx_retry_initialized;
+ bool iov_pf_mdd_blocked;
+ bool iov_pf_vlan_promisc;
+ bool iov_vfta_valid;
+#endif
u64 que_mask;
@@ -555,16 +663,71 @@ struct e1000_softc {
unsigned long dropped_pkts;
unsigned long link_irq;
unsigned long rx_overruns;
- unsigned long watchdog_events;
+ u64 rx_csum_good;
+ u64 rx_csum_errors;
union {
struct e1000_hw_stats stats; /* !sc->vf_ifp */
struct e1000_vf_stats vf_stats; /* sc->vf_ifp */
} ustats;
+ struct callout vf_queue_retry;
+ struct callout vf_mbx_retry;
+ struct timeval vf_last_queue_log;
+ struct timeval vf_last_mbx_log;
+ u32 vf_queue_retry_new_epoch;
+ u32 vf_queue_retry_pending;
+ u32 vf_mbx_ready;
+ u32 vf_mbx_retry_pending;
u16 vf_ifp;
+ u8 vf_queue_failures;
+ u8 vf_mbx_retry_stage;
+ bool vf_queue_gave_up;
+ bool vf_queue_retry_initialized;
+ bool vf_mbx_retry_initialized;
+ bool vf_queues_sanitized;
+ bool vf_reset_pending;
+ /* A PF can retain auxiliary filters across a VF reset. */
+ bool vf_uc_filters_set;
};
+/*
+ * Shared PF/VF mechanisms and VF policy entry points. The latter live in
+ * if_igbv.c so the VF method table cannot accidentally select PF policy.
+ */
+int em_if_attach_pre(if_ctx_t);
+int em_if_attach_post(if_ctx_t);
+void em_add_device_sysctls(struct e1000_softc *);
+int em_if_set_promisc_impl(if_ctx_t, int);
+bool em_is_valid_ether_addr(const u8 *);
+void em_initialize_transmit_rings(if_ctx_t);
+void em_update_stats_counters(struct e1000_softc *);
+void igb_initialize_receive_rings(if_ctx_t, bool);
+
+int igbv_get_regs(SYSCTL_HANDLER_ARGS);
+int igbv_if_attach_pre(if_ctx_t);
+int igbv_if_attach_post(if_ctx_t);
+int igbv_if_media_change(if_ctx_t);
+void igbv_if_intr_enable(if_ctx_t);
+void igbv_if_intr_disable(if_ctx_t);
+void igbv_if_update_admin_status(if_ctx_t);
+void igbv_initialize_receive_unit(if_ctx_t);
+void igbv_initialize_transmit_unit(if_ctx_t);
+void igbv_mbx_retry_detach(struct e1000_softc *);
+void igbv_mbx_retry_failed(if_ctx_t);
+void igbv_mbx_retry_prepare(struct e1000_softc *);
+void igbv_mbx_retry_stop(struct e1000_softc *);
+void igbv_queue_retry_detach(struct e1000_softc *);
+void igbv_queue_retry_failed(if_ctx_t);
+void igbv_queue_retry_prepare(struct e1000_softc *);
+void igbv_queue_retry_stop(struct e1000_softc *);
+void igbv_reconcile_mac(struct e1000_softc *, if_t);
+bool igbv_reset(if_ctx_t);
+void igbv_log_reset_failure(struct e1000_softc *, s32, bool);
+void igbv_update_uc_addr_list(struct e1000_softc *, if_t);
+void igbv_vlan_retry_add(struct e1000_softc *, u16);
+void igbv_vlan_retry_clear(struct e1000_softc *, u16);
+
/********************************************************************************
* vendor_info_array
*
diff --git a/sys/dev/e1000/if_igb_iov.c b/sys/dev/e1000/if_igb_iov.c
new file mode 100644
index 000000000000..e62ca8aa029c
--- /dev/null
+++ b/sys/dev/e1000/if_igb_iov.c
@@ -0,0 +1,2261 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010-2016, Intel Corporation
+ * Copyright (c) 2026 Kevin Bowling <kbowling@FreeBSD.org>
+ */
+
+#include "if_em.h"
+#include "if_igb_iov.h"
+
+#ifdef PCI_IOV
+
+#include <sys/iov.h>
+#include <sys/sdt.h>
+#include <sys/time.h>
+
+#define IGB_IOV_RAH_POOLSEL_SHIFT 18
+#define IGB_IOV_RAH_POOLSEL_MASK (0xffU << IGB_IOV_RAH_POOLSEL_SHIFT)
+#define IGB_IOV_MAX_MAC_FILTERS 3
+#define IGB_IOV_MAX_MC_HASHES 30
+#define IGB_IOV_MBX_RETRY_COUNT 6
+/* Allow two complete 31-VID replays, then sustain eight additions/second. */
+#define IGB_IOV_VLAN_CHANGE_BURST 64
+#define IGB_IOV_VLAN_CHANGE_INTERVAL (SBT_1S / 8)
+/* 82576 Datasheet rev. 2.0, Section 8.14.16: VMOLR[31] must be one. */
+#define IGB_82576_VMOLR_RSV (1U << 31)
+#define IGB_82576_LVMMC_BLOCK_MASK 0x1c
+#define IGB_82576_NUM_QUEUES 16
+#define IGB_82576_QUEUE_MASK 0xffff
+#define IGB_82576_STAGGERED_QUEUE_SHIFT 8
+#define IGB_82576_VF_QUEUE_STRIDE 8
+#define IGB_82576_VF_QUEUES 2
+#define IGB_I350_DTXCTL_ENABLE_SPOOF_QUEUE (1U << 2)
+#define IGB_I350_LVMMC_MAC_VLAN_SPOOF (1U << 25)
+#define IGB_I350_LVMMC_LAST_Q_SHIFT 29
+#define IGB_I350_LVMMC_LAST_Q_MASK 0x7
+#define IGB_I350_NUM_QUEUES 8
+#define IGB_I350_QUEUE_MASK 0xff
+#define IGB_I350_RESET_ACK_TIMEOUT (100 * SBT_1MS)
+#define IGB_I350_VF_QUEUES 1
+#define IGB_IOV_QUEUE_DISABLE_BUSY_RETRIES 10
+#define IGB_IOV_QUEUE_DISABLE_DELAY_US 10
+#define IGB_IOV_QUEUE_DISABLE_PAUSE (100 * SBT_1US)
+#define IGB_IOV_QUEUE_DISABLE_RETRIES 20
+#define IGB_IOV_VF_QUEUES_MAX 2
+
+#define IGB_VF_CTS (1U << 0)
+#define IGB_VF_CAP_MAC (1U << 1)
+#define IGB_VF_ACTIVE (1U << 2)
+#define IGB_VF_MAC_ANTI_SPOOF (1U << 3)
+#define IGB_VF_ALLOW_PROMISC (1U << 4)
+#define IGB_VF_UCAST_PROMISC (1U << 5)
+#define IGB_VF_MCAST_PROMISC (1U << 6)
+#define IGB_VF_MCAST_OVERFLOW (1U << 7)
+#define IGB_VF_MCAST_OVERFLOW_WARNED (1U << 8)
+#define IGB_VF_MDD_BLOCKED (1U << 9)
+#define IGB_VF_MBX_PENDING (1U << 10)
+/*
+ * After bounded PFU retries, suppress future or overlapping VF requests until
+ * RST/VFLR starts a new mailbox epoch. Intel VF drivers assert CTRL.RST
+ * before sending their mailbox reset request.
+ */
+#define IGB_VF_MBX_GAVE_UP (1U << 11)
+#define IGB_VF_MDD_NOTIFY_PENDING (1U << 12)
+
+struct igb_vf {
+ u32 flags;
+ struct timeval last_nack;
+ struct timeval last_mbx_log;
+ struct timeval last_spoof_log;
+ struct timeval last_mdd_log;
+ struct timeval last_queue_log;
+ sbintime_t mbx_retry_at;
+ sbintime_t mdd_notify_at;
+ sbintime_t vlan_token_time;
+ u16 pool;
+ u16 rar_index;
+ u16 max_frame_size;
+ u16 mc_count;
+ u16 vlan_count;
+ u16 vlan_tokens;
+ u16 default_vlan;
+ u8 mbx_retry_count;
+ u8 mac[ETHER_ADDR_LEN];
+ u16 mc_hashes[IGB_IOV_MAX_MC_HASHES];
+ u32 vlans[EM_VFTA_SIZE];
+};
+
+struct igb_vf_mac_filter {
+ bool active;
+ u16 pool;
+ u16 rar_index;
+ u8 mac[ETHER_ADDR_LEN];
+};
+
+MALLOC_DEFINE(M_IGB_IOV, "igb_iov", "igb SR-IOV allocations");
+
+/*
+ * These logical-write probes let hardware tests verify the elision policy.
+ * e1000_write_vfta_i350() expands one VFTA call into ten physical writes, so
+ * the probes intentionally count calls made by the rebuild rather than MMIO
+ * transactions. The state probe exposes the final software images while the
+ * stack arrays are still live.
+ */
+SDT_PROVIDER_DEFINE(igb_iov);
+SDT_PROBE_DEFINE3(igb_iov, vlan, rebuild, vfta_clear,
+ "struct e1000_softc *", "u_int", "uint32_t");
+SDT_PROBE_DEFINE3(igb_iov, vlan, rebuild, vlvf_write,
+ "struct e1000_softc *", "u_int", "uint32_t");
+SDT_PROBE_DEFINE3(igb_iov, vlan, rebuild, vfta_set,
+ "struct e1000_softc *", "u_int", "uint32_t");
+SDT_PROBE_DEFINE3(igb_iov, vlan, rebuild, state,
+ "struct e1000_softc *", "uint32_t *", "uint32_t *");
+SDT_PROBE_DEFINE4(igb_iov, mdd, sample, wvbr,
+ "struct e1000_softc *", "uint32_t", "uint32_t", "uint32_t");
+
+static const struct timeval igb_iov_nack_interval = { 2, 0 };
+static const struct timeval igb_iov_mbx_log_interval = { 2, 0 };
+static const struct timeval igb_iov_spoof_log_interval = { 2, 0 };
+static const struct timeval igb_iov_mdd_log_interval = { 2, 0 };
+static const sbintime_t igb_iov_mdd_notify_retry = SBT_1S / 2;
+static const sbintime_t igb_iov_mbx_retry_delay[IGB_IOV_MBX_RETRY_COUNT] = {
+ SBT_1MS,
+ 2 * SBT_1MS,
+ 4 * SBT_1MS,
+ 8 * SBT_1MS,
+ 16 * SBT_1MS,
+ 32 * SBT_1MS,
+};
+
+static void igb_iov_clear_mac_filters(struct e1000_softc *,
+ const struct igb_vf *);
+static bool igb_iov_mac_in_use(struct e1000_softc *, const u8 *,
+ const struct igb_vf *);
+static bool igb_iov_vlan_present(struct e1000_softc *, u16, bool);
+static int igb_iov_vlan_unique_count(struct e1000_softc *, bool);
+
+static void
+igb_iov_mbx_retry_callout(void *arg)
+{
+ struct e1000_softc *sc;
+
+ sc = arg;
+ /*
+ * Mailbox service is serialized by iflib's context lock. The
+ * callout only re-enters through the ordinary admin task.
+ */
+ iflib_admin_intr_deferred(sc->ctx);
+}
+
+static u_int
+igb_iov_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int idx)
+{
+ u8 *mta;
+
+ if (idx == MAX_NUM_MULTICAST_ADDRESSES)
+ return (0);
+ mta = arg;
+ memcpy(&mta[idx * ETHER_ADDR_LEN], LLADDR(sdl), ETHER_ADDR_LEN);
+ return (1);
+}
+
+static bool
+igb_iov_pf_vlan_promisc(struct e1000_softc *sc)
+{
+ if_t ifp;
+
+ ifp = iflib_get_ifp(sc->ctx);
+ return (sc->iov_pf_vlan_promisc ||
+ (if_getflags(ifp) & IFF_PROMISC) != 0);
+}
+
+static bool
+igb_iov_mac_valid(const u8 *mac)
+{
+ static const u8 zero[ETHER_ADDR_LEN];
+
+ return (!ETHER_IS_MULTICAST(mac) &&
+ memcmp(mac, zero, ETHER_ADDR_LEN) != 0);
+}
+
+static bool
+igb_iov_nack_allowed(struct igb_vf *vf)
+{
+ return (ratecheck(&vf->last_nack, &igb_iov_nack_interval) != 0);
+}
+
+static void
+igb_iov_reset_vlan_rate(struct igb_vf *vf)
+{
+
+ vf->vlan_token_time = getsbinuptime();
+ vf->vlan_tokens = IGB_IOV_VLAN_CHANGE_BURST;
+}
+
+static bool
+igb_iov_vlan_add_allowed(struct igb_vf *vf)
+{
+ sbintime_t elapsed, now;
+ uint64_t refill;
+
+ now = getsbinuptime();
+ elapsed = now - vf->vlan_token_time;
+ if (elapsed >= IGB_IOV_VLAN_CHANGE_INTERVAL) {
+ refill = elapsed / IGB_IOV_VLAN_CHANGE_INTERVAL;
+ vf->vlan_tokens = min((uint64_t)IGB_IOV_VLAN_CHANGE_BURST,
+ vf->vlan_tokens + refill);
+ vf->vlan_token_time = now;
+ }
+ if (vf->vlan_tokens == 0)
+ return (false);
+ vf->vlan_tokens--;
+ return (true);
+}
+
+static u32
+igb_iov_reply_header(u32 request, bool cts, bool ack)
+{
+ u32 reply, type;
+
+ type = request & 0xffff;
+ if (type == E1000_VF_SET_MAC_ADDR &&
+ (request & E1000_VT_MSGINFO_MASK) != 0)
+ reply = request;
+ else
+ reply = type;
+ reply &= ~(E1000_VT_MSGTYPE_ACK | E1000_VT_MSGTYPE_NACK |
+ E1000_VT_MSGTYPE_CTS);
+ if (cts)
+ reply |= E1000_VT_MSGTYPE_CTS;
+ reply |= ack ? E1000_VT_MSGTYPE_ACK : E1000_VT_MSGTYPE_NACK;
+ return (reply);
+}
+
+bool
+igb_iov_supported(const struct e1000_softc *sc)
+{
+ switch (sc->hw.mac.type) {
+ case e1000_82576:
+ case e1000_i350:
+ return (true);
+ default:
+ return (false);
+ }
+}
+
+bool
+igb_iov_enabled(const struct e1000_softc *sc)
+{
+ return (sc->num_vfs != 0);
+}
+
+int
+igb_iov_attach(struct e1000_softc *sc)
+{
+ nvlist_t *pf_schema, *vf_schema;
+ int error, iov_pos;
+
+ if (!igb_iov_supported(sc))
+ return (0);
+ if (pci_find_extcap(sc->dev, PCIZ_SRIOV, &iov_pos) != 0)
+ return (0);
+
+ pf_schema = pci_iov_schema_alloc_node();
+ vf_schema = pci_iov_schema_alloc_node();
+ pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
+ pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
+ IOV_SCHEMA_HASDEFAULT, true);
+ pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
+ IOV_SCHEMA_HASDEFAULT, false);
+ pci_iov_schema_add_bool(vf_schema, "allow-promisc",
+ IOV_SCHEMA_HASDEFAULT, false);
+ pci_iov_schema_add_vlan(vf_schema, "vlan", IOV_SCHEMA_HASDEFAULT,
+ VF_VLAN_TRUNK);
+
+ error = pci_iov_attach(sc->dev, pf_schema, vf_schema);
+ if (error != 0)
+ device_printf(sc->dev,
+ "failed to attach SR-IOV configuration interface: %d\n",
+ error);
+ else {
+ callout_init(&sc->iov_mbx_retry, 1);
+ sc->iov_mbx_retry_initialized = true;
+ }
+ return (error);
+}
+
+void
+igb_iov_detach(struct e1000_softc *sc)
+{
+
+ if (!sc->iov_mbx_retry_initialized)
+ return;
+ callout_drain(&sc->iov_mbx_retry);
+ sc->iov_mbx_retry_initialized = false;
+}
+
+static u32
+igb_iov_active_mask(struct e1000_softc *sc)
+{
+ u32 mask;
+ int i;
+
+ mask = 0;
+ for (i = 0; i < sc->num_vfs; i++)
+ if (sc->vfs[i].flags & IGB_VF_ACTIVE)
+ mask |= 1U << i;
+ return (mask);
+}
+
+static void
+igb_iov_map_rar(struct e1000_softc *sc, u16 rar, const u8 *mac, u16 pool)
+{
+ struct e1000_hw *hw;
+ u32 rah;
+
+ hw = &sc->hw;
+ e1000_rar_set(hw, __DECONST(u8 *, mac), rar);
+ rah = E1000_READ_REG(hw, E1000_RAH(rar));
+ rah &= ~IGB_IOV_RAH_POOLSEL_MASK;
+ rah |= 1U << (IGB_IOV_RAH_POOLSEL_SHIFT + pool);
+ E1000_WRITE_REG(hw, E1000_RAH(rar), rah);
+}
+
+static void
+igb_iov_clear_rar(struct e1000_softc *sc, u16 rar)
+{
+ u8 zero[ETHER_ADDR_LEN] = {};
+
+ e1000_rar_set(&sc->hw, zero, rar);
+}
+
+static void
+igb_iov_clear_mac_filters(struct e1000_softc *sc, const struct igb_vf *vf)
+{
+ struct igb_vf_mac_filter *filter;
+ int i;
+
+ for (i = 0; i < sc->num_vf_mac_filters; i++) {
+ filter = &sc->vf_mac_filters[i];
+ if (!filter->active || filter->pool != vf->pool)
+ continue;
+ igb_iov_clear_rar(sc, filter->rar_index);
+ filter->active = false;
+ memset(filter->mac, 0, sizeof(filter->mac));
+ }
+}
+
+static u32
+igb_iov_switch_reg(struct e1000_softc *sc)
+{
+ return (sc->hw.mac.type == e1000_82576 ?
+ E1000_DTXSWC : E1000_TXSWC);
+}
+
+static void
+igb_iov_set_anti_spoof(struct e1000_softc *sc, struct igb_vf *vf)
+{
+ struct e1000_hw *hw;
+ u32 reg, value;
+
+ hw = &sc->hw;
+ reg = igb_iov_switch_reg(sc);
+ value = E1000_READ_REG(hw, reg);
+ value &= ~((1U << vf->pool) |
+ (1U << (vf->pool + E1000_DTXSWC_VLAN_SPOOF_SHIFT)));
+ if (vf->flags & IGB_VF_MAC_ANTI_SPOOF)
+ value |= 1U << vf->pool;
+ if (vf->flags & IGB_VF_ACTIVE)
+ value |= 1U <<
+ (vf->pool + E1000_DTXSWC_VLAN_SPOOF_SHIFT);
+ E1000_WRITE_REG(hw, reg, value);
+}
+
+static void
+igb_iov_set_uta(struct e1000_softc *sc)
+{
+ struct e1000_hw *hw;
+ bool enable;
+ int i;
+
+ if (!igb_iov_enabled(sc) || sc->hw.mac.type != e1000_82576)
+ return;
+
+ hw = &sc->hw;
+ enable = (E1000_READ_REG(hw, E1000_VMOLR(sc->pool)) &
+ E1000_VMOLR_ROPE) != 0;
+ for (i = 0; i < sc->num_vfs; i++)
+ if ((sc->vfs[i].flags &
+ (IGB_VF_ACTIVE | IGB_VF_UCAST_PROMISC)) ==
+ (IGB_VF_ACTIVE | IGB_VF_UCAST_PROMISC)) {
+ enable = true;
+ break;
+ }
+
+ for (i = 0; i < MAX_MTA_REG; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_UTA, i,
+ enable ? 0xffffffffU : 0);
+}
+
+static void
+igb_iov_configure_dvmolr(struct e1000_softc *sc, u16 pool,
+ bool strip_vlan, bool hide_vlan, bool vf_pool)
+{
+ struct e1000_hw *hw;
+ u32 dvmolr;
+
+ hw = &sc->hw;
+ if (hw->mac.type != e1000_i350)
+ return;
+
+ dvmolr = E1000_READ_REG(hw, E1000_DVMOLR(pool));
+ dvmolr &= ~(E1000_DVMOLR_HIDVLAN | E1000_DVMOLR_STRVLAN |
+ E1000_DVMOLR_STRCRC);
+ if (hide_vlan)
+ dvmolr |= E1000_DVMOLR_HIDVLAN;
+ if (strip_vlan)
+ dvmolr |= E1000_DVMOLR_STRVLAN;
+ if (vf_pool || strip_vlan ||
+ (E1000_READ_REG(hw, E1000_RCTL) & E1000_RCTL_SECRC) != 0)
+ dvmolr |= E1000_DVMOLR_STRCRC;
+ E1000_WRITE_REG(hw, E1000_DVMOLR(pool), dvmolr);
+}
+
+static void
+igb_iov_configure_vmolr(struct e1000_softc *sc, struct igb_vf *vf)
+{
+ struct e1000_hw *hw;
+ u32 max_frame_size, vmolr, vmvir;
+
+ hw = &sc->hw;
+ max_frame_size = vf->max_frame_size;
+ if (vf->vlan_count != 0)
+ max_frame_size = min(max_frame_size + VLAN_TAG_SIZE,
+ IGB_IOV_MAX_FRAME_SIZE);
+ vmolr = E1000_READ_REG(hw, E1000_VMOLR(vf->pool));
+ vmolr &= ~(E1000_VMOLR_RLPML_MASK | E1000_VMOLR_RSSE |
+ E1000_VMOLR_VPE | E1000_VMOLR_UPE | E1000_VMOLR_ROMPE |
+ E1000_VMOLR_ROPE | E1000_VMOLR_MPME | E1000_VMOLR_STRVLAN);
+ vmolr |= E1000_VMOLR_BAM | E1000_VMOLR_LPE |
+ (max_frame_size & E1000_VMOLR_RLPML_MASK);
+ if (vf->default_vlan == 0)
+ vmolr |= E1000_VMOLR_AUPE;
+ if (vf->mc_count != 0 &&
+ (vf->flags & (IGB_VF_MCAST_PROMISC |
+ IGB_VF_MCAST_OVERFLOW)) == 0)
+ vmolr |= E1000_VMOLR_ROMPE;
+ if (hw->mac.type == e1000_82576)
+ vmolr |= IGB_82576_VMOLR_RSV;
+
+ if (vf->flags & IGB_VF_UCAST_PROMISC) {
+ if (hw->mac.type == e1000_82576)
+ vmolr |= E1000_VMOLR_ROPE;
+ else
+ vmolr |= E1000_VMOLR_UPE;
+ }
+ /*
+ * The mailbox can describe only 30 hashes. Fall back to receiving all
+ * multicast within the VF's VLAN membership when that list overflows.
+ */
+ if ((vf->flags & (IGB_VF_MCAST_PROMISC |
+ IGB_VF_MCAST_OVERFLOW)) != 0)
+ vmolr |= E1000_VMOLR_MPME;
+ if (hw->mac.type == e1000_82576 && vf->vlan_count != 0)
+ vmolr |= E1000_VMOLR_STRVLAN;
+ /* A nonzero default VLAN makes this VF an untagged access port. */
+ if (vf->default_vlan == 0)
+ vmvir = 0;
+ else
+ vmvir = vf->default_vlan | E1000_VMVIR_VLANA_DEFAULT;
+
+ E1000_WRITE_REG(hw, E1000_VMOLR(vf->pool), vmolr);
+ E1000_WRITE_REG(hw, E1000_VMVIR(vf->pool), vmvir);
+ igb_iov_configure_dvmolr(sc, vf->pool, vf->vlan_count != 0,
+ vf->default_vlan != 0, true);
+}
+
+static void
+igb_iov_configure_pf_vmolr(struct e1000_softc *sc)
+{
+ struct e1000_hw *hw;
+ if_t ifp;
+ bool strip_vlan;
+ u32 max_frame_size;
+ u32 old_vmolr, vmolr;
+
+ hw = &sc->hw;
+ ifp = iflib_get_ifp(sc->ctx);
+ max_frame_size = min(sc->shared->isc_max_frame_size + VLAN_TAG_SIZE,
+ IGB_IOV_MAX_FRAME_SIZE);
+ strip_vlan = (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_VME) != 0;
+ old_vmolr = E1000_READ_REG(hw, E1000_VMOLR(sc->pool));
+ vmolr = E1000_VMOLR_BAM | E1000_VMOLR_AUPE |
+ E1000_VMOLR_LPE |
+ (max_frame_size & E1000_VMOLR_RLPML_MASK);
+ if (hw->mac.type == e1000_82576) {
+ vmolr |= IGB_82576_VMOLR_RSV;
+ if (strip_vlan)
+ vmolr |= E1000_VMOLR_STRVLAN;
+ } else
+ vmolr |= old_vmolr & E1000_VMOLR_VPE;
+
+ if (if_getflags(ifp) & IFF_PROMISC) {
+ if (hw->mac.type == e1000_82576)
+ vmolr |= E1000_VMOLR_ROPE;
+ else
+ vmolr |= E1000_VMOLR_UPE | E1000_VMOLR_VPE;
+ vmolr |= E1000_VMOLR_MPME;
+ } else if ((if_getflags(ifp) & IFF_ALLMULTI) != 0 ||
+ if_llmaddr_count(ifp) >= MAX_NUM_MULTICAST_ADDRESSES)
+ vmolr |= E1000_VMOLR_MPME;
+ else if (if_llmaddr_count(ifp) != 0)
+ vmolr |= E1000_VMOLR_ROMPE;
+
+ E1000_WRITE_REG(hw, E1000_VMOLR(sc->pool), vmolr);
+ igb_iov_configure_dvmolr(sc, sc->pool, strip_vlan, false, false);
+}
+
+void
+igb_iov_update_pf_vmolr(struct e1000_softc *sc)
+{
+ if (!igb_iov_enabled(sc))
+ return;
+
+ igb_iov_configure_pf_vmolr(sc);
+ igb_iov_set_uta(sc);
+}
+
+u32
+igb_iov_intr_mask(const struct e1000_softc *sc)
+{
+ if (!sc->iov_hw_active)
+ return (0);
+ return (E1000_IMS_VMMB | E1000_IMS_MDDET);
+}
+
+void
+igb_iov_intr_drain_stale(struct e1000_softc *sc)
+{
+ struct e1000_hw *hw;
+ u32 icr;
+
+ if (atomic_readandclear_32(&sc->iov_intr_drain_pending) == 0)
+ return;
+ hw = &sc->hw;
+ /*
+ * Consume setup-time diagnostic state at the actual transition from
+ * masked to armed. Read ICR last so an event arriving after the drain
+ * remains pending and is delivered when the caller enables MDDET.
+ */
+ (void)E1000_READ_REG(hw, E1000_LVMMC);
+ if (hw->mac.type == e1000_82576)
+ (void)E1000_READ_REG(hw, E1000_WVBR);
+ icr = E1000_READ_REG(hw, E1000_ICR);
+ /*
+ * em_if_init() injects LSC after IOV setup to close the post-reset
+ * link race. Preserve that cause across this MDDET-specific drain.
+ */
+ if (__predict_true(icr != 0xffffffff) &&
+ (icr & E1000_ICR_LSC) != 0)
+ E1000_WRITE_REG(hw, E1000_ICS, E1000_ICS_LSC);
+}
+
+static void
+igb_iov_vfta_shadow_invalidate(struct e1000_softc *sc)
+{
+
+ /*
+ * I350 erratum 20 makes VFTA reads unreliable while VMDq loopback or
+ * anti-spoofing is active. The shadow is therefore authoritative
+ * until a reset or another independent hardware writer invalidates
+ * it. Readback cannot reliably audit a stale-but-valid shadow on
+ * this part, so keep all shadow mutation in these two helpers.
+ */
+ memset(sc->iov_vfta, 0, sizeof(sc->iov_vfta));
+ sc->iov_vfta_valid = false;
+}
+
+static void
+igb_iov_vfta_shadow_store(struct e1000_softc *sc, const u32 *vfta)
+{
+
+ memcpy(sc->iov_vfta, vfta, sizeof(sc->iov_vfta));
+ sc->iov_vfta_valid = true;
+}
+
+static void
+igb_iov_notify_vfs_reset(struct e1000_softc *sc)
+{
+ struct igb_vf *vf;
+ struct e1000_hw *hw;
+ sbintime_t deadline;
+ u32 msg, pending, undelivered;
+ int i;
+
+ hw = &sc->hw;
+ /*
+ * Process VFLRs first and wait only for VFs that completed their
+ * mailbox handshake. An unattached VF has nobody who can acknowledge.
+ */
+ igb_iov_handle_mbx(sc);
+ pending = 0;
+ for (i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ if ((vf->flags & (IGB_VF_ACTIVE | IGB_VF_CTS)) ==
+ (IGB_VF_ACTIVE | IGB_VF_CTS))
+ pending |= 1U << i;
+ }
+ if (pending == 0)
+ return;
+
+ /*
+ * I350 SDM section 4.6.11.2.3 requires each VF to acknowledge a
+ * mailbox warning before the PF asserts CTRL.RST.
+ *
+ * The mailbox pass above drained requests and stale acknowledgements.
+ * A VF read of the new notification sets its ACK bit.
+ */
+ undelivered = 0;
+ for (i = 0; i < sc->num_vfs; i++) {
+ if ((pending & (1U << i)) == 0)
+ continue;
+ msg = E1000_PF_CONTROL_MSG;
+ if (e1000_write_mbx(hw, &msg, 1, i) != 0) {
+ undelivered |= 1U << i;
+ pending &= ~(1U << i);
+ }
+ }
+ if (undelivered != 0)
+ device_printf(sc->dev,
+ "could not deliver reset warning to VF mask %#x\n",
+ undelivered);
+
+ deadline = getsbinuptime() + IGB_I350_RESET_ACK_TIMEOUT;
+ while (pending != 0 && getsbinuptime() < deadline) {
+ for (i = 0; i < sc->num_vfs; i++) {
+ if ((pending & (1U << i)) != 0 &&
+ e1000_check_for_ack(hw, i) == 0)
+ pending &= ~(1U << i);
+ }
+ if (pending != 0)
+ pause_sbt("igback", SBT_1MS, 0, C_HARDCLOCK);
+ }
+ if (pending != 0)
+ device_printf(sc->dev,
+ "VF reset acknowledgement timed out for mask %#x\n",
+ pending);
+}
+
+void
+igb_iov_reset_prepare(struct e1000_softc *sc)
+{
+ struct e1000_hw *hw;
+ u32 mask;
+
+ if (sc->iov_hw_active) {
+ hw = &sc->hw;
+ if (atomic_load_acq_32(&sc->iov_teardown) == 0) {
+ if (hw->mac.type == e1000_i350)
+ igb_iov_notify_vfs_reset(sc);
+ else
+ igb_iov_ping_all_vfs(sc);
+ }
+
+ /* Stop VF DMA before the PF asserts CTRL.RST. */
+ mask = 1U << sc->pool;
+ E1000_WRITE_REG(hw, E1000_VFRE, mask);
+ E1000_WRITE_REG(hw, E1000_VFTE, mask);
+ E1000_WRITE_FLUSH(hw);
+ }
+ sc->iov_hw_active = false;
+ if (sc->iov_mbx_retry_initialized)
+ callout_stop(&sc->iov_mbx_retry);
+ sc->iov_mta_valid = false;
+ igb_iov_vfta_shadow_invalidate(sc);
+ atomic_readandclear_32(&sc->iov_mdd_cause);
+ atomic_readandclear_32(&sc->iov_pending);
+ atomic_readandclear_32(&sc->iov_spoof_pending);
+ atomic_readandclear_32(&sc->iov_blocked_pending);
+ /*
+ * Normal iflib initialization prepares the reset before
+ * igb_iov_initialize() requests this drain. Preserve a still-pending
+ * I350 request across a later stop or repeated preparation so the next
+ * interrupt arm consumes it. Other families retain the ordinary
+ * stop-time cleanup.
+ */
+ if (sc->hw.mac.type != e1000_i350)
+ atomic_readandclear_32(&sc->iov_intr_drain_pending);
+}
+
+void
+igb_iov_rebuild_mta(struct e1000_softc *sc)
+{
+ struct e1000_hw *hw;
+ struct igb_vf *vf;
+ u32 hash_bit, hash_reg, hash_value;
+ u32 mta[MAX_MTA_REG] = {};
+ u16 hash;
+ bool changed;
+ int i, j, mcnt;
+
+ if (!igb_iov_enabled(sc))
+ return;
+
+ hw = &sc->hw;
+ memset(sc->mta, 0,
+ ETHER_ADDR_LEN * MAX_NUM_MULTICAST_ADDRESSES);
+ mcnt = if_foreach_llmaddr(iflib_get_ifp(sc->ctx),
+ igb_iov_copy_maddr, sc->mta);
+ mcnt = min(mcnt, MAX_NUM_MULTICAST_ADDRESSES);
+ for (i = 0; i < mcnt; i++) {
+ hash_value = e1000_hash_mc_addr(hw,
+ &sc->mta[i * ETHER_ADDR_LEN]);
+ hash_reg = (hash_value >> 5) &
+ (hw->mac.mta_reg_count - 1);
+ hash_bit = hash_value & 0x1f;
+ mta[hash_reg] |= 1U << hash_bit;
+ }
+ for (i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ if (!(vf->flags & IGB_VF_ACTIVE))
+ continue;
+ for (j = 0; j < vf->mc_count; j++) {
+ hash = vf->mc_hashes[j] & 0xfff;
+ mta[(hash >> 5) & (hw->mac.mta_reg_count - 1)] |=
+ 1U << (hash & 0x1f);
+ }
+ }
+
+ changed = false;
+ for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) {
+ if (sc->iov_mta_valid && hw->mac.mta_shadow[i] == mta[i])
+ continue;
+ hw->mac.mta_shadow[i] = mta[i];
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, mta[i]);
+ changed = true;
+ }
+ if (changed)
+ E1000_WRITE_FLUSH(hw);
+ sc->iov_mta_valid = true;
+}
+
+static int
+igb_iov_vlvf_add(u32 *vlvf, const u32 *old_vlvf, u16 vid, u16 pool,
+ bool preserve_only)
+{
+ int free_slot, i;
+
+ free_slot = -1;
+ for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
+ if ((vlvf[i] & E1000_VLVF_VLANID_ENABLE) != 0 &&
+ (vlvf[i] & E1000_VLVF_VLANID_MASK) == vid) {
+ vlvf[i] |= 1U << (E1000_VLVF_POOLSEL_SHIFT + pool);
+ return (0);
+ }
+ if (free_slot == -1 &&
+ (vlvf[i] & E1000_VLVF_VLANID_ENABLE) == 0)
+ free_slot = i;
+ }
+ for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++)
+ if ((old_vlvf[i] & E1000_VLVF_VLANID_ENABLE) != 0 &&
+ (old_vlvf[i] & E1000_VLVF_VLANID_MASK) == vid &&
+ (vlvf[i] & E1000_VLVF_VLANID_ENABLE) == 0) {
+ free_slot = i;
+ break;
+ }
+ if (preserve_only && (i == E1000_VLVF_ARRAY_SIZE))
+ return (ENOENT);
+ if (free_slot == -1)
+ return (ENOSPC);
+
+ vlvf[free_slot] = E1000_VLVF_VLANID_ENABLE | vid |
+ (1U << (E1000_VLVF_POOLSEL_SHIFT + pool));
+ return (0);
+}
+
+void
+igb_iov_rebuild_vlan(struct e1000_softc *sc)
+{
+ struct e1000_hw *hw;
+ struct igb_vf *vf;
+ u32 old_vlvf[E1000_VLVF_ARRAY_SIZE];
+ u32 effective_vfta[EM_VFTA_SIZE], vfta[EM_VFTA_SIZE];
+ u32 vlvf[E1000_VLVF_ARRAY_SIZE];
+ u32 old_vfta, rctl, vmolr;
+ bool force_vfta, pf_overflow, pf_vlan_promisc, preserve_pf;
+ bool vfta_changed, vlvf_changed;
+ int i, vid;
+
+ if (!igb_iov_enabled(sc))
+ return;
+
+ hw = &sc->hw;
+ rctl = E1000_READ_REG(hw, E1000_RCTL);
+ rctl &= ~E1000_RCTL_CFIEN;
+ rctl |= E1000_RCTL_VFE;
+ E1000_WRITE_REG(hw, E1000_RCTL, rctl);
+ memcpy(vfta, sc->shadow_vfta, sizeof(vfta));
+ memset(vlvf, 0, sizeof(vlvf));
+ for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++)
+ old_vlvf[i] = E1000_READ_REG(hw, E1000_VLVF(i));
+
+ pf_vlan_promisc = igb_iov_pf_vlan_promisc(sc);
+ pf_overflow = !pf_vlan_promisc && hw->mac.type == e1000_i350 &&
+ igb_iov_vlan_unique_count(sc, true) > E1000_VLVF_ARRAY_SIZE;
+ preserve_pf = !pf_vlan_promisc && !pf_overflow;
+
+ /* First keep every surviving VF mapping in its current slot. */
+ for (i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ if (!(vf->flags & IGB_VF_ACTIVE))
+ continue;
+ for (vid = 0; vid < 4096; vid++) {
+ if ((vf->vlans[vid >> 5] & (1U << (vid & 0x1f))) ==
+ 0)
+ continue;
+ (void)igb_iov_vlvf_add(vlvf, old_vlvf, vid,
+ vf->pool, true);
+ }
+ }
+
+ /*
+ * Preserve PF mappings unless I350 needs their slots for VFs.
+ * PF-only VLANs on 82576 intentionally have no VLVF mapping and
+ * reach the default PF pool after passing the global VFTA.
+ */
+ if (preserve_pf)
+ for (vid = 0; vid < 4096; vid++) {
+ if ((sc->shadow_vfta[vid >> 5] &
+ (1U << (vid & 0x1f))) == 0)
+ continue;
+ if (hw->mac.type == e1000_82576 &&
+ !igb_iov_vlan_present(sc, vid, false))
+ continue;
+ (void)igb_iov_vlvf_add(vlvf, old_vlvf, vid,
+ sc->pool, true);
+ }
+
+ /* Allocate new VF mappings before PF mappings. */
+ for (i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ if (!(vf->flags & IGB_VF_ACTIVE))
+ continue;
+ for (vid = 0; vid < 4096; vid++) {
+ if ((vf->vlans[vid >> 5] & (1U << (vid & 0x1f))) ==
+ 0)
+ continue;
+ if (igb_iov_vlvf_add(vlvf, old_vlvf, vid,
+ vf->pool, false) == 0)
+ vfta[vid >> 5] |= 1U << (vid & 0x1f);
+ }
+ igb_iov_configure_vmolr(sc, vf);
+ }
+ if (!pf_vlan_promisc)
+ for (vid = 0; vid < 4096; vid++) {
+ if ((sc->shadow_vfta[vid >> 5] &
+ (1U << (vid & 0x1f))) == 0)
+ continue;
+ /*
+ * With no VLVF match, 82576 sends a globally admitted
+ * VLAN to the default PF pool. A VLVF entry is needed
+ * only when this VLAN is also assigned to a VF.
+ */
+ if (hw->mac.type == e1000_82576 &&
+ !igb_iov_vlan_present(sc, vid, false))
+ continue;
+ if (igb_iov_vlvf_add(vlvf, old_vlvf, vid,
+ sc->pool, false) != 0)
+ pf_overflow = true;
+ }
+
+ if (pf_vlan_promisc) {
+ memset(vfta, 0xff, sizeof(vfta));
+ for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++)
+ if ((vlvf[i] & E1000_VLVF_VLANID_ENABLE) != 0)
+ vlvf[i] |= 1U <<
+ (E1000_VLVF_POOLSEL_SHIFT + sc->pool);
+ }
+
+ /*
+ * Establish the PF fallback before an overflowing I350 rebuild can
+ * displace one of its old VLVF mappings.
+ */
+ vmolr = E1000_READ_REG(hw, E1000_VMOLR(sc->pool));
+ vmolr &= ~E1000_VMOLR_VPE;
+ if (hw->mac.type == e1000_i350 &&
+ (pf_overflow || pf_vlan_promisc))
+ vmolr |= E1000_VMOLR_VPE;
+ E1000_WRITE_REG(hw, E1000_VMOLR(sc->pool), vmolr);
+
+ /*
+ * Remove global VFTA membership before removing a VLAN entirely, and
+ * add a VLVF mapping before globally admitting a new VF VLAN. A
+ * transition to a PF-only VLAN deliberately retains VFTA membership
+ * and falls through to the default PF pool.
+ */
+ force_vfta = hw->mac.type == e1000_i350 &&
+ !sc->iov_vfta_valid;
+ vfta_changed = false;
+ for (i = 0; i < EM_VFTA_SIZE; i++) {
+ /*
+ * I350 erratum 20 makes VFTA reads unreliable while VMDq
+ * loopback or anti-spoofing is active. Its ten-write
+ * workaround is already in e1000_write_vfta_i350(). Force a
+ * complete clear when the authoritative shadow is invalid;
+ * 82576 can safely diff against its live register contents.
+ */
+ if (hw->mac.type == e1000_i350)
+ old_vfta = force_vfta ? 0 : sc->iov_vfta[i];
+ else
+ old_vfta =
+ E1000_READ_REG_ARRAY(hw, E1000_VFTA, i);
+ effective_vfta[i] = old_vfta & vfta[i];
+ if (force_vfta || effective_vfta[i] != old_vfta) {
+ SDT_PROBE3(igb_iov, vlan, rebuild, vfta_clear,
+ sc, i, effective_vfta[i]);
+ e1000_write_vfta(hw, i, effective_vfta[i]);
+ vfta_changed = true;
+ }
+ }
+ if (vfta_changed)
+ E1000_WRITE_FLUSH(hw);
+ vlvf_changed = false;
+ for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++)
+ if (vlvf[i] != old_vlvf[i]) {
+ SDT_PROBE3(igb_iov, vlan, rebuild, vlvf_write,
+ sc, i, vlvf[i]);
+ E1000_WRITE_REG(hw, E1000_VLVF(i), vlvf[i]);
+ vlvf_changed = true;
+ }
+ if (vlvf_changed)
+ E1000_WRITE_FLUSH(hw);
+ vfta_changed = false;
+ for (i = 0; i < EM_VFTA_SIZE; i++)
+ if (vfta[i] != effective_vfta[i]) {
+ SDT_PROBE3(igb_iov, vlan, rebuild, vfta_set,
+ sc, i, vfta[i]);
+ e1000_write_vfta(hw, i, vfta[i]);
+ vfta_changed = true;
+ }
+ if (vfta_changed)
+ E1000_WRITE_FLUSH(hw);
+ SDT_PROBE3(igb_iov, vlan, rebuild, state, sc, vfta, vlvf);
+ igb_iov_vfta_shadow_store(sc, vfta);
+}
+
+static bool
+igb_iov_vlan_present(struct e1000_softc *sc, u16 vid, bool include_pf)
+{
+ int i;
+
+ if (include_pf &&
+ (sc->shadow_vfta[vid >> 5] & (1U << (vid & 0x1f))) != 0)
+ return (true);
+ for (i = 0; i < sc->num_vfs; i++)
+ if ((sc->vfs[i].flags & IGB_VF_ACTIVE) != 0 &&
+ (sc->vfs[i].vlans[vid >> 5] &
+ (1U << (vid & 0x1f))) != 0)
+ return (true);
+ return (false);
+}
+
+static int
+igb_iov_vlan_unique_count(struct e1000_softc *sc, bool include_pf)
+{
+ u32 vlans;
+ int count, i, word;
+
+ count = 0;
+ for (word = 0; word < EM_VFTA_SIZE; word++) {
+ vlans = include_pf ? sc->shadow_vfta[word] : 0;
+ for (i = 0; i < sc->num_vfs; i++)
+ if ((sc->vfs[i].flags & IGB_VF_ACTIVE) != 0)
+ vlans |= sc->vfs[i].vlans[word];
+ count += bitcount32(vlans);
+ }
+ return (count);
+}
+
+static int
+igb_iov_set_vlan(struct e1000_softc *sc, struct igb_vf *vf, u16 vid,
+ bool add)
+{
+ u32 bit;
+ bool present;
+
+ bit = 1U << (vid & 0x1f);
+ present = (vf->vlans[vid >> 5] & bit) != 0;
+ if (vid == 0) {
+ if (!present) {
+ vf->vlans[0] |= 1U;
+ igb_iov_rebuild_vlan(sc);
+ }
+ return (0);
+ }
+ if (add == present)
+ return (0);
+
+ /*
+ * Removals always reduce privilege and remain available. Charge only
+ * additions, which a hostile VF must alternate with removals to force
+ * repeated global VLAN rebuilds.
+ */
+ if (add && !igb_iov_vlan_present(sc, vid, false) &&
+ igb_iov_vlan_unique_count(sc, false) >=
+ E1000_VLVF_ARRAY_SIZE)
+ return (ENOSPC);
+ if (add && !igb_iov_vlan_add_allowed(vf))
+ return (EBUSY);
+
+ if (add) {
+ vf->vlans[vid >> 5] |= bit;
+ vf->vlan_count++;
+ } else {
+ vf->vlans[vid >> 5] &= ~bit;
+ vf->vlan_count--;
+ }
+ igb_iov_rebuild_vlan(sc);
+ return (0);
+}
+
+static void
+igb_iov_reset_vf_state(struct e1000_softc *sc, struct igb_vf *vf)
+{
+ bool update_uta;
+
+ update_uta = (vf->flags & IGB_VF_UCAST_PROMISC) != 0;
+ vf->flags &= ~(IGB_VF_CTS | IGB_VF_UCAST_PROMISC |
+ IGB_VF_MCAST_PROMISC | IGB_VF_MCAST_OVERFLOW |
+ IGB_VF_MBX_PENDING | IGB_VF_MBX_GAVE_UP |
+ IGB_VF_MDD_NOTIFY_PENDING);
+ vf->mbx_retry_at = 0;
+ vf->mdd_notify_at = 0;
+ vf->mbx_retry_count = 0;
+ /*
+ * A reset starts a new mailbox epoch. Permit one immediate NACK so a
+ * premature non-reset request does not wait for its posted-read
+ * timeout.
+ */
+ memset(&vf->last_nack, 0, sizeof(vf->last_nack));
+ vf->max_frame_size = ETHER_MAX_LEN;
+ vf->mc_count = 0;
+ vf->vlan_count = 0;
+ memset(vf->mc_hashes, 0, sizeof(vf->mc_hashes));
+ memset(vf->vlans, 0, sizeof(vf->vlans));
+ /* Preserve the administrative access VLAN across VF and PF resets. */
+ if (vf->default_vlan == 0)
+ vf->vlans[0] = 1U;
+ else {
+ vf->vlans[vf->default_vlan >> 5] =
+ 1U << (vf->default_vlan & 0x1f);
+ vf->vlan_count = 1;
+ }
+ igb_iov_configure_vmolr(sc, vf);
+ if (update_uta)
+ igb_iov_set_uta(sc);
+}
+
+static bool
+igb_iov_vf_vlan_is_default(const struct igb_vf *vf)
+{
+ u32 expected;
+ int i;
+
+ for (i = 0; i < EM_VFTA_SIZE; i++) {
+ expected = 0;
+ if (i == vf->default_vlan >> 5)
+ expected = 1U << (vf->default_vlan & 0x1f);
+ if (vf->vlans[i] != expected)
+ return (false);
+ }
+ return (true);
+}
+
+static bool
+igb_iov_sanitize_vf_queues(struct e1000_softc *sc,
+ struct igb_vf *vf)
+{
+ struct e1000_hw *hw;
+ u16 qid[IGB_IOV_VF_QUEUES_MAX];
+ u32 rxdctl, txdctl;
+ int i, nqueues, retry;
+
+ hw = &sc->hw;
+ switch (hw->mac.type) {
+ case e1000_82576:
+ nqueues = IGB_82576_VF_QUEUES;
+ qid[0] = vf->pool;
+ qid[1] = vf->pool + IGB_82576_VF_QUEUE_STRIDE;
+ break;
+ case e1000_i350:
+ nqueues = IGB_I350_VF_QUEUES;
+ qid[0] = vf->pool;
+ break;
+ default:
+ return (true);
+ }
+
+ /*
+ * I350 maps pool n to queue n. 82576 gives VF n physical queues n
+ * and n + 8, so both retained queue configurations must be cleared.
+ */
+ for (i = 0; i < nqueues; i++)
+ KASSERT(qid[i] < (hw->mac.type == e1000_82576 ?
+ IGB_82576_NUM_QUEUES : IGB_I350_NUM_QUEUES),
+ ("%s: invalid VF queue %u", __func__, qid[i]));
+
+ /*
+ * The 82576 and I350 specification updates, Software Clarification 3,
+ * note that VFLR does not reset the VF queue configuration. Clear the
+ * PF-programmable state before acknowledging the reset so a new VF
+ * owner cannot inherit it, particularly a descriptor-head write-back
+ * DMA address. The new VF driver initializes its active ring pointers
+ * during queue setup.
+ *
+ * Disable every queue first, then wait for outstanding DMA activity to
+ * stop before clearing TDWBAL/H and the remaining retained state.
+ * Spin only for the normal fast transition, then sleep so a VF that
+ * keeps asserting QUEUE_ENABLE cannot busy-wait the PF for 10 ms.
+ */
+ for (i = 0; i < nqueues; i++) {
+ E1000_WRITE_REG(hw, E1000_RXDCTL(qid[i]), 0);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(qid[i]), 0);
+ }
+ E1000_WRITE_FLUSH(hw);
+ for (retry = 0; retry < IGB_IOV_QUEUE_DISABLE_RETRIES; retry++) {
+ for (i = 0; i < nqueues; i++) {
+ rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(qid[i]));
+ txdctl = E1000_READ_REG(hw, E1000_TXDCTL(qid[i]));
+ if ((rxdctl & E1000_RXDCTL_QUEUE_ENABLE) != 0 ||
+ (txdctl & E1000_TXDCTL_QUEUE_ENABLE) != 0)
+ break;
+ }
+ if (i == nqueues)
+ break;
+ if (retry + 1 < IGB_IOV_QUEUE_DISABLE_RETRIES) {
+ if (retry < IGB_IOV_QUEUE_DISABLE_BUSY_RETRIES)
+ DELAY(IGB_IOV_QUEUE_DISABLE_DELAY_US);
+ else
+ pause_sbt("igbqds",
+ IGB_IOV_QUEUE_DISABLE_PAUSE, 0,
+ C_PREL(1));
+ }
+ }
+ if (retry == IGB_IOV_QUEUE_DISABLE_RETRIES) {
+ if (ratecheck(&vf->last_queue_log,
+ &igb_iov_mbx_log_interval))
+ device_printf(sc->dev,
+ "could not disable queues for VF %u; "
+ "reset deferred\n", vf->pool);
+ return (false);
+ }
+
+ for (i = 0; i < nqueues; i++) {
+ E1000_WRITE_REG(hw, E1000_SRRCTL(qid[i]), 0);
+ E1000_WRITE_REG(hw, E1000_DCA_RXCTRL(qid[i]), 0);
+ E1000_WRITE_REG(hw, E1000_TDWBAL(qid[i]), 0);
+ E1000_WRITE_REG(hw, E1000_TDWBAH(qid[i]), 0);
+ E1000_WRITE_REG(hw, E1000_DCA_TXCTRL(qid[i]), 0);
+ }
+ E1000_WRITE_REG(hw, E1000_PSRTYPE(vf->pool), 0);
+ E1000_WRITE_FLUSH(hw);
+ return (true);
+}
+
+static bool
+igb_iov_reset_event_common(struct e1000_softc *sc, struct igb_vf *vf,
+ bool reset_intrs)
+{
+ struct e1000_hw *hw;
+ bool rebuild_mta, rebuild_vlan, sanitized;
+ u32 reg;
+
+ hw = &sc->hw;
+ rebuild_mta = vf->mc_count != 0;
+ rebuild_vlan = !igb_iov_vf_vlan_is_default(vf);
+ reg = E1000_READ_REG(hw, E1000_VFTE);
+ E1000_WRITE_REG(hw, E1000_VFTE, reg & ~(1U << vf->pool));
+ reg = E1000_READ_REG(hw, E1000_VFRE);
+ E1000_WRITE_REG(hw, E1000_VFRE, reg & ~(1U << vf->pool));
+ if (reset_intrs)
+ E1000_WRITE_REG(hw, E1000_VTCTRL(vf->pool),
+ E1000_VTCTRL_RST);
+ sanitized = igb_iov_sanitize_vf_queues(sc, vf);
+ E1000_WRITE_REG(hw, E1000_VMVIR(vf->pool), 0);
+ igb_iov_clear_mac_filters(sc, vf);
+ igb_iov_clear_rar(sc, vf->rar_index);
+ igb_iov_reset_vf_state(sc, vf);
+ if (rebuild_mta)
+ igb_iov_rebuild_mta(sc);
+ if (rebuild_vlan)
+ igb_iov_rebuild_vlan(sc);
+ return (sanitized);
+}
+
+static bool
+igb_iov_reset_event(struct e1000_softc *sc, struct igb_vf *vf)
+{
+ return (igb_iov_reset_event_common(sc, vf, true));
+}
+
+static void
+igb_iov_mdd_reset_event(struct e1000_softc *sc, struct igb_vf *vf)
+{
+ /*
+ * VTCTRL.RST clears the VF's queue-enable and interrupt registers
+ * (I350 section 8.28.1). It therefore also removes the admin-vector
+ * route needed to deliver the reset notification below. MDD recovery
+ * explicitly permits toggling VFTE instead (section 7.8.3.8.3).
+ *
+ * Leave the interrupt registers intact, keep VFTE/VFRE disabled until
+ * the VF completes a new reset handshake, and use the no-CTS control
+ * message to make the guest reinitialize. FreeBSD and DPDK consume
+ * that message directly; Linux ACKs it and the PF's non-CTS ACK path
+ * replies with the NACK that schedules igbvf's reset task.
+ *
+ * Sanitization failure leaves the pool disabled. The VF reset
+ * handshake retries it and is NACKed while a queue remains active.
+ */
+ (void)igb_iov_reset_event_common(sc, vf, false);
+}
+
+static void
+igb_iov_reset_msg(struct e1000_softc *sc, struct igb_vf *vf)
+{
+ struct e1000_hw *hw;
+ u32 msg[3], reg;
+
+ hw = &sc->hw;
+ if (!igb_iov_reset_event(sc, vf)) {
+ msg[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_NACK;
+ e1000_write_mbx(hw, msg, 1, vf->pool);
+ return;
+ }
+ igb_iov_map_rar(sc, vf->rar_index, vf->mac, vf->pool);
+ igb_iov_set_anti_spoof(sc, vf);
+
+ reg = E1000_READ_REG(hw, E1000_VFTE);
+ E1000_WRITE_REG(hw, E1000_VFTE, reg | (1U << vf->pool));
+ reg = E1000_READ_REG(hw, E1000_VFRE);
+ E1000_WRITE_REG(hw, E1000_VFRE, reg | (1U << vf->pool));
+ /*
+ * 82576's WVBR blocked bitmap is read-clear, so the reset handshake
+ * completes that event's lifetime. I350 MDFB might be read-only;
+ * re-arm its edge latch only after a valid MDFB sample reads clear.
+ */
+ if (hw->mac.type == e1000_82576)
+ vf->flags &= ~IGB_VF_MDD_BLOCKED;
+ vf->flags |= IGB_VF_CTS;
+
+ memset(msg, 0, sizeof(msg));
+ msg[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_ACK;
+ memcpy(&msg[1], vf->mac, ETHER_ADDR_LEN);
+ e1000_write_mbx(hw, msg, 3, vf->pool);
+}
+
+static int
+igb_iov_set_mac_filter(struct e1000_softc *sc, struct igb_vf *vf, u32 *msg)
+{
+ struct igb_vf_mac_filter *filter, *free_filter;
+ const u8 *mac;
+ u32 info;
+ int count, i;
+
+ info = msg[0] & E1000_VT_MSGINFO_MASK;
+ if (info == E1000_VF_MAC_FILTER_CLR) {
+ igb_iov_clear_mac_filters(sc, vf);
+ return (0);
+ }
+ if (info != E1000_VF_MAC_FILTER_ADD)
+ return (EINVAL);
+ if ((vf->flags & IGB_VF_CAP_MAC) == 0)
+ return (EPERM);
+
+ mac = (const u8 *)&msg[1];
+ if (!igb_iov_mac_valid(mac))
+ return (EINVAL);
+ if (memcmp(mac, vf->mac, ETHER_ADDR_LEN) == 0)
+ return (0);
+
+ count = 0;
+ free_filter = NULL;
+ for (i = 0; i < sc->num_vf_mac_filters; i++) {
+ filter = &sc->vf_mac_filters[i];
+ if (!filter->active) {
+ if (free_filter == NULL)
+ free_filter = filter;
+ continue;
+ }
+ if (memcmp(filter->mac, mac, ETHER_ADDR_LEN) != 0)
+ continue;
+ return (filter->pool == vf->pool ? 0 : EADDRINUSE);
+ }
+ for (i = 0; i < sc->num_vf_mac_filters; i++)
+ if (sc->vf_mac_filters[i].active &&
+ sc->vf_mac_filters[i].pool == vf->pool)
+ count++;
+ if (igb_iov_mac_in_use(sc, mac, vf))
+ return (EADDRINUSE);
+ if (count >= IGB_IOV_MAX_MAC_FILTERS)
+ return (ENOSPC);
+ if (free_filter == NULL)
+ return (ENOSPC);
+
+ free_filter->active = true;
+ free_filter->pool = vf->pool;
+ memcpy(free_filter->mac, mac, ETHER_ADDR_LEN);
+ igb_iov_map_rar(sc, free_filter->rar_index, free_filter->mac, vf->pool);
+ return (0);
+}
+
+static int
+igb_iov_set_mac(struct e1000_softc *sc, struct igb_vf *vf, u32 *msg)
+{
+ u8 *mac;
+
+ if ((msg[0] & E1000_VT_MSGINFO_MASK) != 0)
+ return (igb_iov_set_mac_filter(sc, vf, msg));
+
+ mac = (u8 *)&msg[1];
+ if (!igb_iov_mac_valid(mac))
+ return (EINVAL);
+ if (memcmp(mac, vf->mac, ETHER_ADDR_LEN) != 0 &&
+ !(vf->flags & IGB_VF_CAP_MAC))
+ return (EPERM);
+ if (memcmp(mac, vf->mac, ETHER_ADDR_LEN) != 0 &&
+ igb_iov_mac_in_use(sc, mac, vf))
+ return (EADDRINUSE);
+
+ memcpy(vf->mac, mac, ETHER_ADDR_LEN);
+ igb_iov_map_rar(sc, vf->rar_index, vf->mac, vf->pool);
+ return (0);
+}
+
+static int
+igb_iov_set_multicast(struct e1000_softc *sc, struct igb_vf *vf, u32 *msg)
+{
+ u16 hashes[IGB_IOV_MAX_MC_HASHES] = {};
+ bool overflow;
+ int count, i;
+
+ count = (msg[0] & E1000_VF_SET_MULTICAST_COUNT_MASK) >>
+ E1000_VT_MSGINFO_SHIFT;
+ overflow = count > IGB_IOV_MAX_MC_HASHES ||
+ (msg[0] & E1000_VF_SET_MULTICAST_OVERFLOW) != 0;
+ count = min(count, IGB_IOV_MAX_MC_HASHES);
+ for (i = 0; i < count; i++)
+ hashes[i] =
+ (msg[1 + i / 2] >> ((i & 1) * 16)) & 0xffff;
+ if (vf->mc_count == count &&
+ ((vf->flags & IGB_VF_MCAST_OVERFLOW) != 0) == overflow &&
+ memcmp(vf->mc_hashes, hashes, sizeof(hashes)) == 0)
+ return (0);
+ memcpy(vf->mc_hashes, hashes, sizeof(vf->mc_hashes));
+ vf->mc_count = count;
+ if (overflow)
+ vf->flags |= IGB_VF_MCAST_OVERFLOW;
+ else
+ vf->flags &= ~IGB_VF_MCAST_OVERFLOW;
+ if (overflow &&
+ (vf->flags & IGB_VF_MCAST_OVERFLOW_WARNED) == 0) {
+ vf->flags |= IGB_VF_MCAST_OVERFLOW_WARNED;
+ device_printf(sc->dev,
+ "VF %u multicast list exceeds 30 entries; "
+ "enabling all-multicast reception\n", vf->pool);
+ }
+ igb_iov_configure_vmolr(sc, vf);
+ igb_iov_rebuild_mta(sc);
+ return (0);
+}
+
+static int
+igb_iov_set_lpe(struct e1000_softc *sc, struct igb_vf *vf, u32 *msg)
+{
+ u32 size;
+
+ size = msg[1];
+ if (size < ETHER_MIN_LEN)
+ return (EINVAL);
+ vf->max_frame_size = min(size, IGB_IOV_MAX_FRAME_SIZE);
+ igb_iov_configure_vmolr(sc, vf);
+ return (0);
+}
+
+static int
+igb_iov_set_promisc(struct e1000_softc *sc, struct igb_vf *vf, u32 msg)
+{
+ u32 mode;
+
+ mode = msg & E1000_VT_MSGINFO_MASK;
+ if (mode & ~(E1000_VF_SET_PROMISC_UNICAST |
+ E1000_VF_SET_PROMISC_MULTICAST))
+ return (EINVAL);
+ if (mode != 0 && !(vf->flags & IGB_VF_ALLOW_PROMISC))
+ return (EPERM);
+
+ vf->flags &= ~(IGB_VF_UCAST_PROMISC | IGB_VF_MCAST_PROMISC);
+ if (mode & E1000_VF_SET_PROMISC_UNICAST)
+ vf->flags |= IGB_VF_UCAST_PROMISC;
+ if (mode & E1000_VF_SET_PROMISC_MULTICAST)
+ vf->flags |= IGB_VF_MCAST_PROMISC;
+ igb_iov_configure_vmolr(sc, vf);
+ igb_iov_set_uta(sc);
+ return (0);
+}
+
+static bool
+igb_iov_process_msg(struct e1000_softc *sc, struct igb_vf *vf)
+{
+ struct e1000_hw *hw;
+ u32 msg[E1000_VFMAILBOX_SIZE], type;
+ int error;
+
+ hw = &sc->hw;
+ memset(msg, 0, sizeof(msg));
+ if (e1000_read_mbx(hw, msg, nitems(msg), vf->pool, false) != 0)
+ return (false);
+ vf->flags &= ~IGB_VF_MBX_PENDING;
+ vf->mbx_retry_at = 0;
+ vf->mbx_retry_count = 0;
+
+ if (msg[0] & (E1000_VT_MSGTYPE_ACK | E1000_VT_MSGTYPE_NACK)) {
+ e1000_unlock_mbx(hw, vf->pool);
+ return (true);
+ }
+ if (msg[0] == E1000_VF_RESET) {
+ igb_iov_reset_msg(sc, vf);
+ return (true);
+ }
+ if (!(vf->flags & IGB_VF_CTS)) {
+ if (igb_iov_nack_allowed(vf)) {
+ msg[0] = igb_iov_reply_header(msg[0], false, false);
+ e1000_write_mbx(hw, msg, 1, vf->pool);
+ } else
+ e1000_unlock_mbx(hw, vf->pool);
+ return (true);
+ }
+
+ type = msg[0] & 0xffff;
+ switch (type) {
+ case E1000_VF_SET_MAC_ADDR:
+ error = igb_iov_set_mac(sc, vf, msg);
+ break;
+ case E1000_VF_SET_MULTICAST:
+ error = igb_iov_set_multicast(sc, vf, msg);
+ break;
+ case E1000_VF_SET_VLAN:
+ if (vf->default_vlan != 0)
+ error = EPERM;
+ else if ((msg[1] & ~E1000_VLVF_VLANID_MASK) != 0)
+ error = EINVAL;
+ else
+ error = igb_iov_set_vlan(sc, vf,
+ msg[1] & E1000_VLVF_VLANID_MASK,
+ (msg[0] & E1000_VF_SET_VLAN_ADD) != 0);
+ break;
+ case E1000_VF_SET_LPE:
+ error = igb_iov_set_lpe(sc, vf, msg);
+ break;
+ case E1000_VF_SET_PROMISC:
+ error = igb_iov_set_promisc(sc, vf, msg[0]);
+ break;
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ msg[0] = igb_iov_reply_header(msg[0], true, error == 0);
+ e1000_write_mbx(hw, msg, 1, vf->pool);
+ return (true);
+}
+
+static sbintime_t
+igb_iov_service_pending_mbx(struct e1000_softc *sc, struct igb_vf *vf,
+ sbintime_t now)
+{
+ sbintime_t delay;
+
+ if ((vf->flags & IGB_VF_MBX_PENDING) == 0)
+ return (0);
+ if (vf->mbx_retry_at != 0 && now < vf->mbx_retry_at)
+ return (vf->mbx_retry_at);
+ if (igb_iov_process_msg(sc, vf))
+ return (0);
+
+ now = getsbinuptime();
+ if (vf->mbx_retry_count < IGB_IOV_MBX_RETRY_COUNT) {
+ delay = igb_iov_mbx_retry_delay[vf->mbx_retry_count++];
+ vf->mbx_retry_at = now + delay;
+ return (vf->mbx_retry_at);
+ }
+
+ vf->flags &= ~(IGB_VF_CTS | IGB_VF_MBX_PENDING);
+ vf->flags |= IGB_VF_MBX_GAVE_UP;
+ vf->mbx_retry_at = 0;
+ if (ratecheck(&vf->last_mbx_log, &igb_iov_mbx_log_interval))
+ device_printf(sc->dev,
+ "mailbox remained busy for VF %u; CTS revoked\n",
+ vf->pool);
+ return (0);
+}
+
+void
+igb_iov_handle_mbx(struct e1000_softc *sc)
+{
+ struct e1000_hw *hw;
+ struct igb_vf *vf;
+ sbintime_t delay, next_retry_at, now, retry_at;
+ u32 msg;
+ int i;
+
+ if (!sc->iov_hw_active)
+ return;
+
+ hw = &sc->hw;
+ next_retry_at = 0;
+ for (i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ if (!(vf->flags & IGB_VF_ACTIVE))
+ continue;
+ now = getsbinuptime();
+ if (e1000_check_for_rst(hw, vf->pool) == 0) {
+ /*
+ * The old VF is gone. A new owner's reset handshake
+ * reruns sanitization before enabling its pool.
+ */
+ (void)igb_iov_reset_event(sc, vf);
+ }
+ if ((vf->flags &
+ (IGB_VF_MBX_PENDING | IGB_VF_MBX_GAVE_UP)) == 0 &&
+ e1000_check_for_msg(hw, vf->pool) == 0) {
+ vf->flags |= IGB_VF_MBX_PENDING;
+ vf->mbx_retry_at = 0;
+ vf->mbx_retry_count = 0;
+ }
+ retry_at = igb_iov_service_pending_mbx(sc, vf, now);
+ if (retry_at != 0 &&
+ (next_retry_at == 0 || retry_at < next_retry_at))
+ next_retry_at = retry_at;
+ if (e1000_check_for_ack(hw, vf->pool) == 0 &&
+ !(vf->flags & IGB_VF_CTS) && igb_iov_nack_allowed(vf)) {
+ msg = E1000_VT_MSGTYPE_NACK;
+ e1000_write_mbx(hw, &msg, 1, vf->pool);
+ }
+ }
+ if (next_retry_at != 0) {
+ delay = next_retry_at - getsbinuptime();
+ if (delay <= 0)
+ delay = SBT_1MS;
+ callout_reset_sbt(&sc->iov_mbx_retry, delay, 0,
+ igb_iov_mbx_retry_callout, sc, C_PREL(1));
+ }
+}
+
+static bool
+igb_iov_notify_vf_mdd_reset(struct e1000_softc *sc, struct igb_vf *vf)
+{
+ u32 msg;
+
+ /*
+ * MDD recovery preserves the VF's admin-vector configuration. Send
+ * the same no-CTS control message used for PF reset notification so
+ * the VF discards its state and completes a new reset handshake.
+ * A failed write is retried from the timer-driven admin pass; the VF's
+ * transmit watchdog remains the final fallback when traffic is still
+ * queued and notification never succeeds.
+ */
+ msg = E1000_PF_CONTROL_MSG;
+ if (e1000_write_mbx(&sc->hw, &msg, 1, vf->pool) != 0) {
+ vf->mdd_notify_at =
+ getsbinuptime() + igb_iov_mdd_notify_retry;
+ if (ratecheck(&vf->last_mbx_log,
+ &igb_iov_mbx_log_interval))
+ device_printf(sc->dev,
+ "could not notify VF %u of malicious-driver "
+ "reset; will retry\n", vf->pool);
+ return (false);
+ }
+ vf->flags &= ~IGB_VF_MDD_NOTIFY_PENDING;
+ vf->mdd_notify_at = 0;
+ return (true);
+}
+
+void
+igb_iov_handle_mdd(struct e1000_softc *sc)
+{
+ struct igb_vf *vf;
+ u32 blocked, cleared, handled, lvmmc;
+ u32 readback, spoofed;
+ bool mdfb_valid, pending;
+ int i;
+
+ pending = atomic_readandclear_32(&sc->iov_pending) != 0;
+ lvmmc = pending ?
+ atomic_readandclear_32(&sc->iov_mdd_cause) : 0;
+ if (!sc->iov_hw_active) {
+ atomic_readandclear_32(&sc->iov_spoof_pending);
+ atomic_readandclear_32(&sc->iov_blocked_pending);
+ return;
+ }
+
+ blocked = 0;
+ handled = 0;
+ mdfb_valid = false;
+ if (sc->hw.mac.type == e1000_i350) {
+ u32 mdfb;
+
+ spoofed = atomic_readandclear_32(&sc->iov_spoof_pending);
+ /*
+ * I350 reports ordinary MAC/VLAN spoofing through the
+ * interrupt-time LVMMC snapshot rather than WVBR. The
+ * filter accumulates Last_Q into iov_spoof_pending so events
+ * from different VFs coalesce safely until this timer-driven
+ * admin pass.
+ */
+ spoofed &= IGB_I350_QUEUE_MASK;
+ /*
+ * Sample MDFB on every admin pass so a blocked queue is not
+ * mislabeled as an ordinary spoof when no MDDET observation
+ * is pending.
+ */
+ mdfb = E1000_READ_REG(&sc->hw, E1000_MDFB);
+ if (__predict_false(mdfb == 0xffffffff))
+ mdfb = 0;
+ else {
+ mdfb &= IGB_I350_QUEUE_MASK;
+ mdfb_valid = true;
+ }
+ /*
+ * I350 SDM sections 8.14.10 and 8.14.11: WVBR reports
+ * spoof and malicious-driver events, while MDFB identifies
+ * the queues actually blocked for malicious behavior.
+ */
+ spoofed &= ~mdfb;
+ blocked = mdfb;
+ if (blocked != 0 && lvmmc == 0)
+ lvmmc = E1000_READ_REG(&sc->hw, E1000_LVMMC);
+ /*
+ * A failed diagnostic read does not invalidate the
+ * blocked-queue bitmap that was read successfully above.
+ */
+ if (__predict_false(lvmmc == 0xffffffff))
+ lvmmc = 0;
+ /*
+ * MDFB is authoritative for queues stopped by malicious-driver
+ * detection. LVMMC reports causes such as VLAN IERR and
+ * Mal_PF, but its Last_Q field does not establish that a queue
+ * was blocked. Do not manufacture a blocked bit when MDFB is
+ * clear.
+ */
+ } else {
+ if (!pending)
+ return;
+ /*
+ * WVBR is read-clear and does not preserve every queue across
+ * multiple MDDET interrupts. The interrupt filter snapshots and
+ * accumulates its pool bitmaps before this deferred admin pass.
+ */
+ spoofed = atomic_readandclear_32(&sc->iov_spoof_pending);
+ blocked = atomic_readandclear_32(&sc->iov_blocked_pending);
+ /* A blocked-queue classification dominates its WVBR low bit. */
+ spoofed &= ~blocked;
+ }
+
+ for (i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ if (!(vf->flags & IGB_VF_ACTIVE))
+ continue;
+ if ((vf->flags & IGB_VF_MDD_NOTIFY_PENDING) != 0 &&
+ getsbinuptime() >= vf->mdd_notify_at)
+ (void)igb_iov_notify_vf_mdd_reset(sc, vf);
+ /*
+ * An invalid MDFB sample must neither report a new edge nor
+ * masquerade as evidence that an old edge has cleared.
+ */
+ if (sc->hw.mac.type == e1000_i350 && mdfb_valid &&
+ (blocked & (1U << i)) == 0)
+ vf->flags &= ~IGB_VF_MDD_BLOCKED;
+ if ((spoofed & (1U << i)) != 0 &&
+ ratecheck(&vf->last_spoof_log,
+ &igb_iov_spoof_log_interval))
+ device_printf(sc->dev,
+ "spoof event detected from VF %u; packet dropped\n",
+ vf->pool);
+ if ((blocked & (1U << i)) == 0)
+ continue;
+ if ((vf->flags & IGB_VF_MDD_BLOCKED) != 0)
+ continue;
+ vf->flags |= IGB_VF_MDD_BLOCKED;
+ if (ratecheck(&vf->last_mdd_log, &igb_iov_mdd_log_interval))
+ device_printf(sc->dev,
+ "malicious-driver event 0x%08x from VF %u; "
+ "resetting VF\n", lvmmc, vf->pool);
+ igb_iov_mdd_reset_event(sc, vf);
+ vf->flags |= IGB_VF_MDD_NOTIFY_PENDING;
+ (void)igb_iov_notify_vf_mdd_reset(sc, vf);
+ handled |= 1U << i;
+ }
+ if (sc->hw.mac.type == e1000_i350 && mdfb_valid &&
+ (blocked & (1U << sc->pool)) == 0)
+ sc->iov_pf_mdd_blocked = false;
+ if ((blocked & (1U << sc->pool)) != 0 &&
+ (sc->hw.mac.type != e1000_i350 ||
+ !sc->iov_pf_mdd_blocked)) {
+ if (sc->hw.mac.type == e1000_i350)
+ sc->iov_pf_mdd_blocked = true;
+ if (ratecheck(&sc->iov_last_mdd_log,
+ &igb_iov_mdd_log_interval))
+ device_printf(sc->dev,
+ "malicious-driver event 0x%08x from PF queue; "
+ "resetting PF\n", lvmmc);
+ iflib_request_reset(sc->ctx);
+ iflib_admin_intr_deferred(sc->ctx);
+ handled |= 1U << sc->pool;
+ }
+ if (sc->hw.mac.type == e1000_i350 && handled != 0) {
+ /*
+ * I350 documentation conflicts: the register summary calls
+ * MDFB RWS while the detailed field table calls it RO. I350
+ * silicon clears a blocked bit when software writes it back.
+ * Write only bits whose recovery was initiated. If a revision
+ * instead implements MDFB as RO, the edge latch above prevents
+ * a reset loop and this one transition-time write is harmless.
+ */
+ E1000_WRITE_REG(&sc->hw, E1000_MDFB, handled);
+ E1000_WRITE_FLUSH(&sc->hw);
+ /*
+ * Rearm from observed hardware state instead of waiting for
+ * the next admin pass. The PF context lock prevents a reset
+ * handshake from re-enabling the VF before this readback. A
+ * write-to-clear part reports zero; a read-only part retains
+ * the bit and therefore retains the one-shot edge latch.
+ */
+ readback = E1000_READ_REG(&sc->hw, E1000_MDFB);
+ if (__predict_false(readback == 0xffffffff))
+ cleared = 0;
+ else
+ cleared = handled &
+ ~(readback & IGB_I350_QUEUE_MASK);
+ for (i = 0; i < sc->num_vfs; i++)
+ if ((cleared & (1U << i)) != 0)
+ sc->vfs[i].flags &= ~IGB_VF_MDD_BLOCKED;
+ if ((cleared & (1U << sc->pool)) != 0)
+ sc->iov_pf_mdd_blocked = false;
+ }
+ if (sc->hw.mac.type == e1000_i350) {
+ /*
+ * I350 can retain EICR.OTHER without delivering the admin MSI-X
+ * even though its EIMS and legacy IMS bits remain enabled. Kick
+ * the already-enabled vector on each admin pass so its filter
+ * consumes any retained ICR/LVMMC cause. A synthetic interrupt
+ * with no legacy cause is handled entirely by the filter.
+ */
+ E1000_WRITE_REG(&sc->hw, E1000_EICS, sc->link_mask);
+ E1000_WRITE_FLUSH(&sc->hw);
+ }
+}
+
+void
+igb_iov_mdd_event(struct e1000_softc *sc)
+{
+ u32 blocked, cause, queues, queue, spoofed, wvbr;
+
+ /*
+ * LVMMC is clear-on-read. Preserve it in the interrupt filter, as
+ * Intel's igb driver does, rather than deferring the only copy.
+ */
+ cause = E1000_READ_REG(&sc->hw, E1000_LVMMC);
+ if (__predict_false(cause == 0xffffffff))
+ return;
+ if (sc->hw.mac.type == e1000_82576) {
+ /*
+ * Snapshot WVBR in the interrupt filter. Waiting for the admin
+ * task loses all but the last of back-to-back VF MDD events on
+ * 82576. Convert the staggered queue map into pool bits and OR
+ * each observation into software latches for deferred recovery.
+ */
+ wvbr = E1000_READ_REG(&sc->hw, E1000_WVBR);
+ if (__predict_false(wvbr == 0xffffffff)) {
+ spoofed = 0;
+ blocked = 0;
+ } else {
+ queues = wvbr & IGB_82576_QUEUE_MASK;
+ spoofed = (queues & 0xff) |
+ (queues >> IGB_82576_STAGGERED_QUEUE_SHIFT);
+ queues = (wvbr >> 16) & IGB_82576_QUEUE_MASK;
+ blocked = (queues & 0xff) |
+ (queues >> IGB_82576_STAGGERED_QUEUE_SHIFT);
+ }
+ SDT_PROBE4(igb_iov, mdd, sample, wvbr, sc, wvbr, spoofed,
+ blocked);
+ /*
+ * 82576 can report a coalesced block-class event with all affected
+ * queues in WVBR's low half and no high-half blocked bits. If an
+ * ordinary spoof shares that snapshot, the register has no per-queue
+ * cause information. Deliberately fail closed by recovering every
+ * low-half queue; this can reset a spoof-only sibling, but avoids
+ * stranding a blocked VF. LVMMC.Last_Q identifies only the final
+ * event and lost simultaneous blocked VFs on tested silicon.
+ */
+ if (blocked == 0 &&
+ (cause & IGB_82576_LVMMC_BLOCK_MASK) != 0) {
+ blocked = spoofed;
+ if (blocked == 0) {
+ queue = (cause >> 16) & 0xf;
+ blocked = 1U << (queue & 0x7);
+ }
+ }
+ if (spoofed != 0)
+ atomic_set_32(&sc->iov_spoof_pending, spoofed);
+ if (blocked != 0)
+ atomic_set_32(&sc->iov_blocked_pending, blocked);
+ }
+ if (sc->hw.mac.type == e1000_i350 &&
+ (cause & IGB_I350_LVMMC_MAC_VLAN_SPOOF) != 0) {
+ queue = (cause >> IGB_I350_LVMMC_LAST_Q_SHIFT) &
+ IGB_I350_LVMMC_LAST_Q_MASK;
+ /*
+ * FreeBSD assigns one queue to each VF pool, so Last_Q is
+ * also the VF number. Preserve all VFs observed before the
+ * timer pass, and do not overwrite an unrelated blocked
+ * queue's diagnostic with this non-blocking spoof event.
+ */
+ atomic_set_32(&sc->iov_spoof_pending, 1U << queue);
+ return;
+ }
+ atomic_store_rel_32(&sc->iov_mdd_cause, cause);
+ atomic_set_32(&sc->iov_pending, 1);
+}
+
+void
+igb_iov_ping_all_vfs(struct e1000_softc *sc)
+{
+ struct igb_vf *vf;
+ u32 msg;
+ int i;
+
+ if (!sc->iov_hw_active)
+ return;
+
+ for (i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ if (!(vf->flags & IGB_VF_ACTIVE))
+ continue;
+ msg = E1000_PF_CONTROL_MSG;
+ if (vf->flags & IGB_VF_CTS)
+ msg |= E1000_VT_MSGTYPE_CTS;
+ e1000_write_mbx(&sc->hw, &msg, 1, vf->pool);
+ }
+}
+
+void
+igb_iov_initialize(struct e1000_softc *sc)
+{
+ struct e1000_hw *hw;
+ struct igb_vf *vf;
+ u32 ctrl_ext, dtxctl, mask, rctl, rplolr, vt_ctl;
+ int i;
+
+ if (sc->num_vfs == 0)
+ return;
+
+ hw = &sc->hw;
+ atomic_readandclear_32(&sc->iov_mdd_cause);
+ atomic_readandclear_32(&sc->iov_pending);
+ atomic_readandclear_32(&sc->iov_spoof_pending);
+ atomic_readandclear_32(&sc->iov_blocked_pending);
+ /* Plain VMDq keeps every 82576 PF/VF pool on queue zero. */
+ E1000_WRITE_REG(hw, E1000_MRQC, E1000_MRQC_ENABLE_VMDQ);
+
+ vt_ctl = E1000_READ_REG(hw, E1000_VT_CTL);
+ vt_ctl &= ~(E1000_VT_CTL_DEFAULT_POOL_MASK |
+ E1000_VT_CTL_DISABLE_DEF_POOL);
+ vt_ctl |= sc->pool << E1000_VT_CTL_DEFAULT_POOL_SHIFT;
+ vt_ctl |= E1000_VT_CTL_VM_REPL_EN;
+ E1000_WRITE_REG(hw, E1000_VT_CTL, vt_ctl);
+
+ mask = 1U << sc->pool;
+ E1000_WRITE_REG(hw, E1000_VFRE, mask);
+ E1000_WRITE_REG(hw, E1000_VFTE, mask);
+ /* A VF without RX descriptors must not block any other pool. */
+ E1000_WRITE_REG(hw, E1000_QDE,
+ hw->mac.type == e1000_i350 ? IGB_I350_QUEUE_MASK : ALL_QUEUES);
+ e1000_vmdq_set_loopback_pf(hw, true);
+ dtxctl = E1000_READ_REG(hw, E1000_DTXCTL);
+ dtxctl |= E1000_DTXCTL_MDP_EN;
+ if (hw->mac.type == e1000_82576) {
+ dtxctl |= E1000_DTXCTL_VLAN_ADDED |
+ E1000_DTXCTL_SPOOF_INT;
+ rplolr = E1000_READ_REG(hw, E1000_RPLOLR);
+ rplolr |= E1000_RPLOLR_STRVLAN;
+ E1000_WRITE_REG(hw, E1000_RPLOLR, rplolr);
+ } else {
+ /*
+ * I350 SDM section 8.12.5 defines this field with inverted
+ * polarity: setting it keeps an ordinary spoof from disabling
+ * the VF queue. Enable its notification as well. I350
+ * hardware reports the VF in LVMMC.Last_Q (WVBR remains zero);
+ * the moderated admin vector captures that value, while
+ * timer-driven administration and per-VF ratecheck bound the
+ * work and console output.
+ */
+ dtxctl |= E1000_DTXCTL_SPOOF_INT |
+ IGB_I350_DTXCTL_ENABLE_SPOOF_QUEUE;
+ }
+ E1000_WRITE_REG(hw, E1000_DTXCTL, dtxctl);
+
+ igb_iov_map_rar(sc, 0, hw->mac.addr, sc->pool);
+ igb_iov_configure_pf_vmolr(sc);
+ igb_iov_set_uta(sc);
+ for (i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ if (!(vf->flags & IGB_VF_ACTIVE))
+ continue;
+ /*
+ * A PF-wide reset is trusted and can require a complete guest
+ * replay. Guest-controlled RESET and VFLR do not refill this
+ * allowance.
+ */
+ igb_iov_reset_vlan_rate(vf);
+ igb_iov_clear_mac_filters(sc, vf);
+ igb_iov_reset_vf_state(sc, vf);
+ igb_iov_clear_rar(sc, vf->rar_index);
+ igb_iov_set_anti_spoof(sc, vf);
+ }
+ igb_iov_rebuild_mta(sc);
+ igb_iov_rebuild_vlan(sc);
+
+ rctl = E1000_READ_REG(hw, E1000_RCTL);
+ E1000_WRITE_REG(hw, E1000_RCTL, rctl | E1000_RCTL_VFE);
+ E1000_WRITE_REG(hw, E1000_MBVFIMR, igb_iov_active_mask(sc));
+ if (hw->mac.type == e1000_i350)
+ E1000_WRITE_REG(hw, E1000_DMACR, 0);
+
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT,
+ ctrl_ext | E1000_CTRL_EXT_PFRSTD);
+ E1000_WRITE_FLUSH(hw);
+ /*
+ * MDDET remains masked until iov_hw_active is published and iflib
+ * rearms the admin vector. Programming the per-pool policy above can
+ * leave a setup-time MDDET observation in the read-clear registers.
+ * If that stale cause is carried across the unmask, a later ordinary
+ * spoof can update LVMMC without generating a new interrupt edge.
+ *
+ * Drain only after all IOV policy is installed and before exposing the
+ * active state. Mailbox requests are also serviced by the periodic
+ * admin pass, and ping_all_vfs() below supplies a fresh notification.
+ */
+ /*
+ * Clear the setup-time interrupt latch before its diagnostic state.
+ * I350 does not reliably generate the next MDDET edge when LVMMC is
+ * consumed while ICR.MDDET remains latched. This differs deliberately
+ * from the final arm-time drain, where ICR is read last so a later event
+ * remains pending for the unmask.
+ */
+ if (hw->mac.type == e1000_i350)
+ (void)E1000_READ_REG(hw, E1000_ICR);
+ (void)E1000_READ_REG(hw, E1000_LVMMC);
+ if (hw->mac.type == e1000_82576)
+ (void)E1000_READ_REG(hw, E1000_WVBR);
+ if (hw->mac.type != e1000_i350)
+ (void)E1000_READ_REG(hw, E1000_ICR);
+ atomic_readandclear_32(&sc->iov_mdd_cause);
+ atomic_readandclear_32(&sc->iov_pending);
+ atomic_readandclear_32(&sc->iov_spoof_pending);
+ atomic_readandclear_32(&sc->iov_blocked_pending);
+ atomic_store_rel_32(&sc->iov_intr_drain_pending, 1);
+ sc->iov_hw_active = true;
+ igb_iov_ping_all_vfs(sc);
+}
+
+int
+igb_iov_validate(struct e1000_softc *sc, u16 num_vfs)
+{
+ if (!igb_iov_supported(sc))
+ return (ENXIO);
+ /* One of the eight hardware pools is reserved for the PF. */
+ if (num_vfs == 0 || num_vfs > MAX_NUM_VFS)
+ return (EINVAL);
+ if (sc->vfs != NULL)
+ return (EBUSY);
+ if (sc->intr_type != IFLIB_INTR_MSIX) {
+ device_printf(sc->dev, "SR-IOV requires MSI-X\n");
+ return (ENOTSUP);
+ }
+ if (sc->tx_num_queues != 1 || sc->rx_num_queues != 1) {
+ device_printf(sc->dev,
+ "SR-IOV requires one PF TX and RX queue; set "
+ "dev.igb.%d.iflib.override_ntxqs=1 and "
+ "dev.igb.%d.iflib.override_nrxqs=1 before attach\n",
+ device_get_unit(sc->dev), device_get_unit(sc->dev));
+ return (EINVAL);
+ }
+ return (0);
+}
+
+int
+igb_if_vf_status(if_ctx_t ctx, nvlist_t *status)
+{
+ struct e1000_softc *sc;
+ struct igb_vf *vf;
+ nvlist_t **vfs;
+ u_int num_queues;
+ int error, i;
+
+ sc = iflib_get_softc(ctx);
+ if (sc->num_vfs == 0)
+ return (ENXIO);
+ num_queues = sc->hw.mac.type == e1000_82576 ?
+ IGB_82576_VF_QUEUES : IGB_I350_VF_QUEUES;
+ vfs = mallocarray(sc->num_vfs, sizeof(*vfs), M_IGB_IOV,
+ M_WAITOK | M_ZERO);
+ for (i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ vfs[i] = nvlist_create(0);
+ nvlist_add_number(vfs[i], IFVF_STATUS_INDEX, i);
+ nvlist_add_bool(vfs[i], IFVF_STATUS_CONFIGURED,
+ (vf->flags & IGB_VF_ACTIVE) != 0);
+ nvlist_add_bool(vfs[i], IFVF_STATUS_INITIALIZED,
+ (vf->flags & IGB_VF_CTS) != 0);
+ nvlist_add_binary(vfs[i], IFVF_STATUS_MAC, vf->mac,
+ ETHER_ADDR_LEN);
+ if (vf->default_vlan == 0)
+ nvlist_add_string(vfs[i], IFVF_STATUS_VLAN_MODE,
+ IFVF_VLAN_MODE_TRUNK);
+ else {
+ nvlist_add_string(vfs[i], IFVF_STATUS_VLAN_MODE,
+ IFVF_VLAN_MODE_ACCESS);
+ nvlist_add_number(vfs[i], IFVF_STATUS_VLAN,
+ vf->default_vlan);
+ }
+ nvlist_add_number(vfs[i], IFVF_STATUS_VLAN_COUNT,
+ vf->vlan_count);
+ nvlist_add_number(vfs[i], IFVF_STATUS_NUM_QUEUES, num_queues);
+ nvlist_add_bool(vfs[i], IFVF_STATUS_ALLOW_SET_MAC,
+ (vf->flags & IGB_VF_CAP_MAC) != 0);
+ nvlist_add_bool(vfs[i], IFVF_STATUS_ALLOW_SET_VLAN,
+ vf->default_vlan == 0);
+ nvlist_add_bool(vfs[i], IFVF_STATUS_MAC_ANTI_SPOOF,
+ (vf->flags & IGB_VF_MAC_ANTI_SPOOF) != 0);
+ nvlist_add_bool(vfs[i], IFVF_STATUS_ALLOW_PROMISC,
+ (vf->flags & IGB_VF_ALLOW_PROMISC) != 0);
+ nvlist_add_bool(vfs[i], IFVF_STATUS_MDD_BLOCKED,
+ (vf->flags & IGB_VF_MDD_BLOCKED) != 0);
+ }
+ nvlist_add_nvlist_array(status, IFVF_STATUS_VFS,
+ (const nvlist_t * const *)vfs, sc->num_vfs);
+ error = nvlist_error(status);
+ for (i = 0; i < sc->num_vfs; i++)
+ nvlist_destroy(vfs[i]);
+ free(vfs, M_IGB_IOV);
+ return (error);
+}
+
+int
+igb_if_iov_init(if_ctx_t ctx, u16 num_vfs, const nvlist_t *config)
+{
+ struct e1000_softc *sc;
+ int error, i;
+
+ sc = iflib_get_softc(ctx);
+ (void)config;
+ /*
+ * This callback may run while the PF is down. Record the software
+ * layout here; igb_iov_initialize() programs it during interface init.
+ */
+ atomic_store_rel_32(&sc->iov_teardown, 0);
+ error = igb_iov_validate(sc, num_vfs);
+ if (error != 0)
+ return (error);
+
+ sc->vfs = mallocarray(num_vfs, sizeof(*sc->vfs), M_IGB_IOV,
+ M_WAITOK | M_ZERO);
+ sc->num_vf_mac_filters =
+ sc->hw.mac.rar_entry_count - num_vfs - 1;
+ sc->vf_mac_filters = mallocarray(sc->num_vf_mac_filters,
+ sizeof(*sc->vf_mac_filters), M_IGB_IOV, M_WAITOK | M_ZERO);
+ for (i = 0; i < sc->num_vf_mac_filters; i++)
+ sc->vf_mac_filters[i].rar_index = i + 1;
+ sc->pool = num_vfs;
+ sc->iov_mta_valid = false;
+ sc->iov_pf_mdd_blocked = false;
+ sc->tx_queues[0].txr.me = sc->pool;
+ sc->rx_queues[0].rxr.me = sc->pool;
+ e1000_init_mbx_params_pf(&sc->hw);
+ sc->num_vfs = num_vfs;
+ return (0);
+}
+
+void
+igb_if_iov_uninit(if_ctx_t ctx)
+{
+ struct e1000_softc *sc;
+ struct e1000_hw *hw;
+ u32 mask, rah;
+ int error, i, iov_pos;
+ u16 iov_ctl;
+
+ sc = iflib_get_softc(ctx);
+ if (sc->vfs == NULL)
+ return;
+ hw = &sc->hw;
+ sc->iov_hw_active = false;
+ if (sc->iov_mbx_retry_initialized)
+ callout_drain(&sc->iov_mbx_retry);
+
+ E1000_WRITE_REG(hw, E1000_MBVFIMR, 0);
+ mask = 1U << sc->pool;
+ E1000_WRITE_REG(hw, E1000_VFRE, mask);
+ E1000_WRITE_REG(hw, E1000_VFTE, mask);
+
+ /*
+ * pci_iov(4) invokes the driver before it clears VF Enable. Quiesce
+ * the VFs and clear it here so that 82576's queue-reuse interval is
+ * measured from the actual IOV-disable event.
+ */
+ error = pci_find_extcap(sc->dev, PCIZ_SRIOV, &iov_pos);
+ if (error == 0) {
+ iov_ctl = pci_read_config(sc->dev,
+ iov_pos + PCIR_SRIOV_CTL, 2);
+ iov_ctl &= ~(PCIM_SRIOV_VF_EN | PCIM_SRIOV_VF_MSE);
+ pci_write_config(sc->dev, iov_pos + PCIR_SRIOV_CTL,
+ iov_ctl, 2);
+ if (hw->mac.type == e1000_82576) {
+ pause("igbiov", MAX(1, howmany(hz, 10)));
+ E1000_WRITE_REG(hw, E1000_IOVCTL,
+ E1000_IOVCTL_REUSE_VFQ);
+ E1000_WRITE_FLUSH(hw);
+ pause("igbiov", MAX(1, howmany(hz, 10)));
+ }
+ } else
+ device_printf(sc->dev,
+ "could not disable PCI SR-IOV before queue reuse: %d\n",
+ error);
+
+ E1000_WRITE_REG(hw, E1000_VT_CTL, 0);
+ e1000_vmdq_set_loopback_pf(hw, false);
+ e1000_vmdq_set_anti_spoofing_pf(hw, false, 0);
+ for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++)
+ E1000_WRITE_REG(hw, E1000_VLVF(i), 0);
+ for (i = 0; i < sc->num_vfs; i++)
+ if (sc->vfs[i].flags & IGB_VF_ACTIVE)
+ igb_iov_clear_rar(sc, sc->vfs[i].rar_index);
+ for (i = 0; i < sc->num_vf_mac_filters; i++)
+ if (sc->vf_mac_filters[i].active)
+ igb_iov_clear_rar(sc, sc->vf_mac_filters[i].rar_index);
+ rah = E1000_READ_REG(hw, E1000_RAH(0));
+ rah &= ~IGB_IOV_RAH_POOLSEL_MASK;
+ E1000_WRITE_REG(hw, E1000_RAH(0), rah);
+
+ free(sc->vfs, M_IGB_IOV);
+ free(sc->vf_mac_filters, M_IGB_IOV);
+ sc->vfs = NULL;
+ sc->vf_mac_filters = NULL;
+ sc->num_vfs = 0;
+ sc->num_vf_mac_filters = 0;
+ sc->pool = 0;
+ sc->iov_mta_valid = false;
+ sc->iov_pf_mdd_blocked = false;
+ sc->iov_pf_vlan_promisc = false;
+ igb_iov_vfta_shadow_invalidate(sc);
+ sc->tx_queues[0].txr.me = 0;
+ sc->rx_queues[0].rxr.me = 0;
+ atomic_readandclear_32(&sc->iov_mdd_cause);
+ atomic_readandclear_32(&sc->iov_pending);
+ atomic_readandclear_32(&sc->iov_spoof_pending);
+ atomic_readandclear_32(&sc->iov_blocked_pending);
+ atomic_readandclear_32(&sc->iov_intr_drain_pending);
+ atomic_store_rel_32(&sc->iov_teardown, 0);
+}
+
+static bool
+igb_iov_mac_in_use(struct e1000_softc *sc, const u8 *mac,
+ const struct igb_vf *skip)
+{
+ int i;
+
+ if (memcmp(sc->hw.mac.addr, mac, ETHER_ADDR_LEN) == 0)
+ return (true);
+ for (i = 0; i < sc->num_vfs; i++)
+ if (&sc->vfs[i] != skip &&
+ (sc->vfs[i].flags & IGB_VF_ACTIVE) != 0 &&
+ memcmp(sc->vfs[i].mac, mac, ETHER_ADDR_LEN) == 0)
+ return (true);
+ for (i = 0; i < sc->num_vf_mac_filters; i++)
+ if (sc->vf_mac_filters[i].active &&
+ memcmp(sc->vf_mac_filters[i].mac, mac,
+ ETHER_ADDR_LEN) == 0)
+ return (true);
+ return (false);
+}
+
+int
+igb_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config)
+{
+ struct e1000_softc *sc;
+ struct igb_vf *vf;
+ struct ether_addr generated;
+ const void *mac;
+ char nameunit[IFNAMSIZ + sizeof("-vf65535")];
+ size_t mac_size;
+ uint64_t configured_vlan;
+ u16 vlan;
+
+ sc = iflib_get_softc(ctx);
+ if (vfnum >= sc->num_vfs)
+ return (EINVAL);
+ vf = &sc->vfs[vfnum];
+ if (vf->flags & IGB_VF_ACTIVE)
+ return (EBUSY);
+
+ configured_vlan = nvlist_get_number(config, "vlan");
+ if (configured_vlan > VF_VLAN_TRUNK)
+ return (EINVAL);
+ vlan = configured_vlan;
+ if (vlan == 0)
+ return (ENOTSUP);
+ if (vlan == VF_VLAN_TRUNK)
+ vlan = 0;
+ if (!igb_iov_vlan_present(sc, vlan, false) &&
+ igb_iov_vlan_unique_count(sc, false) >=
+ E1000_VLVF_ARRAY_SIZE)
+ return (ENOSPC);
+
+ vf->pool = vfnum;
+ vf->rar_index = sc->hw.mac.rar_entry_count - (vfnum + 1);
+ vf->max_frame_size = ETHER_MAX_LEN;
+ vf->default_vlan = vlan;
+ igb_iov_reset_vlan_rate(vf);
+ if (nvlist_exists_binary(config, "mac-addr")) {
+ mac = nvlist_get_binary(config, "mac-addr", &mac_size);
+ if (mac_size != ETHER_ADDR_LEN || !igb_iov_mac_valid(mac))
+ return (EINVAL);
+ if (igb_iov_mac_in_use(sc, mac, vf))
+ return (EADDRINUSE);
+ memcpy(vf->mac, mac, ETHER_ADDR_LEN);
+ } else {
+ snprintf(nameunit, sizeof(nameunit), "%s-vf%u",
+ device_get_nameunit(sc->dev), vfnum);
+ ether_gen_addr_byname(nameunit, &generated);
+ memcpy(vf->mac, generated.octet, ETHER_ADDR_LEN);
+ if (igb_iov_mac_in_use(sc, vf->mac, vf))
+ return (EADDRINUSE);
+ }
+ if (nvlist_get_bool(config, "allow-set-mac"))
+ vf->flags |= IGB_VF_CAP_MAC;
+ if (nvlist_get_bool(config, "mac-anti-spoof"))
+ vf->flags |= IGB_VF_MAC_ANTI_SPOOF;
+ if (nvlist_get_bool(config, "allow-promisc"))
+ vf->flags |= IGB_VF_ALLOW_PROMISC;
+ vf->flags |= IGB_VF_ACTIVE;
+
+ igb_iov_reset_vf_state(sc, vf);
+ igb_iov_set_anti_spoof(sc, vf);
+ igb_iov_rebuild_vlan(sc);
+ E1000_WRITE_REG(&sc->hw, E1000_MBVFIMR, igb_iov_active_mask(sc));
+ return (0);
+}
+
+#endif /* PCI_IOV */
diff --git a/sys/dev/e1000/if_igb_iov.h b/sys/dev/e1000/if_igb_iov.h
new file mode 100644
index 000000000000..390e63175c7a
--- /dev/null
+++ b/sys/dev/e1000/if_igb_iov.h
@@ -0,0 +1,60 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010-2016, Intel Corporation
+ * Copyright (c) 2026 Kevin Bowling <kbowling@FreeBSD.org>
+ */
+
+#ifndef _IF_IGB_IOV_H_
+#define _IF_IGB_IOV_H_
+
+#define IGB_IOV_MAX_FRAME_SIZE 0x2600
+
+#ifdef PCI_IOV
+
+#include <sys/nv.h>
+#include <sys/iov_schema.h>
+#include <dev/pci/pci_iov.h>
+
+int igb_iov_attach(struct e1000_softc *);
+void igb_iov_detach(struct e1000_softc *);
+bool igb_iov_supported(const struct e1000_softc *);
+bool igb_iov_enabled(const struct e1000_softc *);
+int igb_iov_validate(struct e1000_softc *, u16);
+int igb_if_iov_init(if_ctx_t, u16, const nvlist_t *);
+void igb_if_iov_uninit(if_ctx_t);
+int igb_if_iov_vf_add(if_ctx_t, u16, const nvlist_t *);
+int igb_if_vf_status(if_ctx_t, nvlist_t *);
+void igb_iov_initialize(struct e1000_softc *);
+void igb_iov_handle_mbx(struct e1000_softc *);
+void igb_iov_handle_mdd(struct e1000_softc *);
+void igb_iov_mdd_event(struct e1000_softc *);
+void igb_iov_ping_all_vfs(struct e1000_softc *);
+void igb_iov_reset_prepare(struct e1000_softc *);
+u32 igb_iov_intr_mask(const struct e1000_softc *);
+void igb_iov_intr_drain_stale(struct e1000_softc *);
+void igb_iov_rebuild_mta(struct e1000_softc *);
+void igb_iov_rebuild_vlan(struct e1000_softc *);
+void igb_iov_update_pf_vmolr(struct e1000_softc *);
+
+#else
+
+#define igb_iov_attach(_sc) ((void)(_sc), 0)
+#define igb_iov_detach(_sc) ((void)(_sc))
+#define igb_iov_supported(_sc) (false)
+#define igb_iov_enabled(_sc) (false)
+#define igb_iov_initialize(_sc)
+#define igb_iov_handle_mbx(_sc)
+#define igb_iov_handle_mdd(_sc)
+#define igb_iov_mdd_event(_sc)
+#define igb_iov_ping_all_vfs(_sc)
+#define igb_iov_reset_prepare(_sc)
+#define igb_iov_intr_mask(_sc) (0)
+#define igb_iov_intr_drain_stale(_sc) ((void)(_sc))
+#define igb_iov_rebuild_mta(_sc)
+#define igb_iov_rebuild_vlan(_sc)
+#define igb_iov_update_pf_vmolr(_sc)
+
+#endif
+
+#endif /* _IF_IGB_IOV_H_ */
diff --git a/sys/dev/e1000/if_igbv.c b/sys/dev/e1000/if_igbv.c
new file mode 100644
index 000000000000..2d57a39f934e
--- /dev/null
+++ b/sys/dev/e1000/if_igbv.c
@@ -0,0 +1,836 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2001-2024, Intel Corporation
+ * Copyright (c) 2026 Kevin Bowling <kbowling@FreeBSD.org>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include "if_em.h"
+
+#include <sys/sbuf.h>
+
+#define IGBV_82576_QUEUES 2
+#define IGBV_I350_QUEUES 1
+#define IGBV_MAX_MAC_FILTERS 3
+#define IGBV_QUEUE_DISABLE_BUSY_RETRIES 10
+#define IGBV_QUEUE_DISABLE_DELAY_US 10
+#define IGBV_QUEUE_DISABLE_PAUSE (100 * SBT_1US)
+#define IGBV_QUEUE_DISABLE_RETRIES 20
+#define IGBV_QUEUE_SANITIZE_ATTEMPTS 3
+#define IGBV_VLAN_RETRY_BATCH 4
+#define IGBV_VLAN_RETRY_WINDOW (8 * SBT_1S)
+
+static const struct timeval igbv_queue_log_interval = { 2, 0 };
+static const struct timeval igbv_mbx_log_interval = { 60, 0 };
+static const sbintime_t igbv_queue_retry_delay[] = {
+ 100 * SBT_1MS,
+ 500 * SBT_1MS,
+};
+static const sbintime_t igbv_mbx_retry_delay[] = {
+ 250 * SBT_1MS,
+ 1 * SBT_1S,
+ 4 * SBT_1S,
+ 8 * SBT_1S,
+};
+_Static_assert(nitems(igbv_queue_retry_delay) + 1 ==
+ IGBV_QUEUE_SANITIZE_ATTEMPTS, "missing queue retry delay");
+
+struct igb_vf_uc_addr_list {
+ struct e1000_softc *sc;
+ u8 addrs[IGBV_MAX_MAC_FILTERS][ETHER_ADDR_LEN];
+};
+
+static bool igbv_tx_pending(struct e1000_softc *);
+static bool igbv_vlan_retry_pending(const struct e1000_softc *);
+static void igbv_vlan_retry_tick(struct e1000_softc *);
+
+static void
+igbv_queue_retry_callout(void *arg)
+{
+ struct e1000_softc *sc;
+ if_t ifp;
+
+ sc = arg;
+ if (atomic_readandclear_32(&sc->vf_queue_retry_pending) == 0)
+ return;
+ ifp = iflib_get_ifp(sc->ctx);
+ if ((if_getflags(ifp) & IFF_UP) == 0) {
+ atomic_set_32(&sc->vf_queue_retry_new_epoch, 1);
+ return;
+ }
+ iflib_request_reset_if_up(sc->ctx);
+ iflib_admin_intr_deferred(sc->ctx);
+}
+
+/*
+ * A missing PF can make the posted reset handshake wait for a full mailbox
+ * timeout. Keep that work out of stopped status paths. An administratively
+ * up VF retries complete initialization with an exponential delay capped at
+ * eight seconds, so it recovers without creating a tight mailbox poller.
+ */
+static void
+igbv_mbx_retry_callout(void *arg)
+{
+ struct e1000_softc *sc;
+ if_t ifp;
+
+ sc = arg;
+ if (atomic_readandclear_32(&sc->vf_mbx_retry_pending) == 0 ||
+ atomic_load_acq_32(&sc->vf_mbx_ready) != 0 ||
+ iflib_in_detach(sc->ctx))
+ return;
+ ifp = iflib_get_ifp(sc->ctx);
+ if ((if_getflags(ifp) & IFF_UP) == 0)
+ return;
+
+ iflib_request_reset_if_up(sc->ctx);
+ iflib_admin_intr_deferred(sc->ctx);
+}
+
+static const char *
+igbv_reset_error_desc(s32 error)
+{
+
+ switch (error) {
+ case -E1000_ERR_RESET:
+ return ("PF reset acknowledgement timed out");
+ case -E1000_ERR_MAC_INIT:
+ return ("PF returned an invalid VF reset response");
+ case -E1000_ERR_MBX:
+ return ("PF mailbox reset exchange failed");
+ default:
+ return ("VF reset handshake failed");
+ }
+}
+
+void
+igbv_log_reset_failure(struct e1000_softc *sc, s32 error, bool attaching)
+{
+
+ /* Report each backoff stage, then limit the steady eight-second retry. */
+ if (sc->vf_mbx_retry_stage == nitems(igbv_mbx_retry_delay) - 1 &&
+ !ratecheck(&sc->vf_last_mbx_log, &igbv_mbx_log_interval))
+ return;
+ device_printf(sc->dev, "%s (%d)%s\n", igbv_reset_error_desc(error),
+ error, attaching ? "; continuing attach" : "");
+}
+
+void
+igbv_mbx_retry_detach(struct e1000_softc *sc)
+{
+
+ if (!sc->vf_mbx_retry_initialized)
+ return;
+ atomic_readandclear_32(&sc->vf_mbx_retry_pending);
+ callout_drain(&sc->vf_mbx_retry);
+ sc->vf_mbx_retry_initialized = false;
+}
+
+void
+igbv_mbx_retry_prepare(struct e1000_softc *sc)
+{
+
+ if (!sc->vf_mbx_retry_initialized)
+ return;
+ atomic_readandclear_32(&sc->vf_mbx_retry_pending);
+ callout_drain(&sc->vf_mbx_retry);
+}
+
+void
+igbv_mbx_retry_stop(struct e1000_softc *sc)
+{
+ if_t ifp;
+
+ if (!sc->vf_mbx_retry_initialized)
+ return;
+ atomic_readandclear_32(&sc->vf_mbx_retry_pending);
+ callout_drain(&sc->vf_mbx_retry);
+ ifp = iflib_get_ifp(sc->ctx);
+ if ((if_getflags(ifp) & IFF_UP) == 0)
+ sc->vf_mbx_retry_stage = 0;
+}
+
+void
+igbv_mbx_retry_failed(if_ctx_t ctx)
+{
+ struct e1000_softc *sc;
+ if_t ifp;
+ sbintime_t delay;
+ u_int stage;
+
+ sc = iflib_get_softc(ctx);
+ atomic_store_rel_32(&sc->vf_mbx_ready, 0);
+ sc->link_speed = 0;
+ sc->link_duplex = 0;
+ if (sc->link_state != EM_LINK_STATE_DOWN) {
+ sc->link_state = EM_LINK_STATE_DOWN;
+ iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
+ }
+ iflib_init_failed(ctx);
+
+ ifp = iflib_get_ifp(ctx);
+ if (!sc->vf_mbx_retry_initialized ||
+ (if_getflags(ifp) & IFF_UP) == 0)
+ return;
+ stage = sc->vf_mbx_retry_stage;
+ if (stage >= nitems(igbv_mbx_retry_delay))
+ stage = nitems(igbv_mbx_retry_delay) - 1;
+ delay = igbv_mbx_retry_delay[stage];
+ if (sc->vf_mbx_retry_stage + 1 < nitems(igbv_mbx_retry_delay))
+ sc->vf_mbx_retry_stage++;
+ atomic_set_32(&sc->vf_mbx_retry_pending, 1);
+ callout_reset_sbt(&sc->vf_mbx_retry, delay, 0,
+ igbv_mbx_retry_callout, sc, C_PREL(1));
+}
+
+static void
+igbv_mbx_retry_succeeded(struct e1000_softc *sc)
+{
+
+ atomic_store_rel_32(&sc->vf_mbx_ready, 1);
+ atomic_readandclear_32(&sc->vf_mbx_retry_pending);
+ if (sc->vf_mbx_retry_initialized)
+ callout_stop(&sc->vf_mbx_retry);
+ sc->vf_mbx_retry_stage = 0;
+ sc->vf_last_mbx_log.tv_sec = 0;
+ sc->vf_last_mbx_log.tv_usec = 0;
+}
+
+void
+igbv_queue_retry_detach(struct e1000_softc *sc)
+{
+
+ if (!sc->vf_queue_retry_initialized)
+ return;
+ atomic_readandclear_32(&sc->vf_queue_retry_pending);
+ callout_drain(&sc->vf_queue_retry);
+ sc->vf_queue_retry_initialized = false;
+}
+
+void
+igbv_queue_retry_stop(struct e1000_softc *sc)
+{
+
+ if (!sc->vf_queue_retry_initialized)
+ return;
+ if (atomic_readandclear_32(&sc->vf_queue_retry_pending) != 0)
+ atomic_set_32(&sc->vf_queue_retry_new_epoch, 1);
+ callout_stop(&sc->vf_queue_retry);
+}
+
+void
+igbv_queue_retry_prepare(struct e1000_softc *sc)
+{
+ bool new_epoch;
+
+ new_epoch =
+ atomic_readandclear_32(&sc->vf_queue_retry_new_epoch) != 0;
+ if (!sc->vf_queue_gave_up && !new_epoch)
+ return;
+ sc->vf_queue_failures = 0;
+ sc->vf_queue_gave_up = false;
+}
+
+static void
+igbv_queue_retry_succeeded(struct e1000_softc *sc)
+{
+
+ atomic_readandclear_32(&sc->vf_queue_retry_pending);
+ atomic_readandclear_32(&sc->vf_queue_retry_new_epoch);
+ if (sc->vf_queue_retry_initialized)
+ callout_stop(&sc->vf_queue_retry);
+ sc->vf_queue_failures = 0;
+ sc->vf_queue_gave_up = false;
+}
+
+void
+igbv_queue_retry_failed(if_ctx_t ctx)
+{
+ struct e1000_softc *sc;
+ sbintime_t delay;
+
+ sc = iflib_get_softc(ctx);
+ KASSERT(sc->vf_ifp, ("%s called for a PF", __func__));
+
+ if (sc->vf_queue_failures < IGBV_QUEUE_SANITIZE_ATTEMPTS)
+ sc->vf_queue_failures++;
+ if (sc->vf_queue_failures < IGBV_QUEUE_SANITIZE_ATTEMPTS) {
+ delay = igbv_queue_retry_delay[sc->vf_queue_failures - 1];
+ atomic_set_32(&sc->vf_queue_retry_pending, 1);
+ callout_reset_sbt(&sc->vf_queue_retry, delay, 0,
+ igbv_queue_retry_callout, sc, C_PREL(1));
+ } else if (!sc->vf_queue_gave_up) {
+ atomic_readandclear_32(&sc->vf_queue_retry_pending);
+ callout_stop(&sc->vf_queue_retry);
+ sc->vf_queue_gave_up = true;
+ device_printf(sc->dev,
+ "retained VF queues remained active after %u attempts; "
+ "interface left down; toggle it down/up to retry\n",
+ sc->vf_queue_failures);
+ }
+
+ iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
+ iflib_init_failed(ctx);
+}
+
+void
+igbv_vlan_retry_add(struct e1000_softc *sc, u16 vid)
+{
+ bool pending;
+
+ KASSERT(sc->vf_ifp, ("%s called for a PF", __func__));
+ pending = igbv_vlan_retry_pending(sc);
+ sc->vf_vfta_retry[vid >> 5] |= 1U << (vid & 0x1f);
+ /* Bound the whole batch from its first failure, not each new VID. */
+ if (!pending)
+ sc->vf_vlan_retry_deadline =
+ getsbinuptime() + IGBV_VLAN_RETRY_WINDOW;
+}
+
+void
+igbv_vlan_retry_clear(struct e1000_softc *sc, u16 vid)
+{
+
+ KASSERT(sc->vf_ifp, ("%s called for a PF", __func__));
+ sc->vf_vfta_retry[vid >> 5] &= ~(1U << (vid & 0x1f));
+}
+
+static bool
+igbv_vlan_retry_pending(const struct e1000_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < EM_VFTA_SIZE; i++)
+ if (sc->vf_vfta_retry[i] != 0)
+ return (true);
+ return (false);
+}
+
+static void
+igbv_vlan_retry_tick(struct e1000_softc *sc)
+{
+ u32 bit;
+ u16 vid;
+ int attempts, i, remaining;
+
+ if (!igbv_vlan_retry_pending(sc)) {
+ sc->vf_vlan_retry_deadline = 0;
+ return;
+ }
+ if (getsbinuptime() >= sc->vf_vlan_retry_deadline) {
+ remaining = 0;
+ for (i = 0; i < EM_VFTA_SIZE; i++)
+ remaining += bitcount32(sc->vf_vfta_retry[i]);
+ memset(sc->vf_vfta_retry, 0, sizeof(sc->vf_vfta_retry));
+ sc->vf_vlan_retry_deadline = 0;
+ device_printf(sc->dev,
+ "VF VLAN restore retries exhausted for %d VIDs\n",
+ remaining);
+ return;
+ }
+
+ /*
+ * The mailbox NACK does not distinguish a transient PF rate limit
+ * from permanent VLVF exhaustion. Retry at the PF's sustained
+ * allowance, but bound the entire recovery window so ENOSPC cannot
+ * create a permanent mailbox poller.
+ */
+ for (attempts = 0, i = 0;
+ attempts < IGBV_VLAN_RETRY_BATCH && i < 4096; i++) {
+ vid = sc->vf_vlan_retry_cursor;
+ sc->vf_vlan_retry_cursor = (vid + 1) & 0xfff;
+ bit = 1U << (vid & 0x1f);
+ if ((sc->vf_vfta_retry[vid >> 5] & bit) == 0)
+ continue;
+ attempts++;
+ if ((sc->shadow_vfta[vid >> 5] & bit) == 0 ||
+ e1000_vfta_set_vf(&sc->hw, vid, true) ==
+ E1000_SUCCESS)
+ sc->vf_vfta_retry[vid >> 5] &= ~bit;
+ }
+ if (!igbv_vlan_retry_pending(sc))
+ sc->vf_vlan_retry_deadline = 0;
+}
+
+int
+igbv_if_attach_pre(if_ctx_t ctx)
+{
+ struct e1000_softc *sc;
+ device_t dev;
+ int error;
+
+ dev = iflib_get_dev(ctx);
+ if (pci_msix_count(dev) < 2) {
+ device_printf(dev, "VF operation requires two MSI-X vectors\n");
+ return (ENXIO);
+ }
+ error = em_if_attach_pre(ctx);
+ if (error != 0)
+ return (error);
+
+ sc = iflib_get_softc(ctx);
+ callout_init(&sc->vf_queue_retry, 1);
+ sc->vf_queue_retry_initialized = true;
+ callout_init(&sc->vf_mbx_retry, 1);
+ sc->vf_mbx_retry_initialized = true;
+
+ KASSERT(sc->vf_ifp &&
+ (iflib_get_sctx(ctx)->isc_flags & IFLIB_IS_VF) != 0,
+ ("%s: igbv attached without VF policy", __func__));
+ return (0);
+}
+
+int
+igbv_if_attach_post(if_ctx_t ctx)
+{
+ struct e1000_softc *sc;
+ int error;
+
+ sc = iflib_get_softc(ctx);
+ KASSERT(sc->vf_ifp, ("%s called for a PF", __func__));
+ if (sc->intr_type != IFLIB_INTR_MSIX) {
+ device_printf(sc->dev, "VF operation requires MSI-X\n");
+ return (ENXIO);
+ }
+ error = em_if_attach_post(ctx);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Attach failures can leave the device sysctl tree registered when
+ * hw.bus.disable_failed_devices is set. Do not publish handlers with
+ * softc arguments until iflib has successfully allocated MSI-X.
+ */
+ em_add_device_sysctls(sc);
+ return (0);
+}
+
+int
+igbv_if_media_change(if_ctx_t ctx __unused)
+{
+
+ return (EOPNOTSUPP);
+}
+
+void
+igbv_if_update_admin_status(if_ctx_t ctx)
+{
+ struct e1000_softc *sc;
+ struct e1000_hw *hw;
+ device_t dev;
+ bool link_check, timer_tick;
+
+ sc = iflib_get_softc(ctx);
+ hw = &sc->hw;
+ dev = iflib_get_dev(ctx);
+ KASSERT(sc->vf_ifp, ("%s called for a PF", __func__));
+
+ if ((if_getdrvflags(iflib_get_ifp(ctx)) & IFF_DRV_RUNNING) == 0 ||
+ !sc->vf_queues_sanitized ||
+ atomic_load_acq_32(&sc->vf_mbx_ready) == 0) {
+ if (sc->link_state != EM_LINK_STATE_DOWN) {
+ sc->link_speed = 0;
+ sc->link_duplex = 0;
+ sc->link_state = EM_LINK_STATE_DOWN;
+ iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
+ }
+ return;
+ }
+
+ if (!sc->vf_reset_pending &&
+ atomic_readandclear_32(&sc->promisc_pending) != 0)
+ (void)em_if_set_promisc_impl(ctx,
+ if_getflags(iflib_get_ifp(ctx)));
+
+ if (e1000_check_for_link(hw) != E1000_SUCCESS &&
+ !sc->vf_reset_pending) {
+ sc->vf_reset_pending = true;
+ iflib_request_reset(ctx);
+ iflib_admin_intr_deferred(ctx);
+ }
+ link_check = !hw->mac.get_link_status;
+
+ if (link_check &&
+ (sc->link_state == EM_LINK_STATE_DOWN ||
+ sc->link_state == EM_LINK_STATE_DOWN_RESET_PENDING)) {
+ e1000_get_speed_and_duplex(hw, &sc->link_speed,
+ &sc->link_duplex);
+ if (bootverbose)
+ device_printf(dev, "Link is up %d Mbps %s\n",
+ sc->link_speed,
+ sc->link_duplex == FULL_DUPLEX ?
+ "Full Duplex" : "Half Duplex");
+ sc->link_state = EM_LINK_STATE_UP;
+ iflib_link_state_change(ctx, LINK_STATE_UP,
+ IF_Mbps(sc->link_speed));
+ } else if (!link_check &&
+ (sc->link_state == EM_LINK_STATE_UP ||
+ sc->link_state == EM_LINK_STATE_UP_RESET_PENDING)) {
+ sc->link_speed = 0;
+ sc->link_duplex = 0;
+ sc->link_state = EM_LINK_STATE_DOWN;
+ iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
+ }
+
+ /*
+ * A VF stops transmit DMA when its PF reports link down. Reset if
+ * descriptors remain queued so they cannot be sent stale when carrier
+ * returns, matching the periodic check in Linux igbvf.
+ */
+ if (!link_check && !sc->vf_reset_pending && igbv_tx_pending(sc)) {
+ sc->vf_reset_pending = true;
+ iflib_request_reset(ctx);
+ iflib_admin_intr_deferred(ctx);
+ }
+ /* em_if_init() establishes a new counter baseline after the reset. */
+ timer_tick = !sc->vf_reset_pending &&
+ atomic_readandclear_32(&sc->stats_pending) != 0;
+ if (timer_tick) {
+ em_update_stats_counters(sc);
+ /* iflib clears RUNNING before stop; do not replay after reset. */
+ if ((if_getdrvflags(iflib_get_ifp(ctx)) &
+ IFF_DRV_RUNNING) != 0)
+ igbv_vlan_retry_tick(sc);
+ }
+}
+
+static bool
+igbv_tx_pending(struct e1000_softc *sc)
+{
+ struct tx_ring *txr;
+ u32 head, tail;
+
+ for (int i = 0; i < sc->tx_num_queues; i++) {
+ txr = &sc->tx_queues[i].txr;
+ head = E1000_READ_REG(&sc->hw, E1000_TDH(txr->me));
+ tail = E1000_READ_REG(&sc->hw, E1000_TDT(txr->me));
+ if (head != tail)
+ return (true);
+ }
+ return (false);
+}
+
+static bool
+igbv_sanitize_queues(struct e1000_softc *sc)
+{
+ struct e1000_hw *hw;
+ u32 rxdctl, txdctl;
+ int i, nqueues, retry;
+
+ hw = &sc->hw;
+ switch (hw->mac.type) {
+ case e1000_vfadapt:
+ nqueues = IGBV_82576_QUEUES;
+ break;
+ case e1000_vfadapt_i350:
+ nqueues = IGBV_I350_QUEUES;
+ break;
+ default:
+ return (true);
+ }
+
+ /*
+ * The 82576 and I350 specification updates, Software Clarification 3,
+ * note that VFLR leaves this queue configuration intact. Clear it
+ * before programming the new rings so igbv does not depend on its PF
+ * to sanitize state left by a previous VF owner. igbv uses only queue
+ * zero, but must also clear the unused second 82576 queue.
+ *
+ * Disable every queue first and wait for outstanding DMA activity to
+ * stop before programming TDWBAL/H. Spin only for the normal fast
+ * transition, then sleep until the bounded deadline.
+ */
+ for (i = 0; i < nqueues; i++) {
+ E1000_WRITE_REG(hw, E1000_RXDCTL(i), 0);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(i), 0);
+ }
+ E1000_WRITE_FLUSH(hw);
+ for (retry = 0; retry < IGBV_QUEUE_DISABLE_RETRIES; retry++) {
+ for (i = 0; i < nqueues; i++) {
+ rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(i));
+ txdctl = E1000_READ_REG(hw, E1000_TXDCTL(i));
+ if ((rxdctl & E1000_RXDCTL_QUEUE_ENABLE) != 0 ||
+ (txdctl & E1000_TXDCTL_QUEUE_ENABLE) != 0)
+ break;
+ }
+ if (i == nqueues)
+ break;
+ if (retry + 1 < IGBV_QUEUE_DISABLE_RETRIES) {
+ if (retry < IGBV_QUEUE_DISABLE_BUSY_RETRIES)
+ DELAY(IGBV_QUEUE_DISABLE_DELAY_US);
+ else
+ pause_sbt("igbvqds",
+ IGBV_QUEUE_DISABLE_PAUSE, 0,
+ C_PREL(1));
+ }
+ }
+ if (retry == IGBV_QUEUE_DISABLE_RETRIES) {
+ if (ratecheck(&sc->vf_last_queue_log,
+ &igbv_queue_log_interval))
+ device_printf(sc->dev,
+ "could not disable retained VF queues; "
+ "reset deferred\n");
+ return (false);
+ }
+
+ for (i = 0; i < nqueues; i++) {
+ E1000_WRITE_REG(hw, E1000_SRRCTL(i), 0);
+ E1000_WRITE_REG(hw, E1000_DCA_RXCTRL(i), 0);
+ E1000_WRITE_REG(hw, E1000_TDWBAL(i), 0);
+ E1000_WRITE_REG(hw, E1000_TDWBAH(i), 0);
+ E1000_WRITE_REG(hw, E1000_DCA_TXCTRL(i), 0);
+ }
+ E1000_WRITE_REG(hw, E1000_VFPSRTYPE, 0);
+ E1000_WRITE_FLUSH(hw);
+ return (true);
+}
+
+bool
+igbv_reset(if_ctx_t ctx)
+{
+ struct e1000_softc *sc;
+ struct e1000_hw *hw;
+ s32 error;
+
+ sc = iflib_get_softc(ctx);
+ hw = &sc->hw;
+ KASSERT(sc->vf_ifp, ("%s called for a PF", __func__));
+
+ /*
+ * Receive-buffer allocation and flow control are port resources owned
+ * by the PF. Zero is an unavailable PBA sentinel, not a per-VF size.
+ */
+ sc->pba = 0;
+ hw->fc = (struct e1000_fc_info){
+ .current_mode = e1000_fc_none,
+ .requested_mode = e1000_fc_none,
+ };
+
+ error = e1000_reset_hw(hw);
+ atomic_store_rel_32(&sc->vf_mbx_ready, 0);
+ sc->vf_queues_sanitized = igbv_sanitize_queues(sc);
+ if (!sc->vf_queues_sanitized) {
+ return (false);
+ }
+ igbv_queue_retry_succeeded(sc);
+ if (error != E1000_SUCCESS) {
+ igbv_log_reset_failure(sc, error, false);
+ return (false);
+ }
+ memset(sc->vf_vfta_stale, 0, sizeof(sc->vf_vfta_stale));
+ memset(sc->vf_vfta_retry, 0, sizeof(sc->vf_vfta_retry));
+ sc->vf_vlan_retry_deadline = 0;
+ sc->vf_vlan_retry_cursor = 0;
+ if (e1000_init_hw(hw) < 0) {
+ device_printf(sc->dev, "Hardware Initialization Failed\n");
+ return (false);
+ }
+ e1000_check_for_link(hw);
+ igbv_mbx_retry_succeeded(sc);
+ return (true);
+}
+
+void
+igbv_initialize_transmit_unit(if_ctx_t ctx)
+{
+
+ KASSERT(((struct e1000_softc *)iflib_get_softc(ctx))->vf_ifp,
+ ("%s called for a PF", __func__));
+ em_initialize_transmit_rings(ctx);
+}
+
+void
+igbv_initialize_receive_unit(if_ctx_t ctx)
+{
+
+ KASSERT(((struct e1000_softc *)iflib_get_softc(ctx))->vf_ifp,
+ ("%s called for a PF", __func__));
+ igb_initialize_receive_rings(ctx, true);
+}
+
+void
+igbv_if_intr_enable(if_ctx_t ctx)
+{
+ struct e1000_softc *sc;
+ struct e1000_hw *hw;
+ u32 mask;
+
+ sc = iflib_get_softc(ctx);
+ hw = &sc->hw;
+ KASSERT(sc->vf_ifp, ("%s called for a PF", __func__));
+ if (!sc->vf_queues_sanitized ||
+ atomic_load_acq_32(&sc->vf_mbx_ready) == 0)
+ return;
+ mask = sc->que_mask | sc->link_mask;
+
+ E1000_WRITE_REG(hw, E1000_EIAC, mask);
+ E1000_WRITE_REG(hw, E1000_EIAM, mask);
+ E1000_WRITE_REG(hw, E1000_EIMS, mask);
+ E1000_WRITE_FLUSH(hw);
+}
+
+void
+igbv_if_intr_disable(if_ctx_t ctx)
+{
+ struct e1000_softc *sc;
+ struct e1000_hw *hw;
+
+ sc = iflib_get_softc(ctx);
+ hw = &sc->hw;
+ KASSERT(sc->vf_ifp, ("%s called for a PF", __func__));
+
+ E1000_WRITE_REG(hw, E1000_EIMC, 0xffffffff);
+ E1000_WRITE_REG(hw, E1000_EIAC, 0);
+ E1000_WRITE_FLUSH(hw);
+}
+
+int
+igbv_get_regs(SYSCTL_HANDLER_ARGS)
+{
+ struct e1000_softc *sc;
+ struct e1000_hw *hw;
+ struct sbuf *sb;
+ int error;
+
+ sc = (struct e1000_softc *)arg1;
+ hw = &sc->hw;
+ KASSERT(sc->vf_ifp, ("%s called for a PF", __func__));
+
+ sb = sbuf_new_for_sysctl(NULL, NULL, 512, req);
+ if (sb == NULL)
+ return (ENOMEM);
+
+ /*
+ * Limited VF register set:
+ * Don't read EICR here because it is clear-on-read. The VF register
+ * file exposes its queue pair at index zero, so this diagnostic does
+ * not depend on the narrower lifetime of iflib's queue arrays.
+ */
+ sbuf_printf(sb, "VF Registers\n");
+ sbuf_printf(sb, "\tVTCTRL\t %08x\n",
+ E1000_READ_REG(hw, E1000_CTRL));
+ sbuf_printf(sb, "\tSTATUS\t %08x\n",
+ E1000_READ_REG(hw, E1000_STATUS));
+ sbuf_printf(sb, "\tRDLEN\t %08x\n",
+ E1000_READ_REG(hw, E1000_RDLEN(0)));
+ sbuf_printf(sb, "\tRDH\t %08x\n",
+ E1000_READ_REG(hw, E1000_RDH(0)));
+ sbuf_printf(sb, "\tRDT\t %08x\n",
+ E1000_READ_REG(hw, E1000_RDT(0)));
+ sbuf_printf(sb, "\tTDLEN\t %08x\n",
+ E1000_READ_REG(hw, E1000_TDLEN(0)));
+ sbuf_printf(sb, "\tTDH\t %08x\n",
+ E1000_READ_REG(hw, E1000_TDH(0)));
+ sbuf_printf(sb, "\tTDT\t %08x\n",
+ E1000_READ_REG(hw, E1000_TDT(0)));
+
+ error = sbuf_finish(sb);
+ sbuf_delete(sb);
+ return (error);
+}
+
+static u_int
+igbv_copy_uc_addr(void *arg, struct sockaddr_dl *sdl, u_int idx)
+{
+ struct igb_vf_uc_addr_list *list;
+ const u8 *addr;
+
+ list = arg;
+ addr = (const u8 *)LLADDR(sdl);
+ if (memcmp(addr, list->sc->hw.mac.addr, ETHER_ADDR_LEN) == 0)
+ return (0);
+ if (idx < IGBV_MAX_MAC_FILTERS)
+ memcpy(list->addrs[idx], addr, ETHER_ADDR_LEN);
+ return (1);
+}
+
+void
+igbv_update_uc_addr_list(struct e1000_softc *sc, if_t ifp)
+{
+ struct igb_vf_uc_addr_list list = {
+ .sc = sc,
+ };
+ u_int count;
+
+ count = if_foreach_lladdr(ifp, igbv_copy_uc_addr, &list);
+ if (count > IGBV_MAX_MAC_FILTERS) {
+ device_printf(sc->dev,
+ "too many secondary unicast addresses; maximum is %u\n",
+ IGBV_MAX_MAC_FILTERS);
+ }
+ if (count == 0 && !sc->vf_uc_filters_set)
+ return;
+ /*
+ * Linux igb PFs validate the address field before dispatching the CLR
+ * subcommand. Supply the primary address rather than the zero payload
+ * used by igbvf so those PFs actually remove the old filters. FreeBSD
+ * PFs dispatch CLR before inspecting the otherwise-ignored address.
+ */
+ if (e1000_set_uc_addr_vf(&sc->hw, E1000_VF_MAC_FILTER_CLR,
+ sc->hw.mac.addr) != E1000_SUCCESS) {
+ device_printf(sc->dev,
+ "VF secondary unicast filter clear request failed\n");
+ return;
+ }
+ sc->vf_uc_filters_set = false;
+ if (count > IGBV_MAX_MAC_FILTERS)
+ return;
+
+ for (u_int i = 0; i < count; i++) {
+ if (e1000_set_uc_addr_vf(&sc->hw, E1000_VF_MAC_FILTER_ADD,
+ list.addrs[i]) != E1000_SUCCESS) {
+ device_printf(sc->dev,
+ "VF secondary unicast filter add request failed "
+ "for %6D\n", list.addrs[i], ":");
+ } else
+ sc->vf_uc_filters_set = true;
+ usec_delay(200);
+ }
+}
+
+void
+igbv_reconcile_mac(struct e1000_softc *sc, if_t ifp)
+{
+ u8 *lladdr;
+
+ if (!em_is_valid_ether_addr(sc->hw.mac.addr))
+ return;
+ lladdr = (u8 *)if_getlladdr(ifp);
+ if (memcmp(lladdr, sc->hw.mac.addr, ETHER_ADDR_LEN) == 0)
+ return;
+
+ device_printf(sc->dev,
+ "PF rejected or replaced the requested MAC; using %6D\n",
+ sc->hw.mac.addr, ":");
+ /*
+ * if_setlladdr() would re-enter the driver's address-change path.
+ * Initialization already holds the context lock, so update the
+ * storage directly and issue the notification it would have sent.
+ */
+ memcpy(lladdr, sc->hw.mac.addr, ETHER_ADDR_LEN);
+
+ CURVNET_SET_QUIET(if_getvnet(ifp));
+ EVENTHANDLER_INVOKE(iflladdr_event, ifp);
+ CURVNET_RESTORE();
+}
diff --git a/sys/dev/e1000/igb_txrx.c b/sys/dev/e1000/igb_txrx.c
index 46fe5c741055..dd4d1e5b5974 100644
--- a/sys/dev/e1000/igb_txrx.c
+++ b/sys/dev/e1000/igb_txrx.c
@@ -56,7 +56,14 @@ static int igb_tx_ctx_setup(struct tx_ring *, if_pkt_info_t, uint32_t *,
static int igb_tso_setup(struct tx_ring *, if_pkt_info_t, uint32_t *,
uint32_t *);
-static void igb_rx_checksum(uint32_t, if_rxd_info_t, uint32_t);
+enum igb_rx_csum_status {
+ IGB_RX_CSUM_NONE,
+ IGB_RX_CSUM_GOOD,
+ IGB_RX_CSUM_ERROR,
+};
+
+static enum igb_rx_csum_status igb_rx_checksum(uint32_t, if_rxd_info_t,
+ uint32_t);
static int igb_determine_rsstype(uint16_t);
extern void igb_if_enable_intr(if_ctx_t);
@@ -73,6 +80,29 @@ struct if_txrx igb_txrx = {
.ift_legacy_intr = em_intr
};
+static bool
+igb_vf_vlan_registered(const struct e1000_softc *sc, u16 vtag)
+{
+ u32 vlans;
+ u16 vid;
+
+ /*
+ * 82576 strips an administrative access VLAN but still reports it in
+ * the descriptor. Like Linux igbvf, expose tags only when the VF
+ * requested that VID from the PF.
+ */
+ if (sc->hw.mac.type != e1000_vfadapt &&
+ sc->hw.mac.type != e1000_vfadapt_i350)
+ return (true);
+ vid = EVL_VLANOFTAG(vtag);
+ /*
+ * A trunk VF is an implicit member of VID 0, so retain priority-tag
+ * metadata without requiring vlan(4) to register a VID-0 interface.
+ */
+ vlans = sc->shadow_vfta[vid >> 5] | sc->vf_vfta_stale[vid >> 5];
+ return (vid == 0 || (vlans & (1U << (vid & 0x1f))) != 0);
+}
+
/**********************************************************************
*
* Setup work for hardware segmentation offload (TSO) on
@@ -289,10 +319,27 @@ igb_isc_txd_encap(void *arg, if_pkt_info_t pi)
txd->read.cmd_type_len |= htole32(E1000_TXD_CMD_EOP | txd_flags);
pi->ipi_new_pidx = i;
- /* Sent data accounting for AIM */
+ /*
+ * Sent data accounting for AIM. For TSO, ipi_len is the whole
+ * unsegmented payload, which is not a size the moderation calculation
+ * can use. Count the segments the hardware will put on the wire and
+ * the header each of them carries, so that the average it sees is a
+ * wire packet.
+ */
+ if ((pi->ipi_csum_flags & CSUM_TSO) && pi->ipi_tso_segsz != 0) {
+ u32 hdrlen, segs;
+
+ hdrlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen;
+ if (pi->ipi_len > hdrlen) {
+ segs = howmany(pi->ipi_len - hdrlen, pi->ipi_tso_segsz);
+ txr->tx_bytes += pi->ipi_len + (segs - 1) * hdrlen;
+ txr->tx_packets += segs;
+ return (0);
+ }
+ }
+
txr->tx_bytes += pi->ipi_len;
++txr->tx_packets;
-
return (0);
}
@@ -304,6 +351,7 @@ igb_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx)
struct tx_ring *txr = &que->txr;
E1000_WRITE_REG(&sc->hw, E1000_TDT(txr->me), pidx);
+ em_aim_publish(txr);
}
static int
@@ -395,6 +443,7 @@ igb_isc_rxd_flush(void *arg, uint16_t rxqid, uint8_t flid __unused,
struct rx_ring *rxr = &que->rxr;
E1000_WRITE_REG(&sc->hw, E1000_RDT(rxr->me), pidx);
+ em_aim_publish_rx(rxr);
}
static int
@@ -440,6 +489,7 @@ igb_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
uint16_t pkt_info, len;
uint32_t ptype, staterr;
+ enum igb_rx_csum_status csum_status;
int i, cidx;
bool eop;
@@ -458,7 +508,6 @@ igb_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
le32toh(rxd->wb.lower.lo_dword.data) & IGB_PKTTYPE_MASK;
ri->iri_len += len;
- rxr->rx_bytes += ri->iri_len;
rxd->wb.upper.status_error = 0;
eop = ((staterr & E1000_RXD_STAT_EOP) == E1000_RXD_STAT_EOP);
@@ -487,19 +536,29 @@ igb_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
i++;
} while (!eop);
+ rxr->rx_bytes += ri->iri_len;
rxr->rx_packets++;
- if ((scctx->isc_capenable & IFCAP_RXCSUM) != 0)
- igb_rx_checksum(staterr, ri, ptype);
+ if ((scctx->isc_capenable & IFCAP_RXCSUM) != 0) {
+ csum_status = igb_rx_checksum(staterr, ri, ptype);
+ if (sc->vf_ifp) {
+ if (csum_status == IGB_RX_CSUM_GOOD)
+ sc->rx_csum_good++;
+ else if (csum_status == IGB_RX_CSUM_ERROR)
+ sc->rx_csum_errors++;
+ }
+ }
if (staterr & E1000_RXD_STAT_VP) {
if (((sc->hw.mac.type == e1000_i350) ||
- (sc->hw.mac.type == e1000_i354)) &&
+ (sc->hw.mac.type == e1000_i354) ||
+ (sc->hw.mac.type == e1000_vfadapt_i350)) &&
(staterr & E1000_RXDEXT_STATERR_LB))
ri->iri_vtag = be16toh(rxd->wb.upper.vlan);
else
ri->iri_vtag = le16toh(rxd->wb.upper.vlan);
- ri->iri_flags |= M_VLANTAG;
+ if (igb_vf_vlan_registered(sc, ri->iri_vtag))
+ ri->iri_flags |= M_VLANTAG;
}
ri->iri_flowid =
@@ -517,19 +576,19 @@ igb_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
* doesn't spend time verifying the checksum.
*
*********************************************************************/
-static void
+static enum igb_rx_csum_status
igb_rx_checksum(uint32_t staterr, if_rxd_info_t ri, uint32_t ptype)
{
uint16_t status = (uint16_t)staterr;
uint8_t errors = (uint8_t)(staterr >> 24);
if (__predict_false(status & E1000_RXD_STAT_IXSM))
- return;
+ return (IGB_RX_CSUM_NONE);
/* If there is a layer 3 or 4 error we are done */
if (__predict_false(errors &
(E1000_RXD_ERR_IPE | E1000_RXD_ERR_TCPE)))
- return;
+ return (IGB_RX_CSUM_ERROR);
/* IP Checksum Good */
if (status & E1000_RXD_STAT_IPCS)
@@ -549,6 +608,8 @@ igb_rx_checksum(uint32_t staterr, if_rxd_info_t ri, uint32_t ptype)
ri->iri_csum_data = htons(0xffff);
}
}
+
+ return (IGB_RX_CSUM_GOOD);
}
/********************************************************************
@@ -572,7 +633,13 @@ igb_determine_rsstype(uint16_t pkt_info)
return M_HASHTYPE_RSS_IPV6;
case E1000_RXDADV_RSSTYPE_IPV6_TCP_EX:
return M_HASHTYPE_RSS_TCP_IPV6_EX;
+ case E1000_RXDADV_RSSTYPE_IPV4_UDP:
+ return M_HASHTYPE_RSS_UDP_IPV4;
+ case E1000_RXDADV_RSSTYPE_IPV6_UDP:
+ return M_HASHTYPE_RSS_UDP_IPV6;
+ case E1000_RXDADV_RSSTYPE_IPV6_UDP_EX:
+ return M_HASHTYPE_RSS_UDP_IPV6_EX;
default:
- return M_HASHTYPE_OPAQUE;
+ return M_HASHTYPE_NONE;
}
}