Linux-HyperV List
 help / color / mirror / Atom feed
* Re: [PATCH v4 09/10] drm/damage-helper: Rename state parameters in damage helpers
From: Javier Martinez Canillas @ 2026-06-01 10:29 UTC (permalink / raw)
  To: Thomas Zimmermann, mripard, maarten.lankhorst, airlied, airlied,
	simona, admin, gargaditya08, paul, jani.nikula, mhklinux,
	zack.rusin, bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann
In-Reply-To: <20260530185716.65688-10-tzimmermann@suse.de>

Thomas Zimmermann <tzimmermann@suse.de> writes:

> Rename some of the state parameters of the damage-helper functions to
> align them with each other and other helpers. No functional changes.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Acked-by: Zack Rusin <zack.rusin@broadcom.com>
> ---

Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>

-- 
Best regards,

Javier Martinez Canillas
Core Platforms
Red Hat


^ permalink raw reply

* Re: [PATCH v4 08/10] drm/damage-helper: Remove old state from drm_atomic_helper_damage_merged()
From: Javier Martinez Canillas @ 2026-06-01 10:29 UTC (permalink / raw)
  To: Thomas Zimmermann, mripard, maarten.lankhorst, airlied, airlied,
	simona, admin, gargaditya08, paul, jani.nikula, mhklinux,
	zack.rusin, bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann
In-Reply-To: <20260530185716.65688-9-tzimmermann@suse.de>

Thomas Zimmermann <tzimmermann@suse.de> writes:

> Nothing in drm_atomic_helper_damage_merged() requires the old
> plane state. Remove the parameter and mass-convert callers.
>
> Most callers now no longer require the old plane state in their plane's
> atomic_update helper. Remove it as well.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Acked-by: Zack Rusin <zack.rusin@broadcom.com>
> ---

Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>

-- 
Best regards,

Javier Martinez Canillas
Core Platforms
Red Hat


^ permalink raw reply

* Re: [PATCH v4 07/10] drm/damage-helper: Remove old state from drm_atomic_helper_damage_iter_init()
From: Javier Martinez Canillas @ 2026-06-01 10:28 UTC (permalink / raw)
  To: Thomas Zimmermann, mripard, maarten.lankhorst, airlied, airlied,
	simona, admin, gargaditya08, paul, jani.nikula, mhklinux,
	zack.rusin, bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann
In-Reply-To: <20260530185716.65688-8-tzimmermann@suse.de>

Thomas Zimmermann <tzimmermann@suse.de> writes:

> Nothing in drm_atomic_helper_damage_iter_init() requires the old
> plane state. Remove the parameter and mass-convert callers.
>
> Most callers now no longer require the old plane state in their plane's
> atomic_update helper. Remove it as well.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Acked-by: Zack Rusin <zack.rusin@broadcom.com>
> ---

Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>

-- 
Best regards,

Javier Martinez Canillas
Core Platforms
Red Hat


^ permalink raw reply

* [PATCH net v3] net: mana: Optimize irq affinity for low vcpu configs
From: Shradha Gupta @ 2026-06-01 10:27 UTC (permalink / raw)
  To: Dexuan Cui, Wei Liu, Haiyang Zhang, K. Y. Srinivasan, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Konstantin Taranov, Simon Horman, Erni Sri Satya Vennela,
	Dipayaan Roy, Shiraz Saleem, Michael Kelley, Long Li, Yury Norov
  Cc: Shradha Gupta, linux-hyperv, linux-kernel, netdev, Paul Rosswurm,
	Shradha Gupta, Saurabh Singh Sengar, stable

In mana driver, the number of IRQs allocated is capped by the
min(num_cpu + 1, queue count). In cases, where the IRQ count is greater
than the vcpu count, we want to utilize all the vCPUs, irrespective of
their NUMA/core bindings.

This is important, especially in the envs where number of vCPUs are so
few that the softIRQ handling overhead on two IRQs on the same vCPU is
much more than their overheads if they were spread across sibling vCPUs.

This behaviour is more evident with dynamic IRQ allocation. Since MANA
IRQs are assigned at a later stage compared to static allocation, other
device IRQs may already be affinitized to the vCPUs. As a result, IRQ
weights become imbalanced, causing multiple MANA IRQs to land on the
same vCPU, while some vCPUs have none.

In such cases when many parallel TCP connections are tested, the
throughput drops significantly.

Test envs:
=======================================================
Case 1: without this patch
=======================================================
4 vcpu(2 cores), 5 MANA IRQs (1 HWC + 4 Queue)

	TYPE		effective vCPU aff
=======================================================
IRQ0:	HWC		0
IRQ1:	mana_q1		0
IRQ2:	mana_q2		2
IRQ3:	mana_q3		0
IRQ4:	mana_q4		3

%soft on each vCPU(mpstat -P ALL 1) on receiver
vCPU		0	1	2	3
=======================================================
pass 1:		38.85	0.03	24.89	24.65
pass 2:		39.15	0.03	24.57	25.28
pass 3:		40.36	0.03	23.20	23.17

=======================================================
Case 2: with this patch
=======================================================
4 vcpu(2 cores), 5 MANA IRQs (1 HWC + 4 Queue)

        TYPE            effective vCPU aff
=======================================================
IRQ0:   HWC             0
IRQ1:   mana_q1         0
IRQ2:   mana_q2         1
IRQ3:   mana_q3         2
IRQ4:   mana_q4         3

%soft on each vCPU(mpstat -P ALL 1) on receiver
vCPU            0       1       2       3
=======================================================
pass 1:         15.42	15.85	14.99	14.51
pass 2:         15.53	15.94	15.81	15.93
pass 3:         16.41	16.35	16.40	16.36

=======================================================
Throughput Impact(in Gbps, same env)
=======================================================
TCP conn	with patch	w/o patch
20480		15.65		7.73
10240		15.63		8.93
8192		15.64		9.69
6144		15.64		13.16
4096		15.69		15.75
2048		15.69		15.83
1024		15.71		15.28

Fixes: 755391121038 ("net: mana: Allocate MSI-X vectors dynamically")
Cc: stable@vger.kernel.org
Co-developed-by: Erni Sri Satya Vennela <ernis@linux.microsoft.com>
Signed-off-by: Erni Sri Satya Vennela <ernis@linux.microsoft.com>
Signed-off-by: Shradha Gupta <shradhagupta@linux.microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: Simon Horman <horms@kernel.org>
---
Changes in v3
 * Optimize the comments in mana_gd_setup_dyn_irqs()
 * add more details in the dev_dbg for extra IRQs 
---
Changes in v2
 * Removed the unused skip_first_cpu variable
 * fixed exit condition in irq_setup_linear() with len == 0
 * changed return type of irq_setup_linear() as it will always be 0
 * removed the unnecessary rcu_read_lock() in irq_setup_linear()
 * added appropriate comments to indicate expected behaviour when
   IRQs are more than or equal to num_online_cpus()
---
 .../net/ethernet/microsoft/mana/gdma_main.c   | 60 ++++++++++++++++---
 1 file changed, 53 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index 712a0881d720..00a28b3ca0a6 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -197,6 +197,8 @@ static int mana_gd_query_max_resources(struct pci_dev *pdev)
 	} else {
 		/* If dynamic allocation is enabled we have already allocated
 		 * hwc msi
+		 * Also, we make sure in this case the following is always true
+		 * (num_msix_usable - 1 HWC) <= num_online_cpus()
 		 */
 		gc->num_msix_usable = min(resp.max_msix, num_online_cpus() + 1);
 	}
@@ -1717,11 +1719,24 @@ static int irq_setup(unsigned int *irqs, unsigned int len, int node,
 	return 0;
 }
 
+/* should be called with cpus_read_lock() held */
+static void irq_setup_linear(unsigned int *irqs, unsigned int len)
+{
+	int cpu;
+
+	for_each_online_cpu(cpu) {
+		if (len == 0)
+			break;
+
+		irq_set_affinity_and_hint(*irqs++, cpumask_of(cpu));
+		len--;
+	}
+}
+
 static int mana_gd_setup_dyn_irqs(struct pci_dev *pdev, int nvec)
 {
 	struct gdma_context *gc = pci_get_drvdata(pdev);
 	struct gdma_irq_context *gic;
-	bool skip_first_cpu = false;
 	int *irqs, irq, err, i;
 
 	irqs = kmalloc_objs(int, nvec);
@@ -1729,6 +1744,8 @@ static int mana_gd_setup_dyn_irqs(struct pci_dev *pdev, int nvec)
 		return -ENOMEM;
 
 	/*
+	 * In this function, num_msix_usable = HWC IRQ + Queue IRQ.
+	 * nvec is only Queue IRQ (HWC already setup).
 	 * While processing the next pci irq vector, we start with index 1,
 	 * as IRQ vector at index 0 is already processed for HWC.
 	 * However, the population of irqs array starts with index 0, to be
@@ -1767,13 +1784,42 @@ static int mana_gd_setup_dyn_irqs(struct pci_dev *pdev, int nvec)
 	 * first CPU sibling group since they are already affinitized to HWC IRQ
 	 */
 	cpus_read_lock();
-	if (gc->num_msix_usable <= num_online_cpus())
-		skip_first_cpu = true;
+	if (gc->num_msix_usable <= num_online_cpus()) {
+		err = irq_setup(irqs, nvec, gc->numa_node, true);
+		if (err) {
+			cpus_read_unlock();
+			goto free_irq;
+		}
+	} else {
+		/*
+		 * When num_msix_usable are more than num_online_cpus, our
+		 * queue IRQs should be equal to num of online vCPUs.
+		 * We try to make sure queue IRQs spread across all vCPUs.
+		 * In such a case NUMA or CPU core affinity does not matter.
+		 * Note: in this case the total mana IRQ should always be
+		 * num_online_cpus + 1. The first HWC IRQ is already handled
+		 * in HWC setup calls
+		 * However, if CPUs went offline since num_msix_usable was
+		 * computed, queue IRQs will be more than num_online_cpus().
+		 * In such cases remaining extra IRQs will retain their default
+		 * affinity.
+		 */
+		int first_unassigned = num_online_cpus();
+		if (nvec > first_unassigned) {
+			char buf[32];
+
+			if (first_unassigned == nvec - 1)
+				snprintf(buf, sizeof(buf), "%d",
+					 first_unassigned);
+			else
+				snprintf(buf, sizeof(buf), "%d-%d",
+					 first_unassigned, nvec - 1);
+
+			dev_dbg(&pdev->dev,
+				"MANA IRQ indices #%s will retain the default CPU affinity\n", buf);
+		}
 
-	err = irq_setup(irqs, nvec, gc->numa_node, skip_first_cpu);
-	if (err) {
-		cpus_read_unlock();
-		goto free_irq;
+		irq_setup_linear(irqs, nvec);
 	}
 
 	cpus_read_unlock();

base-commit: 8415598365503ced2e3d019491b0a2756c85c494
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH v4 06/10] drm/damage-helper: Test src coord in drm_atomic_helper_check_plane_damage()
From: Javier Martinez Canillas @ 2026-06-01 10:27 UTC (permalink / raw)
  To: Thomas Zimmermann, mripard, maarten.lankhorst, airlied, airlied,
	simona, admin, gargaditya08, paul, jani.nikula, mhklinux,
	zack.rusin, bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann
In-Reply-To: <20260530185716.65688-7-tzimmermann@suse.de>

Thomas Zimmermann <tzimmermann@suse.de> writes:

> Planes require a full update if the source coordinates change across
> atomic commits. Evaluate this during the atomic-check and set the flag
> ignore_damage_clips in the plane state, if so. Remove the check from
> drm_atomic_helper_damage_iter_init().
>
> This will help with removing the old state from the atomic-commit phase
> and simplify atomic_update helpers a bit.
>
> Several unit tests check against the change of the src coordinate. Drop
> them as they do no longer serve a purpose. If the src coordinate changes
> across commits, atomic helpers will set the plane state's
> ignore_damage_clips flag, for which a separate unit test exists.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Acked-by: Zack Rusin <zack.rusin@broadcom.com>
> ---

Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>

-- 
Best regards,

Javier Martinez Canillas
Core Platforms
Red Hat


^ permalink raw reply

* Re: [PATCH v4 05/10] drm/atomic_helper: Do not evaluate plane damage before atomic_check
From: Javier Martinez Canillas @ 2026-06-01 10:22 UTC (permalink / raw)
  To: Thomas Zimmermann, mripard, maarten.lankhorst, airlied, airlied,
	simona, admin, gargaditya08, paul, jani.nikula, mhklinux,
	zack.rusin, bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann
In-Reply-To: <20260530185716.65688-6-tzimmermann@suse.de>

Thomas Zimmermann <tzimmermann@suse.de> writes:

> Remove the call to drm_atomic_helper_check_plane_damage() from before
> calling the atomic_check helpers. The call has no longer any purpose,
> as the actual evaluation happens after running atomic_check.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Acked-by: Zack Rusin <zack.rusin@broadcom.com>
> ---

Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>

-- 
Best regards,

Javier Martinez Canillas
Core Platforms
Red Hat


^ permalink raw reply

* Re: [PATCH v4 04/10] drm/appletbdrm: Allocate request/response buffers in begin_fb_access
From: Javier Martinez Canillas @ 2026-06-01 10:21 UTC (permalink / raw)
  To: Thomas Zimmermann, mripard, maarten.lankhorst, airlied, airlied,
	simona, admin, gargaditya08, paul, jani.nikula, mhklinux,
	zack.rusin, bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann
In-Reply-To: <20260530185716.65688-5-tzimmermann@suse.de>

Thomas Zimmermann <tzimmermann@suse.de> writes:

> In atomic_check, damage handling is not fully evaluated. Another
> atomic_check helper could trigger a full modeset and thus invalidate
> damage clips.
>
> Allocation of the request/response buffers in appletbdrm depends on
> correct damage information. Otherwise it might allocate incorrectly
> sized buffers. Allocate the buffers in the driver's begin_fb_access
> helper. It runs early during the commit when damage clipping has been
> fully evaluated.
>
> v2:
> - allocate before drm_gem_begin_shadow_fb_access() to avoid leak on error

Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>

-- 
Best regards,

Javier Martinez Canillas
Core Platforms
Red Hat


^ permalink raw reply

* Re: [PATCH v4 03/10] drm/ingenic: Remove calls to drm_atomic_helper_check_plane_damage()
From: Javier Martinez Canillas @ 2026-06-01 10:20 UTC (permalink / raw)
  To: Thomas Zimmermann, mripard, maarten.lankhorst, airlied, airlied,
	simona, admin, gargaditya08, paul, jani.nikula, mhklinux,
	zack.rusin, bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann
In-Reply-To: <20260530185716.65688-4-tzimmermann@suse.de>

Thomas Zimmermann <tzimmermann@suse.de> writes:

> Atomic helpers call drm_atomic_helper_check_plane_damage() after the
> atomic_check anyway. See atomic_helper_check_planes(). Remove the calls
> from the planes' atomic_check.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Acked-by: Zack Rusin <zack.rusin@broadcom.com>
> ---

Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>

-- 
Best regards,

Javier Martinez Canillas
Core Platforms
Red Hat


^ permalink raw reply

* Re: [PATCH v4 02/10] drm/atomic-helpers: Evaluate plane damage after atomic_check
From: Javier Martinez Canillas @ 2026-06-01 10:19 UTC (permalink / raw)
  To: Thomas Zimmermann, mripard, maarten.lankhorst, airlied, airlied,
	simona, admin, gargaditya08, paul, jani.nikula, mhklinux,
	zack.rusin, bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann
In-Reply-To: <20260530185716.65688-3-tzimmermann@suse.de>

Thomas Zimmermann <tzimmermann@suse.de> writes:

> Each plane's and CRTC's atomic_check might trigger a full modeset. As
> this affects the plane's damage handling, evaluate damage clips after
> running the atomic_check helpers.
>
> Examples can be found in a number of drivers, such as ast, gud, ingenic,
> mgag200 or vmwgfx, which all set mode_changed in the CRTC state to true.
> Ingenic even re-evaluates damage information in its plane's atomic_check.
> Doing this after the atomic_check helpers ran benefits all drivers.
>
> There's already a damage evaluation before the calls to atomic_check.
> With a few fixes to drivers, this can be removed.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Acked-by: Zack Rusin <zack.rusin@broadcom.com>
> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 51f39edc31ed..4c37299e8ccb 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1065,6 +1065,10 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
>  		}
>  	}
>  
> +	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
> +		drm_atomic_helper_check_plane_damage(state, new_plane_state);
> +	}
> +

I wonder if it's worth to mention this in the drm_atomic_helper_check_planes()
function kernel-doc comment. But regardless, the change makes sense to me:

Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>

-- 
Best regards,

Javier Martinez Canillas
Core Platforms
Red Hat


^ permalink raw reply

* Re: [PATCH v4 01/10] drm/damage-helper: Do not alter damage clips on modeset, but ignore them
From: Javier Martinez Canillas @ 2026-06-01 10:16 UTC (permalink / raw)
  To: Thomas Zimmermann, mripard, maarten.lankhorst, airlied, airlied,
	simona, admin, gargaditya08, paul, jani.nikula, mhklinux,
	zack.rusin, bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann, stable
In-Reply-To: <20260530185716.65688-2-tzimmermann@suse.de>

Thomas Zimmermann <tzimmermann@suse.de> writes:

Hello Thomas,

> User space supplies rectangles for damage clipping in a plane property.
> For full mode sets, drivers still require a full plane update. In this
> case, leave the information as-is and set the ignore_damage_clips flag
> instead. The damage iterator will later ignore any damage information.
>
> Also fixes a bug where ignore_damage_clips was not cleared across plane-
> state duplications.
>
> Leaving the damage information as-is might be helpful to drivers that
> benefit from this information even on full modesets (e.g., for cache
> management). It will also help with consolidating the damage-handling
> logic.
>
> Also add a new unit test that evaluates the ignore_damage_clips flag. It
> sets two damage clips plus the flag and tests if the reported damage
> covers the entire framebuffer.
>
> v4:
> - slightly reword the commit description
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Fixes: 35ed38d58257 ("drm: Allow drivers to indicate the damage helpers to ignore damage clips")
> Acked-by: Zack Rusin <zack.rusin@broadcom.com>
> Cc: dri-devel@lists.freedesktop.org
> Cc: <stable@vger.kernel.org> # v6.10+
> ---
>  drivers/gpu/drm/drm_atomic_state_helper.c     |  1 +
>  drivers/gpu/drm/drm_damage_helper.c           |  6 ++--
>  .../gpu/drm/tests/drm_damage_helper_test.c    | 28 +++++++++++++++++++
>  3 files changed, 31 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
> index cc70508d4fdb..84d5231ccac1 100644
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> @@ -359,6 +359,7 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
>  	state->fence = NULL;
>  	state->commit = NULL;
>  	state->fb_damage_clips = NULL;
> +	state->ignore_damage_clips = false;
>  	state->color_mgmt_changed = false;
>  }

