diff mbox series

[v1,net-next,6/6] net: ena: Add a field for no interrupt moderation update action

Message ID 20240506070453.17054-7-darinzon@amazon.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series ENA driver changes May 2024 | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 926 this patch: 926
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 3 maintainers not CCed: pabeni@redhat.com edumazet@google.com ahmed.zaki@intel.com
netdev/build_clang success Errors and warnings before: 937 this patch: 937
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 937 this patch: 937
netdev/checkpatch warning WARNING: line length of 83 exceeds 80 columns WARNING: line length of 97 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-05-08--00-00 (tests: 1002)

Commit Message

Arinzon, David May 6, 2024, 7:04 a.m. UTC
From: David Arinzon <darinzon@amazon.com>

Changes in the interrupt moderation values for TX/RX are infrequent
from host side. When asking to unmask interrupts, the driver always
provides the requested interrupt moderation values, regardless of
whether they've changed or not.

A new mechanism has been developed in new devices, which allows
selectively updating the relevant HW components based on whether
interrupt moderation values have changed from the previous request
or not (and by that, saving the processing on the device side).

When a change in the interrupt moderation value is made (either by
DIM or through an ethtool command), a field is updated to reflect
this change. When asking to unmask interrupts, the driver checks
the above mentioned field to see if any of the interrupt moderation
values (TX or RX) for the particular queue whose interrupts
are now being unmasked has changed, and updates the device accordingly.
The mentioned field is being reset (set to false) during the
procedure which triggers the interrupt unmask.

Signed-off-by: David Arinzon <darinzon@amazon.com>
---
 drivers/net/ethernet/amazon/ena/ena_com.h     |  9 +++++-
 .../net/ethernet/amazon/ena/ena_eth_io_defs.h |  5 ++-
 drivers/net/ethernet/amazon/ena/ena_ethtool.c | 14 +++++---
 drivers/net/ethernet/amazon/ena/ena_netdev.c  | 32 ++++++++++++++-----
 drivers/net/ethernet/amazon/ena/ena_netdev.h  |  9 ++++--
 5 files changed, 53 insertions(+), 16 deletions(-)

Comments

Jakub Kicinski May 8, 2024, 2:31 a.m. UTC | #1
On Mon, 6 May 2024 07:04:53 +0000 darinzon@amazon.com wrote:
> +	for (i = 0; i < adapter->num_io_queues; i++) {
> +		adapter->rx_ring[i].interrupt_interval_changed =

Shouldn't this be |= ?

> +			adapter->rx_ring[i].interrupt_interval != val;
> +		adapter->rx_ring[i].interrupt_interval = val;
> +	}
Arinzon, David May 8, 2024, 5:55 a.m. UTC | #2
> On Mon, 6 May 2024 07:04:53 +0000 darinzon@amazon.com wrote:
> > +     for (i = 0; i < adapter->num_io_queues; i++) {
> > +             adapter->rx_ring[i].interrupt_interval_changed =
> 
> Shouldn't this be |= ?
> 

Hi Jakub,

Thank you for reviewing the patch.

This is a true/false indicator, it doesn't require history/previous value to be considered.
Therefore, not sure I see the how |= can help us in the logic here.
The flag is set here to true if during the interrupt moderation update, which is, in this flow,
triggered by an ethtool operation, the moderation value has changed from the currently
configurated one.

> > +                     adapter->rx_ring[i].interrupt_interval != val;
> > +             adapter->rx_ring[i].interrupt_interval = val;
> > +     }
Jakub Kicinski May 8, 2024, 3:33 p.m. UTC | #3
On Wed, 8 May 2024 05:55:50 +0000 Arinzon, David wrote:
> This is a true/false indicator, it doesn't require history/previous value to be considered.
> Therefore, not sure I see the how |= can help us in the logic here.
> The flag is set here to true if during the interrupt moderation update, which is, in this flow,
> triggered by an ethtool operation, the moderation value has changed from the currently
> configurated one.

I couldn't locate an immediate application of the new value in 
the ethtool flow. So the question is whether the user can call
update back to back, with the same settings. First time flag
would be set and second time cleared.

Also the whole thing appears to be devoid of locking or any
consideration of concurrency.
Arinzon, David May 9, 2024, 7:25 a.m. UTC | #4
> > This is a true/false indicator, it doesn't require history/previous value to be considered.
> > Therefore, not sure I see the how |= can help us in the logic here.
> > The flag is set here to true if during the interrupt moderation
> > update, which is, in this flow, triggered by an ethtool operation, the
> > moderation value has changed from the currently configurated one.
> 
> I couldn't locate an immediate application of the new value in the ethtool
> flow. So the question is whether the user can call update back to back, with
> the same settings. First time flag would be set and second time cleared.
> 
> Also the whole thing appears to be devoid of locking or any consideration of
> concurrency.

