The branch stable/14 has been updated by kbowling:

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

commit 3e8b8afbb6e99f1f5e0a9a299b15e639deb33329
Author:     Kevin Bowling <[email protected]>
AuthorDate: 2026-08-10 03:46:24 +0000
Commit:     Kevin Bowling <[email protected]>
CommitDate: 2026-08-24 09:12:22 +0000

    ixl: Track and recover MDD-blocked VFs
    
    The hardware identifies each VF with TX and RX malicious-driver
    status latches, but the driver combined all events into one counter
    and reported only the last VF found.
    
    Consume every PF and VF latch, keep per-direction VF counters, and
    rate-limit per-VF diagnostics.  Keep the software block until a
    successful VF or PF reset reconstructs its resources.
    
    Match Linux i40e policy by leaving a detected VF blocked by default.
    Add an opt-in hw.ixl.mdd_auto_reset_vf tunable that notifies and
    resets the VF for installations that prefer availability.  DPDK
    provides the register clear and per-VF attribution precedent; Linux
    provides the recovery policy.
    
    (cherry picked from commit 93f1065920d806400ace6b60b025faf91926bdaa)
---
 share/man/man4/ixl.4      |   6 +++
 sys/dev/ixl/if_ixl.c      |   8 ++-
 sys/dev/ixl/ixl_pf.h      |   9 +++-
 sys/dev/ixl/ixl_pf_iov.c  |  30 +++++++++++
 sys/dev/ixl/ixl_pf_main.c | 132 ++++++++++++++++++++++------------------------
 5 files changed, 115 insertions(+), 70 deletions(-)

diff --git a/share/man/man4/ixl.4 b/share/man/man4/ixl.4
index ef52b9f8b456..37d8c0cf5db8 100644
--- a/share/man/man4/ixl.4
+++ b/share/man/man4/ixl.4
@@ -213,6 +213,12 @@ use a value written to memory by the hardware instead of 
scanning the
 descriptor ring for completed descriptors.
 Enabled by default; disable to mimic the TX behavior found in
 .Xr ix 4 .
+.It Va hw.ixl.mdd_auto_reset_vf
+Automatically reset a VF after malicious-driver detection blocks it.
+This is disabled by default so a non-cooperative VF remains unable to issue
+traffic until it performs an FLR or the SR-IOV configuration is recreated.
+Enabling this tunable favors availability but allows a persistently faulty or
+hostile VF to resume after each reset.
 .El
 .Sh SYSCTL PROCEDURES
 .Bl -tag -width indent
diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c
index bc929753944b..a0e1fefe09fc 100644
--- a/sys/dev/ixl/if_ixl.c
+++ b/sys/dev/ixl/if_ixl.c
@@ -251,6 +251,12 @@ SYSCTL_INT(_hw_ixl, OID_AUTO, enable_vf_loopback, 
CTLFLAG_RDTUN,
     &ixl_enable_vf_loopback, 0,
     IXL_SYSCTL_HELP_VF_LOOPBACK);
 
