Page MenuHomeFreeBSD

D59028.id186086.diff
No OneTemporary

D59028.id186086.diff

diff --git a/share/man/man4/ice.4 b/share/man/man4/ice.4
--- a/share/man/man4/ice.4
+++ b/share/man/man4/ice.4
@@ -32,7 +32,7 @@
.\"
.\" * Other names and brands may be claimed as the property of others.
.\"
-.Dd August 27, 2026
+.Dd September 5, 2026
.Dt ICE 4
.Os
.Sh NAME
@@ -46,6 +46,7 @@
.Xr loader.conf 5 :
.Cd if_ice_load
.Cd hw.ice.enable_health_events
+.Cd hw.ice.mdd_auto_reset_vf
.Cd hw.ice.irdma
.Cd hw.ice.irdma_max_msix
.Cd hw.ice.debug.enable_tx_fc_filter
@@ -1039,6 +1040,18 @@
If enabled, when the driver receives a firmware health event message, it will
print out a description of the event to the kernel message buffer and if
applicable, possible actions to take to remedy it.
+.It Va hw.ice.mdd_auto_reset_vf
+Automatically reconstruct and release a VF after malicious-driver detection
+resets it.
+This is disabled by default so a non-cooperative VF is reset without restoring
+its queues and remains unable to issue traffic until an externally initiated
+VF function-level reset, PF reset, or SR-IOV configuration recreation
+reconstructs it.
+Enabling this tunable favors availability but allows a persistently faulty or
+hostile VF to resume after each reset.
+An individual PF can override the global setting with the
+.Va dev.ice.#.mdd_auto_reset_vf
+loader tunable.
.It Va hw.ice.irdma
Set to 1 to enable the RDMA client interface, required by the
.Xr irdma 4
diff --git a/sys/dev/ice/ice_common_sysctls.h b/sys/dev/ice/ice_common_sysctls.h
--- a/sys/dev/ice/ice_common_sysctls.h
+++ b/sys/dev/ice/ice_common_sysctls.h
@@ -93,6 +93,21 @@
*/
bool ice_enable_health_events = true;
+#ifdef PCI_IOV
+/**
+ * @var ice_mdd_auto_reset_vf
+ * @brief reconstruct and release a VF after a malicious-driver reset
+ *
+ * Global default for automatically reconstructing and releasing a VF after
+ * hardware reports a malicious-driver event and the driver resets it. Leave
+ * this disabled unless availability is more important than keeping a
+ * persistently faulty VF blocked.
+ *
+ * @remark each PF has a separate sysctl which can override this value.
+ */
+bool ice_mdd_auto_reset_vf = false;
+#endif
+
/**
* @var ice_tx_balance_en
* @brief boolean permitting the 5-layer scheduler topology enablement
@@ -133,6 +148,12 @@
&ice_enable_health_events, 0,
"Enable FW health event reporting globally");
+#ifdef PCI_IOV
+SYSCTL_BOOL(_hw_ice, OID_AUTO, mdd_auto_reset_vf, CTLFLAG_RDTUN,
+ &ice_mdd_auto_reset_vf, 0,
+ "Automatically restore VFs after an MDD reset");
+#endif
+
SYSCTL_BOOL(_hw_ice, OID_AUTO, irdma, CTLFLAG_RDTUN, &ice_enable_irdma, 0,
"Enable iRDMA client interface");
diff --git a/sys/dev/ice/ice_iflib.h b/sys/dev/ice/ice_iflib.h
--- a/sys/dev/ice/ice_iflib.h
+++ b/sys/dev/ice/ice_iflib.h
@@ -348,6 +348,7 @@
#ifdef PCI_IOV
struct ice_vf *vfs;
u16 num_vfs;
+ bool mdd_auto_reset_vf;
#endif
struct ice_resmgr os_imgr;
/* For mirror interface */
diff --git a/sys/dev/ice/ice_iov.h b/sys/dev/ice/ice_iov.h
--- a/sys/dev/ice/ice_iov.h
+++ b/sys/dev/ice/ice_iov.h
@@ -73,6 +73,7 @@
VF_FLAG_INITIALIZED = BIT(5),
VF_FLAG_REBUILD_FAILED = BIT(6),
VF_FLAG_RESET_FAILED = BIT(7),
+ VF_FLAG_MDD_BLOCKED = BIT(8),
};
struct ice_vf_mac_filter {
@@ -110,6 +111,10 @@
u32 txq_configured;
u32 rxq_configured;
u32 rxq_enabled;
+
+ u64 mdd_tx_events;
+ u64 mdd_rx_events;
+ struct timeval last_mdd_log;
};
#define ICE_PCIE_DEV_STATUS 0xAA
@@ -134,6 +139,7 @@
void ice_iov_uninit(struct ice_softc *sc);
void ice_iov_handle_vflr(struct ice_softc *sc);
+u32 ice_iov_handle_mdd(struct ice_softc *sc);
void ice_iov_notify_vfs_reset(struct ice_softc *sc);
int ice_iov_quiesce_vfs_for_reset(struct ice_softc *sc);
diff --git a/sys/dev/ice/ice_iov.c b/sys/dev/ice/ice_iov.c
--- a/sys/dev/ice/ice_iov.c
+++ b/sys/dev/ice/ice_iov.c
@@ -59,6 +59,8 @@
static int ice_iov_restore_vf_host_config(struct ice_softc *sc,
struct ice_vf *vf);
static void ice_iov_clear_vf_queue_state(struct ice_vf *vf);
+static void ice_iov_complete_vf_reset(struct ice_softc *sc,
+ struct ice_vf *vf, bool restore_mapping);
static void ice_iov_ready_vf(struct ice_softc *sc, struct ice_vf *vf);
static int ice_reset_vf(struct ice_softc *sc, struct ice_vf *vf,
bool trigger_reset, bool release_vf);
@@ -701,6 +703,117 @@
}
}
+/**
+ * ice_iov_handle_mdd - Attribute malicious-driver events to VFs
+ * @sc: device softc structure
+ *
+ * Consume every per-VF MDD latch. Block further virtchnl requests and reset a
+ * newly blocked VF without restoring its queues, so even event classes which
+ * only drop the offending packet cannot continue traffic. An optional policy
+ * reconstructs and releases the VF immediately instead.
+ *
+ * @returns a mask of enum ice_mdd_source_bits attributed to configured or
+ * unconfigured VFs of this PF.
+ */
+u32
+ice_iov_handle_mdd(struct ice_softc *sc)
+{
+ static const struct timeval log_interval = { 2, 0 };
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_pf_event event = {};
+ struct ice_vf *vf;
+ u32 reg, sources, vf_sources, tx_events, rx_events, vf_flags;
+ bool newly_blocked;
+ int error;
+
+ event.event = VIRTCHNL_EVENT_RESET_IMPENDING;
+ event.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM;
+ vf_sources = 0;
+ for (int i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ sources = 0;
+ tx_events = 0;
+ rx_events = 0;
+
+ reg = rd32(hw, VP_MDET_TX_PQM(vf->vf_num));
+ if ((reg & VP_MDET_TX_PQM_VALID_M) != 0) {
+ wr32(hw, VP_MDET_TX_PQM(vf->vf_num), 0xffff);
+ sources |= ICE_MDD_TX_PQM;
+ tx_events++;
+ }
+ reg = rd32(hw, VP_MDET_TX_TCLAN(vf->vf_num));
+ if ((reg & VP_MDET_TX_TCLAN_VALID_M) != 0) {
+ wr32(hw, VP_MDET_TX_TCLAN(vf->vf_num), 0xffff);
+ sources |= ICE_MDD_TX_TCLAN;
+ tx_events++;
+ }
+ reg = rd32(hw, VP_MDET_TX_TDPU(vf->vf_num));
+ if ((reg & VP_MDET_TX_TDPU_VALID_M) != 0) {
+ wr32(hw, VP_MDET_TX_TDPU(vf->vf_num), 0xffff);
+ sources |= ICE_MDD_TX_TDPU;
+ tx_events++;
+ }
+ reg = rd32(hw, VP_MDET_RX(vf->vf_num));
+ if ((reg & VP_MDET_RX_VALID_M) != 0) {
+ wr32(hw, VP_MDET_RX(vf->vf_num), 0xffff);
+ sources |= ICE_MDD_RX;
+ rx_events++;
+ }
+ if (tx_events == 0 && rx_events == 0)
+ continue;
+ vf_sources |= sources;
+
+ vf_flags = atomic_load_acq_32(&vf->vf_flags);
+ if ((vf_flags & VF_FLAG_ENABLED) == 0 || vf->vsi == NULL)
+ continue;
+ vf->mdd_tx_events += tx_events;
+ vf->mdd_rx_events += rx_events;
+ newly_blocked = (vf_flags & VF_FLAG_MDD_BLOCKED) == 0;
+ atomic_set_32(&vf->vf_flags, VF_FLAG_MDD_BLOCKED);
+
+ if (ratecheck(&vf->last_mdd_log, &log_interval)) {
+ device_printf(sc->dev,
+ "malicious-driver event from VF-%d "
+ "(tx %ju, rx %ju); %s\n", vf->vf_num,
+ (uintmax_t)vf->mdd_tx_events,
+ (uintmax_t)vf->mdd_rx_events,
+ sc->mdd_auto_reset_vf && newly_blocked ?
+ "resetting VF" : "VF remains blocked");
+ }
+ if (!newly_blocked)
+ continue;
+
+ /* Ignore notification failure; reset does not require VF help. */
+ if (sc->mdd_auto_reset_vf &&
+ (vf_flags & VF_FLAG_INITIALIZED) != 0 &&
+ ice_check_sq_alive(hw, &hw->mailboxq)) {
+ (void)ice_aq_send_msg_to_vf(hw, vf->vf_num,
+ VIRTCHNL_OP_EVENT, VIRTCHNL_STATUS_SUCCESS,
+ (u8 *)&event, sizeof(event), NULL);
+ }
+ /*
+ * TDPU MDD drops only the offending packet. Reset the entire VF so
+ * the software blocked state always means that traffic is actually
+ * fenced. The opt-in policy reconstructs its queues immediately.
+ */
+ error = ice_reset_vf(sc, vf, true, sc->mdd_auto_reset_vf);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "failed to quiesce MDD-blocked VF-%d: %d\n",
+ vf->vf_num, error);
+ } else if (!sc->mdd_auto_reset_vf) {
+ /*
+ * Complete VFR without restoring queues. This leaves the VF
+ * inactive and DMA-fenced, but permits a later physical FLR to
+ * create a new reset edge and recover it.
+ */
+ ice_iov_complete_vf_reset(sc, vf, false);
+ }
+ }
+ ice_flush(hw);
+ return (vf_sources);
+}
+
/**
* ice_iov_notify_vfs_reset - Notify initialized VFs of an impending reset
* @sc: device softc structure
@@ -744,37 +857,73 @@
}
/**
- * ice_iov_ready_vf - Setup VF interrupts and mark it as ready
+ * ice_iov_clear_vf_mdd - Clear hardware MDD latches for a reset VF
* @sc: device softc structure
* @vf: driver's VF structure for the VF to update
*
- * Clears VF reset triggering bit, sets up the PF<->VF interrupt
- * mapping and marks the VF as active in the HW so that the VF
- * driver can use it.
+ * Function reset can generate a spurious anti-spoof MDD indication. Consume
+ * all per-VF latches before releasing reset so it cannot re-block a VF which
+ * has just been reconstructed successfully.
*/
static void
-ice_iov_ready_vf(struct ice_softc *sc, struct ice_vf *vf)
+ice_iov_clear_vf_mdd(struct ice_softc *sc, struct ice_vf *vf)
{
struct ice_hw *hw = &sc->hw;
- u32 reg;
- /* A VF or PF reset discards all queue configuration and state. */
- ice_iov_clear_vf_queue_state(vf);
+ wr32(hw, VP_MDET_TX_PQM(vf->vf_num), 0xffff);
+ wr32(hw, VP_MDET_TX_TCLAN(vf->vf_num), 0xffff);
+ wr32(hw, VP_MDET_TX_TDPU(vf->vf_num), 0xffff);
+ wr32(hw, VP_MDET_RX(vf->vf_num), 0xffff);
+ ice_flush(hw);
+}
+
+/**
+ * ice_iov_complete_vf_reset - Complete a VF reset
+ * @sc: device softc structure
+ * @vf: driver's VF structure for the VF to update
+ * @restore_mapping: restore the VF queue and interrupt mappings
+ *
+ * Clear VFSWR after the hardware drain, optionally restore the VF mappings,
+ * and then publish VFACTIVE. The mapping registers do not retain writes made
+ * while VFSWR remains asserted. Callers may instead leave a software-blocked
+ * VF with no queue or interrupt mappings.
+ */
+static void
+ice_iov_complete_vf_reset(struct ice_softc *sc, struct ice_vf *vf,
+ bool restore_mapping)
+{
+ struct ice_hw *hw = &sc->hw;
+ u32 reg;
- /* Clear the triggering bit */
reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_num));
reg &= ~VPGEN_VFRTRIG_VFSWR_M;
wr32(hw, VPGEN_VFRTRIG(vf->vf_num), reg);
-
- /* Setup VF interrupt allocation and mapping */
- ice_iov_setup_intr_mapping(sc, vf);
-
- /* Indicate to the VF that reset is done */
+ if (restore_mapping)
+ ice_iov_setup_intr_mapping(sc, vf);
wr32(hw, VFGEN_RSTAT(vf->vf_num), VIRTCHNL_VFR_VFACTIVE);
-
ice_flush(hw);
}
+/**
+ * ice_iov_ready_vf - Setup VF interrupts and mark it as ready
+ * @sc: device softc structure
+ * @vf: driver's VF structure for the VF to update
+ *
+ * Clears VF reset triggering bit, sets up the PF<->VF interrupt
+ * mapping and marks the VF as active in the HW so that the VF
+ * driver can use it.
+ */
+static void
+ice_iov_ready_vf(struct ice_softc *sc, struct ice_vf *vf)
+{
+ /* A VF or PF reset discards all queue configuration and state. */
+ ice_iov_clear_vf_queue_state(vf);
+ ice_iov_clear_vf_mdd(sc, vf);
+ atomic_clear_32(&vf->vf_flags, VF_FLAG_MDD_BLOCKED);
+
+ ice_iov_complete_vf_reset(sc, vf, true);
+}
+
/**
* ice_iov_rebuild_vf - Rebuild a VF VSI after a PF or device reset
* @sc: device softc structure
@@ -980,6 +1129,8 @@
}
if (!release_vf) {
+ /* Discard any anti-spoof MDD indication caused by the reset. */
+ ice_iov_clear_vf_mdd(sc, vf);
atomic_clear_32(&vf->vf_flags, VF_FLAG_RESET_FAILED);
return (0);
}
@@ -2596,6 +2747,9 @@
vf_flags = atomic_load_acq_32(&vf->vf_flags);
if ((vf_flags & VF_FLAG_ENABLED) == 0 || vf->vsi == NULL)
return;
+ /* Only a reset outside this dispatcher may release an MDD-blocked VF. */
+ if ((vf_flags & VF_FLAG_MDD_BLOCKED) != 0)
+ return;
/*
* Permit only reset negotiation while VF hardware state is unsafe.
diff --git a/sys/dev/ice/ice_lib.h b/sys/dev/ice/ice_lib.h
--- a/sys/dev/ice/ice_lib.h
+++ b/sys/dev/ice/ice_lib.h
@@ -72,6 +72,13 @@
#include "ice_rss.h"
+enum ice_mdd_source_bits {
+ ICE_MDD_TX_PQM = BIT(0),
+ ICE_MDD_TX_TCLAN = BIT(1),
+ ICE_MDD_TX_TDPU = BIT(2),
+ ICE_MDD_RX = BIT(3),
+};
+
/* Hide debug sysctls unless INVARIANTS is enabled */
#ifdef INVARIANTS
#define ICE_CTLFLAG_DEBUG 0
@@ -122,6 +129,11 @@
/* global sysctl indicating whether FW health status events should be enabled */
extern bool ice_enable_health_events;
+#ifdef PCI_IOV
+/* reconstruct and release a VF automatically after an MDD reset */
+extern bool ice_mdd_auto_reset_vf;
+#endif
+
/* global sysctl indicating whether to enable 5-layer scheduler topology */
extern bool ice_tx_balance_en;
diff --git a/sys/dev/ice/ice_lib.c b/sys/dev/ice/ice_lib.c
--- a/sys/dev/ice/ice_lib.c
+++ b/sys/dev/ice/ice_lib.c
@@ -5973,6 +5973,13 @@
CTLFLAG_RDTUN, &sc->enable_health_events, 0,
"Enable FW health event reporting for this PF");
+#ifdef PCI_IOV
+ sc->mdd_auto_reset_vf = ice_mdd_auto_reset_vf;
+ SYSCTL_ADD_BOOL(ctx, ctx_list, OID_AUTO, "mdd_auto_reset_vf",
+ CTLFLAG_RDTUN, &sc->mdd_auto_reset_vf, 0,
+ "Automatically restore VFs after an MDD reset");
+#endif
+
/* Add a node to track VSI sysctls. Keep track of the node in the
* softc so that we can hook other sysctls into it later. This
* includes both the VSI statistics, as well as potentially dynamic
@@ -8397,11 +8404,25 @@
return (0);
}
-#ifndef GL_MDET_TX_TCLAN
-/* Temporarily use this redefinition until the definition is fixed */
-#define GL_MDET_TX_TCLAN E800_GL_MDET_TX_TCLAN
-#define PF_MDET_TX_TCLAN E800_PF_MDET_TX_TCLAN
-#endif /* !defined(GL_MDET_TX_TCLAN) */
+#define ICE_E830_GL_MDET_TX_TCLAN 0x000fccc0
+#define ICE_E830_PF_MDET_TX_TCLAN 0x000fcc00
+
+static u32
+ice_gl_mdet_tx_tclan(struct ice_hw *hw)
+{
+
+ return (ice_is_e830(hw) ? ICE_E830_GL_MDET_TX_TCLAN :
+ GL_MDET_TX_TCLAN);
+}
+
+static u32
+ice_pf_mdet_tx_tclan(struct ice_hw *hw)
+{
+
+ return (ice_is_e830(hw) ? ICE_E830_PF_MDET_TX_TCLAN :
+ PF_MDET_TX_TCLAN);
+}
+
/**
* ice_handle_mdd_event - Handle possibly malicious events
* @sc: the device softc
@@ -8414,98 +8435,143 @@
ice_handle_mdd_event(struct ice_softc *sc)
{
struct ice_hw *hw = &sc->hw;
- bool mdd_detected = false, request_reinit = false;
device_t dev = sc->dev;
- u32 reg;
+ u32 pf_sources, reg, tclan_reg, vf_sources;
+ bool request_reinit;
if (!ice_testandclear_state(&sc->state, ICE_STATE_MDD_PENDING))
return;
- reg = rd32(hw, GL_MDET_TX_TCLAN);
+ pf_sources = 0;
+ vf_sources = 0;
+ tclan_reg = ice_gl_mdet_tx_tclan(hw);
+ reg = rd32(hw, tclan_reg);
if (reg & GL_MDET_TX_TCLAN_VALID_M) {
- u8 pf_num = (reg & GL_MDET_TX_TCLAN_PF_NUM_M) >> GL_MDET_TX_TCLAN_PF_NUM_S;
- u16 vf_num = (reg & GL_MDET_TX_TCLAN_VF_NUM_M) >> GL_MDET_TX_TCLAN_VF_NUM_S;
- u8 event = (reg & GL_MDET_TX_TCLAN_MAL_TYPE_M) >> GL_MDET_TX_TCLAN_MAL_TYPE_S;
- u16 queue = (reg & GL_MDET_TX_TCLAN_QNUM_M) >> GL_MDET_TX_TCLAN_QNUM_S;
+ u8 pf_num = (reg & GL_MDET_TX_TCLAN_PF_NUM_M) >>
+ GL_MDET_TX_TCLAN_PF_NUM_S;
+ u16 vf_num = (reg & GL_MDET_TX_TCLAN_VF_NUM_M) >>
+ GL_MDET_TX_TCLAN_VF_NUM_S;
+ u8 event = (reg & GL_MDET_TX_TCLAN_MAL_TYPE_M) >>
+ GL_MDET_TX_TCLAN_MAL_TYPE_S;
+ u16 queue = (reg & GL_MDET_TX_TCLAN_QNUM_M) >>
+ GL_MDET_TX_TCLAN_QNUM_S;
- device_printf(dev, "Malicious Driver Detection Tx Descriptor check event '%s' on Tx queue %u PF# %u VF# %u\n",
- ice_mdd_tx_tclan_str(event), queue, pf_num, vf_num);
+ device_printf(dev,
+ "malicious-driver Tx descriptor event '%s' on queue %u, "
+ "PF %u, VF %u\n", ice_mdd_tx_tclan_str(event), queue,
+ pf_num, vf_num);
/* Only clear this event if it matches this PF, that way other
* PFs can read the event and determine VF and queue number.
*/
if (pf_num == hw->pf_id)
- wr32(hw, GL_MDET_TX_TCLAN, 0xffffffff);
-
- mdd_detected = true;
+ wr32(hw, tclan_reg, 0xffffffff);
}
/* Determine what triggered the MDD event */
reg = rd32(hw, GL_MDET_TX_PQM);
if (reg & GL_MDET_TX_PQM_VALID_M) {
- u8 pf_num = (reg & GL_MDET_TX_PQM_PF_NUM_M) >> GL_MDET_TX_PQM_PF_NUM_S;
- u16 vf_num = (reg & GL_MDET_TX_PQM_VF_NUM_M) >> GL_MDET_TX_PQM_VF_NUM_S;
- u8 event = (reg & GL_MDET_TX_PQM_MAL_TYPE_M) >> GL_MDET_TX_PQM_MAL_TYPE_S;
- u16 queue = (reg & GL_MDET_TX_PQM_QNUM_M) >> GL_MDET_TX_PQM_QNUM_S;
+ u8 pf_num = (reg & GL_MDET_TX_PQM_PF_NUM_M) >>
+ GL_MDET_TX_PQM_PF_NUM_S;
+ u16 vf_num = (reg & GL_MDET_TX_PQM_VF_NUM_M) >>
+ GL_MDET_TX_PQM_VF_NUM_S;
+ u8 event = (reg & GL_MDET_TX_PQM_MAL_TYPE_M) >>
+ GL_MDET_TX_PQM_MAL_TYPE_S;
+ u16 queue = (reg & GL_MDET_TX_PQM_QNUM_M) >>
+ GL_MDET_TX_PQM_QNUM_S;
- device_printf(dev, "Malicious Driver Detection Tx Quanta check event '%s' on Tx queue %u PF# %u VF# %u\n",
- ice_mdd_tx_pqm_str(event), queue, pf_num, vf_num);
+ device_printf(dev,
+ "malicious-driver Tx quanta event '%s' on queue %u, "
+ "PF %u, VF %u\n", ice_mdd_tx_pqm_str(event), queue,
+ pf_num, vf_num);
/* Only clear this event if it matches this PF, that way other
* PFs can read the event and determine VF and queue number.
*/
if (pf_num == hw->pf_id)
wr32(hw, GL_MDET_TX_PQM, 0xffffffff);
+ }
+
+ reg = rd32(hw, GL_MDET_TX_TDPU);
+ if (reg & GL_MDET_TX_TDPU_VALID_M) {
+ u8 pf_num = (reg & GL_MDET_TX_TDPU_PF_NUM_M) >>
+ GL_MDET_TX_TDPU_PF_NUM_S;
+ u16 vf_num = (reg & GL_MDET_TX_TDPU_VF_NUM_M) >>
+ GL_MDET_TX_TDPU_VF_NUM_S;
+ u8 event = (reg & GL_MDET_TX_TDPU_MAL_TYPE_M) >>
+ GL_MDET_TX_TDPU_MAL_TYPE_S;
+ u16 queue = (reg & GL_MDET_TX_TDPU_QNUM_M) >>
+ GL_MDET_TX_TDPU_QNUM_S;
- mdd_detected = true;
+ device_printf(dev,
+ "malicious-driver Tx data event %#x on queue %u, "
+ "PF %u, VF %u\n", event, queue, pf_num, vf_num);
+ if (pf_num == hw->pf_id)
+ wr32(hw, GL_MDET_TX_TDPU, 0xffffffff);
}
reg = rd32(hw, GL_MDET_RX);
if (reg & GL_MDET_RX_VALID_M) {
- u8 pf_num = (reg & GL_MDET_RX_PF_NUM_M) >> GL_MDET_RX_PF_NUM_S;
- u16 vf_num = (reg & GL_MDET_RX_VF_NUM_M) >> GL_MDET_RX_VF_NUM_S;
- u8 event = (reg & GL_MDET_RX_MAL_TYPE_M) >> GL_MDET_RX_MAL_TYPE_S;
- u16 queue = (reg & GL_MDET_RX_QNUM_M) >> GL_MDET_RX_QNUM_S;
+ u8 pf_num = (reg & GL_MDET_RX_PF_NUM_M) >>
+ GL_MDET_RX_PF_NUM_S;
+ u8 event = (reg & GL_MDET_RX_MAL_TYPE_M) >>
+ GL_MDET_RX_MAL_TYPE_S;
+ u16 queue = (reg & GL_MDET_RX_QNUM_M) >>
+ GL_MDET_RX_QNUM_S;
- device_printf(dev, "Malicious Driver Detection Rx event '%s' on Rx queue %u PF# %u VF# %u\n",
- ice_mdd_rx_str(event), queue, pf_num, vf_num);
+ /*
+ * E810 Datasheet section 9.2.2.2.1 says only the queue field in
+ * GL_MDET_RX is valid. VP_MDET_RX provides VF attribution.
+ */
+ device_printf(dev,
+ "malicious-driver Rx event '%s' on queue %u, PF %u\n",
+ ice_mdd_rx_str(event), queue, pf_num);
/* Only clear this event if it matches this PF, that way other
- * PFs can read the event and determine VF and queue number.
+ * PFs can read the event and determine the queue number.
*/
if (pf_num == hw->pf_id)
wr32(hw, GL_MDET_RX, 0xffffffff);
-
- mdd_detected = true;
}
- /* Now, confirm that this event actually affects this PF, by checking
- * the PF registers.
- */
- if (mdd_detected) {
- reg = rd32(hw, PF_MDET_TX_TCLAN);
- if (reg & PF_MDET_TX_TCLAN_VALID_M) {
- wr32(hw, PF_MDET_TX_TCLAN, 0xffff);
- sc->soft_stats.tx_mdd_count++;
- request_reinit = true;
- }
-
- reg = rd32(hw, PF_MDET_TX_PQM);
- if (reg & PF_MDET_TX_PQM_VALID_M) {
- wr32(hw, PF_MDET_TX_PQM, 0xffff);
- sc->soft_stats.tx_mdd_count++;
- request_reinit = true;
- }
-
- reg = rd32(hw, PF_MDET_RX);
- if (reg & PF_MDET_RX_VALID_M) {
- wr32(hw, PF_MDET_RX, 0xffff);
- sc->soft_stats.rx_mdd_count++;
- request_reinit = true;
- }
+ /* Per-function latches provide authoritative PF/VF attribution. */
+ tclan_reg = ice_pf_mdet_tx_tclan(hw);
+ reg = rd32(hw, tclan_reg);
+ if (reg & PF_MDET_TX_TCLAN_VALID_M) {
+ wr32(hw, tclan_reg, 0xffff);
+ sc->soft_stats.tx_mdd_count++;
+ pf_sources |= ICE_MDD_TX_TCLAN;
+ }
+ reg = rd32(hw, PF_MDET_TX_PQM);
+ if (reg & PF_MDET_TX_PQM_VALID_M) {
+ wr32(hw, PF_MDET_TX_PQM, 0xffff);
+ sc->soft_stats.tx_mdd_count++;
+ pf_sources |= ICE_MDD_TX_PQM;
+ }
+ reg = rd32(hw, PF_MDET_TX_TDPU);
+ if (reg & PF_MDET_TX_TDPU_VALID_M) {
+ wr32(hw, PF_MDET_TX_TDPU, 0xffff);
+ sc->soft_stats.tx_mdd_count++;
+ pf_sources |= ICE_MDD_TX_TDPU;
+ }
+ reg = rd32(hw, PF_MDET_RX);
+ if (reg & PF_MDET_RX_VALID_M) {
+ wr32(hw, PF_MDET_RX, 0xffff);
+ sc->soft_stats.rx_mdd_count++;
+ pf_sources |= ICE_MDD_RX;
}
- /* TODO: Implement logic to detect and handle events caused by VFs. */
+#ifdef PCI_IOV
+ vf_sources = ice_iov_handle_mdd(sc);
+#endif
+ /*
+ * E810 sets the parent PF_MDET latch for events attributed by a
+ * VP_MDET latch to one of its VFs. Recover the PF only for event
+ * classes which were not attributed to a VF. TDPU drops only the
+ * offending packet and does not stop a queue.
+ */
+ request_reinit = (pf_sources & ~vf_sources &
+ (ICE_MDD_TX_PQM | ICE_MDD_TX_TCLAN | ICE_MDD_RX)) != 0;
/* request that the upper stack re-initialize the Tx/Rx queues */
if (request_reinit)

File Metadata

Mime Type
text/plain
Expires
Sun, Oct 4, 12:09 AM (13 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40162209
Default Alt Text
D59028.id186086.diff (20 KB)

Event Timeline