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>