+static int ixl_mdd_auto_reset_vf;
+TUNABLE_INT("hw.ixl.mdd_auto_reset_vf", &ixl_mdd_auto_reset_vf);
+SYSCTL_INT(_hw_ixl, OID_AUTO, mdd_auto_reset_vf, CTLFLAG_RDTUN,
+    &ixl_mdd_auto_reset_vf, 0,
+    "Automatically reset VFs blocked by malicious-driver detection");
+
 /*
  * Different method for processing TX descriptor
  * completion.
@@ -1938,6 +1944,7 @@ ixl_save_pf_tunables(struct ixl_pf *pf)
        pf->hw.debug_mask = ixl_shared_debug_mask;
        pf->vsi.enable_head_writeback = !!(ixl_enable_head_writeback);
        pf->enable_vf_loopback = !!(ixl_enable_vf_loopback);
+       pf->mdd_auto_reset_vf = !!(ixl_mdd_auto_reset_vf);
 #if 0
        pf->dynamic_rx_itr = ixl_dynamic_rx_itr;
        pf->dynamic_tx_itr = ixl_dynamic_tx_itr;
@@ -1987,4 +1994,3 @@ ixl_save_pf_tunables(struct ixl_pf *pf)
                        pf->fc = ixl_flow_control;
        }
 }
-
diff --git a/sys/dev/ixl/ixl_pf.h b/sys/dev/ixl/ixl_pf.h
index 695fc8858140..f7bcf121683f 100644
--- a/sys/dev/ixl/ixl_pf.h
+++ b/sys/dev/ixl/ixl_pf.h
@@ -103,7 +103,12 @@ enum ixl_state {
 struct ixl_vf {
        struct ixl_vsi          vsi;
        u32                     vf_flags;
-       u32                     num_mdd_events;
+       u64                     mdd_tx_events;
+       u64                     mdd_rx_events;
+       struct timeval          last_mdd_log;
+       bool                    mdd_blocked;
+       bool                    mdd_event_pending;
+       bool                    mdd_reset_pending;
 
        u8                      mac[ETHER_ADDR_LEN];
        u8                      
mac_filters[IXL_VF_MAX_MAC_FILTERS][ETHER_ADDR_LEN];
@@ -151,6 +156,7 @@ struct ixl_pf {
        int                     tx_itr;
        int                     rx_itr;
        int                     enable_vf_loopback;
+       int                     mdd_auto_reset_vf;
 
        bool                    link_up;
        int                     advertised_speed;
@@ -384,6 +390,7 @@ int ixl_pf_reset(struct ixl_pf *);
 #ifdef PCI_IOV
 void   ixl_notify_vfs_reset(struct ixl_pf *);
 int    ixl_rebuild_vfs_after_reset(struct ixl_pf *);
+int    ixl_reset_vf_on_mdd(struct ixl_pf *, uint16_t);
 #endif
 
 void   ixl_set_queue_rx_itr(struct ixl_rx_queue *);
diff --git a/sys/dev/ixl/ixl_pf_iov.c b/sys/dev/ixl/ixl_pf_iov.c
index aefb01cfadb9..560b559f40e2 100644
--- a/sys/dev/ixl/ixl_pf_iov.c
+++ b/sys/dev/ixl/ixl_pf_iov.c
@@ -497,6 +497,9 @@ ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf)
 
        wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), VIRTCHNL_VFR_VFACTIVE);
        ixl_flush(hw);
+       vf->mdd_blocked = false;
+       vf->mdd_event_pending = false;
+       vf->mdd_reset_pending = false;
        return (0);
 }
 
@@ -1766,6 +1769,10 @@ ixl_handle_vf_msg(struct ixl_pf *pf, struct 
i40e_arq_event_info *event)
            (vf->vf_flags & VF_FLAG_ENABLED) ? " " : " disabled ",
            vf_num, msg_size);
 
+       /* Only a reset outside the virtchnl dispatcher may unblock the VF. */
+       if (vf->mdd_blocked)
+               return;
+
        /* Perform basic checks on the msg */
        err = virtchnl_vc_validate_vf_msg(&vf->version, opcode, msg, msg_size);
        if (err) {
@@ -2036,6 +2043,26 @@ ixl_notify_vfs_reset(struct ixl_pf *pf)
        }
 }
 
+int
+ixl_reset_vf_on_mdd(struct ixl_pf *pf, uint16_t vfnum)
+{
+       struct virtchnl_pf_event event;
+       struct ixl_vf *vf;
+
+       if (vfnum >= pf->num_vfs)
+               return (EINVAL);
+       vf = &pf->vfs[vfnum];
+       if (!(vf->vf_flags & VF_FLAG_ENABLED))
+               return (ENXIO);
+
+       bzero(&event, sizeof(event));
+       event.event = VIRTCHNL_EVENT_RESET_IMPENDING;
+       event.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM;
+       ixl_send_vf_msg(pf, vf, VIRTCHNL_OP_EVENT, I40E_SUCCESS,
+           &event, sizeof(event));
+       return (ixl_reset_vf(pf, vf));
+}
+
 int
 ixl_rebuild_vfs_after_reset(struct ixl_pf *pf)
 {
@@ -2064,6 +2091,9 @@ ixl_rebuild_vfs_after_reset(struct ixl_pf *pf)
                bit_nclear(vf->vsi.vlans_map, 0,
                    IXL_VLANS_MAP_LEN - 1);
                vf->num_mac_filters = 0;
+               vf->mdd_blocked = false;
+               vf->mdd_event_pending = false;
+               vf->mdd_reset_pending = false;
        }
 
        error = ixl_setup_iov_switch(pf);
