Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F174409458
D59028.id186086.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
20 KB
Referenced Files
None
Subscribers
None
D59028.id186086.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D59028: ice: Isolate VFs after malicious-driver detection
Attached
Detach File
Event Timeline
Log In to Comment