Hi Jakub,

I agree with your points, thank you for identifying them.
Will send a revised version of the logic in v2.
diff mbox series

Patch

diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h
index 924f03f5..adce2d7f 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.h
+++ b/drivers/net/ethernet/amazon/ena/ena_com.h
@@ -980,13 +980,16 @@  static inline bool ena_com_get_cap(struct ena_com_dev *ena_dev,
  * @rx_delay_interval: Rx interval in usecs
  * @tx_delay_interval: Tx interval in usecs
  * @unmask: unmask enable/disable
+ * @no_moderation_update: 0 - Indicates that any of the TX/RX intervals was
+ *                        updated, 1 - otherwise
  *
  * Prepare interrupt update register with the supplied parameters.
  */
 static inline void ena_com_update_intr_reg(struct ena_eth_io_intr_reg *intr_reg,
 					   u32 rx_delay_interval,
 					   u32 tx_delay_interval,
-					   bool unmask)
+					   bool unmask,
+					   bool no_moderation_update)
 {
 	intr_reg->intr_control = 0;
 	intr_reg->intr_control |= rx_delay_interval &
@@ -998,6 +1001,10 @@  static inline void ena_com_update_intr_reg(struct ena_eth_io_intr_reg *intr_reg,
 
 	if (unmask)
 		intr_reg->intr_control |= ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK;
+
+	intr_reg->intr_control |=
+		(((u32)no_moderation_update) << ENA_ETH_IO_INTR_REG_NO_MODERATION_UPDATE_SHIFT) &
+			ENA_ETH_IO_INTR_REG_NO_MODERATION_UPDATE_MASK;
 }
 
 static inline u8 *ena_com_get_next_bounce_buffer(struct ena_com_io_bounce_buffer_control *bounce_buf_ctrl)
diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h b/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h
index 332ac0d2..a4d6d0ee 100644
--- a/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h
+++ b/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h
@@ -261,7 +261,8 @@  struct ena_eth_io_intr_reg {
 	/* 14:0 : rx_intr_delay
 	 * 29:15 : tx_intr_delay
 	 * 30 : intr_unmask
-	 * 31 : reserved
+	 * 31 : no_moderation_update - 0 - moderation
+	 *    updated, 1 - moderation not updated
 	 */
 	u32 intr_control;
 };
@@ -381,6 +382,8 @@  struct ena_eth_io_numa_node_cfg_reg {
 #define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_MASK              GENMASK(29, 15)
 #define ENA_ETH_IO_INTR_REG_INTR_UNMASK_SHIFT               30
 #define ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK                BIT(30)
+#define ENA_ETH_IO_INTR_REG_NO_MODERATION_UPDATE_SHIFT      31
+#define ENA_ETH_IO_INTR_REG_NO_MODERATION_UPDATE_MASK       BIT(31)
 
 /* numa_node_cfg_reg */
 #define ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK              GENMASK(7, 0)
diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c
index b24cc3f0..d7a343ce 100644
--- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c
+++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c
@@ -390,8 +390,11 @@  static void ena_update_tx_rings_nonadaptive_intr_moderation(struct ena_adapter *
 
 	val = ena_com_get_nonadaptive_moderation_interval_tx(adapter->ena_dev);
 
-	for (i = 0; i < adapter->num_io_queues; i++)
-		adapter->tx_ring[i].smoothed_interval = val;
+	for (i = 0; i < adapter->num_io_queues; i++) {
+		adapter->tx_ring[i].interrupt_interval_changed =
+			adapter->tx_ring[i].interrupt_interval != val;
+		adapter->tx_ring[i].interrupt_interval = val;
+	}
 }
 
 static void ena_update_rx_rings_nonadaptive_intr_moderation(struct ena_adapter *adapter)
@@ -401,8 +404,11 @@  static void ena_update_rx_rings_nonadaptive_intr_moderation(struct ena_adapter *
 
 	val = ena_com_get_nonadaptive_moderation_interval_rx(adapter->ena_dev);
 
-	for (i = 0; i < adapter->num_io_queues; i++)
-		adapter->rx_ring[i].smoothed_interval = val;
+	for (i = 0; i < adapter->num_io_queues; i++) {
+		adapter->rx_ring[i].interrupt_interval_changed =
+			adapter->rx_ring[i].interrupt_interval != val;
+		adapter->rx_ring[i].interrupt_interval = val;
+	}
 }
 
 static int ena_set_coalesce(struct net_device *net_dev,
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index 53f1000f..d5bac233 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -224,8 +224,10 @@  void ena_init_io_rings(struct ena_adapter *adapter,
 		txr->tx_max_header_size = ena_dev->tx_max_header_size;
 		txr->tx_mem_queue_type = ena_dev->tx_mem_queue_type;
 		txr->sgl_size = adapter->max_tx_sgl_size;
-		txr->smoothed_interval =
+		txr->interrupt_interval =
 			ena_com_get_nonadaptive_moderation_interval_tx(ena_dev);
+		/* Initial value, mark as true */
+		txr->interrupt_interval_changed = true;
 		txr->disable_meta_caching = adapter->disable_meta_caching;
 		spin_lock_init(&txr->xdp_tx_lock);
 
@@ -238,8 +240,10 @@  void ena_init_io_rings(struct ena_adapter *adapter,
 			rxr->ring_size = adapter->requested_rx_ring_size;
 			rxr->rx_copybreak = adapter->rx_copybreak;
 			rxr->sgl_size = adapter->max_rx_sgl_size;
-			rxr->smoothed_interval =
+			rxr->interrupt_interval =
 				ena_com_get_nonadaptive_moderation_interval_rx(ena_dev);
+			/* Initial value, mark as true */
+			rxr->interrupt_interval_changed = true;
 			rxr->empty_rx_queue = 0;
 			rxr->rx_headroom = NET_SKB_PAD;
 			adapter->ena_napi[i].dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
@@ -1364,7 +1368,10 @@  static void ena_dim_work(struct work_struct *w)
 		net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
 	struct ena_napi *ena_napi = container_of(dim, struct ena_napi, dim);
 
-	ena_napi->rx_ring->smoothed_interval = cur_moder.usec;
+	ena_napi->rx_ring->interrupt_interval = cur_moder.usec;
+	/* DIM will schedule the work in case there was a change in the profile. */
+	ena_napi->rx_ring->interrupt_interval_changed = true;
+
 	dim->state = DIM_START_MEASURE;
 }
 
@@ -1391,24 +1398,33 @@  static void ena_adjust_adaptive_rx_intr_moderation(struct ena_napi *ena_napi)
 void ena_unmask_interrupt(struct ena_ring *tx_ring,
 			  struct ena_ring *rx_ring)
 {
-	u32 rx_interval = tx_ring->smoothed_interval;
+	u32 rx_interval = tx_ring->interrupt_interval;
 	struct ena_eth_io_intr_reg intr_reg;
+	bool no_moderation_update = true;
 
 	/* Rx ring can be NULL when for XDP tx queues which don't have an
 	 * accompanying rx_ring pair.
 	 */
-	if (rx_ring)
+	if (rx_ring) {
 		rx_interval = ena_com_get_adaptive_moderation_enabled(rx_ring->ena_dev) ?
-			rx_ring->smoothed_interval :
+			rx_ring->interrupt_interval :
 			ena_com_get_nonadaptive_moderation_interval_rx(rx_ring->ena_dev);
 
+		no_moderation_update &= !rx_ring->interrupt_interval_changed;
+		rx_ring->interrupt_interval_changed = false;
+	}
+
+	no_moderation_update &= !tx_ring->interrupt_interval_changed;
+	tx_ring->interrupt_interval_changed = false;
+
 	/* Update intr register: rx intr delay,
 	 * tx intr delay and interrupt unmask
 	 */
 	ena_com_update_intr_reg(&intr_reg,
 				rx_interval,
-				tx_ring->smoothed_interval,
-				true);
+				tx_ring->interrupt_interval,
+				true,
+				no_moderation_update);
 
 	ena_increase_stat(&tx_ring->tx_stats.unmask_interrupt, 1,
 			  &tx_ring->syncp);
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h
index d5950974..b5a501eb 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.h
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h
@@ -267,8 +267,13 @@  struct ena_ring {
 	enum ena_admin_placement_policy_type tx_mem_queue_type;
 
 	struct ena_com_rx_buf_info ena_bufs[ENA_PKT_MAX_BUFS];
-	u32  smoothed_interval;
-	u32  per_napi_packets;
+	u32 interrupt_interval;
+	/* Indicates whether interrupt interval has changed since previous set.
+	 * This flag will be kept up, until cleared by the routine which updates
+	 * the device with the modified interrupt interval value.
+	 */
+	bool interrupt_interval_changed;
+	u32 per_napi_packets;
 	u16 non_empty_napi_events;
 	struct u64_stats_sync syncp;
 	union {