diff --git a/sys/dev/ixl/ixl_pf_main.c b/sys/dev/ixl/ixl_pf_main.c
index 092718a12d10..b06188545116 100644
--- a/sys/dev/ixl/ixl_pf_main.c
+++ b/sys/dev/ixl/ixl_pf_main.c
@@ -1853,12 +1853,8 @@ ixl_handle_tx_mdd_event(struct ixl_pf *pf)
        struct i40e_hw *hw = &pf->hw;
        device_t dev = pf->dev;
        struct ixl_vf *vf;
-       bool mdd_detected = false;
-       bool pf_mdd_detected = false;
-       bool vf_mdd_detected = false;
        u16 vf_num, queue;
        u8 pf_num, event;
-       u8 pf_mdet_num, vp_mdet_num;
        u32 reg;
 
        /* find what triggered the MDD event */
@@ -1872,18 +1868,20 @@ ixl_handle_tx_mdd_event(struct ixl_pf *pf)
                    I40E_GL_MDET_TX_EVENT_SHIFT;
                queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
                    I40E_GL_MDET_TX_QUEUE_SHIFT;
+               if (queue >= hw->func_caps.base_queue)
+                       queue -= hw->func_caps.base_queue;
+               device_printf(dev,
+                   "last TX malicious-driver cause %#x on queue %u, "
+                   "PF %#x, VF %#x\n", event, queue, pf_num, vf_num);
                wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
-               mdd_detected = true;
        }
 
-       if (!mdd_detected)
-               return;
-
        reg = rd32(hw, I40E_PF_MDET_TX);
        if (reg & I40E_PF_MDET_TX_VALID_MASK) {
                wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
-               pf_mdet_num = hw->pf_id;
-               pf_mdd_detected = true;
+               device_printf(dev,
+                   "TX malicious-driver issue detected on PF-%u\n",
+                   hw->pf_id);
        }
 
        /* Check if MDD was caused by a VF */
@@ -1892,32 +1890,16 @@ ixl_handle_tx_mdd_event(struct ixl_pf *pf)
                reg = rd32(hw, I40E_VP_MDET_TX(i));
                if (reg & I40E_VP_MDET_TX_VALID_MASK) {
                        wr32(hw, I40E_VP_MDET_TX(i), 0xFFFF);
-                       vp_mdet_num = i;
-                       vf->num_mdd_events++;
-                       vf_mdd_detected = true;
+                       if (!(vf->vf_flags & VF_FLAG_ENABLED))
+                               continue;
+                       vf->mdd_tx_events++;
+                       vf->mdd_event_pending = true;
+                       if (!vf->mdd_blocked) {
+                               vf->mdd_blocked = true;
+                               vf->mdd_reset_pending = true;
+                       }
                }
        }
-
-       /* Print out an error message */
-       if (vf_mdd_detected && pf_mdd_detected)
-               device_printf(dev,
-                   "Malicious Driver Detection event %d"
-                   " on TX queue %d, pf number %d (PF-%d), vf number %d 
(VF-%d)\n",
-                   event, queue, pf_num, pf_mdet_num, vf_num, vp_mdet_num);
-       else if (vf_mdd_detected && !pf_mdd_detected)
-               device_printf(dev,
-                   "Malicious Driver Detection event %d"
-                   " on TX queue %d, pf number %d, vf number %d (VF-%d)\n",
-                   event, queue, pf_num, vf_num, vp_mdet_num);
-       else if (!vf_mdd_detected && pf_mdd_detected)
-               device_printf(dev,
-                   "Malicious Driver Detection event %d"
-                   " on TX queue %d, pf number %d (PF-%d)\n",
-                   event, queue, pf_num, pf_mdet_num);
-       /* Theoretically shouldn't happen */
-       else
-               device_printf(dev,
-                   "TX Malicious Driver Detection event (unknown)\n");
 }
 
 static void
@@ -1926,12 +1908,8 @@ ixl_handle_rx_mdd_event(struct ixl_pf *pf)
        struct i40e_hw *hw = &pf->hw;
        device_t dev = pf->dev;
        struct ixl_vf *vf;
-       bool mdd_detected = false;
-       bool pf_mdd_detected = false;
-       bool vf_mdd_detected = false;
        u16 queue;
        u8 pf_num, event;
