git: ac9a6d00a014 - main - e1000: Update shared igb SR-IOV code
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 30 Jul 2026 00:14:45 UTC
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_ */