I would split this as a separate patch since is the bug you are fixing for
commit 35ed38d58257 ("drm: Allow drivers to indicate the damage helpers to
ignore damage clips").

>  EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
> diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c
> index 74a7f4252ecf..945fac8dc27b 100644
> --- a/drivers/gpu/drm/drm_damage_helper.c
> +++ b/drivers/gpu/drm/drm_damage_helper.c
> @@ -78,10 +78,8 @@ void drm_atomic_helper_check_plane_damage(struct drm_atomic_commit *state,
>  		if (WARN_ON(!crtc_state))
>  			return;
>  
> -		if (drm_atomic_crtc_needs_modeset(crtc_state)) {
> -			drm_property_blob_put(plane_state->fb_damage_clips);
> -			plane_state->fb_damage_clips = NULL;
> -		}
> +		if (drm_atomic_crtc_needs_modeset(crtc_state))
> +			plane_state->ignore_damage_clips = true;
>  	}
>  }

This makes sense to me as well and I agree that re-using the flag for this
is better than making plane_state->fb_damage_clips == NULL the condition.

As mentioned though, I would make it a separate patch. Both changes look
good to me:

Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>

-- 
Best regards,

Javier Martinez Canillas
Core Platforms
Red Hat


^ permalink raw reply

* RE: [PATCH net-next] net: mana: Add Interrupt Moderation support
From: Jagielski, Jedrzej @ 2026-06-01  9:39 UTC (permalink / raw)
  To: Haiyang Zhang, linux-hyperv@vger.kernel.org,
	netdev@vger.kernel.org, K. Y. Srinivasan, Haiyang Zhang, Wei Liu,
	Cui, Dexuan, Long Li, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Konstantin Taranov, Simon Horman,
	Shradha Gupta, Erni Sri Satya Vennela, Dipayaan Roy, Aditya Garg,
	Kees Cook, Breno Leitao, linux-kernel@vger.kernel.org,
	linux-rdma@vger.kernel.org
  Cc: paulros@microsoft.com
In-Reply-To: <20260530194957.1690459-1-haiyangz@linux.microsoft.com>

From: Haiyang Zhang <haiyangz@linux.microsoft.com> 
Sent: Saturday, May 30, 2026 9:50 PM

