From nobody Fri Sep 18 01:42:40 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hmFkG1mHHz6sQTB for ; Fri, 18 Sep 2026 01:42:46 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hmFkG0LgPz3H1J for ; Fri, 18 Sep 2026 01:42:46 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1789695766; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=7PMdymRFtRcoQIt81opLJwvdYRM9aDG9VHJuH8uF8w4=; b=Qa1PlmMYQXdaPtTkZoFqUvlZRif/EG+mEi8TmUxGVT9gsCKSZLZh7nVSAiMssgsajmKeyr NqH1z4x59j+DrSn2e43yeqw4UxMJHCjccxUsUjIY2GfLx9zxk3lt+dkgq/08LAsJcuaoU3 5Vrb91nffb1FXmOxsEBGnyTay6odMb5cfTF9PFu8wMc+u7WZ2sCTM7OTDc2zcpnhidbcZt y/xmk06laPeXUdNyy8lASgse7ID9jwsUW7jpPK8O/tfBM0aNIAMidrLil+qcemJAcI6oew cOy/JEPMeTCKtH9V8345iCmUynzFsFiGSmTnhNkW6BArz9ZgNa/0exPev/Ud9w== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1789695766; b=qkFD5ORU2CyJRhIw5Cg+IMYGsLqY7ENmWubLKnPke6aYiEoTPBKWG4CrojjETCcl1DZTBJ A4NgDUUW6RKkxAP0XI7pfOjf1XtVS1b3Ovpb7orFQdndnFBchpO1X9xrEewOl4FOWXQ2+W UF+4Xw+tvt/UP7Fm9OLfsZhWxSGyl4J4/4Nvl5+TQ/3SGnb+0wF3NYyMfhHGWZMWonHD+I wldLnNh4HZ7YPczhyy5y0+OUaCYrKoyCBBzwqako3yHWyZv6c05jhB3fpRIGbXEc8s8/jH Cw2fC5KzJW6cM7AYTEuXEAtCpXWx3oyXWsSaDCcaFSoj3vJht6K5RPrT5TfsTw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1789695766; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=7PMdymRFtRcoQIt81opLJwvdYRM9aDG9VHJuH8uF8w4=; b=AW4AUGsI9szjLxzDK7305A9ojCW8C84TK06wqfdKsxCqtEnSm9d3+UIQ65Urg1Vp6AAhCo KakcWxVh2nKGnYUaxLn0XKJpOTSIYjKEZrXfebgsIBEU/20brtn5KUn8jQY0le4oGABMar E1HnOSEin0lQ0o3aiz+mzUxreSKzzTWSKyGzD9ahu4ShaAkQFw3Q8d+wjECgmZBXXc7iyt r+j+lsroP4e7INppOtM1gZjCUTmghpmQDzDr9LMOwfFHqUecmFDNOEfEnCFnr07D4t7Ufw JpOp+lGg0+7UGn23o1g9atCpBZJYeZG2jWzlW4m9F4DeonjN++YvAFZc4PnzOQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hmFkF6F7jzyNv for ; Fri, 18 Sep 2026 01:42:45 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3b89e by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Fri, 18 Sep 2026 01:42:40 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kevin Bowling Subject: git: cef57e81ce90 - main - ice: Protect the PF mailbox from flooding VFs List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kbowling X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: cef57e81ce906bcceb0bd3097021be4110f192c5 Auto-Submitted: auto-generated Date: Fri, 18 Sep 2026 01:42:40 +0000 Message-Id: <6aac9710.3b89e.558d1267@gitrepo.freebsd.org> The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=cef57e81ce906bcceb0bd3097021be4110f192c5 commit cef57e81ce906bcceb0bd3097021be4110f192c5 Author: Kevin Bowling AuthorDate: 2026-08-19 11:51:42 +0000 Commit: Kevin Bowling CommitDate: 2026-09-18 01:39:55 +0000 ice: Protect the PF mailbox from flooding VFs Wire the shared code mailbox-overflow detector into the VF lifecycle and virtchnl dispatcher. E830 controllers use their per-VF hardware in-flight-message watermark. On older controllers, attribute a congested mailbox snapshot to its sender, reset it with its queues disabled, and discard its subsequent requests. Advance snapshot accounting even for discarded requests. A physical VFLR, PF reset, or IOV recreation releases the VF. A blocked VF can still submit mailbox messages after reset, so discarding requests does not stop it from replenishing the shared queue. Process at most one initially full mailbox immediately. If producers keep it nonempty, mask only the mailbox interrupt cause and let the periodic admin timer schedule bounded drain work. Keep the shared admin vector enabled so that OICR and other control-queue events can still be serviced. Re-enable the mailbox cause after draining and recheck the queue head for arrivals while the cause was masked. Retry failed reads through the same deferred path instead of treating them as an empty queue. Document both protection models and add failure-injection points for the isolation and scheduling paths. E810-XXV tests with two host-attached iavf VFs injected overflow on VF 0, disabling only that VF while VF 1 completed 60 of 60 pings. A physical VFLR and a PF reset each released VF 0; IOV recreation also reset its cumulative count. Forced persistent mailbox-pending state produced 20 admin and control-queue passes in five seconds, remained timer-paced, and did not interrupt sibling traffic. MFC after: 2 weeks Sponsored by: BBOX.io Differential Revision: https://reviews.freebsd.org/D59029 --- share/man/man4/ice.4 | 10 ++++ sys/dev/ice/ice_iflib.h | 1 + sys/dev/ice/ice_iov.c | 143 +++++++++++++++++++++++++++++++++++++++++++-- sys/dev/ice/ice_iov.h | 7 ++- sys/dev/ice/ice_lib.c | 43 ++++++++++++-- sys/dev/ice/ice_vf_mbx.h | 1 + sys/dev/ice/if_ice_iflib.c | 69 ++++++++++++++++++---- 7 files changed, 253 insertions(+), 21 deletions(-) diff --git a/share/man/man4/ice.4 b/share/man/man4/ice.4 index e3246db08689..91d8f95e8fc7 100644 --- a/share/man/man4/ice.4 +++ b/share/man/man4/ice.4 @@ -1185,6 +1185,16 @@ leaves that VF inactive instead of publishing incomplete hardware state. A later VF reset can retry this recovery; a PF or device reset, or SR-IOV configuration recreation, can also recover the VF. .Pp +The driver protects the shared PF mailbox from a VF which submits requests +faster than the PF can service them. +E830 controllers enforce a per-VF limit of 64 outstanding messages in +hardware. +On older controllers, the driver detects a VF responsible for at least 63 +messages in a congested mailbox snapshot, resets it with its queues disabled, +and discards its requests so that other VFs can continue to use the mailbox. +An externally initiated VF function-level reset, PF reset, or SR-IOV +configuration recreation releases the VF. +.Pp An up to date list of parameters and their defaults can be found by using .Xr iovctl 8 with the diff --git a/sys/dev/ice/ice_iflib.h b/sys/dev/ice/ice_iflib.h index ab576ec1d896..d3f96d9c7225 100644 --- a/sys/dev/ice/ice_iflib.h +++ b/sys/dev/ice/ice_iflib.h @@ -351,6 +351,7 @@ struct ice_softc { #ifdef PCI_IOV struct ice_vf *vfs; u16 num_vfs; + u8 mbx_admin_passes; bool mdd_auto_reset_vf; #endif struct ice_resmgr os_imgr; diff --git a/sys/dev/ice/ice_iov.c b/sys/dev/ice/ice_iov.c index d86044acfc64..d60b40b0e24d 100644 --- a/sys/dev/ice/ice_iov.c +++ b/sys/dev/ice/ice_iov.c @@ -59,6 +59,7 @@ static int ice_iov_configure_mac_anti_spoof(struct ice_softc *sc, 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_clear_vf_mbx(struct ice_softc *sc, 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); @@ -176,12 +177,38 @@ ice_iov_attach(struct ice_softc *sc) "pci_iov_attach failed (error=%s)\n", ice_err_str(error)); ice_clear_bit(ICE_FEATURE_SRIOV, sc->feat_en); - } else + } else { ice_set_bit(ICE_FEATURE_SRIOV, sc->feat_en); + if (ice_is_e830(&sc->hw)) + ice_iov_reconfigure_mbx(sc); + else + ice_mbx_init_snapshot(&sc->hw); + } return (error); } +/** + * ice_iov_reconfigure_mbx - Restore hardware mailbox flood protection + * @sc: device softc structure + * + * E830 limits each VF's outstanding messages in hardware. The threshold + * register is reset by a core reset and must be restored during rebuild. + * Older devices use the software snapshot detector instead. + */ +void +ice_iov_reconfigure_mbx(struct ice_softc *sc) +{ + struct ice_hw *hw = &sc->hw; + + if (!ice_is_e830(hw)) + return; + + wr32(hw, E830_MBX_PF_IN_FLIGHT_VF_MSGS_THRESH, + ICE_MBX_OVERFLOW_WATERMARK); + ice_flush(hw); +} + /** * ice_iov_detach - Teardown SR-IOV PF host support * @sc: device softc structure @@ -225,8 +252,13 @@ ice_iov_init(struct ice_softc *sc, uint16_t num_vfs, const nvlist_t *params __un return (ENOMEM); /* Initialize each VF with basic information */ - for (int i = 0; i < num_vfs; i++) + for (int i = 0; i < num_vfs; i++) { sc->vfs[i].vf_num = i; + if (ice_is_e830(&sc->hw)) + ice_mbx_vf_clear_cnt_e830(&sc->hw, i); + else + ice_mbx_init_vf_info(&sc->hw, &sc->vfs[i].mbx_info); + } /* Save off number of configured VFs */ sc->num_vfs = num_vfs; @@ -612,6 +644,8 @@ ice_iov_uninit(struct ice_softc *sc) /* Release per-VF resources */ for (int i = 0; i < sc->num_vfs; i++) { vf = &sc->vfs[i]; + if (!ice_is_e830(&sc->hw)) + LIST_DEL(&vf->mbx_info.list_entry); atomic_store_rel_32(&vf->vf_flags, 0); vsi = vf->vsi; free(vf->mac_filters, M_ICE); @@ -921,10 +955,26 @@ ice_iov_ready_vf(struct ice_softc *sc, struct ice_vf *vf) 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_clear_vf_mbx(sc, vf); ice_iov_complete_vf_reset(sc, vf, true); } +/** + * ice_iov_clear_vf_mbx - Release mailbox isolation after a completed reset + * @sc: device softc structure + * @vf: VF whose mailbox state should be cleared + */ +static void +ice_iov_clear_vf_mbx(struct ice_softc *sc, struct ice_vf *vf) +{ + if (ice_is_e830(&sc->hw)) + ice_mbx_vf_clear_cnt_e830(&sc->hw, vf->vf_num); + else + ice_mbx_clear_malvf(&vf->mbx_info); + atomic_clear_32(&vf->vf_flags, VF_FLAG_MBX_BLOCKED); +} + /** * ice_iov_rebuild_vf - Rebuild a VF VSI after a PF or device reset * @sc: device softc structure @@ -2707,17 +2757,98 @@ ice_vc_notify_vf_link_state(struct ice_softc *sc, struct ice_vf *vf) VIRTCHNL_STATUS_SUCCESS, (u8 *)&event, sizeof(event), NULL); } +/** + * ice_iov_mbx_overflow - Detect and isolate a VF flooding the PF mailbox + * @sc: device private structure + * @vf: VF which sent the current message + * @mbx_data: software mailbox snapshot data, or NULL on E830 + * + * E830 enforces the per-VF watermark in hardware. On older devices, reset + * and block a VF after the Intel snapshot detector first attributes an + * overflow. A later external VF reset, PF reset, or SR-IOV recreation + * releases it. + * + * @returns true if the current message must be discarded. + */ +static bool +ice_iov_mbx_overflow(struct ice_softc *sc, struct ice_vf *vf, + struct ice_mbx_data *mbx_data) +{ + struct ice_hw *hw = &sc->hw; + bool report_malvf; + u32 reg, vf_flags; + int error, status; + + if (mbx_data == NULL) + return (false); + + /* Every message advances the snapshot, including a blocked VF's. */ + report_malvf = false; + status = ice_mbx_vf_state_handler(hw, mbx_data, &vf->mbx_info, + &report_malvf); + if ((atomic_load_acq_32(&vf->vf_flags) & VF_FLAG_MBX_BLOCKED) != 0) + return (true); + ICE_FAIL_POINT_CODE_COND(sc, _debug_fail_point_ice_iov, + mailbox_overflow, ice_iov_fail_vf_matches(vf->vf_num), + FAIL_POINT_NONSLEEPABLE, { + status = 0; + vf->mbx_info.malicious = 1; + report_malvf = true; + }); + if (status != 0) { + device_printf(sc->dev, + "Unable to check VF %u mailbox overflow, err %s\n", + vf->vf_num, ice_status_str(status)); + return (false); + } + if (!report_malvf) + return (vf->mbx_info.malicious != 0); + + vf->mbx_overflow_events++; + atomic_set_32(&vf->vf_flags, VF_FLAG_MBX_BLOCKED); + device_printf(sc->dev, + "VF %u exceeded the mailbox message limit; resetting and blocking it\n", + vf->vf_num); + + vf_flags = atomic_load_acq_32(&vf->vf_flags); + if ((vf_flags & VF_FLAG_ENABLED) != 0 && vf->vsi != NULL) { + error = ice_reset_vf(sc, vf, true, false); + if (error != 0) { + device_printf(sc->dev, + "Unable to isolate VF %u after mailbox overflow: %s\n", + vf->vf_num, ice_err_str(error)); + } else { + /* + * Leave queues and mailbox requests blocked, but complete VFR + * so a later physical FLR can create a new reset edge and + * recover the VF. + */ + ice_iov_complete_vf_reset(sc, vf, false); + } + } else { + /* An incompletely configured VF has no queues to drain. */ + reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_num)); + reg |= VPGEN_VFRTRIG_VFSWR_M; + wr32(hw, VPGEN_VFRTRIG(vf->vf_num), reg); + ice_flush(hw); + } + + return (true); +} + /** * ice_vc_handle_vf_msg - Handle a message from a VF * @sc: device private structure * @event: event received from the HW MBX queue + * @mbx_data: software overflow-detection data, or NULL on E830 * * Called whenever an event is received from a VF on the HW mailbox queue. * Responsible for handling these messages as well as responding to the * VF afterwards, depending on the received message type. */ void -ice_vc_handle_vf_msg(struct ice_softc *sc, struct ice_rq_event_info *event) +ice_vc_handle_vf_msg(struct ice_softc *sc, struct ice_rq_event_info *event, + struct ice_mbx_data *mbx_data) { struct ice_hw *hw = &sc->hw; device_t dev = sc->dev; @@ -2737,6 +2868,8 @@ ice_vc_handle_vf_msg(struct ice_softc *sc, struct ice_rq_event_info *event) } vf = &sc->vfs[v_id]; + if (ice_iov_mbx_overflow(sc, vf, mbx_data)) + return; /* Perform basic checks on the msg */ err = virtchnl_vc_validate_vf_msg(&vf->version, v_opcode, msg, msglen); @@ -2750,8 +2883,8 @@ ice_vc_handle_vf_msg(struct ice_softc *sc, struct ice_rq_event_info *event) 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) + /* Only a reset outside this dispatcher may release an isolated VF. */ + if ((vf_flags & (VF_FLAG_MDD_BLOCKED | VF_FLAG_MBX_BLOCKED)) != 0) return; /* diff --git a/sys/dev/ice/ice_iov.h b/sys/dev/ice/ice_iov.h index 35f5edcb5acd..3ef565f709cc 100644 --- a/sys/dev/ice/ice_iov.h +++ b/sys/dev/ice/ice_iov.h @@ -74,6 +74,7 @@ enum ice_vf_flags { VF_FLAG_REBUILD_FAILED = BIT(6), VF_FLAG_RESET_FAILED = BIT(7), VF_FLAG_MDD_BLOCKED = BIT(8), + VF_FLAG_MBX_BLOCKED = BIT(9), }; struct ice_vf_mac_filter { @@ -114,6 +115,8 @@ struct ice_vf { u64 mdd_tx_events; u64 mdd_rx_events; + struct ice_mbx_vf_info mbx_info; + u64 mbx_overflow_events; struct timeval last_mdd_log; }; @@ -142,8 +145,10 @@ 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); +void ice_iov_reconfigure_mbx(struct ice_softc *sc); -void ice_vc_handle_vf_msg(struct ice_softc *sc, struct ice_rq_event_info *event); +void ice_vc_handle_vf_msg(struct ice_softc *sc, struct ice_rq_event_info *event, + struct ice_mbx_data *mbx_data); void ice_vc_notify_all_vfs_link_state(struct ice_softc *sc); #endif /* _ICE_IOV_H_ */ diff --git a/sys/dev/ice/ice_lib.c b/sys/dev/ice/ice_lib.c index 679def5c0e6d..9c5732003494 100644 --- a/sys/dev/ice/ice_lib.c +++ b/sys/dev/ice/ice_lib.c @@ -108,7 +108,8 @@ static void ice_check_ctrlq_errors(struct ice_softc *sc, const char *qname, struct ice_ctl_q_info *cq); static void ice_process_link_event(struct ice_softc *sc, struct ice_rq_event_info *e); static void ice_process_ctrlq_event(struct ice_softc *sc, const char *qname, - struct ice_rq_event_info *event); + struct ice_rq_event_info *event, + struct ice_mbx_data *mbx_data); static void ice_nvm_version_str(struct ice_hw *hw, struct sbuf *buf); static void ice_update_port_oversize(struct ice_softc *sc, u64 rx_errors); static void ice_active_pkg_version_str(struct ice_hw *hw, struct sbuf *buf); @@ -2327,7 +2328,8 @@ ice_process_link_event(struct ice_softc *sc, */ static void ice_process_ctrlq_event(struct ice_softc *sc, const char *qname, - struct ice_rq_event_info *event) + struct ice_rq_event_info *event, + struct ice_mbx_data *mbx_data) { u16 opcode; @@ -2339,7 +2341,7 @@ ice_process_ctrlq_event(struct ice_softc *sc, const char *qname, break; #ifdef PCI_IOV case ice_mbx_opc_send_msg_to_pf: - ice_vc_handle_vf_msg(sc, event); + ice_vc_handle_vf_msg(sc, event, mbx_data); break; #endif case ice_aqc_opc_fw_logs_event: @@ -2375,6 +2377,9 @@ int ice_process_ctrlq(struct ice_softc *sc, enum ice_ctl_q q_type, u16 *pending) { struct ice_rq_event_info event = { { 0 } }; +#ifdef PCI_IOV + struct ice_mbx_data mbx_data = { 0 }; +#endif struct ice_hw *hw = &sc->hw; struct ice_ctl_q_info *cq; int status; @@ -2393,6 +2398,11 @@ ice_process_ctrlq(struct ice_softc *sc, enum ice_ctl_q q_type, u16 *pending) case ICE_CTL_Q_MAILBOX: cq = &hw->mailboxq; qname = "Mailbox"; +#ifdef PCI_IOV + if (!ice_is_e830(hw) && sc->num_vfs != 0) + hw->mbx_snapshot.mbx_buf.state = + ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT; +#endif break; default: device_printf(sc->dev, @@ -2428,10 +2438,31 @@ ice_process_ctrlq(struct ice_softc *sc, enum ice_ctl_q q_type, u16 *pending) return (EIO); } /* XXX should we separate this handler by controlq type? */ - ice_process_ctrlq_event(sc, qname, &event); +#ifdef PCI_IOV + if (q_type == ICE_CTL_Q_MAILBOX && + le16toh(event.desc.opcode) == ice_mbx_opc_send_msg_to_pf) { + if (ice_is_e830(hw)) { + ice_process_ctrlq_event(sc, qname, &event, NULL); + ice_e830_mbx_vf_dec_trig(hw, &event); + } else { + mbx_data.max_num_msgs_mbx = cq->num_rq_entries; + mbx_data.async_watermark_val = + ICE_MBX_OVERFLOW_WATERMARK; + mbx_data.num_msg_proc = loop; + mbx_data.num_pending_arq = *pending; + ice_process_ctrlq_event(sc, qname, &event, + &mbx_data); + } + } else +#endif + ice_process_ctrlq_event(sc, qname, &event, NULL); } while (*pending && (++loop < ICE_CTRLQ_WORK_LIMIT)); free(event.msg_buf, M_ICE); + ICE_FAIL_POINT_CODE_COND(sc, _debug_fail_point_ice, mailbox_pending, + q_type == ICE_CTL_Q_MAILBOX, FAIL_POINT_NONSLEEPABLE, { + *pending = 1; + }); return 0; } @@ -5354,6 +5385,10 @@ ice_configure_misc_interrupts(struct ice_softc *sc) /* Associate the OICR interrupt with ITR 0, and enable it */ wr32(hw, PFINT_OICR_CTL, PFINT_OICR_CTL_CAUSE_ENA_M); +#ifdef PCI_IOV + /* Start a fresh drain budget when restoring mailbox interrupts. */ + sc->mbx_admin_passes = 0; +#endif /* Associate the Mailbox interrupt with ITR 0, and enable it */ wr32(hw, PFINT_MBX_CTL, PFINT_MBX_CTL_CAUSE_ENA_M); diff --git a/sys/dev/ice/ice_vf_mbx.h b/sys/dev/ice/ice_vf_mbx.h index 3b185ac89c11..7e4e628e25ec 100644 --- a/sys/dev/ice/ice_vf_mbx.h +++ b/sys/dev/ice/ice_vf_mbx.h @@ -44,6 +44,7 @@ * MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT register. */ #define ICE_ASYNC_VF_MSG_THRESHOLD 63 +#define ICE_MBX_OVERFLOW_WATERMARK (ICE_ASYNC_VF_MSG_THRESHOLD + 1) int ice_aq_send_msg_to_pf(struct ice_hw *hw, enum virtchnl_ops v_opcode, diff --git a/sys/dev/ice/if_ice_iflib.c b/sys/dev/ice/if_ice_iflib.c index 78542abd706b..9068fd385314 100644 --- a/sys/dev/ice/if_ice_iflib.c +++ b/sys/dev/ice/if_ice_iflib.c @@ -2444,8 +2444,10 @@ ice_if_update_admin_status(if_ctx_t ctx) { struct ice_softc *sc = (struct ice_softc *)iflib_get_softc(ctx); enum ice_fw_modes fw_mode; - bool reschedule = false; + bool defer_mailbox = false, reschedule = false; + u32 reg; u16 pending = 0; + int error; ASSERT_CTX_LOCKED(sc); @@ -2489,19 +2491,59 @@ ice_if_update_admin_status(if_ctx_t ctx) */ ; } else if (ice_testandclear_state(&sc->state, ICE_STATE_CONTROLQ_EVENT_PENDING)) { + pending = 0; ice_process_ctrlq(sc, ICE_CTL_Q_ADMIN, &pending); if (pending > 0) reschedule = true; if (ice_is_generic_mac(&sc->hw)) { + pending = 0; ice_process_ctrlq(sc, ICE_CTL_Q_SB, &pending); if (pending > 0) reschedule = true; } - ice_process_ctrlq(sc, ICE_CTL_Q_MAILBOX, &pending); - if (pending > 0) + pending = 0; + error = ice_process_ctrlq(sc, ICE_CTL_Q_MAILBOX, &pending); + if (error == 0 && pending == 0) { + reg = rd32(&sc->hw, PFINT_MBX_CTL); + if ((reg & PFINT_MBX_CTL_CAUSE_ENA_M) == 0) { + wr32(&sc->hw, PFINT_MBX_CTL, + reg | PFINT_MBX_CTL_CAUSE_ENA_M); + ice_flush(&sc->hw); + /* Events received while masked may not interrupt. */ + pending = (rd32(&sc->hw, sc->hw.mailboxq.rq.head) & + sc->hw.mailboxq.rq.head_mask) != + sc->hw.mailboxq.rq.next_to_clean; + } + } + if (error != 0) { + /* Retry a failed read on the timer, not in a task loop. */ + defer_mailbox = true; + } else if (pending > 0) { +#ifdef PCI_IOV + /* + * Two passes drain one initially full 512-entry mailbox. + * If it remains nonempty, a VF is replenishing it faster + * than this task can drain it. Mask only the mailbox cause + * and let the periodic admin timer schedule bounded work. + */ + if (sc->mbx_admin_passes < + howmany(ICE_MBXQ_LEN, ICE_CTRLQ_WORK_LIMIT)) + sc->mbx_admin_passes++; + if (sc->mbx_admin_passes < + howmany(ICE_MBXQ_LEN, ICE_CTRLQ_WORK_LIMIT)) + reschedule = true; + else + defer_mailbox = true; +#else reschedule = true; +#endif + } else { +#ifdef PCI_IOV + sc->mbx_admin_passes = 0; +#endif + } } /* Poll for link up */ @@ -2519,17 +2561,18 @@ ice_if_update_admin_status(if_ctx_t ctx) iflib_iov_intr_deferred(ctx); #endif - /* - * If there are still messages to process, we need to reschedule - * ourselves. Otherwise, we can just re-enable the interrupt. We'll be - * woken up at the next interrupt or timer event. - */ - if (reschedule) { + if (defer_mailbox) { + reg = rd32(&sc->hw, PFINT_MBX_CTL); + wr32(&sc->hw, PFINT_MBX_CTL, + reg & ~PFINT_MBX_CTL_CAUSE_ENA_M); + } + if (reschedule || defer_mailbox) ice_set_state(&sc->state, ICE_STATE_CONTROLQ_EVENT_PENDING); + if (reschedule) iflib_admin_intr_deferred(ctx); - } else { + /* Keep OICR and the other control queues live during mailbox deferral. */ + if (!reschedule || defer_mailbox) ice_enable_intr(&sc->hw, sc->irqvs[0].me); - } } /** @@ -2739,6 +2782,10 @@ ice_rebuild(struct ice_softc *sc) goto err_shutdown_ctrlq; } +#ifdef PCI_IOV + ice_iov_reconfigure_mbx(sc); +#endif + /* Query the allocated resources for Tx scheduler */ status = ice_sched_query_res_alloc(hw); if (status) {