From nobody Sun Feb 8 12:38:26 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (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 BFD916E5E1 for ; Thu, 14 Mar 2024 12:00:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710417660; cv=none; b=kbnwdyOPsfZSNUh/hdfzlmHoUE9Lcm6WTp7BvfD0mbZZ9VfMk04OPCmjAsgn6VpWxcJXb/eJWKRd6Sl41bjRA7zvJ8l21KGQ0CM28lYJMSiDNhQbFtDp4B+BXhq1D6uBtOYk0kt7G0nBBPaogFw5APGd9DP52V11WZJvQMjhDSM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710417660; c=relaxed/simple; bh=h/Ww1+w6U/0FAI0p8RzsE3Jw1ULImCnm9DUDEJ/OYn8=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=cO6uZ+iAnz7x+2Gtt78c5c8mjYIZqAHnp3JVDb/cDhoobKuEDBJrqhoTx5IGBia5aQ2/HVE7jjf5whJHm37Fqrgc/lHlRlx3NurGeIabCJ9dmVd6W+Ibdzd0SAI1MJIyP4CSV6Mf6xvIM+tomJZqMboSH3y9YsLAjhF7tLzEOdc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Rn2pH4wA; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Rn2pH4wA" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1710417657; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=6/gK8g9f+wzelZGE5wq8NtDc/f04FJ1g3I3JNi+j5Os=; b=Rn2pH4wASW0t8uDPJdnB3PEYho5yrGr+BsvX+0+H+JoALPs/f8aMlwSsRghWiocnp2IZcr zcq4h/aOoJrzD5bQcmrzJTdB1LhQJqu1CFDq6UZn7PL0uWPTay8/5f9dUAJcFcZX6LdfQr EreMv4dFIrHkt7B63S6/PsMJRIeIEEU= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-563-tbIZCbFOP_CrupvkeJo2wQ-1; Thu, 14 Mar 2024 08:00:53 -0400 X-MC-Unique: tbIZCbFOP_CrupvkeJo2wQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 1D1463803916; Thu, 14 Mar 2024 12:00:52 +0000 (UTC) Received: from p1.luc.cera.cz (unknown [10.45.224.236]) by smtp.corp.redhat.com (Postfix) with ESMTP id E3FF73C23; Thu, 14 Mar 2024 12:00:49 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: pawel.chmielewski@intel.com, aleksandr.loktionov@intel.com, mschmidt@redhat.com, Hugo Ferreira , Jesse Brandeburg , Tony Nguyen , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Jacob Keller , intel-wired-lan@lists.osuosl.org (moderated list:INTEL ETHERNET DRIVERS), linux-kernel@vger.kernel.org (open list) Subject: [PATCH net v2] i40e: Enforce software interrupt during busy-poll exit Date: Thu, 14 Mar 2024 13:00:48 +0100 Message-ID: <20240314120049.111241-1-ivecera@redhat.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 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.1 Content-Type: text/plain; charset="utf-8" As for ice bug fixed by commit b7306b42beaf ("ice: manage interrupts during poll exit") followed by commit 23be7075b318 ("ice: fix software generating extra interrupts") I'm seeing the similar issue also with i40e driver. In certain situation when busy-loop is enabled together with adaptive coalescing, the driver occasionally misses that there are outstanding descriptors to clean when exiting busy poll. Try to catch the remaining work by triggering a software interrupt when exiting busy poll. No extra interrupts will be generated when busy polling is not used. The issue was found when running sockperf ping-pong tcp test with adaptive coalescing and busy poll enabled (50 as value busy_pool and busy_read sysctl knobs) and results in huge latency spikes with more than 100000us. The fix is inspired from the ice driver and do the following: 1) During napi poll exit in case of busy-poll (napo_complete_done() returns false) this is recorded to q_vector that we were in busy loop. 2) In i40e_update_enable_itr() - updates refreshed ITR intervals directly using PFINT_ITRN register - if we are exiting ordinary poll then just enables the interrupt using PFINT_DYN_CTLN - if we are exiting busy poll then enables the interrupt and additionally triggers an immediate software interrupt to catch any pending clean-ups 3) Reuses unused 3rd ITR (interrupt throttle) index and set it to 20K interrupts per second to limit the number of these sw interrupts. Test results =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Prior: [root@dell-per640-07 net]# sockperf ping-pong -i 10.9.9.1 --tcp -m 1000 --m= ps=3Dmax -t 120 sockperf: =3D=3D version #3.10-no.git =3D=3D sockperf[CLIENT] send on:sockperf: using recvfrom() to block on socket(s) [ 0] IP =3D 10.9.9.1 PORT =3D 11111 # TCP sockperf: Warmup stage (sending a few dummy messages)... sockperf: Starting test... sockperf: Test end (interrupted by timer) sockperf: Test ended sockperf: [Total Run] RunTime=3D119.999 sec; Warm up time=3D400 msec; SentM= essages=3D2438563; ReceivedMessages=3D2438562 sockperf: =3D=3D=3D=3D=3D=3D=3D=3D=3D Printing statistics for Server No: 0 sockperf: [Valid Duration] RunTime=3D119.549 sec; SentMessages=3D2429473; R= eceivedMessages=3D2429473 sockperf: =3D=3D=3D=3D> avg-latency=3D24.571 (std-dev=3D93.297, mean-ad=3D4= .904, median-ad=3D1.510, siqr=3D1.063, cv=3D3.797, std-error=3D0.060, 99.0%= ci=3D[24.417, 24.725]) sockperf: # dropped messages =3D 0; # duplicated messages =3D 0; # out-of-o= rder messages =3D 0 sockperf: Summary: Latency is 24.571 usec sockperf: Total 2429473 observations; each percentile contains 24294.73 obs= ervations sockperf: ---> observation =3D 103294.331 sockperf: ---> percentile 99.999 =3D 45.633 sockperf: ---> percentile 99.990 =3D 37.013 sockperf: ---> percentile 99.900 =3D 35.910 sockperf: ---> percentile 99.000 =3D 33.390 sockperf: ---> percentile 90.000 =3D 28.626 sockperf: ---> percentile 75.000 =3D 27.741 sockperf: ---> percentile 50.000 =3D 26.743 sockperf: ---> percentile 25.000 =3D 25.614 sockperf: ---> observation =3D 12.220 After: [root@dell-per640-07 net]# sockperf ping-pong -i 10.9.9.1 --tcp -m 1000 --m= ps=3Dmax -t 120 sockperf: =3D=3D version #3.10-no.git =3D=3D sockperf[CLIENT] send on:sockperf: using recvfrom() to block on socket(s) [ 0] IP =3D 10.9.9.1 PORT =3D 11111 # TCP sockperf: Warmup stage (sending a few dummy messages)... sockperf: Starting test... sockperf: Test end (interrupted by timer) sockperf: Test ended sockperf: [Total Run] RunTime=3D119.999 sec; Warm up time=3D400 msec; SentM= essages=3D2400055; ReceivedMessages=3D2400054 sockperf: =3D=3D=3D=3D=3D=3D=3D=3D=3D Printing statistics for Server No: 0 sockperf: [Valid Duration] RunTime=3D119.549 sec; SentMessages=3D2391186; R= eceivedMessages=3D2391186 sockperf: =3D=3D=3D=3D> avg-latency=3D24.965 (std-dev=3D5.934, mean-ad=3D4.= 642, median-ad=3D1.485, siqr=3D1.067, cv=3D0.238, std-error=3D0.004, 99.0% = ci=3D[24.955, 24.975]) sockperf: # dropped messages =3D 0; # duplicated messages =3D 0; # out-of-o= rder messages =3D 0 sockperf: Summary: Latency is 24.965 usec sockperf: Total 2391186 observations; each percentile contains 23911.86 obs= ervations sockperf: ---> observation =3D 195.841 sockperf: ---> percentile 99.999 =3D 45.026 sockperf: ---> percentile 99.990 =3D 39.009 sockperf: ---> percentile 99.900 =3D 35.922 sockperf: ---> percentile 99.000 =3D 33.482 sockperf: ---> percentile 90.000 =3D 28.902 sockperf: ---> percentile 75.000 =3D 27.821 sockperf: ---> percentile 50.000 =3D 26.860 sockperf: ---> percentile 25.000 =3D 25.685 sockperf: ---> observation =3D 12.277 Fixes: 0bcd952feec7 ("ethernet/intel: consolidate NAPI and NAPI exit") Reported-by: Hugo Ferreira Signed-off-by: Ivan Vecera Reviewed-by: Michal Schmidt --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_main.c | 6 +++ .../net/ethernet/intel/i40e/i40e_register.h | 2 + drivers/net/ethernet/intel/i40e/i40e_txrx.c | 46 ++++++++++++++----- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 1 + 5 files changed, 45 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/= intel/i40e/i40e.h index ba24f3fa92c3..2fbabcdb5bb5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -955,6 +955,7 @@ struct i40e_q_vector { struct rcu_head rcu; /* to avoid race with update stats on free */ char name[I40E_INT_NAME_STR_LEN]; bool arm_wb_state; + bool in_busy_poll; int irq_num; /* IRQ assigned to this q_vector */ } ____cacheline_internodealigned_in_smp; =20 diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethe= rnet/intel/i40e/i40e_main.c index f86578857e8a..6576a0081093 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3911,6 +3911,12 @@ static void i40e_vsi_configure_msix(struct i40e_vsi = *vsi) q_vector->tx.target_itr >> 1); q_vector->tx.current_itr =3D q_vector->tx.target_itr; =20 + /* Set ITR for software interrupts triggered after exiting + * busy-loop polling. + */ + wr32(hw, I40E_PFINT_ITRN(I40E_SW_ITR, vector - 1), + I40E_ITR_20K); + wr32(hw, I40E_PFINT_RATEN(vector - 1), i40e_intrl_usec_to_reg(vsi->int_rate_limit)); =20 diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/= ethernet/intel/i40e/i40e_register.h index 14ab642cafdb..baa6bb68bcf8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_register.h +++ b/drivers/net/ethernet/intel/i40e/i40e_register.h @@ -335,6 +335,8 @@ #define I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT 5 #define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT 24 #define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_PFINT= _DYN_CTLN_SW_ITR_INDX_ENA_SHIFT) +#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT 25 +#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN= _CTLN_SW_ITR_INDX_SHIFT) #define I40E_PFINT_ICR0 0x00038780 /* Reset: CORER */ #define I40E_PFINT_ICR0_INTEVENT_SHIFT 0 #define I40E_PFINT_ICR0_INTEVENT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_INTEV= ENT_SHIFT) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethe= rnet/intel/i40e/i40e_txrx.c index 0d7177083708..356c3140adf3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2658,8 +2658,22 @@ static inline u32 i40e_buildreg_itr(const int type, = u16 itr) return val; } =20 -/* a small macro to shorten up some long lines */ -#define INTREG I40E_PFINT_DYN_CTLN +static inline u32 i40e_buildreg_swint(int type) +{ + u32 val; + + /* 1. Enable the interrupt + * 2. Do not modify any ITR interval + * 3. Trigger a SW interrupt specified by type + */ + val =3D I40E_PFINT_DYN_CTLN_INTENA_MASK | + I40E_PFINT_DYN_CTLN_ITR_INDX_MASK | /* set noitr */ + I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK | + I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK | + FIELD_PREP(I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK, type); + + return val; +} =20 /* The act of updating the ITR will cause it to immediately trigger. In or= der * to prevent this from throwing off adaptive update statistics we defer t= he @@ -2702,8 +2716,8 @@ static inline void i40e_update_enable_itr(struct i40e= _vsi *vsi, */ if (q_vector->rx.target_itr < q_vector->rx.current_itr) { /* Rx ITR needs to be reduced, this is highest priority */ - intval =3D i40e_buildreg_itr(I40E_RX_ITR, - q_vector->rx.target_itr); + wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, q_vector->reg_idx), + q_vector->rx.target_itr >> 1); q_vector->rx.current_itr =3D q_vector->rx.target_itr; q_vector->itr_countdown =3D ITR_COUNTDOWN_START; } else if ((q_vector->tx.target_itr < q_vector->tx.current_itr) || @@ -2712,25 +2726,33 @@ static inline void i40e_update_enable_itr(struct i4= 0e_vsi *vsi, /* Tx ITR needs to be reduced, this is second priority * Tx ITR needs to be increased more than Rx, fourth priority */ - intval =3D i40e_buildreg_itr(I40E_TX_ITR, - q_vector->tx.target_itr); + wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, q_vector->reg_idx), + q_vector->tx.target_itr >> 1); q_vector->tx.current_itr =3D q_vector->tx.target_itr; q_vector->itr_countdown =3D ITR_COUNTDOWN_START; } else if (q_vector->rx.current_itr !=3D q_vector->rx.target_itr) { /* Rx ITR needs to be increased, third priority */ - intval =3D i40e_buildreg_itr(I40E_RX_ITR, - q_vector->rx.target_itr); + wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, q_vector->reg_idx), + q_vector->rx.target_itr >> 1); q_vector->rx.current_itr =3D q_vector->rx.target_itr; q_vector->itr_countdown =3D ITR_COUNTDOWN_START; } else { /* No ITR update, lowest priority */ - intval =3D i40e_buildreg_itr(I40E_ITR_NONE, 0); if (q_vector->itr_countdown) q_vector->itr_countdown--; } =20 - if (!test_bit(__I40E_VSI_DOWN, vsi->state)) - wr32(hw, INTREG(q_vector->reg_idx), intval); + /* Do not enable interrupt if VSI is down */ + if (test_bit(__I40E_VSI_DOWN, vsi->state)) + return; + + if (!q_vector->in_busy_poll) { + intval =3D i40e_buildreg_itr(I40E_ITR_NONE, 0); + } else { + q_vector->in_busy_poll =3D false; + intval =3D i40e_buildreg_swint(I40E_SW_ITR); + } + wr32(hw, I40E_PFINT_DYN_CTLN(q_vector->reg_idx), intval); } =20 /** @@ -2845,6 +2867,8 @@ int i40e_napi_poll(struct napi_struct *napi, int budg= et) */ if (likely(napi_complete_done(napi, work_done))) i40e_update_enable_itr(vsi, q_vector); + else + q_vector->in_busy_poll =3D true; =20 return min(work_done, budget - 1); } diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethe= rnet/intel/i40e/i40e_txrx.h index abf15067eb5d..2cdc7de6301c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -68,6 +68,7 @@ enum i40e_dyn_idx { /* these are indexes into ITRN registers */ #define I40E_RX_ITR I40E_IDX_ITR0 #define I40E_TX_ITR I40E_IDX_ITR1 +#define I40E_SW_ITR I40E_IDX_ITR2 =20 /* Supported RSS offloads */ #define I40E_DEFAULT_RSS_HENA ( \ --=20 2.43.0