Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 30 Jul 2026 00:14:45 +0000
From:      Kevin Bowling <kbowling@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: ac9a6d00a014 - main - e1000: Update shared igb SR-IOV code
Message-ID:  <6a6a9775.3b6c2.2d488bbc@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=ac9a6d00a0146b3cda6d03b4d2c8895c2813d89a

commit ac9a6d00a0146b3cda6d03b4d2c8895c2813d89a
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-07-28 21:53:43 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-07-30 00:09:34 +0000

    e1000: Update shared igb SR-IOV code
    
    Update the shared e1000 PF/VF mailbox interfaces for an in-tree igb
    SR-IOV implementation.
    
    Intel FreeBSD igb-2.5.31 and DPDK provide the older PF/VF mailbox
    baseline.
    
    The retained PF mailbox read and explicit unlock operation follow a
    simple Linux igb parameter addition to make PF mailbox acquisition
    nonblocking so the driver can retry outside the shared primitive.
    
    Treating a CTS-less E1000_PF_CONTROL_MSG as a reset follows DPDK.
    
    Sponsored by:   BBOX.io
---
 sys/dev/e1000/e1000_82575.h |   2 +-
 sys/dev/e1000/e1000_hw.h    |   3 +-
 sys/dev/e1000/e1000_mbx.c   | 107 ++++++++++++++++++++++++++++++++++----------
 sys/dev/e1000/e1000_mbx.h   |   5 ++-
 sys/dev/e1000/e1000_vf.c    |  29 +++++++++---
 sys/dev/e1000/e1000_vf.h    |   5 ++-
 6 files changed, 116 insertions(+), 35 deletions(-)

diff --git a/sys/dev/e1000/e1000_82575.h b/sys/dev/e1000/e1000_82575.h
index 91ac3fe9fcbf..720ecf8fc817 100644
--- a/sys/dev/e1000/e1000_82575.h
+++ b/sys/dev/e1000/e1000_82575.h
@@ -402,7 +402,7 @@ 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);
 void e1000_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value);
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;
 }
@@ -175,6 +187,24 @@ s32 e1000_check_for_rst(struct e1000_hw *hw, u16 mbx_id)
 	return ret_val;
 }
 
+/**
+ *  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
@@ -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_vf.c b/sys/dev/e1000/e1000_vf.c
index 9bcd2798e486..d25dc7a23056 100644
--- a/sys/dev/e1000/e1000_vf.c
+++ b/sys/dev/e1000/e1000_vf.c
@@ -400,7 +400,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 +442,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 +457,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 +571,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 +601,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..b509ba48eb0b 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,7 @@ 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);
 #endif /* _E1000_VF_H_ */


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a6a9775.3b6c2.2d488bbc>