-       u8 pf_mdet_num, vp_mdet_num;
        u32 reg;
 
        /*
@@ -1946,18 +1924,20 @@ ixl_handle_rx_mdd_event(struct ixl_pf *pf)
                    I40E_GL_MDET_RX_EVENT_SHIFT;
                queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
                    I40E_GL_MDET_RX_QUEUE_SHIFT;
+               if (queue >= hw->func_caps.base_queue)
+                       queue -= hw->func_caps.base_queue;
+               device_printf(dev,
+                   "last RX malicious-driver cause %#x on queue %u, "
+                   "function %#x\n", event, queue, pf_num);
                wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
-               mdd_detected = true;
        }
 
-       if (!mdd_detected)
-               return;
-
        reg = rd32(hw, I40E_PF_MDET_RX);
        if (reg & I40E_PF_MDET_RX_VALID_MASK) {
                wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
-               pf_mdet_num = hw->pf_id;
-               pf_mdd_detected = true;
+               device_printf(dev,
+                   "RX malicious-driver issue detected on PF-%u\n",
+                   hw->pf_id);
        }
 
        /* Check if MDD was caused by a VF */
@@ -1966,32 +1946,16 @@ ixl_handle_rx_mdd_event(struct ixl_pf *pf)
                reg = rd32(hw, I40E_VP_MDET_RX(i));
                if (reg & I40E_VP_MDET_RX_VALID_MASK) {
                        wr32(hw, I40E_VP_MDET_RX(i), 0xFFFF);
-                       vp_mdet_num = i;
-                       vf->num_mdd_events++;
-                       vf_mdd_detected = true;
+                       if (!(vf->vf_flags & VF_FLAG_ENABLED))
+                               continue;
+                       vf->mdd_rx_events++;
+                       vf->mdd_event_pending = true;
+                       if (!vf->mdd_blocked) {
+                               vf->mdd_blocked = true;
+                               vf->mdd_reset_pending = true;
+                       }
                }
        }
-
-       /* Print out an error message */
-       if (vf_mdd_detected && pf_mdd_detected)
-               device_printf(dev,
-                   "Malicious Driver Detection event %d"
-                   " on RX queue %d, pf number %d (PF-%d), (VF-%d)\n",
-                   event, queue, pf_num, pf_mdet_num, vp_mdet_num);
-       else if (vf_mdd_detected && !pf_mdd_detected)
-               device_printf(dev,
-                   "Malicious Driver Detection event %d"
-                   " on RX queue %d, pf number %d, (VF-%d)\n",
-                   event, queue, pf_num, vp_mdet_num);
-       else if (!vf_mdd_detected && pf_mdd_detected)
-               device_printf(dev,
-                   "Malicious Driver Detection event %d"
-                   " on RX queue %d, pf number %d (PF-%d)\n",
-                   event, queue, pf_num, pf_mdet_num);
-       /* Theoretically shouldn't happen */
-       else
-               device_printf(dev,
-                   "RX Malicious Driver Detection event (unknown)\n");
 }
 
 /**
@@ -2004,6 +1968,10 @@ void
 ixl_handle_mdd_event(struct ixl_pf *pf)
 {
        struct i40e_hw *hw = &pf->hw;
+       struct ixl_vf *vf;
+       static const struct timeval log_interval = { 2, 0 };
+       bool reset;
+       int i;
        u32 reg;
 
        /*
@@ -2012,6 +1980,34 @@ ixl_handle_mdd_event(struct ixl_pf *pf)
         */
        ixl_handle_tx_mdd_event(pf);
        ixl_handle_rx_mdd_event(pf);
+       for (i = 0; i < pf->num_vfs; i++) {
+               vf = &pf->vfs[i];
+               if (!vf->mdd_event_pending)
+                       continue;
+               vf->mdd_event_pending = false;
+               reset = vf->mdd_reset_pending;
+               vf->mdd_reset_pending = false;
+               if (ratecheck(&vf->last_mdd_log, &log_interval)) {
+                       device_printf(pf->dev,
+                           "malicious-driver event from VF-%d "
+                           "(tx %ju, rx %ju); %s\n", i,
+                           (uintmax_t)vf->mdd_tx_events,
+                           (uintmax_t)vf->mdd_rx_events,
+                           pf->mdd_auto_reset_vf && reset ?
+                           "resetting VF" : "VF remains blocked");
+               }
+#ifdef PCI_IOV
+               if (pf->mdd_auto_reset_vf && reset) {
+                       int error;
+
+                       error = ixl_reset_vf_on_mdd(pf, i);
+                       if (error != 0)
+                               device_printf(pf->dev,
+                                   "failed to reset MDD-blocked VF-%d: %d\n",
+                                   i, error);
+               }
+#endif
+       }
 
        ixl_clear_state(&pf->state, IXL_STATE_MDD_PENDING);
 

Reply via email to