From nobody Sun Oct 5 01:50:03 2025 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F3BBD2E2DC3; Mon, 11 Aug 2025 16:13:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754928792; cv=none; b=BVEuhRjs286vHjY+uIUvraMpvywqfw51CxxamLeUBf5xXrIW1Q6LcnjGpk1/B+m5xRjbgvkL8LQrH6f4KUri1r2xZN8pHpUW1E3fWpSWESOpm7+YAoptgD4UiZfa1Yoo8O//C4YvSB02d/+6DpyVdi58sYxl+kbcR/z6W1f0d0E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754928792; c=relaxed/simple; bh=SOkGjA3o0TOwktBXNR5uJmCW97L7GQRulyxLFYvC6z0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=imdg9eql62QtWJydMizOEkiLkNNspi5Er/fQlWtCdIzeTo+6kEtChp2aGRzCet8dEWyyaeKpGbsI/B8Y+JeiB7E3sA1qJRbDSf1vrpED+lq9LOux/0FiVu39o9WTQ2KBSSIvXyUyio25NBmF1E9A48Ozex6ZBaRBVParAIZlA6E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=NcPHXjVK; arc=none smtp.client-ip=198.175.65.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="NcPHXjVK" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1754928791; x=1786464791; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=SOkGjA3o0TOwktBXNR5uJmCW97L7GQRulyxLFYvC6z0=; b=NcPHXjVK37QQvPeOl8EQTYaDP6pwiiXQcrGFJ632BVBpUSc1YX9wTcZC 4sQhqwI2gdYb7Is4w7JvAgP70cuSKbpK7dSs42BXjfv4KCJBxD/0hhyi3 kHRek8NYPid1UmsYKt9A2VmFbCtNMJnOAM34j2TQLG2sQdgUzhF2P/Y9E Fr5902cqoLRm80/MwErs0EW+pN8YRtWb9Fe6GDM6VF6qMEVe/8vWZI5ip qFDN2WHQ6dGLuQeJA71Xkuk/2hIRcMLMkbsuHYWJMENWJXvawooxz/Lsr pxezVxHKFUSMeu9/Cu8EHfTC+TNcz2bRG30bwiYz0dYHPJzs2wRIzkumf w==; X-CSE-ConnectionGUID: 00IDcIREQ8WDRrXdhC14WQ== X-CSE-MsgGUID: P8Sq3mLURrevNCBKu2jyoQ== X-IronPort-AV: E=McAfee;i="6800,10657,11518"; a="56899618" X-IronPort-AV: E=Sophos;i="6.17,278,1747724400"; d="scan'208";a="56899618" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by orvoesa112.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 11 Aug 2025 09:13:11 -0700 X-CSE-ConnectionGUID: vOru7BRPQPGNUlZDORHzNA== X-CSE-MsgGUID: OcHxUzlmTRKPKRA2OVp/CQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.17,278,1747724400"; d="scan'208";a="165163211" Received: from newjersey.igk.intel.com ([10.102.20.203]) by orviesa006.jf.intel.com with ESMTP; 11 Aug 2025 09:13:06 -0700 From: Alexander Lobakin To: intel-wired-lan@lists.osuosl.org Cc: Alexander Lobakin , Michal Kubiak , Maciej Fijalkowski , Tony Nguyen , Przemek Kitszel , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Alexei Starovoitov , Daniel Borkmann , Simon Horman , nxne.cnse.osdt.itp.upstreaming@intel.com, bpf@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH iwl-next v4 06/13] idpf: remove SW marker handling from NAPI Date: Mon, 11 Aug 2025 18:10:37 +0200 Message-ID: <20250811161044.32329-7-aleksander.lobakin@intel.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250811161044.32329-1-aleksander.lobakin@intel.com> References: <20250811161044.32329-1-aleksander.lobakin@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Michal Kubiak SW marker descriptors on completion queues are used only when a queue is about to be destroyed. It's far from hotpath and handling it in the hotpath NAPI poll makes no sense. Instead, run a simple poller after a virtchnl message for destroying the queue is sent and wait for the replies. If replies for all of the queues are received, this means the synchronization is done correctly and we can go forth with stopping the link. Signed-off-by: Michal Kubiak Signed-off-by: Alexander Lobakin --- drivers/net/ethernet/intel/idpf/idpf.h | 7 +- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 4 +- drivers/net/ethernet/intel/idpf/idpf_lib.c | 2 - drivers/net/ethernet/intel/idpf/idpf_txrx.c | 97 ++++++++++++------- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 34 ++----- 5 files changed, 72 insertions(+), 72 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/= intel/idpf/idpf.h index f4c0eaf9bde3..d462568e7c29 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -40,6 +40,7 @@ struct idpf_vport_max_q; #define IDPF_NUM_CHUNKS_PER_MSG(struct_sz, chunk_sz) \ ((IDPF_CTLQ_MAX_BUF_LEN - (struct_sz)) / (chunk_sz)) =20 +#define IDPF_WAIT_FOR_MARKER_TIMEO 500 #define IDPF_MAX_WAIT 500 =20 /* available message levels */ @@ -246,13 +247,10 @@ enum idpf_vport_reset_cause { /** * enum idpf_vport_flags - Vport flags * @IDPF_VPORT_DEL_QUEUES: To send delete queues message - * @IDPF_VPORT_SW_MARKER: Indicate TX pipe drain software marker packets - * processing is done * @IDPF_VPORT_FLAGS_NBITS: Must be last */ enum idpf_vport_flags { IDPF_VPORT_DEL_QUEUES, - IDPF_VPORT_SW_MARKER, IDPF_VPORT_FLAGS_NBITS, }; =20 @@ -318,7 +316,6 @@ struct idpf_fsteer_fltr { * @tx_itr_profile: TX profiles for Dynamic Interrupt Moderation * @port_stats: per port csum, header split, and other offload stats * @link_up: True if link is up - * @sw_marker_wq: workqueue for marker packets * @tx_tstamp_caps: Capabilities negotiated for Tx timestamping * @tstamp_config: The Tx tstamp config * @tstamp_task: Tx timestamping task @@ -367,8 +364,6 @@ struct idpf_vport { =20 bool link_up; =20 - wait_queue_head_t sw_marker_wq; - struct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps; struct kernel_hwtstamp_config tstamp_config; struct work_struct tstamp_task; diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethe= rnet/intel/idpf/idpf_txrx.h index 11a318fd48d4..1c570794e5bc 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -275,7 +275,6 @@ struct idpf_ptype_state { * bit and Q_RFL_GEN is the SW bit. * @__IDPF_Q_FLOW_SCH_EN: Enable flow scheduling * @__IDPF_Q_SW_MARKER: Used to indicate TX queue marker completions - * @__IDPF_Q_POLL_MODE: Enable poll mode * @__IDPF_Q_CRC_EN: enable CRC offload in singleq mode * @__IDPF_Q_HSPLIT_EN: enable header split on Rx (splitq) * @__IDPF_Q_PTP: indicates whether the Rx timestamping is enabled for the @@ -287,7 +286,6 @@ enum idpf_queue_flags_t { __IDPF_Q_RFL_GEN_CHK, __IDPF_Q_FLOW_SCH_EN, __IDPF_Q_SW_MARKER, - __IDPF_Q_POLL_MODE, __IDPF_Q_CRC_EN, __IDPF_Q_HSPLIT_EN, __IDPF_Q_PTP, @@ -1036,4 +1034,6 @@ bool idpf_rx_singleq_buf_hw_alloc_all(struct idpf_rx_= queue *rxq, u16 cleaned_count); int idpf_tso(struct sk_buff *skb, struct idpf_tx_offload_params *off); =20 +void idpf_wait_for_sw_marker_completion(const struct idpf_tx_queue *txq); + #endif /* !_IDPF_TXRX_H_ */ diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ether= net/intel/idpf/idpf_lib.c index 8c4114473f29..2a0ba72dd5b1 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1565,8 +1565,6 @@ void idpf_init_task(struct work_struct *work) index =3D vport->idx; vport_config =3D adapter->vport_config[index]; =20 - init_waitqueue_head(&vport->sw_marker_wq); - spin_lock_init(&vport_config->mac_filter_list_lock); =20 INIT_LIST_HEAD(&vport_config->user_config.mac_filter_list); diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethe= rnet/intel/idpf/idpf_txrx.c index 723190563eb2..f3ff481a5ae1 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -1539,32 +1539,6 @@ int idpf_vport_queues_alloc(struct idpf_vport *vport) return err; } =20 -/** - * idpf_tx_handle_sw_marker - Handle queue marker packet - * @tx_q: tx queue to handle software marker - */ -static void idpf_tx_handle_sw_marker(struct idpf_tx_queue *tx_q) -{ - struct idpf_netdev_priv *priv =3D netdev_priv(tx_q->netdev); - struct idpf_vport *vport =3D priv->vport; - int i; - - idpf_queue_clear(SW_MARKER, tx_q); - /* Hardware must write marker packets to all queues associated with - * completion queues. So check if all queues received marker packets - */ - for (i =3D 0; i < vport->num_txq; i++) - /* If we're still waiting on any other TXQ marker completions, - * just return now since we cannot wake up the marker_wq yet. - */ - if (idpf_queue_has(SW_MARKER, vport->txqs[i])) - return; - - /* Drain complete */ - set_bit(IDPF_VPORT_SW_MARKER, vport->flags); - wake_up(&vport->sw_marker_wq); -} - /** * idpf_tx_read_tstamp - schedule a work to read Tx timestamp value * @txq: queue to read the timestamp from @@ -1812,9 +1786,6 @@ static bool idpf_tx_clean_complq(struct idpf_compl_qu= eue *complq, int budget, idpf_tx_handle_rs_completion(tx_q, tx_desc, &cleaned_stats, budget); break; - case IDPF_TXD_COMPLT_SW_MARKER: - idpf_tx_handle_sw_marker(tx_q); - break; default: netdev_err(tx_q->netdev, "Unknown TX completion type: %d\n", ctype); @@ -1886,6 +1857,66 @@ static bool idpf_tx_clean_complq(struct idpf_compl_q= ueue *complq, int budget, return !!complq_budget; } =20 +/** + * idpf_wait_for_sw_marker_completion - wait for SW marker of disabled Tx = queue + * @txq: disabled Tx queue + * + * When Tx queue is requested for disabling, the CP sends a special comple= tion + * descriptor called "SW marker", meaning the queue is ready to be destroy= ed. + * If, for some reason, the marker is not received within 500 ms, break the + * polling to not hang the driver. + */ +void idpf_wait_for_sw_marker_completion(const struct idpf_tx_queue *txq) +{ + struct idpf_compl_queue *complq =3D txq->txq_grp->complq; + u32 ntc =3D complq->next_to_clean; + unsigned long timeout; + bool flow, gen_flag; + + if (!idpf_queue_has(SW_MARKER, txq)) + return; + + flow =3D idpf_queue_has(FLOW_SCH_EN, complq); + gen_flag =3D idpf_queue_has(GEN_CHK, complq); + + timeout =3D jiffies + msecs_to_jiffies(IDPF_WAIT_FOR_MARKER_TIMEO); + + do { + struct idpf_splitq_4b_tx_compl_desc *tx_desc; + struct idpf_tx_queue *target; + u32 ctype_gen, id; + + tx_desc =3D flow ? &complq->comp[ntc].common : + &complq->comp_4b[ntc]; + ctype_gen =3D le16_to_cpu(tx_desc->qid_comptype_gen); + + if (!!(ctype_gen & IDPF_TXD_COMPLQ_GEN_M) !=3D gen_flag) { + usleep_range(500, 1000); + continue; + } + + if (FIELD_GET(IDPF_TXD_COMPLQ_COMPL_TYPE_M, ctype_gen) !=3D + IDPF_TXD_COMPLT_SW_MARKER) + goto next; + + id =3D FIELD_GET(IDPF_TXD_COMPLQ_QID_M, ctype_gen); + target =3D complq->txq_grp->txqs[id]; + + idpf_queue_clear(SW_MARKER, target); + if (target =3D=3D txq) + break; + +next: + if (unlikely(++ntc =3D=3D complq->desc_count)) { + ntc =3D 0; + gen_flag =3D !gen_flag; + } + } while (time_before(jiffies, timeout)); + + idpf_queue_assign(GEN_CHK, complq, gen_flag); + complq->next_to_clean =3D ntc; +} + /** * idpf_tx_splitq_build_ctb - populate command tag and size for queue * based scheduling descriptors @@ -3996,14 +4027,6 @@ static int idpf_vport_splitq_napi_poll(struct napi_s= truct *napi, int budget) return budget; } =20 - /* Switch to poll mode in the tear-down path after sending disable - * queues virtchnl message, as the interrupts will be disabled after - * that. - */ - if (unlikely(q_vector->num_txq && idpf_queue_has(POLL_MODE, - q_vector->tx[0]))) - return budget; - work_done =3D min_t(int, work_done, budget - 1); =20 /* Exit the polling mode, but don't re-enable interrupts if stack might diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/= ethernet/intel/idpf/idpf_virtchnl.c index 6164094c6ae5..d3289b3e6602 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -724,21 +724,17 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter) **/ static int idpf_wait_for_marker_event(struct idpf_vport *vport) { - int event; - int i; - - for (i =3D 0; i < vport->num_txq; i++) - idpf_queue_set(SW_MARKER, vport->txqs[i]); + bool markers_rcvd =3D true; =20 - event =3D wait_event_timeout(vport->sw_marker_wq, - test_and_clear_bit(IDPF_VPORT_SW_MARKER, - vport->flags), - msecs_to_jiffies(500)); + for (u32 i =3D 0; i < vport->num_txq; i++) { + struct idpf_tx_queue *txq =3D vport->txqs[i]; =20 - for (i =3D 0; i < vport->num_txq; i++) - idpf_queue_clear(POLL_MODE, vport->txqs[i]); + idpf_queue_set(SW_MARKER, txq); + idpf_wait_for_sw_marker_completion(txq); + markers_rcvd &=3D !idpf_queue_has(SW_MARKER, txq); + } =20 - if (event) + if (markers_rcvd) return 0; =20 dev_warn(&vport->adapter->pdev->dev, "Failed to receive marker packets\n"= ); @@ -2137,24 +2133,12 @@ int idpf_send_enable_queues_msg(struct idpf_vport *= vport) */ int idpf_send_disable_queues_msg(struct idpf_vport *vport) { - int err, i; + int err; =20 err =3D idpf_send_ena_dis_queues_msg(vport, false); if (err) return err; =20 - /* switch to poll mode as interrupts will be disabled after disable - * queues virtchnl message is sent - */ - for (i =3D 0; i < vport->num_txq; i++) - idpf_queue_set(POLL_MODE, vport->txqs[i]); - - /* schedule the napi to receive all the marker packets */ - local_bh_disable(); - for (i =3D 0; i < vport->num_q_vectors; i++) - napi_schedule(&vport->q_vectors[i].napi); - local_bh_enable(); - return idpf_wait_for_marker_event(vport); } =20 --=20 2.50.1