>From: Haiyang Zhang <haiyangz@microsoft.com>
>
>Add Static and Dynamic Interrupt Moderation (DIM) support for
>Rx and Tx.
>Update queue creation procedure with new data struct with the related
>settings.
>Add functions to collect stat for DIM, and workers to update DIM data
>and settings.
>Update ethtool handler to get/set the moderation settings from a user.
>By default, adaptive-rx/tx (DIM) are enabled.
>
>Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
>---
> drivers/net/ethernet/microsoft/Kconfig        |   1 +
> .../net/ethernet/microsoft/mana/gdma_main.c   |  27 ++++
> drivers/net/ethernet/microsoft/mana/mana_en.c | 101 ++++++++++++++-
> .../ethernet/microsoft/mana/mana_ethtool.c    | 120 +++++++++++++++++-
> include/net/mana/gdma.h                       |  24 +++-
> include/net/mana/mana.h                       |  42 ++++++
> 6 files changed, 309 insertions(+), 6 deletions(-)
>
>diff --git a/drivers/net/ethernet/microsoft/Kconfig b/drivers/net/ethernet/microsoft/Kconfig
>index 3f36ee6a8ece..e9be18c92ca5 100644
>--- a/drivers/net/ethernet/microsoft/Kconfig
>+++ b/drivers/net/ethernet/microsoft/Kconfig
>@@ -21,6 +21,7 @@ config MICROSOFT_MANA
> 	depends on X86_64 || (ARM64 && !CPU_BIG_ENDIAN)
> 	depends on PCI_HYPERV
> 	select AUXILIARY_BUS
>+	select DIMLIB
> 	select PAGE_POOL
> 	select NET_SHAPER
> 	help
>diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
>index 712a0881d720..5aa0ea794a00 100644
>--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
>+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
>@@ -405,6 +405,7 @@ static int mana_gd_disable_queue(struct gdma_queue *queue)
> #define DOORBELL_OFFSET_RQ	0x400
> #define DOORBELL_OFFSET_CQ	0x800
> #define DOORBELL_OFFSET_EQ	0xFF8
>+#define DOORBELL_OFFSET_DIM	0x820
> 
> static void mana_gd_ring_doorbell(struct gdma_context *gc, u32 db_index,
> 				  enum gdma_queue_type q_type, u32 qid,
>@@ -445,6 +446,16 @@ static void mana_gd_ring_doorbell(struct gdma_context *gc, u32 db_index,
> 		addr += DOORBELL_OFFSET_SQ;
> 		break;
> 
>+	case GDMA_DIM:
>+		e.dim.id = qid;
>+		e.dim.mod_usec = tail_ptr;
>+		e.dim.mod_usec_vld = tail_ptr >> 15;
>+		e.dim.mod_comps = tail_ptr >> 16;

please use defines instead of magic

>+		e.dim.mod_comps_vld = num_req;
>+
>+		addr += DOORBELL_OFFSET_DIM;
>+		break;
>+
> 	default:
> 		WARN_ON(1);
> 		return;
>@@ -479,6 +490,22 @@ void mana_gd_ring_cq(struct gdma_queue *cq, u8 arm_bit)
> }
> EXPORT_SYMBOL_NS(mana_gd_ring_cq, "NET_MANA");
> 
>+void mana_gd_ring_dim(struct gdma_queue *cq, u32 mod_usec, bool mod_usec_vld,
>+		      u32 mod_comps, bool mod_comps_vld)
>+{
>+	struct gdma_context *gc = cq->gdma_dev->gdma_context;
>+	u32 dim_val;
>+
>+	/* Convert the DIM values to doorbell parameters */
>+	dim_val = (mod_usec & MANA_INTR_MODR_USEC_MAX) |
>+		  (((u32)mod_usec_vld & 1) << 15) |
>+		  ((mod_comps & MANA_INTR_MODR_COMP_MAX) << 16);

i believe FIELD_PREP if preferrable in such cases

>+
>+	mana_gd_ring_doorbell(gc, cq->gdma_dev->doorbell, GDMA_DIM, cq->id,
>+			      dim_val, (u8)mod_comps_vld & 1);
>+}
>+EXPORT_SYMBOL_NS(mana_gd_ring_dim, "NET_MANA");
>+
> #define MANA_SERVICE_PERIOD 10
> 
> static void mana_serv_rescan(struct pci_dev *pdev)
>diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
>index 82f1461a48e9..f1a16f8aca66 100644
>--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
>+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
>@@ -1551,6 +1551,9 @@ int mana_create_wq_obj(struct mana_port_context *apc,
> 
> 	mana_gd_init_req_hdr(&req.hdr, MANA_CREATE_WQ_OBJ,
> 			     sizeof(req), sizeof(resp));
>+
>+	req.hdr.req.msg_version = GDMA_MESSAGE_V3;
>+	req.hdr.resp.msg_version = GDMA_MESSAGE_V2;
> 	req.vport = vport;
> 	req.wq_type = wq_type;
> 	req.wq_gdma_region = wq_spec->gdma_region;
>@@ -1559,6 +1562,9 @@ int mana_create_wq_obj(struct mana_port_context *apc,
> 	req.cq_size = cq_spec->queue_size;
> 	req.cq_moderation_ctx_id = cq_spec->modr_ctx_id;
> 	req.cq_parent_qid = cq_spec->attached_eq;
>+	req.req_cq_moderation = cq_spec->req_cq_moderation;
>+	req.cq_moderation_comp = cq_spec->cq_moderation_comp;
>+	req.cq_moderation_usec = cq_spec->cq_moderation_usec;
> 
> 	err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
> 				sizeof(resp));
>@@ -2253,6 +2259,66 @@ static void mana_poll_rx_cq(struct mana_cq *cq)
> 		xdp_do_flush();
> }
> 
>+static void mana_rx_dim_work(struct work_struct *work)
>+{
>+	struct dim *dim = container_of(work, struct dim, work);
>+	struct mana_cq *cq = container_of(dim, struct mana_cq, dim);
>+	struct dim_cq_moder cur_moder =
>+		net_dim_get_rx_moderation(dim->mode, dim->profile_ix);

RCT; here and for following

>+
>+	cur_moder.usec = min_t(u16, cur_moder.usec, MANA_INTR_MODR_USEC_MAX);
>+	cur_moder.pkts = min_t(u16, cur_moder.pkts, MANA_INTR_MODR_COMP_MAX);
>+
>+	mana_gd_ring_dim(cq->gdma_cq, cur_moder.usec, true,
>+			 cur_moder.pkts, true);
>+
>+	dim->state = DIM_START_MEASURE;
>+}
>+
>+static void mana_tx_dim_work(struct work_struct *work)
>+{
>+	struct dim *dim = container_of(work, struct dim, work);
>+	struct mana_cq *cq = container_of(dim, struct mana_cq, dim);
>+	struct dim_cq_moder cur_moder =
>+		net_dim_get_tx_moderation(dim->mode, dim->profile_ix);
>+
>+	cur_moder.usec = min_t(u16, cur_moder.usec, MANA_INTR_MODR_USEC_MAX);
>+	cur_moder.pkts = min_t(u16, cur_moder.pkts, MANA_INTR_MODR_COMP_MAX);
>+
>+	mana_gd_ring_dim(cq->gdma_cq, cur_moder.usec, true,
>+			 cur_moder.pkts, true);
>+
>+	dim->state = DIM_START_MEASURE;
>+}
>+
>+static void mana_update_rx_dim(struct mana_cq *cq)
>+{
>+	struct mana_rxq *rxq = cq->rxq;
>+	struct mana_port_context *apc = netdev_priv(rxq->ndev);
>+	struct dim_sample dim_sample = {};
>+
>+	if (!apc->rx_dim_enabled)
>+		return;
>+
>+	dim_update_sample(READ_ONCE(cq->dim_event_ctr), rxq->stats.packets,
>+			  rxq->stats.bytes, &dim_sample);
>+	net_dim(&cq->dim, &dim_sample);
>+}
>+
>+static void mana_update_tx_dim(struct mana_cq *cq)
>+{
>+	struct mana_txq *txq = cq->txq;
>+	struct mana_port_context *apc = netdev_priv(txq->ndev);
>+	struct dim_sample dim_sample = {};
>+
>+	if (!apc->tx_dim_enabled)
>+		return;
>+
>+	dim_update_sample(READ_ONCE(cq->dim_event_ctr), txq->stats.packets,
>+			  txq->stats.bytes, &dim_sample);
>+	net_dim(&cq->dim, &dim_sample);
>+}
>+
> static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
> {
> 	struct mana_cq *cq = context;
>@@ -2271,7 +2337,13 @@ static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
> 	if (w < cq->budget) {
> 		mana_gd_ring_cq(gdma_queue, SET_ARM_BIT);
> 		cq->work_done_since_doorbell = 0;
>-		napi_complete_done(&cq->napi, w);
>+
>+		if (napi_complete_done(&cq->napi, w)) {
>+			if (cq->type == MANA_CQ_TYPE_RX)
>+				mana_update_rx_dim(cq);
>+			else
>+				mana_update_tx_dim(cq);
>+		}
> 	} else if (cq->work_done_since_doorbell >=
> 		   (cq->gdma_cq->queue_size / COMP_ENTRY_SIZE) * 4) {
> 		/* MANA hardware requires at least one doorbell ring every 8
>@@ -2303,6 +2375,7 @@ static void mana_schedule_napi(void *context, struct gdma_queue *gdma_queue)
> {
> 	struct mana_cq *cq = context;
> 
>+	WRITE_ONCE(cq->dim_event_ctr, cq->dim_event_ctr + 1);
> 	napi_schedule_irqoff(&cq->napi);
> }
> 
>@@ -2345,6 +2418,7 @@ static void mana_destroy_txq(struct mana_port_context *apc)
> 		if (apc->tx_qp[i]->txq.napi_initialized) {
> 			napi_synchronize(napi);
> 			napi_disable_locked(napi);
>+			cancel_work_sync(&apc->tx_qp[i]->tx_cq.dim.work);
> 			netif_napi_del_locked(napi);
> 			apc->tx_qp[i]->txq.napi_initialized = false;
> 		}
>@@ -2475,6 +2549,10 @@ static int mana_create_txq(struct mana_port_context *apc,
> 		cq_spec.queue_size = cq->gdma_cq->queue_size;
> 		cq_spec.modr_ctx_id = 0;
> 		cq_spec.attached_eq = cq->gdma_cq->cq.parent->id;
>+		cq_spec.req_cq_moderation = apc->tx_dim_enabled ||
>+			(apc->intr_modr_tx_usec && apc->intr_modr_tx_comp);
>+		cq_spec.cq_moderation_usec = apc->intr_modr_tx_usec;
>+		cq_spec.cq_moderation_comp = apc->intr_modr_tx_comp;
> 
> 		err = mana_create_wq_obj(apc, apc->port_handle, GDMA_SQ,
> 					 &wq_spec, &cq_spec,
>@@ -2509,6 +2587,9 @@ static int mana_create_txq(struct mana_port_context *apc,
> 		napi_enable_locked(&cq->napi);
> 		txq->napi_initialized = true;
> 
>+		INIT_WORK(&cq->dim.work, mana_tx_dim_work);
>+		cq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
>+
> 		mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT);
> 	}
> 
>@@ -2543,6 +2624,7 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
> 		napi_synchronize(napi);
> 
> 		napi_disable_locked(napi);
>+		cancel_work_sync(&rxq->rx_cq.dim.work);
> 		netif_napi_del_locked(napi);
> 	}
> 
>@@ -2780,6 +2862,10 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
> 	cq_spec.queue_size = cq->gdma_cq->queue_size;
> 	cq_spec.modr_ctx_id = 0;
> 	cq_spec.attached_eq = cq->gdma_cq->cq.parent->id;
>+	cq_spec.req_cq_moderation = apc->rx_dim_enabled ||
>+		(apc->intr_modr_rx_usec && apc->intr_modr_rx_comp);
>+	cq_spec.cq_moderation_usec = apc->intr_modr_rx_usec;
>+	cq_spec.cq_moderation_comp = apc->intr_modr_rx_comp;
> 
> 	err = mana_create_wq_obj(apc, apc->port_handle, GDMA_RQ,
> 				 &wq_spec, &cq_spec, &rxq->rxobj);
>@@ -2815,6 +2901,9 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
> 
> 	napi_enable_locked(&cq->napi);
> 
>+	INIT_WORK(&cq->dim.work, mana_rx_dim_work);
>+	cq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
>+
> 	mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT);
> out:
> 	if (!err)
>@@ -3432,6 +3521,16 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,
> 	apc->port_idx = port_idx;
> 	apc->cqe_coalescing_enable = 0;
> 
>+	/* Initialize interrupt moderation settings if supported by HW */
>+	if (gc->pf_cap_flags1 & GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION) {
>+		apc->intr_modr_rx_usec = MANA_INTR_MODR_USEC_DEF;
>+		apc->intr_modr_rx_comp = MANA_INTR_MODR_COMP_DEF;
>+		apc->intr_modr_tx_usec = MANA_INTR_MODR_USEC_DEF;
>+		apc->intr_modr_tx_comp = MANA_INTR_MODR_COMP_DEF;
>+		apc->rx_dim_enabled = MANA_ADAPTIVE_RX_DEF;
>+		apc->tx_dim_enabled = MANA_ADAPTIVE_TX_DEF;
>+	}
>+
> 	mutex_init(&apc->vport_mutex);
> 	apc->vport_use_count = 0;
> 
>diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
>index 04350973e19e..a90216eba794 100644
>--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
>+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
>@@ -419,6 +419,15 @@ static int mana_get_coalesce(struct net_device *ndev,
> 	    !kernel_coal->rx_cqe_nsecs)
> 		kernel_coal->rx_cqe_nsecs = MANA_RX_CQE_NSEC_DEF;
> 
>+	ec->rx_coalesce_usecs = apc->intr_modr_rx_usec;
>+	ec->rx_max_coalesced_frames = apc->intr_modr_rx_comp;
>+
>+	ec->tx_coalesce_usecs = apc->intr_modr_tx_usec;
>+	ec->tx_max_coalesced_frames = apc->intr_modr_tx_comp;
>+
>+	ec->use_adaptive_rx_coalesce = apc->rx_dim_enabled;
>+	ec->use_adaptive_tx_coalesce = apc->tx_dim_enabled;
>+
> 	return 0;
> }
> 
>@@ -429,8 +438,28 @@ static int mana_set_coalesce(struct net_device *ndev,
> {
> 	struct mana_port_context *apc = netdev_priv(ndev);
> 	u8 saved_cqe_coalescing_enable;
>+	u16 old_rx_usec, old_rx_comp;
>+	u16 old_tx_usec, old_tx_comp;
>+	bool old_rx_dim, old_tx_dim;

how about using some sort of struct instead of declaring a number
of params for bookkeeping? imho would be cleaner

>+	bool modr_changed = false;
>+	bool dim_changed = false;
>+	struct gdma_context *gc;
> 	int err;
> 
>+	gc = apc->ac->gdma_dev->gdma_context;
>+
>+	/* Both static and dynamic interrupt moderation (DIM) rely on the
>+	 * same HW capability advertised by the PF.
>+	 */
>+	if ((ec->use_adaptive_rx_coalesce || ec->use_adaptive_tx_coalesce ||
>+	     ec->rx_coalesce_usecs || ec->tx_coalesce_usecs ||
>+	     ec->rx_max_coalesced_frames || ec->tx_max_coalesced_frames) &&
>+	    !(gc->pf_cap_flags1 & GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION)) {
>+		NL_SET_ERR_MSG(extack,
>+			       "Interrupt Moderation is not supported by HW");
>+		return -EOPNOTSUPP;
>+	}
>+
> 	if (kernel_coal->rx_cqe_frames != 1 &&
> 	    kernel_coal->rx_cqe_frames != MANA_RXCOMP_OOB_NUM_PPI) {
> 		NL_SET_ERR_MSG_FMT(extack,
>@@ -440,6 +469,47 @@ static int mana_set_coalesce(struct net_device *ndev,
> 		return -EINVAL;
> 	}
> 
>+	if (ec->rx_coalesce_usecs > MANA_INTR_MODR_USEC_MAX ||
>+	    ec->tx_coalesce_usecs > MANA_INTR_MODR_USEC_MAX) {
>+		NL_SET_ERR_MSG_FMT(extack,
>+				   "coalesce usecs must be <= %u",
>+				   MANA_INTR_MODR_USEC_MAX);
>+		return -EINVAL;
>+	}
>+
>+	if (ec->rx_max_coalesced_frames > MANA_INTR_MODR_COMP_MAX ||
>+	    ec->tx_max_coalesced_frames > MANA_INTR_MODR_COMP_MAX) {
>+		NL_SET_ERR_MSG_FMT(extack,
>+				   "coalesce frames must be <= %u",
>+				   MANA_INTR_MODR_COMP_MAX);
>+		return -EINVAL;
>+	}
>+
>+	if (ec->rx_coalesce_usecs != apc->intr_modr_rx_usec ||
>+	    ec->rx_max_coalesced_frames != apc->intr_modr_rx_comp ||
>+	    ec->tx_coalesce_usecs != apc->intr_modr_tx_usec ||
>+	    ec->tx_max_coalesced_frames != apc->intr_modr_tx_comp)
>+		modr_changed = true;
>+
>+	old_rx_usec = apc->intr_modr_rx_usec;
>+	old_rx_comp = apc->intr_modr_rx_comp;
>+	old_tx_usec = apc->intr_modr_tx_usec;
>+	old_tx_comp = apc->intr_modr_tx_comp;
>+
>+	apc->intr_modr_rx_usec = ec->rx_coalesce_usecs;
>+	apc->intr_modr_rx_comp = ec->rx_max_coalesced_frames;
>+	apc->intr_modr_tx_usec = ec->tx_coalesce_usecs;
>+	apc->intr_modr_tx_comp = ec->tx_max_coalesced_frames;
>+
>+	if (!!ec->use_adaptive_rx_coalesce != apc->rx_dim_enabled ||
>+	    !!ec->use_adaptive_tx_coalesce != apc->tx_dim_enabled)
>+		dim_changed = true;
>+
>+	old_rx_dim = apc->rx_dim_enabled;
>+	old_tx_dim = apc->tx_dim_enabled;
>+	apc->rx_dim_enabled = !!ec->use_adaptive_rx_coalesce;
>+	apc->tx_dim_enabled = !!ec->use_adaptive_tx_coalesce;
>+
> 	saved_cqe_coalescing_enable = apc->cqe_coalescing_enable;
> 	apc->cqe_coalescing_enable =
> 		kernel_coal->rx_cqe_frames == MANA_RXCOMP_OOB_NUM_PPI;
>@@ -447,10 +517,46 @@ static int mana_set_coalesce(struct net_device *ndev,
> 	if (!apc->port_is_up)
> 		return 0;
> 
>-	err = mana_config_rss(apc, TRI_STATE_TRUE, false, false);
>-	if (err)
>-		apc->cqe_coalescing_enable = saved_cqe_coalescing_enable;
>+	if (apc->cqe_coalescing_enable != saved_cqe_coalescing_enable &&
>+	    !modr_changed && !dim_changed) {
>+		/* If only CQE coalescing setting is changed, we can just update
>+		 * RSS configuration.
>+		 */
>+		err = mana_config_rss(apc, TRI_STATE_TRUE, false, false);
>+		if (err) {
>+			netdev_err(ndev, "Change CQE coalescing failed: %d\n",
>+				   err);
>+			apc->cqe_coalescing_enable =
>+				saved_cqe_coalescing_enable;
>+			return err;
>+		}
>+		return 0;
>+	}
>+
>+	if (modr_changed || dim_changed) {
>+		err = mana_detach(ndev, false);
>+		if (err) {
>+			netdev_err(ndev, "mana_detach failed: %d\n", err);
>+			goto restore_modr;
>+		}
>+
>+		err = mana_attach(ndev);
>+		if (err) {
>+			netdev_err(ndev, "mana_attach failed: %d\n", err);
>+			goto restore_modr;

i see there is already such pattern in the mana code; how about
creating a helper?

>+		}
>+	}
>+
>+	return 0;
> 
>+restore_modr:
>+	apc->cqe_coalescing_enable = saved_cqe_coalescing_enable;
>+	apc->intr_modr_rx_usec = old_rx_usec;
>+	apc->intr_modr_rx_comp = old_rx_comp;
>+	apc->intr_modr_tx_usec = old_tx_usec;
>+	apc->intr_modr_tx_comp = old_tx_comp;
>+	apc->rx_dim_enabled = old_rx_dim;
>+	apc->tx_dim_enabled = old_tx_dim;
> 	return err;
> }
> 
>@@ -574,7 +680,13 @@ static int mana_get_link_ksettings(struct net_device *ndev,
> }
> 
> const struct ethtool_ops mana_ethtool_ops = {
>-	.supported_coalesce_params = ETHTOOL_COALESCE_RX_CQE_FRAMES,
>+	.supported_coalesce_params = ETHTOOL_COALESCE_RX_CQE_FRAMES |
>+				    ETHTOOL_COALESCE_RX_USECS |
>+				    ETHTOOL_COALESCE_RX_MAX_FRAMES |
>+				    ETHTOOL_COALESCE_TX_USECS |
>+				    ETHTOOL_COALESCE_TX_MAX_FRAMES |
>+				    ETHTOOL_COALESCE_USE_ADAPTIVE_RX |
>+				    ETHTOOL_COALESCE_USE_ADAPTIVE_TX,
> 	.get_ethtool_stats	= mana_get_ethtool_stats,
> 	.get_sset_count		= mana_get_sset_count,
> 	.get_strings		= mana_get_strings,
>diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
>index 70d62bc32837..0a0cc7b080d3 100644
>--- a/include/net/mana/gdma.h
>+++ b/include/net/mana/gdma.h
>@@ -47,6 +47,7 @@ enum gdma_queue_type {
> 	GDMA_RQ,
> 	GDMA_CQ,
> 	GDMA_EQ,
>+	GDMA_DIM,
> };
> 
> enum gdma_work_request_flags {
>@@ -126,6 +127,17 @@ union gdma_doorbell_entry {
> 		u64 tail_ptr	: 31;
> 		u64 arm		: 1;
> 	} eq;
>+
>+	struct {
>+		u64 id           : 24;
>+		u64 reserved     : 8;
>+		u64 mod_usec     : 10;
>+		u64 reserve1     : 5;
>+		u64 mod_usec_vld : 1;
>+		u64 mod_comps    : 8;
>+		u64 reserve2     : 7;
>+		u64 mod_comps_vld: 1;
>+	} dim;
> }; /* HW DATA */
> 
> struct gdma_msg_hdr {
>@@ -484,6 +496,9 @@ void mana_gd_ring_cq(struct gdma_queue *cq, u8 arm_bit);
> 
> int mana_schedule_serv_work(struct gdma_context *gc, enum gdma_eqe_type type);
> 
>+void mana_gd_ring_dim(struct gdma_queue *cq, u32 mod_usec, bool mod_usec_vld,
>+		      u32 mod_comps, bool mod_comps_vld);
>+
> struct gdma_wqe {
> 	u32 reserved	:24;
> 	u32 last_vbytes	:8;
>@@ -629,6 +644,9 @@ enum {
> /* Driver supports self recovery on Hardware Channel timeouts */
> #define GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY BIT(25)
> 
>+/* Driver supports dynamic interrupt moderation - DIM */
>+#define GDMA_DRV_CAP_FLAG_1_DYN_INTERRUPT_MODERATION BIT(27)
>+
> #define GDMA_DRV_CAP_FLAGS1 \
> 	(GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
> 	 GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
>@@ -643,7 +661,8 @@ enum {
> 	 GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE | \
> 	 GDMA_DRV_CAP_FLAG_1_PROBE_RECOVERY | \
> 	 GDMA_DRV_CAP_FLAG_1_HANDLE_STALL_SQ_RECOVERY | \
>-	 GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY)
>+	 GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY | \
>+	 GDMA_DRV_CAP_FLAG_1_DYN_INTERRUPT_MODERATION)
> 
> #define GDMA_DRV_CAP_FLAGS2 0
> 
>@@ -679,6 +698,9 @@ struct gdma_verify_ver_req {
> 	u8 os_ver_str4[128];
> }; /* HW DATA */
> 
>+/* HW supports dynamic interrupt moderation - DIM */
>+#define GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION BIT(15)
>+
> struct gdma_verify_ver_resp {
> 	struct gdma_resp_hdr hdr;
> 	u64 gdma_protocol_ver;
>diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
>index d9c27310fd04..57868a79f23d 100644
>--- a/include/net/mana/mana.h
>+++ b/include/net/mana/mana.h
>@@ -4,6 +4,7 @@
> #ifndef _MANA_H
> #define _MANA_H
> 
>+#include <linux/dim.h>
> #include <net/xdp.h>
> #include <net/net_shaper.h>
> 
>@@ -64,6 +65,16 @@ enum TRI_STATE {
> /* Maximum number of packets per coalesced CQE */
> #define MANA_RXCOMP_OOB_NUM_PPI 4
> 
>+/* Default/max interrupt moderation settings */
>+#define MANA_INTR_MODR_USEC_DEF 0
>+#define MANA_INTR_MODR_COMP_DEF 0
>+
>+#define MANA_ADAPTIVE_RX_DEF true
>+#define MANA_ADAPTIVE_TX_DEF true
>+
>+#define MANA_INTR_MODR_USEC_MAX 1023
>+#define MANA_INTR_MODR_COMP_MAX 255

used as a limiter and mask - for mask case i believe
GENMASK cand be used


^ permalink raw reply

* Re: [PATCH v2 0/5] treewide: Convert buses to use generic driver_override
From: Danilo Krummrich @ 2026-06-01  0:07 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, linux, nipun.gupta, nikhil.agarwal, kys, haiyangz,
	wei.liu, decui, longli, andersson, mathieu.poirier, driver-core,
	linux-kernel, linux-hyperv, linux-arm-msm, linux-remoteproc
In-Reply-To: <20260505133935.3772495-1-dakr@kernel.org>

On Tue,  5 May 2026 15:37:20 +0200, Danilo Krummrich wrote:
> [PATCH v2 0/5] treewide: Convert buses to use generic driver_override

Applied, thanks!

  Branch: driver-core-testing
  Tree:   git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git

[1/5] amba: use generic driver_override infrastructure
      commit: 1947229f5f2a
[2/5] cdx: use generic driver_override infrastructure
      commit: d541aa1897f6
[3/5] Drivers: hv: vmbus: use generic driver_override infrastructure
      commit: 331d8900121a
[4/5] rpmsg: use generic driver_override infrastructure
      commit: 55ced13c4292
[5/5] driver core: remove driver_set_override()
      commit: 46def663dd34

The patches will appear in the next linux-next integration (typically within 24
hours on weekdays).

The patches are in the driver-core-testing branch and will be promoted to
driver-core-next after validation.

^ permalink raw reply

* Re: [PATCH net-next] net: mana: Add Interrupt Moderation support
From: sashiko-bot @ 2026-05-31 19:51 UTC (permalink / raw)
  To: Haiyang Zhang; +Cc: linux-hyperv
In-Reply-To: <20260530194957.1690459-1-haiyangz@linux.microsoft.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] Static CQ moderation is silently disabled if only one parameter is configured.
- [High] Unconditional use of `GDMA_MESSAGE_V3` may break queue creation on older firmware.
- [High] Data race in DIM updates due to calling net_dim() after napi_complete_done().

Pre-existing issues:
- [High] ethtool coalesce change can leave the interface permanently detached/down on failure.
--

commit ed18c14aae7553debe324941814e80fe58d99fe0
Author: Haiyang Zhang <haiyangz@microsoft.com>

net: mana: Add Interrupt Moderation support

Add Static and Dynamic Interrupt Moderation (DIM) support for Rx and Tx.
Update queue creation procedure with new data struct with the related
settings. Update ethtool handler to get/set the moderation settings.

> diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
> --- a/drivers/net/ethernet/microsoft/mana/mana_en.c
> +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
> @@ -1551,6 +1551,9 @@ int mana_create_wq_obj(struct mana_port_context *apc,
>  
>  	mana_gd_init_req_hdr(&req.hdr, MANA_CREATE_WQ_OBJ,
>  			     sizeof(req), sizeof(resp));
> +
> +	req.hdr.req.msg_version = GDMA_MESSAGE_V3;
> +	req.hdr.resp.msg_version = GDMA_MESSAGE_V2;

[Severity: High]
Could this unconditional upgrade to GDMA_MESSAGE_V3 break queue creation on
older firmware?

If the driver is loaded on an older host where the hardware firmware does
not support V3 messages (for example, lacking DIM capabilities), it seems
the hardware might reject the MANA_CREATE_WQ_OBJ request. Would it be
safer to conditionally apply this message version upgrade based on hardware
capabilities?

[ ... ]

> @@ -2271,7 +2337,13 @@ static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
>  	if (w < cq->budget) {
>  		mana_gd_ring_cq(gdma_queue, SET_ARM_BIT);
>  		cq->work_done_since_doorbell = 0;
> -		napi_complete_done(&cq->napi, w);
> +
> +		if (napi_complete_done(&cq->napi, w)) {
> +			if (cq->type == MANA_CQ_TYPE_RX)
> +				mana_update_rx_dim(cq);
> +			else
> +				mana_update_tx_dim(cq);
> +		}

[Severity: High]
Does calling net_dim() after napi_complete_done() introduce a data race?

Since napi_complete_done() clears the NAPI_STATE_SCHED bit and
relinquishes the NAPI polling context, and the hardware interrupt
was already armed via mana_gd_ring_cq() just above, a new interrupt
could fire immediately.

If another CPU schedules NAPI and executes mana_cq_handler() concurrently,
it seems internal state in net_dim() could be corrupted. Additionally,
could this lead to torn reads of 64-bit queue statistics on 32-bit systems
since they are read outside NAPI protection?

[ ... ]

> @@ -2780,6 +2862,10 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
>  	cq_spec.queue_size = cq->gdma_cq->queue_size;
>  	cq_spec.modr_ctx_id = 0;
>  	cq_spec.attached_eq = cq->gdma_cq->cq.parent->id;
> +	cq_spec.req_cq_moderation = apc->rx_dim_enabled ||
> +		(apc->intr_modr_rx_usec && apc->intr_modr_rx_comp);
> +	cq_spec.cq_moderation_usec = apc->intr_modr_rx_usec;
> +	cq_spec.cq_moderation_comp = apc->intr_modr_rx_comp;

[Severity: High]
Does this logic silently disable static moderation if only one parameter is
configured?

If a user disables adaptive moderation and requests timer-based moderation
without a frame limit (e.g. adaptive-rx off rx-usecs 50 rx-frames 0), the
logical AND evaluates to false. This appears to cause the driver to silently
disable hardware moderation completely instead of applying the requested
rx-usecs.

(Note: The same pattern appears in mana_create_txq() for TX).

> diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
> --- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
> +++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
[ ... ]
> @@ -447,10 +517,46 @@ static int mana_set_coalesce(struct net_device *ndev,
[ ... ]
> +	if (modr_changed || dim_changed) {
> +		err = mana_detach(ndev, false);
> +		if (err) {
> +			netdev_err(ndev, "mana_detach failed: %d\n", err);
> +			goto restore_modr;
> +		}
> +
> +		err = mana_attach(ndev);
> +		if (err) {
> +			netdev_err(ndev, "mana_attach failed: %d\n", err);
> +			goto restore_modr;
> +		}
> +	}
> +
>  	return err;
>  
> +restore_modr:
> +	apc->cqe_coalescing_enable = saved_cqe_coalescing_enable;

[Severity: High]
This is a pre-existing issue, but does this error path leave the interface
permanently detached?

If mana_detach() succeeds but mana_attach() fails (for example, due to an
allocation failure), the function jumps to restore_modr. This restores the
software tracking variables but does not appear to revert the hardware state.

This could leave the network interface completely broken and detached from
the system until it is manually brought down and up again.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260530194957.1690459-1-haiyangz@linux.microsoft.com?part=1

^ permalink raw reply

* Re: [RFC PATCH 00/20] mshv: enable kexec with Hyper-V donated pages and partitions
From: Mike Rapoport @ 2026-05-31 17:10 UTC (permalink / raw)
  To: Jork Loeser
  Cc: linux-hyperv, linux-mm, kexec, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, Long Li, Pasha Tatashin, Pratyush Yadav,
	Alexander Graf, Jason Miu, Andrew Morton, David Hildenbrand,
	Muchun Song, Oscar Salvador, Baoquan He, Catalin Marinas,
	Will Deacon, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, Kees Cook, Ran Xiaokai,
	Justinien Bouron, Sourabh Jain, Pingfan Liu, Rafael J. Wysocki,
	Mario Limonciello, linux-arm-kernel, x86, linux-kernel,
	Michael Kelley
In-Reply-To: <20260528004204.1484584-1-jloeser@linux.microsoft.com>

Hi Jork,

Only had time to skim through the patches.
I have a couple of high level questions for now.

On Wed, May 27, 2026 at 05:41:42PM -0700, Jork Loeser wrote:
> When Linux runs as an L1 Virtual Host (L1VH) under Hyper-V, the MSHV
> root partition driver deposits pages to the hypervisor and creates
> partitions for guest VMs. Prior patches enabled kexec for L1VH, but
> only when no partitions had been created and no memory had been donated.
> 
> This series lifts that limitation. It uses KHO (Kexec Handover) to:
> 
>  - Track all pages deposited to the hypervisor in a KHO radix tree
>    and preserve them across kexec so the new kernel knows which pages
>    are owned by the hypervisor.
> 
>  - Freeze running partitions before kexec, record their IDs in the
>    KHO FDT, and vacuum (tear down + reclaim memory) stale partitions
>    after kexec.
> 
>  - In case of a crash, exclude hypervisor-owned pages from crash
>    dump collection by passing the radix tree root PA via Hyper-V
>    crash MSR P2 to the crash kernel.
> 
> Dependency on Pratyush's KHO series
> ===================================
> 
> Patches 1-12 are cherry-picked from Pratyush Yadav's v1 series
> "kho: make boot time huge page allocation work nicely with KHO" [1],
> which is still under discussion. This series uses functionality from
> those patches -- specifically the meta-data page enumeration via table
> callbacks and the restructured radix tree API. It also extends the
> KHO radix tree with:
> 
>  - A freeze mechanism to lock the tree before serializing for kexec
>    (patch 13).

There were a lot of effort to make KHO stateless and drop the requirement
for finalization/freeze.

Why is this necessary to add a freeze mechanism to kho_radix_tree?
If it's a hard requirement of mshv maybe the freeze part should be handled
there?
 
>  - A crash-kernel-safe variant that memremaps radix nodes for use
>    outside the direct map (patch 14).
> 
> Patch overview
> ==============
> 
> Patches 1-12:  KHO radix tree and memblock changes (from [1])
> Patch 13:      Radix tree freeze and del_key() error reporting

del_key() error reporting sounds like something we'd want to avoid.
del_key() is called on "freeing" path and during error handling, it would
be hard if at all possible to deal with errors from del_key().

> Patch 14:      Crash-kernel-safe radix tree presence check
> Patch 15:      Page tracker using KHO radix tree for deposited pages
> Patch 16:      Debugfs interface for page tracker
> Patches 17-18: Crash MSR reshuffling + crash dump page exclusion
> Patch 19:      Export kexec_in_progress for modules

Isn't there another way to differentiate kexec reboot?

> Patch 20:      Freeze and vacuum partitions across kexec
> 
> Feedback
> ========
> 
> This is an RFC. I am looking for feedback on the overall approach as
> well as the KHO changes (patches 13-14).
> 
> [1] https://lore.kernel.org/linux-mm/20260429133928.850721-1-pratyush@kernel.org/
> 
> Based-on: linux-next/master (next-20260527)

-- 
Sincerely yours,
Mike.

^ permalink raw reply

* [PATCH net-next] net: mana: Add Interrupt Moderation support
From: Haiyang Zhang @ 2026-05-30 19:49 UTC (permalink / raw)
  To: linux-hyperv, netdev, K. Y. Srinivasan, Haiyang Zhang, Wei Liu,
	Dexuan Cui, Long Li, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Konstantin Taranov, Simon Horman,
	Shradha Gupta, Erni Sri Satya Vennela, Dipayaan Roy, Aditya Garg,
	Kees Cook, Breno Leitao, linux-kernel, linux-rdma
  Cc: paulros

From: Haiyang Zhang <haiyangz@microsoft.com>

Add Static and Dynamic Interrupt Moderation (DIM) support for
Rx and Tx.
Update queue creation procedure with new data struct with the related
settings.
Add functions to collect stat for DIM, and workers to update DIM data
and settings.
Update ethtool handler to get/set the moderation settings from a user.
By default, adaptive-rx/tx (DIM) are enabled.

Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/net/ethernet/microsoft/Kconfig        |   1 +
 .../net/ethernet/microsoft/mana/gdma_main.c   |  27 ++++
 drivers/net/ethernet/microsoft/mana/mana_en.c | 101 ++++++++++++++-
 .../ethernet/microsoft/mana/mana_ethtool.c    | 120 +++++++++++++++++-
 include/net/mana/gdma.h                       |  24 +++-
 include/net/mana/mana.h                       |  42 ++++++
 6 files changed, 309 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/microsoft/Kconfig b/drivers/net/ethernet/microsoft/Kconfig
index 3f36ee6a8ece..e9be18c92ca5 100644
--- a/drivers/net/ethernet/microsoft/Kconfig
+++ b/drivers/net/ethernet/microsoft/Kconfig
@@ -21,6 +21,7 @@ config MICROSOFT_MANA
 	depends on X86_64 || (ARM64 && !CPU_BIG_ENDIAN)
 	depends on PCI_HYPERV
 	select AUXILIARY_BUS
+	select DIMLIB
 	select PAGE_POOL
 	select NET_SHAPER
 	help
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index 712a0881d720..5aa0ea794a00 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -405,6 +405,7 @@ static int mana_gd_disable_queue(struct gdma_queue *queue)
 #define DOORBELL_OFFSET_RQ	0x400
 #define DOORBELL_OFFSET_CQ	0x800
 #define DOORBELL_OFFSET_EQ	0xFF8
+#define DOORBELL_OFFSET_DIM	0x820
 
 static void mana_gd_ring_doorbell(struct gdma_context *gc, u32 db_index,
 				  enum gdma_queue_type q_type, u32 qid,
@@ -445,6 +446,16 @@ static void mana_gd_ring_doorbell(struct gdma_context *gc, u32 db_index,
 		addr += DOORBELL_OFFSET_SQ;
 		break;
 
+	case GDMA_DIM:
+		e.dim.id = qid;
+		e.dim.mod_usec = tail_ptr;
+		e.dim.mod_usec_vld = tail_ptr >> 15;
+		e.dim.mod_comps = tail_ptr >> 16;
+		e.dim.mod_comps_vld = num_req;
+
+		addr += DOORBELL_OFFSET_DIM;
+		break;
+
 	default:
 		WARN_ON(1);
 		return;
@@ -479,6 +490,22 @@ void mana_gd_ring_cq(struct gdma_queue *cq, u8 arm_bit)
 }
 EXPORT_SYMBOL_NS(mana_gd_ring_cq, "NET_MANA");
 
+void mana_gd_ring_dim(struct gdma_queue *cq, u32 mod_usec, bool mod_usec_vld,
+		      u32 mod_comps, bool mod_comps_vld)
+{
+	struct gdma_context *gc = cq->gdma_dev->gdma_context;
+	u32 dim_val;
+
+	/* Convert the DIM values to doorbell parameters */
+	dim_val = (mod_usec & MANA_INTR_MODR_USEC_MAX) |
+		  (((u32)mod_usec_vld & 1) << 15) |
+		  ((mod_comps & MANA_INTR_MODR_COMP_MAX) << 16);
+
+	mana_gd_ring_doorbell(gc, cq->gdma_dev->doorbell, GDMA_DIM, cq->id,
+			      dim_val, (u8)mod_comps_vld & 1);
+}
+EXPORT_SYMBOL_NS(mana_gd_ring_dim, "NET_MANA");
+
 #define MANA_SERVICE_PERIOD 10
 
 static void mana_serv_rescan(struct pci_dev *pdev)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 82f1461a48e9..f1a16f8aca66 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -1551,6 +1551,9 @@ int mana_create_wq_obj(struct mana_port_context *apc,
 
 	mana_gd_init_req_hdr(&req.hdr, MANA_CREATE_WQ_OBJ,
 			     sizeof(req), sizeof(resp));
+
+	req.hdr.req.msg_version = GDMA_MESSAGE_V3;
+	req.hdr.resp.msg_version = GDMA_MESSAGE_V2;
 	req.vport = vport;
 	req.wq_type = wq_type;
 	req.wq_gdma_region = wq_spec->gdma_region;
@@ -1559,6 +1562,9 @@ int mana_create_wq_obj(struct mana_port_context *apc,
 	req.cq_size = cq_spec->queue_size;
 	req.cq_moderation_ctx_id = cq_spec->modr_ctx_id;
 	req.cq_parent_qid = cq_spec->attached_eq;
+	req.req_cq_moderation = cq_spec->req_cq_moderation;
+	req.cq_moderation_comp = cq_spec->cq_moderation_comp;
+	req.cq_moderation_usec = cq_spec->cq_moderation_usec;
 
 	err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
 				sizeof(resp));
@@ -2253,6 +2259,66 @@ static void mana_poll_rx_cq(struct mana_cq *cq)
 		xdp_do_flush();
 }
 
+static void mana_rx_dim_work(struct work_struct *work)
+{
+	struct dim *dim = container_of(work, struct dim, work);
+	struct mana_cq *cq = container_of(dim, struct mana_cq, dim);
+	struct dim_cq_moder cur_moder =
+		net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
+
+	cur_moder.usec = min_t(u16, cur_moder.usec, MANA_INTR_MODR_USEC_MAX);
+	cur_moder.pkts = min_t(u16, cur_moder.pkts, MANA_INTR_MODR_COMP_MAX);
+
+	mana_gd_ring_dim(cq->gdma_cq, cur_moder.usec, true,
+			 cur_moder.pkts, true);
+
+	dim->state = DIM_START_MEASURE;
+}
+
+static void mana_tx_dim_work(struct work_struct *work)
+{
+	struct dim *dim = container_of(work, struct dim, work);
+	struct mana_cq *cq = container_of(dim, struct mana_cq, dim);
+	struct dim_cq_moder cur_moder =
+		net_dim_get_tx_moderation(dim->mode, dim->profile_ix);
+
+	cur_moder.usec = min_t(u16, cur_moder.usec, MANA_INTR_MODR_USEC_MAX);
+	cur_moder.pkts = min_t(u16, cur_moder.pkts, MANA_INTR_MODR_COMP_MAX);
+
+	mana_gd_ring_dim(cq->gdma_cq, cur_moder.usec, true,
+			 cur_moder.pkts, true);
+
+	dim->state = DIM_START_MEASURE;
+}
+
+static void mana_update_rx_dim(struct mana_cq *cq)
+{
+	struct mana_rxq *rxq = cq->rxq;
+	struct mana_port_context *apc = netdev_priv(rxq->ndev);
+	struct dim_sample dim_sample = {};
+
+	if (!apc->rx_dim_enabled)
+		return;
+
+	dim_update_sample(READ_ONCE(cq->dim_event_ctr), rxq->stats.packets,
+			  rxq->stats.bytes, &dim_sample);
+	net_dim(&cq->dim, &dim_sample);
+}
+
+static void mana_update_tx_dim(struct mana_cq *cq)
+{
+	struct mana_txq *txq = cq->txq;
+	struct mana_port_context *apc = netdev_priv(txq->ndev);
+	struct dim_sample dim_sample = {};
+
+	if (!apc->tx_dim_enabled)
+		return;
+
+	dim_update_sample(READ_ONCE(cq->dim_event_ctr), txq->stats.packets,
+			  txq->stats.bytes, &dim_sample);
+	net_dim(&cq->dim, &dim_sample);
+}
+
 static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
 {
 	struct mana_cq *cq = context;
@@ -2271,7 +2337,13 @@ static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
 	if (w < cq->budget) {
 		mana_gd_ring_cq(gdma_queue, SET_ARM_BIT);
 		cq->work_done_since_doorbell = 0;
-		napi_complete_done(&cq->napi, w);
+
+		if (napi_complete_done(&cq->napi, w)) {
+			if (cq->type == MANA_CQ_TYPE_RX)
+				mana_update_rx_dim(cq);
+			else
+				mana_update_tx_dim(cq);
+		}
 	} else if (cq->work_done_since_doorbell >=
 		   (cq->gdma_cq->queue_size / COMP_ENTRY_SIZE) * 4) {
 		/* MANA hardware requires at least one doorbell ring every 8
@@ -2303,6 +2375,7 @@ static void mana_schedule_napi(void *context, struct gdma_queue *gdma_queue)
 {
 	struct mana_cq *cq = context;
 
+	WRITE_ONCE(cq->dim_event_ctr, cq->dim_event_ctr + 1);
 	napi_schedule_irqoff(&cq->napi);
 }
 
@@ -2345,6 +2418,7 @@ static void mana_destroy_txq(struct mana_port_context *apc)
 		if (apc->tx_qp[i]->txq.napi_initialized) {
 			napi_synchronize(napi);
 			napi_disable_locked(napi);
+			cancel_work_sync(&apc->tx_qp[i]->tx_cq.dim.work);
 			netif_napi_del_locked(napi);
 			apc->tx_qp[i]->txq.napi_initialized = false;
 		}
@@ -2475,6 +2549,10 @@ static int mana_create_txq(struct mana_port_context *apc,
 		cq_spec.queue_size = cq->gdma_cq->queue_size;
 		cq_spec.modr_ctx_id = 0;
 		cq_spec.attached_eq = cq->gdma_cq->cq.parent->id;
+		cq_spec.req_cq_moderation = apc->tx_dim_enabled ||
+			(apc->intr_modr_tx_usec && apc->intr_modr_tx_comp);
+		cq_spec.cq_moderation_usec = apc->intr_modr_tx_usec;
+		cq_spec.cq_moderation_comp = apc->intr_modr_tx_comp;
 
 		err = mana_create_wq_obj(apc, apc->port_handle, GDMA_SQ,
 					 &wq_spec, &cq_spec,
@@ -2509,6 +2587,9 @@ static int mana_create_txq(struct mana_port_context *apc,
 		napi_enable_locked(&cq->napi);
 		txq->napi_initialized = true;
 
+		INIT_WORK(&cq->dim.work, mana_tx_dim_work);
+		cq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+
 		mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT);
 	}
 
@@ -2543,6 +2624,7 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
 		napi_synchronize(napi);
 
 		napi_disable_locked(napi);
+		cancel_work_sync(&rxq->rx_cq.dim.work);
 		netif_napi_del_locked(napi);
 	}
 
@@ -2780,6 +2862,10 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
 	cq_spec.queue_size = cq->gdma_cq->queue_size;
 	cq_spec.modr_ctx_id = 0;
 	cq_spec.attached_eq = cq->gdma_cq->cq.parent->id;
+	cq_spec.req_cq_moderation = apc->rx_dim_enabled ||
+		(apc->intr_modr_rx_usec && apc->intr_modr_rx_comp);
+	cq_spec.cq_moderation_usec = apc->intr_modr_rx_usec;
+	cq_spec.cq_moderation_comp = apc->intr_modr_rx_comp;
 
 	err = mana_create_wq_obj(apc, apc->port_handle, GDMA_RQ,
 				 &wq_spec, &cq_spec, &rxq->rxobj);
@@ -2815,6 +2901,9 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
 
 	napi_enable_locked(&cq->napi);
 
+	INIT_WORK(&cq->dim.work, mana_rx_dim_work);
+	cq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+
 	mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT);
 out:
 	if (!err)
@@ -3432,6 +3521,16 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,
 	apc->port_idx = port_idx;
 	apc->cqe_coalescing_enable = 0;
 
+	/* Initialize interrupt moderation settings if supported by HW */
+	if (gc->pf_cap_flags1 & GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION) {
+		apc->intr_modr_rx_usec = MANA_INTR_MODR_USEC_DEF;
+		apc->intr_modr_rx_comp = MANA_INTR_MODR_COMP_DEF;
+		apc->intr_modr_tx_usec = MANA_INTR_MODR_USEC_DEF;
+		apc->intr_modr_tx_comp = MANA_INTR_MODR_COMP_DEF;
+		apc->rx_dim_enabled = MANA_ADAPTIVE_RX_DEF;
+		apc->tx_dim_enabled = MANA_ADAPTIVE_TX_DEF;
+	}
+
 	mutex_init(&apc->vport_mutex);
 	apc->vport_use_count = 0;
 
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 04350973e19e..a90216eba794 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -419,6 +419,15 @@ static int mana_get_coalesce(struct net_device *ndev,
 	    !kernel_coal->rx_cqe_nsecs)
 		kernel_coal->rx_cqe_nsecs = MANA_RX_CQE_NSEC_DEF;
 
+	ec->rx_coalesce_usecs = apc->intr_modr_rx_usec;
+	ec->rx_max_coalesced_frames = apc->intr_modr_rx_comp;
+
+	ec->tx_coalesce_usecs = apc->intr_modr_tx_usec;
+	ec->tx_max_coalesced_frames = apc->intr_modr_tx_comp;
+
+	ec->use_adaptive_rx_coalesce = apc->rx_dim_enabled;
+	ec->use_adaptive_tx_coalesce = apc->tx_dim_enabled;
+
 	return 0;
 }
 
@@ -429,8 +438,28 @@ static int mana_set_coalesce(struct net_device *ndev,
 {
 	struct mana_port_context *apc = netdev_priv(ndev);
 	u8 saved_cqe_coalescing_enable;
+	u16 old_rx_usec, old_rx_comp;
+	u16 old_tx_usec, old_tx_comp;
+	bool old_rx_dim, old_tx_dim;
+	bool modr_changed = false;
+	bool dim_changed = false;
+	struct gdma_context *gc;
 	int err;
 
+	gc = apc->ac->gdma_dev->gdma_context;
+
+	/* Both static and dynamic interrupt moderation (DIM) rely on the
+	 * same HW capability advertised by the PF.
+	 */
+	if ((ec->use_adaptive_rx_coalesce || ec->use_adaptive_tx_coalesce ||
+	     ec->rx_coalesce_usecs || ec->tx_coalesce_usecs ||
+	     ec->rx_max_coalesced_frames || ec->tx_max_coalesced_frames) &&
+	    !(gc->pf_cap_flags1 & GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION)) {
+		NL_SET_ERR_MSG(extack,
+			       "Interrupt Moderation is not supported by HW");
+		return -EOPNOTSUPP;
+	}
+
 	if (kernel_coal->rx_cqe_frames != 1 &&
 	    kernel_coal->rx_cqe_frames != MANA_RXCOMP_OOB_NUM_PPI) {
 		NL_SET_ERR_MSG_FMT(extack,
@@ -440,6 +469,47 @@ static int mana_set_coalesce(struct net_device *ndev,
 		return -EINVAL;
 	}
 
+	if (ec->rx_coalesce_usecs > MANA_INTR_MODR_USEC_MAX ||
+	    ec->tx_coalesce_usecs > MANA_INTR_MODR_USEC_MAX) {
+		NL_SET_ERR_MSG_FMT(extack,
+				   "coalesce usecs must be <= %u",
+				   MANA_INTR_MODR_USEC_MAX);
+		return -EINVAL;
+	}
+
+	if (ec->rx_max_coalesced_frames > MANA_INTR_MODR_COMP_MAX ||
+	    ec->tx_max_coalesced_frames > MANA_INTR_MODR_COMP_MAX) {
+		NL_SET_ERR_MSG_FMT(extack,
+				   "coalesce frames must be <= %u",
+				   MANA_INTR_MODR_COMP_MAX);
+		return -EINVAL;
+	}
+
+	if (ec->rx_coalesce_usecs != apc->intr_modr_rx_usec ||
+	    ec->rx_max_coalesced_frames != apc->intr_modr_rx_comp ||
+	    ec->tx_coalesce_usecs != apc->intr_modr_tx_usec ||
+	    ec->tx_max_coalesced_frames != apc->intr_modr_tx_comp)
+		modr_changed = true;
+
+	old_rx_usec = apc->intr_modr_rx_usec;
+	old_rx_comp = apc->intr_modr_rx_comp;
+	old_tx_usec = apc->intr_modr_tx_usec;
+	old_tx_comp = apc->intr_modr_tx_comp;
+
+	apc->intr_modr_rx_usec = ec->rx_coalesce_usecs;
+	apc->intr_modr_rx_comp = ec->rx_max_coalesced_frames;
+	apc->intr_modr_tx_usec = ec->tx_coalesce_usecs;
+	apc->intr_modr_tx_comp = ec->tx_max_coalesced_frames;
+
+	if (!!ec->use_adaptive_rx_coalesce != apc->rx_dim_enabled ||
+	    !!ec->use_adaptive_tx_coalesce != apc->tx_dim_enabled)
+		dim_changed = true;
+
+	old_rx_dim = apc->rx_dim_enabled;
+	old_tx_dim = apc->tx_dim_enabled;
+	apc->rx_dim_enabled = !!ec->use_adaptive_rx_coalesce;
+	apc->tx_dim_enabled = !!ec->use_adaptive_tx_coalesce;
+
 	saved_cqe_coalescing_enable = apc->cqe_coalescing_enable;
 	apc->cqe_coalescing_enable =
 		kernel_coal->rx_cqe_frames == MANA_RXCOMP_OOB_NUM_PPI;
@@ -447,10 +517,46 @@ static int mana_set_coalesce(struct net_device *ndev,
 	if (!apc->port_is_up)
 		return 0;
 
-	err = mana_config_rss(apc, TRI_STATE_TRUE, false, false);
-	if (err)
-		apc->cqe_coalescing_enable = saved_cqe_coalescing_enable;
+	if (apc->cqe_coalescing_enable != saved_cqe_coalescing_enable &&
+	    !modr_changed && !dim_changed) {
+		/* If only CQE coalescing setting is changed, we can just update
+		 * RSS configuration.
+		 */
+		err = mana_config_rss(apc, TRI_STATE_TRUE, false, false);
+		if (err) {
+			netdev_err(ndev, "Change CQE coalescing failed: %d\n",
+				   err);
+			apc->cqe_coalescing_enable =
+				saved_cqe_coalescing_enable;
+			return err;
+		}
+		return 0;
+	}
+
+	if (modr_changed || dim_changed) {
+		err = mana_detach(ndev, false);
+		if (err) {
+			netdev_err(ndev, "mana_detach failed: %d\n", err);
+			goto restore_modr;
+		}
+
+		err = mana_attach(ndev);
+		if (err) {
+			netdev_err(ndev, "mana_attach failed: %d\n", err);
+			goto restore_modr;
+		}
+	}
+
+	return 0;
 
+restore_modr:
+	apc->cqe_coalescing_enable = saved_cqe_coalescing_enable;
+	apc->intr_modr_rx_usec = old_rx_usec;
+	apc->intr_modr_rx_comp = old_rx_comp;
+	apc->intr_modr_tx_usec = old_tx_usec;
+	apc->intr_modr_tx_comp = old_tx_comp;
+	apc->rx_dim_enabled = old_rx_dim;
+	apc->tx_dim_enabled = old_tx_dim;
 	return err;
 }
 
@@ -574,7 +680,13 @@ static int mana_get_link_ksettings(struct net_device *ndev,
 }
 
 const struct ethtool_ops mana_ethtool_ops = {
-	.supported_coalesce_params = ETHTOOL_COALESCE_RX_CQE_FRAMES,
+	.supported_coalesce_params = ETHTOOL_COALESCE_RX_CQE_FRAMES |
+				    ETHTOOL_COALESCE_RX_USECS |
+				    ETHTOOL_COALESCE_RX_MAX_FRAMES |
+				    ETHTOOL_COALESCE_TX_USECS |
+				    ETHTOOL_COALESCE_TX_MAX_FRAMES |
+				    ETHTOOL_COALESCE_USE_ADAPTIVE_RX |
+				    ETHTOOL_COALESCE_USE_ADAPTIVE_TX,
 	.get_ethtool_stats	= mana_get_ethtool_stats,
 	.get_sset_count		= mana_get_sset_count,
 	.get_strings		= mana_get_strings,
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 70d62bc32837..0a0cc7b080d3 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -47,6 +47,7 @@ enum gdma_queue_type {
 	GDMA_RQ,
 	GDMA_CQ,
 	GDMA_EQ,
+	GDMA_DIM,
 };
 
 enum gdma_work_request_flags {
@@ -126,6 +127,17 @@ union gdma_doorbell_entry {
 		u64 tail_ptr	: 31;
 		u64 arm		: 1;
 	} eq;
+
+	struct {
+		u64 id           : 24;
+		u64 reserved     : 8;
+		u64 mod_usec     : 10;
+		u64 reserve1     : 5;
+		u64 mod_usec_vld : 1;
+		u64 mod_comps    : 8;
+		u64 reserve2     : 7;
+		u64 mod_comps_vld: 1;
+	} dim;
 }; /* HW DATA */
 
 struct gdma_msg_hdr {
@@ -484,6 +496,9 @@ void mana_gd_ring_cq(struct gdma_queue *cq, u8 arm_bit);
 
 int mana_schedule_serv_work(struct gdma_context *gc, enum gdma_eqe_type type);
 
+void mana_gd_ring_dim(struct gdma_queue *cq, u32 mod_usec, bool mod_usec_vld,
+		      u32 mod_comps, bool mod_comps_vld);
+
 struct gdma_wqe {
 	u32 reserved	:24;
 	u32 last_vbytes	:8;
@@ -629,6 +644,9 @@ enum {
 /* Driver supports self recovery on Hardware Channel timeouts */
 #define GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY BIT(25)
 
+/* Driver supports dynamic interrupt moderation - DIM */
+#define GDMA_DRV_CAP_FLAG_1_DYN_INTERRUPT_MODERATION BIT(27)
+
 #define GDMA_DRV_CAP_FLAGS1 \
 	(GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
 	 GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
@@ -643,7 +661,8 @@ enum {
 	 GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE | \
 	 GDMA_DRV_CAP_FLAG_1_PROBE_RECOVERY | \
 	 GDMA_DRV_CAP_FLAG_1_HANDLE_STALL_SQ_RECOVERY | \
-	 GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY)
+	 GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY | \
+	 GDMA_DRV_CAP_FLAG_1_DYN_INTERRUPT_MODERATION)
 
 #define GDMA_DRV_CAP_FLAGS2 0
 
@@ -679,6 +698,9 @@ struct gdma_verify_ver_req {
 	u8 os_ver_str4[128];
 }; /* HW DATA */
 
+/* HW supports dynamic interrupt moderation - DIM */
+#define GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION BIT(15)
+
 struct gdma_verify_ver_resp {
 	struct gdma_resp_hdr hdr;
 	u64 gdma_protocol_ver;
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index d9c27310fd04..57868a79f23d 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -4,6 +4,7 @@
 #ifndef _MANA_H
 #define _MANA_H
 
+#include <linux/dim.h>
 #include <net/xdp.h>
 #include <net/net_shaper.h>
 
@@ -64,6 +65,16 @@ enum TRI_STATE {
 /* Maximum number of packets per coalesced CQE */
 #define MANA_RXCOMP_OOB_NUM_PPI 4
 
+/* Default/max interrupt moderation settings */
+#define MANA_INTR_MODR_USEC_DEF 0
+#define MANA_INTR_MODR_COMP_DEF 0
+
+#define MANA_ADAPTIVE_RX_DEF true
+#define MANA_ADAPTIVE_TX_DEF true
+
+#define MANA_INTR_MODR_USEC_MAX 1023
+#define MANA_INTR_MODR_COMP_MAX 255
+
 /* Update this count whenever the respective structures are changed */
 #define MANA_STATS_RX_COUNT (6 + MANA_RXCOMP_OOB_NUM_PPI - 1)
 #define MANA_STATS_TX_COUNT 11
@@ -297,6 +308,10 @@ struct mana_cq {
 	int work_done;
 	int work_done_since_doorbell;
 	int budget;
+
+	/* DIM - Dynamic Interrupt Moderation */
+	struct dim dim;
+	u16 dim_event_ctr;
 };
 
 struct mana_recv_buf_oob {
@@ -562,6 +577,15 @@ struct mana_port_context {
 	u8 cqe_coalescing_enable;
 	u32 cqe_coalescing_timeout_ns;
 
+	/* Interrupt moderation settings */
+	u16 intr_modr_rx_usec;
+	u16 intr_modr_rx_comp;
+	u16 intr_modr_tx_usec;
+	u16 intr_modr_tx_comp;
+
+	bool rx_dim_enabled;
+	bool tx_dim_enabled;
+
 	struct mana_ethtool_stats eth_stats;
 
 	struct mana_ethtool_phy_stats phy_stats;
@@ -622,6 +646,9 @@ struct mana_obj_spec {
 	u32 queue_size;
 	u32 attached_eq;
 	u32 modr_ctx_id;
+	u8 req_cq_moderation;
+	u16 cq_moderation_comp;
+	u16 cq_moderation_usec;
 };
 
 enum mana_command_code {
@@ -753,6 +780,15 @@ struct mana_create_wqobj_req {
 	u32 cq_size;
 	u32 cq_moderation_ctx_id;
 	u32 cq_parent_qid;
+
+	/* V2 */
+	u8 allow_rqwqe_chain;
+
+	/* V3 */
+	u8 req_cq_moderation;
+	u16 cq_moderation_comp;
+	u16 cq_moderation_usec;
+	u8 reserved2[2];
 }; /* HW DATA */
 
 struct mana_create_wqobj_resp {
@@ -760,6 +796,12 @@ struct mana_create_wqobj_resp {
 	u32 wq_id;
 	u32 cq_id;
 	mana_handle_t wq_obj;
+
+	/* V2 */
+	u16 cq_moderation_comp;
+	u16 cq_moderation_usec;
+	u8 cq_moderation_enabled;
+	u8 reserved1[3];
 }; /* HW DATA */
 
 /* Destroy WQ Object */
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH v4 08/10] drm/damage-helper: Remove old state from drm_atomic_helper_damage_merged()
From: sashiko-bot @ 2026-05-30 19:16 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-hyperv
In-Reply-To: <20260530185716.65688-9-tzimmermann@suse.de>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The i915 driver fails to perform full plane updates when source coordinates change (e.g., panning or cropping), leading to visual corruption.
--

commit 020ae3c303979cf114157a7b95370725231ed90b
Author: Thomas Zimmermann <tzimmermann@suse.de>

drm/damage-helper: Remove old state from drm_atomic_helper_damage_merged()

Nothing in drm_atomic_helper_damage_merged() requires the old plane state.
Remove the parameter and mass-convert callers. Most callers now no longer
require the old plane state in their plane's atomic_update helper.

> diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c
> index 2a52b36c646c7..3560e222a3eae 100644
> --- a/drivers/gpu/drm/i915/display/intel_plane.c
> +++ b/drivers/gpu/drm/i915/display/intel_plane.c
[ ... ]
> @@ -346,7 +346,6 @@ static void intel_plane_clear_hw_state(struct intel_plane_state *plane_state)
>  
>  static void
>  intel_plane_copy_uapi_plane_damage(struct intel_plane_state *new_plane_state,
> -				   const struct intel_plane_state *old_uapi_plane_state,
>  				   const struct intel_plane_state *new_uapi_plane_state)
>  {
>  	struct intel_display *display = to_intel_display(new_plane_state);
> @@ -356,10 +355,9 @@ intel_plane_copy_uapi_plane_damage(struct intel_plane_state *new_plane_state,
>  	if (DISPLAY_VER(display) < 12)
>  		return;
>  
> -	if (!drm_atomic_helper_damage_merged(&old_uapi_plane_state->uapi,
> -					     &new_uapi_plane_state->uapi,
> +	if (!drm_atomic_helper_damage_merged(&new_uapi_plane_state->uapi,
>  					     damage))

[Severity: High]
Does this code risk missing full plane updates when source coordinates change?

It appears that with the removal of the old state, the fallback checking
for source coordinate changes (like panning) was also removed from the
damage iterators. The DRM core now expects drivers to call
drm_atomic_helper_check_plane_damage() to set ignore_damage_clips = true
when the source changes.

Because i915 implements a custom atomic check phase in intel_atomic_check()
that does not call drm_atomic_helper_check_planes() or
drm_atomic_helper_check_plane_damage(), ignore_damage_clips remains unset.

Will drm_atomic_helper_damage_merged() incorrectly return only partial
damage here when the plane is panned, missing the full update?

> -		/* Incase helper fails, mark whole plane region as damage */
> +		/* In case the helper fails, mark whole plane region as damage */
>  		*damage = drm_plane_state_src(&new_uapi_plane_state->uapi);
>  }
[ ... ]
> diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
> index e138982dc91f6..22bab263d85d4 100644
> --- a/drivers/gpu/drm/i915/display/intel_psr.c
> +++ b/drivers/gpu/drm/i915/display/intel_psr.c
[ ... ]
> @@ -3018,8 +3018,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
>  		src = drm_plane_state_src(&new_plane_state->uapi);
>  		drm_rect_fp_to_int(&src, &src);
>  
> -		if (!drm_atomic_helper_damage_merged(&old_plane_state->uapi,
> -						     &new_plane_state->uapi, &damaged_area))
> +		if (!drm_atomic_helper_damage_merged(&new_plane_state->uapi, &damaged_area))

[Severity: High]
Can this cause severe visual corruption for PSR2 selective fetch?

If intel_psr2_sel_fetch_update() no longer forces a full update on source
coordinate changes, it seems this might only fetch the small damaged area
(such as a blinking cursor) while leaving the rest of the panned screen
stale.

>  			continue;
>  
>  		damaged_area.y1 += new_plane_state->uapi.dst.y1 - src.y1;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260530185716.65688-1-tzimmermann@suse.de?part=8

^ permalink raw reply

* Re: [PATCH v4 01/10] drm/damage-helper: Do not alter damage clips on modeset, but ignore them
From: sashiko-bot @ 2026-05-30 19:10 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-hyperv
In-Reply-To: <20260530185716.65688-2-tzimmermann@suse.de>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Drivers using raw damage clip getters bypass the newly introduced `ignore_damage_clips` flag, leading to partial screen updates during full modesets.
--

commit 8480930644dc907381d0145f944fe144e2010b34
Author: Thomas Zimmermann <tzimmermann@suse.de>

drm/damage-helper: Do not alter damage clips on modeset, but ignore them

This commit changes the behavior of drm_atomic_helper_check_plane_damage()
to preserve fb_damage_clips during a modeset. Instead of clearing the clips,
it now sets a new ignore_damage_clips flag, which the damage iterator
respects.

> diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c
> index 74a7f4252ecff..945fac8dc27b6 100644
> --- a/drivers/gpu/drm/drm_damage_helper.c
> +++ b/drivers/gpu/drm/drm_damage_helper.c
[ ... ]
> @@ -78,10 +78,8 @@ void drm_atomic_helper_check_plane_damage(struct drm_atomic_commit *state,
>  		if (WARN_ON(!crtc_state))
>  			return;
>  
> -		if (drm_atomic_crtc_needs_modeset(crtc_state)) {
> -			drm_property_blob_put(plane_state->fb_damage_clips);
> -			plane_state->fb_damage_clips = NULL;
> -		}
> +		if (drm_atomic_crtc_needs_modeset(crtc_state))
> +			plane_state->ignore_damage_clips = true;
>  	}
>  }

[Severity: High]
Does this change cause a regression for drivers that use the raw damage clip
getters instead of the iterator?

Several drivers call drm_plane_get_damage_clips() and
drm_plane_get_damage_clips_count() directly. These raw getters return the
fb_damage_clips without evaluating the new ignore_damage_clips flag:

drivers/gpu/drm/drm_plane.c:drm_plane_get_damage_clips() {
    ...
    return __drm_plane_get_damage_clips(state);
}

Before this patch, fb_damage_clips was forced to NULL on modeset, which
caused drivers to correctly fall back to a full frame update. Now they will
see num_clips > 0 and attempt a partial screen update during a full modeset.

For example, in amdgpu, the full frame update fallback is skipped:

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:fill_dc_dirty_rects() {
    ...
    num_clips = drm_plane_get_damage_clips_count(new_plane_state);
    clips = drm_plane_get_damage_clips(new_plane_state);
    ...
}

Similarly in vboxvideo:

drivers/gpu/drm/vboxvideo/vbox_mode.c:vbox_primary_atomic_update() {
    ...
    clips = drm_plane_get_damage_clips(new_state);
    num_clips = drm_plane_get_damage_clips_count(new_state);
    ...
}

And in vmwgfx:

drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c:vmw_ldu_primary_plane_atomic_update() {
    ...
    struct drm_mode_rect *damage_rects = drm_plane_get_damage_clips(new_state);
    u32 rect_count = drm_plane_get_damage_clips_count(new_state);
    ...
}

Should the raw getters be updated to check ignore_damage_clips, or should
these drivers be transitioned to use the damage iterator?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260530185716.65688-1-tzimmermann@suse.de?part=1

^ permalink raw reply

* Re: [PATCH v4 04/10] drm/appletbdrm: Allocate request/response buffers in begin_fb_access
From: sashiko-bot @ 2026-05-30 19:09 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-hyperv
In-Reply-To: <20260530185716.65688-5-tzimmermann@suse.de>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [Critical] Passing `NULL` as the `old_state` parameter to `drm_atomic_helper_damage_iter_init()` causes a kernel panic due to a NULL pointer dereference.

Pre-existing issues:
- [Critical] Accumulating damage clip sizes in `frames_size` can overflow on 32-bit platforms, causing an undersized buffer allocation and a subsequent heap buffer overflow.
--

commit 72afced3e1b6baa294269874c7c4d9d05230889c
Author: Thomas Zimmermann <tzimmermann@suse.de>

drm/appletbdrm: Allocate request/response buffers in begin_fb_access

In atomic_check, damage handling is not fully evaluated. Another
atomic_check helper could trigger a full modeset and thus invalidate
damage clips.

Allocation of the request/response buffers in appletbdrm depends on
correct damage information. Otherwise it might allocate incorrectly
sized buffers. Allocate the buffers in the driver's begin_fb_access
helper. It runs early during the commit when damage clipping has been
fully evaluated.

> diff --git a/drivers/gpu/drm/tiny/appletbdrm.c b/drivers/gpu/drm/tiny/appletbdrm.c
> index cdd35af498920..b683dcb35b0be 100644
> --- a/drivers/gpu/drm/tiny/appletbdrm.c
> +++ b/drivers/gpu/drm/tiny/appletbdrm.c
> @@ -315,33 +315,16 @@ static const u32 appletbdrm_primary_plane_formats[] = {

[ ... ]

> -	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, new_plane_state);
> +	drm_atomic_helper_damage_iter_init(&iter, NULL, new_plane_state);

[Severity: Critical]
Does passing NULL as the old_state parameter to
drm_atomic_helper_damage_iter_init() cause a kernel panic?

If userspace has provided damage clips,
drm_atomic_helper_damage_iter_init() evaluates
!drm_rect_equals(&state->src, &old_state->src) to check if the source
coordinates changed:

drivers/gpu/drm/drm_damage_helper.c:drm_atomic_helper_damage_iter_init() {
    ...
	if (!iter->clips || state->ignore_damage_clips ||
	    !drm_rect_equals(&state->src, &old_state->src)) {
    ...
}

This appears to pass the address of src offset from the NULL pointer to
drm_rect_equals(), which would immediately dereference it and trigger an
oops. This could allow any userspace process with display access to
trivially crash the system by attaching a damage clip.

I found the fix for this regression later in the patch series in the
commit 'drm/damage-helper: Remove old state from
drm_atomic_helper_damage_iter_init()', but I am reporting it here since
it breaks at this step in the git history.

>  	drm_atomic_for_each_plane_damage(&iter, &damage) {
>  		frames_size += struct_size((struct appletbdrm_frame *)0, buf, rect_size(&damage));

[Severity: Critical]
This is a pre-existing issue, but can this unchecked accumulation overflow
frames_size on 32-bit platforms?

Because userspace can submit an arbitrary number of overlapping damage
clips up to the maximum property blob size, this unchecked addition could
wrap around a 32-bit size_t counter, causing kvzalloc() to allocate an
undersized buffer.

During appletbdrm_flush_damage(), the driver loops over the same clips
and uses drm_fb_memcpy() to write the full, un-overflowed volume of pixel
data into the undersized allocation:

drivers/gpu/drm/tiny/appletbdrm.c:appletbdrm_flush_damage() {
    ...
		switch (fb->format->format) {
		case DRM_FORMAT_XRGB8888:
			drm_fb_xrgb8888_to_bgr888(&dst, NULL, &shadow_plane_state->data[0], fb, &damage, &shadow_plane_state->fmtcnv_state);
			break;
		default:
			drm_fb_memcpy(&dst, NULL, &shadow_plane_state->data[0], fb, &damage);
			break;
		}
    ...
}

This causes an out-of-bounds heap write, which could potentially be exploited.

>  	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260530185716.65688-1-tzimmermann@suse.de?part=4

^ permalink raw reply

* Re: [PATCH v4 06/10] drm/damage-helper: Test src coord in drm_atomic_helper_check_plane_damage()
From: sashiko-bot @ 2026-05-30 19:09 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-hyperv
In-Reply-To: <20260530185716.65688-7-tzimmermann@suse.de>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Accessor functions `drm_plane_get_damage_clips()` and `drm_plane_get_damage_clips_count()` return outdated partial clips instead of forcing a full update when `ignore_damage_clips` is set, causing drivers to skip full plane updates during modesets and `src` coordinate changes.
--

commit 18363d38b23996b07f12d04823d811d72b0f24d4
Author: Thomas Zimmermann <tzimmermann@suse.de>

drm/damage-helper: Test src coord in drm_atomic_helper_check_plane_damage()

This commit updates drm_atomic_helper_check_plane_damage() to evaluate if
the source coordinates change across atomic commits. If they do, it sets the
ignore_damage_clips flag in the plane state to force a full update, and
removes this check from drm_atomic_helper_damage_iter_init().

> diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c
> index 945fac8dc27b6..f492a59edbeb5 100644
> --- a/drivers/gpu/drm/drm_damage_helper.c
> +++ b/drivers/gpu/drm/drm_damage_helper.c

[ ... ]

> @@ -67,19 +68,23 @@ static void convert_clip_rect_to_rect(const struct drm_clip_rect *src,
>   * &drm_plane_state.src as damage.
>   */
>  void drm_atomic_helper_check_plane_damage(struct drm_atomic_commit *state,
> -					  struct drm_plane_state *plane_state)
> +					  const struct drm_plane_state *old_plane_state,
> +					  struct drm_plane_state *new_plane_state)
>  {
>  	struct drm_crtc_state *crtc_state;
>  
> -	if (plane_state->crtc) {
> +	if (!drm_rect_equals(&new_plane_state->src, &old_plane_state->src))
> +		new_plane_state->ignore_damage_clips = true;
> +

[Severity: High]
Will this cause display corruption in drivers that manually read the damage
clips?

The accessors drm_plane_get_damage_clips_count() and
__drm_plane_get_damage_clips() in drivers/gpu/drm/drm_plane.c do not check
the ignore_damage_clips flag. 

If a driver calls them directly, such as AMDGPU in fill_dc_dirty_rects():

    num_clips = drm_plane_get_damage_clips_count(new_plane_state);
    clips = drm_plane_get_damage_clips(new_plane_state);

won't it receive the stale or partial user-provided damage clips instead of
performing a full update when the src coordinates change or during a full
modeset? 

> +	if (new_plane_state->crtc) {
>  		crtc_state = drm_atomic_get_new_crtc_state(state,
> -							   plane_state->crtc);
> +							   new_plane_state->crtc);
>  
>  		if (WARN_ON(!crtc_state))
>  			return;
>  
>  		if (drm_atomic_crtc_needs_modeset(crtc_state))
> -			plane_state->ignore_damage_clips = true;
> +			new_plane_state->ignore_damage_clips = true;
>  	}
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260530185716.65688-1-tzimmermann@suse.de?part=6

^ permalink raw reply

* Re: [PATCH v4 02/10] drm/atomic-helpers: Evaluate plane damage after atomic_check
From: sashiko-bot @ 2026-05-30 19:08 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-hyperv
In-Reply-To: <20260530185716.65688-3-tzimmermann@suse.de>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Modifying `ignore_damage_clips` after `plane->atomic_check` runs invalidates resource allocations based on partial damage clips, leading to heap buffer overflows.
--

commit 395f91f063087b27412023cba7e5d824633a9392
Author: Thomas Zimmermann <tzimmermann@suse.de>

drm/atomic-helpers: Evaluate plane damage after atomic_check

This commit evaluates damage clips after running the atomic_check helpers.
It adds a loop calling drm_atomic_helper_check_plane_damage() after the
driver's plane and CRTC atomic_check hooks have executed. This allows the
damage handling to account for full modesets triggered by the check hooks.

> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 51f39edc31edc..4c37299e8ccb7 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
[ ... ]
> @@ -1065,6 +1065,10 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
>  		}
>  	}
>  
> +	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
> +		drm_atomic_helper_check_plane_damage(state, new_plane_state);
> +	}
> +

[Severity: High]
Does modifying ignore_damage_clips after plane->atomic_check has already
run invalidate resource allocations in drivers that use partial damage clips?

For example, in drivers/gpu/drm/tiny/appletbdrm.c:appletbdrm_primary_plane_helper_atomic_check(),
the driver sizes a buffer precisely to the damage clips evaluated during
atomic_check:

	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, new_plane_state);
	drm_atomic_for_each_plane_damage(&iter, &damage) {
		frames_size += struct_size((struct appletbdrm_frame *)0, buf, rect_size(&damage));
	}
	...
	appletbdrm_state->request = kvzalloc(request_size, GFP_KERNEL);

If a modeset is triggered during the check hooks and this second loop sets
ignore_damage_clips to true, won't drm_atomic_helper_damage_iter_init() later
return a full-screen damage clip during atomic_update? Could this cause the
driver to copy full-screen damage into the buffer allocated only for partial
damage, resulting in a heap buffer overflow?

I understand this is explicitly acknowledged and fixed later in the patch
series by commit 72afced3e1b6baa294269874c7c4d9d05230889c ('drm/appletbdrm:
Allocate request/response buffers in begin_fb_access').

>  	return ret;
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_check_planes);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260530185716.65688-1-tzimmermann@suse.de?part=2

^ permalink raw reply

* Re: [PATCH v4 03/10] drm/ingenic: Remove calls to drm_atomic_helper_check_plane_damage()
From: sashiko-bot @ 2026-05-30 19:05 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-hyperv
In-Reply-To: <20260530185716.65688-4-tzimmermann@suse.de>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Setting `crtc_state->mode_changed = true` inside `plane_atomic_check` without re-calling `drm_atomic_helper_check_modeset()` bypasses necessary modeset validations and state updates, leading to incomplete modesets.
--

commit 0b5b8aa5c5b9f98bc80329fb6bac6de5430060f3
Author: Thomas Zimmermann <tzimmermann@suse.de>

drm/ingenic: Remove calls to drm_atomic_helper_check_plane_damage()

Atomic helpers call drm_atomic_helper_check_plane_damage() after the
atomic_check anyway. Remove the calls from the planes' atomic_check.

> diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
> index 42c86f195c66b..e99b44e3ac923 100644
> --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
> +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
[ ... ]
> @@ -519,9 +519,6 @@ static int ingenic_drm_plane_atomic_check(struct drm_plane *plane,
>  	     old_plane_state->fb->format->format != new_plane_state->fb->format->format))
>  		crtc_state->mode_changed = true;
>  

[Severity: High]
This is a pre-existing issue, but does setting crtc_state->mode_changed to
true here in ingenic_drm_plane_atomic_check() bypass necessary validations?

The DRM core documentation notes that if drivers set mode_changed = true
during the plane check, they must re-call drm_atomic_helper_check_modeset().
Since the ingenic driver assigns drm_atomic_helper_check() directly to its
global .atomic_check hook, check_modeset() runs before check_planes().

If a modeset check is not re-evaluated after planes alter the modeset
requirement, affected connectors and bridges might never be added to the
atomic state via drm_atomic_add_affected_connectors().

Will this cause the display pipeline to skip bridge and encoder modesets
during the commit phase, potentially desynchronizing the output?

> -	if (priv->soc_info->map_noncoherent)
> -		drm_atomic_helper_check_plane_damage(state, new_plane_state);
> -
>  	return 0;
>  }

> diff --git a/drivers/gpu/drm/ingenic/ingenic-ipu.c b/drivers/gpu/drm/ingenic/ingenic-ipu.c
> index 56143a191f361..fd17c642c7ac5 100644
> --- a/drivers/gpu/drm/ingenic/ingenic-ipu.c
> +++ b/drivers/gpu/drm/ingenic/ingenic-ipu.c
[ ... ]
> @@ -611,7 +611,7 @@ static int ingenic_ipu_plane_atomic_check(struct drm_plane *plane,
>  		return -EINVAL;
>  
>  	if (!osd_changed(new_plane_state, old_plane_state))
> -		goto out_check_damage;
> +		return 0;
>  
>  	crtc_state->mode_changed = true;
>  

[Severity: High]
This is also a pre-existing issue, but similar to the above, does setting
crtc_state->mode_changed to true here in ingenic_ipu_plane_atomic_check()
result in the same missing validation?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260530185716.65688-1-tzimmermann@suse.de?part=3

^ permalink raw reply

* [PATCH v4 10/10] drm/vmwgfx: Remove unused field struct vmwgfx_du_update_plane.old_state
From: Thomas Zimmermann @ 2026-05-30 18:53 UTC (permalink / raw)
  To: mripard, maarten.lankhorst, airlied, airlied, simona, admin,
	gargaditya08, paul, jani.nikula, mhklinux, zack.rusin,
	bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann
In-Reply-To: <20260530185716.65688-1-tzimmermann@suse.de>

Plane updates no longer require the old plane state. Remove the field
from struct vmwgfx_du_update_plane and fix all callers.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Zack Rusin <zack.rusin@broadcom.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h  |  2 --
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 12 ++----------
 drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 11 ++---------
 3 files changed, 4 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 2224d7d91d1b..8c2072b82062 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -19,7 +19,6 @@
 /**
  * struct vmw_du_update_plane - Closure structure for vmw_du_helper_plane_update
  * @plane: Plane which is being updated.
- * @old_state: Old state of plane.
  * @dev_priv: Device private.
  * @du: Display unit on which to update the plane.
  * @vfb: Framebuffer which is blitted to display unit.
@@ -102,7 +101,6 @@ struct vmw_du_update_plane {
 				    struct drm_rect *bb);
 
 	struct drm_plane *plane;
-	struct drm_plane_state *old_state;
 	struct vmw_private *dev_priv;
 	struct vmw_display_unit *du;
 	struct vmw_framebuffer *vfb;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index c83061cf7455..fa84bc7ab5bb 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -530,7 +530,6 @@ static uint32_t vmw_stud_bo_post_clip(struct vmw_du_update_plane  *update,
  */
 static int vmw_sou_plane_update_bo(struct vmw_private *dev_priv,
 				   struct drm_plane *plane,
-				   struct drm_plane_state *old_state,
 				   struct vmw_framebuffer *vfb,
 				   struct vmw_fence_obj **out_fence)
 {
@@ -538,7 +537,6 @@ static int vmw_sou_plane_update_bo(struct vmw_private *dev_priv,
 
 	memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer));
 	bo_update.base.plane = plane;
-	bo_update.base.old_state = old_state;
 	bo_update.base.dev_priv = dev_priv;
 	bo_update.base.du = vmw_crtc_to_du(plane->state->crtc);
 	bo_update.base.vfb = vfb;
@@ -692,7 +690,6 @@ static uint32_t vmw_sou_surface_post_clip(struct vmw_du_update_plane *update,
  */
 static int vmw_sou_plane_update_surface(struct vmw_private *dev_priv,
 					struct drm_plane *plane,
-					struct drm_plane_state *old_state,
 					struct vmw_framebuffer *vfb,
 					struct vmw_fence_obj **out_fence)
 {
@@ -700,7 +697,6 @@ static int vmw_sou_plane_update_surface(struct vmw_private *dev_priv,
 
 	memset(&srf_update, 0, sizeof(struct vmw_du_update_plane_surface));
 	srf_update.base.plane = plane;
-	srf_update.base.old_state = old_state;
 	srf_update.base.dev_priv = dev_priv;
 	srf_update.base.du = vmw_crtc_to_du(plane->state->crtc);
 	srf_update.base.vfb = vfb;
@@ -721,7 +717,6 @@ static void
 vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
 				    struct drm_atomic_commit *state)
 {
-	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
 	struct drm_crtc *crtc = new_state->crtc;
 	struct vmw_fence_obj *fence = NULL;
@@ -734,12 +729,9 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
 			vmw_framebuffer_to_vfb(new_state->fb);
 
 		if (vfb->bo)
-			ret = vmw_sou_plane_update_bo(dev_priv, plane,
-						      old_state, vfb, &fence);
+			ret = vmw_sou_plane_update_bo(dev_priv, plane, vfb, &fence);
 		else
-			ret = vmw_sou_plane_update_surface(dev_priv, plane,
-							   old_state, vfb,
-							   &fence);
+			ret = vmw_sou_plane_update_surface(dev_priv, plane, vfb, &fence);
 		if (ret != 0)
 			DRM_ERROR("Failed to update screen.\n");
 	} else {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index f0df2b1c8465..474e3badb80f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -1240,7 +1240,6 @@ vmw_stdu_bo_populate_update_cpu(struct vmw_du_update_plane  *update, void *cmd,
  */
 static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv,
 				    struct drm_plane *plane,
-				    struct drm_plane_state *old_state,
 				    struct vmw_framebuffer *vfb,
 				    struct vmw_fence_obj **out_fence)
 {
@@ -1248,7 +1247,6 @@ static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv,
 
 	memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer));
 	bo_update.base.plane = plane;
-	bo_update.base.old_state = old_state;
 	bo_update.base.dev_priv = dev_priv;
 	bo_update.base.du = vmw_crtc_to_du(plane->state->crtc);
 	bo_update.base.vfb = vfb;
@@ -1350,7 +1348,6 @@ vmw_stdu_surface_populate_update(struct vmw_du_update_plane  *update, void *cmd,
  */
 static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv,
 					 struct drm_plane *plane,
-					 struct drm_plane_state *old_state,
 					 struct vmw_framebuffer *vfb,
 					 struct vmw_fence_obj **out_fence)
 {
@@ -1363,7 +1360,6 @@ static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv,
 
 	memset(&srf_update, 0, sizeof(struct vmw_du_update_plane));
 	srf_update.plane = plane;
-	srf_update.old_state = old_state;
 	srf_update.dev_priv = dev_priv;
 	srf_update.du = vmw_crtc_to_du(plane->state->crtc);
 	srf_update.vfb = vfb;
@@ -1424,12 +1420,9 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
 			DRM_ERROR("Failed to bind surface to STDU.\n");
 
 		if (vfb->bo)
-			ret = vmw_stdu_plane_update_bo(dev_priv, plane,
-						       old_state, vfb, &fence);
+			ret = vmw_stdu_plane_update_bo(dev_priv, plane, vfb, &fence);
 		else
-			ret = vmw_stdu_plane_update_surface(dev_priv, plane,
-							    old_state, vfb,
-							    &fence);
+			ret = vmw_stdu_plane_update_surface(dev_priv, plane, vfb, &fence);
 		if (ret)
 			DRM_ERROR("Failed to update STDU.\n");
 	} else {
-- 
2.54.0


^ permalink raw reply related

* [PATCH v4 09/10] drm/damage-helper: Rename state parameters in damage helpers
From: Thomas Zimmermann @ 2026-05-30 18:53 UTC (permalink / raw)
  To: mripard, maarten.lankhorst, airlied, airlied, simona, admin,
	gargaditya08, paul, jani.nikula, mhklinux, zack.rusin,
	bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann
In-Reply-To: <20260530185716.65688-1-tzimmermann@suse.de>

Rename some of the state parameters of the damage-helper functions to
align them with each other and other helpers. No functional changes.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Zack Rusin <zack.rusin@broadcom.com>
---
 drivers/gpu/drm/drm_damage_helper.c | 20 ++++++++++----------
 include/drm/drm_damage_helper.h     |  4 ++--
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c
index 28b847636253..23701e5c51b7 100644
--- a/drivers/gpu/drm/drm_damage_helper.c
+++ b/drivers/gpu/drm/drm_damage_helper.c
@@ -209,7 +209,7 @@ EXPORT_SYMBOL(drm_atomic_helper_dirtyfb);
 /**
  * drm_atomic_helper_damage_iter_init - Initialize the damage iterator.
  * @iter: The iterator to initialize.
- * @state: Plane state from which to iterate the damage clips.
+ * @plane_state: Plane state from which to iterate the damage clips.
  *
  * Initialize an iterator, which clips plane damage
  * &drm_plane_state.fb_damage_clips to plane &drm_plane_state.src. This iterator
@@ -225,26 +225,26 @@ EXPORT_SYMBOL(drm_atomic_helper_dirtyfb);
  */
 void
 drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
-				   const struct drm_plane_state *state)
+				   const struct drm_plane_state *plane_state)
 {
 	struct drm_rect src;
 	memset(iter, 0, sizeof(*iter));
 
-	if (!state || !state->crtc || !state->fb || !state->visible)
+	if (!plane_state || !plane_state->crtc || !plane_state->fb || !plane_state->visible)
 		return;
 
-	iter->clips = (struct drm_rect *)drm_plane_get_damage_clips(state);
-	iter->num_clips = drm_plane_get_damage_clips_count(state);
+	iter->clips = (struct drm_rect *)drm_plane_get_damage_clips(plane_state);
+	iter->num_clips = drm_plane_get_damage_clips_count(plane_state);
 
 	/* Round down for x1/y1 and round up for x2/y2 to catch all pixels */
-	src = drm_plane_state_src(state);
+	src = drm_plane_state_src(plane_state);
 
 	iter->plane_src.x1 = src.x1 >> 16;
 	iter->plane_src.y1 = src.y1 >> 16;
 	iter->plane_src.x2 = (src.x2 >> 16) + !!(src.x2 & 0xFFFF);
 	iter->plane_src.y2 = (src.y2 >> 16) + !!(src.y2 & 0xFFFF);
 
-	if (!iter->clips || state->ignore_damage_clips) {
+	if (!iter->clips || plane_state->ignore_damage_clips) {
 		iter->clips = NULL;
 		iter->num_clips = 0;
 		iter->full_update = true;
@@ -296,7 +296,7 @@ EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
 
 /**
  * drm_atomic_helper_damage_merged - Merged plane damage
- * @state: Plane state from which to iterate the damage clips.
+ * @plane_state: Plane state from which to iterate the damage clips.
  * @rect: Returns the merged damage rectangle
  *
  * This function merges any valid plane damage clips into one rectangle and
@@ -308,7 +308,7 @@ EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
  * Returns:
  * True if there is valid plane damage otherwise false.
  */
-bool drm_atomic_helper_damage_merged(const struct drm_plane_state *state,
+bool drm_atomic_helper_damage_merged(const struct drm_plane_state *plane_state,
 				     struct drm_rect *rect)
 {
 	struct drm_atomic_helper_damage_iter iter;
@@ -320,7 +320,7 @@ bool drm_atomic_helper_damage_merged(const struct drm_plane_state *state,
 	rect->x2 = 0;
 	rect->y2 = 0;
 
-	drm_atomic_helper_damage_iter_init(&iter, state);
+	drm_atomic_helper_damage_iter_init(&iter, plane_state);
 	drm_atomic_for_each_plane_damage(&iter, &clip) {
 		rect->x1 = min(rect->x1, clip.x1);
 		rect->y1 = min(rect->y1, clip.y1);
diff --git a/include/drm/drm_damage_helper.h b/include/drm/drm_damage_helper.h
index b5a4de779db6..4a1ac47b9051 100644
--- a/include/drm/drm_damage_helper.h
+++ b/include/drm/drm_damage_helper.h
@@ -73,11 +73,11 @@ int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
 			      unsigned int num_clips);
 void
 drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
-				   const struct drm_plane_state *state);
+				   const struct drm_plane_state *plane_state);
 bool
 drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
 				   struct drm_rect *rect);
-bool drm_atomic_helper_damage_merged(const struct drm_plane_state *state,
+bool drm_atomic_helper_damage_merged(const struct drm_plane_state *plane_state,
 				     struct drm_rect *rect);
 
 #endif
-- 
2.54.0


^ permalink raw reply related

* [PATCH v4 07/10] drm/damage-helper: Remove old state from drm_atomic_helper_damage_iter_init()
From: Thomas Zimmermann @ 2026-05-30 18:53 UTC (permalink / raw)
  To: mripard, maarten.lankhorst, airlied, airlied, simona, admin,
	gargaditya08, paul, jani.nikula, mhklinux, zack.rusin,
	bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann
In-Reply-To: <20260530185716.65688-1-tzimmermann@suse.de>

Nothing in drm_atomic_helper_damage_iter_init() requires the old
plane state. Remove the parameter and mass-convert callers.

Most callers now no longer require the old plane state in their plane's
atomic_update helper. Remove it as well.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Zack Rusin <zack.rusin@broadcom.com>
---
 drivers/gpu/drm/ast/ast_mode.c                |  2 +-
 drivers/gpu/drm/drm_damage_helper.c           |  4 +-
 drivers/gpu/drm/drm_fb_dma_helper.c           |  2 +-
 drivers/gpu/drm/gud/gud_pipe.c                |  3 +-
 drivers/gpu/drm/hyperv/hyperv_drm_modeset.c   |  3 +-
 drivers/gpu/drm/mgag200/mgag200_mode.c        |  3 +-
 drivers/gpu/drm/sitronix/st7571.c             |  3 +-
 drivers/gpu/drm/sitronix/st7920.c             |  3 +-
 drivers/gpu/drm/solomon/ssd130x.c             |  9 +--
 drivers/gpu/drm/sysfb/drm_sysfb_modeset.c     |  3 +-
 .../gpu/drm/tests/drm_damage_helper_test.c    | 55 ++++++-------------
 drivers/gpu/drm/tiny/appletbdrm.c             |  8 +--
 drivers/gpu/drm/tiny/bochs.c                  |  3 +-
 drivers/gpu/drm/tiny/cirrus-qemu.c            |  2 +-
 drivers/gpu/drm/udl/udl_modeset.c             |  3 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c           |  5 +-
 include/drm/drm_damage_helper.h               |  3 +-
 17 files changed, 37 insertions(+), 77 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index d5ed8c5c7925..6fe3fda6d145 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -579,7 +579,7 @@ static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane,
 
 	/* if the buffer comes from another device */
 	if (drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE) == 0) {
-		drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+		drm_atomic_helper_damage_iter_init(&iter, plane_state);
 		drm_atomic_for_each_plane_damage(&iter, &damage) {
 			ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage,
 					  &shadow_plane_state->fmtcnv_state);
diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c
index f492a59edbeb..28f26234523d 100644
--- a/drivers/gpu/drm/drm_damage_helper.c
+++ b/drivers/gpu/drm/drm_damage_helper.c
@@ -209,7 +209,6 @@ EXPORT_SYMBOL(drm_atomic_helper_dirtyfb);
 /**
  * drm_atomic_helper_damage_iter_init - Initialize the damage iterator.
  * @iter: The iterator to initialize.
- * @old_state: Unused, pass NULL.
  * @state: Plane state from which to iterate the damage clips.
  *
  * Initialize an iterator, which clips plane damage
@@ -226,7 +225,6 @@ EXPORT_SYMBOL(drm_atomic_helper_dirtyfb);
  */
 void
 drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
-				   const struct drm_plane_state *old_state,
 				   const struct drm_plane_state *state)
 {
 	struct drm_rect src;
@@ -324,7 +322,7 @@ bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state,
 	rect->x2 = 0;
 	rect->y2 = 0;
 
-	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
+	drm_atomic_helper_damage_iter_init(&iter, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip) {
 		rect->x1 = min(rect->x1, clip.x1);
 		rect->y1 = min(rect->y1, clip.y1);
diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c
index fd71969d2fb1..bbad16d32b6f 100644
--- a/drivers/gpu/drm/drm_fb_dma_helper.c
+++ b/drivers/gpu/drm/drm_fb_dma_helper.c
@@ -138,7 +138,7 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm,
 			continue;
 
 		daddr = drm_fb_dma_get_gem_addr(state->fb, state, i);
-		drm_atomic_helper_damage_iter_init(&iter, old_state, state);
+		drm_atomic_helper_damage_iter_init(&iter, state);
 
 		drm_atomic_for_each_plane_damage(&iter, &clip) {
 			/* Ignore x1/x2 values, invalidate complete lines */
diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c
index 5ef887d8485a..758990cd78aa 100644
--- a/drivers/gpu/drm/gud/gud_pipe.c
+++ b/drivers/gpu/drm/gud/gud_pipe.c
@@ -618,7 +618,6 @@ void gud_plane_atomic_update(struct drm_plane *plane,
 {
 	struct drm_device *drm = plane->dev;
 	struct gud_device *gdrm = to_gud_device(drm);
-	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(atomic_state, plane);
 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(atomic_state, plane);
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(new_state);
 	struct drm_framebuffer *fb = new_state->fb;
@@ -647,7 +646,7 @@ void gud_plane_atomic_update(struct drm_plane *plane,
 	if (ret)
 		goto out;
 
-	drm_atomic_helper_damage_iter_init(&iter, old_state, new_state);
+	drm_atomic_helper_damage_iter_init(&iter, new_state);
 	drm_atomic_for_each_plane_damage(&iter, &damage)
 		gud_fb_handle_damage(gdrm, fb, &shadow_plane_state->data[0], &damage);
 
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
index 1bbb7de5ab49..9f74365c4d7e 100644
--- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
+++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
@@ -171,14 +171,13 @@ static void hyperv_plane_atomic_update(struct drm_plane *plane,
 				       struct drm_atomic_commit *state)
 {
 	struct hyperv_drm_device *hv = to_hv(plane->dev);
-	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(new_state);
 	struct drm_rect damage;
 	struct drm_rect dst_clip;
 	struct drm_atomic_helper_damage_iter iter;
 
-	drm_atomic_helper_damage_iter_init(&iter, old_state, new_state);
+	drm_atomic_helper_damage_iter_init(&iter, new_state);
 	drm_atomic_for_each_plane_damage(&iter, &damage) {
 		dst_clip = new_state->dst;
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 7e07fc3f1a60..ea121428adf2 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -503,14 +503,13 @@ void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane,
 	struct drm_device *dev = plane->dev;
 	struct mga_device *mdev = to_mga_device(dev);
 	struct drm_plane_state *plane_state = plane->state;
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane);
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_framebuffer *fb = plane_state->fb;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect damage;
 
 	mgag200_set_datasiz(mdev, fb->format->format);
-	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+	drm_atomic_helper_damage_iter_init(&iter, plane_state);
 	drm_atomic_for_each_plane_damage(&iter, &damage) {
 		mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage);
 	}
diff --git a/drivers/gpu/drm/sitronix/st7571.c b/drivers/gpu/drm/sitronix/st7571.c
index 20954c33eca9..bc0e59c2600c 100644
--- a/drivers/gpu/drm/sitronix/st7571.c
+++ b/drivers/gpu/drm/sitronix/st7571.c
@@ -342,7 +342,6 @@ static int st7571_primary_plane_helper_atomic_check(struct drm_plane *plane,
 static void st7571_primary_plane_helper_atomic_update(struct drm_plane *plane,
 						      struct drm_atomic_commit *state)
 {
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_framebuffer *fb = plane_state->fb;
@@ -362,7 +361,7 @@ static void st7571_primary_plane_helper_atomic_update(struct drm_plane *plane,
 	if (!drm_dev_enter(drm, &idx))
 		goto out_drm_gem_fb_end_cpu_access;
 
-	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+	drm_atomic_helper_damage_iter_init(&iter, plane_state);
 	drm_atomic_for_each_plane_damage(&iter, &damage) {
 		st7571->pformat->prepare_buffer(st7571,
 						&shadow_plane_state->data[0],
diff --git a/drivers/gpu/drm/sitronix/st7920.c b/drivers/gpu/drm/sitronix/st7920.c
index d320391801f3..7ee45a2b2d3e 100644
--- a/drivers/gpu/drm/sitronix/st7920.c
+++ b/drivers/gpu/drm/sitronix/st7920.c
@@ -390,7 +390,6 @@ static void st7920_primary_plane_atomic_update(struct drm_plane *plane,
 					       struct drm_atomic_commit *state)
 {
 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
 	struct st7920_crtc_state *st7920_crtc_state =  to_st7920_crtc_state(crtc_state);
@@ -407,7 +406,7 @@ static void st7920_primary_plane_atomic_update(struct drm_plane *plane,
 		return;
 
 	if (drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE) == 0) {
-		drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+		drm_atomic_helper_damage_iter_init(&iter, plane_state);
 		drm_atomic_for_each_plane_damage(&iter, &damage) {
 			dst_clip = plane_state->dst;
 
diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
index cae92a3ae8a4..4b55532da31b 100644
--- a/drivers/gpu/drm/solomon/ssd130x.c
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -1198,7 +1198,6 @@ static void ssd130x_primary_plane_atomic_update(struct drm_plane *plane,
 						struct drm_atomic_commit *state)
 {
 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
 	struct ssd130x_crtc_state *ssd130x_crtc_state =  to_ssd130x_crtc_state(crtc_state);
@@ -1216,7 +1215,7 @@ static void ssd130x_primary_plane_atomic_update(struct drm_plane *plane,
 	if (drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE))
 		goto out_drm_dev_exit;
 
-	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+	drm_atomic_helper_damage_iter_init(&iter, plane_state);
 	drm_atomic_for_each_plane_damage(&iter, &damage) {
 		dst_clip = plane_state->dst;
 
@@ -1239,7 +1238,6 @@ static void ssd132x_primary_plane_atomic_update(struct drm_plane *plane,
 						struct drm_atomic_commit *state)
 {
 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
 	struct ssd130x_crtc_state *ssd130x_crtc_state =  to_ssd130x_crtc_state(crtc_state);
@@ -1257,7 +1255,7 @@ static void ssd132x_primary_plane_atomic_update(struct drm_plane *plane,
 	if (drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE))
 		goto out_drm_dev_exit;
 
-	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+	drm_atomic_helper_damage_iter_init(&iter, plane_state);
 	drm_atomic_for_each_plane_damage(&iter, &damage) {
 		dst_clip = plane_state->dst;
 
@@ -1280,7 +1278,6 @@ static void ssd133x_primary_plane_atomic_update(struct drm_plane *plane,
 						struct drm_atomic_commit *state)
 {
 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
 	struct ssd130x_crtc_state *ssd130x_crtc_state =  to_ssd130x_crtc_state(crtc_state);
@@ -1297,7 +1294,7 @@ static void ssd133x_primary_plane_atomic_update(struct drm_plane *plane,
 	if (drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE))
 		goto out_drm_dev_exit;
 
-	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+	drm_atomic_helper_damage_iter_init(&iter, plane_state);
 	drm_atomic_for_each_plane_damage(&iter, &damage) {
 		dst_clip = plane_state->dst;
 
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_modeset.c b/drivers/gpu/drm/sysfb/drm_sysfb_modeset.c
index d2de29caf89e..9f1ae5ca9a11 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_modeset.c
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_modeset.c
@@ -331,7 +331,6 @@ void drm_sysfb_plane_helper_atomic_update(struct drm_plane *plane, struct drm_at
 	struct drm_device *dev = plane->dev;
 	struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_sysfb_plane_state *sysfb_plane_state = to_drm_sysfb_plane_state(plane_state);
 	struct drm_shadow_plane_state *shadow_plane_state = &sysfb_plane_state->base;
 	struct drm_framebuffer *fb = plane_state->fb;
@@ -351,7 +350,7 @@ void drm_sysfb_plane_helper_atomic_update(struct drm_plane *plane, struct drm_at
 	if (!drm_dev_enter(dev, &idx))
 		goto out_drm_gem_fb_end_cpu_access;
 
-	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+	drm_atomic_helper_damage_iter_init(&iter, plane_state);
 	drm_atomic_for_each_plane_damage(&iter, &damage) {
 		struct iosys_map dst = sysfb->fb_addr;
 		struct drm_rect dst_clip = plane_state->dst;
diff --git a/drivers/gpu/drm/tests/drm_damage_helper_test.c b/drivers/gpu/drm/tests/drm_damage_helper_test.c
index ef931497baf9..2139ec8b0eb0 100644
--- a/drivers/gpu/drm/tests/drm_damage_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_damage_helper_test.c
@@ -20,7 +20,6 @@ struct drm_damage_mock {
 	struct drm_property prop;
 	struct drm_framebuffer fb;
 	struct drm_plane_state state;
-	struct drm_plane_state old_state;
 };
 
 static int drm_damage_helper_init(struct kunit *test)
@@ -37,7 +36,6 @@ static int drm_damage_helper_init(struct kunit *test)
 	mock->state.fb = &mock->fb;
 	mock->state.visible = true;
 
-	mock->old_state.plane = &mock->plane;
 	mock->state.plane = &mock->plane;
 
 	/* just enough so that drm_plane_enable_fb_damage_clips() works */
@@ -124,9 +122,8 @@ static void drm_test_damage_iter_no_damage(struct kunit *test)
 	u32 num_hits = 0;
 
 	/* Plane src same as fb size. */
-	set_plane_src(&mock->old_state, 0, 0, mock->fb.width << 16, mock->fb.height << 16);
 	set_plane_src(&mock->state, 0, 0, mock->fb.width << 16, mock->fb.height << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -142,11 +139,9 @@ static void drm_test_damage_iter_no_damage_fractional_src(struct kunit *test)
 	u32 num_hits = 0;
 
 	/* Plane src has fractional part. */
-	set_plane_src(&mock->old_state, 0x3fffe, 0x3fffe,
-		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
 	set_plane_src(&mock->state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -164,9 +159,8 @@ static void drm_test_damage_iter_no_damage_not_visible(struct kunit *test)
 
 	mock->state.visible = false;
 
-	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -182,9 +176,8 @@ static void drm_test_damage_iter_no_damage_no_crtc(struct kunit *test)
 
 	mock->state.crtc = NULL;
 
-	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -200,9 +193,8 @@ static void drm_test_damage_iter_no_damage_no_fb(struct kunit *test)
 
 	mock->state.fb = NULL;
 
-	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -218,13 +210,12 @@ static void drm_test_damage_iter_simple_damage(struct kunit *test)
 	struct drm_rect clip;
 	u32 num_hits = 0;
 
-	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
 	/* Damage set to plane src */
 	set_damage_clip(&damage, 0, 0, 1024, 768);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
 	set_plane_damage(&mock->state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -241,12 +232,11 @@ static void drm_test_damage_iter_single_damage(struct kunit *test)
 	struct drm_rect clip;
 	u32 num_hits = 0;
 
-	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
 	set_damage_clip(&damage, 256, 192, 768, 576);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
 	set_plane_damage(&mock->state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -263,13 +253,12 @@ static void drm_test_damage_iter_single_damage_intersect_src(struct kunit *test)
 	struct drm_rect clip;
 	u32 num_hits = 0;
 
-	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
 	/* Damage intersect with plane src. */
 	set_damage_clip(&damage, 256, 192, 1360, 768);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
 	set_plane_damage(&mock->state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -286,13 +275,12 @@ static void drm_test_damage_iter_single_damage_outside_src(struct kunit *test)
 	struct drm_rect clip;
 	u32 num_hits = 0;
 
-	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
 	/* Damage clip outside plane src */
 	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
 	set_plane_damage(&mock->state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -309,14 +297,12 @@ static void drm_test_damage_iter_single_damage_fractional_src(struct kunit *test
 	u32 num_hits = 0;
 
 	/* Plane src has fractional part. */
-	set_plane_src(&mock->old_state, 0x40002, 0x40002,
-		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	set_plane_src(&mock->state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	set_damage_clip(&damage, 10, 10, 256, 330);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
 	set_plane_damage(&mock->state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -334,15 +320,13 @@ static void drm_test_damage_iter_single_damage_intersect_fractional_src(struct k
 	u32 num_hits = 0;
 
 	/* Plane src has fractional part. */
-	set_plane_src(&mock->old_state, 0x40002, 0x40002,
-		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	set_plane_src(&mock->state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	/* Damage intersect with plane src. */
 	set_damage_clip(&damage, 10, 1, 1360, 330);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
 	set_plane_damage(&mock->state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -361,15 +345,13 @@ static void drm_test_damage_iter_single_damage_outside_fractional_src(struct kun
 	u32 num_hits = 0;
 
 	/* Plane src has fractional part. */
-	set_plane_src(&mock->old_state, 0x40002, 0x40002,
-		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	set_plane_src(&mock->state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	/* Damage clip outside plane src */
 	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
 	set_plane_damage(&mock->state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -385,14 +367,13 @@ static void drm_test_damage_iter_damage(struct kunit *test)
 	struct drm_rect clip;
 	u32 num_hits = 0;
 
-	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
 	/* 2 damage clips. */
 	set_damage_clip(&damage[0], 20, 30, 200, 180);
 	set_damage_clip(&damage[1], 240, 200, 280, 250);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
 	set_plane_damage(&mock->state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip) {
 		if (num_hits == 0)
 			check_damage_clip(test, &clip, 20, 30, 200, 180);
@@ -413,8 +394,6 @@ static void drm_test_damage_iter_damage_one_intersect(struct kunit *test)
 	struct drm_rect clip;
 	u32 num_hits = 0;
 
-	set_plane_src(&mock->old_state, 0x40002, 0x40002,
-		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	set_plane_src(&mock->state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	/* 2 damage clips, one intersect plane src. */
@@ -422,7 +401,7 @@ static void drm_test_damage_iter_damage_one_intersect(struct kunit *test)
 	set_damage_clip(&damage[1], 2, 2, 1360, 1360);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
 	set_plane_damage(&mock->state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip) {
 		if (num_hits == 0)
 			check_damage_clip(test, &clip, 20, 30, 200, 180);
@@ -443,14 +422,13 @@ static void drm_test_damage_iter_damage_one_outside(struct kunit *test)
 	struct drm_rect clip;
 	u32 num_hits = 0;
 
-	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
 	/* 2 damage clips, one outside plane src. */
 	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
 	set_damage_clip(&damage[1], 240, 200, 280, 250);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
 	set_plane_damage(&mock->state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -467,7 +445,6 @@ static void drm_test_damage_iter_damage_ignore(struct kunit *test)
 	struct drm_rect clip;
 	u32 num_hits = 0;
 
-	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
 	/* 2 damage clips, but ignore them. */
 	set_damage_clip(&damage[0], 20, 30, 200, 180);
@@ -475,7 +452,7 @@ static void drm_test_damage_iter_damage_ignore(struct kunit *test)
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
 	set_plane_damage(&mock->state, &damage_blob);
 	mock->state.ignore_damage_clips = true;
-	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_helper_damage_iter_init(&iter, &mock->state);
 	drm_atomic_for_each_plane_damage(&iter, &clip) {
 		if (num_hits == 0)
 			check_damage_clip(test, &clip, 0, 0, 1024, 768);
diff --git a/drivers/gpu/drm/tiny/appletbdrm.c b/drivers/gpu/drm/tiny/appletbdrm.c
index b683dcb35b0b..eadc3aed7277 100644
--- a/drivers/gpu/drm/tiny/appletbdrm.c
+++ b/drivers/gpu/drm/tiny/appletbdrm.c
@@ -324,7 +324,7 @@ static int appletbdrm_primary_plane_helper_begin_fb_access(struct drm_plane *pla
 	struct drm_rect damage;
 	size_t request_size;
 
-	drm_atomic_helper_damage_iter_init(&iter, NULL, new_plane_state);
+	drm_atomic_helper_damage_iter_init(&iter, new_plane_state);
 	drm_atomic_for_each_plane_damage(&iter, &damage) {
 		frames_size += struct_size((struct appletbdrm_frame *)0, buf, rect_size(&damage));
 	}
@@ -376,7 +376,6 @@ static int appletbdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
 }
 
 static int appletbdrm_flush_damage(struct appletbdrm_device *adev,
-				   struct drm_plane_state *old_state,
 				   struct drm_plane_state *state)
 {
 	struct appletbdrm_plane_state *appletbdrm_state = to_appletbdrm_plane_state(state);
@@ -412,7 +411,7 @@ static int appletbdrm_flush_damage(struct appletbdrm_device *adev,
 
 	frame = (struct appletbdrm_frame *)request->data;
 
-	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
+	drm_atomic_helper_damage_iter_init(&iter, state);
 	drm_atomic_for_each_plane_damage(&iter, &damage) {
 		struct drm_rect dst_clip = state->dst;
 		struct iosys_map dst = IOSYS_MAP_INIT_VADDR(frame->buf);
@@ -479,13 +478,12 @@ static void appletbdrm_primary_plane_helper_atomic_update(struct drm_plane *plan
 	struct appletbdrm_device *adev = drm_to_adev(plane->dev);
 	struct drm_device *drm = plane->dev;
 	struct drm_plane_state *plane_state = plane->state;
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane);
 	int idx;
 
 	if (!drm_dev_enter(drm, &idx))
 		return;
 
-	appletbdrm_flush_damage(adev, old_plane_state, plane_state);
+	appletbdrm_flush_damage(adev, plane_state);
 
 	drm_dev_exit(idx);
 }
diff --git a/drivers/gpu/drm/tiny/bochs.c b/drivers/gpu/drm/tiny/bochs.c
index e2d957e51505..1e19e98694c0 100644
--- a/drivers/gpu/drm/tiny/bochs.c
+++ b/drivers/gpu/drm/tiny/bochs.c
@@ -447,7 +447,6 @@ static void bochs_primary_plane_helper_atomic_update(struct drm_plane *plane,
 	struct drm_device *dev = plane->dev;
 	struct bochs_device *bochs = to_bochs_device(dev);
 	struct drm_plane_state *plane_state = plane->state;
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_framebuffer *fb = plane_state->fb;
 	struct drm_atomic_helper_damage_iter iter;
@@ -456,7 +455,7 @@ static void bochs_primary_plane_helper_atomic_update(struct drm_plane *plane,
 	if (!fb || !bochs->stride)
 		return;
 
-	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+	drm_atomic_helper_damage_iter_init(&iter, plane_state);
 	drm_atomic_for_each_plane_damage(&iter, &damage) {
 		struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(bochs->fb_map);
 
diff --git a/drivers/gpu/drm/tiny/cirrus-qemu.c b/drivers/gpu/drm/tiny/cirrus-qemu.c
index 075221b431d3..44ffce563e51 100644
--- a/drivers/gpu/drm/tiny/cirrus-qemu.c
+++ b/drivers/gpu/drm/tiny/cirrus-qemu.c
@@ -350,7 +350,7 @@ static void cirrus_primary_plane_helper_atomic_update(struct drm_plane *plane,
 	if (!old_fb || old_fb->pitches[0] != fb->pitches[0])
 		cirrus_pitch_set(cirrus, fb->pitches[0]);
 
-	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+	drm_atomic_helper_damage_iter_init(&iter, plane_state);
 	drm_atomic_for_each_plane_damage(&iter, &damage) {
 		unsigned int offset = drm_fb_clip_offset(fb->pitches[0], fb->format, &damage);
 		struct iosys_map dst = IOSYS_MAP_INIT_OFFSET(&vaddr, offset);
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 289711035b67..ac981ffca5d9 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -286,7 +286,6 @@ static void udl_primary_plane_helper_atomic_update(struct drm_plane *plane,
 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_framebuffer *fb = plane_state->fb;
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect damage;
 	int ret, idx;
@@ -301,7 +300,7 @@ static void udl_primary_plane_helper_atomic_update(struct drm_plane *plane,
 	if (!drm_dev_enter(dev, &idx))
 		goto out_drm_gem_fb_end_cpu_access;
 
-	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+	drm_atomic_helper_damage_iter_init(&iter, plane_state);
 	drm_atomic_for_each_plane_damage(&iter, &damage) {
 		udl_handle_damage(fb, &shadow_plane_state->data[0], &damage);
 	}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 1b407b61f683..32617eb9538e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1733,7 +1733,6 @@ void vmw_kms_lost_device(struct drm_device *dev)
 int vmw_du_helper_plane_update(struct vmw_du_update_plane *update)
 {
 	struct drm_plane_state *state = update->plane->state;
-	struct drm_plane_state *old_state = update->old_state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	struct drm_rect bb;
@@ -1750,7 +1749,7 @@ int vmw_du_helper_plane_update(struct vmw_du_update_plane *update)
 	 * Iterate in advance to check if really need plane update and find the
 	 * number of clips that actually are in plane src for fifo allocation.
 	 */
-	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
+	drm_atomic_helper_damage_iter_init(&iter, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
@@ -1818,7 +1817,7 @@ int vmw_du_helper_plane_update(struct vmw_du_update_plane *update)
 	bb.x2 = INT_MIN;
 	bb.y2 = INT_MIN;
 
-	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
+	drm_atomic_helper_damage_iter_init(&iter, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip) {
 		uint32_t fb_x = clip.x1;
 		uint32_t fb_y = clip.y1;
diff --git a/include/drm/drm_damage_helper.h b/include/drm/drm_damage_helper.h
index e93eaa0fbcb6..fafe29b50fc6 100644
--- a/include/drm/drm_damage_helper.h
+++ b/include/drm/drm_damage_helper.h
@@ -73,8 +73,7 @@ int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
 			      unsigned int num_clips);
 void
 drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
-				   const struct drm_plane_state *old_state,
-				   const struct drm_plane_state *new_state);
+				   const struct drm_plane_state *state);
 bool
 drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
 				   struct drm_rect *rect);
-- 
2.54.0


^ permalink raw reply related

* [PATCH v4 08/10] drm/damage-helper: Remove old state from drm_atomic_helper_damage_merged()
From: Thomas Zimmermann @ 2026-05-30 18:53 UTC (permalink / raw)
  To: mripard, maarten.lankhorst, airlied, airlied, simona, admin,
	gargaditya08, paul, jani.nikula, mhklinux, zack.rusin,
	bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann
In-Reply-To: <20260530185716.65688-1-tzimmermann@suse.de>

Nothing in drm_atomic_helper_damage_merged() requires the old
plane state. Remove the parameter and mass-convert callers.

Most callers now no longer require the old plane state in their plane's
atomic_update helper. Remove it as well.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Zack Rusin <zack.rusin@broadcom.com>
---
 drivers/gpu/drm/ast/ast_cursor.c           |  3 +--
 drivers/gpu/drm/drm_damage_helper.c        |  4 +---
 drivers/gpu/drm/drm_mipi_dbi.c             |  3 +--
 drivers/gpu/drm/i915/display/intel_plane.c | 11 ++---------
 drivers/gpu/drm/i915/display/intel_psr.c   |  3 +--
 drivers/gpu/drm/sitronix/st7586.c          |  3 +--
 drivers/gpu/drm/tiny/gm12u320.c            |  2 +-
 drivers/gpu/drm/tiny/ili9225.c             |  3 +--
 drivers/gpu/drm/tiny/repaper.c             |  2 +-
 drivers/gpu/drm/tiny/sharp-memory.c        |  3 +--
 drivers/gpu/drm/virtio/virtgpu_plane.c     |  2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c       |  4 +---
 include/drm/drm_damage_helper.h            |  3 +--
 13 files changed, 14 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_cursor.c b/drivers/gpu/drm/ast/ast_cursor.c
index fd19c45f2abe..12d5f93eec5f 100644
--- a/drivers/gpu/drm/ast/ast_cursor.c
+++ b/drivers/gpu/drm/ast/ast_cursor.c
@@ -251,7 +251,6 @@ static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane,
 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_framebuffer *fb = plane_state->fb;
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 	struct ast_device *ast = to_ast_device(plane->dev);
 	struct drm_rect damage;
 	u64 dst_off = ast_plane->offset;
@@ -266,7 +265,7 @@ static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane,
 	 * engine to the offset.
 	 */
 
-	if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &damage)) {
+	if (drm_atomic_helper_damage_merged(plane_state, &damage)) {
 		const u8 *argb4444 = ast_cursor_plane_get_argb4444(ast_cursor_plane,
 								   shadow_plane_state,
 								   &damage);
diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c
index 28f26234523d..28b847636253 100644
--- a/drivers/gpu/drm/drm_damage_helper.c
+++ b/drivers/gpu/drm/drm_damage_helper.c
@@ -296,7 +296,6 @@ EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
 
 /**
  * drm_atomic_helper_damage_merged - Merged plane damage
- * @old_state: Old plane state for validation.
  * @state: Plane state from which to iterate the damage clips.
  * @rect: Returns the merged damage rectangle
  *
@@ -309,8 +308,7 @@ EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
  * Returns:
  * True if there is valid plane damage otherwise false.
  */
-bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state,
-				     const struct drm_plane_state *state,
+bool drm_atomic_helper_damage_merged(const struct drm_plane_state *state,
 				     struct drm_rect *rect)
 {
 	struct drm_atomic_helper_damage_iter iter;
diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c
index 25cf04d029f7..4da201c38c93 100644
--- a/drivers/gpu/drm/drm_mipi_dbi.c
+++ b/drivers/gpu/drm/drm_mipi_dbi.c
@@ -380,7 +380,6 @@ void drm_mipi_dbi_plane_helper_atomic_update(struct drm_plane *plane,
 	struct drm_plane_state *plane_state = plane->state;
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_framebuffer *fb = plane_state->fb;
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_rect rect;
 	int idx;
 
@@ -388,7 +387,7 @@ void drm_mipi_dbi_plane_helper_atomic_update(struct drm_plane *plane,
 		return;
 
 	if (drm_dev_enter(plane->dev, &idx)) {
-		if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &rect))
+		if (drm_atomic_helper_damage_merged(plane_state, &rect))
 			mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect,
 					  &shadow_plane_state->fmtcnv_state);
 		drm_dev_exit(idx);
diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c
index 2a52b36c646c..3560e222a3ea 100644
--- a/drivers/gpu/drm/i915/display/intel_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_plane.c
@@ -346,7 +346,6 @@ static void intel_plane_clear_hw_state(struct intel_plane_state *plane_state)
 
 static void
 intel_plane_copy_uapi_plane_damage(struct intel_plane_state *new_plane_state,
-				   const struct intel_plane_state *old_uapi_plane_state,
 				   const struct intel_plane_state *new_uapi_plane_state)
 {
 	struct intel_display *display = to_intel_display(new_plane_state);
@@ -356,10 +355,9 @@ intel_plane_copy_uapi_plane_damage(struct intel_plane_state *new_plane_state,
 	if (DISPLAY_VER(display) < 12)
 		return;
 
-	if (!drm_atomic_helper_damage_merged(&old_uapi_plane_state->uapi,
-					     &new_uapi_plane_state->uapi,
+	if (!drm_atomic_helper_damage_merged(&new_uapi_plane_state->uapi,
 					     damage))
-		/* Incase helper fails, mark whole plane region as damage */
+		/* In case the helper fails, mark whole plane region as damage */
 		*damage = drm_plane_state_src(&new_uapi_plane_state->uapi);
 }
 
@@ -815,7 +813,6 @@ static int plane_atomic_check(struct intel_atomic_state *state,
 	const struct intel_plane_state *old_plane_state =
 		intel_atomic_get_old_plane_state(state, plane);
 	const struct intel_plane_state *new_primary_crtc_plane_state;
-	const struct intel_plane_state *old_primary_crtc_plane_state;
 	struct intel_crtc *crtc = intel_crtc_for_pipe(display, plane->pipe);
 	const struct intel_crtc_state *old_crtc_state =
 		intel_atomic_get_old_crtc_state(state, crtc);
@@ -830,15 +827,11 @@ static int plane_atomic_check(struct intel_atomic_state *state,
 
 		new_primary_crtc_plane_state =
 			intel_atomic_get_new_plane_state(state, primary_crtc_plane);
-		old_primary_crtc_plane_state =
-			intel_atomic_get_old_plane_state(state, primary_crtc_plane);
 	} else {
 		new_primary_crtc_plane_state = new_plane_state;
-		old_primary_crtc_plane_state = old_plane_state;
 	}
 
 	intel_plane_copy_uapi_plane_damage(new_plane_state,
-					   old_primary_crtc_plane_state,
 					   new_primary_crtc_plane_state);
 
 	intel_plane_copy_uapi_to_hw_state(new_plane_state,
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 5047e3fdc9ff..185c065aaebb 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -3015,8 +3015,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
 		src = drm_plane_state_src(&new_plane_state->uapi);
 		drm_rect_fp_to_int(&src, &src);
 
-		if (!drm_atomic_helper_damage_merged(&old_plane_state->uapi,
-						     &new_plane_state->uapi, &damaged_area))
+		if (!drm_atomic_helper_damage_merged(&new_plane_state->uapi, &damaged_area))
 			continue;
 
 		damaged_area.y1 += new_plane_state->uapi.dst.y1 - src.y1;
diff --git a/drivers/gpu/drm/sitronix/st7586.c b/drivers/gpu/drm/sitronix/st7586.c
index 28b2245f6b79..2cc0312595a4 100644
--- a/drivers/gpu/drm/sitronix/st7586.c
+++ b/drivers/gpu/drm/sitronix/st7586.c
@@ -176,7 +176,6 @@ static void st7586_plane_helper_atomic_update(struct drm_plane *plane,
 	struct drm_plane_state *plane_state = plane->state;
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_framebuffer *fb = plane_state->fb;
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_rect rect;
 	int idx;
 
@@ -186,7 +185,7 @@ static void st7586_plane_helper_atomic_update(struct drm_plane *plane,
 	if (!drm_dev_enter(plane->dev, &idx))
 		return;
 
-	if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &rect))
+	if (drm_atomic_helper_damage_merged(plane_state, &rect))
 		st7586_fb_dirty(&shadow_plane_state->data[0], fb, &rect,
 				&shadow_plane_state->fmtcnv_state);
 
diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c
index d73dfebb4353..880b965e283a 100644
--- a/drivers/gpu/drm/tiny/gm12u320.c
+++ b/drivers/gpu/drm/tiny/gm12u320.c
@@ -582,7 +582,7 @@ static void gm12u320_pipe_update(struct drm_simple_display_pipe *pipe,
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
 	struct drm_rect rect;
 
-	if (drm_atomic_helper_damage_merged(old_state, state, &rect))
+	if (drm_atomic_helper_damage_merged(state, &rect))
 		gm12u320_fb_mark_dirty(state->fb, &shadow_plane_state->data[0], &rect);
 }
 
diff --git a/drivers/gpu/drm/tiny/ili9225.c b/drivers/gpu/drm/tiny/ili9225.c
index 5bf52a8fd75b..d821a659a585 100644
--- a/drivers/gpu/drm/tiny/ili9225.c
+++ b/drivers/gpu/drm/tiny/ili9225.c
@@ -185,7 +185,6 @@ static void ili9225_plane_helper_atomic_update(struct drm_plane *plane,
 	struct drm_plane_state *plane_state = plane->state;
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_framebuffer *fb = plane_state->fb;
-	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_rect rect;
 	int idx;
 
@@ -195,7 +194,7 @@ static void ili9225_plane_helper_atomic_update(struct drm_plane *plane,
 	if (!drm_dev_enter(drm, &idx))
 		return;
 
-	if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &rect))
+	if (drm_atomic_helper_damage_merged(plane_state, &rect))
 		ili9225_fb_dirty(&shadow_plane_state->data[0], fb, &rect,
 				 &shadow_plane_state->fmtcnv_state);
 
diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c
index c8270591afc7..531831d2b73f 100644
--- a/drivers/gpu/drm/tiny/repaper.c
+++ b/drivers/gpu/drm/tiny/repaper.c
@@ -837,7 +837,7 @@ static void repaper_pipe_update(struct drm_simple_display_pipe *pipe,
 	if (!pipe->crtc.state->active)
 		return;
 
-	if (drm_atomic_helper_damage_merged(old_state, state, &rect))
+	if (drm_atomic_helper_damage_merged(state, &rect))
 		repaper_fb_dirty(state->fb, shadow_plane_state->data,
 				 &shadow_plane_state->fmtcnv_state);
 }
diff --git a/drivers/gpu/drm/tiny/sharp-memory.c b/drivers/gpu/drm/tiny/sharp-memory.c
index 506e6432e70d..1dacd41ddbaa 100644
--- a/drivers/gpu/drm/tiny/sharp-memory.c
+++ b/drivers/gpu/drm/tiny/sharp-memory.c
@@ -241,7 +241,6 @@ static int sharp_memory_plane_atomic_check(struct drm_plane *plane,
 static void sharp_memory_plane_atomic_update(struct drm_plane *plane,
 					     struct drm_atomic_commit *state)
 {
-	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
 	struct drm_plane_state *plane_state = plane->state;
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct sharp_memory_device *smd;
@@ -251,7 +250,7 @@ static void sharp_memory_plane_atomic_update(struct drm_plane *plane,
 	if (!smd->crtc.state->active)
 		return;
 
-	if (drm_atomic_helper_damage_merged(old_state, plane_state, &rect))
+	if (drm_atomic_helper_damage_merged(plane_state, &rect))
 		sharp_memory_fb_dirty(plane_state->fb, shadow_plane_state->data,
 				      &rect, &shadow_plane_state->fmtcnv_state);
 }
diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c
index 1d1b27ece62a..4728047315a2 100644
--- a/drivers/gpu/drm/virtio/virtgpu_plane.c
+++ b/drivers/gpu/drm/virtio/virtgpu_plane.c
@@ -260,7 +260,7 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
 		return;
 	}
 
-	if (!drm_atomic_helper_damage_merged(old_state, plane->state, &rect))
+	if (!drm_atomic_helper_damage_merged(plane->state, &rect))
 		return;
 
 	bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index 4139837f4caf..f0df2b1c8465 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -977,7 +977,6 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
 	enum stdu_content_type new_content_type;
 	struct vmw_framebuffer_surface *new_vfbs;
 	uint32_t hdisplay = new_state->crtc_w, vdisplay = new_state->crtc_h;
-	struct drm_plane_state *old_state = plane->state;
 	struct drm_rect rect;
 	int ret;
 
@@ -1101,8 +1100,7 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
 		struct vmw_surface *surf = vmw_user_object_surface(&vps->uo);
 		struct vmw_resource *res = &surf->res;
 
-		if (!res->res_dirty && drm_atomic_helper_damage_merged(old_state,
-								       new_state,
+		if (!res->res_dirty && drm_atomic_helper_damage_merged(new_state,
 								       &rect)) {
 			/*
 			 * At some point it might be useful to actually translate
diff --git a/include/drm/drm_damage_helper.h b/include/drm/drm_damage_helper.h
index fafe29b50fc6..b5a4de779db6 100644
--- a/include/drm/drm_damage_helper.h
+++ b/include/drm/drm_damage_helper.h
@@ -77,8 +77,7 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
 bool
 drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
 				   struct drm_rect *rect);
-bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state,
-				     const struct drm_plane_state *state,
+bool drm_atomic_helper_damage_merged(const struct drm_plane_state *state,
 				     struct drm_rect *rect);
 
 #endif
-- 
2.54.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox