The branch main has been updated by kbowling:

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

commit ac9a6d00a0146b3cda6d03b4d2c8895c2813d89a
Author:     Kevin Bowling <[email protected]>
AuthorDate: 2026-07-28 21:53:43 +0000
Commit:     Kevin Bowling <[email protected]>
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_ */

Reply via email to