* [PATCH 01/29] drm/atomic: Document atomic state lifetime
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:08 ` Thomas Zimmermann
2025-09-02 8:32 ` [PATCH 02/29] drm/atomic: Fix unused but set warning in for_each_old_plane_in_state Maxime Ripard
` (28 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
How drm_atomic_state structures and the various entity structures are
allocated and freed isn't really trivial, so let's document it.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
Documentation/gpu/drm-kms.rst | 6 ++++++
drivers/gpu/drm/drm_atomic.c | 45 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+)
diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
index abfe220764e1edc758a6bc6fb5ff9c8e1c7749ff..dc0f61a3d29e752889077d855a4bea381f2e2c18 100644
--- a/Documentation/gpu/drm-kms.rst
+++ b/Documentation/gpu/drm-kms.rst
@@ -280,10 +280,16 @@ structure, ordering of committing state changes to hardware is sequenced using
:c:type:`struct drm_crtc_commit <drm_crtc_commit>`.
Read on in this chapter, and also in :ref:`drm_atomic_helper` for more detailed
coverage of specific topics.
+Atomic State Lifetime
+---------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
+ :doc: state lifetime
+
Handling Driver Private State
-----------------------------
.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
:doc: handling driver private state
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index cd15cf52f0c9144711da5879da57884674aea9e4..b356d26faad4acaa25c1fe6f9bd5043b6364ce87 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -44,10 +44,55 @@
#include <drm/drm_writeback.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
+/**
+ * DOC: state lifetime
+ *
+ * &struct drm_atomic_state represents an update to video pipeline state.
+ *
+ * Its lifetime is:
+ *
+ * - at reset time, the entity reset implementation will allocate a
+ * new, default, state and will store it in the entity state pointer.
+ *
+ * - whenever a new update is needed:
+ *
+ * + we allocate a new &struct drm_atomic_state using drm_atomic_state_alloc().
+ *
+ * + we copy the state of each affected entity into our &struct
+ * drm_atomic_state using drm_atomic_get_plane_state(),
+ * drm_atomic_get_crtc_state(), drm_atomic_get_connector_state(), or
+ * drm_atomic_get_private_obj_state(). That state can then be
+ * modified.
+ *
+ * At that point, &struct drm_atomic_state stores three state
+ * pointers for that particular entity: the old, new, and existing
+ * (called "state") states. The old state is the state currently
+ * active in the hardware, ie either the one initialized by reset()
+ * or a newer one if a commit has been made. The new state is the
+ * state we just allocated and we might eventually commit to the
+ * hardware. The existing state points to the state we'll eventually
+ * have to free, the new state for now.
+ *
+ * + Once we run a commit, it is first checked and if the check is
+ * successful, it is committed. Part of the commit is a call to
+ * drm_atomic_helper_swap_state() which will turn the new state into
+ * the active state. Doing so involves updating the entity state
+ * pointer (&drm_crtc.state or similar) to point to the new state,
+ * and the existing state will now point to the old state, that used
+ * to be active but isn't anymore.
+ *
+ * + When the commit is done, and when all references to our &struct
+ * drm_atomic_state are put, drm_atomic_state_clear() runs and will
+ * free all the old states.
+ *
+ * + Now, we don't have any active &struct drm_atomic_state anymore,
+ * and only the entity active states remain allocated.
+ */
+
void __drm_crtc_commit_free(struct kref *kref)
{
struct drm_crtc_commit *commit =
container_of(kref, struct drm_crtc_commit, ref);
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 01/29] drm/atomic: Document atomic state lifetime
2025-09-02 8:32 ` [PATCH 01/29] drm/atomic: Document atomic state lifetime Maxime Ripard
@ 2025-09-02 13:08 ` Thomas Zimmermann
2025-09-02 18:59 ` Laurent Pinchart
0 siblings, 1 reply; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:08 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Hi
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> How drm_atomic_state structures and the various entity structures are
> allocated and freed isn't really trivial, so let's document it.
Thanks for doing this.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> Documentation/gpu/drm-kms.rst | 6 ++++++
> drivers/gpu/drm/drm_atomic.c | 45 +++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 51 insertions(+)
>
> diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
> index abfe220764e1edc758a6bc6fb5ff9c8e1c7749ff..dc0f61a3d29e752889077d855a4bea381f2e2c18 100644
> --- a/Documentation/gpu/drm-kms.rst
> +++ b/Documentation/gpu/drm-kms.rst
> @@ -280,10 +280,16 @@ structure, ordering of committing state changes to hardware is sequenced using
> :c:type:`struct drm_crtc_commit <drm_crtc_commit>`.
>
> Read on in this chapter, and also in :ref:`drm_atomic_helper` for more detailed
> coverage of specific topics.
>
> +Atomic State Lifetime
> +---------------------
> +
> +.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
> + :doc: state lifetime
> +
> Handling Driver Private State
> -----------------------------
>
> .. kernel-doc:: drivers/gpu/drm/drm_atomic.c
> :doc: handling driver private state
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index cd15cf52f0c9144711da5879da57884674aea9e4..b356d26faad4acaa25c1fe6f9bd5043b6364ce87 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -44,10 +44,55 @@
> #include <drm/drm_writeback.h>
>
> #include "drm_crtc_internal.h"
> #include "drm_internal.h"
>
> +/**
> + * DOC: state lifetime
> + *
> + * &struct drm_atomic_state represents an update to video pipeline state.
> + *
> + * Its lifetime is:
> + *
> + * - at reset time, the entity reset implementation will allocate a
> + * new, default, state and will store it in the entity state pointer.
Can you somehow mention drm_mode_config_reset() here? 'Reset time' might
be too abstract.
> + *
> + * - whenever a new update is needed:
> + *
> + * + we allocate a new &struct drm_atomic_state using drm_atomic_state_alloc().
> + *
> + * + we copy the state of each affected entity into our &struct
> + * drm_atomic_state using drm_atomic_get_plane_state(),
> + * drm_atomic_get_crtc_state(), drm_atomic_get_connector_state(), or
> + * drm_atomic_get_private_obj_state(). That state can then be
> + * modified.
> + *
> + * At that point, &struct drm_atomic_state stores three state
> + * pointers for that particular entity: the old, new, and existing
> + * (called "state") states. The old state is the state currently
> + * active in the hardware, ie either the one initialized by reset()
'ie' should be replaced by 'which is'. AFAIK ie is used like this:
(i.e., ...).
> + * or a newer one if a commit has been made. The new state is the
> + * state we just allocated and we might eventually commit to the
> + * hardware. The existing state points to the state we'll eventually
> + * have to free, the new state for now.
That final sentence is confusing. What are we doing with the existing
state? Will the old state ever become the existing state? You also never
explain this below.
Maybe only focus on the old and new state for now and explain the
meaning of the existing state in a separate bullet point.
Best regards
Thomas
> + *
> + * + Once we run a commit, it is first checked and if the check is
> + * successful, it is committed. Part of the commit is a call to
> + * drm_atomic_helper_swap_state() which will turn the new state into
> + * the active state. Doing so involves updating the entity state
> + * pointer (&drm_crtc.state or similar) to point to the new state,
> + * and the existing state will now point to the old state, that used
> + * to be active but isn't anymore.
> + *
> + * + When the commit is done, and when all references to our &struct
> + * drm_atomic_state are put, drm_atomic_state_clear() runs and will
> + * free all the old states.
> + *
> + * + Now, we don't have any active &struct drm_atomic_state anymore,
> + * and only the entity active states remain allocated.
> + */
> +
> void __drm_crtc_commit_free(struct kref *kref)
> {
> struct drm_crtc_commit *commit =
> container_of(kref, struct drm_crtc_commit, ref);
>
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 01/29] drm/atomic: Document atomic state lifetime
2025-09-02 13:08 ` Thomas Zimmermann
@ 2025-09-02 18:59 ` Laurent Pinchart
0 siblings, 0 replies; 57+ messages in thread
From: Laurent Pinchart @ 2025-09-02 18:59 UTC (permalink / raw)
To: Thomas Zimmermann
Cc: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
Jernej Skrabec, Jyri Sarha, Tomi Valkeinen, Devarsh Thakkar,
dri-devel, linux-kernel
On Tue, Sep 02, 2025 at 03:08:12PM +0200, Thomas Zimmermann wrote:
> Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> > How drm_atomic_state structures and the various entity structures are
"entity" isn't commonly used in this sense in DRM/KMS. "object" is the
best term I can think so, even if some DRM objects (in the
drm_mode_object sense) are out of scope in this context. Same below
where you use "entity".
> > allocated and freed isn't really trivial, so let's document it.
>
> Thanks for doing this.
>
> > Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > ---
> > Documentation/gpu/drm-kms.rst | 6 ++++++
> > drivers/gpu/drm/drm_atomic.c | 45 +++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 51 insertions(+)
> >
> > diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
> > index abfe220764e1edc758a6bc6fb5ff9c8e1c7749ff..dc0f61a3d29e752889077d855a4bea381f2e2c18 100644
> > --- a/Documentation/gpu/drm-kms.rst
> > +++ b/Documentation/gpu/drm-kms.rst
> > @@ -280,10 +280,16 @@ structure, ordering of committing state changes to hardware is sequenced using
> > :c:type:`struct drm_crtc_commit <drm_crtc_commit>`.
> >
> > Read on in this chapter, and also in :ref:`drm_atomic_helper` for more detailed
> > coverage of specific topics.
> >
> > +Atomic State Lifetime
> > +---------------------
> > +
> > +.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
> > + :doc: state lifetime
> > +
> > Handling Driver Private State
> > -----------------------------
> >
> > .. kernel-doc:: drivers/gpu/drm/drm_atomic.c
> > :doc: handling driver private state
> > diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > index cd15cf52f0c9144711da5879da57884674aea9e4..b356d26faad4acaa25c1fe6f9bd5043b6364ce87 100644
> > --- a/drivers/gpu/drm/drm_atomic.c
> > +++ b/drivers/gpu/drm/drm_atomic.c
> > @@ -44,10 +44,55 @@
> > #include <drm/drm_writeback.h>
> >
> > #include "drm_crtc_internal.h"
> > #include "drm_internal.h"
> >
> > +/**
> > + * DOC: state lifetime
> > + *
> > + * &struct drm_atomic_state represents an update to video pipeline state.
> > + *
> > + * Its lifetime is:
This indicates you'll talk about the lifetime of drm_atomic_state
itself, while the text below also covers the lifetime of the state of
the individual objects. This is a bit confusing. One of the important
aspects that I think you should document is that drm_atomic_state is a
transient object that holds a state update (I once proposed renaming it
to drm_atomic_commit, and to my surprise the idea wasn't rejected right
away, but it would cause lots of churn) in the form of pointers to
individual objects' states, and only exists for the duration of an
atomic commit operation, while object states have a different lifetime.
> > + *
> > + * - at reset time, the entity reset implementation will allocate a
> > + * new, default, state and will store it in the entity state pointer.
Strictly speaking, this isn't related to the drm_atomic_state lifetime.
> Can you somehow mention drm_mode_config_reset() here? 'Reset time' might
> be too abstract.
>
> > + *
> > + * - whenever a new update is needed:
> > + *
> > + * + we allocate a new &struct drm_atomic_state using drm_atomic_state_alloc().
> > + *
> > + * + we copy the state of each affected entity into our &struct
> > + * drm_atomic_state using drm_atomic_get_plane_state(),
> > + * drm_atomic_get_crtc_state(), drm_atomic_get_connector_state(), or
> > + * drm_atomic_get_private_obj_state(). That state can then be
> > + * modified.
> > + *
> > + * At that point, &struct drm_atomic_state stores three state
> > + * pointers for that particular entity: the old, new, and existing
> > + * (called "state") states. The old state is the state currently
> > + * active in the hardware, ie either the one initialized by reset()
>
> 'ie' should be replaced by 'which is'. AFAIK ie is used like this:
> (i.e., ...).
>
> > + * or a newer one if a commit has been made. The new state is the
> > + * state we just allocated and we might eventually commit to the
> > + * hardware. The existing state points to the state we'll eventually
> > + * have to free, the new state for now.
>
> That final sentence is confusing. What are we doing with the existing
> state? Will the old state ever become the existing state? You also never
> explain this below.
>
> Maybe only focus on the old and new state for now and explain the
> meaning of the existing state in a separate bullet point.
I agree, the documentation here is clear for someone who knows exactly
how things work, but quite confusing for a newcomer.
> > + *
> > + * + Once we run a commit, it is first checked and if the check is
> > + * successful, it is committed. Part of the commit is a call to
"Committing a commit" sounds weird. As you define the atomic state above
as "an update to video pipeline state", I would write
After the state is populated, it is checked. If the check is successful, the
state update is then committed.
> > + * drm_atomic_helper_swap_state() which will turn the new state into
> > + * the active state. Doing so involves updating the entity state
> > + * pointer (&drm_crtc.state or similar) to point to the new state,
> > + * and the existing state will now point to the old state, that used
> > + * to be active but isn't anymore.
> > + *
> > + * + When the commit is done, and when all references to our &struct
> > + * drm_atomic_state are put, drm_atomic_state_clear() runs and will
> > + * free all the old states.
> > + *
> > + * + Now, we don't have any active &struct drm_atomic_state anymore,
> > + * and only the entity active states remain allocated.
> > + */
> > +
> > void __drm_crtc_commit_free(struct kref *kref)
> > {
> > struct drm_crtc_commit *commit =
> > container_of(kref, struct drm_crtc_commit, ref);
> >
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/29] drm/atomic: Fix unused but set warning in for_each_old_plane_in_state
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
2025-09-02 8:32 ` [PATCH 01/29] drm/atomic: Document atomic state lifetime Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:10 ` Thomas Zimmermann
2025-09-02 19:25 ` Laurent Pinchart
2025-09-02 8:32 ` [PATCH 03/29] drm/atomic: Fix unused but set warning in for_each_old_private_obj_in_state Maxime Ripard
` (27 subsequent siblings)
29 siblings, 2 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The for_each_old_plane_in_state() macro triggers a compiler warning if
the plane parameter passed to it isn't used in the code block.
Add a similar workaround than in most other macros.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
include/drm/drm_atomic.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 38636a593c9d98cadda85ccd67326cb152f0dd27..689a29bdeb4a06672ab6fffecb513d58ff6e07f9 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -1053,11 +1053,13 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
for ((__i) = 0; \
(__i) < (__state)->dev->mode_config.num_total_plane; \
(__i)++) \
for_each_if ((__state)->planes[__i].ptr && \
((plane) = (__state)->planes[__i].ptr, \
+ (void)(plane) /* Only to avoid unused-but-set-variable warning */, \
(old_plane_state) = (__state)->planes[__i].old_state, 1))
+
/**
* for_each_new_plane_in_state - iterate over all planes in an atomic update
* @__state: &struct drm_atomic_state pointer
* @plane: &struct drm_plane iteration cursor
* @new_plane_state: &struct drm_plane_state iteration cursor for the new state
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 02/29] drm/atomic: Fix unused but set warning in for_each_old_plane_in_state
2025-09-02 8:32 ` [PATCH 02/29] drm/atomic: Fix unused but set warning in for_each_old_plane_in_state Maxime Ripard
@ 2025-09-02 13:10 ` Thomas Zimmermann
2025-09-02 19:25 ` Laurent Pinchart
1 sibling, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:10 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Hi
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> The for_each_old_plane_in_state() macro triggers a compiler warning if
> the plane parameter passed to it isn't used in the code block.
>
> Add a similar workaround than in most other macros.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
This patch should probably get merged in any case
Best regards
Thomas
> ---
> include/drm/drm_atomic.h | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 38636a593c9d98cadda85ccd67326cb152f0dd27..689a29bdeb4a06672ab6fffecb513d58ff6e07f9 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -1053,11 +1053,13 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
> for ((__i) = 0; \
> (__i) < (__state)->dev->mode_config.num_total_plane; \
> (__i)++) \
> for_each_if ((__state)->planes[__i].ptr && \
> ((plane) = (__state)->planes[__i].ptr, \
> + (void)(plane) /* Only to avoid unused-but-set-variable warning */, \
> (old_plane_state) = (__state)->planes[__i].old_state, 1))
> +
> /**
> * for_each_new_plane_in_state - iterate over all planes in an atomic update
> * @__state: &struct drm_atomic_state pointer
> * @plane: &struct drm_plane iteration cursor
> * @new_plane_state: &struct drm_plane_state iteration cursor for the new state
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/29] drm/atomic: Fix unused but set warning in for_each_old_plane_in_state
2025-09-02 8:32 ` [PATCH 02/29] drm/atomic: Fix unused but set warning in for_each_old_plane_in_state Maxime Ripard
2025-09-02 13:10 ` Thomas Zimmermann
@ 2025-09-02 19:25 ` Laurent Pinchart
1 sibling, 0 replies; 57+ messages in thread
From: Laurent Pinchart @ 2025-09-02 19:25 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
Jernej Skrabec, Jyri Sarha, Tomi Valkeinen, Devarsh Thakkar,
dri-devel, linux-kernel
Hi Maxime,
Thank you for the patch.
On Tue, Sep 02, 2025 at 10:32:30AM +0200, Maxime Ripard wrote:
> The for_each_old_plane_in_state() macro triggers a compiler warning if
> the plane parameter passed to it isn't used in the code block.
>
> Add a similar workaround than in most other macros.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> include/drm/drm_atomic.h | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 38636a593c9d98cadda85ccd67326cb152f0dd27..689a29bdeb4a06672ab6fffecb513d58ff6e07f9 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -1053,11 +1053,13 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
> for ((__i) = 0; \
> (__i) < (__state)->dev->mode_config.num_total_plane; \
> (__i)++) \
> for_each_if ((__state)->planes[__i].ptr && \
> ((plane) = (__state)->planes[__i].ptr, \
> + (void)(plane) /* Only to avoid unused-but-set-variable warning */, \
> (old_plane_state) = (__state)->planes[__i].old_state, 1))
> +
While at it, shouldn't you apply the same workaround to the
old_plane_state variable, like done for new_plane_state in
for_each_new_plane_in_state() ? Or is it expected that drivers will
always make use of it.
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> /**
> * for_each_new_plane_in_state - iterate over all planes in an atomic update
> * @__state: &struct drm_atomic_state pointer
> * @plane: &struct drm_plane iteration cursor
> * @new_plane_state: &struct drm_plane_state iteration cursor for the new state
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 03/29] drm/atomic: Fix unused but set warning in for_each_old_private_obj_in_state
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
2025-09-02 8:32 ` [PATCH 01/29] drm/atomic: Document atomic state lifetime Maxime Ripard
2025-09-02 8:32 ` [PATCH 02/29] drm/atomic: Fix unused but set warning in for_each_old_plane_in_state Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:10 ` Thomas Zimmermann
2025-09-02 19:26 ` Laurent Pinchart
2025-09-02 8:32 ` [PATCH 04/29] drm/atomic_helper: Skip over NULL private_obj pointers Maxime Ripard
` (26 subsequent siblings)
29 siblings, 2 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The for_each_old_private_obj_in_state() macro triggers a compiler
warning if the obj parameter passed to it isn't used in the code block.
Add a similar workaround than in most other macros.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
include/drm/drm_atomic.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 689a29bdeb4a06672ab6fffecb513d58ff6e07f9..f13f926d21047e42bb9ac692c2dd4b88f2ebd91c 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -1112,10 +1112,11 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
*/
#define for_each_old_private_obj_in_state(__state, obj, old_obj_state, __i) \
for ((__i) = 0; \
(__i) < (__state)->num_private_objs && \
((obj) = (__state)->private_objs[__i].ptr, \
+ (void)(obj) /* Only to avoid unused-but-set-variable warning */, \
(old_obj_state) = (__state)->private_objs[__i].old_state, 1); \
(__i)++)
/**
* for_each_new_private_obj_in_state - iterate over all private objects in an atomic update
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 03/29] drm/atomic: Fix unused but set warning in for_each_old_private_obj_in_state
2025-09-02 8:32 ` [PATCH 03/29] drm/atomic: Fix unused but set warning in for_each_old_private_obj_in_state Maxime Ripard
@ 2025-09-02 13:10 ` Thomas Zimmermann
2025-09-02 19:26 ` Laurent Pinchart
1 sibling, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:10 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> The for_each_old_private_obj_in_state() macro triggers a compiler
> warning if the obj parameter passed to it isn't used in the code block.
>
> Add a similar workaround than in most other macros.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> include/drm/drm_atomic.h | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 689a29bdeb4a06672ab6fffecb513d58ff6e07f9..f13f926d21047e42bb9ac692c2dd4b88f2ebd91c 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -1112,10 +1112,11 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
> */
> #define for_each_old_private_obj_in_state(__state, obj, old_obj_state, __i) \
> for ((__i) = 0; \
> (__i) < (__state)->num_private_objs && \
> ((obj) = (__state)->private_objs[__i].ptr, \
> + (void)(obj) /* Only to avoid unused-but-set-variable warning */, \
> (old_obj_state) = (__state)->private_objs[__i].old_state, 1); \
> (__i)++)
>
> /**
> * for_each_new_private_obj_in_state - iterate over all private objects in an atomic update
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 03/29] drm/atomic: Fix unused but set warning in for_each_old_private_obj_in_state
2025-09-02 8:32 ` [PATCH 03/29] drm/atomic: Fix unused but set warning in for_each_old_private_obj_in_state Maxime Ripard
2025-09-02 13:10 ` Thomas Zimmermann
@ 2025-09-02 19:26 ` Laurent Pinchart
1 sibling, 0 replies; 57+ messages in thread
From: Laurent Pinchart @ 2025-09-02 19:26 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
Jernej Skrabec, Jyri Sarha, Tomi Valkeinen, Devarsh Thakkar,
dri-devel, linux-kernel
Hi Maxime,
Thank you for the patch.
On Tue, Sep 02, 2025 at 10:32:31AM +0200, Maxime Ripard wrote:
> The for_each_old_private_obj_in_state() macro triggers a compiler
> warning if the obj parameter passed to it isn't used in the code block.
>
> Add a similar workaround than in most other macros.
>
I'd squash this with the previous patch, and also address the other
similar macros.
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> include/drm/drm_atomic.h | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 689a29bdeb4a06672ab6fffecb513d58ff6e07f9..f13f926d21047e42bb9ac692c2dd4b88f2ebd91c 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -1112,10 +1112,11 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
> */
> #define for_each_old_private_obj_in_state(__state, obj, old_obj_state, __i) \
> for ((__i) = 0; \
> (__i) < (__state)->num_private_objs && \
> ((obj) = (__state)->private_objs[__i].ptr, \
> + (void)(obj) /* Only to avoid unused-but-set-variable warning */, \
> (old_obj_state) = (__state)->private_objs[__i].old_state, 1); \
> (__i)++)
>
> /**
> * for_each_new_private_obj_in_state - iterate over all private objects in an atomic update
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 04/29] drm/atomic_helper: Skip over NULL private_obj pointers
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (2 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 03/29] drm/atomic: Fix unused but set warning in for_each_old_private_obj_in_state Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:13 ` Thomas Zimmermann
2025-09-02 8:32 ` [PATCH 05/29] drm/atomic_state_helper: Fix bridge state initialization Maxime Ripard
` (25 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index b356d26faad4acaa25c1fe6f9bd5043b6364ce87..9b198610791d19c7fd276ca59264a961d21caf43 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -295,10 +295,13 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
}
for (i = 0; i < state->num_private_objs; i++) {
struct drm_private_obj *obj = state->private_objs[i].ptr;
+ if (!obj)
+ continue;
+
obj->funcs->atomic_destroy_state(obj,
state->private_objs[i].state);
state->private_objs[i].ptr = NULL;
state->private_objs[i].state = NULL;
state->private_objs[i].old_state = NULL;
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 04/29] drm/atomic_helper: Skip over NULL private_obj pointers
2025-09-02 8:32 ` [PATCH 04/29] drm/atomic_helper: Skip over NULL private_obj pointers Maxime Ripard
@ 2025-09-02 13:13 ` Thomas Zimmermann
2025-09-02 19:29 ` Laurent Pinchart
0 siblings, 1 reply; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:13 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
However, can this happen? Private state objects without state data?
Best regards
Thomas
> ---
> drivers/gpu/drm/drm_atomic.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index b356d26faad4acaa25c1fe6f9bd5043b6364ce87..9b198610791d19c7fd276ca59264a961d21caf43 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -295,10 +295,13 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
> }
>
> for (i = 0; i < state->num_private_objs; i++) {
> struct drm_private_obj *obj = state->private_objs[i].ptr;
>
> + if (!obj)
> + continue;
> +
> obj->funcs->atomic_destroy_state(obj,
> state->private_objs[i].state);
> state->private_objs[i].ptr = NULL;
> state->private_objs[i].state = NULL;
> state->private_objs[i].old_state = NULL;
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 04/29] drm/atomic_helper: Skip over NULL private_obj pointers
2025-09-02 13:13 ` Thomas Zimmermann
@ 2025-09-02 19:29 ` Laurent Pinchart
0 siblings, 0 replies; 57+ messages in thread
From: Laurent Pinchart @ 2025-09-02 19:29 UTC (permalink / raw)
To: Thomas Zimmermann
Cc: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
Jernej Skrabec, Jyri Sarha, Tomi Valkeinen, Devarsh Thakkar,
dri-devel, linux-kernel
On Tue, Sep 02, 2025 at 03:13:30PM +0200, Thomas Zimmermann wrote:
> Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> > Signed-off-by: Maxime Ripard <mripard@kernel.org>
>
> Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
>
> However, can this happen? Private state objects without state data?
I was going to ask the same. The commit message should explain why.
> > ---
> > drivers/gpu/drm/drm_atomic.c | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > index b356d26faad4acaa25c1fe6f9bd5043b6364ce87..9b198610791d19c7fd276ca59264a961d21caf43 100644
> > --- a/drivers/gpu/drm/drm_atomic.c
> > +++ b/drivers/gpu/drm/drm_atomic.c
> > @@ -295,10 +295,13 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
> > }
> >
> > for (i = 0; i < state->num_private_objs; i++) {
> > struct drm_private_obj *obj = state->private_objs[i].ptr;
> >
> > + if (!obj)
> > + continue;
> > +
> > obj->funcs->atomic_destroy_state(obj,
> > state->private_objs[i].state);
> > state->private_objs[i].ptr = NULL;
> > state->private_objs[i].state = NULL;
> > state->private_objs[i].old_state = NULL;
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 05/29] drm/atomic_state_helper: Fix bridge state initialization
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (3 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 04/29] drm/atomic_helper: Skip over NULL private_obj pointers Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:18 ` Thomas Zimmermann
2025-09-02 19:49 ` Laurent Pinchart
2025-09-02 8:32 ` [PATCH 06/29] drm/bridge: Implement atomic_print_state Maxime Ripard
` (24 subsequent siblings)
29 siblings, 2 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
Bridges implement their state using a drm_private_obj and an
hand-crafted reset implementation.
Since drm_private_obj doesn't have a set of reset helper like the other
states, __drm_atomic_helper_bridge_reset() was initializing both the
drm_private_state and the drm_bridge_state structures.
This initialization however was missing the drm_private_state.obj
pointer to the drm_private_obj the state was allocated for, creating a
NULL pointer dereference when trying to access it.
Fixes: 751465913f04 ("drm/bridge: Add a drm_bridge_state object")
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index 7142e163e618ea0d7d9d828e1bd9ff2a6ec0dfeb..b962c342b16aabf4e3bea52a914e5deb1c2080ce 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -707,10 +707,17 @@ void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
__drm_atomic_helper_connector_destroy_state(state);
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
+static void __drm_atomic_helper_private_obj_reset(struct drm_private_obj *obj,
+ struct drm_private_state *state)
+{
+ memset(state, 0, sizeof(*state));
+ state->obj = obj;
+}
+
/**
* __drm_atomic_helper_private_obj_duplicate_state - copy atomic private state
* @obj: CRTC object
* @state: new private object state
*
@@ -796,10 +803,11 @@ EXPORT_SYMBOL(drm_atomic_helper_bridge_destroy_state);
*/
void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
struct drm_bridge_state *state)
{
memset(state, 0, sizeof(*state));
+ __drm_atomic_helper_private_obj_reset(&bridge->base, &state->base);
state->bridge = bridge;
}
EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset);
/**
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 05/29] drm/atomic_state_helper: Fix bridge state initialization
2025-09-02 8:32 ` [PATCH 05/29] drm/atomic_state_helper: Fix bridge state initialization Maxime Ripard
@ 2025-09-02 13:18 ` Thomas Zimmermann
2025-09-02 19:49 ` Laurent Pinchart
1 sibling, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:18 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Hi
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> Bridges implement their state using a drm_private_obj and an
> hand-crafted reset implementation.
>
> Since drm_private_obj doesn't have a set of reset helper like the other
> states, __drm_atomic_helper_bridge_reset() was initializing both the
> drm_private_state and the drm_bridge_state structures.
>
> This initialization however was missing the drm_private_state.obj
> pointer to the drm_private_obj the state was allocated for, creating a
> NULL pointer dereference when trying to access it.
>
> Fixes: 751465913f04 ("drm/bridge: Add a drm_bridge_state object")
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> drivers/gpu/drm/drm_atomic_state_helper.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
> index 7142e163e618ea0d7d9d828e1bd9ff2a6ec0dfeb..b962c342b16aabf4e3bea52a914e5deb1c2080ce 100644
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> @@ -707,10 +707,17 @@ void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
> __drm_atomic_helper_connector_destroy_state(state);
> kfree(state);
> }
> EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
>
> +static void __drm_atomic_helper_private_obj_reset(struct drm_private_obj *obj,
> + struct drm_private_state *state)
> +{
> + memset(state, 0, sizeof(*state));
This argument is guaranteed to be zero'd, I think. No need for a memset.
> + state->obj = obj;
> +}
> +
> /**
> * __drm_atomic_helper_private_obj_duplicate_state - copy atomic private state
> * @obj: CRTC object
> * @state: new private object state
> *
> @@ -796,10 +803,11 @@ EXPORT_SYMBOL(drm_atomic_helper_bridge_destroy_state);
> */
> void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
> struct drm_bridge_state *state)
> {
> memset(state, 0, sizeof(*state));
Another unnecessary memset?
Best regards
Thomas
> + __drm_atomic_helper_private_obj_reset(&bridge->base, &state->base);
> state->bridge = bridge;
> }
> EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset);
>
> /**
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 05/29] drm/atomic_state_helper: Fix bridge state initialization
2025-09-02 8:32 ` [PATCH 05/29] drm/atomic_state_helper: Fix bridge state initialization Maxime Ripard
2025-09-02 13:18 ` Thomas Zimmermann
@ 2025-09-02 19:49 ` Laurent Pinchart
1 sibling, 0 replies; 57+ messages in thread
From: Laurent Pinchart @ 2025-09-02 19:49 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
Jernej Skrabec, Jyri Sarha, Tomi Valkeinen, Devarsh Thakkar,
dri-devel, linux-kernel
Hi Maxime,
On Tue, Sep 02, 2025 at 10:32:33AM +0200, Maxime Ripard wrote:
> Bridges implement their state using a drm_private_obj and an
s/and an/and a/
> hand-crafted reset implementation.
>
> Since drm_private_obj doesn't have a set of reset helper like the other
> states, __drm_atomic_helper_bridge_reset() was initializing both the
s/was initializing/initializes/
> drm_private_state and the drm_bridge_state structures.
>
> This initialization however was missing the drm_private_state.obj
s/was missing/is missing/
Or do I incorrectly think that the commit message should describe the
current situation in the present tense ?
> pointer to the drm_private_obj the state was allocated for, creating a
> NULL pointer dereference when trying to access it.
>
> Fixes: 751465913f04 ("drm/bridge: Add a drm_bridge_state object")
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> drivers/gpu/drm/drm_atomic_state_helper.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
> index 7142e163e618ea0d7d9d828e1bd9ff2a6ec0dfeb..b962c342b16aabf4e3bea52a914e5deb1c2080ce 100644
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> @@ -707,10 +707,17 @@ void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
> __drm_atomic_helper_connector_destroy_state(state);
> kfree(state);
> }
> EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
>
> +static void __drm_atomic_helper_private_obj_reset(struct drm_private_obj *obj,
> + struct drm_private_state *state)
> +{
> + memset(state, 0, sizeof(*state));
As Thomas mentioned, the memset is likely not needed.
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> + state->obj = obj;
> +}
> +
> /**
> * __drm_atomic_helper_private_obj_duplicate_state - copy atomic private state
> * @obj: CRTC object
> * @state: new private object state
> *
> @@ -796,10 +803,11 @@ EXPORT_SYMBOL(drm_atomic_helper_bridge_destroy_state);
> */
> void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
> struct drm_bridge_state *state)
> {
> memset(state, 0, sizeof(*state));
> + __drm_atomic_helper_private_obj_reset(&bridge->base, &state->base);
> state->bridge = bridge;
> }
> EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset);
>
> /**
>
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 06/29] drm/bridge: Implement atomic_print_state
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (4 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 05/29] drm/atomic_state_helper: Fix bridge state initialization Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:22 ` Thomas Zimmermann
2025-09-02 8:32 ` [PATCH 07/29] drm/atomic: Implement drm_atomic_print_old_state Maxime Ripard
` (23 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
Bridges have some fields in their state worth printing, but we don't
provide an atomic_print_state implementation to show those fields.
Let's do so.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_bridge.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index dd439d55177a867acb7ab73c02182bada44d93c9..e803dfd8fd5aae9c16931445213df04d8715b9f6 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -370,13 +370,31 @@ drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj,
struct drm_bridge *bridge = drm_priv_to_bridge(obj);
bridge->funcs->atomic_destroy_state(bridge, state);
}
+static void
+drm_bridge_atomic_print_priv_state(struct drm_printer *p,
+ const struct drm_private_state *s)
+{
+ const struct drm_bridge_state *state =
+ container_of_const(s, struct drm_bridge_state, base);
+ struct drm_bridge *bridge = drm_priv_to_bridge(s->obj);
+
+ drm_printf(p, "bridge: %s", drm_get_connector_type_name(bridge->type));
+ drm_printf(p, "\tinput bus configuration:");
+ drm_printf(p, "\t\tcode: %04x", state->input_bus_cfg.format);
+ drm_printf(p, "\t\tflags: %08x", state->input_bus_cfg.flags);
+ drm_printf(p, "\toutput bus configuration:");
+ drm_printf(p, "\t\tcode: %04x", state->output_bus_cfg.format);
+ drm_printf(p, "\t\tflags: %08x", state->output_bus_cfg.flags);
+}
+
static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
.atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
.atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
+ .atomic_print_state = drm_bridge_atomic_print_priv_state,
};
static bool drm_bridge_is_atomic(struct drm_bridge *bridge)
{
return bridge->funcs->atomic_reset != NULL;
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 06/29] drm/bridge: Implement atomic_print_state
2025-09-02 8:32 ` [PATCH 06/29] drm/bridge: Implement atomic_print_state Maxime Ripard
@ 2025-09-02 13:22 ` Thomas Zimmermann
2025-09-02 20:22 ` Laurent Pinchart
0 siblings, 1 reply; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:22 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Hi
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> Bridges have some fields in their state worth printing, but we don't
> provide an atomic_print_state implementation to show those fields.
>
> Let's do so.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> drivers/gpu/drm/drm_bridge.c | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index dd439d55177a867acb7ab73c02182bada44d93c9..e803dfd8fd5aae9c16931445213df04d8715b9f6 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -370,13 +370,31 @@ drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj,
> struct drm_bridge *bridge = drm_priv_to_bridge(obj);
>
> bridge->funcs->atomic_destroy_state(bridge, state);
> }
>
> +static void
> +drm_bridge_atomic_print_priv_state(struct drm_printer *p,
> + const struct drm_private_state *s)
> +{
> + const struct drm_bridge_state *state =
> + container_of_const(s, struct drm_bridge_state, base);
Maybe adopt drm_priv_to_bridge_state() to accept const pointers?
https://elixir.bootlin.com/linux/v6.16.4/source/include/drm/drm_atomic.h#L1236
> + struct drm_bridge *bridge = drm_priv_to_bridge(s->obj);
> +
> + drm_printf(p, "bridge: %s", drm_get_connector_type_name(bridge->type));
> + drm_printf(p, "\tinput bus configuration:");
> + drm_printf(p, "\t\tcode: %04x", state->input_bus_cfg.format);
> + drm_printf(p, "\t\tflags: %08x", state->input_bus_cfg.flags);
> + drm_printf(p, "\toutput bus configuration:");
> + drm_printf(p, "\t\tcode: %04x", state->output_bus_cfg.format);
> + drm_printf(p, "\t\tflags: %08x", state->output_bus_cfg.flags);
> +}
> +
> static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
> .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
> .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
> + .atomic_print_state = drm_bridge_atomic_print_priv_state,
> };
>
> static bool drm_bridge_is_atomic(struct drm_bridge *bridge)
> {
> return bridge->funcs->atomic_reset != NULL;
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 06/29] drm/bridge: Implement atomic_print_state
2025-09-02 13:22 ` Thomas Zimmermann
@ 2025-09-02 20:22 ` Laurent Pinchart
0 siblings, 0 replies; 57+ messages in thread
From: Laurent Pinchart @ 2025-09-02 20:22 UTC (permalink / raw)
To: Thomas Zimmermann
Cc: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
Jernej Skrabec, Jyri Sarha, Tomi Valkeinen, Devarsh Thakkar,
dri-devel, linux-kernel
On Tue, Sep 02, 2025 at 03:22:40PM +0200, Thomas Zimmermann wrote:
> Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> > Bridges have some fields in their state worth printing, but we don't
> > provide an atomic_print_state implementation to show those fields.
> >
> > Let's do so.
> >
> > Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > ---
> > drivers/gpu/drm/drm_bridge.c | 18 ++++++++++++++++++
> > 1 file changed, 18 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > index dd439d55177a867acb7ab73c02182bada44d93c9..e803dfd8fd5aae9c16931445213df04d8715b9f6 100644
> > --- a/drivers/gpu/drm/drm_bridge.c
> > +++ b/drivers/gpu/drm/drm_bridge.c
> > @@ -370,13 +370,31 @@ drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj,
> > struct drm_bridge *bridge = drm_priv_to_bridge(obj);
> >
> > bridge->funcs->atomic_destroy_state(bridge, state);
> > }
> >
> > +static void
> > +drm_bridge_atomic_print_priv_state(struct drm_printer *p,
> > + const struct drm_private_state *s)
> > +{
> > + const struct drm_bridge_state *state =
> > + container_of_const(s, struct drm_bridge_state, base);
>
> Maybe adopt drm_priv_to_bridge_state() to accept const pointers?
>
> https://elixir.bootlin.com/linux/v6.16.4/source/include/drm/drm_atomic.h#L1236
container_of_const() can helper, but drm_priv_to_bridge_state() will
need to be turned into a macro.
> > + struct drm_bridge *bridge = drm_priv_to_bridge(s->obj);
> > +
> > + drm_printf(p, "bridge: %s", drm_get_connector_type_name(bridge->type));
It would be nice to identify the bridge more precisely, but bridges have
no object ID :-/ The raw pointer may not be very useful. I wonder if we
should give an object ID to drm_private_obj instances, even if we don't
expose them to userspace. That's not a topic for this series of course.
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> > + drm_printf(p, "\tinput bus configuration:");
> > + drm_printf(p, "\t\tcode: %04x", state->input_bus_cfg.format);
> > + drm_printf(p, "\t\tflags: %08x", state->input_bus_cfg.flags);
> > + drm_printf(p, "\toutput bus configuration:");
> > + drm_printf(p, "\t\tcode: %04x", state->output_bus_cfg.format);
> > + drm_printf(p, "\t\tflags: %08x", state->output_bus_cfg.flags);
> > +}
> > +
> > static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
> > .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
> > .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
> > + .atomic_print_state = drm_bridge_atomic_print_priv_state,
> > };
> >
> > static bool drm_bridge_is_atomic(struct drm_bridge *bridge)
> > {
> > return bridge->funcs->atomic_reset != NULL;
> >
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 07/29] drm/atomic: Implement drm_atomic_print_old_state
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (5 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 06/29] drm/bridge: Implement atomic_print_state Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:26 ` Thomas Zimmermann
2025-09-02 20:35 ` Laurent Pinchart
2025-09-02 8:32 ` [PATCH 08/29] drm/atomic: Only call atomic_destroy_state on a !NULL pointer Maxime Ripard
` (22 subsequent siblings)
29 siblings, 2 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
We currently have a helper to print the new states associated to a
drm_atomic_state, but we don't have a variant to print the old state.
It's somewhat expected, since we almost never care about what the new
state looks like when we commit a new state, but we're about to change
that.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic.c | 45 +++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/drm_crtc_internal.h | 2 ++
2 files changed, 47 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 9b198610791d19c7fd276ca59264a961d21caf43..38f2b2633fa992b3543e8c425c7faeab1ce69765 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1875,10 +1875,55 @@ void drm_atomic_print_new_state(const struct drm_atomic_state *state,
for_each_new_private_obj_in_state(state, obj, obj_state, i)
drm_atomic_private_obj_print_state(p, obj_state);
}
EXPORT_SYMBOL(drm_atomic_print_new_state);
+/**
+ * drm_atomic_print_old_state - prints drm atomic state
+ * @state: atomic configuration to check
+ * @p: drm printer
+ *
+ * This functions prints the drm atomic state snapshot using the drm printer
+ * which is passed to it. This snapshot can be used for debugging purposes.
+ *
+ * Note that this function looks into the old state objects and hence its not
+ * safe to be used after the call to drm_atomic_helper_commit_hw_done().
+ */
+void drm_atomic_print_old_state(const struct drm_atomic_state *state,
+ struct drm_printer *p)
+{
+ struct drm_plane *plane;
+ struct drm_plane_state *plane_state;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ struct drm_connector *connector;
+ struct drm_connector_state *connector_state;
+ struct drm_private_obj *obj;
+ struct drm_private_state *obj_state;
+ int i;
+
+ if (!p) {
+ drm_err(state->dev, "invalid drm printer\n");
+ return;
+ }
+
+ drm_dbg_atomic(state->dev, "checking %p\n", state);
+
+ for_each_old_plane_in_state(state, plane, plane_state, i)
+ drm_atomic_plane_print_state(p, plane_state);
+
+ for_each_old_crtc_in_state(state, crtc, crtc_state, i)
+ drm_atomic_crtc_print_state(p, crtc_state);
+
+ for_each_old_connector_in_state(state, connector, connector_state, i)
+ drm_atomic_connector_print_state(p, connector_state);
+
+ for_each_old_private_obj_in_state(state, obj, obj_state, i)
+ drm_atomic_private_obj_print_state(p, obj_state);
+}
+EXPORT_SYMBOL(drm_atomic_print_old_state);
+
static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p,
bool take_locks)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_plane *plane;
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index 89706aa8232fc0b2830af67c7588985a29653299..a8139fda1a1015c2ac8d8af3b12c5ac0b00cfc1a 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -249,10 +249,12 @@ int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
int __drm_atomic_helper_set_config(struct drm_mode_set *set,
struct drm_atomic_state *state);
void drm_atomic_print_new_state(const struct drm_atomic_state *state,
struct drm_printer *p);
+void drm_atomic_print_old_state(const struct drm_atomic_state *state,
+ struct drm_printer *p);
/* drm_atomic_uapi.c */
int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
struct drm_connector *connector,
int mode);
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 07/29] drm/atomic: Implement drm_atomic_print_old_state
2025-09-02 8:32 ` [PATCH 07/29] drm/atomic: Implement drm_atomic_print_old_state Maxime Ripard
@ 2025-09-02 13:26 ` Thomas Zimmermann
2025-09-02 20:35 ` Laurent Pinchart
1 sibling, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:26 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> We currently have a helper to print the new states associated to a
> drm_atomic_state, but we don't have a variant to print the old state.
>
> It's somewhat expected, since we almost never care about what the new
> state looks like when we commit a new state, but we're about to change
> that.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
I assume something later in the series uses this code?
> ---
> drivers/gpu/drm/drm_atomic.c | 45 +++++++++++++++++++++++++++++++++++++
> drivers/gpu/drm/drm_crtc_internal.h | 2 ++
> 2 files changed, 47 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 9b198610791d19c7fd276ca59264a961d21caf43..38f2b2633fa992b3543e8c425c7faeab1ce69765 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -1875,10 +1875,55 @@ void drm_atomic_print_new_state(const struct drm_atomic_state *state,
> for_each_new_private_obj_in_state(state, obj, obj_state, i)
> drm_atomic_private_obj_print_state(p, obj_state);
> }
> EXPORT_SYMBOL(drm_atomic_print_new_state);
>
> +/**
> + * drm_atomic_print_old_state - prints drm atomic state
> + * @state: atomic configuration to check
> + * @p: drm printer
> + *
> + * This functions prints the drm atomic state snapshot using the drm printer
> + * which is passed to it. This snapshot can be used for debugging purposes.
> + *
> + * Note that this function looks into the old state objects and hence its not
> + * safe to be used after the call to drm_atomic_helper_commit_hw_done().
> + */
> +void drm_atomic_print_old_state(const struct drm_atomic_state *state,
> + struct drm_printer *p)
> +{
> + struct drm_plane *plane;
> + struct drm_plane_state *plane_state;
> + struct drm_crtc *crtc;
> + struct drm_crtc_state *crtc_state;
> + struct drm_connector *connector;
> + struct drm_connector_state *connector_state;
> + struct drm_private_obj *obj;
> + struct drm_private_state *obj_state;
> + int i;
> +
> + if (!p) {
> + drm_err(state->dev, "invalid drm printer\n");
> + return;
> + }
> +
> + drm_dbg_atomic(state->dev, "checking %p\n", state);
> +
> + for_each_old_plane_in_state(state, plane, plane_state, i)
> + drm_atomic_plane_print_state(p, plane_state);
> +
> + for_each_old_crtc_in_state(state, crtc, crtc_state, i)
> + drm_atomic_crtc_print_state(p, crtc_state);
> +
> + for_each_old_connector_in_state(state, connector, connector_state, i)
> + drm_atomic_connector_print_state(p, connector_state);
> +
> + for_each_old_private_obj_in_state(state, obj, obj_state, i)
> + drm_atomic_private_obj_print_state(p, obj_state);
> +}
> +EXPORT_SYMBOL(drm_atomic_print_old_state);
> +
> static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p,
> bool take_locks)
> {
> struct drm_mode_config *config = &dev->mode_config;
> struct drm_plane *plane;
> diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
> index 89706aa8232fc0b2830af67c7588985a29653299..a8139fda1a1015c2ac8d8af3b12c5ac0b00cfc1a 100644
> --- a/drivers/gpu/drm/drm_crtc_internal.h
> +++ b/drivers/gpu/drm/drm_crtc_internal.h
> @@ -249,10 +249,12 @@ int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
> int __drm_atomic_helper_set_config(struct drm_mode_set *set,
> struct drm_atomic_state *state);
>
> void drm_atomic_print_new_state(const struct drm_atomic_state *state,
> struct drm_printer *p);
> +void drm_atomic_print_old_state(const struct drm_atomic_state *state,
> + struct drm_printer *p);
>
> /* drm_atomic_uapi.c */
> int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
> struct drm_connector *connector,
> int mode);
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 07/29] drm/atomic: Implement drm_atomic_print_old_state
2025-09-02 8:32 ` [PATCH 07/29] drm/atomic: Implement drm_atomic_print_old_state Maxime Ripard
2025-09-02 13:26 ` Thomas Zimmermann
@ 2025-09-02 20:35 ` Laurent Pinchart
1 sibling, 0 replies; 57+ messages in thread
From: Laurent Pinchart @ 2025-09-02 20:35 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
Jernej Skrabec, Jyri Sarha, Tomi Valkeinen, Devarsh Thakkar,
dri-devel, linux-kernel
Hi Maxime,
Thank you for the patch.
On Tue, Sep 02, 2025 at 10:32:35AM +0200, Maxime Ripard wrote:
> We currently have a helper to print the new states associated to a
> drm_atomic_state, but we don't have a variant to print the old state.
>
> It's somewhat expected, since we almost never care about what the new
> state looks like when we commit a new state, but we're about to change
> that.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/drm_atomic.c | 45 +++++++++++++++++++++++++++++++++++++
> drivers/gpu/drm/drm_crtc_internal.h | 2 ++
> 2 files changed, 47 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 9b198610791d19c7fd276ca59264a961d21caf43..38f2b2633fa992b3543e8c425c7faeab1ce69765 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -1875,10 +1875,55 @@ void drm_atomic_print_new_state(const struct drm_atomic_state *state,
> for_each_new_private_obj_in_state(state, obj, obj_state, i)
> drm_atomic_private_obj_print_state(p, obj_state);
> }
> EXPORT_SYMBOL(drm_atomic_print_new_state);
>
> +/**
> + * drm_atomic_print_old_state - prints drm atomic state
> + * @state: atomic configuration to check
> + * @p: drm printer
> + *
> + * This functions prints the drm atomic state snapshot using the drm printer
> + * which is passed to it. This snapshot can be used for debugging purposes.
> + *
> + * Note that this function looks into the old state objects and hence its not
> + * safe to be used after the call to drm_atomic_helper_commit_hw_done().
> + */
> +void drm_atomic_print_old_state(const struct drm_atomic_state *state,
> + struct drm_printer *p)
> +{
> + struct drm_plane *plane;
> + struct drm_plane_state *plane_state;
> + struct drm_crtc *crtc;
> + struct drm_crtc_state *crtc_state;
> + struct drm_connector *connector;
> + struct drm_connector_state *connector_state;
> + struct drm_private_obj *obj;
> + struct drm_private_state *obj_state;
> + int i;
> +
> + if (!p) {
> + drm_err(state->dev, "invalid drm printer\n");
> + return;
> + }
> +
> + drm_dbg_atomic(state->dev, "checking %p\n", state);
> +
> + for_each_old_plane_in_state(state, plane, plane_state, i)
> + drm_atomic_plane_print_state(p, plane_state);
> +
> + for_each_old_crtc_in_state(state, crtc, crtc_state, i)
> + drm_atomic_crtc_print_state(p, crtc_state);
> +
> + for_each_old_connector_in_state(state, connector, connector_state, i)
> + drm_atomic_connector_print_state(p, connector_state);
> +
> + for_each_old_private_obj_in_state(state, obj, obj_state, i)
> + drm_atomic_private_obj_print_state(p, obj_state);
> +}
> +EXPORT_SYMBOL(drm_atomic_print_old_state);
> +
> static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p,
> bool take_locks)
> {
> struct drm_mode_config *config = &dev->mode_config;
> struct drm_plane *plane;
> diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
> index 89706aa8232fc0b2830af67c7588985a29653299..a8139fda1a1015c2ac8d8af3b12c5ac0b00cfc1a 100644
> --- a/drivers/gpu/drm/drm_crtc_internal.h
> +++ b/drivers/gpu/drm/drm_crtc_internal.h
> @@ -249,10 +249,12 @@ int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
> int __drm_atomic_helper_set_config(struct drm_mode_set *set,
> struct drm_atomic_state *state);
>
> void drm_atomic_print_new_state(const struct drm_atomic_state *state,
> struct drm_printer *p);
> +void drm_atomic_print_old_state(const struct drm_atomic_state *state,
> + struct drm_printer *p);
>
> /* drm_atomic_uapi.c */
> int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
> struct drm_connector *connector,
> int mode);
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 08/29] drm/atomic: Only call atomic_destroy_state on a !NULL pointer
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (6 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 07/29] drm/atomic: Implement drm_atomic_print_old_state Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:30 ` Thomas Zimmermann
2025-09-02 20:52 ` Laurent Pinchart
2025-09-02 8:32 ` [PATCH 09/29] drm/modeset: Create atomic_reset hook Maxime Ripard
` (21 subsequent siblings)
29 siblings, 2 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The drm_atomic_state structure is freed through the
drm_atomic_state_put() function, that eventually calls
drm_atomic_state_default_clear() by default when there's no active
users of that state.
It then iterates over all entities with a state, and will call the
atomic_destroy_state callback on the state pointer. The state pointer is
mostly used these days to point to which of the old or new state needs
to be freed, depending on whether the state was committed or not.
So it all makes sense.
However, with the hardware state readout support approaching, we might
have a state, with multiple entities in it, but no state to free because
we want them to persist. In such a case, state is going to be NULL, and
thus we'll end up with NULL pointer dereference.
In order to make it work, let's first test if the state pointer isn't
NULL before calling atomic_destroy_state on it.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 38f2b2633fa992b3543e8c425c7faeab1ce69765..f26678835a94f40da56a8c1297d92f226d7ff2e2 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -249,12 +249,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
struct drm_connector *connector = state->connectors[i].ptr;
if (!connector)
continue;
- connector->funcs->atomic_destroy_state(connector,
- state->connectors[i].state);
+ if (state->connectors[i].state)
+ connector->funcs->atomic_destroy_state(connector,
+ state->connectors[i].state);
+
state->connectors[i].ptr = NULL;
state->connectors[i].state = NULL;
state->connectors[i].old_state = NULL;
state->connectors[i].new_state = NULL;
drm_connector_put(connector);
@@ -264,12 +266,13 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
struct drm_crtc *crtc = state->crtcs[i].ptr;
if (!crtc)
continue;
- crtc->funcs->atomic_destroy_state(crtc,
- state->crtcs[i].state);
+ if (state->crtcs[i].state)
+ crtc->funcs->atomic_destroy_state(crtc,
+ state->crtcs[i].state);
state->crtcs[i].ptr = NULL;
state->crtcs[i].state = NULL;
state->crtcs[i].old_state = NULL;
state->crtcs[i].new_state = NULL;
@@ -284,12 +287,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
struct drm_plane *plane = state->planes[i].ptr;
if (!plane)
continue;
- plane->funcs->atomic_destroy_state(plane,
- state->planes[i].state);
+ if (state->planes[i].state)
+ plane->funcs->atomic_destroy_state(plane,
+ state->planes[i].state);
+
state->planes[i].ptr = NULL;
state->planes[i].state = NULL;
state->planes[i].old_state = NULL;
state->planes[i].new_state = NULL;
}
@@ -298,12 +303,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
struct drm_private_obj *obj = state->private_objs[i].ptr;
if (!obj)
continue;
- obj->funcs->atomic_destroy_state(obj,
- state->private_objs[i].state);
+ if (state->private_objs[i].state)
+ obj->funcs->atomic_destroy_state(obj,
+ state->private_objs[i].state);
+
state->private_objs[i].ptr = NULL;
state->private_objs[i].state = NULL;
state->private_objs[i].old_state = NULL;
state->private_objs[i].new_state = NULL;
}
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 08/29] drm/atomic: Only call atomic_destroy_state on a !NULL pointer
2025-09-02 8:32 ` [PATCH 08/29] drm/atomic: Only call atomic_destroy_state on a !NULL pointer Maxime Ripard
@ 2025-09-02 13:30 ` Thomas Zimmermann
2025-09-02 20:52 ` Laurent Pinchart
1 sibling, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:30 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> The drm_atomic_state structure is freed through the
> drm_atomic_state_put() function, that eventually calls
> drm_atomic_state_default_clear() by default when there's no active
> users of that state.
>
> It then iterates over all entities with a state, and will call the
> atomic_destroy_state callback on the state pointer. The state pointer is
> mostly used these days to point to which of the old or new state needs
> to be freed, depending on whether the state was committed or not.
>
> So it all makes sense.
>
> However, with the hardware state readout support approaching, we might
> have a state, with multiple entities in it, but no state to free because
> we want them to persist. In such a case, state is going to be NULL, and
> thus we'll end up with NULL pointer dereference.
>
> In order to make it work, let's first test if the state pointer isn't
> NULL before calling atomic_destroy_state on it.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> drivers/gpu/drm/drm_atomic.c | 23 +++++++++++++++--------
> 1 file changed, 15 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 38f2b2633fa992b3543e8c425c7faeab1ce69765..f26678835a94f40da56a8c1297d92f226d7ff2e2 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -249,12 +249,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
> struct drm_connector *connector = state->connectors[i].ptr;
>
> if (!connector)
> continue;
>
> - connector->funcs->atomic_destroy_state(connector,
> - state->connectors[i].state);
> + if (state->connectors[i].state)
> + connector->funcs->atomic_destroy_state(connector,
> + state->connectors[i].state);
> +
> state->connectors[i].ptr = NULL;
> state->connectors[i].state = NULL;
> state->connectors[i].old_state = NULL;
> state->connectors[i].new_state = NULL;
> drm_connector_put(connector);
> @@ -264,12 +266,13 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
> struct drm_crtc *crtc = state->crtcs[i].ptr;
>
> if (!crtc)
> continue;
>
> - crtc->funcs->atomic_destroy_state(crtc,
> - state->crtcs[i].state);
> + if (state->crtcs[i].state)
> + crtc->funcs->atomic_destroy_state(crtc,
> + state->crtcs[i].state);
>
> state->crtcs[i].ptr = NULL;
> state->crtcs[i].state = NULL;
> state->crtcs[i].old_state = NULL;
> state->crtcs[i].new_state = NULL;
> @@ -284,12 +287,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
> struct drm_plane *plane = state->planes[i].ptr;
>
> if (!plane)
> continue;
>
> - plane->funcs->atomic_destroy_state(plane,
> - state->planes[i].state);
> + if (state->planes[i].state)
> + plane->funcs->atomic_destroy_state(plane,
> + state->planes[i].state);
> +
> state->planes[i].ptr = NULL;
> state->planes[i].state = NULL;
> state->planes[i].old_state = NULL;
> state->planes[i].new_state = NULL;
> }
> @@ -298,12 +303,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
> struct drm_private_obj *obj = state->private_objs[i].ptr;
>
> if (!obj)
> continue;
>
> - obj->funcs->atomic_destroy_state(obj,
> - state->private_objs[i].state);
> + if (state->private_objs[i].state)
> + obj->funcs->atomic_destroy_state(obj,
> + state->private_objs[i].state);
> +
> state->private_objs[i].ptr = NULL;
> state->private_objs[i].state = NULL;
> state->private_objs[i].old_state = NULL;
> state->private_objs[i].new_state = NULL;
> }
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 08/29] drm/atomic: Only call atomic_destroy_state on a !NULL pointer
2025-09-02 8:32 ` [PATCH 08/29] drm/atomic: Only call atomic_destroy_state on a !NULL pointer Maxime Ripard
2025-09-02 13:30 ` Thomas Zimmermann
@ 2025-09-02 20:52 ` Laurent Pinchart
1 sibling, 0 replies; 57+ messages in thread
From: Laurent Pinchart @ 2025-09-02 20:52 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
Jernej Skrabec, Jyri Sarha, Tomi Valkeinen, Devarsh Thakkar,
dri-devel, linux-kernel
On Tue, Sep 02, 2025 at 10:32:36AM +0200, Maxime Ripard wrote:
> The drm_atomic_state structure is freed through the
> drm_atomic_state_put() function, that eventually calls
> drm_atomic_state_default_clear() by default when there's no active
> users of that state.
>
> It then iterates over all entities with a state, and will call the
Did you mean s/with a state/within the state/ ?
I'd also replace "entity" with "object" as mentioned in the review of a
previous patch.
> atomic_destroy_state callback on the state pointer. The state pointer is
> mostly used these days to point to which of the old or new state needs
> to be freed, depending on whether the state was committed or not.
>
> So it all makes sense.
>
> However, with the hardware state readout support approaching, we might
> have a state, with multiple entities in it, but no state to free because
> we want them to persist. In such a case, state is going to be NULL, and
> thus we'll end up with NULL pointer dereference.
I'm not sure to follow you here. Are we talking with objects whose old
and new states will both need to be preserved ? Or objects that have no
old state ? I assume it's the latter, a clarification would be useful
here. With that,
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> In order to make it work, let's first test if the state pointer isn't
> NULL before calling atomic_destroy_state on it.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> drivers/gpu/drm/drm_atomic.c | 23 +++++++++++++++--------
> 1 file changed, 15 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 38f2b2633fa992b3543e8c425c7faeab1ce69765..f26678835a94f40da56a8c1297d92f226d7ff2e2 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -249,12 +249,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
> struct drm_connector *connector = state->connectors[i].ptr;
>
> if (!connector)
> continue;
>
> - connector->funcs->atomic_destroy_state(connector,
> - state->connectors[i].state);
> + if (state->connectors[i].state)
> + connector->funcs->atomic_destroy_state(connector,
> + state->connectors[i].state);
> +
> state->connectors[i].ptr = NULL;
> state->connectors[i].state = NULL;
> state->connectors[i].old_state = NULL;
> state->connectors[i].new_state = NULL;
> drm_connector_put(connector);
> @@ -264,12 +266,13 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
> struct drm_crtc *crtc = state->crtcs[i].ptr;
>
> if (!crtc)
> continue;
>
> - crtc->funcs->atomic_destroy_state(crtc,
> - state->crtcs[i].state);
> + if (state->crtcs[i].state)
> + crtc->funcs->atomic_destroy_state(crtc,
> + state->crtcs[i].state);
>
> state->crtcs[i].ptr = NULL;
> state->crtcs[i].state = NULL;
> state->crtcs[i].old_state = NULL;
> state->crtcs[i].new_state = NULL;
> @@ -284,12 +287,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
> struct drm_plane *plane = state->planes[i].ptr;
>
> if (!plane)
> continue;
>
> - plane->funcs->atomic_destroy_state(plane,
> - state->planes[i].state);
> + if (state->planes[i].state)
> + plane->funcs->atomic_destroy_state(plane,
> + state->planes[i].state);
> +
> state->planes[i].ptr = NULL;
> state->planes[i].state = NULL;
> state->planes[i].old_state = NULL;
> state->planes[i].new_state = NULL;
> }
> @@ -298,12 +303,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
> struct drm_private_obj *obj = state->private_objs[i].ptr;
>
> if (!obj)
> continue;
>
> - obj->funcs->atomic_destroy_state(obj,
> - state->private_objs[i].state);
> + if (state->private_objs[i].state)
> + obj->funcs->atomic_destroy_state(obj,
> + state->private_objs[i].state);
> +
> state->private_objs[i].ptr = NULL;
> state->private_objs[i].state = NULL;
> state->private_objs[i].old_state = NULL;
> state->private_objs[i].new_state = NULL;
> }
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 09/29] drm/modeset: Create atomic_reset hook
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (7 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 08/29] drm/atomic: Only call atomic_destroy_state on a !NULL pointer Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 21:04 ` Laurent Pinchart
2025-09-02 8:32 ` [PATCH 10/29] drm/atomic: Add atomic_state_readout infrastructure Maxime Ripard
` (20 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
Since we're about to integrate some infrastructure to implement hardware
state readout, we need a way to differentiate between drivers wanting to
start from a pristine state, with the classic reset sequence, and
drivers that want to pickup their initial state from reading out the
hardware state.
To do so we can create an optional reset hook in
drm_mode_config_helper_funcs that will default to the classic reset
implementation, and can be setup to a helper we will provide in a later
patch to read the hardware state.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_mode_config.c | 32 +++++++++++++++++++++++---------
include/drm/drm_modeset_helper_vtables.h | 13 +++++++++++++
2 files changed, 36 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 25f376869b3a41d47bbe72b0df3e35cad142f3e6..82180760032d3490d63fe83136465d2c26551d08 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -27,10 +27,11 @@
#include <drm/drm_encoder.h>
#include <drm/drm_file.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_managed.h>
#include <drm/drm_mode_config.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <linux/dma-resv.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
@@ -179,19 +180,11 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
drm_connector_list_iter_end(&conn_iter);
return ret;
}
-/**
- * drm_mode_config_reset - call ->reset callbacks
- * @dev: drm device
- *
- * This functions calls all the crtc's, encoder's and connector's ->reset
- * callback. Drivers can use this in e.g. their driver load or resume code to
- * reset hardware and software state.
- */
-void drm_mode_config_reset(struct drm_device *dev)
+static void drm_mode_config_reset_pristine(struct drm_device *dev)
{
struct drm_crtc *crtc;
struct drm_plane *plane;
struct drm_encoder *encoder;
struct drm_connector *connector;
@@ -213,10 +206,31 @@ void drm_mode_config_reset(struct drm_device *dev)
drm_for_each_connector_iter(connector, &conn_iter)
if (connector->funcs->reset)
connector->funcs->reset(connector);
drm_connector_list_iter_end(&conn_iter);
}
+
+/**
+ * drm_mode_config_reset - call ->reset callbacks
+ * @dev: drm device
+ *
+ * This functions calls all the crtc's, encoder's and connector's ->reset
+ * callback. Drivers can use this in e.g. their driver load or resume code to
+ * reset hardware and software state.
+ */
+void drm_mode_config_reset(struct drm_device *dev)
+{
+ if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+ const struct drm_mode_config_helper_funcs *funcs =
+ dev->mode_config.helper_private;
+
+ if (funcs && funcs->atomic_reset)
+ return funcs->atomic_reset(dev);
+ }
+
+ return drm_mode_config_reset_pristine(dev);
+}
EXPORT_SYMBOL(drm_mode_config_reset);
/*
* Global properties
*/
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
index ce7c7aeac887bb8438d73710f16071c97a851839..6d22a7676d6bf49fb78af4d0706bd91005cef186 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -1561,8 +1561,21 @@ struct drm_mode_config_helper_funcs {
* how one should implement this.
*
* This hook is optional.
*/
int (*atomic_commit_setup)(struct drm_atomic_state *state);
+
+ /**
+ * @atomic_reset:
+ *
+ * This hook is used to create the initial @drm_atomic_state.
+ * It's used by drm_mode_config_reset().
+ *
+ * The default implementation will create an empty one, but
+ * drivers can provide an alternative implementation to, for
+ * example, read the initial state from hardware to implement
+ * flicker-free and / or faster boot.
+ */
+ void (*atomic_reset)(struct drm_device *dev);
};
#endif
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 09/29] drm/modeset: Create atomic_reset hook
2025-09-02 8:32 ` [PATCH 09/29] drm/modeset: Create atomic_reset hook Maxime Ripard
@ 2025-09-02 21:04 ` Laurent Pinchart
0 siblings, 0 replies; 57+ messages in thread
From: Laurent Pinchart @ 2025-09-02 21:04 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
Jernej Skrabec, Jyri Sarha, Tomi Valkeinen, Devarsh Thakkar,
dri-devel, linux-kernel
On Tue, Sep 02, 2025 at 10:32:37AM +0200, Maxime Ripard wrote:
> Since we're about to integrate some infrastructure to implement hardware
> state readout, we need a way to differentiate between drivers wanting to
> start from a pristine state, with the classic reset sequence, and
> drivers that want to pickup their initial state from reading out the
> hardware state.
>
> To do so we can create an optional reset hook in
> drm_mode_config_helper_funcs that will default to the classic reset
> implementation, and can be setup to a helper we will provide in a later
> patch to read the hardware state.
I'm a bit puzzled by this. Isn't the whole point of the existing reset
operations to allow drivers to read out the hardware state if they wish
? Why do we need something new ?
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> drivers/gpu/drm/drm_mode_config.c | 32 +++++++++++++++++++++++---------
> include/drm/drm_modeset_helper_vtables.h | 13 +++++++++++++
> 2 files changed, 36 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
> index 25f376869b3a41d47bbe72b0df3e35cad142f3e6..82180760032d3490d63fe83136465d2c26551d08 100644
> --- a/drivers/gpu/drm/drm_mode_config.c
> +++ b/drivers/gpu/drm/drm_mode_config.c
> @@ -27,10 +27,11 @@
> #include <drm/drm_encoder.h>
> #include <drm/drm_file.h>
> #include <drm/drm_framebuffer.h>
> #include <drm/drm_managed.h>
> #include <drm/drm_mode_config.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> #include <drm/drm_print.h>
> #include <linux/dma-resv.h>
>
> #include "drm_crtc_internal.h"
> #include "drm_internal.h"
> @@ -179,19 +180,11 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
> drm_connector_list_iter_end(&conn_iter);
>
> return ret;
> }
>
> -/**
> - * drm_mode_config_reset - call ->reset callbacks
> - * @dev: drm device
> - *
> - * This functions calls all the crtc's, encoder's and connector's ->reset
> - * callback. Drivers can use this in e.g. their driver load or resume code to
> - * reset hardware and software state.
> - */
> -void drm_mode_config_reset(struct drm_device *dev)
> +static void drm_mode_config_reset_pristine(struct drm_device *dev)
> {
> struct drm_crtc *crtc;
> struct drm_plane *plane;
> struct drm_encoder *encoder;
> struct drm_connector *connector;
> @@ -213,10 +206,31 @@ void drm_mode_config_reset(struct drm_device *dev)
> drm_for_each_connector_iter(connector, &conn_iter)
> if (connector->funcs->reset)
> connector->funcs->reset(connector);
> drm_connector_list_iter_end(&conn_iter);
> }
> +
> +/**
> + * drm_mode_config_reset - call ->reset callbacks
> + * @dev: drm device
> + *
> + * This functions calls all the crtc's, encoder's and connector's ->reset
> + * callback. Drivers can use this in e.g. their driver load or resume code to
> + * reset hardware and software state.
> + */
> +void drm_mode_config_reset(struct drm_device *dev)
> +{
> + if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
> + const struct drm_mode_config_helper_funcs *funcs =
> + dev->mode_config.helper_private;
> +
> + if (funcs && funcs->atomic_reset)
> + return funcs->atomic_reset(dev);
> + }
> +
> + return drm_mode_config_reset_pristine(dev);
> +}
> EXPORT_SYMBOL(drm_mode_config_reset);
>
> /*
> * Global properties
> */
> diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> index ce7c7aeac887bb8438d73710f16071c97a851839..6d22a7676d6bf49fb78af4d0706bd91005cef186 100644
> --- a/include/drm/drm_modeset_helper_vtables.h
> +++ b/include/drm/drm_modeset_helper_vtables.h
> @@ -1561,8 +1561,21 @@ struct drm_mode_config_helper_funcs {
> * how one should implement this.
> *
> * This hook is optional.
> */
> int (*atomic_commit_setup)(struct drm_atomic_state *state);
> +
> + /**
> + * @atomic_reset:
> + *
> + * This hook is used to create the initial @drm_atomic_state.
> + * It's used by drm_mode_config_reset().
> + *
> + * The default implementation will create an empty one, but
> + * drivers can provide an alternative implementation to, for
> + * example, read the initial state from hardware to implement
> + * flicker-free and / or faster boot.
> + */
> + void (*atomic_reset)(struct drm_device *dev);
> };
>
> #endif
>
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 10/29] drm/atomic: Add atomic_state_readout infrastructure
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (8 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 09/29] drm/modeset: Create atomic_reset hook Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:44 ` Thomas Zimmermann
2025-09-02 8:32 ` [PATCH 11/29] drm/crtc: Drop no_vblank bit field Maxime Ripard
` (19 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
In order to enable drivers to fill their initial state from the hardware
state, we need to provide an alternative atomic_reset helper.
This helper relies on each state having its own atomic_state_readout()
hooks. Each component will thus be able to fill the initial state based
on what they can figure out from the hardware.
It also allocates a dummy drm_atomic_state to glue the whole thing
together so atomic_state_readout implementations can still figure out
the state of other related entities.
Link: https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_helper.c | 382 ++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/drm_mode_config.c | 1 +
include/drm/drm_atomic_helper.h | 1 +
include/drm/drm_bridge.h | 21 ++
include/drm/drm_connector.h | 26 +++
include/drm/drm_crtc.h | 19 ++
include/drm/drm_plane.h | 27 +++
7 files changed, 477 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index d5ebe6ea0acbc5a08aef7fa41ecb9ed5d8fa8e80..f59512476ebf2b48e1c7034950bcaf99237f03c6 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -45,10 +45,392 @@
#include <drm/drm_vblank.h>
#include <drm/drm_writeback.h>
#include "drm_crtc_helper_internal.h"
#include "drm_crtc_internal.h"
+#include "drm_internal.h"
+
+static void drm_atomic_set_old_plane_state(struct drm_atomic_state *state,
+ struct drm_plane *plane,
+ struct drm_plane_state *plane_state)
+{
+ int idx = drm_plane_index(plane);
+
+ state->planes[idx].old_state = plane_state;
+ state->planes[idx].ptr = plane;
+
+ drm_dbg_atomic(plane->dev, "Added [PLANE:%d:%s] %p state to %p\n",
+ plane->base.id, plane->name, plane_state, state);
+}
+
+static void drm_atomic_set_old_crtc_state(struct drm_atomic_state *state,
+ struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state)
+{
+ int idx = drm_crtc_index(crtc);
+
+ state->crtcs[idx].old_state = crtc_state;
+ state->crtcs[idx].ptr = crtc;
+
+ drm_dbg_atomic(state->dev, "Added [CRTC:%d:%s] %p state to %p\n",
+ crtc->base.id, crtc->name, crtc_state, state);
+}
+
+static void drm_atomic_set_old_connector_state(struct drm_atomic_state *state,
+ struct drm_connector *conn,
+ struct drm_connector_state *conn_state)
+{
+ int idx = drm_connector_index(conn);
+
+ drm_connector_get(conn);
+ state->connectors[idx].old_state = conn_state;
+ state->connectors[idx].ptr = conn;
+ state->num_connector++;
+
+ drm_dbg_atomic(conn->dev,
+ "Added [CONNECTOR:%d:%s] %p state to %p\n",
+ conn->base.id, conn->name, conn_state, state);
+}
+
+static void drm_atomic_set_old_private_obj_state(struct drm_atomic_state *state,
+ struct drm_private_obj *obj,
+ struct drm_private_state *obj_state)
+{
+ int idx = state->num_private_objs;
+
+ memset(&state->private_objs[idx], 0, sizeof(*state->private_objs));
+ state->private_objs[idx].old_state = obj_state;
+ state->private_objs[idx].ptr = obj;
+ state->num_private_objs++;
+
+ drm_dbg_atomic(state->dev,
+ "Added new private object %p state %p to %p\n", obj,
+ obj_state, state);
+}
+
+static void drm_atomic_set_old_bridge_state(struct drm_atomic_state *state,
+ struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state)
+{
+ drm_atomic_set_old_private_obj_state(state, &bridge->base, &bridge_state->base);
+}
+
+static struct drm_connector_state *
+find_connector_state_for_encoder(struct drm_atomic_state *state,
+ struct drm_encoder *encoder)
+{
+ struct drm_connector_list_iter conn_iter;
+ struct drm_connector *connector;
+
+ drm_connector_list_iter_begin(state->dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ struct drm_connector_state *conn_state =
+ drm_atomic_get_old_connector_state(state, connector);
+
+ if (WARN_ON(!conn_state))
+ continue;
+
+ if (encoder == conn_state->best_encoder)
+ return conn_state;
+ }
+ drm_connector_list_iter_end(&conn_iter);
+
+ return NULL;
+}
+
+/**
+ * drm_atomic_helper_install_readout_state - Sets the state pointer from their readout state
+ * @state: drm_atomic_state to initialize the DRM device with.
+ *
+ * This function takes a &struct drm_atomic_state initialized by
+ * drm_atomic_build_readout_state() and sets up the entities state
+ * pointers (ie, &drm_crtc.state and similar) to properly setup the
+ * initial state.
+ */
+static void
+drm_atomic_helper_install_readout_state(struct drm_atomic_state *state)
+{
+ struct drm_connector_state *old_conn_state;
+ struct drm_private_state *old_obj_state;
+ struct drm_plane_state *old_plane_state;
+ struct drm_crtc_state *old_crtc_state;
+ struct drm_connector *connector;
+ struct drm_private_obj *obj;
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
+ unsigned int i;
+
+ for_each_old_connector_in_state(state, connector, old_conn_state, i) {
+ connector->state = old_conn_state;
+
+ drm_connector_put(state->connectors[i].ptr);
+ state->connectors[i].ptr = NULL;
+ state->connectors[i].old_state = NULL;
+ }
+
+ for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
+ crtc->state = old_crtc_state;
+
+ state->crtcs[i].ptr = NULL;
+ state->crtcs[i].old_state = NULL;
+ }
+
+ for_each_old_plane_in_state(state, plane, old_plane_state, i) {
+ plane->state = old_plane_state;
+
+ state->planes[i].ptr = NULL;
+ state->planes[i].old_state = NULL;
+ }
+
+ for_each_old_private_obj_in_state(state, obj, old_obj_state, i) {
+ obj->state = old_obj_state;
+
+ state->private_objs[i].ptr = NULL;
+ state->private_objs[i].old_state = NULL;
+ }
+}
+
+static unsigned int count_private_obj(struct drm_device *dev)
+{
+ struct drm_mode_config *config = &dev->mode_config;
+ struct drm_private_obj *obj;
+ unsigned int count = 0;
+
+ list_for_each_entry(obj, &config->privobj_list, head)
+ count++;
+
+ return count;
+}
+
+/**
+ * drm_atomic_build_readout_state - Creates an initial state from the hardware
+ * @dev: DRM device to build the state for
+ *
+ * This function allocates a &struct drm_atomic_state, calls the
+ * atomic_readout_state callbacks, and fills the global state old states
+ * by what the callbacks returned.
+ *
+ * Returns:
+ *
+ * A partially initialized &struct drm_atomic_state on success, an error
+ * pointer otherwise.
+ */
+static struct drm_atomic_state *
+drm_atomic_build_readout_state(struct drm_device *dev)
+{
+ struct drm_connector_list_iter conn_iter;
+ struct drm_atomic_state *state;
+ struct drm_mode_config *config =
+ &dev->mode_config;
+ struct drm_connector *connector;
+ struct drm_printer p =
+ drm_info_printer(dev->dev);
+ struct drm_encoder *encoder;
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
+ int ret;
+
+ drm_dbg_kms(dev, "Starting to build atomic state from hardware state.\n");
+
+ state = drm_atomic_state_alloc(dev);
+ if (WARN_ON(!state))
+ return ERR_PTR(-ENOMEM);
+
+ state->connectors = kcalloc(config->num_connector, sizeof(*state->connectors), GFP_KERNEL);
+ if (WARN_ON(!state->connectors)) {
+ ret = -ENOMEM;
+ goto err_state_put;
+ }
+
+ state->private_objs = kcalloc(count_private_obj(dev), sizeof(*state->private_objs), GFP_KERNEL);
+ if (WARN_ON(!state->private_objs)) {
+ ret = -ENOMEM;
+ goto err_state_put;
+ }
+
+ drm_for_each_crtc(crtc, dev) {
+ const struct drm_crtc_funcs *crtc_funcs =
+ crtc->funcs;
+ struct drm_crtc_state *crtc_state;
+
+ drm_dbg_kms(dev, "Initializing CRTC %s state.\n", crtc->name);
+
+ if (crtc_funcs->atomic_readout_state) {
+ crtc_state = crtc_funcs->atomic_readout_state(crtc);
+ } else if (crtc_funcs->reset) {
+ crtc_funcs->reset(crtc);
+
+ /*
+ * We don't want to set crtc->state field yet. Let's save and clear it up.
+ */
+ crtc_state = crtc->state;
+ crtc->state = NULL;
+ } else {
+ drm_warn(dev, "No CRTC readout or reset implementation.");
+ continue;
+ }
+
+ if (WARN_ON(IS_ERR(crtc_state))) {
+ ret = PTR_ERR(crtc_state);
+ goto err_state_put;
+ }
+
+ drm_atomic_set_old_crtc_state(state, crtc, crtc_state);
+ }
+
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ const struct drm_connector_funcs *conn_funcs =
+ connector->funcs;
+ struct drm_connector_state *conn_state;
+
+ drm_dbg_kms(dev, "Initializing Connector %s state.\n", connector->name);
+
+ if (conn_funcs->atomic_readout_state) {
+ conn_state = conn_funcs->atomic_readout_state(connector, state);
+ } else if (conn_funcs->reset) {
+ conn_funcs->reset(connector);
+
+ /*
+ * We don't want to set connector->state field yet. Let's save and clear it
+ * up.
+ */
+ conn_state = connector->state;
+ connector->state = NULL;
+ } else {
+ drm_warn(dev, "No Connector readout or reset implementation.");
+ continue;
+ }
+
+ if (WARN_ON(IS_ERR(conn_state))) {
+ ret = PTR_ERR(conn_state);
+ goto err_state_put;
+ }
+
+ drm_atomic_set_old_connector_state(state, connector, conn_state);
+ }
+ drm_connector_list_iter_end(&conn_iter);
+
+ WARN_ON(state->num_connector != config->num_connector);
+
+ drm_for_each_encoder(encoder, dev) {
+ struct drm_connector_state *enc_conn_state;
+ struct drm_crtc_state *enc_crtc_state;
+ struct drm_bridge *bridge;
+
+ /*
+ * It works a bit differently for bridges. Because they are
+ * using a drm_private_state, and because
+ * drm_atomic_private_obj_init() asks for its initial state when
+ * initializing, instead of doing it later on through a reset
+ * call like the other entities, we can't have reset xor
+ * readout.
+ *
+ * We'll need a mandatory reset to create that initial, blank,
+ * state, and then readout will fill that state later on if the
+ * driver implements it.
+ *
+ * This also means we don't need to call the readout state
+ * function if we don't have the bridge enabled (ie, if no
+ * drm_connector_state->best_encoder points to bridge->encoder,
+ * and / or if drm_connector_state->crtc is NULL).
+ *
+ * In such a case, we would get the blank state reset created
+ * during registration.
+ */
+
+ enc_conn_state = find_connector_state_for_encoder(state, encoder);
+ if (!enc_conn_state)
+ continue;
+
+ enc_crtc_state = drm_atomic_get_old_crtc_state(state, enc_conn_state->crtc);
+ if (!enc_crtc_state)
+ continue;
+
+ list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
+ const struct drm_bridge_funcs *bridge_funcs = bridge->funcs;
+ struct drm_bridge_state *bridge_state;
+
+ bridge_state = drm_bridge_get_current_state(bridge);
+ if (WARN_ON(!bridge_state)) {
+ ret = -EINVAL;
+ goto err_state_put;
+ }
+
+ if (bridge_funcs->atomic_readout_state) {
+ ret = bridge_funcs->atomic_readout_state(bridge,
+ bridge_state,
+ enc_crtc_state,
+ enc_conn_state);
+ if (WARN_ON(ret))
+ goto err_state_put;
+ }
+
+ drm_atomic_set_old_bridge_state(state, bridge, bridge_state);
+ }
+ }
+
+ drm_for_each_plane(plane, dev) {
+ const struct drm_plane_funcs *plane_funcs =
+ plane->funcs;
+ struct drm_plane_state *plane_state;
+
+ drm_dbg_kms(dev, "Initializing Plane %s state.\n", plane->name);
+
+ if (plane_funcs->atomic_readout_state) {
+ plane_state = plane_funcs->atomic_readout_state(plane, state);
+ } else if (plane_funcs->reset) {
+ plane_funcs->reset(plane);
+
+ /*
+ * We don't want to set conn->state field yet. Let's save and clear it up.
+ */
+ plane_state = plane->state;
+ plane->state = NULL;
+ } else {
+ drm_warn(dev, "No plane readout or reset implementation.");
+ continue;
+ }
+
+ if (WARN_ON(IS_ERR(plane_state))) {
+ ret = PTR_ERR(plane_state);
+ goto err_state_put;
+ }
+
+ drm_atomic_set_old_plane_state(state, plane, plane_state);
+ }
+
+ drm_atomic_print_old_state(state, &p);
+
+ return state;
+
+err_state_put:
+ drm_atomic_state_put(state);
+ return ERR_PTR(ret);
+}
+
+/**
+ * drm_atomic_helper_readout_state - Builds an initial state from hardware state
+ * @dev: DRM device to build the state for
+ *
+ * This function creates the initial state for all the entities on a
+ * @dev. Drivers can use this as their
+ * &drm_mode_config_helper_funcs.atomic_reset callback to implement
+ * hardware state readout suppport.
+ */
+void drm_atomic_helper_readout_state(struct drm_device *dev)
+{
+ struct drm_atomic_state *state;
+
+ state = drm_atomic_build_readout_state(dev);
+ if (IS_ERR(state))
+ return;
+
+ drm_atomic_helper_install_readout_state(state);
+ drm_atomic_state_put(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_readout_state);
/**
* DOC: overview
*
* This helper library provides implementations of check and commit functions on
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 82180760032d3490d63fe83136465d2c26551d08..96d38a49be501a0090457cbe96135f82bb1358b5 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -26,10 +26,11 @@
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
#include <drm/drm_file.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_mode_config.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <linux/dma-resv.h>
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 53382fe93537bbcda9cee8827bc95de9a515efb5..47902a9181727a08581fb808faabe67d92a755cf 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -45,10 +45,11 @@
struct drm_atomic_state;
struct drm_private_obj;
struct drm_private_state;
+void drm_atomic_helper_readout_state(struct drm_device *dev);
int drm_atomic_helper_check_modeset(struct drm_device *dev,
struct drm_atomic_state *state);
int drm_atomic_helper_check_wb_connector_state(struct drm_connector *connector,
struct drm_atomic_state *state);
int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 8d9d4fd078e72977677fd992d725261232754e3e..15b63053f01869786831936ba28b7efc1e55e2e8 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -490,10 +490,31 @@ struct drm_bridge_funcs {
* The @atomic_post_disable callback is optional.
*/
void (*atomic_post_disable)(struct drm_bridge *bridge,
struct drm_atomic_state *state);
+ /**
+ * @atomic_readout_state:
+ *
+ * Initializes,this bridge atomic state.
+ *
+ * It's meant to be used by drivers that wants to implement fast
+ * / flicker-free boot and allows to initialize the atomic state
+ * from the hardware state left by the firmware.
+ *
+ * It's used at initialization time, so drivers must make sure
+ * that the power state is sensible when accessing the hardware.
+ *
+ * RETURNS:
+ *
+ * 0 on success, an error code otherwise.
+ */
+ int (*atomic_readout_state)(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state);
+
/**
* @atomic_duplicate_state:
*
* Duplicate the current bridge state object (which is guaranteed to be
* non-NULL).
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 8f34f4b8183d83dccd3e820a444fbf74fb6c16f2..f68bd9627c085c6d2463b847aaa245ccc651f27b 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1464,10 +1464,36 @@ struct drm_connector_funcs {
* when a connector is being hot-unplugged for drivers that support
* connector hotplugging (e.g. DisplayPort MST).
*/
void (*destroy)(struct drm_connector *connector);
+ /**
+ * @atomic_readout_state:
+ *
+ * Allocates, initializes, and returns an atomic state for this
+ * connector.
+ *
+ * It's meant to be used by drivers that wants to implement fast
+ * / flicker-free boot and allows to initialize the atomic state
+ * from the hardware state left by the firmware.
+ *
+ * It's used at initialization time, so drivers must make sure
+ * that the power state is sensible when accessing the hardware.
+ *
+ * The drm_atomic_state being passed is not fully filled. Only
+ * the CRTC state are there when this hooks is called, and only
+ * their old state. The only safe operation one can do on this
+ * state in this hook is calling
+ * drm_atomic_get_old_crtc_state().
+ *
+ * RETURNS:
+ *
+ * An atomic state on success, an error pointer otherwise.
+ */
+ struct drm_connector_state *(*atomic_readout_state)(struct drm_connector *connector,
+ struct drm_atomic_state *state);
+
/**
* @atomic_duplicate_state:
*
* Duplicate the current atomic state for this connector and return it.
* The core and helpers guarantee that any atomic state duplicated with
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index caa56e039da2a748cf40ebf45b37158acda439d9..c462bd9b2f7d3ae08e669463717002e5f78122fe 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -613,10 +613,29 @@ struct drm_crtc_funcs {
* 0 on success or a negative error code on failure.
*/
int (*set_property)(struct drm_crtc *crtc,
struct drm_property *property, uint64_t val);
+ /**
+ * @atomic_readout_state:
+ *
+ * Allocates, initializes, and returns an atomic state for this
+ * CRTC.
+ *
+ * It's meant to be used by drivers that wants to implement fast
+ * / flicker-free boot and allows to initialize the atomic state
+ * from the hardware state left by the firmware.
+ *
+ * It's used at initialization time, so drivers must make sure
+ * that the power state is sensible when accessing the hardware.
+ *
+ * RETURNS:
+ *
+ * An atomic state on success, an error pointer otherwise.
+ */
+ struct drm_crtc_state *(*atomic_readout_state)(struct drm_crtc *crtc);
+
/**
* @atomic_duplicate_state:
*
* Duplicate the current atomic state for this CRTC and return it.
* The core and helpers guarantee that any atomic state duplicated with
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 01479dd94e76a8389a0c9e9d6744400aa2291064..691a267c857a228f674ef02a63fb6d1ff9e379a8 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -378,10 +378,37 @@ struct drm_plane_funcs {
* 0 on success or a negative error code on failure.
*/
int (*set_property)(struct drm_plane *plane,
struct drm_property *property, uint64_t val);
+ /**
+ * @atomic_readout_state:
+ *
+ * Allocates, initializes, and returns an atomic state for this
+ * plane.
+ *
+ * It's meant to be used by drivers that wants to implement fast
+ * / flicker-free boot and allows to initialize the atomic state
+ * from the hardware state left by the firmware.
+ *
+ * It's used at initialization time, so drivers must make sure
+ * that the power state is sensible when accessing the hardware.
+ *
+ * The drm_atomic_state being passed is not fully filled. Only
+ * the CRTC and connector states are there when this hooks is
+ * called, and only their old state. The only safe operation one
+ * can do on this state in this hook is calling
+ * drm_atomic_get_old_crtc_state() and
+ * drm_atomic_get_old_connector_state().
+ *
+ * RETURNS:
+ *
+ * An atomic state on success, an error pointer otherwise.
+ */
+ struct drm_plane_state *(*atomic_readout_state)(struct drm_plane *plane,
+ struct drm_atomic_state *state);
+
/**
* @atomic_duplicate_state:
*
* Duplicate the current atomic state for this plane and return it.
* The core and helpers guarantee that any atomic state duplicated with
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 10/29] drm/atomic: Add atomic_state_readout infrastructure
2025-09-02 8:32 ` [PATCH 10/29] drm/atomic: Add atomic_state_readout infrastructure Maxime Ripard
@ 2025-09-02 13:44 ` Thomas Zimmermann
0 siblings, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:44 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Hi
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> In order to enable drivers to fill their initial state from the hardware
> state, we need to provide an alternative atomic_reset helper.
>
> This helper relies on each state having its own atomic_state_readout()
> hooks. Each component will thus be able to fill the initial state based
> on what they can figure out from the hardware.
>
> It also allocates a dummy drm_atomic_state to glue the whole thing
> together so atomic_state_readout implementations can still figure out
> the state of other related entities.
>
> Link: https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 382 ++++++++++++++++++++++++++++++++++++
> drivers/gpu/drm/drm_mode_config.c | 1 +
> include/drm/drm_atomic_helper.h | 1 +
> include/drm/drm_bridge.h | 21 ++
> include/drm/drm_connector.h | 26 +++
> include/drm/drm_crtc.h | 19 ++
> include/drm/drm_plane.h | 27 +++
> 7 files changed, 477 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index d5ebe6ea0acbc5a08aef7fa41ecb9ed5d8fa8e80..f59512476ebf2b48e1c7034950bcaf99237f03c6 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -45,10 +45,392 @@
> #include <drm/drm_vblank.h>
> #include <drm/drm_writeback.h>
>
> #include "drm_crtc_helper_internal.h"
> #include "drm_crtc_internal.h"
> +#include "drm_internal.h"
> +
> +static void drm_atomic_set_old_plane_state(struct drm_atomic_state *state,
> + struct drm_plane *plane,
> + struct drm_plane_state *plane_state)
> +{
> + int idx = drm_plane_index(plane);
> +
> + state->planes[idx].old_state = plane_state;
> + state->planes[idx].ptr = plane;
> +
> + drm_dbg_atomic(plane->dev, "Added [PLANE:%d:%s] %p state to %p\n",
> + plane->base.id, plane->name, plane_state, state);
> +}
> +
> +static void drm_atomic_set_old_crtc_state(struct drm_atomic_state *state,
> + struct drm_crtc *crtc,
> + struct drm_crtc_state *crtc_state)
> +{
> + int idx = drm_crtc_index(crtc);
> +
> + state->crtcs[idx].old_state = crtc_state;
> + state->crtcs[idx].ptr = crtc;
> +
> + drm_dbg_atomic(state->dev, "Added [CRTC:%d:%s] %p state to %p\n",
> + crtc->base.id, crtc->name, crtc_state, state);
> +}
> +
> +static void drm_atomic_set_old_connector_state(struct drm_atomic_state *state,
> + struct drm_connector *conn,
> + struct drm_connector_state *conn_state)
> +{
> + int idx = drm_connector_index(conn);
> +
> + drm_connector_get(conn);
> + state->connectors[idx].old_state = conn_state;
> + state->connectors[idx].ptr = conn;
> + state->num_connector++;
> +
> + drm_dbg_atomic(conn->dev,
> + "Added [CONNECTOR:%d:%s] %p state to %p\n",
> + conn->base.id, conn->name, conn_state, state);
> +}
> +
> +static void drm_atomic_set_old_private_obj_state(struct drm_atomic_state *state,
> + struct drm_private_obj *obj,
> + struct drm_private_state *obj_state)
> +{
> + int idx = state->num_private_objs;
> +
> + memset(&state->private_objs[idx], 0, sizeof(*state->private_objs));
> + state->private_objs[idx].old_state = obj_state;
> + state->private_objs[idx].ptr = obj;
> + state->num_private_objs++;
> +
> + drm_dbg_atomic(state->dev,
> + "Added new private object %p state %p to %p\n", obj,
> + obj_state, state);
> +}
> +
> +static void drm_atomic_set_old_bridge_state(struct drm_atomic_state *state,
> + struct drm_bridge *bridge,
> + struct drm_bridge_state *bridge_state)
> +{
> + drm_atomic_set_old_private_obj_state(state, &bridge->base, &bridge_state->base);
> +}
> +
> +static struct drm_connector_state *
> +find_connector_state_for_encoder(struct drm_atomic_state *state,
> + struct drm_encoder *encoder)
> +{
> + struct drm_connector_list_iter conn_iter;
> + struct drm_connector *connector;
> +
> + drm_connector_list_iter_begin(state->dev, &conn_iter);
> + drm_for_each_connector_iter(connector, &conn_iter) {
> + struct drm_connector_state *conn_state =
> + drm_atomic_get_old_connector_state(state, connector);
> +
> + if (WARN_ON(!conn_state))
> + continue;
> +
> + if (encoder == conn_state->best_encoder)
> + return conn_state;
> + }
> + drm_connector_list_iter_end(&conn_iter);
> +
> + return NULL;
> +}
> +
> +/**
> + * drm_atomic_helper_install_readout_state - Sets the state pointer from their readout state
> + * @state: drm_atomic_state to initialize the DRM device with.
> + *
> + * This function takes a &struct drm_atomic_state initialized by
> + * drm_atomic_build_readout_state() and sets up the entities state
> + * pointers (ie, &drm_crtc.state and similar) to properly setup the
> + * initial state.
> + */
> +static void
> +drm_atomic_helper_install_readout_state(struct drm_atomic_state *state)
> +{
> + struct drm_connector_state *old_conn_state;
> + struct drm_private_state *old_obj_state;
> + struct drm_plane_state *old_plane_state;
> + struct drm_crtc_state *old_crtc_state;
> + struct drm_connector *connector;
> + struct drm_private_obj *obj;
> + struct drm_plane *plane;
> + struct drm_crtc *crtc;
> + unsigned int i;
> +
> + for_each_old_connector_in_state(state, connector, old_conn_state, i) {
> + connector->state = old_conn_state;
> +
> + drm_connector_put(state->connectors[i].ptr);
> + state->connectors[i].ptr = NULL;
> + state->connectors[i].old_state = NULL;
> + }
> +
> + for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
> + crtc->state = old_crtc_state;
> +
> + state->crtcs[i].ptr = NULL;
> + state->crtcs[i].old_state = NULL;
> + }
> +
> + for_each_old_plane_in_state(state, plane, old_plane_state, i) {
> + plane->state = old_plane_state;
> +
> + state->planes[i].ptr = NULL;
> + state->planes[i].old_state = NULL;
> + }
> +
> + for_each_old_private_obj_in_state(state, obj, old_obj_state, i) {
> + obj->state = old_obj_state;
> +
> + state->private_objs[i].ptr = NULL;
> + state->private_objs[i].old_state = NULL;
> + }
> +}
> +
> +static unsigned int count_private_obj(struct drm_device *dev)
> +{
> + struct drm_mode_config *config = &dev->mode_config;
> + struct drm_private_obj *obj;
> + unsigned int count = 0;
> +
> + list_for_each_entry(obj, &config->privobj_list, head)
> + count++;
> +
> + return count;
> +}
> +
> +/**
> + * drm_atomic_build_readout_state - Creates an initial state from the hardware
> + * @dev: DRM device to build the state for
> + *
> + * This function allocates a &struct drm_atomic_state, calls the
> + * atomic_readout_state callbacks, and fills the global state old states
> + * by what the callbacks returned.
> + *
> + * Returns:
> + *
> + * A partially initialized &struct drm_atomic_state on success, an error
> + * pointer otherwise.
> + */
> +static struct drm_atomic_state *
> +drm_atomic_build_readout_state(struct drm_device *dev)
> +{
> + struct drm_connector_list_iter conn_iter;
> + struct drm_atomic_state *state;
> + struct drm_mode_config *config =
> + &dev->mode_config;
> + struct drm_connector *connector;
> + struct drm_printer p =
> + drm_info_printer(dev->dev);
> + struct drm_encoder *encoder;
> + struct drm_plane *plane;
> + struct drm_crtc *crtc;
> + int ret;
> +
> + drm_dbg_kms(dev, "Starting to build atomic state from hardware state.\n");
> +
> + state = drm_atomic_state_alloc(dev);
> + if (WARN_ON(!state))
> + return ERR_PTR(-ENOMEM);
> +
> + state->connectors = kcalloc(config->num_connector, sizeof(*state->connectors), GFP_KERNEL);
> + if (WARN_ON(!state->connectors)) {
> + ret = -ENOMEM;
> + goto err_state_put;
> + }
> +
> + state->private_objs = kcalloc(count_private_obj(dev), sizeof(*state->private_objs), GFP_KERNEL);
> + if (WARN_ON(!state->private_objs)) {
> + ret = -ENOMEM;
> + goto err_state_put;
> + }
> +
> + drm_for_each_crtc(crtc, dev) {
> + const struct drm_crtc_funcs *crtc_funcs =
> + crtc->funcs;
> + struct drm_crtc_state *crtc_state;
> +
> + drm_dbg_kms(dev, "Initializing CRTC %s state.\n", crtc->name);
> +
> + if (crtc_funcs->atomic_readout_state) {
> + crtc_state = crtc_funcs->atomic_readout_state(crtc);
> + } else if (crtc_funcs->reset) {
> + crtc_funcs->reset(crtc);
> +
> + /*
> + * We don't want to set crtc->state field yet. Let's save and clear it up.
> + */
> + crtc_state = crtc->state;
> + crtc->state = NULL;
Chancing the crtc->state pointer behind the back of the reset callback
seems fragile. We never how if some other piece of the driver refers to
it (although illegally).
For now, wouldn't it be better to require a read-out helper for all
elements of the driver's mode-setting pipeline? The trivial
implementation would copy the existing reset function and keep
crtc->state to NULL.
> + } else {
> + drm_warn(dev, "No CRTC readout or reset implementation.");
> + continue;
> + }
> +
> + if (WARN_ON(IS_ERR(crtc_state))) {
> + ret = PTR_ERR(crtc_state);
> + goto err_state_put;
> + }
> +
> + drm_atomic_set_old_crtc_state(state, crtc, crtc_state);
> + }
> +
> + drm_connector_list_iter_begin(dev, &conn_iter);
> + drm_for_each_connector_iter(connector, &conn_iter) {
> + const struct drm_connector_funcs *conn_funcs =
> + connector->funcs;
> + struct drm_connector_state *conn_state;
> +
> + drm_dbg_kms(dev, "Initializing Connector %s state.\n", connector->name);
> +
> + if (conn_funcs->atomic_readout_state) {
> + conn_state = conn_funcs->atomic_readout_state(connector, state);
> + } else if (conn_funcs->reset) {
> + conn_funcs->reset(connector);
> +
> + /*
> + * We don't want to set connector->state field yet. Let's save and clear it
> + * up.
> + */
> + conn_state = connector->state;
> + connector->state = NULL;
> + } else {
> + drm_warn(dev, "No Connector readout or reset implementation.");
> + continue;
> + }
> +
> + if (WARN_ON(IS_ERR(conn_state))) {
> + ret = PTR_ERR(conn_state);
> + goto err_state_put;
> + }
> +
> + drm_atomic_set_old_connector_state(state, connector, conn_state);
> + }
> + drm_connector_list_iter_end(&conn_iter);
> +
> + WARN_ON(state->num_connector != config->num_connector);
drm_WARN_ON() here and elsewhere.
> +
> + drm_for_each_encoder(encoder, dev) {
> + struct drm_connector_state *enc_conn_state;
> + struct drm_crtc_state *enc_crtc_state;
> + struct drm_bridge *bridge;
> +
> + /*
> + * It works a bit differently for bridges. Because they are
> + * using a drm_private_state, and because
> + * drm_atomic_private_obj_init() asks for its initial state when
> + * initializing, instead of doing it later on through a reset
> + * call like the other entities, we can't have reset xor
> + * readout.
> + *
> + * We'll need a mandatory reset to create that initial, blank,
> + * state, and then readout will fill that state later on if the
> + * driver implements it.
> + *
> + * This also means we don't need to call the readout state
> + * function if we don't have the bridge enabled (ie, if no
> + * drm_connector_state->best_encoder points to bridge->encoder,
> + * and / or if drm_connector_state->crtc is NULL).
> + *
> + * In such a case, we would get the blank state reset created
> + * during registration.
> + */
> +
> + enc_conn_state = find_connector_state_for_encoder(state, encoder);
> + if (!enc_conn_state)
> + continue;
> +
> + enc_crtc_state = drm_atomic_get_old_crtc_state(state, enc_conn_state->crtc);
> + if (!enc_crtc_state)
> + continue;
> +
> + list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
> + const struct drm_bridge_funcs *bridge_funcs = bridge->funcs;
> + struct drm_bridge_state *bridge_state;
> +
> + bridge_state = drm_bridge_get_current_state(bridge);
> + if (WARN_ON(!bridge_state)) {
> + ret = -EINVAL;
> + goto err_state_put;
> + }
> +
> + if (bridge_funcs->atomic_readout_state) {
> + ret = bridge_funcs->atomic_readout_state(bridge,
> + bridge_state,
> + enc_crtc_state,
> + enc_conn_state);
> + if (WARN_ON(ret))
> + goto err_state_put;
> + }
> +
> + drm_atomic_set_old_bridge_state(state, bridge, bridge_state);
> + }
> + }
> +
> + drm_for_each_plane(plane, dev) {
> + const struct drm_plane_funcs *plane_funcs =
> + plane->funcs;
> + struct drm_plane_state *plane_state;
> +
> + drm_dbg_kms(dev, "Initializing Plane %s state.\n", plane->name);
> +
> + if (plane_funcs->atomic_readout_state) {
> + plane_state = plane_funcs->atomic_readout_state(plane, state);
> + } else if (plane_funcs->reset) {
> + plane_funcs->reset(plane);
> +
> + /*
> + * We don't want to set conn->state field yet. Let's save and clear it up.
> + */
> + plane_state = plane->state;
> + plane->state = NULL;
> + } else {
> + drm_warn(dev, "No plane readout or reset implementation.");
> + continue;
> + }
> +
> + if (WARN_ON(IS_ERR(plane_state))) {
> + ret = PTR_ERR(plane_state);
> + goto err_state_put;
> + }
> +
> + drm_atomic_set_old_plane_state(state, plane, plane_state);
> + }
> +
> + drm_atomic_print_old_state(state, &p);
> +
> + return state;
> +
> +err_state_put:
> + drm_atomic_state_put(state);
> + return ERR_PTR(ret);
> +}
> +
> +/**
> + * drm_atomic_helper_readout_state - Builds an initial state from hardware state
> + * @dev: DRM device to build the state for
> + *
> + * This function creates the initial state for all the entities on a
> + * @dev. Drivers can use this as their
> + * &drm_mode_config_helper_funcs.atomic_reset callback to implement
> + * hardware state readout suppport.
> + */
> +void drm_atomic_helper_readout_state(struct drm_device *dev)
> +{
> + struct drm_atomic_state *state;
> +
> + state = drm_atomic_build_readout_state(dev);
> + if (IS_ERR(state))
> + return;
> +
> + drm_atomic_helper_install_readout_state(state);
> + drm_atomic_state_put(state);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_readout_state);
>
> /**
> * DOC: overview
> *
> * This helper library provides implementations of check and commit functions on
> diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
> index 82180760032d3490d63fe83136465d2c26551d08..96d38a49be501a0090457cbe96135f82bb1358b5 100644
> --- a/drivers/gpu/drm/drm_mode_config.c
> +++ b/drivers/gpu/drm/drm_mode_config.c
> @@ -26,10 +26,11 @@
> #include <drm/drm_drv.h>
> #include <drm/drm_encoder.h>
> #include <drm/drm_file.h>
> #include <drm/drm_framebuffer.h>
> #include <drm/drm_managed.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> #include <drm/drm_mode_config.h>
> #include <drm/drm_modeset_helper_vtables.h>
> #include <drm/drm_print.h>
> #include <linux/dma-resv.h>
>
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> index 53382fe93537bbcda9cee8827bc95de9a515efb5..47902a9181727a08581fb808faabe67d92a755cf 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -45,10 +45,11 @@
>
> struct drm_atomic_state;
> struct drm_private_obj;
> struct drm_private_state;
>
> +void drm_atomic_helper_readout_state(struct drm_device *dev);
> int drm_atomic_helper_check_modeset(struct drm_device *dev,
> struct drm_atomic_state *state);
> int drm_atomic_helper_check_wb_connector_state(struct drm_connector *connector,
> struct drm_atomic_state *state);
> int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 8d9d4fd078e72977677fd992d725261232754e3e..15b63053f01869786831936ba28b7efc1e55e2e8 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -490,10 +490,31 @@ struct drm_bridge_funcs {
> * The @atomic_post_disable callback is optional.
> */
> void (*atomic_post_disable)(struct drm_bridge *bridge,
> struct drm_atomic_state *state);
>
> + /**
> + * @atomic_readout_state:
> + *
> + * Initializes,this bridge atomic state.
> + *
> + * It's meant to be used by drivers that wants to implement fast
'want'
> + * / flicker-free boot and allows to initialize the atomic state
I think we should only call it flicker-free boot. Fast boot is misleading.
> + * from the hardware state left by the firmware.
> + *
> + * It's used at initialization time, so drivers must make sure
> + * that the power state is sensible when accessing the hardware.
> + *
> + * RETURNS:
> + *
> + * 0 on success, an error code otherwise.
> + */
> + int (*atomic_readout_state)(struct drm_bridge *bridge,
> + struct drm_bridge_state *bridge_state,
> + struct drm_crtc_state *crtc_state,
> + struct drm_connector_state *conn_state);
> +
> /**
> * @atomic_duplicate_state:
> *
> * Duplicate the current bridge state object (which is guaranteed to be
> * non-NULL).
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index 8f34f4b8183d83dccd3e820a444fbf74fb6c16f2..f68bd9627c085c6d2463b847aaa245ccc651f27b 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -1464,10 +1464,36 @@ struct drm_connector_funcs {
> * when a connector is being hot-unplugged for drivers that support
> * connector hotplugging (e.g. DisplayPort MST).
> */
> void (*destroy)(struct drm_connector *connector);
>
> + /**
> + * @atomic_readout_state:
> + *
> + * Allocates, initializes, and returns an atomic state for this
> + * connector.
> + *
> + * It's meant to be used by drivers that wants to implement fast
> + * / flicker-free boot and allows to initialize the atomic state
> + * from the hardware state left by the firmware.
> + *
> + * It's used at initialization time, so drivers must make sure
> + * that the power state is sensible when accessing the hardware.
> + *
> + * The drm_atomic_state being passed is not fully filled. Only
> + * the CRTC state are there when this hooks is called, and only
> + * their old state. The only safe operation one can do on this
> + * state in this hook is calling
> + * drm_atomic_get_old_crtc_state().
> + *
> + * RETURNS:
> + *
> + * An atomic state on success, an error pointer otherwise.
> + */
> + struct drm_connector_state *(*atomic_readout_state)(struct drm_connector *connector,
> + struct drm_atomic_state *state);
> +
> /**
> * @atomic_duplicate_state:
> *
> * Duplicate the current atomic state for this connector and return it.
> * The core and helpers guarantee that any atomic state duplicated with
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index caa56e039da2a748cf40ebf45b37158acda439d9..c462bd9b2f7d3ae08e669463717002e5f78122fe 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -613,10 +613,29 @@ struct drm_crtc_funcs {
> * 0 on success or a negative error code on failure.
> */
> int (*set_property)(struct drm_crtc *crtc,
> struct drm_property *property, uint64_t val);
>
> + /**
> + * @atomic_readout_state:
> + *
> + * Allocates, initializes, and returns an atomic state for this
> + * CRTC.
> + *
> + * It's meant to be used by drivers that wants to implement fast
> + * / flicker-free boot and allows to initialize the atomic state
> + * from the hardware state left by the firmware.
> + *
> + * It's used at initialization time, so drivers must make sure
> + * that the power state is sensible when accessing the hardware.
> + *
> + * RETURNS:
> + *
> + * An atomic state on success, an error pointer otherwise.
> + */
> + struct drm_crtc_state *(*atomic_readout_state)(struct drm_crtc *crtc);
> +
> /**
> * @atomic_duplicate_state:
> *
> * Duplicate the current atomic state for this CRTC and return it.
> * The core and helpers guarantee that any atomic state duplicated with
> diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
> index 01479dd94e76a8389a0c9e9d6744400aa2291064..691a267c857a228f674ef02a63fb6d1ff9e379a8 100644
> --- a/include/drm/drm_plane.h
> +++ b/include/drm/drm_plane.h
> @@ -378,10 +378,37 @@ struct drm_plane_funcs {
> * 0 on success or a negative error code on failure.
> */
> int (*set_property)(struct drm_plane *plane,
> struct drm_property *property, uint64_t val);
>
> + /**
> + * @atomic_readout_state:
> + *
> + * Allocates, initializes, and returns an atomic state for this
> + * plane.
> + *
> + * It's meant to be used by drivers that wants to implement fast
> + * / flicker-free boot and allows to initialize the atomic state
> + * from the hardware state left by the firmware.
> + *
> + * It's used at initialization time, so drivers must make sure
> + * that the power state is sensible when accessing the hardware.
> + *
> + * The drm_atomic_state being passed is not fully filled. Only
> + * the CRTC and connector states are there when this hooks is
> + * called, and only their old state. The only safe operation one
> + * can do on this state in this hook is calling
> + * drm_atomic_get_old_crtc_state() and
> + * drm_atomic_get_old_connector_state().
> + *
> + * RETURNS:
> + *
> + * An atomic state on success, an error pointer otherwise.
> + */
> + struct drm_plane_state *(*atomic_readout_state)(struct drm_plane *plane,
> + struct drm_atomic_state *state);
> +
> /**
> * @atomic_duplicate_state:
> *
> * Duplicate the current atomic state for this plane and return it.
> * The core and helpers guarantee that any atomic state duplicated with
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 11/29] drm/crtc: Drop no_vblank bit field
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (9 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 10/29] drm/atomic: Add atomic_state_readout infrastructure Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:45 ` Thomas Zimmermann
2025-09-02 8:32 ` [PATCH 12/29] drm/atomic_helper: Pass nonblock to commit_tail Maxime Ripard
` (18 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The no_vblank field in drm_crtc_state is defined as a bit-field with a
single bit.
This will create a syntax issue with the macros we'll introduce next,
and most other booleans but the *_changed ones in drm_crtc_state do not
use a bit field anyway.
Let's drop it.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
include/drm/drm_crtc.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index c462bd9b2f7d3ae08e669463717002e5f78122fe..11e3299cfad1572c6e507918c7cceae7a28ba4cf 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -184,11 +184,11 @@ struct drm_crtc_state {
* &drm_crtc_state.no_blank == true is valid and usually used when the
* writeback connector attached to the CRTC has a new job queued. In
* this case the driver will send the VBLANK event on its own when the
* writeback job is complete.
*/
- bool no_vblank : 1;
+ bool no_vblank;
/**
* @plane_mask: Bitmask of drm_plane_mask(plane) of planes attached to
* this CRTC.
*/
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 11/29] drm/crtc: Drop no_vblank bit field
2025-09-02 8:32 ` [PATCH 11/29] drm/crtc: Drop no_vblank bit field Maxime Ripard
@ 2025-09-02 13:45 ` Thomas Zimmermann
0 siblings, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:45 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> The no_vblank field in drm_crtc_state is defined as a bit-field with a
> single bit.
>
> This will create a syntax issue with the macros we'll introduce next,
> and most other booleans but the *_changed ones in drm_crtc_state do not
> use a bit field anyway.
>
> Let's drop it.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> include/drm/drm_crtc.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index c462bd9b2f7d3ae08e669463717002e5f78122fe..11e3299cfad1572c6e507918c7cceae7a28ba4cf 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -184,11 +184,11 @@ struct drm_crtc_state {
> * &drm_crtc_state.no_blank == true is valid and usually used when the
> * writeback connector attached to the CRTC has a new job queued. In
> * this case the driver will send the VBLANK event on its own when the
> * writeback job is complete.
> */
> - bool no_vblank : 1;
> + bool no_vblank;
>
> /**
> * @plane_mask: Bitmask of drm_plane_mask(plane) of planes attached to
> * this CRTC.
> */
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 12/29] drm/atomic_helper: Pass nonblock to commit_tail
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (10 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 11/29] drm/crtc: Drop no_vblank bit field Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:46 ` Thomas Zimmermann
2025-09-02 8:32 ` [PATCH 13/29] drm/atomic_helper: Compare actual and readout states once the commit is done Maxime Ripard
` (17 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
We'll need to know if a commit is blocking or non-blocking in
commit_tail later on, so let's pass it along.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_helper.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index f59512476ebf2b48e1c7034950bcaf99237f03c6..14d9bc282ca570964e494936090898b2dc6bee31 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -2332,11 +2332,11 @@ void drm_atomic_helper_commit_tail_rpm(struct drm_atomic_state *state)
drm_atomic_helper_cleanup_planes(dev, state);
}
EXPORT_SYMBOL(drm_atomic_helper_commit_tail_rpm);
-static void commit_tail(struct drm_atomic_state *state)
+static void commit_tail(struct drm_atomic_state *state, bool nonblock)
{
struct drm_device *dev = state->dev;
const struct drm_mode_config_helper_funcs *funcs;
struct drm_crtc_state *new_crtc_state;
struct drm_crtc *crtc;
@@ -2390,11 +2390,11 @@ static void commit_tail(struct drm_atomic_state *state)
static void commit_work(struct work_struct *work)
{
struct drm_atomic_state *state = container_of(work,
struct drm_atomic_state,
commit_work);
- commit_tail(state);
+ commit_tail(state, true);
}
/**
* drm_atomic_helper_async_check - check if state can be committed asynchronously
* @dev: DRM device
@@ -2610,11 +2610,11 @@ int drm_atomic_helper_commit(struct drm_device *dev,
drm_atomic_state_get(state);
if (nonblock)
queue_work(system_unbound_wq, &state->commit_work);
else
- commit_tail(state);
+ commit_tail(state, false);
return 0;
err:
drm_atomic_helper_unprepare_planes(dev, state);
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 12/29] drm/atomic_helper: Pass nonblock to commit_tail
2025-09-02 8:32 ` [PATCH 12/29] drm/atomic_helper: Pass nonblock to commit_tail Maxime Ripard
@ 2025-09-02 13:46 ` Thomas Zimmermann
0 siblings, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:46 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> We'll need to know if a commit is blocking or non-blocking in
> commit_tail later on, so let's pass it along.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index f59512476ebf2b48e1c7034950bcaf99237f03c6..14d9bc282ca570964e494936090898b2dc6bee31 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -2332,11 +2332,11 @@ void drm_atomic_helper_commit_tail_rpm(struct drm_atomic_state *state)
>
> drm_atomic_helper_cleanup_planes(dev, state);
> }
> EXPORT_SYMBOL(drm_atomic_helper_commit_tail_rpm);
>
> -static void commit_tail(struct drm_atomic_state *state)
> +static void commit_tail(struct drm_atomic_state *state, bool nonblock)
> {
> struct drm_device *dev = state->dev;
> const struct drm_mode_config_helper_funcs *funcs;
> struct drm_crtc_state *new_crtc_state;
> struct drm_crtc *crtc;
> @@ -2390,11 +2390,11 @@ static void commit_tail(struct drm_atomic_state *state)
> static void commit_work(struct work_struct *work)
> {
> struct drm_atomic_state *state = container_of(work,
> struct drm_atomic_state,
> commit_work);
> - commit_tail(state);
> + commit_tail(state, true);
> }
>
> /**
> * drm_atomic_helper_async_check - check if state can be committed asynchronously
> * @dev: DRM device
> @@ -2610,11 +2610,11 @@ int drm_atomic_helper_commit(struct drm_device *dev,
>
> drm_atomic_state_get(state);
> if (nonblock)
> queue_work(system_unbound_wq, &state->commit_work);
> else
> - commit_tail(state);
> + commit_tail(state, false);
>
> return 0;
>
> err:
> drm_atomic_helper_unprepare_planes(dev, state);
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 13/29] drm/atomic_helper: Compare actual and readout states once the commit is done
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (11 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 12/29] drm/atomic_helper: Pass nonblock to commit_tail Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 8:32 ` [PATCH 14/29] drm/atomic_state_helper: Provide comparison macros Maxime Ripard
` (16 subsequent siblings)
29 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The new atomic state readout infrastructure can be hard to test because
getting access to every firmware variation is hard, but also because
most firmware setup will be pretty basic and won't test a wide range of
features. Noticing whether it was sucessful or not is also not very
convenient.
In order to make it easier, we can however provide some infrastructure
to read out a new state every time a non-blocking commit is made, and
compare the readout one with the committed one. And since we do this
only on non-blocking commits, the time penalty doesn't matter.
To do so, we introduce a new hook for every state, atomic_compare_state,
that takes two state instances and is supposed to return whether they
are identical or not.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_helper.c | 113 ++++++++++++++++++++++++++++++++++++
include/drm/drm_atomic.h | 14 +++++
include/drm/drm_bridge.h | 14 +++++
include/drm/drm_connector.h | 14 +++++
include/drm/drm_crtc.h | 14 +++++
include/drm/drm_plane.h | 14 +++++
6 files changed, 183 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 14d9bc282ca570964e494936090898b2dc6bee31..aa8f52b5d5a5e6146a6472eebaf02e675c35ccd2 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -428,10 +428,120 @@ void drm_atomic_helper_readout_state(struct drm_device *dev)
drm_atomic_helper_install_readout_state(state);
drm_atomic_state_put(state);
}
EXPORT_SYMBOL(drm_atomic_helper_readout_state);
+static bool drm_atomic_helper_readout_compare(struct drm_atomic_state *committed_state)
+{
+ struct drm_device *dev = committed_state->dev;
+ struct drm_printer p = drm_err_printer(dev, NULL);
+ struct drm_private_state *new_obj_state;
+ struct drm_private_obj *obj;
+ struct drm_plane_state *new_plane_state;
+ struct drm_plane *plane;
+ struct drm_crtc_state *new_crtc_state;
+ struct drm_crtc *crtc;
+ struct drm_connector_state *new_conn_state;
+ struct drm_connector *conn;
+ struct drm_atomic_state *readout_state;
+ unsigned int i;
+ bool identical = true;
+
+ readout_state = drm_atomic_build_readout_state(dev);
+ if (WARN_ON(IS_ERR(readout_state)))
+ return false;
+
+ for_each_new_plane_in_state(committed_state, plane, new_plane_state, i) {
+ const struct drm_plane_funcs *plane_funcs =
+ plane->funcs;
+ struct drm_plane_state *readout_plane_state;
+
+ readout_plane_state = drm_atomic_get_old_plane_state(readout_state, plane);
+ if (!readout_plane_state) {
+ identical = false;
+ continue;
+ }
+
+ if (!plane_funcs->atomic_compare_state)
+ continue;
+
+ if (!plane_funcs->atomic_compare_state(plane, &p, new_plane_state, readout_plane_state)) {
+ drm_warn(dev, "[PLANE:%d:%s] Committed and Readout PLANE state don't match\n",
+ plane->base.id, plane->name);
+ identical = false;
+ continue;
+ }
+ }
+
+ for_each_new_crtc_in_state(committed_state, crtc, new_crtc_state, i) {
+ const struct drm_crtc_funcs *crtc_funcs = crtc->funcs;
+ struct drm_crtc_state *readout_crtc_state;
+
+ readout_crtc_state = drm_atomic_get_old_crtc_state(readout_state, crtc);
+ if (!readout_crtc_state) {
+ identical = false;
+ continue;
+ }
+
+ if (!crtc_funcs->atomic_compare_state)
+ continue;
+
+ if (!crtc_funcs->atomic_compare_state(crtc, &p, new_crtc_state, readout_crtc_state)) {
+ drm_warn(dev, "[CRTC:%d:%s] Committed and Readout CRTC state don't match\n",
+ crtc->base.id, crtc->name);
+ identical = false;
+ continue;
+ }
+ }
+
+ for_each_new_connector_in_state(committed_state, conn, new_conn_state, i) {
+ const struct drm_connector_funcs *conn_funcs =
+ conn->funcs;
+ struct drm_connector_state *readout_conn_state;
+
+ readout_conn_state = drm_atomic_get_old_connector_state(readout_state, conn);
+ if (!readout_conn_state) {
+ identical = false;
+ continue;
+ }
+
+ if (!conn_funcs->atomic_compare_state)
+ continue;
+
+ if (!conn_funcs->atomic_compare_state(conn, &p, new_conn_state, readout_conn_state)) {
+ drm_warn(dev, "[CONNECTOR:%d:%s] Committed and Readout connector state don't match\n",
+ conn->base.id, conn->name);
+ identical = false;
+ continue;
+ }
+ }
+
+ for_each_new_private_obj_in_state(committed_state, obj, new_obj_state, i) {
+ const struct drm_private_state_funcs *obj_funcs = obj->funcs;
+ struct drm_private_state *readout_obj_state;
+
+ readout_obj_state = drm_atomic_get_old_private_obj_state(readout_state, obj);
+ if (!readout_obj_state) {
+ identical = false;
+ continue;
+ }
+
+ if (!obj_funcs->atomic_compare_state)
+ continue;
+
+ if (!obj_funcs->atomic_compare_state(obj, &p, new_obj_state, readout_obj_state)) {
+ drm_warn(dev, "Committed and Readout private object state don't match\n");
+ identical = false;
+ continue;
+ }
+ }
+
+ drm_atomic_state_put(readout_state);
+
+ return identical;
+}
+
/**
* DOC: overview
*
* This helper library provides implementations of check and commit functions on
* top of the CRTC modeset helper callbacks and the plane helper callbacks. It
@@ -2382,10 +2492,13 @@ static void commit_tail(struct drm_atomic_state *state, bool nonblock)
(unsigned long)commit_time_ms,
new_self_refresh_mask);
drm_atomic_helper_commit_cleanup_done(state);
+ if (!nonblock)
+ drm_atomic_helper_readout_compare(state);
+
drm_atomic_state_put(state);
}
static void commit_work(struct work_struct *work)
{
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index f13f926d21047e42bb9ac692c2dd4b88f2ebd91c..d75a9c7e23adf7fa264df766b47526f75e9cc753 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -226,10 +226,24 @@ struct drm_private_state_funcs {
* Frees the private object state created with @atomic_duplicate_state.
*/
void (*atomic_destroy_state)(struct drm_private_obj *obj,
struct drm_private_state *state);
+ /**
+ * @atomic_compare_state
+ *
+ * Compares two &struct drm_private_state instances.
+ *
+ * RETURNS:
+ *
+ * True if the states are identical, false otherwise.
+ */
+ bool (*atomic_compare_state)(struct drm_private_obj *obj,
+ struct drm_printer *p,
+ struct drm_private_state *a,
+ struct drm_private_state *b);
+
/**
* @atomic_print_state:
*
* If driver subclasses &struct drm_private_state, it should implement
* this optional hook for printing additional driver specific state.
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 15b63053f01869786831936ba28b7efc1e55e2e8..5ea63b51a4dd4cb00468afcf7d126c774f63ade0 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -511,10 +511,24 @@ struct drm_bridge_funcs {
int (*atomic_readout_state)(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state);
+ /**
+ * @atomic_compare_state
+ *
+ * Compares two &struct drm_bridge_state instances.
+ *
+ * RETURNS:
+ *
+ * True if the states are identical, false otherwise.
+ */
+ bool (*atomic_compare_state)(struct drm_bridge *bridge,
+ struct drm_printer *p,
+ struct drm_bridge_state *a,
+ struct drm_bridge_state *b);
+
/**
* @atomic_duplicate_state:
*
* Duplicate the current bridge state object (which is guaranteed to be
* non-NULL).
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index f68bd9627c085c6d2463b847aaa245ccc651f27b..dc2c77b04df9010cbfb2028de8ef8c747003c489 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1534,10 +1534,24 @@ struct drm_connector_funcs {
* This callback is mandatory for atomic drivers.
*/
void (*atomic_destroy_state)(struct drm_connector *connector,
struct drm_connector_state *state);
+ /**
+ * @atomic_compare_state
+ *
+ * Compares two &struct drm_connector_state instances.
+ *
+ * RETURNS:
+ *
+ * True if the states are identical, false otherwise.
+ */
+ bool (*atomic_compare_state)(struct drm_connector *connector,
+ struct drm_printer *p,
+ struct drm_connector_state *a,
+ struct drm_connector_state *b);
+
/**
* @atomic_set_property:
*
* Decode a driver-private property value and store the decoded value
* into the passed-in state structure. Since the atomic core decodes all
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 11e3299cfad1572c6e507918c7cceae7a28ba4cf..21c20ecdda40f3d155d3c140e06b3801270f5262 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -676,10 +676,24 @@ struct drm_crtc_funcs {
* This callback is mandatory for atomic drivers.
*/
void (*atomic_destroy_state)(struct drm_crtc *crtc,
struct drm_crtc_state *state);
+ /**
+ * @atomic_compare_state
+ *
+ * Compares two &struct drm_crtc_state instances.
+ *
+ * RETURNS:
+ *
+ * True if the states are identical, false otherwise.
+ */
+ bool (*atomic_compare_state)(struct drm_crtc *crtc,
+ struct drm_printer *p,
+ struct drm_crtc_state *a,
+ struct drm_crtc_state *b);
+
/**
* @atomic_set_property:
*
* Decode a driver-private property value and store the decoded value
* into the passed-in state structure. Since the atomic core decodes all
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 691a267c857a228f674ef02a63fb6d1ff9e379a8..c24c10ccc8e8f2ba23e77e279aef61ae86e320c7 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -449,10 +449,24 @@ struct drm_plane_funcs {
* This callback is mandatory for atomic drivers.
*/
void (*atomic_destroy_state)(struct drm_plane *plane,
struct drm_plane_state *state);
+ /**
+ * @atomic_compare_state
+ *
+ * Compares two &struct drm_plane_state instances.
+ *
+ * RETURNS:
+ *
+ * True if the states are identical, false otherwise.
+ */
+ bool (*atomic_compare_state)(struct drm_plane *plane,
+ struct drm_printer *p,
+ struct drm_plane_state *a,
+ struct drm_plane_state *b);
+
/**
* @atomic_set_property:
*
* Decode a driver-private property value and store the decoded value
* into the passed-in state structure. Since the atomic core decodes all
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH 14/29] drm/atomic_state_helper: Provide comparison macros
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (12 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 13/29] drm/atomic_helper: Compare actual and readout states once the commit is done Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 8:32 ` [PATCH 15/29] drm/atomic_state_helper: Provide atomic_compare_state helpers Maxime Ripard
` (15 subsequent siblings)
29 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
In order to make the implementation of atomic_compare_state easier and
reduce the boilerplate, this patch implements a bunch of macros to
compare values depending on their type.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 19 +++
include/drm/drm_atomic_state_helper.h | 218 ++++++++++++++++++++++++++++++
2 files changed, 237 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index b962c342b16aabf4e3bea52a914e5deb1c2080ce..78556e0c08d2fa84b16d70243ddd21617a322014 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -830,5 +830,24 @@ drm_atomic_helper_bridge_reset(struct drm_bridge *bridge)
__drm_atomic_helper_bridge_reset(bridge, bridge_state);
return bridge_state;
}
EXPORT_SYMBOL(drm_atomic_helper_bridge_reset);
+
+void __printf(4, 5)
+drm_atomic_helper_print_state_mismatch(struct drm_printer *p,
+ const char *name,
+ const char *field,
+ const char *format, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, format);
+ vaf.fmt = format;
+ vaf.va = &args;
+
+ drm_printf(p, "%s configuration mismatch in %s %pV\n", name, field, &vaf);
+
+ va_end(args);
+}
+EXPORT_SYMBOL(drm_atomic_helper_print_state_mismatch);
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index b9740edb26586d58f99a5223902bb8e333ac75a2..3c6ffa7122cf895f1eda09ec74c6537594d4aee3 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -22,19 +22,21 @@
* Authors:
* Rob Clark <robdclark@gmail.com>
* Daniel Vetter <daniel.vetter@ffwll.ch>
*/
+#include <linux/string_choices.h>
#include <linux/types.h>
struct drm_atomic_state;
struct drm_bridge;
struct drm_bridge_state;
struct drm_crtc;
struct drm_crtc_state;
struct drm_plane;
struct drm_plane_state;
+struct drm_printer;
struct drm_connector;
struct drm_connector_state;
struct drm_private_obj;
struct drm_private_state;
struct drm_modeset_acquire_ctx;
@@ -95,5 +97,221 @@ void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge,
struct drm_bridge_state *state);
void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
struct drm_bridge_state *state);
struct drm_bridge_state *
drm_atomic_helper_bridge_reset(struct drm_bridge *bridge);
+
+void __printf(4, 5)
+drm_atomic_helper_print_state_mismatch(struct drm_printer *p,
+ const char *name,
+ const char *field,
+ const char *format, ...);
+
+#define STATE_CHECK_BOOL(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ static_assert(__same_type(sa->f, bool), \
+ __stringify(name) " is not a bool"); \
+ if (sa->f != sb->f) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "expected %s, got %s", \
+ str_yes_no(sa->f), \
+ str_yes_no(sb->f)); \
+ r = false; \
+ } \
+ } while (0)
+
+#define STATE_CHECK_DISPLAY_MODE(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ static_assert(__same_type(sa->f, struct drm_display_mode), \
+ __stringify(name) " is not a drm_display_mode structure"); \
+ if (!drm_mode_equal(&sa->f, &sb->f)) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "expected " DRM_MODE_FMT ", got " DRM_MODE_FMT, \
+ DRM_MODE_ARG(&sa->f), \
+ DRM_MODE_ARG(&sb->f)); \
+ r = false; \
+ } \
+ } while (0)
+
+#define STATE_CHECK_INFOFRAME(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ static_assert(__same_type(sa->f, union hdmi_infoframe), \
+ __stringify(name) " is not an hdmi_infoframe union"); \
+ if (memcmp(&sa->f, &sb->f, sizeof(union hdmi_infoframe))) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "infoframes don't match"); \
+ r = false; \
+ } \
+ } while (0)
+
+#define STATE_CHECK_FORMAT_INFO(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ static_assert(__same_type(sa->f, const struct drm_format_info *), \
+ __stringify(name) " is not a drm_format_info pointer"); \
+ if (sa->f != sb->f) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "expected %p4cc, got %p4cc", \
+ &sa->f->format, \
+ &sb->f->format); \
+ r = false; \
+ } \
+ } while (0)
+
+#define STATE_CHECK_PROPERTY_BLOB(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ static_assert(__same_type(sa->f, struct drm_property_blob *), \
+ __stringify(name) " is not a drm_property_blob pointer"); \
+ if (sa->f != sb->f && \
+ ((sa->f->length != sb->f->length) || \
+ memcmp(sa->f->data, sb->f->data, sa->f->length))) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "blobs don't match"); \
+ r = false; \
+ } \
+ } while (0)
+
+#define STATE_CHECK_PTR(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ if (sa->f != sb->f) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "expected %px, got %px", \
+ sa->f, sb->f); \
+ r = false; \
+ } \
+ } while (0)
+
+#define STATE_CHECK_S32(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ static_assert(__same_type(sa->f, (s32)0), \
+ __stringify(name) " is not an s32"); \
+ if (sa->f != sb->f) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "expected %u, got %u", \
+ sa->f, sb->f); \
+ r = false; \
+ } \
+ } while (0)
+
+#define STATE_CHECK_S32_X(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ static_assert(__same_type(sa->f, (s32)0), \
+ __stringify(name) " is not an s32"); \
+ if (sa->f != sb->f) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "expected %x, got %x", \
+ sa->f, sb->f); \
+ r = false; \
+ } \
+ } while (0)
+
+#define STATE_CHECK_U16(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ static_assert(__same_type(sa->f, (u16)0), \
+ __stringify(name) " is not a u16"); \
+ if (sa->f != sb->f) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "expected %u, got %u", \
+ sa->f, sb->f); \
+ r = false; \
+ } \
+ } while (0)
+
+#define STATE_CHECK_U32(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ static_assert(__same_type(sa->f, (u32)0), \
+ __stringify(name) " is not a u32"); \
+ if (sa->f != sb->f) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "expected %u, got %u", \
+ sa->f, sb->f); \
+ r = false; \
+ } \
+ } while (0)
+
+#define STATE_CHECK_U32_16_16(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ static_assert(__same_type(sa->f, (u32)0), \
+ __stringify(name) " is not a u32"); \
+ if (sa->f != sb->f) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "expected %d.%06u, got %d.%06u", \
+ sa->f >> 16, ((sa->f && 0xffff) * 15625) >> 10, \
+ sb->f >> 16, ((sb->f && 0xffff) * 15625) >> 10); \
+ r = false; \
+ } \
+ } while (0)
+
+#define STATE_CHECK_U32_X(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ static_assert(__same_type(sa->f, (u32)0), \
+ __stringify(name) " is not a u32"); \
+ if (sa->f != sb->f) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "expected %08x, got %08x", \
+ sa->f, sb->f); \
+ r = false; \
+ } \
+ } while (0)
+
+#define STATE_CHECK_U64(r, p, n, sa, sb, f) \
+ do { \
+ static_assert(__same_type(sa->f, sb->f), \
+ __stringify(f) " field types don't match"); \
+ static_assert(__same_type(sa->f, (u64)0), \
+ __stringify(name) " is not a u64"); \
+ if (sa->f != sb->f) { \
+ drm_atomic_helper_print_state_mismatch(p, \
+ n, \
+ __stringify(f), \
+ "expected %llu, got %llu", \
+ sa->f, sb->f); \
+ r = false; \
+ } \
+ } while (0)
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH 15/29] drm/atomic_state_helper: Provide atomic_compare_state helpers
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (13 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 14/29] drm/atomic_state_helper: Provide comparison macros Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 8:32 ` [PATCH 16/29] drm/encoder: Create get_current_crtc hook Maxime Ripard
` (14 subsequent siblings)
29 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
Now that we have introduced some new infrastructure to compare state
instances, let's provide helpers for the default states.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 213 ++++++++++++++++++++++++++++++
drivers/gpu/drm/drm_bridge.c | 16 +++
include/drm/drm_atomic_state_helper.h | 19 +++
3 files changed, 248 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index 78556e0c08d2fa84b16d70243ddd21617a322014..289a8434db5e973825f8ba4616d6d8f00c8f8b0e 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -233,10 +233,48 @@ void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
__drm_atomic_helper_crtc_destroy_state(state);
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
+/**
+ * drm_atomic_helper_crtc_compare_state - default &drm_crtc_funcs.atomic_compare_state hook for crtcs
+ * @crtc: the &struct drm_crtc instance
+ * @p: the &struct drm_printer to use
+ * @expected: Expected &struct drm_crtc_state value
+ * @actual: Actual &struct drm_crtc_state value
+ *
+ * Compares @actual to @expected and returns true if they are equal.
+ */
+bool drm_atomic_helper_crtc_compare_state(struct drm_crtc *crtc,
+ struct drm_printer *p,
+ struct drm_crtc_state *expected,
+ struct drm_crtc_state *actual)
+{
+ bool ret = true;
+
+ STATE_CHECK_PTR(ret, p, crtc->name, expected, actual, crtc);
+ STATE_CHECK_BOOL(ret, p, crtc->name, expected, actual, enable);
+ STATE_CHECK_BOOL(ret, p, crtc->name, expected, actual, active);
+ STATE_CHECK_BOOL(ret, p, crtc->name, expected, actual, no_vblank);
+ STATE_CHECK_U32(ret, p, crtc->name, expected, actual, plane_mask);
+ STATE_CHECK_U32(ret, p, crtc->name, expected, actual, connector_mask);
+ STATE_CHECK_U32(ret, p, crtc->name, expected, actual, encoder_mask);
+
+ STATE_CHECK_DISPLAY_MODE(ret, p, crtc->name, expected, actual, mode);
+ STATE_CHECK_DISPLAY_MODE(ret, p, crtc->name, expected, actual, adjusted_mode);
+ STATE_CHECK_PROPERTY_BLOB(ret, p, crtc->name, expected, actual, mode_blob);
+ STATE_CHECK_PROPERTY_BLOB(ret, p, crtc->name, expected, actual, degamma_lut);
+ STATE_CHECK_PROPERTY_BLOB(ret, p, crtc->name, expected, actual, ctm);
+ STATE_CHECK_PROPERTY_BLOB(ret, p, crtc->name, expected, actual, gamma_lut);
+ STATE_CHECK_BOOL(ret, p, crtc->name, expected, actual, vrr_enabled);
+ STATE_CHECK_BOOL(ret, p, crtc->name, expected, actual, self_refresh_active);
+ STATE_CHECK_U32(ret, p, crtc->name, expected, actual, scaling_filter);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_compare_state);
+
/**
* __drm_atomic_helper_plane_state_reset - resets plane state to default values
* @plane_state: atomic plane state, must not be NULL
* @plane: plane object, must not be NULL
*
@@ -417,10 +455,100 @@ void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
__drm_atomic_helper_plane_destroy_state(state);
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
+static bool drm_atomic_helper_fb_compare(struct drm_printer *p,
+ struct drm_framebuffer *expected,
+ struct drm_framebuffer *actual)
+{
+ unsigned int i;
+ bool ret = true;
+
+ STATE_CHECK_FORMAT_INFO(ret, p, "framebuffer", expected, actual, format);
+
+ for (i = 0; i < expected->format->num_planes; i++) {
+ STATE_CHECK_U32(ret, p, "framebuffer", expected, actual, pitches[i]);
+ STATE_CHECK_U32(ret, p, "framebuffer", expected, actual, offsets[i]);
+ }
+
+ STATE_CHECK_U64(ret, p, "framebuffer", expected, actual, modifier);
+ STATE_CHECK_U32(ret, p, "framebuffer", expected, actual, width);
+ STATE_CHECK_U32(ret, p, "framebuffer", expected, actual, height);
+ STATE_CHECK_S32_X(ret, p, "framebuffer", expected, actual, flags);
+
+ return ret;
+}
+
+/**
+ * drm_atomic_helper_plane_compare_state - default &drm_plane_funcs.atomic_compare_state hook for planes
+ * @plane: drm plane
+ * @p: the &drm_printer to use
+ * @expected: Expected &struct drm_plane_state value
+ * @actual: Actual &struct drm_plane_state value
+ *
+ * Compares @actual to @expected and returns true if they are equal.
+ */
+bool drm_atomic_helper_plane_compare_state(struct drm_plane *plane,
+ struct drm_printer *p,
+ struct drm_plane_state *expected,
+ struct drm_plane_state *actual)
+{
+ bool ret = true;
+
+ STATE_CHECK_PTR(ret, p, plane->name, expected, actual, plane);
+ STATE_CHECK_PTR(ret, p, plane->name, expected, actual, crtc);
+
+ if (expected->fb && actual->fb) {
+ if (!drm_atomic_helper_fb_compare(p, expected->fb, actual->fb))
+ ret = false;
+ } else if (!(!expected->fb && !actual->fb)) {
+ drm_atomic_helper_print_state_mismatch(p,
+ plane->name,
+ "fb",
+ "expected framebuffer is %s, got %s",
+ expected->fb ? "non-NULL" : "NULL",
+ actual->fb ? "non-NULL" : "NULL");
+ ret = false;
+ }
+
+ STATE_CHECK_S32(ret, p, plane->name, expected, actual, crtc_x);
+ STATE_CHECK_S32(ret, p, plane->name, expected, actual, crtc_y);
+ STATE_CHECK_U32(ret, p, plane->name, expected, actual, crtc_w);
+ STATE_CHECK_U32(ret, p, plane->name, expected, actual, crtc_h);
+ STATE_CHECK_U32_16_16(ret, p, plane->name, expected, actual, src_x);
+ STATE_CHECK_U32_16_16(ret, p, plane->name, expected, actual, src_y);
+ STATE_CHECK_U32_16_16(ret, p, plane->name, expected, actual, src_w);
+ STATE_CHECK_U32_16_16(ret, p, plane->name, expected, actual, src_h);
+ STATE_CHECK_S32(ret, p, plane->name, expected, actual, hotspot_x);
+ STATE_CHECK_S32(ret, p, plane->name, expected, actual, hotspot_y);
+ STATE_CHECK_U16(ret, p, plane->name, expected, actual, alpha);
+ STATE_CHECK_U16(ret, p, plane->name, expected, actual, pixel_blend_mode);
+ STATE_CHECK_U32(ret, p, plane->name, expected, actual, rotation);
+ STATE_CHECK_U32(ret, p, plane->name, expected, actual, zpos);
+ STATE_CHECK_U32(ret, p, plane->name, expected, actual, normalized_zpos);
+ STATE_CHECK_U32(ret, p, plane->name, expected, actual, color_encoding);
+ STATE_CHECK_U32(ret, p, plane->name, expected, actual, color_range);
+
+ // TODO: damage clips
+
+ STATE_CHECK_BOOL(ret, p, plane->name, expected, actual, ignore_damage_clips);
+ STATE_CHECK_S32(ret, p, plane->name, expected, actual, src.x1);
+ STATE_CHECK_S32(ret, p, plane->name, expected, actual, src.x2);
+ STATE_CHECK_S32(ret, p, plane->name, expected, actual, src.y1);
+ STATE_CHECK_S32(ret, p, plane->name, expected, actual, src.y2);
+ STATE_CHECK_S32(ret, p, plane->name, expected, actual, dst.x1);
+ STATE_CHECK_S32(ret, p, plane->name, expected, actual, dst.x2);
+ STATE_CHECK_S32(ret, p, plane->name, expected, actual, dst.y1);
+ STATE_CHECK_S32(ret, p, plane->name, expected, actual, dst.y2);
+ STATE_CHECK_BOOL(ret, p, plane->name, expected, actual, visible);
+ STATE_CHECK_U32(ret, p, plane->name, expected, actual, scaling_filter);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_compare_state);
+
/**
* __drm_atomic_helper_connector_state_reset - reset the connector state
* @conn_state: atomic connector state, must not be NULL
* @connector: connectotr object, must not be NULL
*
@@ -707,10 +835,69 @@ void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
__drm_atomic_helper_connector_destroy_state(state);
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
+/**
+ * drm_atomic_helper_connector_compare_state - default &drm_connector_funcs.atomic_compare_state hook for connectors
+ * @connector: the &struct drm_connector instance
+ * @p: the &struct drm_printer to use
+ * @expected: Expected &struct drm_connector_state value
+ * @actual: Actual &struct drm_connector_state value
+ *
+ * Compares @actual to @expected and returns true if they are equal.
+ */
+bool drm_atomic_helper_connector_compare_state(struct drm_connector *conn,
+ struct drm_printer *p,
+ struct drm_connector_state *expected,
+ struct drm_connector_state *actual)
+{
+ bool ret = true;
+
+ STATE_CHECK_PTR(ret, p, conn->name, expected, actual, connector);
+ STATE_CHECK_PTR(ret, p, conn->name, expected, actual, crtc);
+ STATE_CHECK_PTR(ret, p, conn->name, expected, actual, best_encoder);
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, link_status);
+
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, tv.select_subconnector);
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, tv.subconnector);
+
+ STATE_CHECK_BOOL(ret, p, conn->name, expected, actual, self_refresh_aware);
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, picture_aspect_ratio);
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, content_type);
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, hdcp_content_type);
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, scaling_mode);
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, content_protection);
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, colorspace);
+
+ /*
+ * NOTE: We can't check max_bpc and max_requested_bpc because it
+ * will typically come from userspace and we can't read it out
+ * from the hardware.
+ */
+
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, privacy_screen_sw_state);
+ STATE_CHECK_PROPERTY_BLOB(ret, p, conn->name, expected, actual, hdr_output_metadata);
+
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, hdmi.broadcast_rgb);
+ STATE_CHECK_BOOL(ret, p, conn->name, expected, actual, hdmi.infoframes.avi.set);
+ STATE_CHECK_INFOFRAME(ret, p, conn->name, expected, actual, hdmi.infoframes.avi.data);
+ STATE_CHECK_BOOL(ret, p, conn->name, expected, actual, hdmi.infoframes.hdr_drm.set);
+ STATE_CHECK_INFOFRAME(ret, p, conn->name, expected, actual, hdmi.infoframes.hdr_drm.data);
+ STATE_CHECK_BOOL(ret, p, conn->name, expected, actual, hdmi.infoframes.spd.set);
+ STATE_CHECK_INFOFRAME(ret, p, conn->name, expected, actual, hdmi.infoframes.spd.data);
+ STATE_CHECK_BOOL(ret, p, conn->name, expected, actual, hdmi.infoframes.hdmi.set);
+ STATE_CHECK_INFOFRAME(ret, p, conn->name, expected, actual, hdmi.infoframes.hdmi.data);
+ STATE_CHECK_BOOL(ret, p, conn->name, expected, actual, hdmi.is_limited_range);
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, hdmi.output_bpc);
+ STATE_CHECK_U32(ret, p, conn->name, expected, actual, hdmi.output_format);
+ STATE_CHECK_U64(ret, p, conn->name, expected, actual, hdmi.tmds_char_rate);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_compare_state);
+
static void __drm_atomic_helper_private_obj_reset(struct drm_private_obj *obj,
struct drm_private_state *state)
{
memset(state, 0, sizeof(*state));
state->obj = obj;
@@ -831,10 +1018,36 @@ drm_atomic_helper_bridge_reset(struct drm_bridge *bridge)
__drm_atomic_helper_bridge_reset(bridge, bridge_state);
return bridge_state;
}
EXPORT_SYMBOL(drm_atomic_helper_bridge_reset);
+/**
+ * drm_atomic_helper_bridge_compare_state - default &drm_bridge_funcs.atomic_compare_state hook for bridges
+ * @bridge: the &struct drm_bridge instance
+ * @p: the &struct drm_printer to use
+ * @expected: Expected &struct drm_bridge_state value
+ * @actual: Actual &struct drm_bridge_state value
+ *
+ * Compares @actual to @expected and returns true if they are equal.
+ */
+bool drm_atomic_helper_bridge_compare_state(struct drm_bridge *bridge,
+ struct drm_printer *p,
+ struct drm_bridge_state *expected,
+ struct drm_bridge_state *actual)
+{
+ bool ret = true;
+
+ STATE_CHECK_PTR(ret, p, "bridge", expected, actual, bridge);
+ STATE_CHECK_U32_X(ret, p, "bridge", expected, actual, input_bus_cfg.format);
+ STATE_CHECK_U32_X(ret, p, "bridge", expected, actual, input_bus_cfg.flags);
+ STATE_CHECK_U32_X(ret, p, "bridge", expected, actual, output_bus_cfg.format);
+ STATE_CHECK_U32_X(ret, p, "bridge", expected, actual, output_bus_cfg.flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_bridge_compare_state);
+
void __printf(4, 5)
drm_atomic_helper_print_state_mismatch(struct drm_printer *p,
const char *name,
const char *field,
const char *format, ...)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index e803dfd8fd5aae9c16931445213df04d8715b9f6..5fe5b75773449aeeda2d723c039126106c8d5001 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -350,10 +350,25 @@ void drm_bridge_remove(struct drm_bridge *bridge)
drm_bridge_put(bridge);
}
EXPORT_SYMBOL(drm_bridge_remove);
+static bool drm_bridge_atomic_compare_priv_state(struct drm_private_obj *obj,
+ struct drm_printer *p,
+ struct drm_private_state *a,
+ struct drm_private_state *b)
+{
+ struct drm_bridge *bridge = drm_priv_to_bridge(obj);
+ struct drm_bridge_state *state_a = drm_priv_to_bridge_state(a);
+ struct drm_bridge_state *state_b = drm_priv_to_bridge_state(b);
+
+ if (bridge->funcs->atomic_compare_state)
+ return bridge->funcs->atomic_compare_state(bridge, p, state_a, state_b);
+ else
+ return false;
+}
+
static struct drm_private_state *
drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj)
{
struct drm_bridge *bridge = drm_priv_to_bridge(obj);
struct drm_bridge_state *state;
@@ -388,10 +403,11 @@ drm_bridge_atomic_print_priv_state(struct drm_printer *p,
drm_printf(p, "\t\tcode: %04x", state->output_bus_cfg.format);
drm_printf(p, "\t\tflags: %08x", state->output_bus_cfg.flags);
}
static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
+ .atomic_compare_state = drm_bridge_atomic_compare_priv_state,
.atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
.atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
.atomic_print_state = drm_bridge_atomic_print_priv_state,
};
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index 3c6ffa7122cf895f1eda09ec74c6537594d4aee3..7542b1679a623ddd8bb5ed12e770832f3ccf16ee 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -35,10 +35,11 @@ struct drm_crtc_state;
struct drm_plane;
struct drm_plane_state;
struct drm_printer;
struct drm_connector;
struct drm_connector_state;
+struct drm_printer;
struct drm_private_obj;
struct drm_private_state;
struct drm_modeset_acquire_ctx;
struct drm_device;
@@ -52,10 +53,14 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
struct drm_crtc_state *
drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state);
void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state);
+bool drm_atomic_helper_crtc_compare_state(struct drm_crtc *crtc,
+ struct drm_printer *p,
+ struct drm_crtc_state *expected,
+ struct drm_crtc_state *actual);
void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *state,
struct drm_plane *plane);
void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
struct drm_plane_state *state);
@@ -65,10 +70,14 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
struct drm_plane_state *
drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state);
void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state);
+bool drm_atomic_helper_plane_compare_state(struct drm_plane *plane,
+ struct drm_printer *p,
+ struct drm_plane_state *expected,
+ struct drm_plane_state *actual);
void __drm_atomic_helper_connector_state_reset(struct drm_connector_state *conn_state,
struct drm_connector *connector);
void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
struct drm_connector_state *conn_state);
@@ -78,10 +87,15 @@ int drm_atomic_helper_connector_tv_check(struct drm_connector *connector,
struct drm_atomic_state *state);
void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connector);
void
__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
struct drm_connector_state *state);
+bool drm_atomic_helper_connector_compare_state(struct drm_connector *connector,
+ struct drm_printer *p,
+ struct drm_connector_state *expected,
+ struct drm_connector_state *actual);
+
struct drm_connector_state *
drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
void
__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state);
void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
@@ -98,10 +112,15 @@ void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge,
void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
struct drm_bridge_state *state);
struct drm_bridge_state *
drm_atomic_helper_bridge_reset(struct drm_bridge *bridge);
+bool drm_atomic_helper_bridge_compare_state(struct drm_bridge *bridge,
+ struct drm_printer *p,
+ struct drm_bridge_state *expected,
+ struct drm_bridge_state *actual);
+
void __printf(4, 5)
drm_atomic_helper_print_state_mismatch(struct drm_printer *p,
const char *name,
const char *field,
const char *format, ...);
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH 16/29] drm/encoder: Create get_current_crtc hook
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (14 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 15/29] drm/atomic_state_helper: Provide atomic_compare_state helpers Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 8:32 ` [PATCH 17/29] drm/bridge_connector: Implement hw readout for connector Maxime Ripard
` (13 subsequent siblings)
29 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
In order for drivers to implement drm_connectors atomic_state_readout
hooks, they need to query the hardware and lookup the CRTC to set
drm_connector_state.crtc.
It should be easy enough for drivers that are tightly integrated from
the CRTC to the connectors, but if the driver uses bridges, there's no
coupling between the CRTC and encoder, and the bridge driver.
The only thing the bridge has access to is the encoder, but the
relationship between a CRTC and an encoder isn't a fixed mapping at the
framework level, and thus the bridge can't deduce which CRTC is feeding
its encoder.
Thus, let's create a new hook for encoders to implement to return the
CRTC they are currently connected to.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
include/drm/drm_encoder.h | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
index 977a9381c8ba943b4d3e021635ea14856df8a17d..7abb5e35ac950c941b56fc311a52789bbc427df6 100644
--- a/include/drm/drm_encoder.h
+++ b/include/drm/drm_encoder.h
@@ -86,10 +86,23 @@ struct drm_encoder_funcs {
* @debugfs_init:
*
* Allows encoders to create encoder-specific debugfs files.
*/
void (*debugfs_init)(struct drm_encoder *encoder, struct dentry *root);
+
+ /**
+ * @get_current_crtc:
+ *
+ * This optional hook is used during initialization to read out
+ * the initial state by connectors that support atomic state
+ * hardware readout.
+ *
+ * Returns:
+ *
+ * The CRTC currently associated with the encoder if enabled, NULL otherwise.
+ */
+ struct drm_crtc *(*get_current_crtc)(struct drm_encoder *encoder);
};
/**
* struct drm_encoder - central DRM encoder structure
* @dev: parent DRM device
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH 17/29] drm/bridge_connector: Implement hw readout for connector
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (15 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 16/29] drm/encoder: Create get_current_crtc hook Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 8:32 ` [PATCH 18/29] drm/tidss: Convert to drm logging Maxime Ripard
` (12 subsequent siblings)
29 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
drm_bridge_connector allows to create a generic connector from a list of
bridges.
However, it's a somewhat virtual connector, and relies on the bridges to
implement its various capabilities.
What we actually want though is for the last bridge implementing
hardware readout to fill the connector state from its own state.
Thus, let's implement a new op for bridge_connector to allow just that.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 36 +++++++++++++++++++++++---
include/drm/drm_bridge.h | 21 +++++++++++++++
2 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 091c5335355a2b6c70dd823df69ce060fd56c4f9..0cf97cd0e554fd5f1101e4afb28f2a341bd774fb 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -64,10 +64,18 @@ struct drm_bridge_connector {
* @encoder:
*
* The encoder at the start of the bridges chain.
*/
struct drm_encoder *encoder;
+ /**
+ * @bridge_connector_hw_readout:
+ *
+ * The last bridge in the chain (closest to the connector) that
+ * provides hardware state readout support, if any (see
+ * &DRM_BRIDGE_OP_CONNECTOR_HW_READOUT).
+ */
+ struct drm_bridge *bridge_connector_hw_readout;
/**
* @bridge_edid:
*
* The last bridge in the chain (closest to the connector) that provides
* EDID read support, if any (see &DRM_BRIDGE_OP_EDID).
@@ -256,26 +264,46 @@ static void drm_bridge_connector_debugfs_init(struct drm_connector *connector,
if (bridge->funcs->debugfs_init)
bridge->funcs->debugfs_init(bridge, root);
}
}
-static void drm_bridge_connector_reset(struct drm_connector *connector)
+static struct drm_connector_state *
+drm_bridge_connector_readout_state(struct drm_connector *connector,
+ struct drm_atomic_state *state)
{
struct drm_bridge_connector *bridge_connector =
to_drm_bridge_connector(connector);
+ struct drm_connector_state *conn_state;
+ struct drm_bridge *readout =
+ bridge_connector->bridge_connector_hw_readout;
+
+ if (connector->state)
+ connector->funcs->atomic_destroy_state(connector,
+ connector->state);
+
+ conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
+ if (!conn_state)
+ return ERR_PTR(-ENOMEM);
+
+ __drm_atomic_helper_connector_state_reset(conn_state, connector);
- drm_atomic_helper_connector_reset(connector);
if (bridge_connector->bridge_hdmi)
__drm_atomic_helper_connector_hdmi_reset(connector,
connector->state);
+
+ if (readout)
+ readout->funcs->connector_hw_readout(readout, state, conn_state);
+
+ return conn_state;
}
static const struct drm_connector_funcs drm_bridge_connector_funcs = {
- .reset = drm_bridge_connector_reset,
.detect = drm_bridge_connector_detect,
.force = drm_bridge_connector_force,
.fill_modes = drm_helper_probe_single_connector_modes,
+ .atomic_readout_state = drm_bridge_connector_readout_state,
+ .atomic_compare_state = drm_atomic_helper_connector_compare_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.debugfs_init = drm_bridge_connector_debugfs_init,
.oob_hotplug_event = drm_bridge_connector_oob_hotplug_event,
};
@@ -671,10 +699,12 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
if (!bridge->interlace_allowed)
connector->interlace_allowed = false;
if (!bridge->ycbcr_420_allowed)
connector->ycbcr_420_allowed = false;
+ if (bridge->ops & DRM_BRIDGE_OP_CONNECTOR_HW_READOUT)
+ bridge_connector->bridge_connector_hw_readout = bridge;
if (bridge->ops & DRM_BRIDGE_OP_EDID)
bridge_connector->bridge_edid = bridge;
if (bridge->ops & DRM_BRIDGE_OP_HPD)
bridge_connector->bridge_hpd = bridge;
if (bridge->ops & DRM_BRIDGE_OP_DETECT)
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 5ea63b51a4dd4cb00468afcf7d126c774f63ade0..7c401e905c023923f1f94daec746b56c3e478b83 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1017,10 +1017,27 @@ struct drm_bridge_funcs {
*/
int (*dp_audio_mute_stream)(struct drm_bridge *bridge,
struct drm_connector *connector,
bool enable, int direction);
+ /**
+ * @connector_hw_readout:
+ *
+ * Initializes the &struct drm_connector_state based on hardware
+ * state.
+ *
+ * This callback is optional, it can be implemented by bridges
+ * that set the @DRM_BRIDGE_OP_CONNECTOR_HW_READOUT flag in
+ * their &drm_bridge->ops.
+ *
+ * Returns:
+ * 0 on success, a negative error code otherwise
+ */
+ int (*connector_hw_readout)(struct drm_bridge *bridge,
+ struct drm_atomic_state *state,
+ struct drm_connector_state *conn_state);
+
/**
* @debugfs_init:
*
* Allows bridges to create bridge-specific debugfs files.
*/
@@ -1138,10 +1155,14 @@ enum drm_bridge_ops {
/**
* @DRM_BRIDGE_OP_HDMI_CEC_ADAPTER: The bridge requires CEC adapter
* to be present.
*/
DRM_BRIDGE_OP_HDMI_CEC_ADAPTER = BIT(8),
+ /**
+ * @DRM_BRIDGE_OP_CONNECTOR_HW_READOUT: TODO
+ */
+ DRM_BRIDGE_OP_CONNECTOR_HW_READOUT = BIT(9),
};
/**
* struct drm_bridge - central DRM bridge control structure
*/
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH 18/29] drm/tidss: Convert to drm logging
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (16 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 17/29] drm/bridge_connector: Implement hw readout for connector Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:49 ` Thomas Zimmermann
2025-09-02 8:32 ` [PATCH 19/29] drm/tidss: Remove ftrace-like logs Maxime Ripard
` (11 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
DRM drivers should prefer the drm logging functions to the dev logging
ones when possible. Let's convert the existing dev_* logs to their drm
counterparts.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_crtc.c | 4 ++--
drivers/gpu/drm/tidss/tidss_dispc.c | 6 ++++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
index da89fd01c3376352840185cd4ac355dd41fd5bb1..f497138ad053ed4be207e12eeee6c304e1c949bd 100644
--- a/drivers/gpu/drm/tidss/tidss_crtc.c
+++ b/drivers/gpu/drm/tidss/tidss_crtc.c
@@ -101,11 +101,11 @@ static int tidss_crtc_atomic_check(struct drm_crtc *crtc,
mode = &crtc_state->adjusted_mode;
ok = dispc_vp_mode_valid(dispc, hw_videoport, mode);
if (ok != MODE_OK) {
- dev_dbg(ddev->dev, "%s: bad mode: %ux%u pclk %u kHz\n",
+ drm_dbg(ddev, "%s: bad mode: %ux%u pclk %u kHz\n",
__func__, mode->hdisplay, mode->vdisplay, mode->clock);
return -EINVAL;
}
if (drm_atomic_crtc_needs_modeset(crtc_state))
@@ -170,11 +170,11 @@ static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
struct drm_device *ddev = crtc->dev;
struct tidss_device *tidss = to_tidss(ddev);
unsigned long flags;
- dev_dbg(ddev->dev, "%s: %s is %sactive, %s modeset, event %p\n",
+ drm_dbg(ddev, "%s: %s is %sactive, %s modeset, event %p\n",
__func__, crtc->name, crtc->state->active ? "" : "not ",
drm_atomic_crtc_needs_modeset(crtc->state) ? "needs" : "doesn't need",
crtc->state->event);
/*
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index 190d32ed53f84371456ccb997d1898ed5cef9db1..8b1d6b72f303b91fbf86f7d0e351800804757126 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -1063,24 +1063,26 @@ struct dispc_bus_format *dispc_vp_find_bus_fmt(struct dispc_device *dispc,
}
int dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport,
const struct drm_crtc_state *state)
{
+ struct tidss_device *tidss = dispc->tidss;
+ struct drm_device *dev = &tidss->ddev;
const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
const struct dispc_bus_format *fmt;
fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format,
tstate->bus_flags);
if (!fmt) {
- dev_dbg(dispc->dev, "%s: Unsupported bus format: %u\n",
+ drm_dbg(dev, "%s: Unsupported bus format: %u\n",
__func__, tstate->bus_format);
return -EINVAL;
}
if (dispc->feat->vp_bus_type[hw_videoport] != DISPC_VP_OLDI_AM65X &&
fmt->is_oldi_fmt) {
- dev_dbg(dispc->dev, "%s: %s is not OLDI-port\n",
+ drm_dbg(dev, "%s: %s is not OLDI-port\n",
__func__, dispc->feat->vp_name[hw_videoport]);
return -EINVAL;
}
return 0;
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 18/29] drm/tidss: Convert to drm logging
2025-09-02 8:32 ` [PATCH 18/29] drm/tidss: Convert to drm logging Maxime Ripard
@ 2025-09-02 13:49 ` Thomas Zimmermann
0 siblings, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:49 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Hi
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> DRM drivers should prefer the drm logging functions to the dev logging
> ones when possible. Let's convert the existing dev_* logs to their drm
> counterparts.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> drivers/gpu/drm/tidss/tidss_crtc.c | 4 ++--
> drivers/gpu/drm/tidss/tidss_dispc.c | 6 ++++--
> 2 files changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
> index da89fd01c3376352840185cd4ac355dd41fd5bb1..f497138ad053ed4be207e12eeee6c304e1c949bd 100644
> --- a/drivers/gpu/drm/tidss/tidss_crtc.c
> +++ b/drivers/gpu/drm/tidss/tidss_crtc.c
> @@ -101,11 +101,11 @@ static int tidss_crtc_atomic_check(struct drm_crtc *crtc,
>
> mode = &crtc_state->adjusted_mode;
>
> ok = dispc_vp_mode_valid(dispc, hw_videoport, mode);
> if (ok != MODE_OK) {
> - dev_dbg(ddev->dev, "%s: bad mode: %ux%u pclk %u kHz\n",
> + drm_dbg(ddev, "%s: bad mode: %ux%u pclk %u kHz\n",
> __func__, mode->hdisplay, mode->vdisplay, mode->clock);
> return -EINVAL;
> }
>
> if (drm_atomic_crtc_needs_modeset(crtc_state))
> @@ -170,11 +170,11 @@ static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
> struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
> struct drm_device *ddev = crtc->dev;
> struct tidss_device *tidss = to_tidss(ddev);
> unsigned long flags;
>
> - dev_dbg(ddev->dev, "%s: %s is %sactive, %s modeset, event %p\n",
> + drm_dbg(ddev, "%s: %s is %sactive, %s modeset, event %p\n",
> __func__, crtc->name, crtc->state->active ? "" : "not ",
> drm_atomic_crtc_needs_modeset(crtc->state) ? "needs" : "doesn't need",
> crtc->state->event);
>
> /*
> diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
> index 190d32ed53f84371456ccb997d1898ed5cef9db1..8b1d6b72f303b91fbf86f7d0e351800804757126 100644
> --- a/drivers/gpu/drm/tidss/tidss_dispc.c
> +++ b/drivers/gpu/drm/tidss/tidss_dispc.c
> @@ -1063,24 +1063,26 @@ struct dispc_bus_format *dispc_vp_find_bus_fmt(struct dispc_device *dispc,
> }
>
> int dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport,
> const struct drm_crtc_state *state)
> {
> + struct tidss_device *tidss = dispc->tidss;
> + struct drm_device *dev = &tidss->ddev;
> const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
> const struct dispc_bus_format *fmt;
>
> fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format,
> tstate->bus_flags);
> if (!fmt) {
> - dev_dbg(dispc->dev, "%s: Unsupported bus format: %u\n",
> + drm_dbg(dev, "%s: Unsupported bus format: %u\n",
> __func__, tstate->bus_format);
> return -EINVAL;
> }
>
> if (dispc->feat->vp_bus_type[hw_videoport] != DISPC_VP_OLDI_AM65X &&
> fmt->is_oldi_fmt) {
> - dev_dbg(dispc->dev, "%s: %s is not OLDI-port\n",
> + drm_dbg(dev, "%s: %s is not OLDI-port\n",
> __func__, dispc->feat->vp_name[hw_videoport]);
> return -EINVAL;
> }
>
> return 0;
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 19/29] drm/tidss: Remove ftrace-like logs
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (17 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 18/29] drm/tidss: Convert to drm logging Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:50 ` Thomas Zimmermann
2025-09-02 8:32 ` [PATCH 20/29] drm/tidss: crtc: Change variable name Maxime Ripard
` (10 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
These logs don't really log any information and create checkpatch
warnings. Remove them.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_crtc.c | 6 ------
drivers/gpu/drm/tidss/tidss_dispc.c | 4 ----
drivers/gpu/drm/tidss/tidss_drv.c | 16 ----------------
drivers/gpu/drm/tidss/tidss_kms.c | 4 ----
drivers/gpu/drm/tidss/tidss_plane.c | 8 --------
5 files changed, 38 deletions(-)
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
index f497138ad053ed4be207e12eeee6c304e1c949bd..091f82c86f53bc76c572de4723746af2e35ce1c1 100644
--- a/drivers/gpu/drm/tidss/tidss_crtc.c
+++ b/drivers/gpu/drm/tidss/tidss_crtc.c
@@ -92,12 +92,10 @@ static int tidss_crtc_atomic_check(struct drm_crtc *crtc,
struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
u32 hw_videoport = tcrtc->hw_videoport;
struct drm_display_mode *mode;
enum drm_mode_status ok;
- dev_dbg(ddev->dev, "%s\n", __func__);
-
if (!crtc_state->enable)
return 0;
mode = &crtc_state->adjusted_mode;
@@ -326,12 +324,10 @@ static const struct drm_crtc_helper_funcs tidss_crtc_helper_funcs = {
static int tidss_crtc_enable_vblank(struct drm_crtc *crtc)
{
struct drm_device *ddev = crtc->dev;
struct tidss_device *tidss = to_tidss(ddev);
- dev_dbg(ddev->dev, "%s\n", __func__);
-
tidss_runtime_get(tidss);
tidss_irq_enable_vblank(crtc);
return 0;
@@ -340,12 +336,10 @@ static int tidss_crtc_enable_vblank(struct drm_crtc *crtc)
static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
{
struct drm_device *ddev = crtc->dev;
struct tidss_device *tidss = to_tidss(ddev);
- dev_dbg(ddev->dev, "%s\n", __func__);
-
tidss_irq_disable_vblank(crtc);
tidss_runtime_put(tidss);
}
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index 8b1d6b72f303b91fbf86f7d0e351800804757126..7d94c1142e8083dab00fcf5c652ae40f98baeabf 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -2863,12 +2863,10 @@ int dispc_runtime_resume(struct dispc_device *dispc)
return 0;
}
void dispc_remove(struct tidss_device *tidss)
{
- dev_dbg(tidss->dev, "%s\n", __func__);
-
tidss->dispc = NULL;
}
static int dispc_iomap_resource(struct platform_device *pdev, const char *name,
void __iomem **base)
@@ -3006,12 +3004,10 @@ int dispc_init(struct tidss_device *tidss)
struct dispc_device *dispc;
const struct dispc_features *feat;
unsigned int i, num_fourccs;
int r = 0;
- dev_dbg(dev, "%s\n", __func__);
-
feat = tidss->feat;
if (feat->subrev != DISPC_K2G) {
r = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
if (r)
diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c
index 27d9a8fd541fc164f2fb2535f148432bd7895f46..1c8cc18bc53c3ea3c50368b9f55ab02a0a02fc77 100644
--- a/drivers/gpu/drm/tidss/tidss_drv.c
+++ b/drivers/gpu/drm/tidss/tidss_drv.c
@@ -31,45 +31,37 @@
int tidss_runtime_get(struct tidss_device *tidss)
{
int r;
- dev_dbg(tidss->dev, "%s\n", __func__);
-
r = pm_runtime_resume_and_get(tidss->dev);
WARN_ON(r < 0);
return r;
}
void tidss_runtime_put(struct tidss_device *tidss)
{
int r;
- dev_dbg(tidss->dev, "%s\n", __func__);
-
pm_runtime_mark_last_busy(tidss->dev);
r = pm_runtime_put_autosuspend(tidss->dev);
WARN_ON(r < 0);
}
static int __maybe_unused tidss_pm_runtime_suspend(struct device *dev)
{
struct tidss_device *tidss = dev_get_drvdata(dev);
- dev_dbg(dev, "%s\n", __func__);
-
return dispc_runtime_suspend(tidss->dispc);
}
static int __maybe_unused tidss_pm_runtime_resume(struct device *dev)
{
struct tidss_device *tidss = dev_get_drvdata(dev);
int r;
- dev_dbg(dev, "%s\n", __func__);
-
r = dispc_runtime_resume(tidss->dispc);
if (r)
return r;
return 0;
@@ -77,21 +69,17 @@ static int __maybe_unused tidss_pm_runtime_resume(struct device *dev)
static int __maybe_unused tidss_suspend(struct device *dev)
{
struct tidss_device *tidss = dev_get_drvdata(dev);
- dev_dbg(dev, "%s\n", __func__);
-
return drm_mode_config_helper_suspend(&tidss->ddev);
}
static int __maybe_unused tidss_resume(struct device *dev)
{
struct tidss_device *tidss = dev_get_drvdata(dev);
- dev_dbg(dev, "%s\n", __func__);
-
return drm_mode_config_helper_resume(&tidss->ddev);
}
static __maybe_unused const struct dev_pm_ops tidss_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(tidss_suspend, tidss_resume)
@@ -125,12 +113,10 @@ static int tidss_probe(struct platform_device *pdev)
struct tidss_device *tidss;
struct drm_device *ddev;
int ret;
int irq;
- dev_dbg(dev, "%s\n", __func__);
-
tidss = devm_drm_dev_alloc(&pdev->dev, &tidss_driver,
struct tidss_device, ddev);
if (IS_ERR(tidss))
return PTR_ERR(tidss);
@@ -226,12 +212,10 @@ static void tidss_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct tidss_device *tidss = platform_get_drvdata(pdev);
struct drm_device *ddev = &tidss->ddev;
- dev_dbg(dev, "%s\n", __func__);
-
drm_dev_unregister(ddev);
drm_atomic_helper_shutdown(ddev);
tidss_irq_uninstall(ddev);
diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c
index c34eb90cddbeac634f281cf163d493ba75b7ea29..86eb5d97410bedced57129c2bbcd35f1719424c2 100644
--- a/drivers/gpu/drm/tidss/tidss_kms.c
+++ b/drivers/gpu/drm/tidss/tidss_kms.c
@@ -22,12 +22,10 @@
static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state)
{
struct drm_device *ddev = old_state->dev;
struct tidss_device *tidss = to_tidss(ddev);
- dev_dbg(ddev->dev, "%s\n", __func__);
-
tidss_runtime_get(tidss);
drm_atomic_helper_commit_modeset_disables(ddev, old_state);
drm_atomic_helper_commit_planes(ddev, old_state, DRM_PLANE_COMMIT_ACTIVE_ONLY);
drm_atomic_helper_commit_modeset_enables(ddev, old_state);
@@ -243,12 +241,10 @@ static int tidss_dispc_modeset_init(struct tidss_device *tidss)
int tidss_modeset_init(struct tidss_device *tidss)
{
struct drm_device *ddev = &tidss->ddev;
int ret;
- dev_dbg(tidss->dev, "%s\n", __func__);
-
ret = drmm_mode_config_init(ddev);
if (ret)
return ret;
ddev->mode_config.min_width = 8;
diff --git a/drivers/gpu/drm/tidss/tidss_plane.c b/drivers/gpu/drm/tidss/tidss_plane.c
index 142ae81951a0916ccf7d3add1b83b011eca7f6b9..bd10bc1b9961571e6c6dee26698149fc9dd135b0 100644
--- a/drivers/gpu/drm/tidss/tidss_plane.c
+++ b/drivers/gpu/drm/tidss/tidss_plane.c
@@ -40,12 +40,10 @@ static int tidss_plane_atomic_check(struct drm_plane *plane,
struct drm_crtc_state *crtc_state;
u32 hw_plane = tplane->hw_plane_id;
u32 hw_videoport;
int ret;
- dev_dbg(ddev->dev, "%s\n", __func__);
-
if (!new_plane_state->crtc) {
/*
* The visible field is not reset by the DRM core but only
* updated by drm_atomic_helper_check_plane_state(), set it
* manually.
@@ -122,12 +120,10 @@ static void tidss_plane_atomic_update(struct drm_plane *plane,
struct tidss_plane *tplane = to_tidss_plane(plane);
struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
plane);
u32 hw_videoport;
- dev_dbg(ddev->dev, "%s\n", __func__);
-
if (!new_state->visible) {
dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false);
return;
}
@@ -141,24 +137,20 @@ static void tidss_plane_atomic_enable(struct drm_plane *plane,
{
struct drm_device *ddev = plane->dev;
struct tidss_device *tidss = to_tidss(ddev);
struct tidss_plane *tplane = to_tidss_plane(plane);
- dev_dbg(ddev->dev, "%s\n", __func__);
-
dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, true);
}
static void tidss_plane_atomic_disable(struct drm_plane *plane,
struct drm_atomic_state *state)
{
struct drm_device *ddev = plane->dev;
struct tidss_device *tidss = to_tidss(ddev);
struct tidss_plane *tplane = to_tidss_plane(plane);
- dev_dbg(ddev->dev, "%s\n", __func__);
-
dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false);
}
static void drm_plane_destroy(struct drm_plane *plane)
{
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 19/29] drm/tidss: Remove ftrace-like logs
2025-09-02 8:32 ` [PATCH 19/29] drm/tidss: Remove ftrace-like logs Maxime Ripard
@ 2025-09-02 13:50 ` Thomas Zimmermann
0 siblings, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:50 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> These logs don't really log any information and create checkpatch
> warnings. Remove them.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Most of this output should be available from DRM's atomic helpers already.
> ---
> drivers/gpu/drm/tidss/tidss_crtc.c | 6 ------
> drivers/gpu/drm/tidss/tidss_dispc.c | 4 ----
> drivers/gpu/drm/tidss/tidss_drv.c | 16 ----------------
> drivers/gpu/drm/tidss/tidss_kms.c | 4 ----
> drivers/gpu/drm/tidss/tidss_plane.c | 8 --------
> 5 files changed, 38 deletions(-)
>
> diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
> index f497138ad053ed4be207e12eeee6c304e1c949bd..091f82c86f53bc76c572de4723746af2e35ce1c1 100644
> --- a/drivers/gpu/drm/tidss/tidss_crtc.c
> +++ b/drivers/gpu/drm/tidss/tidss_crtc.c
> @@ -92,12 +92,10 @@ static int tidss_crtc_atomic_check(struct drm_crtc *crtc,
> struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
> u32 hw_videoport = tcrtc->hw_videoport;
> struct drm_display_mode *mode;
> enum drm_mode_status ok;
>
> - dev_dbg(ddev->dev, "%s\n", __func__);
> -
> if (!crtc_state->enable)
> return 0;
>
> mode = &crtc_state->adjusted_mode;
>
> @@ -326,12 +324,10 @@ static const struct drm_crtc_helper_funcs tidss_crtc_helper_funcs = {
> static int tidss_crtc_enable_vblank(struct drm_crtc *crtc)
> {
> struct drm_device *ddev = crtc->dev;
> struct tidss_device *tidss = to_tidss(ddev);
>
> - dev_dbg(ddev->dev, "%s\n", __func__);
> -
> tidss_runtime_get(tidss);
>
> tidss_irq_enable_vblank(crtc);
>
> return 0;
> @@ -340,12 +336,10 @@ static int tidss_crtc_enable_vblank(struct drm_crtc *crtc)
> static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
> {
> struct drm_device *ddev = crtc->dev;
> struct tidss_device *tidss = to_tidss(ddev);
>
> - dev_dbg(ddev->dev, "%s\n", __func__);
> -
> tidss_irq_disable_vblank(crtc);
>
> tidss_runtime_put(tidss);
> }
>
> diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
> index 8b1d6b72f303b91fbf86f7d0e351800804757126..7d94c1142e8083dab00fcf5c652ae40f98baeabf 100644
> --- a/drivers/gpu/drm/tidss/tidss_dispc.c
> +++ b/drivers/gpu/drm/tidss/tidss_dispc.c
> @@ -2863,12 +2863,10 @@ int dispc_runtime_resume(struct dispc_device *dispc)
> return 0;
> }
>
> void dispc_remove(struct tidss_device *tidss)
> {
> - dev_dbg(tidss->dev, "%s\n", __func__);
> -
> tidss->dispc = NULL;
> }
>
> static int dispc_iomap_resource(struct platform_device *pdev, const char *name,
> void __iomem **base)
> @@ -3006,12 +3004,10 @@ int dispc_init(struct tidss_device *tidss)
> struct dispc_device *dispc;
> const struct dispc_features *feat;
> unsigned int i, num_fourccs;
> int r = 0;
>
> - dev_dbg(dev, "%s\n", __func__);
> -
> feat = tidss->feat;
>
> if (feat->subrev != DISPC_K2G) {
> r = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
> if (r)
> diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c
> index 27d9a8fd541fc164f2fb2535f148432bd7895f46..1c8cc18bc53c3ea3c50368b9f55ab02a0a02fc77 100644
> --- a/drivers/gpu/drm/tidss/tidss_drv.c
> +++ b/drivers/gpu/drm/tidss/tidss_drv.c
> @@ -31,45 +31,37 @@
>
> int tidss_runtime_get(struct tidss_device *tidss)
> {
> int r;
>
> - dev_dbg(tidss->dev, "%s\n", __func__);
> -
> r = pm_runtime_resume_and_get(tidss->dev);
> WARN_ON(r < 0);
> return r;
> }
>
> void tidss_runtime_put(struct tidss_device *tidss)
> {
> int r;
>
> - dev_dbg(tidss->dev, "%s\n", __func__);
> -
> pm_runtime_mark_last_busy(tidss->dev);
>
> r = pm_runtime_put_autosuspend(tidss->dev);
> WARN_ON(r < 0);
> }
>
> static int __maybe_unused tidss_pm_runtime_suspend(struct device *dev)
> {
> struct tidss_device *tidss = dev_get_drvdata(dev);
>
> - dev_dbg(dev, "%s\n", __func__);
> -
> return dispc_runtime_suspend(tidss->dispc);
> }
>
> static int __maybe_unused tidss_pm_runtime_resume(struct device *dev)
> {
> struct tidss_device *tidss = dev_get_drvdata(dev);
> int r;
>
> - dev_dbg(dev, "%s\n", __func__);
> -
> r = dispc_runtime_resume(tidss->dispc);
> if (r)
> return r;
>
> return 0;
> @@ -77,21 +69,17 @@ static int __maybe_unused tidss_pm_runtime_resume(struct device *dev)
>
> static int __maybe_unused tidss_suspend(struct device *dev)
> {
> struct tidss_device *tidss = dev_get_drvdata(dev);
>
> - dev_dbg(dev, "%s\n", __func__);
> -
> return drm_mode_config_helper_suspend(&tidss->ddev);
> }
>
> static int __maybe_unused tidss_resume(struct device *dev)
> {
> struct tidss_device *tidss = dev_get_drvdata(dev);
>
> - dev_dbg(dev, "%s\n", __func__);
> -
> return drm_mode_config_helper_resume(&tidss->ddev);
> }
>
> static __maybe_unused const struct dev_pm_ops tidss_pm_ops = {
> SET_SYSTEM_SLEEP_PM_OPS(tidss_suspend, tidss_resume)
> @@ -125,12 +113,10 @@ static int tidss_probe(struct platform_device *pdev)
> struct tidss_device *tidss;
> struct drm_device *ddev;
> int ret;
> int irq;
>
> - dev_dbg(dev, "%s\n", __func__);
> -
> tidss = devm_drm_dev_alloc(&pdev->dev, &tidss_driver,
> struct tidss_device, ddev);
> if (IS_ERR(tidss))
> return PTR_ERR(tidss);
>
> @@ -226,12 +212,10 @@ static void tidss_remove(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> struct tidss_device *tidss = platform_get_drvdata(pdev);
> struct drm_device *ddev = &tidss->ddev;
>
> - dev_dbg(dev, "%s\n", __func__);
> -
> drm_dev_unregister(ddev);
>
> drm_atomic_helper_shutdown(ddev);
>
> tidss_irq_uninstall(ddev);
> diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c
> index c34eb90cddbeac634f281cf163d493ba75b7ea29..86eb5d97410bedced57129c2bbcd35f1719424c2 100644
> --- a/drivers/gpu/drm/tidss/tidss_kms.c
> +++ b/drivers/gpu/drm/tidss/tidss_kms.c
> @@ -22,12 +22,10 @@
> static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state)
> {
> struct drm_device *ddev = old_state->dev;
> struct tidss_device *tidss = to_tidss(ddev);
>
> - dev_dbg(ddev->dev, "%s\n", __func__);
> -
> tidss_runtime_get(tidss);
>
> drm_atomic_helper_commit_modeset_disables(ddev, old_state);
> drm_atomic_helper_commit_planes(ddev, old_state, DRM_PLANE_COMMIT_ACTIVE_ONLY);
> drm_atomic_helper_commit_modeset_enables(ddev, old_state);
> @@ -243,12 +241,10 @@ static int tidss_dispc_modeset_init(struct tidss_device *tidss)
> int tidss_modeset_init(struct tidss_device *tidss)
> {
> struct drm_device *ddev = &tidss->ddev;
> int ret;
>
> - dev_dbg(tidss->dev, "%s\n", __func__);
> -
> ret = drmm_mode_config_init(ddev);
> if (ret)
> return ret;
>
> ddev->mode_config.min_width = 8;
> diff --git a/drivers/gpu/drm/tidss/tidss_plane.c b/drivers/gpu/drm/tidss/tidss_plane.c
> index 142ae81951a0916ccf7d3add1b83b011eca7f6b9..bd10bc1b9961571e6c6dee26698149fc9dd135b0 100644
> --- a/drivers/gpu/drm/tidss/tidss_plane.c
> +++ b/drivers/gpu/drm/tidss/tidss_plane.c
> @@ -40,12 +40,10 @@ static int tidss_plane_atomic_check(struct drm_plane *plane,
> struct drm_crtc_state *crtc_state;
> u32 hw_plane = tplane->hw_plane_id;
> u32 hw_videoport;
> int ret;
>
> - dev_dbg(ddev->dev, "%s\n", __func__);
> -
> if (!new_plane_state->crtc) {
> /*
> * The visible field is not reset by the DRM core but only
> * updated by drm_atomic_helper_check_plane_state(), set it
> * manually.
> @@ -122,12 +120,10 @@ static void tidss_plane_atomic_update(struct drm_plane *plane,
> struct tidss_plane *tplane = to_tidss_plane(plane);
> struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
> plane);
> u32 hw_videoport;
>
> - dev_dbg(ddev->dev, "%s\n", __func__);
> -
> if (!new_state->visible) {
> dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false);
> return;
> }
>
> @@ -141,24 +137,20 @@ static void tidss_plane_atomic_enable(struct drm_plane *plane,
> {
> struct drm_device *ddev = plane->dev;
> struct tidss_device *tidss = to_tidss(ddev);
> struct tidss_plane *tplane = to_tidss_plane(plane);
>
> - dev_dbg(ddev->dev, "%s\n", __func__);
> -
> dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, true);
> }
>
> static void tidss_plane_atomic_disable(struct drm_plane *plane,
> struct drm_atomic_state *state)
> {
> struct drm_device *ddev = plane->dev;
> struct tidss_device *tidss = to_tidss(ddev);
> struct tidss_plane *tplane = to_tidss_plane(plane);
>
> - dev_dbg(ddev->dev, "%s\n", __func__);
> -
> dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false);
> }
>
> static void drm_plane_destroy(struct drm_plane *plane)
> {
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 20/29] drm/tidss: crtc: Change variable name
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (18 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 19/29] drm/tidss: Remove ftrace-like logs Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:51 ` Thomas Zimmermann
2025-09-02 8:32 ` [PATCH 21/29] drm/tidss: crtc: Implement destroy_state Maxime Ripard
` (9 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The tidss_crtc_reset() function stores a pointer to struct
tidss_crtc_state in a variable called tcrtc, while it uses tcrtc as a
pointer to struct tidss_crtc in the rest of the driver.
This is confusing, so let's change the variable name.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_crtc.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
index 091f82c86f53bc76c572de4723746af2e35ce1c1..db7c5e4225e6247047087a35a2e6422950fc0111 100644
--- a/drivers/gpu/drm/tidss/tidss_crtc.c
+++ b/drivers/gpu/drm/tidss/tidss_crtc.c
@@ -343,24 +343,24 @@ static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
tidss_runtime_put(tidss);
}
static void tidss_crtc_reset(struct drm_crtc *crtc)
{
- struct tidss_crtc_state *tcrtc;
+ struct tidss_crtc_state *tstate;
if (crtc->state)
__drm_atomic_helper_crtc_destroy_state(crtc->state);
kfree(crtc->state);
- tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
- if (!tcrtc) {
+ tstate = kzalloc(sizeof(*tstate), GFP_KERNEL);
+ if (!tstate) {
crtc->state = NULL;
return;
}
- __drm_atomic_helper_crtc_reset(crtc, &tcrtc->base);
+ __drm_atomic_helper_crtc_reset(crtc, &tstate->base);
}
static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc)
{
struct tidss_crtc_state *state, *current_state;
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 20/29] drm/tidss: crtc: Change variable name
2025-09-02 8:32 ` [PATCH 20/29] drm/tidss: crtc: Change variable name Maxime Ripard
@ 2025-09-02 13:51 ` Thomas Zimmermann
0 siblings, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:51 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> The tidss_crtc_reset() function stores a pointer to struct
> tidss_crtc_state in a variable called tcrtc, while it uses tcrtc as a
> pointer to struct tidss_crtc in the rest of the driver.
>
> This is confusing, so let's change the variable name.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> drivers/gpu/drm/tidss/tidss_crtc.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
> index 091f82c86f53bc76c572de4723746af2e35ce1c1..db7c5e4225e6247047087a35a2e6422950fc0111 100644
> --- a/drivers/gpu/drm/tidss/tidss_crtc.c
> +++ b/drivers/gpu/drm/tidss/tidss_crtc.c
> @@ -343,24 +343,24 @@ static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
> tidss_runtime_put(tidss);
> }
>
> static void tidss_crtc_reset(struct drm_crtc *crtc)
> {
> - struct tidss_crtc_state *tcrtc;
> + struct tidss_crtc_state *tstate;
>
> if (crtc->state)
> __drm_atomic_helper_crtc_destroy_state(crtc->state);
>
> kfree(crtc->state);
>
> - tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
> - if (!tcrtc) {
> + tstate = kzalloc(sizeof(*tstate), GFP_KERNEL);
> + if (!tstate) {
> crtc->state = NULL;
> return;
> }
>
> - __drm_atomic_helper_crtc_reset(crtc, &tcrtc->base);
> + __drm_atomic_helper_crtc_reset(crtc, &tstate->base);
> }
>
> static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc)
> {
> struct tidss_crtc_state *state, *current_state;
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 21/29] drm/tidss: crtc: Implement destroy_state
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (19 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 20/29] drm/tidss: crtc: Change variable name Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:52 ` Thomas Zimmermann
2025-09-02 8:32 ` [PATCH 22/29] drm/tidss: crtc: Cleanup reset implementation Maxime Ripard
` (8 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The tidss crtc driver implements its own state, with its own
implementation of reset and duplicate_state, but uses the default
destroy_state helper.
This somewhat works for now because the drm_crtc_state field in
tidss_crtc_state is the first field so the offset is 0, but it's pretty
fragile and it should really have its own destroy_state implementation.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_crtc.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
index db7c5e4225e6247047087a35a2e6422950fc0111..eb431a238b11d22349d61f0e17f05994f50d5f2f 100644
--- a/drivers/gpu/drm/tidss/tidss_crtc.c
+++ b/drivers/gpu/drm/tidss/tidss_crtc.c
@@ -341,10 +341,19 @@ static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
tidss_irq_disable_vblank(crtc);
tidss_runtime_put(tidss);
}
+static void tidss_crtc_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
+
+ __drm_atomic_helper_crtc_destroy_state(&tstate->base);
+ kfree(tstate);
+}
+
static void tidss_crtc_reset(struct drm_crtc *crtc)
{
struct tidss_crtc_state *tstate;
if (crtc->state)
@@ -396,11 +405,11 @@ static const struct drm_crtc_funcs tidss_crtc_funcs = {
.reset = tidss_crtc_reset,
.destroy = tidss_crtc_destroy,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.atomic_duplicate_state = tidss_crtc_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .atomic_destroy_state = tidss_crtc_destroy_state,
.enable_vblank = tidss_crtc_enable_vblank,
.disable_vblank = tidss_crtc_disable_vblank,
};
struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 21/29] drm/tidss: crtc: Implement destroy_state
2025-09-02 8:32 ` [PATCH 21/29] drm/tidss: crtc: Implement destroy_state Maxime Ripard
@ 2025-09-02 13:52 ` Thomas Zimmermann
0 siblings, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:52 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> The tidss crtc driver implements its own state, with its own
> implementation of reset and duplicate_state, but uses the default
> destroy_state helper.
>
> This somewhat works for now because the drm_crtc_state field in
> tidss_crtc_state is the first field so the offset is 0, but it's pretty
> fragile and it should really have its own destroy_state implementation.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> drivers/gpu/drm/tidss/tidss_crtc.c | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
> index db7c5e4225e6247047087a35a2e6422950fc0111..eb431a238b11d22349d61f0e17f05994f50d5f2f 100644
> --- a/drivers/gpu/drm/tidss/tidss_crtc.c
> +++ b/drivers/gpu/drm/tidss/tidss_crtc.c
> @@ -341,10 +341,19 @@ static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
> tidss_irq_disable_vblank(crtc);
>
> tidss_runtime_put(tidss);
> }
>
> +static void tidss_crtc_destroy_state(struct drm_crtc *crtc,
> + struct drm_crtc_state *state)
> +{
> + struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
> +
> + __drm_atomic_helper_crtc_destroy_state(&tstate->base);
> + kfree(tstate);
> +}
> +
> static void tidss_crtc_reset(struct drm_crtc *crtc)
> {
> struct tidss_crtc_state *tstate;
>
> if (crtc->state)
> @@ -396,11 +405,11 @@ static const struct drm_crtc_funcs tidss_crtc_funcs = {
> .reset = tidss_crtc_reset,
> .destroy = tidss_crtc_destroy,
> .set_config = drm_atomic_helper_set_config,
> .page_flip = drm_atomic_helper_page_flip,
> .atomic_duplicate_state = tidss_crtc_duplicate_state,
> - .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
> + .atomic_destroy_state = tidss_crtc_destroy_state,
> .enable_vblank = tidss_crtc_enable_vblank,
> .disable_vblank = tidss_crtc_disable_vblank,
> };
>
> struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 22/29] drm/tidss: crtc: Cleanup reset implementation
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (20 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 21/29] drm/tidss: crtc: Implement destroy_state Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 13:54 ` Thomas Zimmermann
2025-09-02 8:32 ` [PATCH 23/29] drm/tidss: dispc: Add format lookup by hw value Maxime Ripard
` (7 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The tidss_crtc_reset() function will (rightfully) destroy any
pre-existing state.
However, the tidss CRTC driver has its own CRTC state structure that
subclasses drm_crtc_state, and yet will destroy the previous state
by calling __drm_atomic_helper_crtc_destroy_state() and kfree() on its
drm_crtc_state pointer.
It works only because the drm_crtc_state is the first field in the
structure, and thus its offset is 0. It's incredibly fragile however, so
let's call our destroy implementation in such a case to deal with it
properly.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_crtc.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
index eb431a238b11d22349d61f0e17f05994f50d5f2f..8fcc6a2f94770ae825eeb2a3b09856a2bf2d6a1e 100644
--- a/drivers/gpu/drm/tidss/tidss_crtc.c
+++ b/drivers/gpu/drm/tidss/tidss_crtc.c
@@ -355,13 +355,11 @@ static void tidss_crtc_destroy_state(struct drm_crtc *crtc,
static void tidss_crtc_reset(struct drm_crtc *crtc)
{
struct tidss_crtc_state *tstate;
if (crtc->state)
- __drm_atomic_helper_crtc_destroy_state(crtc->state);
-
- kfree(crtc->state);
+ tidss_crtc_destroy_state(crtc, crtc->state);
tstate = kzalloc(sizeof(*tstate), GFP_KERNEL);
if (!tstate) {
crtc->state = NULL;
return;
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 22/29] drm/tidss: crtc: Cleanup reset implementation
2025-09-02 8:32 ` [PATCH 22/29] drm/tidss: crtc: Cleanup reset implementation Maxime Ripard
@ 2025-09-02 13:54 ` Thomas Zimmermann
0 siblings, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 13:54 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> The tidss_crtc_reset() function will (rightfully) destroy any
> pre-existing state.
>
> However, the tidss CRTC driver has its own CRTC state structure that
> subclasses drm_crtc_state, and yet will destroy the previous state
> by calling __drm_atomic_helper_crtc_destroy_state() and kfree() on its
> drm_crtc_state pointer.
>
> It works only because the drm_crtc_state is the first field in the
> structure, and thus its offset is 0. It's incredibly fragile however, so
> let's call our destroy implementation in such a case to deal with it
> properly.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> drivers/gpu/drm/tidss/tidss_crtc.c | 4 +---
> 1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
> index eb431a238b11d22349d61f0e17f05994f50d5f2f..8fcc6a2f94770ae825eeb2a3b09856a2bf2d6a1e 100644
> --- a/drivers/gpu/drm/tidss/tidss_crtc.c
> +++ b/drivers/gpu/drm/tidss/tidss_crtc.c
> @@ -355,13 +355,11 @@ static void tidss_crtc_destroy_state(struct drm_crtc *crtc,
> static void tidss_crtc_reset(struct drm_crtc *crtc)
> {
> struct tidss_crtc_state *tstate;
>
> if (crtc->state)
> - __drm_atomic_helper_crtc_destroy_state(crtc->state);
> -
> - kfree(crtc->state);
> + tidss_crtc_destroy_state(crtc, crtc->state);
>
> tstate = kzalloc(sizeof(*tstate), GFP_KERNEL);
> if (!tstate) {
> crtc->state = NULL;
> return;
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 23/29] drm/tidss: dispc: Add format lookup by hw value
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (21 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 22/29] drm/tidss: crtc: Cleanup reset implementation Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 8:32 ` [PATCH 24/29] drm/tidss: dispc: Improve mode checking logs Maxime Ripard
` (6 subsequent siblings)
29 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The tidss dispc driver has a table associating fourcc's and their
hardware representation.
So far, we only needed to do the fourcc to hardware lookup, but we'll
need to do the hardware to fourcc lookup in the future, so let's provide
a function to do so.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_dispc.c | 11 +++++++++++
drivers/gpu/drm/tidss/tidss_dispc.h | 1 +
2 files changed, 12 insertions(+)
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index 7d94c1142e8083dab00fcf5c652ae40f98baeabf..32248b5f71b7566dc33d7a7db0efb26d3a9ed1c3 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -2117,10 +2117,21 @@ static const struct {
{ DRM_FORMAT_UYVY, 0x3f, },
{ DRM_FORMAT_NV12, 0x3d, },
};
+u32 dispc_plane_find_fourcc_by_dss_code(u8 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i)
+ if (dispc_color_formats[i].dss_code == code)
+ return dispc_color_formats[i].fourcc;
+
+ return 0;
+}
+
static void dispc_plane_set_pixel_format(struct dispc_device *dispc,
u32 hw_plane, u32 fourcc)
{
unsigned int i;
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h
index 60c1b400eb8933dd13efd4ae3d09dc9569eed96f..849ec984026e223de7c8a55a4b5672c2262f38c0 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.h
+++ b/drivers/gpu/drm/tidss/tidss_dispc.h
@@ -146,10 +146,11 @@ int dispc_plane_check(struct dispc_device *dispc, u32 hw_plane,
void dispc_plane_setup(struct dispc_device *dispc, u32 hw_plane,
const struct drm_plane_state *state,
u32 hw_videoport);
void dispc_plane_enable(struct dispc_device *dispc, u32 hw_plane, bool enable);
const u32 *dispc_plane_formats(struct dispc_device *dispc, unsigned int *len);
+u32 dispc_plane_find_fourcc_by_dss_code(u8 code);
int dispc_init(struct tidss_device *tidss);
void dispc_remove(struct tidss_device *tidss);
#endif
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH 24/29] drm/tidss: dispc: Improve mode checking logs
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (22 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 23/29] drm/tidss: dispc: Add format lookup by hw value Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 14:06 ` Thomas Zimmermann
2025-09-02 8:32 ` [PATCH 25/29] drm/tidss: dispc: Move dispc_device definition to headers Maxime Ripard
` (5 subsequent siblings)
29 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The dispc_vp_mode_valid() function checks whether a mode can be handled
by the display controller.
There's a whole bunch of criteria, and it's not clear when a rejection
happens why it did. Let's add a bunch of logs on error to make it
clearer.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_dispc.c | 47 +++++++++++++++++++++++++++++--------
1 file changed, 37 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index 32248b5f71b7566dc33d7a7db0efb26d3a9ed1c3..ef948e3041e10bc65cf2c4794a4e4cffa7e3fb3a 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -1349,47 +1349,63 @@ static void dispc_vp_set_default_color(struct dispc_device *dispc,
enum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc,
u32 hw_videoport,
const struct drm_display_mode *mode)
{
+ struct tidss_device *tidss = dispc->tidss;
+ struct drm_device *dev = &tidss->ddev;
u32 hsw, hfp, hbp, vsw, vfp, vbp;
enum dispc_vp_bus_type bus_type;
int max_pclk;
bus_type = dispc->feat->vp_bus_type[hw_videoport];
max_pclk = dispc->feat->max_pclk_khz[bus_type];
- if (WARN_ON(max_pclk == 0))
+ if (WARN_ON(max_pclk == 0)) {
+ drm_dbg(dev, "Invalid maximum pixel clock");
return MODE_BAD;
+ }
- if (mode->clock < dispc->feat->min_pclk_khz)
+ if (mode->clock < dispc->feat->min_pclk_khz) {
+ drm_dbg(dev, "Mode pixel clock below hardware minimum pixel clock");
return MODE_CLOCK_LOW;
+ }
- if (mode->clock > max_pclk)
+ if (mode->clock > max_pclk) {
+ drm_dbg(dev, "Mode pixel clock above hardware maximum pixel clock");
return MODE_CLOCK_HIGH;
+ }
- if (mode->hdisplay > 4096)
+ if (mode->hdisplay > 4096) {
+ drm_dbg(dev, "Number of active horizontal pixels above hardware limits.");
return MODE_BAD;
+ }
- if (mode->vdisplay > 4096)
+ if (mode->vdisplay > 4096) {
+ drm_dbg(dev, "Number of active vertical lines above hardware limits.");
return MODE_BAD;
+ }
/* TODO: add interlace support */
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ drm_dbg(dev, "Interlace modes not suppported.");
return MODE_NO_INTERLACE;
+ }
/*
* Enforce the output width is divisible by 2. Actually this
* is only needed in following cases:
* - YUV output selected (BT656, BT1120)
* - Dithering enabled
* - TDM with TDMCycleFormat == 3
* But for simplicity we enforce that always.
*/
- if ((mode->hdisplay % 2) != 0)
+ if ((mode->hdisplay % 2) != 0) {
+ drm_dbg(dev, "Number of active horizontal pixels must be even.");
return MODE_BAD_HVALUE;
+ }
hfp = mode->hsync_start - mode->hdisplay;
hsw = mode->hsync_end - mode->hsync_start;
hbp = mode->htotal - mode->hsync_end;
@@ -1397,29 +1413,40 @@ enum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc,
vsw = mode->vsync_end - mode->vsync_start;
vbp = mode->vtotal - mode->vsync_end;
if (hsw < 1 || hsw > 256 ||
hfp < 1 || hfp > 4096 ||
- hbp < 1 || hbp > 4096)
+ hbp < 1 || hbp > 4096) {
+ drm_dbg(dev,
+ "Horizontal blanking or sync outside of hardware limits (fp: %u, sw: %u, bp: %u).",
+ hfp, hsw, hbp);
return MODE_BAD_HVALUE;
+ }
if (vsw < 1 || vsw > 256 ||
- vfp > 4095 || vbp > 4095)
+ vfp > 4095 || vbp > 4095) {
+ drm_dbg(dev,
+ "Vertical blanking or sync outside of hardware limits (fp: %u, sw: %u, bp: %u).",
+ vfp, vsw, vbp);
return MODE_BAD_VVALUE;
+ }
if (dispc->memory_bandwidth_limit) {
const unsigned int bpp = 4;
u64 bandwidth;
bandwidth = 1000 * mode->clock;
bandwidth = bandwidth * mode->hdisplay * mode->vdisplay * bpp;
bandwidth = div_u64(bandwidth, mode->htotal * mode->vtotal);
- if (dispc->memory_bandwidth_limit < bandwidth)
+ if (dispc->memory_bandwidth_limit < bandwidth) {
+ drm_dbg(dev, "Required memory bandwidth outside of hardware limits.");
return MODE_BAD;
+ }
}
+ drm_dbg(dev, "Mode is valid.");
return MODE_OK;
}
int dispc_vp_enable_clk(struct dispc_device *dispc, u32 hw_videoport)
{
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 24/29] drm/tidss: dispc: Improve mode checking logs
2025-09-02 8:32 ` [PATCH 24/29] drm/tidss: dispc: Improve mode checking logs Maxime Ripard
@ 2025-09-02 14:06 ` Thomas Zimmermann
0 siblings, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 14:06 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> The dispc_vp_mode_valid() function checks whether a mode can be handled
> by the display controller.
>
> There's a whole bunch of criteria, and it's not clear when a rejection
> happens why it did. Let's add a bunch of logs on error to make it
> clearer.
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> drivers/gpu/drm/tidss/tidss_dispc.c | 47 +++++++++++++++++++++++++++++--------
> 1 file changed, 37 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
> index 32248b5f71b7566dc33d7a7db0efb26d3a9ed1c3..ef948e3041e10bc65cf2c4794a4e4cffa7e3fb3a 100644
> --- a/drivers/gpu/drm/tidss/tidss_dispc.c
> +++ b/drivers/gpu/drm/tidss/tidss_dispc.c
> @@ -1349,47 +1349,63 @@ static void dispc_vp_set_default_color(struct dispc_device *dispc,
>
> enum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc,
> u32 hw_videoport,
> const struct drm_display_mode *mode)
> {
> + struct tidss_device *tidss = dispc->tidss;
> + struct drm_device *dev = &tidss->ddev;
> u32 hsw, hfp, hbp, vsw, vfp, vbp;
> enum dispc_vp_bus_type bus_type;
> int max_pclk;
>
> bus_type = dispc->feat->vp_bus_type[hw_videoport];
>
> max_pclk = dispc->feat->max_pclk_khz[bus_type];
>
> - if (WARN_ON(max_pclk == 0))
> + if (WARN_ON(max_pclk == 0)) {
Better remove this WARN_ON(). User-space could trigger it and spam the
kernel logs. It's also a driver bug, I think.
> + drm_dbg(dev, "Invalid maximum pixel clock");
> return MODE_BAD;
> + }
>
> - if (mode->clock < dispc->feat->min_pclk_khz)
> + if (mode->clock < dispc->feat->min_pclk_khz) {
> + drm_dbg(dev, "Mode pixel clock below hardware minimum pixel clock");
> return MODE_CLOCK_LOW;
> + }
>
> - if (mode->clock > max_pclk)
> + if (mode->clock > max_pclk) {
> + drm_dbg(dev, "Mode pixel clock above hardware maximum pixel clock");
> return MODE_CLOCK_HIGH;
> + }
>
> - if (mode->hdisplay > 4096)
> + if (mode->hdisplay > 4096) {
> + drm_dbg(dev, "Number of active horizontal pixels above hardware limits.");
> return MODE_BAD;
> + }
>
> - if (mode->vdisplay > 4096)
> + if (mode->vdisplay > 4096) {
> + drm_dbg(dev, "Number of active vertical lines above hardware limits.");
> return MODE_BAD;
> + }
>
> /* TODO: add interlace support */
> - if (mode->flags & DRM_MODE_FLAG_INTERLACE)
> + if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
> + drm_dbg(dev, "Interlace modes not suppported.");
> return MODE_NO_INTERLACE;
> + }
>
> /*
> * Enforce the output width is divisible by 2. Actually this
> * is only needed in following cases:
> * - YUV output selected (BT656, BT1120)
> * - Dithering enabled
> * - TDM with TDMCycleFormat == 3
> * But for simplicity we enforce that always.
> */
> - if ((mode->hdisplay % 2) != 0)
> + if ((mode->hdisplay % 2) != 0) {
> + drm_dbg(dev, "Number of active horizontal pixels must be even.");
> return MODE_BAD_HVALUE;
> + }
>
> hfp = mode->hsync_start - mode->hdisplay;
> hsw = mode->hsync_end - mode->hsync_start;
> hbp = mode->htotal - mode->hsync_end;
>
> @@ -1397,29 +1413,40 @@ enum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc,
> vsw = mode->vsync_end - mode->vsync_start;
> vbp = mode->vtotal - mode->vsync_end;
>
> if (hsw < 1 || hsw > 256 ||
> hfp < 1 || hfp > 4096 ||
> - hbp < 1 || hbp > 4096)
> + hbp < 1 || hbp > 4096) {
> + drm_dbg(dev,
> + "Horizontal blanking or sync outside of hardware limits (fp: %u, sw: %u, bp: %u).",
> + hfp, hsw, hbp);
> return MODE_BAD_HVALUE;
> + }
>
> if (vsw < 1 || vsw > 256 ||
> - vfp > 4095 || vbp > 4095)
> + vfp > 4095 || vbp > 4095) {
> + drm_dbg(dev,
> + "Vertical blanking or sync outside of hardware limits (fp: %u, sw: %u, bp: %u).",
> + vfp, vsw, vbp);
> return MODE_BAD_VVALUE;
> + }
>
> if (dispc->memory_bandwidth_limit) {
> const unsigned int bpp = 4;
> u64 bandwidth;
>
> bandwidth = 1000 * mode->clock;
> bandwidth = bandwidth * mode->hdisplay * mode->vdisplay * bpp;
> bandwidth = div_u64(bandwidth, mode->htotal * mode->vtotal);
>
> - if (dispc->memory_bandwidth_limit < bandwidth)
> + if (dispc->memory_bandwidth_limit < bandwidth) {
> + drm_dbg(dev, "Required memory bandwidth outside of hardware limits.");
> return MODE_BAD;
> + }
> }
>
> + drm_dbg(dev, "Mode is valid.");
> return MODE_OK;
> }
>
> int dispc_vp_enable_clk(struct dispc_device *dispc, u32 hw_videoport)
> {
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 25/29] drm/tidss: dispc: Move dispc_device definition to headers
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (23 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 24/29] drm/tidss: dispc: Improve mode checking logs Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 8:32 ` [PATCH 26/29] drm/tidss: dispc: make accessors accessible to other parts of the driver Maxime Ripard
` (4 subsequent siblings)
29 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
We'll need to access the dispc_device structure from other parts of the
driver so let's move it to a header.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_dispc.c | 33 ---------------------------------
drivers/gpu/drm/tidss/tidss_dispc.h | 33 +++++++++++++++++++++++++++++++++
2 files changed, 33 insertions(+), 33 deletions(-)
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index ef948e3041e10bc65cf2c4794a4e4cffa7e3fb3a..2f9cf95d6d0525a02d8adaae968aa551b7e27077 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -476,43 +476,10 @@ const struct dispc_features dispc_am62l_feats = {
.vid_order = {0},
};
static const u16 *dispc_common_regmap;
-struct dss_vp_data {
- u32 *gamma_table;
-};
-
-struct dispc_device {
- struct tidss_device *tidss;
- struct device *dev;
-
- void __iomem *base_common;
- void __iomem *base_vid[TIDSS_MAX_PLANES];
- void __iomem *base_ovr[TIDSS_MAX_PORTS];
- void __iomem *base_vp[TIDSS_MAX_PORTS];
-
- struct regmap *am65x_oldi_io_ctrl;
-
- struct clk *vp_clk[TIDSS_MAX_PORTS];
-
- const struct dispc_features *feat;
-
- struct clk *fclk;
-
- bool is_enabled;
-
- struct dss_vp_data vp_data[TIDSS_MAX_PORTS];
-
- u32 *fourccs;
- u32 num_fourccs;
-
- u32 memory_bandwidth_limit;
-
- struct dispc_errata errata;
-};
-
static void CH(struct dispc_device *dispc)
{
WARN_ON((dispc->dev->power.runtime_status != RPM_ACTIVE) &&
(dispc->dev->power.runtime_status != RPM_RESUMING) &&
(dispc->dev->power.runtime_status != RPM_SUSPENDING));
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h
index 849ec984026e223de7c8a55a4b5672c2262f38c0..f5d5798de1ba550dedbcba36b1ef41d5ecceaa0c 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.h
+++ b/drivers/gpu/drm/tidss/tidss_dispc.h
@@ -95,10 +95,43 @@ struct dispc_features {
u32 num_vids;
struct dispc_vid_info vid_info[TIDSS_MAX_PLANES];
u32 vid_order[TIDSS_MAX_PLANES];
};
+struct dss_vp_data {
+ u32 *gamma_table;
+};
+
+struct dispc_device {
+ struct tidss_device *tidss;
+ struct device *dev;
+
+ void __iomem *base_common;
+ void __iomem *base_vid[TIDSS_MAX_PLANES];
+ void __iomem *base_ovr[TIDSS_MAX_PORTS];
+ void __iomem *base_vp[TIDSS_MAX_PORTS];
+
+ struct regmap *am65x_oldi_io_ctrl;
+
+ struct clk *vp_clk[TIDSS_MAX_PORTS];
+
+ const struct dispc_features *feat;
+
+ struct clk *fclk;
+
+ bool is_enabled;
+
+ struct dss_vp_data vp_data[TIDSS_MAX_PORTS];
+
+ u32 *fourccs;
+ u32 num_fourccs;
+
+ u32 memory_bandwidth_limit;
+
+ struct dispc_errata errata;
+};
+
extern const struct dispc_features dispc_k2g_feats;
extern const struct dispc_features dispc_am625_feats;
extern const struct dispc_features dispc_am62a7_feats;
extern const struct dispc_features dispc_am62l_feats;
extern const struct dispc_features dispc_am65x_feats;
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH 26/29] drm/tidss: dispc: make accessors accessible to other parts of the driver
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (24 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 25/29] drm/tidss: dispc: Move dispc_device definition to headers Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 8:32 ` [PATCH 27/29] drm/tidss: Implement readout support Maxime Ripard
` (3 subsequent siblings)
29 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_dispc.c | 4 ++--
drivers/gpu/drm/tidss/tidss_dispc.h | 3 +++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index 2f9cf95d6d0525a02d8adaae968aa551b7e27077..18b6beddfe51f9b5c164481ee2ef0fa289e63318 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -504,11 +504,11 @@ void dispc_vid_write(struct dispc_device *dispc, u32 hw_plane, u16 reg, u32 val)
CH(dispc);
iowrite32(val, base + reg);
}
-static u32 dispc_vid_read(struct dispc_device *dispc, u32 hw_plane, u16 reg)
+u32 dispc_vid_read(struct dispc_device *dispc, u32 hw_plane, u16 reg)
{
void __iomem *base = dispc->base_vid[hw_plane];
CH(dispc);
return ioread32(base + reg);
@@ -538,11 +538,11 @@ static void dispc_vp_write(struct dispc_device *dispc, u32 hw_videoport,
CH(dispc);
iowrite32(val, base + reg);
}
-static u32 dispc_vp_read(struct dispc_device *dispc, u32 hw_videoport, u16 reg)
+u32 dispc_vp_read(struct dispc_device *dispc, u32 hw_videoport, u16 reg)
{
void __iomem *base = dispc->base_vp[hw_videoport];
CH(dispc);
return ioread32(base + reg);
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h
index f5d5798de1ba550dedbcba36b1ef41d5ecceaa0c..b249cd0da331bf801992a7f38ff9031a5f8da0b8 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.h
+++ b/drivers/gpu/drm/tidss/tidss_dispc.h
@@ -181,9 +181,12 @@ void dispc_plane_setup(struct dispc_device *dispc, u32 hw_plane,
u32 hw_videoport);
void dispc_plane_enable(struct dispc_device *dispc, u32 hw_plane, bool enable);
const u32 *dispc_plane_formats(struct dispc_device *dispc, unsigned int *len);
u32 dispc_plane_find_fourcc_by_dss_code(u8 code);
+u32 dispc_vid_read(struct dispc_device *dispc, u32 hw_plane, u16 reg);
+u32 dispc_vp_read(struct dispc_device *dispc, u32 hw_videoport, u16 reg);
+
int dispc_init(struct tidss_device *tidss);
void dispc_remove(struct tidss_device *tidss);
#endif
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH 27/29] drm/tidss: Implement readout support
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (25 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 26/29] drm/tidss: dispc: make accessors accessible to other parts of the driver Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 8:32 ` [PATCH 28/29] drm/tidss: encoder: implement get_current_crtc Maxime Ripard
` (2 subsequent siblings)
29 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
With the hardware readout infrastructure now in place in the KMS
framework, we can provide it for the tidss driver.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_crtc.c | 218 +++++++++++++++++++++++++++++++++++-
drivers/gpu/drm/tidss/tidss_dispc.c | 48 --------
drivers/gpu/drm/tidss/tidss_kms.c | 3 +-
drivers/gpu/drm/tidss/tidss_plane.c | 194 +++++++++++++++++++++++++++++++-
4 files changed, 409 insertions(+), 54 deletions(-)
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
index 8fcc6a2f94770ae825eeb2a3b09856a2bf2d6a1e..454c4db92942c6c781440aff78c755e386b2edf3 100644
--- a/drivers/gpu/drm/tidss/tidss_crtc.c
+++ b/drivers/gpu/drm/tidss/tidss_crtc.c
@@ -2,18 +2,22 @@
/*
* Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*/
+#include <linux/clk.h>
+
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_crtc.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_vblank.h>
#include "tidss_crtc.h"
#include "tidss_dispc.h"
+#include "tidss_dispc_regs.h"
#include "tidss_drv.h"
#include "tidss_irq.h"
#include "tidss_plane.h"
/* Page flip and frame done IRQs */
@@ -350,24 +354,229 @@ static void tidss_crtc_destroy_state(struct drm_crtc *crtc,
__drm_atomic_helper_crtc_destroy_state(&tstate->base);
kfree(tstate);
}
-static void tidss_crtc_reset(struct drm_crtc *crtc)
+static unsigned long calc_pixel_clock_hz(unsigned int htotal,
+ unsigned int vtotal,
+ unsigned int refresh,
+ unsigned int freq_div)
{
+ unsigned long rate = (unsigned long)htotal * vtotal * refresh;
+
+ return (rate * 1000) / freq_div;
+}
+
+static const unsigned int refresh_tries[] = {30, 50, 60};
+static const unsigned int refresh_factors_tries[] = {1000, 1001};
+
+static unsigned int tidss_find_closest_refresh_rate_from_clk(struct drm_device *dev,
+ struct clk *clk,
+ unsigned int htotal,
+ unsigned int vtotal,
+ unsigned long *pixel_clock_hz)
+{
+ unsigned long actual_clk_rate = clk_get_rate(clk);
+ unsigned long best_clk_rate = 0;
+ unsigned long best_rate_diff = ULONG_MAX;
+ unsigned int best_refresh = 0;
+ unsigned int i, j;
+
+ drm_dbg(dev, "Actual clock rate is %lu\n", actual_clk_rate);
+
+ for (i = 0; i < ARRAY_SIZE(refresh_tries); i++) {
+ for (j = 0; j < ARRAY_SIZE(refresh_factors_tries); j++) {
+ unsigned int try_refresh = refresh_tries[i];
+ unsigned int try_factor = refresh_factors_tries[j];
+ unsigned long try_clk_rate = calc_pixel_clock_hz(htotal,
+ vtotal,
+ try_refresh,
+ try_factor);
+ unsigned long diff;
+
+ drm_dbg(dev, "Evaluating refresh %u, factor %u, rate %lu\n",
+ try_refresh, try_factor, try_clk_rate);
+
+ if (try_clk_rate == actual_clk_rate) {
+ drm_dbg(dev, "Found exact match. Stopping.\n");
+ best_refresh = try_refresh;
+ best_clk_rate = try_clk_rate;
+ goto out;
+ }
+
+
+ diff = abs_diff(actual_clk_rate, try_clk_rate);
+ if (diff < best_rate_diff) {
+ drm_dbg(dev, "Found new candidate. Difference is %lu\n", diff);
+ best_refresh = try_refresh;
+ best_clk_rate = try_clk_rate;
+ best_rate_diff = diff;
+ }
+ }
+ }
+
+out:
+ drm_dbg(dev, "Best candidate is %u Hz, pixel clock rate %lu Hz", best_refresh, best_clk_rate);
+
+ if (pixel_clock_hz)
+ *pixel_clock_hz = best_clk_rate;
+
+ return best_refresh;
+}
+
+static int tidss_crtc_readout_mode(struct dispc_device *dispc,
+ struct tidss_crtc *tcrtc,
+ struct drm_display_mode *mode)
+{
+ struct tidss_device *tidss = dispc->tidss;
+ struct drm_device *dev = &tidss->ddev;
+ unsigned long pixel_clock;
+ unsigned int refresh;
+ u16 hdisplay, hfp, hsw, hbp;
+ u16 vdisplay, vfp, vsw, vbp;
+ u32 vp = tcrtc->hw_videoport;
+ u32 val;
+
+ val = dispc_vp_read(dispc, vp, DISPC_VP_SIZE_SCREEN);
+ hdisplay = FIELD_GET(DISPC_VP_SIZE_SCREEN_HDISPLAY_MASK, val) + 1;
+ vdisplay = FIELD_GET(DISPC_VP_SIZE_SCREEN_VDISPLAY_MASK, val) + 1;
+
+ mode->hdisplay = hdisplay;
+ mode->vdisplay = vdisplay;
+
+ val = dispc_vp_read(dispc, vp, DISPC_VP_TIMING_H);
+ hsw = FIELD_GET(DISPC_VP_TIMING_H_SYNC_PULSE_MASK, val) + 1;
+ hfp = FIELD_GET(DISPC_VP_TIMING_H_FRONT_PORCH_MASK, val) + 1;
+ hbp = FIELD_GET(DISPC_VP_TIMING_H_BACK_PORCH_MASK, val) + 1;
+
+ mode->hsync_start = hdisplay + hfp;
+ mode->hsync_end = hdisplay + hfp + hsw;
+ mode->htotal = hdisplay + hfp + hsw + hbp;
+
+ val = dispc_vp_read(dispc, vp, DISPC_VP_TIMING_V);
+ vsw = FIELD_GET(DISPC_VP_TIMING_V_SYNC_PULSE_MASK, val) + 1;
+ vfp = FIELD_GET(DISPC_VP_TIMING_V_FRONT_PORCH_MASK, val);
+ vbp = FIELD_GET(DISPC_VP_TIMING_V_BACK_PORCH_MASK, val);
+
+ mode->vsync_start = vdisplay + vfp;
+ mode->vsync_end = vdisplay + vfp + vsw;
+ mode->vtotal = vdisplay + vfp + vsw + vbp;
+
+ refresh = tidss_find_closest_refresh_rate_from_clk(dev,
+ dispc->vp_clk[vp],
+ mode->htotal,
+ mode->vtotal,
+ &pixel_clock);
+ if (!refresh)
+ return -EINVAL;
+
+ mode->clock = pixel_clock / 1000;
+
+ val = dispc_vp_read(dispc, vp, DISPC_VP_POL_FREQ);
+ if (FIELD_GET(DISPC_VP_POL_FREQ_IVS_MASK, val))
+ mode->flags |= DRM_MODE_FLAG_NVSYNC;
+ else
+ mode->flags |= DRM_MODE_FLAG_PVSYNC;
+
+ if (FIELD_GET(DISPC_VP_POL_FREQ_IHS_MASK, val))
+ mode->flags |= DRM_MODE_FLAG_NHSYNC;
+ else
+ mode->flags |= DRM_MODE_FLAG_PHSYNC;
+
+ mode->type |= DRM_MODE_TYPE_DRIVER;
+ drm_mode_set_name(mode);
+ drm_mode_set_crtcinfo(mode, 0);
+
+ return 0;
+}
+
+static struct drm_crtc_state *
+tidss_crtc_readout_state(struct drm_crtc *crtc)
+{
+ struct drm_device *ddev = crtc->dev;
+ struct tidss_device *tidss = to_tidss(ddev);
+ struct dispc_device *dispc = tidss->dispc;
struct tidss_crtc_state *tstate;
+ struct tidss_crtc *tcrtc =
+ to_tidss_crtc(crtc);
+ struct drm_display_mode mode;
+ u32 val;
+ int ret;
if (crtc->state)
tidss_crtc_destroy_state(crtc, crtc->state);
tstate = kzalloc(sizeof(*tstate), GFP_KERNEL);
if (!tstate) {
- crtc->state = NULL;
- return;
+ return ERR_PTR(-ENOMEM);
}
__drm_atomic_helper_crtc_reset(crtc, &tstate->base);
+
+ tidss_runtime_get(tidss);
+
+ val = dispc_vp_read(dispc, tcrtc->hw_videoport, DISPC_VP_CONTROL);
+ if (!FIELD_GET(DISPC_VP_CONTROL_ENABLE_MASK, val))
+ goto out;
+
+ /*
+ * The display is active, we need to enable our clock to have
+ * proper reference count.
+ */
+ WARN_ON(dispc_vp_enable_clk(tidss->dispc, tcrtc->hw_videoport));
+
+ tstate->base.active = 1;
+ tstate->base.enable = 1;
+
+ ret = tidss_crtc_readout_mode(dispc, tcrtc, &mode);
+ if (ret)
+ goto err_runtime_put;
+
+ ret = drm_atomic_set_mode_for_crtc(&tstate->base, &mode);
+ if (WARN_ON(ret))
+ goto err_runtime_put;
+
+ drm_mode_copy(&tstate->base.adjusted_mode, &mode);
+
+ val = dispc_vp_read(dispc, tcrtc->hw_videoport, DISPC_VP_POL_FREQ);
+ if (FIELD_GET(DISPC_VP_POL_FREQ_IPC_MASK, val))
+ tstate->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
+
+ if (FIELD_GET(DISPC_VP_POL_FREQ_IEO_MASK, val))
+ tstate->bus_flags |= DRM_BUS_FLAG_DE_LOW;
+
+ if (FIELD_GET(DISPC_VP_POL_FREQ_RF_MASK, val))
+ tstate->bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
+
+ /*
+ * The active connectors and planes will be filled by their
+ * respective readout callbacks.
+ */
+
+out:
+ tidss_runtime_put(tidss);
+ return &tstate->base;
+
+err_runtime_put:
+ tidss_runtime_put(tidss);
+ kfree(tstate);
+ return ERR_PTR(ret);
+}
+
+static bool tidss_crtc_compare_state(struct drm_crtc *crtc,
+ struct drm_printer *p,
+ struct drm_crtc_state *expected,
+ struct drm_crtc_state *actual)
+{
+ struct tidss_crtc_state *t_expected = to_tidss_crtc_state(expected);
+ struct tidss_crtc_state *t_actual = to_tidss_crtc_state(actual);
+ int ret = drm_atomic_helper_crtc_compare_state(crtc, p, expected, actual);
+
+ STATE_CHECK_U32_X(ret, p, crtc->name, t_expected, t_actual, bus_format);
+ STATE_CHECK_U32_X(ret, p, crtc->name, t_expected, t_actual, bus_flags);
+
+ return ret;
}
static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc)
{
struct tidss_crtc_state *state, *current_state;
@@ -398,14 +607,15 @@ static void tidss_crtc_destroy(struct drm_crtc *crtc)
drm_crtc_cleanup(crtc);
kfree(tcrtc);
}
static const struct drm_crtc_funcs tidss_crtc_funcs = {
- .reset = tidss_crtc_reset,
.destroy = tidss_crtc_destroy,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
+ .atomic_readout_state = tidss_crtc_readout_state,
+ .atomic_compare_state = tidss_crtc_compare_state,
.atomic_duplicate_state = tidss_crtc_duplicate_state,
.atomic_destroy_state = tidss_crtc_destroy_state,
.enable_vblank = tidss_crtc_enable_vblank,
.disable_vblank = tidss_crtc_disable_vblank,
};
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index 18b6beddfe51f9b5c164481ee2ef0fa289e63318..e7f6f047574f5b520b00195c2b14d98224db6f19 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -2916,51 +2916,10 @@ static void dispc_init_errata(struct dispc_device *dispc)
dispc->errata.i2000 = true;
dev_info(dispc->dev, "WA for erratum i2000: YUV formats disabled\n");
}
}
-/*
- * K2G display controller does not support soft reset, so we do a basic manual
- * reset here: make sure the IRQs are masked and VPs are disabled.
- */
-static void dispc_softreset_k2g(struct dispc_device *dispc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dispc->tidss->irq_lock, flags);
- dispc_set_irqenable(dispc, 0);
- dispc_read_and_clear_irqstatus(dispc);
- spin_unlock_irqrestore(&dispc->tidss->irq_lock, flags);
-
- for (unsigned int vp_idx = 0; vp_idx < dispc->feat->num_vps; ++vp_idx)
- VP_REG_FLD_MOD(dispc, vp_idx, DISPC_VP_CONTROL, 0,
- DISPC_VP_CONTROL_ENABLE_MASK);
-}
-
-static int dispc_softreset(struct dispc_device *dispc)
-{
- u32 val;
- int ret;
-
- if (dispc->feat->subrev == DISPC_K2G) {
- dispc_softreset_k2g(dispc);
- return 0;
- }
-
- /* Soft reset */
- REG_FLD_MOD(dispc, DSS_SYSCONFIG, 1, DSS_SYSCONFIG_SOFTRESET_MASK);
- /* Wait for reset to complete */
- ret = readl_poll_timeout(dispc->base_common + DSS_SYSSTATUS,
- val, val & 1, 100, 5000);
- if (ret) {
- dev_err(dispc->dev, "failed to reset dispc\n");
- return ret;
- }
-
- return 0;
-}
-
static int dispc_init_hw(struct dispc_device *dispc)
{
struct device *dev = dispc->dev;
int ret;
@@ -2974,26 +2933,19 @@ static int dispc_init_hw(struct dispc_device *dispc)
if (ret) {
dev_err(dev, "Failed to enable DSS fclk\n");
goto err_runtime_suspend;
}
- ret = dispc_softreset(dispc);
- if (ret)
- goto err_clk_disable;
-
clk_disable_unprepare(dispc->fclk);
ret = pm_runtime_set_suspended(dev);
if (ret) {
dev_err(dev, "Failed to set DSS PM to suspended\n");
return ret;
}
return 0;
-err_clk_disable:
- clk_disable_unprepare(dispc->fclk);
-
err_runtime_suspend:
ret = pm_runtime_set_suspended(dev);
if (ret) {
dev_err(dev, "Failed to set DSS PM to suspended\n");
return ret;
diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c
index 86eb5d97410bedced57129c2bbcd35f1719424c2..38c90027c158a392f96012f88824ead091332fb7 100644
--- a/drivers/gpu/drm/tidss/tidss_kms.c
+++ b/drivers/gpu/drm/tidss/tidss_kms.c
@@ -37,11 +37,12 @@ static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state)
tidss_runtime_put(tidss);
}
static const struct drm_mode_config_helper_funcs mode_config_helper_funcs = {
- .atomic_commit_tail = tidss_atomic_commit_tail,
+ .atomic_commit_tail = tidss_atomic_commit_tail,
+ .atomic_reset = drm_atomic_helper_readout_state,
};
static int tidss_atomic_check(struct drm_device *ddev,
struct drm_atomic_state *state)
{
diff --git a/drivers/gpu/drm/tidss/tidss_plane.c b/drivers/gpu/drm/tidss/tidss_plane.c
index bd10bc1b9961571e6c6dee26698149fc9dd135b0..037c21354dd170511868baca24960ff9295dbea5 100644
--- a/drivers/gpu/drm/tidss/tidss_plane.c
+++ b/drivers/gpu/drm/tidss/tidss_plane.c
@@ -10,13 +10,15 @@
#include <drm/drm_crtc.h>
#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
#include "tidss_crtc.h"
#include "tidss_dispc.h"
+#include "tidss_dispc_regs.h"
#include "tidss_drv.h"
#include "tidss_plane.h"
void tidss_plane_error_irq(struct drm_plane *plane, u64 irqstatus)
{
@@ -173,17 +175,207 @@ static const struct drm_plane_helper_funcs tidss_primary_plane_helper_funcs = {
.atomic_enable = tidss_plane_atomic_enable,
.atomic_disable = tidss_plane_atomic_disable,
.get_scanout_buffer = drm_fb_dma_get_scanout_buffer,
};
+static const struct drm_framebuffer_funcs tidss_plane_readout_fb_funcs = {
+ .destroy = drm_gem_fb_destroy,
+};
+
+static struct drm_framebuffer *tidss_plane_readout_fb(struct drm_plane *plane)
+{
+ struct drm_device *ddev = plane->dev;
+ struct tidss_device *tidss = to_tidss(ddev);
+ struct dispc_device *dispc = tidss->dispc;
+ struct tidss_plane *tplane = to_tidss_plane(plane);
+ const struct drm_format_info *info;
+ struct drm_framebuffer *fb;
+ u32 fourcc, val;
+ int ret;
+
+ fb = kzalloc(sizeof(*fb), GFP_KERNEL);
+ if (!fb)
+ return ERR_PTR(-ENOMEM);
+
+ fb->dev = plane->dev;
+
+ val = dispc_vid_read(dispc, tplane->hw_plane_id, DISPC_VID_ATTRIBUTES);
+ fourcc =
+ dispc_plane_find_fourcc_by_dss_code(FIELD_GET(DISPC_VID_ATTRIBUTES_FORMAT_MASK,
+ val));
+ if (!fourcc) {
+ ret = -EINVAL;
+ goto err_free_fb;
+ }
+
+ info = drm_format_info(fourcc);
+ if (!info) {
+ ret = -EINVAL;
+ goto err_free_fb;
+ }
+
+ // TODO: Figure out YUV and multiplanar formats
+ if (info->is_yuv) {
+ ret = -EINVAL;
+ goto err_free_fb;
+ }
+
+ fb->format = info;
+
+ val = dispc_vid_read(dispc, tplane->hw_plane_id, DISPC_VID_PICTURE_SIZE);
+ fb->width = FIELD_GET(DISPC_VID_PICTURE_SIZE_MEMSIZEX_MASK, val) + 1;
+ fb->height = FIELD_GET(DISPC_VID_PICTURE_SIZE_MEMSIZEY_MASK, val) + 1;
+
+ // TODO: Figure that out.
+ val = dispc_vid_read(dispc, tplane->hw_plane_id, DISPC_VID_ROW_INC);
+ if (val != 1) {
+ ret = -EINVAL;
+ goto err_free_fb;
+ }
+
+ fb->pitches[0] = fb->width * (drm_format_info_bpp(info, 0) / 8);
+
+ // TODO: Figure out the offsets
+ fb->offsets[0] = 0;
+
+ ret = drm_framebuffer_init(plane->dev, fb, &tidss_plane_readout_fb_funcs);
+ if (ret) {
+ kfree(fb);
+ return ERR_PTR(ret);
+ }
+
+ return fb;
+
+err_free_fb:
+ kfree(fb);
+ return ERR_PTR(ret);
+}
+
+static struct drm_crtc *tidss_plane_readout_crtc(struct drm_plane *plane)
+{
+ struct drm_device *dev = plane->dev;
+
+ if (dev->num_crtcs != 1)
+ return ERR_PTR(-EINVAL);
+
+ return list_first_entry(&dev->mode_config.crtc_list, struct drm_crtc, head);
+}
+
+static struct drm_plane_state *tidss_plane_atomic_readout_state(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_device *ddev = plane->dev;
+ struct tidss_device *tidss = to_tidss(ddev);
+ struct dispc_device *dispc = tidss->dispc;
+ struct tidss_plane *tplane = to_tidss_plane(plane);
+ struct drm_plane_state *plane_state;
+ struct drm_crtc_state *crtc_state;
+ struct drm_framebuffer *fb;
+ struct drm_crtc *crtc;
+ bool lite = dispc->feat->vid_info[tplane->hw_plane_id].is_lite;
+ u16 in_w, in_h;
+ u32 val;
+ int ret;
+
+ if (plane->state)
+ drm_atomic_helper_plane_destroy_state(plane, plane->state);
+
+ plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
+ if (!plane_state)
+ return ERR_PTR(-ENOMEM);
+
+ __drm_atomic_helper_plane_state_reset(plane_state, plane);
+
+ tidss_runtime_get(tidss);
+
+ val = dispc_vid_read(dispc, tplane->hw_plane_id, DISPC_VID_ATTRIBUTES);
+ if (!FIELD_GET(DISPC_VID_ATTRIBUTES_ENABLE_MASK, val)) {
+ goto out;
+ }
+
+ fb = tidss_plane_readout_fb(plane);
+ if (IS_ERR(fb)) {
+ ret = PTR_ERR(fb);
+ goto err_runtime_pm;
+ }
+
+ crtc = tidss_plane_readout_crtc(plane);
+ if (IS_ERR(crtc)) {
+ ret = PTR_ERR(crtc);
+ goto err_runtime_pm;
+ }
+
+ plane_state->fb = fb;
+ plane_state->crtc = crtc;
+ plane_state->visible = true;
+
+ val = dispc_vid_read(dispc, tplane->hw_plane_id, DISPC_VID_PICTURE_SIZE);
+ in_w = FIELD_GET(DISPC_VID_PICTURE_SIZE_MEMSIZEX_MASK, val) + 1;
+ in_h = FIELD_GET(DISPC_VID_PICTURE_SIZE_MEMSIZEY_MASK, val) + 1;
+ plane_state->src_w = in_w << 16;
+ plane_state->src_h = in_h << 16;
+
+ if (!lite) {
+ val = dispc_vid_read(dispc, tplane->hw_plane_id, DISPC_VID_SIZE);
+ plane_state->crtc_w = FIELD_GET(DISPC_VID_SIZE_SIZEX_MASK, val) + 1;
+ plane_state->crtc_h = FIELD_GET(DISPC_VID_SIZE_SIZEY_MASK, val) + 1;
+ } else {
+ plane_state->crtc_w = in_w;
+ plane_state->crtc_h = in_h;
+ }
+
+ // TODO: Handle crtc_x/crtc_x/src_x/src_y
+ // crtc_x/crtc_y are handled by DISPC_OVR_ATTRIBUTES / OVR1_DSS_ATTRIBUTES
+
+ // TODO: Handle zpos, see DISPC_OVR_ATTRIBUTES / OVR1_DSS_ATTRIBUTES
+
+ plane_state->src.x1 = 0;
+ plane_state->src.x2 = plane_state->src_w;
+ plane_state->src.y1 = 0;
+ plane_state->src.y2 = plane_state->src_h;
+ plane_state->dst.x1 = 0;
+ plane_state->dst.x2 = plane_state->crtc_w;
+ plane_state->dst.y1 = 0;
+ plane_state->dst.y2 = plane_state->crtc_h;
+
+ val = dispc_vid_read(dispc, tplane->hw_plane_id, DISPC_VID_GLOBAL_ALPHA);
+ plane_state->alpha = FIELD_GET(DISPC_VID_GLOBAL_ALPHA_GLOBALALPHA_MASK, val) << 16;
+
+ val = dispc_vid_read(dispc, tplane->hw_plane_id, DISPC_VID_ATTRIBUTES);
+ if (FIELD_GET(DISPC_VID_ATTRIBUTES_PREMULTIPLYALPHA_MASK, val))
+ plane_state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
+ else
+ plane_state->pixel_blend_mode = DRM_MODE_BLEND_COVERAGE;
+
+ // TODO: If YUV, handle color encoding and range
+
+ crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
+ if (!crtc_state) {
+ ret = -ENODEV;
+ goto err_runtime_pm;
+ }
+
+ crtc_state->plane_mask |= drm_plane_mask(plane);
+
+out:
+ tidss_runtime_put(tidss);
+ return plane_state;
+
+err_runtime_pm:
+ tidss_runtime_put(tidss);
+ kfree(plane_state);
+ return ERR_PTR(ret);
+}
+
static const struct drm_plane_funcs tidss_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .reset = drm_atomic_helper_plane_reset,
.destroy = drm_plane_destroy,
+ .atomic_compare_state = drm_atomic_helper_plane_compare_state,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .atomic_readout_state = tidss_plane_atomic_readout_state,
};
struct tidss_plane *tidss_plane_create(struct tidss_device *tidss,
u32 hw_plane_id, u32 plane_type,
u32 crtc_mask, const u32 *formats,
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH 28/29] drm/tidss: encoder: implement get_current_crtc
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (26 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 27/29] drm/tidss: Implement readout support Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 8:32 ` [PATCH 29/29] drm/bridge: sii902x: Implement hw state readout Maxime Ripard
2025-09-02 14:13 ` [PATCH 00/29] drm: Implement state readout support Thomas Zimmermann
29 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The tidss driver doesn't really care implement anything with encoders,
it just relies on simple encoders, bridges and drm_bridge_connector.
In order to figure out the CRTC -> connector association from the
hardware state, we do need encoder support though, through the
get_current_crtc callback.
Since the tidss encoders are always connected to a single CRTC, we don't
really need to read the hardware state though, we can simply return the
one we know we are always connected to.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_encoder.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/tidss/tidss_encoder.c b/drivers/gpu/drm/tidss/tidss_encoder.c
index 81a04f7677701b0b1bee204ac9fc5835ac373950..2cb12ab48a48cec453defcb261915e4663806289 100644
--- a/drivers/gpu/drm/tidss/tidss_encoder.c
+++ b/drivers/gpu/drm/tidss/tidss_encoder.c
@@ -79,10 +79,29 @@ static const struct drm_bridge_funcs tidss_bridge_funcs = {
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
};
+static struct drm_crtc *tidss_encoder_get_current_crtc(struct drm_encoder *encoder)
+{
+ struct drm_crtc *crtc;
+
+ WARN_ON(hweight32(encoder->possible_crtcs) > 1);
+
+ drm_for_each_crtc(crtc, encoder->dev) {
+ if (encoder->possible_crtcs == (1 << drm_crtc_index(crtc)))
+ return crtc;
+ }
+
+ return NULL;
+}
+
+static const struct drm_encoder_funcs tidss_encoder_funcs = {
+ .get_current_crtc = tidss_encoder_get_current_crtc,
+ .destroy = drm_encoder_cleanup,
+};
+
int tidss_encoder_create(struct tidss_device *tidss,
struct drm_bridge *next_bridge,
u32 encoder_type, u32 possible_crtcs)
{
struct tidss_encoder *t_enc;
@@ -93,12 +112,13 @@ int tidss_encoder_create(struct tidss_device *tidss,
t_enc = devm_drm_bridge_alloc(tidss->dev, struct tidss_encoder,
bridge, &tidss_bridge_funcs);
if (IS_ERR(t_enc))
return PTR_ERR(t_enc);
- ret = drm_simple_encoder_init(&tidss->ddev, &t_enc->encoder,
- encoder_type);
+ ret = drm_encoder_init(&tidss->ddev, &t_enc->encoder,
+ &tidss_encoder_funcs,
+ encoder_type, NULL);
if (ret)
return ret;
t_enc->tidss = tidss;
t_enc->next_bridge = next_bridge;
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH 29/29] drm/bridge: sii902x: Implement hw state readout
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (27 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 28/29] drm/tidss: encoder: implement get_current_crtc Maxime Ripard
@ 2025-09-02 8:32 ` Maxime Ripard
2025-09-02 14:13 ` [PATCH 00/29] drm: Implement state readout support Thomas Zimmermann
29 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2025-09-02 8:32 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
Let's implement the hardware state readout for the sii902x bridge now
that we have all the infrastructure in place.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/bridge/sii902x.c | 51 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 50 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index d537b1d036fb09ce55a690a0809dcc28fc0f41be..5ffceb9131540d2cb1b82a74b4f7cec9bc7fd8ca 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -540,17 +540,66 @@ sii902x_bridge_mode_valid(struct drm_bridge *bridge,
return MODE_CLOCK_HIGH;
return MODE_OK;
}
+static int sii902x_bridge_connector_hw_readout(struct drm_bridge *bridge,
+ struct drm_atomic_state *state,
+ struct drm_connector_state *conn_state)
+{
+ struct sii902x *sii902x = bridge_to_sii902x(bridge);
+ struct drm_connector *connector = conn_state->connector;
+ struct drm_crtc_state *crtc_state;
+ struct drm_encoder *encoder;
+ struct drm_crtc *crtc;
+
+ if (regmap_test_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, SII902X_SYS_CTRL_PWR_DWN))
+ return 0;
+
+ encoder = bridge->encoder;
+ crtc = encoder->funcs->get_current_crtc(encoder);
+ if (!crtc)
+ return -ENODEV;
+
+ crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
+ if (!crtc_state)
+ return -ENODEV;
+
+ crtc_state->encoder_mask |= drm_encoder_mask(encoder);
+ crtc_state->connector_mask |= drm_connector_mask(connector);
+
+ conn_state->crtc = crtc;
+ conn_state->best_encoder = encoder;
+
+ return 0;
+}
+
+static int sii902x_bridge_readout_state(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct sii902x *sii902x = bridge_to_sii902x(bridge);
+
+ if (regmap_test_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, SII902X_SYS_CTRL_PWR_DWN))
+ return 0;
+
+ /* bridge_state is pretty trivial, we don't have anything to do here */
+
+ return 0;
+}
+
static const struct drm_bridge_funcs sii902x_bridge_funcs = {
.attach = sii902x_bridge_attach,
.mode_set = sii902x_bridge_mode_set,
.atomic_disable = sii902x_bridge_atomic_disable,
.atomic_enable = sii902x_bridge_atomic_enable,
+ .connector_hw_readout = sii902x_bridge_connector_hw_readout,
.detect = sii902x_bridge_detect,
.edid_read = sii902x_bridge_edid_read,
+ .atomic_compare_state = drm_atomic_helper_bridge_compare_state,
+ .atomic_readout_state = sii902x_bridge_readout_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_get_input_bus_fmts = sii902x_bridge_atomic_get_input_bus_fmts,
.atomic_check = sii902x_bridge_atomic_check,
@@ -1136,11 +1185,11 @@ static int sii902x_init(struct sii902x *sii902x)
if (ret)
goto err_unreg_audio;
sii902x->bridge.of_node = dev->of_node;
sii902x->bridge.timings = &default_sii902x_timings;
- sii902x->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;
+ sii902x->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_CONNECTOR_HW_READOUT;
sii902x->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
if (sii902x->i2c->irq > 0)
sii902x->bridge.ops |= DRM_BRIDGE_OP_HPD;
--
2.50.1
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH 00/29] drm: Implement state readout support
2025-09-02 8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
` (28 preceding siblings ...)
2025-09-02 8:32 ` [PATCH 29/29] drm/bridge: sii902x: Implement hw state readout Maxime Ripard
@ 2025-09-02 14:13 ` Thomas Zimmermann
29 siblings, 0 replies; 57+ messages in thread
From: Thomas Zimmermann @ 2025-09-02 14:13 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel
Hi Maxime,
there are a number of patches in this series that can be merged
immediately, and likely should.
Is the state-compare code really necessary? Doing this separately might
ease the review.
Best regards
Thomas
Am 02.09.25 um 10:32 schrieb Maxime Ripard:
> Hi,
>
> Here's a series that implement what i915 calls "fastboot", ie,
> initializing the initial KMS state from the hardware state at boot, to
> skip the first modeset if the firmware already set up the display.
>
> This series creates the infrastructure in KMS to create that state by
> relying on driver specific hooks. It also implements some infrastructure
> to check during non-blocking commits that the readout helpers work
> properly by reading out the state that was just committed and comparing
> it to what was supposed to be commited.
>
> This relies on another set of driver hooks to compare the entities
> states, with helpers providing the default implementation.
>
> It then implements the readout support in the TIDSS driver, and was
> tested with the SK-AM62 board. This board in particular is pretty
> interesting, since it relies on an DPI to HDMI bridge, and uses the
> drm_bridge_connector infrastructure.
>
> So the readout works with the current state of the art on embedded-ish
> platforms.
>
> The whole thing feels a bit clunky at the moment:
>
> - The initial state buildup ties everything together in a state in the
> old state pointer. It's useful for the initial readout because
> accessors can then use the usual state accessors to look into the
> state of other entities. But one of the argument for it was also
> that for state comparison, it allows to compare the new state
> (committed) to the old state (readout). It doesn't really work in
> practice, since in such a case the old state contains the previous
> hardware state to be freed, and thus we would end up with a memory
> leak
>
> - The framebuffer refcounting is broken.
>
> - The tidss atomic_flush waits for the go bit on the initial
> modesetting, except that if the state is readout we didn't commit
> anything and the driver will wait forever, eventually resulting in
> commit timeout
>
> - The tidss_crtc_state fields are not read properly at the moment
> either.
>
> The main thing works though: the state is picked up properly, doesn't
> trigger a modeset if what was programmed is the one the first modeset
> tries to pick as well, will switch properly if it isn't, etc.
>
> Let me know what you think,
> Maxime
>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> Maxime Ripard (29):
> drm/atomic: Document atomic state lifetime
> drm/atomic: Fix unused but set warning in for_each_old_plane_in_state
> drm/atomic: Fix unused but set warning in for_each_old_private_obj_in_state
> drm/atomic_helper: Skip over NULL private_obj pointers
> drm/atomic_state_helper: Fix bridge state initialization
> drm/bridge: Implement atomic_print_state
> drm/atomic: Implement drm_atomic_print_old_state
> drm/atomic: Only call atomic_destroy_state on a !NULL pointer
> drm/modeset: Create atomic_reset hook
> drm/atomic: Add atomic_state_readout infrastructure
> drm/crtc: Drop no_vblank bit field
> drm/atomic_helper: Pass nonblock to commit_tail
> drm/atomic_helper: Compare actual and readout states once the commit is done
> drm/atomic_state_helper: Provide comparison macros
> drm/atomic_state_helper: Provide atomic_compare_state helpers
> drm/encoder: Create get_current_crtc hook
> drm/bridge_connector: Implement hw readout for connector
> drm/tidss: Convert to drm logging
> drm/tidss: Remove ftrace-like logs
> drm/tidss: crtc: Change variable name
> drm/tidss: crtc: Implement destroy_state
> drm/tidss: crtc: Cleanup reset implementation
> drm/tidss: dispc: Add format lookup by hw value
> drm/tidss: dispc: Improve mode checking logs
> drm/tidss: dispc: Move dispc_device definition to headers
> drm/tidss: dispc: make accessors accessible to other parts of the driver
> drm/tidss: Implement readout support
> drm/tidss: encoder: implement get_current_crtc
> drm/bridge: sii902x: Implement hw state readout
>
> Documentation/gpu/drm-kms.rst | 6 +
> drivers/gpu/drm/bridge/sii902x.c | 51 ++-
> drivers/gpu/drm/display/drm_bridge_connector.c | 36 +-
> drivers/gpu/drm/drm_atomic.c | 116 +++++-
> drivers/gpu/drm/drm_atomic_helper.c | 501 ++++++++++++++++++++++++-
> drivers/gpu/drm/drm_atomic_state_helper.c | 240 ++++++++++++
> drivers/gpu/drm/drm_bridge.c | 34 ++
> drivers/gpu/drm/drm_crtc_internal.h | 2 +
> drivers/gpu/drm/drm_mode_config.c | 33 +-
> drivers/gpu/drm/tidss/tidss_crtc.c | 251 ++++++++++++-
> drivers/gpu/drm/tidss/tidss_dispc.c | 153 +++-----
> drivers/gpu/drm/tidss/tidss_dispc.h | 37 ++
> drivers/gpu/drm/tidss/tidss_drv.c | 16 -
> drivers/gpu/drm/tidss/tidss_encoder.c | 24 +-
> drivers/gpu/drm/tidss/tidss_kms.c | 7 +-
> drivers/gpu/drm/tidss/tidss_plane.c | 202 +++++++++-
> include/drm/drm_atomic.h | 17 +
> include/drm/drm_atomic_helper.h | 1 +
> include/drm/drm_atomic_state_helper.h | 237 ++++++++++++
> include/drm/drm_bridge.h | 56 +++
> include/drm/drm_connector.h | 40 ++
> include/drm/drm_crtc.h | 35 +-
> include/drm/drm_encoder.h | 13 +
> include/drm/drm_modeset_helper_vtables.h | 13 +
> include/drm/drm_plane.h | 41 ++
> 25 files changed, 1986 insertions(+), 176 deletions(-)
> ---
> base-commit: 82c0fd61f0379fc5729b5256c2218cebcbbd9c50
> change-id: 20250730-drm-state-readout-108f089c1c30
> prerequisite-change-id: 20250729-drm-tidss-field-api-382947a92d44:v3
> prerequisite-patch-id: adcfe2dd21db7ee52a5d5daf49281df831a31061
> prerequisite-patch-id: a228f8ce614e8437096cb0d161d703ccc6eecde7
> prerequisite-patch-id: 5d80c0c4ffea5e3d0827ff2499a7e807e8ca45f6
> prerequisite-patch-id: b71c1edb5702bb3e78e6d417102b1fc405a836e7
> prerequisite-patch-id: b6089d4e312ae3ad782c665460201f9bf431bd45
> prerequisite-patch-id: 8aa19c7a8141cab89b178f16512508e094203c38
> prerequisite-patch-id: be07ce0190b3db712901f70cbe91a4c7aa12ff98
> prerequisite-patch-id: ec483f7ac1304bf475cba904e0e35c89dc89454b
> prerequisite-patch-id: 4454e7c360326ba6b95f5a379d5ebdacfd423113
> prerequisite-patch-id: e5092ded26bd7d1a0b95dd531f98a5e303b509d8
> prerequisite-patch-id: 3f9270642d14f43bbd6c2b29bdafeb6cb4e54050
> prerequisite-patch-id: 61077539c32e10305a944527273e65f83248ff91
> prerequisite-patch-id: d058e3e4743ed4bea5d6b24fcbfa95c6e7058fef
> prerequisite-patch-id: 3ae7ddc94edf54dd8abaf69ee2022f39e8c1eee0
> prerequisite-patch-id: ea8364098af74e18ed336abd58d182696a3ddb8c
> prerequisite-patch-id: b914a195bc019fdd247950d2e31d0bef12ac23c0
> prerequisite-patch-id: b3aeae3f02fdae77a5b596f96a0fd642f0d1c18a
> prerequisite-patch-id: 245536ddf94a4e8658324631477d20ad3b360a50
> prerequisite-patch-id: 7b9f7225a13327ec3d9c5d79cf84bf8f22875402
> prerequisite-patch-id: cbfd50d99462a263525f59e6196aa1225febf88d
> prerequisite-patch-id: 8657a5160de936674cbb5a1f57b690a1da9f78af
> prerequisite-patch-id: 32bc21f02f4db93d317d981a42633750e2b36943
> prerequisite-patch-id: 593bde395fdcc3803b47304b52e217d8d6339f70
> prerequisite-patch-id: 3ceb5b700540e5af13d03411245703d5acd4b5fc
> prerequisite-patch-id: a50cb978d239f2342fde4130376bfa4e6dae1221
> prerequisite-patch-id: b1f4634a9369dfe3f787596897538d6de7a46792
> prerequisite-patch-id: a3bcd3d4cf48502a821dec6ac7bb7e98a875b5c3
> prerequisite-patch-id: 584371623c8ac3cd2f814c111e4ec74a27aa5606
> prerequisite-patch-id: 0588a49c8716e7df05f6925e3a7e1eb48360da38
> prerequisite-patch-id: dbdc4af71b37e5797e05c67a961f7e4647915b62
> prerequisite-patch-id: 63d62599f2cbdacc08495d6255ec69d97af89b94
> prerequisite-patch-id: aa4897b1cf10fb4ce24be7a89e2534ad9c202ee8
> prerequisite-patch-id: ae8bdbce4709c319404908d6adefce1185e72928
> prerequisite-patch-id: a2699195641cea9ab162a47c9881f5eb4ff69c76
> prerequisite-patch-id: 7c7f9762d66ed3947d93a577b9aace53011948e2
> prerequisite-patch-id: 3d209c18afaf3199fa0ac9597f72fea9ec2b9f51
> prerequisite-patch-id: ce0d4f98551253dc1148a4bf3798f365eb872a6d
> prerequisite-patch-id: 0970684d9a2425786eeb689e19688889038cb9b9
> prerequisite-patch-id: c62bbc6ed6f367380674918e227e5b7aa6605797
> prerequisite-patch-id: 3c0cd5eb6b5150e8e9dbb120dfab141bffec5767
> prerequisite-patch-id: ac3d62b1e16625fdf55010e00fca031ce70dcf28
> prerequisite-patch-id: 533ca9357d446865ddca558bdd6dab906a2be80d
> prerequisite-patch-id: 24f6c5c07d10fa03745924d2d6ba22c78c1921d2
> prerequisite-patch-id: e264e20a7d7b56c73d6b59505f32632a23e861c1
> prerequisite-patch-id: 54cefef5c576c5d4a74198ddb15da2842ae0b62a
> prerequisite-patch-id: 89c3d3b7ebaddd96f0b38af9caac6c58d0a028eb
> prerequisite-patch-id: b4a7b747915caa796001d071bcca054e3e9a7943
> prerequisite-patch-id: d81316904b1a8255322d9d6bd7d08a7a66349974
> prerequisite-patch-id: f545e65c0766869a45842a9ffc544dd2f77202b2
> prerequisite-patch-id: 57201c1e0976af67f32d79c57232be4a6e93766d
> prerequisite-patch-id: 05b0d2ef4844d5a88de2ab43fa473dcbe374b6ca
> prerequisite-patch-id: 6e3dee263d0942c9f2fc183c495a3d8ab4e22f2d
> prerequisite-patch-id: 3df6b5daed8709bdb30890479b7aecf17efc8465
> prerequisite-patch-id: 9cad25e9663374c804961cdbd9bbb9f975364940
> prerequisite-patch-id: 35ec7e6a59b2a8640b158601387676db18afe91d
> prerequisite-patch-id: 199e68f508246a4562b70ce86fa8a75406396424
> prerequisite-patch-id: 547072eac7c87c960eca6072539cf1dd4391c672
> prerequisite-patch-id: cc8da25aad5d4e71755289ab77f6a5530c86de47
> prerequisite-patch-id: c7c79eb3ce3cae2f161bbdce0f1f737d1950217b
> prerequisite-patch-id: 529b1873247cb9c13e5630ec1313978bf6bc174f
> prerequisite-patch-id: 1efc149304bbddcb1a83d8f49bd55f213b239eb2
> prerequisite-patch-id: f6a50c4402af2f07c155267d4507530ed0952b15
> prerequisite-patch-id: 4773028acf455db1497434d5e0cfd327e88c2074
> prerequisite-patch-id: 0197b757ab6690e478345c44903aaef8ec597b71
> prerequisite-patch-id: 9aff1b19f3591ae7010d61b15a928e8718bff13e
> prerequisite-patch-id: 2ae174e920748e0d22e2874159233d5253adf78e
> prerequisite-patch-id: b58341e4471e9f45068140c568e7801cd24a9f31
> prerequisite-patch-id: f5362829be6b18a7e175589bc1b0d3fcba983f12
> prerequisite-patch-id: bb0d2ae4e329e62f0795984895e57d1a76d00122
> prerequisite-patch-id: 96dc8fc85618c9531fec1278ed8d2f9cb99e4510
> prerequisite-patch-id: 284f1753b3962cc8df87ec38c2fe424cc88ef6b4
> prerequisite-patch-id: 1d0a21e64fffc7b7f887399cdf7de8894fd915cd
> prerequisite-patch-id: 89a600abdbf0dd8f2b4786c8dbfcde9acda6da40
> prerequisite-patch-id: e514050d2a6456412636f21fa20b48f8e19f44d4
> prerequisite-patch-id: 0dcbc99ea8ca4e49d19144c7d27487f7a9ac1149
> prerequisite-patch-id: 522d35d3c34fc50a80f2e62d8dc2ecb787d721fd
> prerequisite-patch-id: e40f7e0e15ff494031e0abcb838d801d695cf72a
> prerequisite-patch-id: d89177350199d46741926852dcd2424f8896e6f8
> prerequisite-patch-id: 1de07f3df2f70cbb0d1920f88273ce8241bbbd41
> prerequisite-patch-id: b8f6fb42d704d825c300a78e0b24f18fe1f0b08e
> prerequisite-patch-id: 75a476d98c921ea44f3be2eaf6fbeb7da651bd62
> prerequisite-patch-id: 770402f913827934f3571884d4a1c9bc6b57b0f0
> prerequisite-patch-id: 67511093b9dca3e8b4d154fb94221b44e2a9783d
> prerequisite-patch-id: 1ec9d90b671e02804c5a394a2ae87904eae7a34a
> prerequisite-patch-id: 7dcbcf8505c35ea61618059a0098e886d7e4dd90
> prerequisite-patch-id: 2274ec9bc66c3ba9182ef4e9586df522ced5c5cb
> prerequisite-patch-id: 92567d24bcae53bf0acfb2d5467c13fff597bc82
> prerequisite-patch-id: ea735c14630e68cdadda001df0fb06159ae70a39
> prerequisite-patch-id: 4e79fb20e5edd224318d99b966a8d2508694e71a
> prerequisite-patch-id: a0c9bc84d87b7c61c8ea3962192c2459330c47df
> prerequisite-patch-id: 4a6b996fda54948f4ed938f9e92299d4a92fe31c
> prerequisite-patch-id: e6b242038abe456e289f8efb162cb55a604b8302
> prerequisite-patch-id: c747335171f751b175b030c26d839d6e77d6c8f9
> prerequisite-patch-id: 8c26d6bcbd304a195062e75f9e24daf2478f3d27
> prerequisite-patch-id: 7f834e2be30a86d3fac23d24d05a8a80c26de286
> prerequisite-patch-id: 3c2e794b21741065fb892dc2f9a84cc2f57367ff
> prerequisite-patch-id: 5c1fdf603ec886b1b93695dda8cef2c71e4c8532
> prerequisite-patch-id: 3f566ded2710ac4b60befad08c9e983d98438e78
> prerequisite-patch-id: b625db757230f8a2b4531d922c966fba2dbf4012
> prerequisite-patch-id: 389967141292e8bd795eba8f9f168b64074dd719
> prerequisite-patch-id: f4964632abb6276f74156ca5a712899efee7c6f1
> prerequisite-patch-id: 897df40e4e6e61912df824c4dcd48c77fea743b5
> prerequisite-patch-id: 627c33df1156b494f50fba99ca23dc9029424cca
> prerequisite-patch-id: df1b5484685184ae26e1abace780406c9f56f4ca
> prerequisite-patch-id: 83db8ef1d1c4268160055926bcedd590ce1e3b08
> prerequisite-patch-id: ba62fb80f2c755f568af489dc51fad8be4adaf96
> prerequisite-patch-id: 4ee3b1ca8a600c12e71b0510eac12a7f83e6e6d6
> prerequisite-patch-id: fca9b2be12db6b89ffde8daa2746f0855b8822ee
> prerequisite-patch-id: f3fb18fc828cbbf719c115551e8a1e81b4a0b4da
> prerequisite-patch-id: 374987fae6c89baa601ecc5da30f65d642904c3a
> prerequisite-patch-id: ac272b936e2d29586a2d61a8924be39188788224
> prerequisite-patch-id: fc0b12d595ba6e14d1fc18bd48b3affc0d01d142
> prerequisite-patch-id: 9ffe2c54684ec3449063d2aa95ca3c0efa5b27c9
> prerequisite-patch-id: 6726e208e1834321742a2304216f7eb96f04d143
> prerequisite-patch-id: ff9433f8502334ddd46c15075309c408f9d13ae6
> prerequisite-patch-id: 77f37b3121129cd3bf25e4b4223168025598823c
> prerequisite-patch-id: ad53d0c3fad6ff179a22a993d17473393d6cb54e
> prerequisite-patch-id: bd5ebb6508bb840ce4b2b9df73315d83ae4144df
> prerequisite-patch-id: 8d5c81ad736ea277040d04627d4b0687c0c371ac
> prerequisite-patch-id: e5c582d4ae84406c4d4288ad52504c49dc453c08
> prerequisite-patch-id: 037956698683c89fb5325e31a109c373a996cbab
> prerequisite-patch-id: a101b0ed7bd1f1aa4f0306a9e138e49c631017f0
> prerequisite-patch-id: dc946e816c4a6f6768500a42d65d889e20cf80e0
> prerequisite-patch-id: cadbbae69ce7f3e9673254d9328bca3d086b6ca4
> prerequisite-patch-id: 5ddb4ad0fb58788e76e5b698e3b2fc18661de30e
> prerequisite-patch-id: 940c743d5612ef0b9bcf9695ae4ea4a17f59a0d0
> prerequisite-patch-id: 8b2c1d4b21d9761193ef977fd01d3c5eed4c1acf
> prerequisite-patch-id: f39b5c77b80c6ef051e713f2fde0830807a28b17
> prerequisite-patch-id: 2be216bd5f18cd4705c90e6a039394a5d1123130
> prerequisite-patch-id: e2d8cbd4a7c8e60997d8c178756f6dedad8790d3
> prerequisite-patch-id: f8f6a33603e91943f4ae62d14a3f6a8498f59bd1
> prerequisite-patch-id: b6ffa35a64d67bc1fb1142305473a91391f64eef
> prerequisite-patch-id: d398d5e536b4f888cabb2c82e5dcf7deef6f7b42
> prerequisite-patch-id: 618edf9f3fcdef736f0792af5d5979016ccb40de
> prerequisite-patch-id: cee119129008ea080de6e92fc6102bf0da8acd10
> prerequisite-patch-id: 825c1d57786104b84a80e94313ea40988a51c8c0
> prerequisite-patch-id: 5812c27cf20bf17ad10afc4e0525e065ee7c8ecf
> prerequisite-patch-id: 2c0dff4f69e2cff8efc96f8e2c87a1115e45f782
> prerequisite-patch-id: d81eb36c5d70979ade3fc2b30d93992614bbc816
> prerequisite-patch-id: e33794b12c39f0bd8f03ed8153c1a65838910351
> prerequisite-patch-id: 8ebfe339eade48facac4858becb0cebebfaaf412
> prerequisite-patch-id: ffee814f3ef2dd45853d62b5ab74fe6afc5fb641
> prerequisite-patch-id: 4817581f30147aa411bf27c5e629b7e70b31d54f
> prerequisite-patch-id: fe8196ab62daf46cb700e8df9bf672571ab23b1b
> prerequisite-patch-id: 311d1d0f0d86d168b557ab0fd624a5ddc9fc928e
> prerequisite-patch-id: 0f2d15420dfdb4af716a1692dec94f7940704110
> prerequisite-patch-id: ff813f972613a5bbf86bd33081afeee3e9a72674
> prerequisite-patch-id: b18592d584b837c1c592a20a9306d5eccb615af3
> prerequisite-patch-id: f37aadc2be3422f7196b2f1b89283181e307657e
> prerequisite-patch-id: 46f85780de7846e31f122972b2f07dcb3a577bbf
> prerequisite-patch-id: bb03eab832fb940fb340d2f290001d8e31ca86ca
> prerequisite-patch-id: ab1be2690eed3ac169edb9ea5e54c8f3d18d7a1f
> prerequisite-patch-id: 5bf8a90ffeeda480c5be62a18bc8c4b065c471d7
> prerequisite-patch-id: 10dbfab27221bc06b967eb141730cc8951e24732
> prerequisite-patch-id: a455a63367b0ba87b820d8337de05dcc34b19485
> prerequisite-patch-id: 54d425637e3132b2aa29cd1e0b7571469c2636ef
> prerequisite-patch-id: 91686c8ad708461c6d1080cda8dde47bba06f25e
> prerequisite-patch-id: 740fe292f4fdd064669f84c88285c4e35496ba08
> prerequisite-patch-id: 07ce1a7f418450d5aec2cdc2c1e3081c3d257925
> prerequisite-patch-id: 82b0a7dea699216c838d09d3207c88237f06f669
> prerequisite-patch-id: 6cc3e00a6a41f1d8ea0bf2a1000686578bdaa537
> prerequisite-patch-id: 7f6cad45f3e264b3399b348b1434239ea0cb7d74
> prerequisite-patch-id: 394c8d1b9126d7db148b257b5fe1b15cca0b2239
> prerequisite-patch-id: 17687eeabec0d5d6561215e6388110df900bffae
> prerequisite-patch-id: 3cd8e4ba6f213be9728e33d8d13ea73cc119607a
> prerequisite-patch-id: ba3638db6afd756643f3860ebf05441c3ff1f209
> prerequisite-patch-id: 77104afa338a791e5918eef25d23c9743d6230a3
> prerequisite-patch-id: de04e95b802ca7b155992cf5d04901df82f020a3
> prerequisite-patch-id: 558cad95dafcc5c0505a55cc49a13b368fb33ea2
> prerequisite-patch-id: 214f0fa8017ad45c5ffb3ce7a7a6d0c0d92d3423
> prerequisite-patch-id: 471cbae6778e524b16e32142630fe0306f2ad574
> prerequisite-patch-id: 137c176d44ac8826bf148d99a9b09412a3124191
> prerequisite-patch-id: adc8025c305f3b80fd5754d7b8680d4431e5f6fd
> prerequisite-patch-id: a934747bbae4db410bb085f4ce864ed9956b920c
> prerequisite-patch-id: 000f6ea374783053c360031b373db7a04aae88a4
> prerequisite-patch-id: e39704cc21eda7582262ef4a83dcb5db9a3ea49d
> prerequisite-patch-id: a323c980e4ec9a9b94b16c737cf27b92fd177aca
> prerequisite-patch-id: c52bc384e5e511dca533562c4cf166f527e78d71
> prerequisite-patch-id: bfd61249473acf7e0ca407209c70e74ceaf47f2f
> prerequisite-patch-id: 34cff22eea9002bb535ca19bf575bbfdad359d99
> prerequisite-patch-id: c145e9dcabf24c99d4191a15afc5198fd33d251a
> prerequisite-patch-id: 559b47142f89381cbe23313f4819284a61a994ee
> prerequisite-patch-id: ee0b923253d3a477256c618ad6111f844470a2ff
> prerequisite-patch-id: b8d7c14bacdd09dc62672487b1770b8f8de2db12
> prerequisite-patch-id: 6ad124c6d1581175229953ba593222f57c756e95
> prerequisite-patch-id: 8e9b56ef576ae152403703324d65a6287150d05e
> prerequisite-patch-id: f039f7e9dc9f95127a9008687381b135cbefcd42
> prerequisite-patch-id: 7a9e4236e2b7e6f5d15f04f5c5a57cbebf8796a1
> prerequisite-patch-id: 49bbd7a440746f327820450738364a8adfe74055
> prerequisite-patch-id: 527c042d98c53038d7bde2823cad80945aa6de02
> prerequisite-patch-id: 2d396fa6816268227533e9a26f88322e857a5681
> prerequisite-patch-id: b214e0dd58be88a8bcc0a85e73bea57f7355b2dc
> prerequisite-patch-id: ba30ef1bdc4612c7ce2e91eef1546f46e99d5d8a
> prerequisite-patch-id: 463bd50dac0e9065f1ec7798cb2b1abbd22de35e
> prerequisite-patch-id: 29e9559a277d6e182efc7021950a5ab2a06b8192
> prerequisite-patch-id: 72780e7e0ce2959660c81ba24ee6b1870c92df13
> prerequisite-patch-id: cd334e43a5d22fa82f5116f0f156cadfa7fcf6db
> prerequisite-patch-id: 5c69d2c2f819b5b2e64d3f93c44fd89c73591b2d
> prerequisite-patch-id: 242f2a6d2db196fb74e34c57c6b6097e191819c7
> prerequisite-patch-id: 435e414bc5c7197f7ad84147e9e23acf2ae2d783
> prerequisite-patch-id: 654ccef258908f2fae5facbae735799c733688f3
> prerequisite-patch-id: fc1bacf0061b0470947b07e1280fdc0478102a64
> prerequisite-patch-id: b55eea1a4bea85b09633ca486d033fc9186148f0
> prerequisite-patch-id: bb1d504da872b6ac2801546efadd3f50e61c3459
> prerequisite-patch-id: f435928c74b170b9b601a3dabeb94572572ad427
> prerequisite-patch-id: 4c1b771e71612c907f366c92ab3040c0fbeb2271
> prerequisite-patch-id: 572603d43c1aa79927d6b57fd7b930dcaf5b5dc6
> prerequisite-patch-id: 00abfed04b66e8bf2dc7bd4a45807e541d0a931c
> prerequisite-patch-id: 3c559058033d55116dc9d5d4e64ee7c6f0dbad0c
> prerequisite-patch-id: 45bb4559db758cfeb94e01f4c90622cf9b540846
> prerequisite-patch-id: 4e56cda2145b0a89d13c7f0fec6aba5899bb2d55
> prerequisite-patch-id: b31440fffdb0a72d1d1e3cce278d7bb534f6dc10
> prerequisite-patch-id: a3d7b93be8e30600fd865a902de11336667bc895
> prerequisite-patch-id: e2ec60020e7ab92288d115cf2684f48678ce9378
> prerequisite-patch-id: 55d498cc4da6fd365f094642f34217281ae83c05
> prerequisite-patch-id: 5c9ba2602fd0189eea505c2c0b5b837fa98e06e8
> prerequisite-patch-id: 43382aba0d1e536e860a65de4d99544134a80a89
> prerequisite-patch-id: 2f2b8962043cd9dd50e5fdca62ae6df6a91e82f9
> prerequisite-patch-id: 08b8d50e10c5e9a597b65cb9335c766a870bc4e6
> prerequisite-patch-id: 28dc0b0953bb385595f7ce18f495032866867811
> prerequisite-patch-id: 0ff3c31646d9c062682ed6cf1fb79ee306d7e3bf
> prerequisite-patch-id: fc1fd6e5b9c689c1304a3bed2e19bbf27e4fb4f0
> prerequisite-patch-id: 5f02318a85cf3471c6fc55f24e424bbe85728533
> prerequisite-patch-id: 4efcab28e7a44222af258822608cf5c6f917ab06
> prerequisite-patch-id: 3494627da8f7039b4063802608a1f88cb28d66fe
> prerequisite-patch-id: d1eda4d6858b1136669990ee33ecf25147fe57e6
> prerequisite-patch-id: 09e7a79237e223ec238104a8dfc45f10fd1e0232
> prerequisite-patch-id: af8777f069987f98aab3f4e41d935b3f8341ac83
> prerequisite-patch-id: 8d923d44309257c8d57d72695e008f8031d63b7a
> prerequisite-patch-id: de1204567a4d17e1ebd76ced2235318153b77a74
> prerequisite-patch-id: 5d2dd10d326bf3f67508fab923641f93c7739ae7
> prerequisite-patch-id: b798139aeb2bf41a5020bd2eb33c3490edd23c31
> prerequisite-patch-id: 6f708fad66228a5276c97ed0fa128cd78b4e2a18
> prerequisite-patch-id: 51cd5c25c34ca99de39713cf00d2d950cafea75a
> prerequisite-patch-id: 2201b2e3c7ed6ddf15eea855b5090e9d4c76023a
> prerequisite-patch-id: 7f30af4ab734528f6e5da483dbb97dc13e5885e5
> prerequisite-patch-id: 54835df0b25c592b19ee75c8409227a6934af9f5
> prerequisite-patch-id: a260fe429b09abc340730272c280aac94f176cc4
> prerequisite-patch-id: 5d82895af79266297a8c8da06d66b8fc2c9c2ea9
> prerequisite-patch-id: 5e98757b4e379d2bdca7714954d1adbf21162834
> prerequisite-patch-id: 9792f30d86362d9493fcd900e8779c3c9e477989
> prerequisite-patch-id: 5072911f480723ff96d7bcc2b7cc86539a13c03d
> prerequisite-patch-id: bc118b8379cb2437d22c39b5fcf0d305b0b759d5
> prerequisite-patch-id: 2fe2d80bd3075ca8f2531233f73d94be0223b8b2
> prerequisite-patch-id: 5b08008bed2ce50eb89e2c9880e9489f65399b25
> prerequisite-patch-id: 108f2d88007e0403dc6e06ae4550e96581dc1d6c
> prerequisite-patch-id: 53a3c0bdae4e298bb0040eddadcd4da1eafa94da
> prerequisite-patch-id: af94e2a0ee7f111c46b2943c22fa965fa71ecc40
> prerequisite-patch-id: 425bbfca67e863d55bda6fb02cd5f7445cc35fe4
> prerequisite-patch-id: 20910d42b5b95ffac9a017653eb51d3d0df9a874
> prerequisite-patch-id: 0e96105ac4ef530ea88fc3d2316d6156f0d6b245
> prerequisite-patch-id: 66827074cafbcc5d8380a30e872b843e40705745
> prerequisite-patch-id: f3fce7c330ed88ab1ffa9642e22b8f271a3928f2
> prerequisite-patch-id: 683f0caf48c56dd5bf2372078f944e72b053077c
> prerequisite-patch-id: bd1ec88bfe21a30686e19c6a8019593fc8540bff
> prerequisite-patch-id: cc397c9809e356c105c6b37d06e92429f7aaca70
> prerequisite-patch-id: 001b6f56c389bcd5a159c6b088f5798fb098a1f9
> prerequisite-patch-id: 7faa36e0ce4f6b060ee42567f87f05618a7398ef
> prerequisite-patch-id: e4ffbe63ae1f52599f0765f0a7a0167fb7d1e202
> prerequisite-patch-id: b5dfc201bc2b9b6bd9249c04da82376ad904b864
> prerequisite-patch-id: e743994ae02334f59a0f988aafa567079d9defea
> prerequisite-patch-id: e573f2f1f5102fb7960762edf8df7b19795495be
> prerequisite-patch-id: 4661a8478d7d9fd245157b489b0d8d186778535e
> prerequisite-patch-id: 28978e3bfd6eade670de34dc2da871c677c8e58e
> prerequisite-patch-id: 057a5e71bdab2e8ef371884a64110fda8f4fbeef
> prerequisite-patch-id: 0a572a96817bfe9d600cbfba44c8078cf178ab6f
> prerequisite-patch-id: 8e56b042797fcad0b4bf0052656a96d7938ccf76
> prerequisite-patch-id: ef9082d2a1fd158499904b06b242f922523990a3
> prerequisite-patch-id: 474b761dffca426a0b0ae59cec20efb826e4f924
> prerequisite-patch-id: efe1d97d4d16ba75c60de772a431d5b3dbb726d4
> prerequisite-patch-id: f9c993800bc1049a236215585e02a3c9f458fef7
> prerequisite-patch-id: fca869306474f329afb4ee4b0bc3537dc5030b49
> prerequisite-patch-id: f2b0304b2952536da248081638abda48368121a9
> prerequisite-patch-id: f047c468c6efcd20c7f674df6a1a3d613c6be6eb
> prerequisite-patch-id: 1471cebeae0c86d60c68204e73bf323f4c38fc80
> prerequisite-patch-id: 9e343205ce6b7bc68ecf2a8a71edbd61c82389d8
> prerequisite-patch-id: e2cf8b02bdac0ccf8fceb41df88ef35496dda9be
> prerequisite-patch-id: 802a209802649844e4190443d81b53eca9662f72
> prerequisite-patch-id: 4e46ca97f13fa5876abdca36ded8d5a5b20683d7
> prerequisite-patch-id: 55f99c4968eb94f810f1d6c86125f7569c2b2a5a
> prerequisite-patch-id: ef389cb84d70794f3d8ba97f71f23031f026c53f
> prerequisite-patch-id: a7064a315c00f2841bf624f0bfeff4e99d74443f
> prerequisite-patch-id: 1d95c64cb0bd7bc8555333846c93a8fadf9adc50
> prerequisite-patch-id: 0da2c7d3f53367a2e3733ba52d41b51fb1c24267
> prerequisite-patch-id: b5a1297f9748c20f4eb15b3f9f0700f976071c87
> prerequisite-patch-id: 4bf52389a054865ca26f60ff9a9481e62a757992
> prerequisite-patch-id: 1c4c0135b2ab77c8452b2273099edf6a6f13a6bb
> prerequisite-patch-id: 80e9a5012646984149bf6195a58efbd2e9376bd4
> prerequisite-patch-id: c56bfeb644743a79eb3d3810ec6948610d565d00
> prerequisite-patch-id: 3d8379f40ea180f5e620cac49f757965b1dd18d2
> prerequisite-patch-id: 3393a168b01f2ca273055bd3caeeda4b7baf5083
> prerequisite-patch-id: e35ff5d4629fffceae1fc16b5664785aec769c3c
> prerequisite-patch-id: 1911db34222c06fd86a81c9e6b05e5bcf0867b52
> prerequisite-patch-id: 55674ff89ed77a9b1aceadb0ad1dd50b8b5caa44
> prerequisite-patch-id: 7a12328229e6ed94819c9a944d7ea00592627157
> prerequisite-patch-id: a0bc220dbf370b6743ac1f21d3fc98b26e780f6a
> prerequisite-patch-id: 512fafe2d142cb4d4b8000f678a95b4bbc6a2c5f
> prerequisite-patch-id: f9e6363e6fd0e0fd308fd2047bab4cfd5c430539
> prerequisite-patch-id: cc9e2be6339eab16b2c7b25ea332cca8f5a9d434
> prerequisite-patch-id: 83ce76966c854c3fd0d8f24845d73e3abea425e8
> prerequisite-patch-id: ffb428416241853c5e502706e49dc63948242509
> prerequisite-patch-id: 47c2efa079795ae45855e62cdd3044d35e0bc842
> prerequisite-patch-id: 98fe6896bc0eececf353fb8c8868652dac0c738b
> prerequisite-patch-id: 634a865b49c57c1ee33762666e98cb240f091beb
> prerequisite-patch-id: 1f21a7b91f204b250950795d5e48f2efdf60fe1c
> prerequisite-patch-id: 136680a0511ae87c3500869c60d4b112044c6e51
> prerequisite-patch-id: 9cb5946ebef3c707e4f9c2ada4e4d703a21d7dd1
> prerequisite-patch-id: d028d7bafced5b55216be788b4a0052a09c77693
> prerequisite-patch-id: 0099b49566295f0e768d4188c59ecffe9c13b1e5
> prerequisite-patch-id: 12fe26ed8bf319c187553deab9a48696b332dedb
> prerequisite-patch-id: 262238f2703afaeb46a786880416f8903c4d52cf
> prerequisite-patch-id: c2bf443e33f3e44262e8a5f9a90d165e0847efaf
> prerequisite-patch-id: 00295d8fe70e9b9d34c4a7011ff8074755090f2e
> prerequisite-patch-id: 4d5d8e4ef78205bb6026ccd5fb9607a6a9b62599
> prerequisite-patch-id: c5324306ff4dfc3b1f92589817f308d05f49957f
> prerequisite-patch-id: cc50d93efb7b37fdca603e1b8e9e2ef08386d830
> prerequisite-patch-id: 87757b952f3c5411747c343b0da2b297f734b0d8
> prerequisite-patch-id: c447e1965a0415681cddcc0bca87e5f68c2f46b4
> prerequisite-patch-id: b49fef42912c257d880736a69116731478584daa
> prerequisite-patch-id: b49d28826b7b8a0fc05070eba3b4c060aae41f5c
> prerequisite-patch-id: 6448c5250f57ef2c4bc8dc202ecb5ef8f58a91c2
> prerequisite-patch-id: aa2baf3506de0c1f30318a5042082a7116b241d9
> prerequisite-patch-id: e1e84b0fea42479bce4231407e6906b076146df0
> prerequisite-patch-id: 922689d7dba1ce924d9b73cd737f04551a5801c3
> prerequisite-patch-id: 3b9f07da8904fbab2efe15d7bb0b7087128882cc
> prerequisite-patch-id: f8f5cbc6c0c5974bcad3165ae5bfa2dcffea26fc
> prerequisite-patch-id: 3a40a149809077d0827698875b78952916cb194a
> prerequisite-patch-id: 38b6af6a69086caeae65d475b13bea033f0a50ac
> prerequisite-patch-id: 8435f9e0f567b5fb6af00586e79b814acbe126ab
> prerequisite-patch-id: 5ce93c118e1ee0992aa9a5bb7c3351ca30cf1186
> prerequisite-patch-id: 0d6ab862a4f793ca7cbd04ba6fcd34c57a174607
> prerequisite-patch-id: 08c654f87fab3e453892a483af844935684163be
> prerequisite-patch-id: fae751671cd00ebbfa147ce36600d2c6348cf1d9
> prerequisite-patch-id: 723a4be72e9bf2ccf9a3aab5500e4c91d16af6f6
> prerequisite-patch-id: fcc16e7bd6c15c5add36941100733a8c9e517159
> prerequisite-patch-id: 0dcd82ae3f8623074a4079a67ef8df37764fc5bf
> prerequisite-patch-id: b79856d3b388b199652979d2ec2e0f604a543205
> prerequisite-patch-id: 1a5b5bafa4e2b8460464598ff01aecaded867c9b
> prerequisite-patch-id: a51445466ccbd4dbd0ea9f336c48fbba9d1ba087
> prerequisite-patch-id: 92d4582b60c9daddd42e6fb19bd63b07e978a938
> prerequisite-patch-id: 747617abf2aa8b3786f78a9ffc978a27221eee52
> prerequisite-patch-id: f93cbe202710a68e86857a7f8bcfdb855da79c2d
> prerequisite-patch-id: ef54eda33d7b1a9df1e5d61eecff8000bfe29080
> prerequisite-patch-id: a1ca1305f29b406fe87c4a5b878ea60c17b5f13a
> prerequisite-patch-id: ccce295605ec2822e0fe2894c412cf8b3a19bac1
> prerequisite-patch-id: 249fb7caaf337127908c9d7d285b12f64c520119
> prerequisite-patch-id: 2eb06dcacccda43bd316f3d77f6c6273fbaab65c
> prerequisite-patch-id: 73b2e085b1b487ddc55f2c66385d635e7390ccb5
> prerequisite-patch-id: c9620a8a8685dfa0a260d2c0a1df8f1dcb68118e
> prerequisite-patch-id: 47b23fd780f48243dd1647517af8d75bc2b8f205
> prerequisite-patch-id: 3a7965908cf4fede7be37f1f0ac132b002a320eb
> prerequisite-patch-id: 9f7748c968cb7afed67eae36b838374f0fb56623
> prerequisite-patch-id: 92013f322f7256eaeb76662cd31d8752d51cbc2e
> prerequisite-patch-id: 4c78f078056385d5c688543dc7922fb2f3b55061
> prerequisite-patch-id: 0100c0820f9ca5eda059358c527590ec3bf755ab
> prerequisite-patch-id: ca92defced31ce7aa9035a5103e5c2ad3e02e4ef
> prerequisite-patch-id: 37bd328dca896d89c5d1b22a649e4eae684da552
> prerequisite-patch-id: 20221a83e93afded7e6f6d24f749a3326f6aa60a
> prerequisite-patch-id: 52beeb36f36b77fdfae17d93943949e5598f6eb7
> prerequisite-patch-id: a15221efc6955c12cedef79a0a0fd128f72e8dbc
> prerequisite-patch-id: 0700c5fb0a38322af7bb4c00c709cfed2b8a3617
> prerequisite-patch-id: cd0f56a392080be768cc001c2da33417f456e86d
> prerequisite-patch-id: 530281bb5d5fa5566acc7873510dd1aff57f8a1b
> prerequisite-patch-id: 042cfcf9f4a98e98ee4dacbb333cfb8b3eebaef4
> prerequisite-patch-id: 998155a6ece5036d1a928d8d51120d01af6d6fa2
> prerequisite-patch-id: 0737e38612d7724b21c13f00f1b993a32be9849c
> prerequisite-patch-id: 3d329443d7cb1f063ed6e547b4b6c5107b592c48
> prerequisite-patch-id: 67ee52d57d890e6ea9ff622222d8e8561c6cd8f0
> prerequisite-patch-id: baeadd7858caf4deee71c9ead107949280d7a777
> prerequisite-patch-id: 09cef5d1d6068ce318de5107a6d1e5e5728f27aa
> prerequisite-patch-id: 6571adf5e879dda3e48a0fcdec83b6f779641327
> prerequisite-patch-id: 6d3032be4619acbfeed0082fec7eab2d727ff4a1
> prerequisite-patch-id: 1f347834a0896c25188a6c1a552c8c1fba1d131e
> prerequisite-patch-id: 675206d6655dd0bb2617d6dcd0b54cf160232bdb
> prerequisite-patch-id: 4fae6d9c0a061d79c8738336274e259c4840730c
> prerequisite-patch-id: db70111855c887f4bf1749f073ff30b0273aee5b
> prerequisite-patch-id: 0e9a747b77830a57ba0f12ee595683ffa6f4f18b
> prerequisite-patch-id: fe24b1cc60e77bd7116cdf872f13601082c8277d
> prerequisite-patch-id: 2f4ea9b0046ca49d3684b6b9b501d98721e70581
> prerequisite-patch-id: d0506df6444c3b969bf444c83388c8ecd81895d0
> prerequisite-patch-id: 8ddf7d00db265158cde3b85d3f90dae3a85cd49a
> prerequisite-patch-id: 82c740d2e8d766dbd947e390ac2682589c409400
> prerequisite-patch-id: 23cc9b3719da888b14abea634af3c08d565636f7
> prerequisite-patch-id: 38aa7b80b39293d0e45ba6f366b27f46938a96a5
> prerequisite-patch-id: bccf45fd8af5897fa5d90fd14cd47a07381b1bc5
> prerequisite-patch-id: b0e6c57ba6e9760565f28baf407346a575214a64
> prerequisite-patch-id: 4fd5008fb9ed18f350d15c3ad8ee0edbb1630762
> prerequisite-patch-id: b007e986474c31c009ffed433a8508b554cbc2eb
> prerequisite-patch-id: 73979d75b634725e8727fa7c45e5bc36e2b2f6c4
> prerequisite-patch-id: c5b3dfb22714aae8e353fa6083f98633008b4bbd
> prerequisite-patch-id: 0aaf2673e63da487b8ee32bcd068e6dd6aa4ba38
> prerequisite-patch-id: 41a1c7f79f6ad00d354fb68443d8723b6d2262dd
> prerequisite-patch-id: caa769bcaa9c23eacc143c7bbba2e30a97721ec7
> prerequisite-patch-id: 473526ba117087270d06dd194e16451d24ec9992
> prerequisite-patch-id: 6f293c7d3b24675662317ea3ec13350e75665c16
> prerequisite-patch-id: 0829980d3906d021fe677796467ab8c3abcf56d4
> prerequisite-patch-id: d22663045c6dfe98141838a005c12b5b7c7b45e8
> prerequisite-patch-id: 36b244e155904f71887ea3d7da9b675183e5be34
> prerequisite-patch-id: eba235cdfa4bc2e7797d9778a0f34867b8a9e054
> prerequisite-patch-id: 6a86607acd4c3e7cbe9cddb436fa37dfbeffd443
> prerequisite-patch-id: b3b318070e9934617b367556168408bc5335d7df
> prerequisite-patch-id: e26b47a3efffa4872499a55ed8bcb46900759086
> prerequisite-patch-id: 0a5ce5feaab35215dcc73a6abeaaf286d7c1c149
> prerequisite-patch-id: ec77271f228e956565ca4ebfd574a53f6c1a8e7a
> prerequisite-patch-id: b4320b3b69ba254ae93739cfb1d8c4b05ef840c7
> prerequisite-patch-id: 3f31f50d29272ee2a516f2fab1396da9e0552ea7
> prerequisite-patch-id: 322f4d4c8f54a9985992de2a65052410a7458980
> prerequisite-patch-id: 93815ee19a56371c9853219bd8dd95031b5fb9b7
> prerequisite-patch-id: 5da985bf58a730ce68bd621a5923f9ed33db965c
> prerequisite-patch-id: 17b9c4798792df365696a97a4319e1053d6689ad
> prerequisite-patch-id: d706b8d9ecfc9d78b772cfdec737efaa4cbacd7c
> prerequisite-patch-id: 7bd664aec3278a5bc199db89d29955a723409b04
> prerequisite-patch-id: 026153345475c8e9eca44671565a38fc39fee7a9
> prerequisite-patch-id: 79212f8439e16c7dabfd0c20d032abc63df3db66
> prerequisite-patch-id: e66f89443a57bbac9774d369b5a55d7d321859ee
> prerequisite-patch-id: 0fc449f8c345e59fcc6d38c8238ad32a9eb579f3
> prerequisite-patch-id: 74f08f2626089529245caab5a2ef1789d7e3555a
> prerequisite-patch-id: 596d9fecb34f93f3fc8d31a46aae8e0bc9c3b589
> prerequisite-patch-id: b7c0c3c9a3c289d74eadc10bb7df601921cbc769
> prerequisite-patch-id: fcb0ce9d7cbfe09bdec7ab5aab540356faf59ab4
> prerequisite-patch-id: 264fe194b2c36c745965f7dfabf662ff71ee6002
> prerequisite-patch-id: 67bf57cd7707431ecd0dcf1a0f902067b1063950
> prerequisite-patch-id: 3fe4cb1c407eb89bcbe3c65e0404b45a99120c3d
> prerequisite-patch-id: d453f72dcdcf2487ea90f6036cc1b5fbe5835237
> prerequisite-patch-id: 0a8181bd5b2c9f2d0cf6e1f1129cef2cff8a9a1f
> prerequisite-patch-id: 71cf12dd97c890f532a2086a9dc862e29f5a6591
> prerequisite-patch-id: c1f02c3bf2321e4f89a874cbe3d1e293a9fb43ee
> prerequisite-patch-id: 13cb9764a42ae5068abba369e82e358cfd6a3f69
> prerequisite-patch-id: c26357057f89eefd6ca76e00c2bfd01f678de940
> prerequisite-patch-id: 24d03f40ea704c666abc4a0f3ce53de650ae0502
> prerequisite-patch-id: f4fef8746e7f9069eeaa1a9450a8f344ffca50bd
> prerequisite-patch-id: a57dc5d45bb0c6bb2e6e9991878b5ae0f4a46d60
> prerequisite-patch-id: 3d8c5a424ac0f550406120d9df777bd05a0f90ba
> prerequisite-patch-id: b7a343906ee7ac068f115e1fc70a60f908fe0f72
> prerequisite-patch-id: 34b9378f4f98de4b95a9d9a269f2b56ced57735d
> prerequisite-patch-id: 2b16591f85a4667e63260c339f13d757ac4b1953
> prerequisite-patch-id: 230603d5d0e537bf019840ec4597de44fa1aeb85
> prerequisite-patch-id: 6f5c055c039bf96d425fdda0bb2ae710b0812f85
> prerequisite-patch-id: fa8d845127ba364c283a0b8831fbd31fdddb7406
> prerequisite-patch-id: 4aca839c10d18d9d141696fab9036b6e875ec171
> prerequisite-patch-id: 703b4d9df6e2d0abf1e076a669e7c5c8ef64b26e
> prerequisite-patch-id: 84b90307666c51f722bd383964cee0943b706019
> prerequisite-patch-id: 8572d000a6f2751e3c1e8cf6161749ee4f2182e0
> prerequisite-patch-id: 15ccadd64d8fd1eba165248b2610c730b4e9a251
> prerequisite-patch-id: e2798551294549430c91dd2ca7e4bde69fb42011
> prerequisite-patch-id: b0641d22294d52e473243b89ff0cd79ccb8d4567
> prerequisite-patch-id: abb7c60a1480281b48f36ce94c3e93ff5db8719c
> prerequisite-patch-id: 44964d63374a7786e87db2cb1cf7f10393b73ef6
> prerequisite-patch-id: 8ac70a3ac81632f158b478fb58df262f578b615f
> prerequisite-patch-id: b4802fb9b22430966756738813c29d4624118f89
> prerequisite-patch-id: 91d45fbdf22918ae22b821acb4690d2e3bfb08ec
> prerequisite-patch-id: 707563727acde2910a0aca5ca22c5b00d0169059
> prerequisite-patch-id: a6bafdbbc5279b07c87a10bf94fe3afa4ab2b9c1
> prerequisite-patch-id: 555246657d30c06beacdd1a58de3f16fd58a3bea
> prerequisite-patch-id: f0cdac50580faf136f5268abc19b76a51e29936e
> prerequisite-patch-id: 4441405c190d18bced781431c54279794df0f7c4
> prerequisite-patch-id: 5f1490cfceceaa577fb65a808d3bee4b018ca6e2
> prerequisite-patch-id: fad8bc0d0197c823ef6667fd8809c0aebb605d4a
> prerequisite-patch-id: cc4f8f7d81b7209c990737aa734d2ce08edc584e
> prerequisite-patch-id: 246b2ef7612840b7709a1da400ffd9df6d36a710
> prerequisite-patch-id: bab66e1123b49b9079b0fb892a63d2326b69c574
> prerequisite-patch-id: 00d12ffdf151f90aeec4c00a15b33174f2b5f478
> prerequisite-patch-id: cc54c2483a24c996dca80bebe5047e9c101fc0d3
> prerequisite-patch-id: 16ed37a9feb761abf66d543be4f05dba2c794bf8
> prerequisite-patch-id: 5409cc32d333d235d24fafaacda9d15de2ad17e0
> prerequisite-patch-id: cbf8a6d1163b0bc8753bf5e9d63d43ed46af3d2c
> prerequisite-patch-id: 67f086f94d9d519cf9f1b28c0534f661452e31cc
> prerequisite-patch-id: 348dcd79bb6e33538d449af0092af41049702919
> prerequisite-patch-id: 8666a2598d27a2cfaf868227f872f352a915a3e1
> prerequisite-patch-id: c349356dab27c7b26a6f223b2a5c348ae7b78811
> prerequisite-patch-id: ea78efd6945f2e7f12f2ad6fcadf7036d5002863
> prerequisite-patch-id: 74390fa5149a759b6585709d891246e0b3e9a0a0
> prerequisite-patch-id: 3fa350c4c89e4e950f3d0a08cb1ea1ec055aaeba
> prerequisite-patch-id: cde4aa22c8c0731d15f68525fe1d273afcb77662
> prerequisite-patch-id: b78498edd9840d678ec4793ce708297e23fdee52
> prerequisite-patch-id: 67421a6289caaf5020ff7251e846b93888f5a843
> prerequisite-patch-id: faab60a07c42066ef36320ebe79a8627c7fd246f
> prerequisite-patch-id: f197253221979b1d01245a8999dcedf27dd72fd3
> prerequisite-patch-id: 8aa2a65f715163c4e5a59692aec1302e2adc7727
> prerequisite-patch-id: 1409781554e60d0f9d40d97b985e0dc7064d4184
> prerequisite-patch-id: 4833ec6e81c32d686808de5fef7f58d3800ef981
> prerequisite-patch-id: 530377b4fe87148f2ff2a8fe3c8dd0b6449c20e4
> prerequisite-patch-id: 2a4a7b908952cf096ff19f805b60b36e18096391
> prerequisite-patch-id: d23a53eab71727aca4614c5d8aa7edd7506b447e
> prerequisite-patch-id: 1de1698fe0356d98ec6b46175aa4470e16b21f29
> prerequisite-patch-id: 6f2bd111a999b4b0756abe8c3ac5a397de3173fc
> prerequisite-patch-id: fd9740694cf63a2f4646a03f274761fa774c3ce0
> prerequisite-patch-id: a67df18b5b29574330bcbca0043f2f40ff108913
> prerequisite-patch-id: c6e39e8733c44a8b616222e0551c25b2b065380b
> prerequisite-patch-id: f01f8af0a9f397d59a49b72cbf465196afcdca08
> prerequisite-patch-id: ab7a7b0d1e185b23143a46cf07c806341ccbd8fa
> prerequisite-patch-id: ddc2c4d5887878ca29bbf83c9f6c76d98f2fefe1
> prerequisite-patch-id: 53602caca725a2a2fe4e1d963ed2a28436aa5e23
> prerequisite-patch-id: 2f77a73d5e3a68e339866d1d8fac58a5856c7f39
> prerequisite-patch-id: de2de10a53fbea689591b240525fc3d1ddc9b98b
> prerequisite-patch-id: d8b40d146636e48a60c53bac869d3c4259f17ce6
> prerequisite-patch-id: c5ec011481d27c1a8ab8ffc3b9f26fc5536fc5e6
> prerequisite-patch-id: d42090eb4ca75b3dee2ef118807112014d2a5d43
> prerequisite-patch-id: 18daf013a8cbd2d26b89bd20348933fc9145572d
> prerequisite-patch-id: 5626dd3842d1629c0b4a887c50ad5626f16466ee
> prerequisite-patch-id: 443bde5338afbc7e315e97314e27d9958c49fad6
> prerequisite-patch-id: c83dc54f0e332a3906f6644161164b5274e4dcb6
> prerequisite-patch-id: 3a24936db5d4f42566cc2aa827febe7d04b7d486
> prerequisite-patch-id: 26c99a17cb3018a8ca946360a2ed15a7d8b8175f
> prerequisite-patch-id: 95212b0bec9f23d6626d0db7ef34586dd9b24811
> prerequisite-patch-id: 8dd66c23394412d1d6a47fd5fbb784ecdb6bca94
> prerequisite-patch-id: c6a444677c9c71fe0fa932af4827485bdbf1cf41
> prerequisite-patch-id: a29d09a2a85c6ff3f8f30ecf321cdfb2650a626e
> prerequisite-patch-id: 79b2801b06d37456eeb6aed5df1d9b7b5e52f6ec
> prerequisite-patch-id: 04589f185d1822e04f58c46ef918b33ba51961f9
> prerequisite-patch-id: f53ce2e68cd45292b75319105103bf5c96221fc6
> prerequisite-patch-id: 4729cbbc717a54ac908ee6006f09693efbad76de
> prerequisite-patch-id: 5a4d7bf07fc65aa728cb5622497a7611e6dde17a
> prerequisite-patch-id: 4719e925e7aa02aff3c108179a3cbe9f4345f34d
> prerequisite-patch-id: 0ca0638fe75a042f09d671406e5b4a074e79d5d8
> prerequisite-patch-id: 78987ff3df32968404cc456a3482eaa955039d3c
> prerequisite-patch-id: 0304dc7dda55bd2d3d7d0cfeeadf8a7093910ec2
> prerequisite-patch-id: cb3b1df794b21cdc4a4e6141331e9491bf707913
> prerequisite-patch-id: ba2c1af8edfb4883707e7047ad874f56f10c3b5a
> prerequisite-patch-id: 453ef1d8276ad9bec805f807cf194be33aaa5243
> prerequisite-patch-id: 14d626c3dbb5bfce5d96fde261c67efc3ef47809
> prerequisite-patch-id: 9e0fe13834cbb03c179b87b6b2e5ee94bf7f32bd
> prerequisite-patch-id: bdbf8883ddad6f8cb9ea5401cc1a86682344f05b
> prerequisite-patch-id: 97538be113d34014e806920dc51e3d67d0d55e72
> prerequisite-patch-id: f9be9a3f4f5862157a1fbdae5fe44e12bcea10e0
> prerequisite-patch-id: 110d121917f629521a62903aed2d1062537f14b0
> prerequisite-patch-id: da95e95d7b79c68ad42622ec7fbe0242704e6f31
> prerequisite-patch-id: 9814623fff84d751e18d7035036436e3aee4798d
> prerequisite-patch-id: 1f2428118933ae246206e9267e13c2984f7b25f2
> prerequisite-patch-id: 15ec31b6f8dadafd4832a75c4f5f0885ba947288
> prerequisite-patch-id: 6627634cb62e6c472ef9505dac23b177ba79d93b
> prerequisite-patch-id: 51edb70b44378bb00fa796cc13262a2c7516394e
> prerequisite-patch-id: 5d123f5b5d25787cd956f768b3f2c529f8551ed8
> prerequisite-patch-id: b9713c994e97377c828f6c11492fbf39528a88be
> prerequisite-patch-id: 7cd39822c0894f6833526d1d739c3ae11d5e464e
> prerequisite-patch-id: 4cacc6ae2080429644ce6aab6fe6bb1d6abc0449
> prerequisite-patch-id: ac72b27c6c317fc9431b2a03209a6585d223be40
> prerequisite-patch-id: 6b60ca7ab9863d825ad201ecd095f23820830826
> prerequisite-patch-id: 1e933926e54a436b02e767cc255d6256670b4cd0
> prerequisite-patch-id: d7cd0c5c8956192b06da5999d3e1e82eaaa59c89
> prerequisite-patch-id: 1e261b3d4d77a4f4d3afc9b0c47566f55dde051b
> prerequisite-patch-id: 5afc376e9814b105b10ab34c87d2625523603fa4
> prerequisite-patch-id: 6d9d8842b760749835b8be885f7f5203e12e1b6f
> prerequisite-patch-id: 541f3b03a5850a1a9813bf0c96f852a3c2f2c0a4
> prerequisite-patch-id: d584d82c902d9786934e1f266db10b21df632242
> prerequisite-patch-id: 523c508511e8b4e1ddca4bcbfcd47db188dff588
> prerequisite-patch-id: 1adbd2e7af3179a1511402ede6e6905b180fbf03
> prerequisite-patch-id: 9bd9c4911cc7d4e512e191070219152b3e3ffb15
> prerequisite-patch-id: 10ea3119b2eabf80303abd69697ce930b1cd21dd
> prerequisite-patch-id: 76374d1db084dd5febae3a9cb46180e206f6b706
> prerequisite-patch-id: d7d107a84ad3152eb0a1794610c04cd1983d3969
> prerequisite-patch-id: c32a442331ccaffa517d8645841478a3e3b55a4e
> prerequisite-patch-id: 9c0302fcc73074b9cf9fccf7b6c323b4b3842a9d
> prerequisite-patch-id: 780a41da228dd24d48b79954c6816becf967c211
> prerequisite-patch-id: 11b9d2874d54471a9c921aa96c699f1f54d16003
> prerequisite-patch-id: 24b08b536041b63352bb09e21cb5d5cccb64ef32
> prerequisite-patch-id: 53d5989e5f27088215a4c7c579970202769d2e6d
> prerequisite-patch-id: 8b9fa0758dec431945696c19c949d789032fbf47
> prerequisite-patch-id: 307c57a598b4c1b8b6bf4d9dd27f8e61690c131a
> prerequisite-patch-id: 96b1995196a64d8d28f18ef44615bebfdbfef40a
> prerequisite-patch-id: d0330f3c02c7e932834094d2c017af5801f3cf39
> prerequisite-patch-id: aed0c6885998fb981f6e342de92cde58e0d787d6
> prerequisite-patch-id: 4b7625b70a0b4b29f159ef97bb1301b7f3fc2115
> prerequisite-patch-id: ec82d9da01727077333d0d1ea06f1f014cbbc8ef
> prerequisite-patch-id: afeddaa550c625464488697e13697713bcaabacb
> prerequisite-patch-id: c2e2bb9b82e0eacb1383ca8fecc973f6c3543e13
> prerequisite-patch-id: 438826d6933cb7df78b6f34860d9ab98cc35b1cd
> prerequisite-patch-id: cf71da7c4065b1453d9a30df7457f69f58026870
> prerequisite-patch-id: 05bc37baf628d3cc21acf892492aaff7ace51207
> prerequisite-patch-id: d02a56992a0618777de2e139e8cb90766cee1ce8
> prerequisite-patch-id: 321ad48f0cb909de0c9f1b866b9b0cd4db933c9a
> prerequisite-patch-id: 97cf1c926ff5c45ab3ca299dde4cb33e7b0db5cf
> prerequisite-patch-id: fdacdf0acd565a910b012d0e83bd98dc75cfe7a5
> prerequisite-patch-id: a9d02bfd4caed7532d846ede41d359192f38bdc8
> prerequisite-patch-id: ecdcb3b66e47fdc752d5d48208ddb7ff375791cd
> prerequisite-patch-id: f680ada43bdad09ecaf32d2657c2750db55a2e4b
> prerequisite-patch-id: 523c508511e8b4e1ddca4bcbfcd47db188dff588
> prerequisite-patch-id: 1adbd2e7af3179a1511402ede6e6905b180fbf03
> prerequisite-patch-id: 9bd9c4911cc7d4e512e191070219152b3e3ffb15
> prerequisite-patch-id: b2b77f44d685188e696d26f5056059b5bdfa63ac
> prerequisite-patch-id: b41085482a1a67f0ef7d7e52f1a9c9f32d374c95
> prerequisite-patch-id: 4adaa1407d6403ea5c7e7604ad5c9dde76836e1c
> prerequisite-patch-id: 13b5c7fde5e221b3f52c79d0a04e6e60a8b59239
> prerequisite-patch-id: bcb3e1fcfdb394ca6217757f6de094a743dda95f
> prerequisite-patch-id: 588bfe0bae61f626e7d361f4f6a22fc70d2fd57a
> prerequisite-patch-id: 34cdbc1b9e3ca041357a7b3ba652b7fa90835917
> prerequisite-patch-id: 813583afe2f42c131390735e6c9bebd97066d55e
> prerequisite-patch-id: 44624e397a0deef516dbe7c0ca79a13bc1c3b491
> prerequisite-patch-id: a737a7db82a2690f8ad3dee761ebbc6c6fc4ecf2
> prerequisite-patch-id: 3458312f2e6dbb124123c9ba5729d43b34ff6c93
> prerequisite-patch-id: 418e9932e5431e326756e98a0789fc0c2e98d464
> prerequisite-patch-id: 1681af511012503252c5439e1893c821af6829fa
> prerequisite-patch-id: 9ed721239f7370566db458f64cdbb1f2cb01d2f4
> prerequisite-patch-id: d8e8b8b6928670ca45ce93c33d0a20fca8502ffa
> prerequisite-patch-id: 039563120957afc00f35c0c7b960a42d2c50fb5c
> prerequisite-patch-id: 338ea096d48ac7fac0f746551374abd70096c2a5
> prerequisite-patch-id: 656e340f4921d87fefb3743a091346581ae80f6f
> prerequisite-patch-id: a4e592e370dd3da54ae5ab25fc4bfa91f40b2e45
> prerequisite-patch-id: edcaab31525c1fd4b175604264d2639fb923b971
> prerequisite-patch-id: 080cb96d452b70489e977b257fa9c2ce5692d578
> prerequisite-patch-id: 50681ad1217d0baeff5818fd579d6e424189df20
> prerequisite-patch-id: 492f91ff5575c94f72271d7d2d675b78fa117cb7
> prerequisite-patch-id: 7e4f686cbb1eae0ac6c3f0bbc6aa649b689c87e0
> prerequisite-patch-id: 0816b19c13ef3b351a86858250e869a0bace9e42
> prerequisite-patch-id: a2fa766f6dca60b53c25fe73f28949fe3eb5ac26
> prerequisite-patch-id: ad1ab31af52811f7c9301dbe43d06996b7630b90
> prerequisite-patch-id: ab2a7b4e9a24361edb19e6ed4ff983091f76573f
> prerequisite-patch-id: da39dc9de749b2bec147885e5c1ce8406325f901
> prerequisite-patch-id: 92a79b7c2a0d7a2650fc0bf0dabd1de5c0c132c3
> prerequisite-patch-id: 7342e8bbd202c2efb45987b68f84863abf80dff1
> prerequisite-patch-id: 85eb5a457a115d13662daa1a3418e176aa64cc76
> prerequisite-patch-id: d23eefa0780694f485edc2dc7961a745c832f607
> prerequisite-patch-id: 339f9ea26830fcd8a535213f623bfa50d2da48d0
> prerequisite-patch-id: 401933f04cb9a686bcaf8f2a53cc6b82e0b4b19b
> prerequisite-patch-id: a4d6266d89c0ffc7af4ce88f7d58c3dc7cc574b4
> prerequisite-patch-id: 613a5e9a5b2ad96252c1f8d4baa8fbc47551a9a4
> prerequisite-patch-id: 593689b7280849e0771d816636996025651b9add
> prerequisite-patch-id: bceaa173022cf34990a287b957c030dd6fb2a4a0
> prerequisite-patch-id: 882be9f25ad559ba285f8ac62396e9fe54dc1da7
> prerequisite-patch-id: 9a5663945f60c9233ca5445f7295316a1fa48e37
> prerequisite-patch-id: a08415fa1f44ec2f865c0504dea6cdef0d0f9b6d
> prerequisite-patch-id: 062fdb593aa49e0bc6728f881d67a8b893d4cbed
> prerequisite-patch-id: 870772c9da8853b86cd39abad9baee3cbedf392f
> prerequisite-patch-id: 83efed7f9a33937c4d043dc3945e4c4567be7e5a
> prerequisite-patch-id: 78176e521be3688e67d62fd9036045fb4d2c41cb
> prerequisite-patch-id: 79165eea68059c9ec1ce70fda7e0d037db5f5de0
> prerequisite-patch-id: e0329c422e70a431ea857762daa8d3c941e84588
> prerequisite-patch-id: eca120ec949905268e30504366ecd007773383c7
> prerequisite-patch-id: bf97518186c04508fc58980c06ae3b3056c2f05e
> prerequisite-patch-id: 580abf275ebc39eed92c5331102b7e6be5f1fd3e
> prerequisite-patch-id: e843467fd6e9fe712ed3f9edd0e41ca35d7c5c2d
> prerequisite-patch-id: 18bb8b8f0614489908fb54cdc8d50048cac823f9
> prerequisite-patch-id: 616a2ffde019eb0c6ea921e4044c2fed42ed5ec8
> prerequisite-patch-id: f273a456556d30d37dc2869321394b8192eaa552
> prerequisite-patch-id: e7b4aee58c0e07070b43a578efeff330a68b942e
> prerequisite-patch-id: d7ba3f6fb511ecc8e47102f00e92a033e0f208b1
> prerequisite-patch-id: 9eccf0e522e6797490c99b816d2ac836cd639037
> prerequisite-patch-id: de4e50ed623a9a32fb8611255fd24e163dd77a5f
> prerequisite-patch-id: 983242d861a55d68a091804a5c9f3a7d93ea8058
> prerequisite-patch-id: c93e750fbe586494a402acd059d927b0f51f2f3b
> prerequisite-patch-id: 12413348d750b2e215b59e93f1d5fcef3855b8c9
> prerequisite-patch-id: 1a86a6acde521a068a1410143fefa28919cd175b
> prerequisite-patch-id: 93977258899fb6973bc57b039e7228aab24f020c
> prerequisite-patch-id: fa9e83e9c1660119acd43b88134167346709081d
> prerequisite-patch-id: 1a967a9360ffe314bfd2bba7b42377dbb826f8f1
> prerequisite-patch-id: e75357782f1b93b685ef0246f9592181347427ca
> prerequisite-patch-id: c64617257be6edcdf9ebc6967c81daf6259527ef
> prerequisite-patch-id: af244f028d8ed1c4ae5ffb5c72325c590f9f4aaf
> prerequisite-patch-id: 5e2a4b12ee9827b181852aa4cb3da0895ba525c0
> prerequisite-patch-id: 0ae40a570cbb992afa7fd8f7a6a8e021de765f1d
> prerequisite-patch-id: cdd8b397486405134f75c3c575cea39bdce1600d
> prerequisite-patch-id: 0f0942812eac42dcc651eb995e281f7f8143fcef
> prerequisite-patch-id: d8b5b3c7d6dd954f9d68dca5bfd50d8ecba6ac0f
> prerequisite-patch-id: 8b92716ed19694176f0629f6a87d4cdc4aaa86d3
> prerequisite-patch-id: 60682f89c60b3684ca9658ecac88165ef58b3fbb
> prerequisite-patch-id: e57b8e0fc280adaf1d4c9f63630c5f59f66f6f61
> prerequisite-patch-id: 58920b0f6b1aada458169820e54c8ba3aa9e9ec6
> prerequisite-patch-id: 4c550bf4c42e1b504bf51f470daed8b524a2b8b2
> prerequisite-patch-id: dae987f9c073cf751e89212f19fe1a78d880ff8e
> prerequisite-patch-id: d48bf10aabe0239d85c0b19ca941eb577562002a
> prerequisite-patch-id: 87f37a66cba546d859998e5b2afb0ade72707ddf
> prerequisite-patch-id: 0572793e0eee39b86970c9c52646231fa4aea8d2
> prerequisite-patch-id: 6c289d1d6a3cd1581eb60068b19c125d3c9b730d
> prerequisite-patch-id: 9fd28952f7ac8b285ef9707ef571a789290042b2
> prerequisite-patch-id: 58d0b74005d651b7b908e7c96eb83ade89f7f637
> prerequisite-patch-id: 28fab58cc82b96a7ddafc78f93613f5ff12509f8
> prerequisite-patch-id: 9c3ec00d070255f0693fe9b74fc6573f73d5fd4c
> prerequisite-patch-id: 5432b9418a315fe872929fef0b10fe950bc44822
> prerequisite-patch-id: ebd215b9ba3563a4a242da5e855d6b12ff042230
> prerequisite-patch-id: 422e9b8a9a12b8aefd46e333bde7ceea8280379d
> prerequisite-patch-id: 9194ac783e24f4d2b47a35772b59fd58b11a4061
> prerequisite-patch-id: d86d9ca4a53447e3d4a4df5878363612357c14d4
> prerequisite-patch-id: bc6187a92399f1cb1d1d047a342da0bd92993270
> prerequisite-patch-id: a8dd85d63121158903ffeb3ee683cf126ece25e7
> prerequisite-patch-id: bc508680629b3690ff7318fbcea59fe774385391
> prerequisite-patch-id: 280e25f60bb0a1238c833aa315121dc5ff4930e3
> prerequisite-patch-id: 738439a1b5d82631bfea9f63a1ec677013411c8c
> prerequisite-patch-id: ae9af4f9b5cdd064caa414c7014f3112f5fa117b
> prerequisite-patch-id: 39499b2eaebc92d37dcb9597bc0b829eb5dc0a77
> prerequisite-patch-id: fb4241ec439cd013203882f271a1b48f71da4a71
> prerequisite-patch-id: b6923c59546a4c17430261eca6183c18954e388a
> prerequisite-patch-id: 431d0faf1ffd3c4fb4ab16833383bbf47acf3a03
> prerequisite-patch-id: d794eac0043578de98050d8c2841d483d2de54c8
> prerequisite-patch-id: 4ed685efb03ba1701fc7b0335310ce711e777826
> prerequisite-patch-id: 7712fdf7c27d1d2d130d7176d3885e0640a70280
> prerequisite-patch-id: fc3aa5f6bfec1ccda0d9da6f8e7cbd06a848aaf7
> prerequisite-patch-id: 5d941900bfa254100379520bfd5f8f283a5174c2
> prerequisite-patch-id: 737a59abdbf42715f8bdc87e018ae9ca439e63bb
> prerequisite-patch-id: adcdad660135ca4dc170ae1cc5c0e23dc94b2cac
> prerequisite-patch-id: 9052a78c8397751cdfa5f9ca8c04bd064a44ac1d
> prerequisite-patch-id: 73b7a9a0c50a2f0ff97db44c867fcb00140b1bf3
> prerequisite-patch-id: c386a48c29a789c254ddfd2d013c5879c6eefea6
> prerequisite-patch-id: a6bdc4678e0e840d451e5c6a27af01395dc0f541
> prerequisite-patch-id: 9380c00b2ebe9597cac083c87c79c245cd52904e
> prerequisite-patch-id: 67362686a0592f21e3f21d0369d0d467b8c6323b
> prerequisite-patch-id: 78449e2113023eee135f46f929361c09531d920a
> prerequisite-patch-id: a32013c4dfdd165778dde963f35d6995d1315432
> prerequisite-patch-id: 1298db103404adc02029fa911cdbca9482460228
> prerequisite-patch-id: 683a72aedb2edc15e4ff150b903bcbf28e65682e
> prerequisite-patch-id: ea9dc398074cff5bd871f32c91a1cb18eec62d1f
> prerequisite-patch-id: f577e9af27095832fbf6be3bfcdc91b487051994
> prerequisite-patch-id: 4c05963ef8110a3600fcd03793e4e31aaec95c54
> prerequisite-patch-id: 657e960acb78bf00250c18db8ed1b713eff31dde
> prerequisite-patch-id: 8d218775892023e437310caef622c04dc19ded48
> prerequisite-patch-id: 035b2c21c96a90edc41e607af87838473a833790
> prerequisite-patch-id: cf90f0e4c2499400e7934a527804778279c258aa
> prerequisite-patch-id: 4ce0eefeff0d51fedec1e0c2fe02af0ba9a2c1fc
> prerequisite-patch-id: 32ae3587c4cb2f23c03424cb788b2b09b78cd5ba
> prerequisite-patch-id: 977319a0abcdcd99ffb6002a94533e5f9ab68cae
> prerequisite-patch-id: 3b40e9182bdc1a4c42aa3feef2fdb2ccff0298be
> prerequisite-patch-id: 7962894d87c739121eaf2b5c37b74f79a9a59bcc
> prerequisite-patch-id: 52676cdb910d7ccdfd4a0dceb30031c34f7c62b0
> prerequisite-patch-id: aeaf86ed99e3b25404f82bb712f82db411a38d27
> prerequisite-patch-id: 916dd927a820244e48051db240c797ed609ad486
> prerequisite-patch-id: 87e9a258949b164d588ef2910cf8cb821c0a6bb6
> prerequisite-patch-id: 6e2574673f5ccd510b96632500aa94ad7282d5a5
> prerequisite-patch-id: a2a257aa72a093dbec878fc7978b709039a3bef2
> prerequisite-patch-id: 369cf3af3757866eedd5de5b89bfdeca08449fda
> prerequisite-patch-id: 02820be16ddebf67326007bc9912a549ec577194
> prerequisite-patch-id: bf91e27e389dc441415083d1287fefae1a4d3cb4
> prerequisite-patch-id: 698ad187919644a02c4e63afe4333c8907333ff7
> prerequisite-patch-id: 4d37f40a0fcb1c4961bc1caa3e488c8359c0ff0c
> prerequisite-patch-id: c15260573e2f6ddebe6729b195202d99edd82eff
> prerequisite-patch-id: 199e40a04886f4d0323983837ecf21cb07d637ef
> prerequisite-patch-id: 60f27d8432c7c722154f2cfc105b2a43341bdc98
> prerequisite-patch-id: b6c9c09a8b07337099fe7ef1eb4ef0a686fd7d33
> prerequisite-patch-id: c53f88bf75a026071444de65d6ebdfef1011b798
> prerequisite-patch-id: 9306ecfb9a36c238f099786b39541f62bd016fbf
> prerequisite-patch-id: 2f60fed309ca43e0184601f74f8a3ab1de8359ec
> prerequisite-patch-id: 1f245619b5f421bca861e47f6583226f3ff048b1
> prerequisite-patch-id: 692d6e49a5f7e0ff7eea8058aa09413130e301a1
> prerequisite-patch-id: 10298d261fe5424854a2b24ee2c44f13e3177c43
> prerequisite-patch-id: 31ce4d1c812b0cc16accc41db1c4bacd42818350
> prerequisite-patch-id: 29b752afca31c6c4181fad942320cb5f0a8042a6
> prerequisite-patch-id: ad877ef06cd3f40fd3a021d82024e5391a4b767b
> prerequisite-patch-id: 1efef8b11c83a1be1af29f0daf62340c7cb0487d
> prerequisite-patch-id: b1c3896c9530faea05995f4f7a46a941b44d51fe
> prerequisite-patch-id: 8166988a1e8e32438dca610b210a22447cdfea93
> prerequisite-patch-id: aa8950f02505e9335f6776b37f8cf4275c8972b9
> prerequisite-patch-id: 0b62e946bbf5a2fb13267744cb5d8250a12e84a1
> prerequisite-patch-id: e0c1872e022af51aa40e9f3bca7049bf041a2bbc
> prerequisite-patch-id: ac267435fff9964df295d564869a4139de1251f6
> prerequisite-patch-id: c6e67ea22cdbaacf176c92d1a8207e4b9cc9b4ff
> prerequisite-patch-id: 3d91a3b719073f5724fd09cd347bd4b36840ca32
> prerequisite-patch-id: d41c787db6557ba29c390e0d05224360b7f39520
> prerequisite-patch-id: 5c1f8cce19d6a1864a6adfe1bac405496eae31aa
> prerequisite-patch-id: ce448cf95647af02a8cacc57b71d55e70b92b314
> prerequisite-patch-id: 78487a406e5311157aa4e1006b1daaaf89818ebb
> prerequisite-patch-id: 7cea1bc2d66ad0b6920a9f1b64eda714ffbc4794
> prerequisite-patch-id: f5ce7b53942624944cc813c0ff4e4d48b47cff03
> prerequisite-patch-id: 6962f4f327353d8387870c08f486d6f27a389d84
> prerequisite-patch-id: 93b9523c26f99cf6e7838283113ffde23fa8903f
> prerequisite-patch-id: abec7459bbba5301973e4bacd09e4f80c3393d96
> prerequisite-patch-id: a86452fc011693bf0fc9490829f8d8158c85f894
> prerequisite-patch-id: bb9e1b3c5e182314da2675fad216288d69a5adc0
> prerequisite-patch-id: 433a33c6c95e294772fc2b4d8476c0fdb7f6000d
> prerequisite-patch-id: 75d1964725387d132e7489a27b0274490661badf
> prerequisite-patch-id: 12237490257ded85a8cbd5fcf377b9e394c89929
> prerequisite-patch-id: aca9d8138b8c945c21063847c8342d96ed6dbaec
> prerequisite-patch-id: cdd6ce28566a1d12cdbf56578f0bfe87f046881d
> prerequisite-patch-id: f379c7ce90d780a81745e148e1e4ec207c043e4c
> prerequisite-patch-id: 1afdf1d7d6d317efbb956807ec2c29d3e829bc4e
> prerequisite-patch-id: 62da9ce33a6b0bf5ae7e749645d2ee149a0ba859
> prerequisite-patch-id: 053e9fea43dcd0ebd177d4114fede594bc900966
> prerequisite-patch-id: 3b42b8991b13ea2089e18e0516ad569b9eae88c7
> prerequisite-patch-id: 5f8b1ddd1bc4cce9bc2c12d3bbbf2063e471e0cb
> prerequisite-patch-id: 6ded5d8577521237772e98755ffbfb9629645078
> prerequisite-patch-id: 7b2524114689a5427ba235c67d722e4f585aa8a1
> prerequisite-patch-id: 0e10c3a2364a5f334f7941332d18cc985bf1cc23
> prerequisite-patch-id: 0baa3949c169034d4f3a017780ef8938b1585e22
> prerequisite-patch-id: fa128b452e315f8d805d8839d9826ee2c3ced821
> prerequisite-patch-id: 7e550d0db6dfdb728790d964af36527c691adede
> prerequisite-patch-id: a6ca0c22af4fa87e4baf78c39189f2bfa4048628
> prerequisite-patch-id: 4ccb314409fd870efa9ec1bb7c5e00011687da86
> prerequisite-patch-id: 359b777257d1cb501c69f50a8a088c90d497f30e
> prerequisite-patch-id: 98e7816f9c8b83640e0f57108f353dd2d061fe2a
> prerequisite-patch-id: 2c2da370d015c5c910b19e6b15ba47b4d638b6a1
> prerequisite-patch-id: 25a3a873d6822b66212636946a9afc9ebe308923
> prerequisite-patch-id: 8c3796e2964de13d27ed75af85a892de235dbdba
> prerequisite-patch-id: 4e0bd0fceab14ab5c6f58ec1d241f60b60a23771
> prerequisite-patch-id: a5df7edc88968d712c8f630a9cfbb4a534ea0ca9
> prerequisite-patch-id: 7be8d59e13f7f108ec384e33e92246812f0788b1
> prerequisite-patch-id: 23e2f7601bb1fda8008fc453b24baddad7428356
> prerequisite-patch-id: 511af494d718d57617055e43eea573a40ff2e1b8
> prerequisite-patch-id: 6236be4f1c18eace9387c685020f9e7aa7233ed1
> prerequisite-patch-id: e5ab2912cb385a968070cbb1a885133f76500346
> prerequisite-patch-id: 14da6c77e9f6476d817d54127a32353b16944cc8
> prerequisite-patch-id: 804776b12c034859dfce9ca0b66e1a9195dce065
> prerequisite-patch-id: c1364a84806f53b4647c2d89a2e3e1d88b11c1c6
> prerequisite-patch-id: 4303b471cdf7d3ec6f91010ec6dbd19976ffa552
> prerequisite-patch-id: f8c772622063069979e1993aace410efe241c870
> prerequisite-patch-id: 43a92b5ed4baee00496aa3d8b49b93bde933d70e
> prerequisite-patch-id: 8f45a84aec05fc0cfdb5d0de8de2045c8a7f609e
> prerequisite-patch-id: b5d9f6e9a09ae8dde5107f3e8ebfd5d4a37724fc
> prerequisite-patch-id: de8136f530bcdc0e8e858f79e6ba63b253d46940
> prerequisite-patch-id: c715d244b50bdae4d16718f766d67d24ef46d812
> prerequisite-patch-id: de4f6ad41ce635bbc1a5ac825f1a8b66485ed9f4
> prerequisite-patch-id: 6c99db1eb933e7b41327b44dd207f5b78c63ba66
> prerequisite-patch-id: 4fc054f1f135bfc9494ba05454c036b8bbffbb23
> prerequisite-patch-id: c4a1b8263a5328883b08e89a958fea55f828cd15
> prerequisite-patch-id: 556e07966c7a1b9afbd968ee0fad9240c08367dd
> prerequisite-patch-id: 07be8ea751c94def872023dbb10650a3bc162b4b
> prerequisite-patch-id: 43a24a5769fdfd44f4c120290c0ac9a2b0563d96
> prerequisite-patch-id: 180861407de9910e35ffd738f6814dea81a26eee
> prerequisite-patch-id: 704c7b17c778dff92b3bf1e56bf0fe06dc964dcf
> prerequisite-patch-id: ce19b9d3216e2f3961ab941e9f444762f72ef5e0
> prerequisite-patch-id: 647dfd80102229abcf52db0e4f4695772cff8b33
> prerequisite-patch-id: cb5eee4a972341282815f9ecb4c3feb644ca7ccf
> prerequisite-patch-id: 5878c9c11f65c0623ca672a94dd222d84a3976b0
> prerequisite-patch-id: 9f3908feee621eb3ad375b3f80a754593838d157
> prerequisite-patch-id: 15cdf83320012c7f4154647101dd00edd258c25b
> prerequisite-patch-id: d0b9491e6eabc2e3d341611947743933baa7ee6d
> prerequisite-patch-id: b7a7ec79af92aa55ba246f8edd66f83cb9a08661
> prerequisite-patch-id: 31cb1c92248126ea4353b906552ca7d589f339ca
> prerequisite-patch-id: 075207dca53de4de57f865688fbecc3fd2175bf0
> prerequisite-patch-id: feea1f28a51d17bf82e7f6cab782cb910b6b1665
> prerequisite-patch-id: f6368fae198d86e493663016238cfde98740cae2
> prerequisite-patch-id: d7a5e78d8fe7b70b1d50cc5a17232ad1e0242171
> prerequisite-patch-id: 8a9a857d0a78bf4a5bcc5e14fed742453de99d09
> prerequisite-patch-id: b5c74da30bffba436a483422015f3919dbd15e66
> prerequisite-patch-id: 7214671d86cfc9f34ac7e519e6641f9665c3ea72
> prerequisite-patch-id: 148b5b744cb0f821392f9cff576952bbc1302691
> prerequisite-patch-id: 56ca8ca1c75e476600abcfaf7fe68ef7d0a08ce9
> prerequisite-patch-id: 8df4e2b31d9221fc0505db38166c710bdaca79dd
> prerequisite-patch-id: 950fde0b1e29df4751709e7090034f499a7598c8
> prerequisite-patch-id: 88d52061463b2f56b4000f4dc11f35aa65c96efb
> prerequisite-patch-id: 81b337a76a026ca62f866a98e9994d6b8edab5a4
> prerequisite-patch-id: e6583a70f049366270dd2e5ecbfbcc0e58dcc2ec
> prerequisite-patch-id: 71aae8ecc8cd2e2e28b1c125b0c9bf75ece6ba6f
> prerequisite-patch-id: 95683ce824bb79c91d2fe8574a1738a0d9dc46e4
> prerequisite-patch-id: c5e8f66a712d292f40f5097e6acd3162ebaf04b3
> prerequisite-patch-id: 3a3b624c016ad88c415b621cbdbd6f1b7bf721d0
> prerequisite-patch-id: 40cd58af523c09b22c3917b5e63c4070a2689942
> prerequisite-patch-id: b56f7dd08cb279b776c8411e8aa8d13e82d0f23b
> prerequisite-patch-id: dedcdcdeabb83150ba8b1e471f321a65ccdfc11b
> prerequisite-patch-id: 66a088ed2223326ffd91be837c6a52db6f147a36
> prerequisite-patch-id: 8fa636340cff33e2aa7100aa6b7590ef7505fc6c
> prerequisite-patch-id: 8294c0fef912fb6cf7af8cb9dbdcd97bf0bc32e7
> prerequisite-patch-id: 0e07636b55a5e9a6f3cf3e3edd4b60f0cd3a0ee9
> prerequisite-patch-id: 3d5e7c7e7c2c033ba7d6e3234cc1ea383d9e6106
> prerequisite-patch-id: ccd00b22708d32d9fb3c14b3bdd56f7c700b7103
> prerequisite-patch-id: 343c8f45644659cef0f4307b095ce3115a4ac29d
> prerequisite-patch-id: 332e702df7d3875bacb8965fda9cc9b630824090
> prerequisite-patch-id: f6aa82e9a89056108ba87cab584524b6f6d889db
> prerequisite-patch-id: d71bb532e6fa5263fd2b786619daf8ab4270b7d7
> prerequisite-patch-id: f218fb0a00440c6a5ba114f79d491950a5f72ceb
> prerequisite-patch-id: caa8fbcc5004d78f3e0832e4f9cc3f54e31a4859
> prerequisite-patch-id: 03cfe96c3bb1f09af9f9899c837e0bd262cbf849
> prerequisite-patch-id: fc5ecf1d635a7ae06bce0434337a944bc60cbf7a
> prerequisite-patch-id: c2bf443e33f3e44262e8a5f9a90d165e0847efaf
> prerequisite-patch-id: 00295d8fe70e9b9d34c4a7011ff8074755090f2e
> prerequisite-patch-id: 4d5d8e4ef78205bb6026ccd5fb9607a6a9b62599
> prerequisite-patch-id: 8410fe3a3e078d71e47a6088da4a30fd61c33314
> prerequisite-patch-id: 6a71218281d0cda2c35cec16e362c13fc73dd80f
> prerequisite-patch-id: 385b30d5027312e6040a28cfa8a470b68b18d136
> prerequisite-patch-id: fd18c5386d678617c7cd6cb7dcb9596a697de163
> prerequisite-patch-id: 8da531ca9c21812a703d52b50822189f9829db05
> prerequisite-patch-id: c0de27fa61a2da376bdc618db54db92245e9a3ff
> prerequisite-patch-id: 43bddcc7d940243a76fcfe320bffbc5016ebf215
> prerequisite-patch-id: 7635182b235a590376c78fd4508d4567005c7c61
> prerequisite-patch-id: 106d91504b278b0ac2cdb7acf22fdc8a3851d430
> prerequisite-patch-id: ce27d5d90f8d0e26f5bdce3fbaa95a64180eb3e2
> prerequisite-patch-id: cb1cdd79b386b48e1c789a671a4c8078eda3d571
> prerequisite-patch-id: b1e909c19bb32981697c3b7af81df8b2d32c6efe
> prerequisite-patch-id: 8f91e177db3aa142705298ad59228b2c011f552b
> prerequisite-patch-id: 60c34b4fa3db025fa41e74912e48c2d5f21ed725
> prerequisite-patch-id: 04b1163842ca5adfa2f0e21e0c41228623da1342
> prerequisite-patch-id: 6e1ff24b391a64deb4a0e4e8a0f4ad5a7b5b904d
> prerequisite-patch-id: b85a33144ec9ca38b66a1e5e7200a32d02c30988
> prerequisite-patch-id: 5f84bbe91a339b77021911cc07c60b0b3f54947d
> prerequisite-patch-id: a6a5205940b31089a98f072f4c03de53b4f21ba7
> prerequisite-patch-id: 82b5485cc3c0293bf1483572a5d42889f44bb2dc
> prerequisite-patch-id: c4198d83bf55920ade9a42dde0fd73bb2dd74c82
> prerequisite-patch-id: 204849b7b208442e6cf5e593aa942e7f886b79a5
> prerequisite-patch-id: fc74b233775df0f2f5785951b055c008690a3371
> prerequisite-patch-id: 4d8ee05c23514f9aa09ba6c2cb9d63921b58fa89
> prerequisite-patch-id: fecd01ca3505f3558630ffe9233cc1a11c8072db
> prerequisite-patch-id: 2e58f20b87b7f1414228dd238f16ad3234bb4892
> prerequisite-patch-id: 1f2e2e34f7c454ada1fcadedd7741c688bb1f91d
> prerequisite-patch-id: 134184723b065addec79e96b8868c97f779580d6
> prerequisite-patch-id: c06d4c38159f6e997f31d54bc812f899c9ce2432
> prerequisite-patch-id: d36849ef4840ed4a7f45b2460829e5a4b31a93f0
> prerequisite-patch-id: 0c0987760592dd33ec7f0c1ca06ea2ebdb4f3165
> prerequisite-patch-id: 5a857dc647f6f1744d13e255ad03b3a5e587a3a7
> prerequisite-patch-id: fad5395a4b86d083d6bb5f65e7a18d489b8cd1ad
> prerequisite-patch-id: 5a86af1105bc392e3c63413a157a043a5c82ec75
> prerequisite-patch-id: 8e3f805cc7c2dd83bfe16b228d3649db77e808da
> prerequisite-patch-id: 656b634ff064a90d02df0d763b54bc880bd24def
> prerequisite-patch-id: ca0eeca1d9bab21325f71cb12023f06f2e687baf
> prerequisite-patch-id: e903f06a7423a0c47bca8b596d8512088fbec0b1
> prerequisite-patch-id: ac0fd5a6f17dc3a6979d8580407fb337a6d72a23
> prerequisite-patch-id: 7467dc112a9ad9bce059ddbf1d97618ef0f9313f
> prerequisite-patch-id: 3541add2ee6f4d8699dbf6126363b291089679f4
> prerequisite-patch-id: d2386bf650746d72f3d677f82f0f96c353ea4797
> prerequisite-patch-id: 60dea359afff6fae0bed2d9610d87824a8bcdd02
> prerequisite-patch-id: 15c39525ea5cf6855af3402120de715d1ac93de1
> prerequisite-patch-id: 9367aa200cfa20b3ee2554e232b71e7bf2b04edc
> prerequisite-patch-id: 9fadda11463a221ba48eb860788addfed93e3727
> prerequisite-patch-id: 8e0c375c6c28784f5cd49c81a2a1eac7bcac5d23
> prerequisite-patch-id: e3fc773965519c33541dfe51b24e933bcf6505e9
> prerequisite-patch-id: d4d0ffb7606b1062e86cb2354d1282f452af37e1
> prerequisite-patch-id: 863e0183ef98f52e63ed27be79fe3af623abf4ca
> prerequisite-patch-id: 0f3cb3117c6b39e73815931de73b57f2e7ba5985
> prerequisite-patch-id: fb1ba4cc8577d4bc85d2b6cc57895135c674ff5a
> prerequisite-patch-id: e25de5e19bcd0b5dd1ad03db1097abab3fffe398
> prerequisite-patch-id: 00d2f8410fcea6f31d9adf6ace3ea52f5f429369
> prerequisite-patch-id: 21067cbf1619599ea17b4bc04c7105984829b708
> prerequisite-patch-id: 6d7b35c95c831976f871be349b1583131749ebc2
> prerequisite-patch-id: 5b176ed979eabe265920b08d28cb4cc9374f81b8
> prerequisite-patch-id: b554b78ee9cfdb8fa7efb969c9ab61e4adf71f93
> prerequisite-patch-id: 5585fdcc4bdb43f12ff992434e4a29ad6af40f27
> prerequisite-patch-id: 22c4a028bcf369a7a744a85d5a9797ea84a1281b
> prerequisite-patch-id: d9efa909a290253026b1878a97c5d87e62411be2
> prerequisite-patch-id: ebec43f5063cd7471e52757bb29c0bce9fa9598c
> prerequisite-patch-id: ba68661a2410f69ba197e207c94246730d0bb8b6
> prerequisite-patch-id: 105ff210d4124d75d99428c7ed608b32345f89ba
> prerequisite-patch-id: c9253214ba4228013a490a1e56d25c0030aa1548
> prerequisite-patch-id: 59b25ee0934b66f942df1a949e953cb57700d0c7
> prerequisite-patch-id: eb222f4b773b14d7a179b546052d3894dde9bbaa
> prerequisite-patch-id: 73c013f99e2d2157aa290f5c54b5f712f248caac
> prerequisite-patch-id: 3c658010327c71951bc80495602e53c249782837
> prerequisite-patch-id: 7f91dd8878f8560a1c66f61e61b3618192e00a2e
> prerequisite-patch-id: bb7298b7b6ed93f529dfbf5872520cb2051775a3
> prerequisite-patch-id: f538395f03f711d8760d108b66e73c69e2ed2084
> prerequisite-patch-id: aa09b09ec793764b4ddb2b371eaaacdbf0323825
> prerequisite-patch-id: 477f3133f253a8b5dd70b8fb1c50abd5d4422362
> prerequisite-patch-id: 6aaeaccef7726dfe8515670ca6be55792bb10d5b
> prerequisite-patch-id: 76d270853f4c722f54e7d35a2b291590440cef4f
> prerequisite-patch-id: 0f1a0841fd711801a656199b95afc78558e127b1
> prerequisite-patch-id: d57121935195cded44c452b7b6872f0016204a1a
> prerequisite-patch-id: 0bad09c190118eec6e11d6cc7f522e27317d4009
> prerequisite-patch-id: 636c3c8a10be486ff3821d8627d36b741df1fde9
> prerequisite-patch-id: 7d0cf90944a0743ac909a3dae2a5586436c8393e
> prerequisite-patch-id: 772dd6a0577c205e8bd0465606ab88fa8b272b47
> prerequisite-patch-id: c53c2a80bf7369107a46baa83915738d0140420c
> prerequisite-patch-id: 75c3156b5d03d2bc4d576565423ae0c98a775f08
> prerequisite-patch-id: b27d07ee84703ebbee53e495e1c64a6dd0ee2334
> prerequisite-patch-id: 34c7d047cdf73d91bc6f90a962352112b2234329
> prerequisite-patch-id: 0086cdf4152cac2666b072ec4fdb5e3eb795b55b
> prerequisite-patch-id: f43e91648761bce699872c1ddb48d9294893c629
> prerequisite-patch-id: 43ee072a35b09d95e561a87c2bc635ecb66dbac7
> prerequisite-patch-id: 063a7e1c0d454e427638cb603e399971d064c334
> prerequisite-patch-id: 9bb45e42ee9fc0e4f1e7a0d415a5c4e106801c96
> prerequisite-patch-id: 528a9b1945a3feb1629bd4f2dff7567ed12104a8
> prerequisite-patch-id: 0509d651b3cc3400b98f9ce92db95bc7d047c23c
> prerequisite-patch-id: 54a314624dd4ea92876b14a3d943a15dfc2dbbc1
> prerequisite-patch-id: 404cd1408ce3a9cfa340a53a2159837310bca39d
> prerequisite-patch-id: 04d396d0b7c42ba82603b17b9b63e18447e632cd
> prerequisite-patch-id: 4a11a4630778ea48838309dd7ceb4ab4e8fc0332
> prerequisite-patch-id: cbb8eb9b167f532a90a450067ed406ed75b9f165
> prerequisite-patch-id: 9648d52d9a4c1fe4be48febffd9bb4ff2bcc7d66
> prerequisite-patch-id: 28dfed774f6996e4604a6d89806bba8485775dff
> prerequisite-patch-id: 9bc0b714c72f78025522b7aa7fb9c5decf95a8a2
> prerequisite-patch-id: b510bfc650fbc4dc660b4d8701a785aa98d875cc
> prerequisite-patch-id: dc7ddb60c7909ca7c762cb26ff920a87a005d69e
> prerequisite-patch-id: 41524d1bd17bfabae8004a172a300f04921c473a
> prerequisite-patch-id: 8a853c322f4a1a3057f826e40ddc2850eeaac42a
> prerequisite-patch-id: 8714399675fd6c553e24cacde0b65934167bbafd
> prerequisite-patch-id: 499ac133a6551cd59d514bc4809deef01d149ad7
> prerequisite-patch-id: 879fd2575bba68264ef665e17610045b4e8500f7
> prerequisite-patch-id: 3d82a029ea586cc22625a85479c93e70d10c78b0
> prerequisite-patch-id: 936a17199d253aefc6c288dc2496a70efc483b6c
> prerequisite-patch-id: 6d8eef97c36e286ffeff52fac08020ca37a8c6c4
> prerequisite-patch-id: 250b7ea5af0d507d9c4a29270ef7d933b0eb89e8
> prerequisite-patch-id: 2c4ef26f83724f1bff3905c7fd3f07a78396ab6a
> prerequisite-patch-id: 446b2b97b5f94851911a131c88c75fe69030eedf
> prerequisite-patch-id: 6d22e728266c9dbc1691a78ea4602e9b7d4613f0
> prerequisite-patch-id: 63b11b3accb5b75397764401954700306cca3e34
> prerequisite-patch-id: f7a7acdd7103207b400c38923a40b3d3226e2d34
> prerequisite-patch-id: c0355cff111770dbb1165162fc98280beada22fb
> prerequisite-patch-id: 2613cfa227685bea9f38f5969fe7b5ff540ae89a
> prerequisite-patch-id: 8f37eb50edb2a7ae9d50be02e1933cdcd1d22d53
> prerequisite-patch-id: 744cee23c04b10297544ca26fdc91906864a3ec6
> prerequisite-patch-id: 5575e34a5f3a03b934df3959f3dc212077c8edfd
> prerequisite-patch-id: 62bee054ef94a995bc82a7b1030a606256fb5578
> prerequisite-patch-id: df887017da7e7abd9d0187efdc8652c8bac47a83
> prerequisite-patch-id: 7059a7b1f7e96c2b157494652dfd74cff19eb330
> prerequisite-patch-id: c6f031ad6a54e94ce64dca6195454e4256601226
> prerequisite-patch-id: a27a43442338d0767fd77731b1bee1998cfe095b
> prerequisite-patch-id: a9152b922ce8ffc1579a18cc04b08e5f2e4b26a1
> prerequisite-patch-id: 943053529c2b76018aff818f4c9e5bdb38f199a6
> prerequisite-patch-id: c4de9190c22b7234c780291d9f1616744731714c
> prerequisite-patch-id: e9a6ec6234fc12cb289409e25033359cc8c35166
> prerequisite-patch-id: 9f09efb58155f570590aea6e8a8c41b2fc26c7dd
> prerequisite-patch-id: 8ce46c2b7f2d4f5894fd29931b1e31f14e18e779
> prerequisite-patch-id: f777d1ad00f7c28d7e32dff32ca71b6dd6abfa3e
> prerequisite-patch-id: efe45cea1eb7716918e57896d5421925496022be
> prerequisite-patch-id: 9c1d6d7e0518ec6b6eff8170ce71acba2cf31144
> prerequisite-patch-id: 299cb03179116b827d862f3a6cb2f0b2694d1a74
> prerequisite-patch-id: 2289648760a67deb6c3acd7c7e1bbfdd2a5ab6b1
> prerequisite-patch-id: 1f1ad7649995a4592e341c314fb3fa613d30c0c0
> prerequisite-patch-id: 9e385406ada1244b01a26f2ed9686a32f671f193
> prerequisite-patch-id: 92aea6471c0492fc78a6c4f430f6d80656f327eb
> prerequisite-patch-id: e00293581dd1ace8d934f84f1ac99c10525b7eb3
> prerequisite-patch-id: 16c5e6b1ab38515974c23cc2ba70e0cedf0d358b
> prerequisite-patch-id: 44708c52bd2a276c9b83f2809b44c53d21ec8f68
> prerequisite-patch-id: ecb626139964569830b119597e3a92652e7d3b73
> prerequisite-patch-id: 14cbcaf4e13b9e5712fcf1b5f531f661cd9c8894
> prerequisite-patch-id: 126318155b63b45204866bc88f089819628d35e5
> prerequisite-patch-id: 5fdedb35a89b8e60a1c79625faa0c0a7bdca0058
> prerequisite-patch-id: d53a80a07aab7a88e0b91287adca6368f56e5f3d
> prerequisite-patch-id: 43cd28c24a5696eb2ae1093e339c1cf694dff587
> prerequisite-patch-id: b9dcbf11a044d4b5c77449e1349f6646ec4bde12
> prerequisite-patch-id: 94d47af8b9231b0d0dbbe1d83073bf08a2b2c2bc
> prerequisite-patch-id: 458e343863f572159d72cf5a49dee7e0b6e1b87f
> prerequisite-patch-id: 8ff924c86af70cf8984653e46099c4ab54cd2446
> prerequisite-patch-id: 66751246dac406f4c9ccf66b2f5110fe69a964bb
> prerequisite-patch-id: f6a5751e208265a1c34c9c2f3e56a0f6e9d1f4f3
> prerequisite-patch-id: a32a2c2058be0de353c8083e50e8f564db5916ab
> prerequisite-patch-id: 489f3b520bb6cc735a9d813ed070777687548ff4
> prerequisite-patch-id: fa6e36f42cf86dec5a60bb44612b372d7f8353dc
> prerequisite-patch-id: 2747d48ea61b52e268aef92781271d0c4c9c4caa
> prerequisite-patch-id: d87c6d65b9e152f0e82c10bdf6b175c4f11dea39
> prerequisite-patch-id: c4787cd239acf9d4ed22ead100b4e8b0bc814524
> prerequisite-patch-id: b60522c71c5d80ed1f369bfea0d22ef87134c661
> prerequisite-patch-id: 3af07cf3e100deb6d816aafb5482a66e61c1f963
> prerequisite-patch-id: 7a771977d1ec6f17ede18c6f59c6f80c85e7b543
> prerequisite-patch-id: a6cb824c3c7988bfe3a51bdfc6759204d47d5150
> prerequisite-patch-id: 46704d4e1ea135ac045070249ce778dc7487e49a
> prerequisite-patch-id: 2f0c18a6793d1fd10509b0c055023de8210a1ba7
> prerequisite-patch-id: 76f7e29a972a8c663818c812dce080670c12e823
> prerequisite-patch-id: 49a24b65e0453b3ec9203470df2008eed56a8cb3
> prerequisite-patch-id: b4bd611b4b3cdd2e125ebad0123ce748de5bde7f
> prerequisite-patch-id: 054220c4c9000f568ac803be255aca4e1a4d4a33
> prerequisite-patch-id: 34269983aa5e36822331fb15ec0857b675a3bead
> prerequisite-patch-id: 8ad9bba9e175fd0c135dc786bd61c9c199827c35
> prerequisite-patch-id: 1c7d1564a88eec395ca1bced5bafa9562e60d0ff
> prerequisite-patch-id: b0c4635707bbb914af04a1c676a0af9abd48e55c
> prerequisite-patch-id: 6817249736501c3e7b0d8338321824703279bc1a
> prerequisite-patch-id: df3d8e77ebedbf63267dfd07aebb4b8ec9cd286d
> prerequisite-patch-id: 5f448d76d911e0f617ea0d0ccf897464ed0d57ed
> prerequisite-patch-id: 693ac532fcf8b248f58a1674af1168fa1a37b1bc
> prerequisite-patch-id: 27108b5708e692c917b6d0082e618c06e4e6ea66
> prerequisite-patch-id: a41aeb4634ee5bbefaff4d9e8c7a750f15097184
> prerequisite-patch-id: f46f992d936c383894a4cd29d8939c0e7c565ae7
> prerequisite-patch-id: 76b91a47f91a65f145aa62e07b86cfc7be6f9485
> prerequisite-patch-id: f9d209c20706f524d71c08f6b06312d3dfa8b2ea
> prerequisite-patch-id: fd5bcf9d421517dc89c17900cb7f89f2a9ef5a76
> prerequisite-patch-id: d9e4f398a7fe6b8a3afa0851b6aa74e112d9d3ea
> prerequisite-patch-id: 1dc6dfb708ebd967de072a4a0933232eb71e4d21
> prerequisite-patch-id: 9ce5773387d9f7b3b8ec78654de70031b239a9d3
> prerequisite-patch-id: 54437ba4b103440df34d3c5a1dc799d1e0c1bd4a
> prerequisite-patch-id: b85726143fc681114def6ddd1f64402f4dbad74d
> prerequisite-patch-id: bf652b2d57c7996a0e41754f24a95fc8b4ddc051
> prerequisite-patch-id: 91a265d4315e1f0743790d438cf173be52c25aca
> prerequisite-patch-id: b91b1ee2f16c1b1a680c5b8ef914e0cb9b6793f4
> prerequisite-patch-id: 8835ea7366770315d4ac1b0f97759e2370568e43
> prerequisite-patch-id: 41f16a720c5f4b6a011c1963e4d20f6861a87721
> prerequisite-patch-id: 24807beb123e440abfe283f41fe31a4a722763d6
> prerequisite-patch-id: a237f9d0a6427b1106c7e4fb1064720802ef25ca
> prerequisite-patch-id: 3ac5fa651d5fbda0302644376ac746226c0beb19
> prerequisite-patch-id: f1c28c223c979813b2ddb91aa69fb859f9ce8e01
> prerequisite-patch-id: 0429a0e6b90e61a39d648c3f747d847f17a36522
> prerequisite-patch-id: 5ba17efd990d1cd9eb3e567c8e54298528d7d33d
> prerequisite-patch-id: bc71d03054efd211467145699be60d2684e86672
> prerequisite-patch-id: f584b763a58c8658ac1fe71d94a05496a5878f22
> prerequisite-patch-id: 7aadb4cb022f0154ed68689e7c27f304fcd0f253
> prerequisite-patch-id: 8621dcdb8186fd8c3d724b0b5ca8e0f3a68dc4ff
> prerequisite-patch-id: f84694172a54a9e5270190b1571f2f2d7227456f
> prerequisite-patch-id: 11955791e590d903cf162fdfcf7354b406a77c89
> prerequisite-patch-id: 667c83967a3aadaaf977abd1f81a428f831ee5b3
> prerequisite-patch-id: e9915a829a18b923b579891764385d4808fef7fb
> prerequisite-patch-id: bf678b283d570dfdcebf62c185584f53a211c4d7
> prerequisite-patch-id: a40df82babd3287338f2c205c1b0a55e918aa1ed
> prerequisite-patch-id: 693700aff38cac6a8c340e42bae16f6f5799eaee
> prerequisite-patch-id: eb3cb98cc9202fec7595fcfb5f84d8f397bcb5fd
> prerequisite-patch-id: 472c461dbd15c460d4c6df7d0dd1eb72b68f22af
> prerequisite-patch-id: 74397498f467d853077caae7a67450c257a3131a
> prerequisite-patch-id: d6379b3e1eab262fb25bee769f6531617f28a0db
> prerequisite-patch-id: 0259a95682e8384a9a2352b01b1832f8700cab1c
> prerequisite-patch-id: 7cffc7be770f7aa59a30bf6250fab835b0297b94
> prerequisite-patch-id: dc1c385ca312cc9be0651cbebff0bba54bdf6893
> prerequisite-patch-id: d4d7ad674798aa9c15b3e1d4824f1ad941419358
> prerequisite-patch-id: 100d8f0737cd6625dba772a70fb4a38284a3243d
> prerequisite-patch-id: 4b71d27c3fbc59da535411e1038cf1393d2b6768
> prerequisite-patch-id: bfd87ea6fbffdfa5261b405de654578db7dea1ef
> prerequisite-patch-id: cbe69ccb3f7c76723a8a402e7652d6093b3a5176
> prerequisite-patch-id: 1012e89134c5840dd379d92afc583e7253fc2ddd
> prerequisite-patch-id: e1f42845bc0aaf50f1886c881c662a0b3acc26b6
> prerequisite-patch-id: 3b87a1db719e4d9097d66db54bb4226ff990d14a
> prerequisite-patch-id: c4f2a3dc52622507edda9d85107441e2ed2c0436
> prerequisite-patch-id: 0e0dd75c73b3d4ac13324ff3282909e3fcb3a739
> prerequisite-patch-id: 868be5764ab29178ee01d4b51b5d9d830cc527ac
> prerequisite-patch-id: 529ebb52bf94d1050aa9d7f11e7228bfd956840b
> prerequisite-patch-id: 987cad9e8b48845d09b0b754cdc1965547de23b5
> prerequisite-patch-id: ae11a2c4616416eec2d0e79a0ca55bf093be745b
> prerequisite-patch-id: 3adf73043cc9a1972e3a3b9d1d0e883d1b9d4d41
> prerequisite-patch-id: a4cf542ee9e28834f574570fff837ba24616e984
> prerequisite-patch-id: 727c7c1e7a61e3047a682f4383e4b66f4fb29335
> prerequisite-patch-id: 38cf24a9c1aa9733b7390a90c3d06ff38ee4c297
> prerequisite-patch-id: df9e4947cc0fa0ea00c2e8ad9d3531006fa9267d
> prerequisite-patch-id: f50f5c3356643b62f55a449431f95849fe30f167
> prerequisite-patch-id: bb0a0f87ed1da4429592d469bc0191b6bb21645c
> prerequisite-patch-id: d8a432be78660c69fdbc319e988be7557ba45ec4
> prerequisite-patch-id: 7aa11823a3099aa64e0ade805feee14d4f47fdb9
> prerequisite-patch-id: 987e44a32e471008a08ef01aa6ccf1bf0c36fd68
> prerequisite-patch-id: 8f8c3aa28f83077d6764854d12f962d825a36fc7
> prerequisite-patch-id: 503a70aa76fccb9aaa146cd556b3af992117e26e
> prerequisite-patch-id: 4c5c0dae6c7be94085dce197a9826a847ca53320
> prerequisite-patch-id: 419faf2ded4131ed948f289cca5a770d6fc53c13
> prerequisite-patch-id: 7c7682f122a8776f68ba1b97ab070803f7a91141
> prerequisite-patch-id: 5b5de70d90341e4e952a86c137fa06fe6b2c29d6
> prerequisite-patch-id: 1358a6fe3a6abb897b2f24be6c535c810aa3f390
> prerequisite-patch-id: eed21c74a29df9938ae1bbb875a41eafa1c690f8
> prerequisite-patch-id: 6b8e314943d42aa15eb08948e5302652f60bb53e
> prerequisite-patch-id: 0e209dc13d7216abd45ccaf623f886dd74cccdd2
> prerequisite-patch-id: f8a802939039720bd63f4089d50040b2ce144052
> prerequisite-patch-id: 5e027d8c5889f9972b29e350be558e5f7bc38ecd
> prerequisite-patch-id: 02115b530e3b1cf917cb61682eba5c41d6c08da3
> prerequisite-patch-id: 46902c437cf4e3504adb9d16551f1a92139f01fa
> prerequisite-patch-id: 54bf4ce70747a448b2c8bea68c60f8a92ef82f77
> prerequisite-patch-id: f3e6d93b11946cfd8c074d88fd1470021025d261
> prerequisite-patch-id: 42c994231daf55e04ad3c4e2c5132150013db7e9
> prerequisite-patch-id: ab42c7461903deab38e50b914cb9a0393cbe7441
> prerequisite-patch-id: 794260a7123e6af3c53d8cedfb5ddb4ec8f67008
> prerequisite-patch-id: 0f63c97f615329754fe2a80028dee3c4e6355ad6
> prerequisite-patch-id: 6465e081d888a35cf6d89e0feaa5a381171c3cf8
> prerequisite-patch-id: 352efffe76c74c8d2dc9929bc8c9775bc59d772d
> prerequisite-patch-id: 15037fed19d07c4e2f8dd2cc430d86931b61cb6c
> prerequisite-patch-id: b90533d59fe3582f3cc011d31bbf42aaa09c063b
> prerequisite-patch-id: a264d00377d2681244fab2e9c7e1dcb3ab4c6281
> prerequisite-patch-id: ad3910fa1b9d84d27f740d0cc8ec4cc1782d560c
> prerequisite-patch-id: f174dfc9940148c3489571db28ecf8f663b642d1
> prerequisite-patch-id: a3018d78dd6216798b641ae1068a73b18bda1085
> prerequisite-patch-id: 820d3eefb615852f2266c0c8a468b9e936011c61
> prerequisite-patch-id: 1e93a3b805e16f6c901f24f00b5be0c3e8a20d86
> prerequisite-patch-id: 61e65e6199e0fc9b94e966026e38b3c4fd8cd273
> prerequisite-patch-id: 095b8474fd8aaa97b8c2cc9c17e8b669a43e0002
> prerequisite-patch-id: 1d209f21ed11c55b1b1440786369d3b73264ecbf
> prerequisite-patch-id: 87c484ffd124047839ce65b5b4af588fc227116e
> prerequisite-patch-id: 80f8b65af333d70ae745a8715e40db235892dade
> prerequisite-patch-id: 6e6357becb24a1b787716069ee284a9e17e92c72
> prerequisite-patch-id: 4ec28cb646dfdb514d5cbbfd61db7fb4274d93b7
> prerequisite-patch-id: 92e19a35ca5f968f48802f3524e3455f22ff77bb
> prerequisite-patch-id: 1484c0baf9c93ca8897c8f9474598c4cfa790d1e
> prerequisite-patch-id: 8f0a0c8ea4846639ac4b1d4c45204754f9105e4b
> prerequisite-patch-id: b71c93ad0435c4bb681a5ba87bef37ff7efe1b9d
> prerequisite-patch-id: 4075c42788ba2a17fd9e12e88daccbdb0f80b0ab
> prerequisite-patch-id: 0d74c9551bdb2d815fb4447cdd01e0f0adaa9b52
> prerequisite-patch-id: 29ffe666724b71a2fe12a398b93fd82f8dbfce3f
> prerequisite-patch-id: 47493c8b8b0883c2de9ffaf2e0be8f7970cfc450
> prerequisite-patch-id: c50a1866ad8de4054348d829600c2c0275ed9104
> prerequisite-patch-id: e29d3337c2e914780d8380b18474a8c407aa951b
> prerequisite-patch-id: b8602c233715c49a726408a92c3c07706b9ad313
> prerequisite-patch-id: 62f89d06622ee199b270da20229b92f5dfc4848a
> prerequisite-patch-id: 976aed2432cc1e83ee164dcbedd0dfcda66dab20
> prerequisite-patch-id: 8c1c1d26633d40fe5c8f96e4f7cb1f0dfa8505f2
> prerequisite-patch-id: 078e74b342224c24c3343b9fba415d8963de1227
> prerequisite-patch-id: 42e71f87fd0844c730507f664432c1da06bc6cfb
> prerequisite-patch-id: 5ae77fa2989399390294557d15065a4b8a2a7b95
> prerequisite-patch-id: 1c5a5128010e6ee6f83737eb6e2e097c55580422
> prerequisite-patch-id: 5e1310279f85958849fa78e87ede43e5372da1ed
> prerequisite-patch-id: de28bfdf152bc1825f550cb0a347f7e900f41be3
> prerequisite-patch-id: 8141435c133ffd12585d356df2fce46f6220b625
> prerequisite-patch-id: ca4a4b6f6b2821d3e72cb7414d06831a2fab2706
> prerequisite-patch-id: 731ac1735d7dd60cd7052bb199285182d9a48820
> prerequisite-patch-id: 2780a5e8473db208326372a739c69f94f2075b80
> prerequisite-patch-id: 01377bccd733fed65b2939e71fb98063425bb0ad
> prerequisite-patch-id: 7f6c9c9e1245498abfdde8aaf14c1322c412b4d3
> prerequisite-patch-id: 1f0b67a43fffe9b66dfd81f9f03c8fa815c1a562
> prerequisite-patch-id: f201fc987152ff7d65794bcdebcd176596bf403d
> prerequisite-patch-id: 878e7c2cb6bafdae01ae231d0568821826035399
> prerequisite-patch-id: b3e6347cff7cdf76bf554ab790e9c6e47bbb3934
> prerequisite-patch-id: 2a7cd07546be2dfa8063e96aac899cdb493efa09
> prerequisite-patch-id: 3c1d84ce075b71c32e9314cd8e80ea44f9bf5f76
> prerequisite-patch-id: 19b643dc28ed1bcf7127f4cfbe6a52268b4f3a7d
> prerequisite-patch-id: 8949951f666720908afaae0f637e46f4ce808536
> prerequisite-patch-id: cb751bfd2cbfcf53ef6ebfa01b1c96f46fa3c137
> prerequisite-patch-id: 40abf2f6cee4378528a6bc7e8df53556037efb77
> prerequisite-patch-id: f307189b535748a1f3f3953e7e913d021f60778d
> prerequisite-patch-id: d470fc3a9df67c7b61aad266a64a16945cafccfb
> prerequisite-patch-id: e2168b0ecbf1923a2ae3c64c5eef46c93d27ff63
> prerequisite-patch-id: ee57421c39fb21036194be224fa6a54ae272480b
> prerequisite-patch-id: 59a2825c36d71fe21515a97e36b2a6e3b3deb10f
> prerequisite-patch-id: c40f57b10e31d978009131e1b0ed421e0883a601
> prerequisite-patch-id: 33769aefff8fa279f0a8af7b6735253732f651d2
> prerequisite-patch-id: 79134b9a20118a75c5e90b49ea84b5d68ff8a25c
> prerequisite-patch-id: 3c982c4c9ea6cbb561451d6e6b4d989f6c4e1bf4
> prerequisite-patch-id: 0000511ae0ea43bce2bfd60163014f9efcb58057
> prerequisite-patch-id: fb91b31bbe162702021213d832d1d0973c0a454e
> prerequisite-patch-id: 4e0536e11b6f1b504fd12c484c67fdd18bdc3b2a
> prerequisite-patch-id: bb9006980a404b78edcea09a88b6211d791c759b
> prerequisite-patch-id: 327a98aaad1aa4910cbd9d54ef0f29935de93277
> prerequisite-patch-id: 7d82275e121ed7f80b73abb072fe1b5337d8d141
> prerequisite-patch-id: b604615895ba0a235584a8a5008ba529ea0d6b85
> prerequisite-patch-id: a9f8102f1d3df32bc1c8bd8adcbd617bc354b608
> prerequisite-patch-id: d0b4fb7fd5958f7cfcda1f8537591cf061ea7013
> prerequisite-patch-id: c45e7b5fe6d28e34cb9155a8bfa846a5348e7c6a
> prerequisite-patch-id: a75569897a2b3b082e0d6df94a10512932534d8e
> prerequisite-patch-id: ba174d345c43823b535413438883f37ce84ec545
> prerequisite-patch-id: 3f56725153df34865011fa15a7d5ad34ec0571fa
> prerequisite-patch-id: 675386b40e7f97628024ebd3f9e5c718f417a9bc
> prerequisite-patch-id: fbee3d674bd52219116116fa97a35ca4dac52d36
> prerequisite-patch-id: 4a83a58e35d2471a77336b7a7ad3af5e504544b4
> prerequisite-patch-id: 98ba2d8a08e62a152ea817df45606e89c20fc8d5
> prerequisite-patch-id: 68746456331932f5b8b43b21764e62a74c90c69d
> prerequisite-patch-id: add05d48f957ae9c58e26d9b64e53bec2bfc2877
> prerequisite-patch-id: 77bb62282448d397bf5759817b1f102709aea688
> prerequisite-patch-id: de28ff1d1bceafe9efcb8b6c8b160d9a4e218ec7
> prerequisite-patch-id: 0ef2d3421fd4b3f45657ceb48ef3abb0df9c2da7
> prerequisite-patch-id: b1e26135732e46192ad476931b36fe24679e9c8e
> prerequisite-patch-id: 099fd9b94f91a5dca303c9ecf086b6987adf8c12
> prerequisite-patch-id: 0ad7081926ebf86ccfd2836e1231a2dfb40545d5
> prerequisite-patch-id: 24e3a60834b53c58a28278c13f1d97bce043e34b
> prerequisite-patch-id: 7f4ee09c0452037f3e9a57b5d24b32a49133169b
> prerequisite-patch-id: f9d1eca2a104a0ef9beabd18e456acc0be1f3381
> prerequisite-patch-id: f132bc29ff93156fd68cd2386a05a3d927a6641a
> prerequisite-patch-id: f2667b22654cdb3e114268a66b6d06b74eed0ce9
> prerequisite-patch-id: e6cc38a5aa966dfe806691be98d3bff1bbd6f48b
> prerequisite-patch-id: 409965b3c26e1468622ccf430f3cb3f88d09d224
> prerequisite-patch-id: 82ca57db5840bdbedfc38f1a7a1fa12ca217f913
> prerequisite-patch-id: dc1bb18a7b0abcc89c873c92cbaa0c819e7d2f75
> prerequisite-patch-id: 94558d950db43a1738910a115dac714aa6acf28c
> prerequisite-patch-id: ef1d6d052dcf6b09c59a4f33bc62b5d10ef6934c
> prerequisite-patch-id: f04523e6188df5873d97738401264b56c7856a5e
> prerequisite-patch-id: b29dcfd91f99e674a6c6a44bbc9ae731cdfa679a
> prerequisite-patch-id: 8ec72dae2c79435dcea21e03cb9e1d8af4cb9c8f
> prerequisite-patch-id: c8477af3ec3e2ce4edc18f25c4a3cd075f520c9e
> prerequisite-patch-id: 9b1e66062e3d140e1ab713a9418f12b69d05f348
> prerequisite-patch-id: 3e9b2900834ca0551649e5d0e60db703b2339ce3
> prerequisite-patch-id: e1139190c16ed7d345fe24b6f61804789d97136b
> prerequisite-patch-id: 37772884fa92264ee1e96a084c2c4aa7c2675fac
> prerequisite-patch-id: f49145e791089d9b4286693be26c34fd04206ad4
> prerequisite-patch-id: 0288d1bd74c2af381104866698deff464a58fe32
> prerequisite-patch-id: 5c5f12e52e580a7908aa85668547f24e13075b74
> prerequisite-patch-id: bcd7edf6a822ba1ec27ea83775c269649fe9867e
> prerequisite-patch-id: 6b06e6a7904b624a01f0527932705093ad03f04e
> prerequisite-patch-id: 18cb14dc38da7947fddd2c1ec2595b79a91b1ee6
> prerequisite-patch-id: 31e05db80c383d62653c256fe5dad591115aca02
> prerequisite-patch-id: f557102d257b1462d25e2efd6a888a38122b382e
> prerequisite-patch-id: 29d98f436c80d8f9f479ac4f740d3bc7336d1911
> prerequisite-patch-id: ac6c438f3d22fa3d33d6901db814d49da87000ed
> prerequisite-patch-id: b63bd26ef662000fdbbba0f2f37c4c12b0e810da
> prerequisite-patch-id: ecdb3fc93286e492398316909efeef7636e9d714
> prerequisite-patch-id: c20fcc41a46dbdd88e1284e30d1bbf67c22f74d5
> prerequisite-patch-id: 41a73028663bfec1efb8c9f8151aa502fdc8f4df
> prerequisite-patch-id: 5a83ebd77be51f83883719d55ffc47c5bf6504e9
> prerequisite-patch-id: a16ab1c95ccafcddf541f3cbff849709c1361575
> prerequisite-patch-id: c38880407e6b7b48304eeb4fd9c73a1f77d0bccc
> prerequisite-patch-id: 437c3b07f8942435345198ea7228345ffb45f93b
> prerequisite-patch-id: f6035754644b47cb2ec2762996ba6b9f30e3b524
> prerequisite-patch-id: 57a0094c9c14610c09f6b250c110373e6147a978
> prerequisite-patch-id: 98ec3280bedd9d8b0e143afe4b7b2da70aca0bd9
> prerequisite-patch-id: b111f940649b9f50476d3aa8ae33287ec49aa187
> prerequisite-patch-id: 63f5e18eb6dcaa3de1a8fe1307ef284858ce5770
> prerequisite-patch-id: 006a3274b20c6fcfb4ec1889736e8d4230ad08c3
> prerequisite-patch-id: af03e1494f567cbe8ad85036eb36b5dcf2db4c9e
> prerequisite-patch-id: 7caa9a2a11de82440012976f7ba8413b7c0fa8c4
> prerequisite-patch-id: 572f14be4bfd9ea9ee6a6c673479578c0961918b
> prerequisite-patch-id: 12fd4dcc561c4f59c2cbc4fe1413a1ac42a825b0
> prerequisite-patch-id: 6dfa3d5c89064a6418d76dfbe1b4ce945b2d181d
> prerequisite-patch-id: 693553d55402c2c48f089067780bb6b6074aa38f
> prerequisite-patch-id: 04fda41b3a20d00246369444e2dff458e59f4334
> prerequisite-patch-id: cf53b43828175daafa51b1df41f0414f377fc1e6
> prerequisite-patch-id: 72f021f8608a8c12c9d2ebd15e886c94e5c3efa9
> prerequisite-patch-id: 1d46aae85cfbf7c35770e86be9afd35fbed569e1
> prerequisite-patch-id: 8163eb6bd478b7fd20b67752958f106df30536c9
> prerequisite-patch-id: 91276292e9f7bbd13c9a3b30470333a607792e72
> prerequisite-patch-id: 0c6a43e5df31a48f1ed747ef4616e07b2328a515
> prerequisite-patch-id: a2f720f121dec4f8ca3a4a9ad775c123d8301987
> prerequisite-patch-id: 10027b98de8dd6a7803e68c42c8a1b2d21059df2
> prerequisite-patch-id: b094b88cb9c28f595db34a9b1bb92582cf2c12f5
> prerequisite-patch-id: bf614fe4f0c482bd7dee152a62e4133f72fa6b16
> prerequisite-patch-id: a20c3316137088e359cb18c05d046278c08ff0ce
> prerequisite-patch-id: 6d4290b6f9bb47ce2756ff1839b2ab8b71e05cb8
> prerequisite-patch-id: 00b1b2e5ee003543c3fd6233af0eefd412f05c85
> prerequisite-patch-id: 4636bd51ae1d3c28e93bf7f21b63c685991d7a42
> prerequisite-patch-id: b683c11fae0be2e4293d685f5af12b42d491846a
> prerequisite-patch-id: fa87c449d9804d90190146f08eb661ccf75d1831
> prerequisite-patch-id: 3e72b3e4632565fdda738f01e03b8e64f323e195
> prerequisite-patch-id: 8341033b66bc45ed2a65d7d2c7a8b04b02f29c77
> prerequisite-patch-id: a4f1e0828ceed6eab997a960f54495ddf2c5dec6
> prerequisite-patch-id: 4ef54c7cc50ec6f04c6a1952cfdf4abc2c21f3ae
> prerequisite-patch-id: e6ccfc53a5a26a232ebfea951fdbba5737a8bd85
> prerequisite-patch-id: 024628736045733b0ba7296a8bea5ff12e9ecefb
> prerequisite-patch-id: e733096a663be798b3833b998d2113402865b0e7
> prerequisite-patch-id: ac909c5d29b5392d77a97a684aaad284bc251f7a
> prerequisite-patch-id: 9087169f25a172a1456cfd0588f8477cf41e7f9c
> prerequisite-patch-id: d261085e2d5ead8c3903d0bb62d6d8cf40f3b1d7
> prerequisite-patch-id: 12d7a06860c78788c30d5e786ab5e34649f03f28
> prerequisite-patch-id: 6541efbc464765e94fe5dc38f6ff51711c407f1a
> prerequisite-patch-id: caa769bcaa9c23eacc143c7bbba2e30a97721ec7
> prerequisite-patch-id: f3722aa32dc9b08a6029cf1140cbbe52ef5431f2
> prerequisite-patch-id: b1c82afa4da417d603fae3fc6bf771a18d6b7f01
> prerequisite-patch-id: ec134d48661b54017798be6aad27f3a126722774
> prerequisite-patch-id: 6f0fa1e4ddfbf22540c655b083884f94206ec73d
> prerequisite-patch-id: 7ebb74f18bb200675fe1ae7de4bc09c69631dd22
> prerequisite-patch-id: 833209dd669b4339df44a5dca38c7cd83444bda7
> prerequisite-patch-id: 5f539686a9d3e1b0339bc628a824fe8acbe148a5
> prerequisite-patch-id: 64cf05912d9d3a7d62cd998167976d07e186a972
> prerequisite-patch-id: e447f01cfdb044d33b61f18a36cc553736df6ca8
> prerequisite-patch-id: d4e7b68b6bcdca90fcbc290dbde830e6b008de2b
> prerequisite-patch-id: baade8481b08945c28a747eaa70752795caa7d9a
> prerequisite-patch-id: 642c5b57222ce88b40ac11ea05f2c1999f27bc2b
> prerequisite-patch-id: 10bc753c3637c54dd3a820df9e46d4fdfbb8a62e
> prerequisite-patch-id: 37b5cbf2e9debc9834ad990d355a6c940b5f31a0
> prerequisite-patch-id: c87db141d7667ee2f197f9a197257628ddd14089
> prerequisite-patch-id: 13fe06d1de118bc1c2b3463f229fc47e129ad772
> prerequisite-patch-id: 9bed7f0777c20a9cea3d2a4566e5384be5e33bf5
> prerequisite-patch-id: 4b5605f68ac8aa7da31a88cb0be4637efda1a215
> prerequisite-patch-id: 614315a5db5ca2dcf9b4271f3321f58f616287e1
> prerequisite-patch-id: d7676a74af3b0d031287a52d85c0d4ba7c402ed4
> prerequisite-patch-id: 7920ff877e97f6e47b9ffd1734b2b00fb2bb634d
> prerequisite-patch-id: 54034059f25f9a5b962941df568dd6265b72db49
> prerequisite-patch-id: 1ea4d3e472f9beb361d8d8b939c3ba1c1f5064a5
> prerequisite-patch-id: 7c77b4e2090e09609cb9c8ce31a9cb02bced8f43
> prerequisite-patch-id: 94e92a5c7aa0fe94a446c0026dba7b5394cd726a
> prerequisite-patch-id: 392011cc99b6c007a522ecc3182b9758d288d1be
> prerequisite-patch-id: da9c970ce98552dfc6d465d3c8098da589ed28c6
> prerequisite-patch-id: 70d84fbb3eef2bb334340762b512e0d82054a9c6
> prerequisite-patch-id: 61fa61ee7bbeda03214cd4c400e8e3958071f989
> prerequisite-patch-id: 1e43c74ed90e5de4b785fc3d866b0c6d59e893de
> prerequisite-patch-id: 18b62e662bcde151676a3eb697062ce2755ba8fc
> prerequisite-patch-id: e409ebe2c5419fc1f9d3c9dd8d45c17cca7da816
> prerequisite-patch-id: 30a2de2c6b9705fe9a9b567a4a13df4bb9f50099
> prerequisite-patch-id: a5ddf715d593936c19db3bad4c0f56cb3132dc3b
> prerequisite-patch-id: e206f7013aea6de9fa0be730d6f1df9cbdfc7265
> prerequisite-patch-id: d6266e4e6cf351b0878f382e497a2fe186de758a
> prerequisite-patch-id: 9b299aa1bcd201826919971e17431f33fe9253f8
> prerequisite-patch-id: 455aa2b2a9cdb49be4103b218a9b9150f4e02be2
> prerequisite-patch-id: ca91ef160f8b46e6719735458c05b72d14c614ff
> prerequisite-patch-id: 8e7ac40a25d10b591a87c1db981efdef2a518ae0
> prerequisite-patch-id: 41a41d694a9fbf2090d5f075611306bf5d33993e
> prerequisite-patch-id: 0c66a69e6aecf739b67dc534e55495bd09cdc48a
> prerequisite-patch-id: 3a5d43c7aff536cb9a9ef3a4186a8d3a76f9fce3
> prerequisite-patch-id: efeee9a371398bad97d18eaaa95661f71399e5f0
> prerequisite-patch-id: 2ae150696995d1101021783ec3d0fdeb34a37465
> prerequisite-patch-id: 1529a93bff01a25112b03e70d5f7ab11cd41ed81
> prerequisite-patch-id: eaf2e90eb0eec7b2c2c82b4f25fa2231a93abcbc
> prerequisite-patch-id: 5f58457e8467883f4e366de55f644838e7457f12
> prerequisite-patch-id: cd68080d38cdd8139058e2ff81a9fe5d776acc15
> prerequisite-patch-id: 129418d97704fe48acc871ce47ddca4ebdb2bde1
> prerequisite-patch-id: 57cc7b35a905875e213a8d19cfa75e555ac41aae
> prerequisite-patch-id: d1b67c0e292767e81974911ccdee881c66af6e34
> prerequisite-patch-id: 5e008e064f44b31e0675d6648d8d3cdefa36da5f
> prerequisite-patch-id: c47cf0481f815b64c9264cb34bb05904e58af1bb
> prerequisite-patch-id: d88d2808ab696882e6f54cf42dddab382cc8dda7
> prerequisite-patch-id: 92528ed771c0e048656cebad644326aa7c0bdee1
> prerequisite-patch-id: 404b9c0433652a91da44d01d620f4146c65597c5
> prerequisite-patch-id: 4e27a0de44995b899ce260f395f32e91699f2d95
> prerequisite-patch-id: 2afd1e77326fd47d48b8281929384212663a6e45
> prerequisite-patch-id: 3423331a91870253afe0147cf2117fa9738b60fa
> prerequisite-patch-id: 34866d44f6c629a552c45fe2843e335707a1d91a
> prerequisite-patch-id: 79a4b09ebec7cebaee560b66e2bc0c06f181373c
> prerequisite-patch-id: 69b692b89309733438ab30577b070e0d76d9c3a4
> prerequisite-patch-id: 05b1d33293d4c84ad345a5d23cc29ce79bf971df
> prerequisite-patch-id: 33d869ed4d2e1bdb5e1067e01e6e8ee6e87c1199
> prerequisite-patch-id: 8a31aea7bc6620b0b8366085c49b1d8d3d9b8faf
> prerequisite-patch-id: 6dc6141de38f18d883c8cca856747cf61ecc91fe
> prerequisite-patch-id: 78f1f30ee92355ea18c4cb89950523d75f4e6ded
> prerequisite-patch-id: d3baf95a43ad1beacb60c83d5fa626ec5b2c0431
> prerequisite-patch-id: ff79debbd8f7568fb8897df9cd0acfbbafa8b44d
> prerequisite-patch-id: 2c139cc507e6d4ffe8f1a11894907f04ed696f85
> prerequisite-patch-id: b8fdec4277e438162ba7d644205d50e233c1882d
> prerequisite-patch-id: 5a6f2dd6cab4de9fcbdef8851a6b350abb839e9a
> prerequisite-patch-id: 332cc109d9c9ffd91ba9cf88783e75cdc0b6820c
> prerequisite-patch-id: 84c397634c0639b7898eb19b491707cdeb4353ca
> prerequisite-patch-id: e215b883d8a9b7f2072aef810b6735f7d8d3cedb
> prerequisite-patch-id: 17ddc11a0a0beb809b7c3b87fef981864b335c32
> prerequisite-patch-id: 1d7de3e0948301fd2f6faf0f46246053176b9995
> prerequisite-patch-id: 40780eaa29f2407212415641bd2708e35c466edd
> prerequisite-patch-id: 11b39dfa2b593d29dab96e644bc6f49ba56f818b
> prerequisite-patch-id: 96c5e743abe196c0188474d6c793fa16fe2aeeea
> prerequisite-patch-id: 3483ba3aa184b89b52922d5db12ab952375e5643
> prerequisite-patch-id: 14f84802e7e03fd205bed491c9307536879830c9
> prerequisite-patch-id: b48460f9f4af2ff41bbe9e664ad8a9713f6bbd10
> prerequisite-patch-id: c099dfe3484b8b6f729dda34a50d8e8ee72ef41a
> prerequisite-patch-id: ee6229d0d81a37777bc37d4a662d17105c47b492
> prerequisite-patch-id: 672de23a0227ada912aaa3d047eff73a288b33ef
> prerequisite-patch-id: b54e69accd866daa0f1ae0b8ae10ca58111b9cca
> prerequisite-patch-id: f2d9ff114f739d5e1151561271ddaceef5580996
> prerequisite-patch-id: f05fac6e3c255397c692e8790033108ac97fef45
> prerequisite-patch-id: f0968db6c59a2b9cd0d4b9997b499ee83934af9a
> prerequisite-patch-id: 41338deb5791d14f05b6587f21d66d687e324830
> prerequisite-patch-id: f838f4454fa644f49ea397f38f52d6cfe0b25c2f
> prerequisite-patch-id: 0fca9a2ce6757e1738d3f65c4749242dca910d5c
> prerequisite-patch-id: 94a83f635fafc2e78a33339370931a28c38530ad
> prerequisite-patch-id: 6a822b7354602924f998a3927323008759ce8354
> prerequisite-patch-id: 95bbb389d449f66c6438b6ede8112814ac21834c
> prerequisite-patch-id: 51f98c165b5c5fcef9c658f9bd53afbe4173f3c2
> prerequisite-patch-id: f209f1ba7251bc3224e7c4071979760243cc7ca3
> prerequisite-patch-id: 25557ef57bfd2b29e10382de4b3ff939a2ff82ba
> prerequisite-patch-id: d80be59d7d97a5844114dcd94ce02f8e7eaea45d
> prerequisite-patch-id: eb6850a91f6ee7f42af5882fc2a61d81dd027551
> prerequisite-patch-id: 3fa0758d3f6449250056c27c9ccdc9a04689dfff
> prerequisite-patch-id: 14a64f0ff9612426894de15727ad72451eeffaa6
> prerequisite-patch-id: 0a7ccdc1b90eb8aef356cc68a4f7a7ecdc097d27
> prerequisite-patch-id: dc170ac715df72bfe9e89caa49adf233a853c5da
> prerequisite-patch-id: ae8bdbce4709c319404908d6adefce1185e72928
> prerequisite-patch-id: 541a876f77d42a4a2bda6e9014989ac93862b02b
> prerequisite-patch-id: af901a08b356805e46e40d309574bf7a11d812d1
> prerequisite-patch-id: 9addfa5a4b3fe3719bf9e91f3f11393e823ba60d
> prerequisite-patch-id: d2caf6bf8184e1352da9178ed82212de01c420f3
> prerequisite-patch-id: d56e13849c721abe0d8dd325a8d66da2f1333364
> prerequisite-patch-id: 047c47b4c7d16a876364454dd2d57c1d1f550b69
> prerequisite-patch-id: 629d7044aeea72b841b8aee90fc4fe5f32112461
> prerequisite-patch-id: c69698f308b3ece9c56f5f6cefc6445410462cc9
> prerequisite-patch-id: b73314adaf43688481da0f9ee51218cf2b63812e
> prerequisite-patch-id: a007db18ef50e220b4abdae216e158ecd97faa9e
> prerequisite-patch-id: a042813060e1fd489377e0bf47c590d594dc32ff
> prerequisite-patch-id: 78d0734cbff61e6ad55a50a615ecb0048293e77b
> prerequisite-patch-id: 424430b94f460c3672bf2f17b1ded7cbda37d89a
> prerequisite-patch-id: 4f3d0fb2f636fa7ac227880cfb53a4eeb47bc58f
> prerequisite-patch-id: e8af176999d3ddc22aa52f9675e63b3a107640ed
> prerequisite-patch-id: 289f56bb20f84e820550cd69992ec9bd97f678d0
> prerequisite-patch-id: 8a4ff160663f05243458532b0f8a8e7ac64f11f6
> prerequisite-patch-id: fdd00ddec5f7109fb7ecf7dc1832b7a02ce8a651
> prerequisite-patch-id: 4b97402c818fa5bfe950b910f33d2d456a71f329
> prerequisite-patch-id: 79733734f8c9bfa323f33be23ec093dd7fe052b5
> prerequisite-patch-id: 38ea0c9a710cf18fdf89a4205e6e85e116caca4c
> prerequisite-patch-id: f29afac46f5c6d48d6d0a35b8268c75c1a63a8de
> prerequisite-patch-id: ef08e41ae63968c65b0a2ec9f1bf0bdad9f7a253
> prerequisite-patch-id: 629021de845006760688d122e49976c12b989310
> prerequisite-patch-id: 9ee25385e29e53e60439f94f4400e10e37930606
> prerequisite-patch-id: b47beae8e9d368ffaa80a09a6c8b1a0f8f11b08a
> prerequisite-patch-id: 3791b41e0f3baa853da5a2fe3a917b7d4c22bf73
> prerequisite-patch-id: 12b63e6650540f2088c5a5b77f7a98464a030fc2
> prerequisite-patch-id: f6dfa8284616df636a2511f0b80b08c3653949f0
> prerequisite-patch-id: 433c1704d3fc0de0f65b2aa03582ae0474d5c30e
> prerequisite-patch-id: 5f9834d1a44357b42ead622c48a6665912ad1209
> prerequisite-patch-id: bee05b8dd3437f877c562d921e8e229ff26e02ae
> prerequisite-patch-id: 04423c6aae615cb1d01340271fde1b456515f6cb
> prerequisite-patch-id: 04b1fb70bd82c8219fdcf7787d39605bbf314a89
> prerequisite-patch-id: cb935aa8fdc842166e53fd280d2884d1232a7e62
> prerequisite-patch-id: c62c18703342ccb60969542fec3a838952f22b33
> prerequisite-patch-id: bd8f3e84dbc2ef895f7e70b04aa8b20138def90c
> prerequisite-patch-id: 443682f4e04a5d5afcac3baa3bb58ec0b76a2986
> prerequisite-patch-id: 2afc6b752eb0cc77f90228e65ee7065174b509be
> prerequisite-patch-id: 7e3e0aa6fc0d0fb877994d0316a673f2ce494de2
> prerequisite-patch-id: 2dd0f62f6a20ceda1f75534b604030fe0b92d34b
> prerequisite-patch-id: f506d2129382ff38985a3f12a7b18b5362da71a7
> prerequisite-patch-id: 1354bf646b58990c95f04ea85784690c4c64ca1f
> prerequisite-patch-id: a1aa53f267a8ac20b4f98744b7175ed69f2ae978
> prerequisite-patch-id: 08de601794d3cca83b3470dc20c1c46e4f54c60c
> prerequisite-patch-id: 4ca8b3ceb8e1794f146e81190cb7999cb0ba9711
> prerequisite-patch-id: 7cefe1e70d3023f41995954810ec7424311fc74c
> prerequisite-patch-id: 94e7bcf4633af4b08c742953ce995aa21a01849b
> prerequisite-patch-id: 37eeba93ce17710bd33076ed8313a0f1016d021c
> prerequisite-patch-id: 905390bb71637e1761334a7965ee0b6e5bdd7531
> prerequisite-patch-id: 579d20689694657d5e4029987d5d89409f862840
> prerequisite-patch-id: 949b5ee85313910b664e640521eef26c417a9f51
> prerequisite-patch-id: cfe5ef7d5732b9e408ef4ea90bbbbd19c8970a24
> prerequisite-patch-id: d81dc1b2a538de72762563cce9fe96c06540d5b0
> prerequisite-patch-id: ea167d757bcbebbaed80405f362fae2d4e45306e
> prerequisite-patch-id: ade50c2297e855f63aeaef5374aa97d7901b991a
> prerequisite-patch-id: 06c5b5f8095bb4c1c64477aec404fca0fc51cece
> prerequisite-patch-id: 6835a19517799681dc986eaff20b22674bead33e
> prerequisite-patch-id: 098d6e7d5070fd833127325739642f30af29f88c
> prerequisite-patch-id: c5324306ff4dfc3b1f92589817f308d05f49957f
> prerequisite-patch-id: cc50d93efb7b37fdca603e1b8e9e2ef08386d830
> prerequisite-patch-id: 87757b952f3c5411747c343b0da2b297f734b0d8
> prerequisite-patch-id: f09417e50d109c347ae74e533d6ea4f279ed82b4
> prerequisite-patch-id: 2988e0da21f5e4a0e6c868933fc6a188cebdd523
> prerequisite-patch-id: 5afa6f2fc779fa72bb09e46442b95d351a063dc8
> prerequisite-patch-id: c3ea6d2d4960b1a4f4454a15680c2bec88ffe259
> prerequisite-patch-id: a520662c7fc1788ef518c958e79af5b3229ff792
> prerequisite-patch-id: 5de354fa5e2a89608f8f55725ed22891ae5e24cb
> prerequisite-patch-id: 54eaff7c3e4e113edab8198d46c18dd90d21f936
> prerequisite-patch-id: d1bc5b9d9b9372d3a072d54a7ef448d6a7b9f1af
> prerequisite-patch-id: 7e6414985fc68ad3f0d6213814f46e3e54902e9f
> prerequisite-patch-id: 39552a24f04a7b142634ce8cdd4f036bbb887a96
> prerequisite-patch-id: 64baa1fd2b3d941b8a7ec0d7c24d167e47ceccc0
> prerequisite-patch-id: f61fdd7cad4054045fc4d02086a857dc6ce9baf3
> prerequisite-patch-id: 2ccd8e7e99bfdc2e19bb403e77a35ef0baf5e810
> prerequisite-patch-id: 565a234c3fb35d612f4e20d01c093d2d844fad95
> prerequisite-patch-id: 9706d0f3578aa2afe765e47f23b381ddbf95c55c
> prerequisite-patch-id: 380d154b5a1993ee4a10d7812eb996ac3beee0f8
> prerequisite-patch-id: cf1c565fda62a2ecdcdb09bbdd7d20221e2e7c81
> prerequisite-patch-id: 346fd615602cbe3e18939d28089150abeb04cd3e
> prerequisite-patch-id: 91308baf6fe614e78267162bf09aac04896118d5
> prerequisite-patch-id: 558ffa54f22e79def34eba3227e7b7bde0553779
> prerequisite-patch-id: 15e5bcfe00f49776a0b1f8b91fc50fdc1d4072a4
> prerequisite-patch-id: 140dd85471ffa5ccdd043afce6836465a96238a1
> prerequisite-patch-id: 282e019adc7987674b4d4e823a70b5287dac2e28
> prerequisite-patch-id: 0027d2a82673b328b710cbe3e9e694285610569b
> prerequisite-patch-id: a7a325bbf7b630c990e4eabac7a4b91493361717
> prerequisite-patch-id: 67233bcf6d5a2d93593bdc56c470480eb027342d
> prerequisite-patch-id: 07982e1fafd282133c406f20eff27d0b7fab498c
> prerequisite-patch-id: bbf0c9626003eafad8c2c16a72fb95ac0bdc7d67
> prerequisite-patch-id: ad1c368efdd6356eca68bf42182f5e69b055487a
> prerequisite-patch-id: d80c1876e62fddc463561ee21590550563c52218
> prerequisite-patch-id: c488171e2a1b48aa32805a27a3c244584948bccf
> prerequisite-patch-id: e43500c23d397754174431adfcf53fecd06657c5
> prerequisite-patch-id: 9f276d666ccf0024dd50d1c2292a494574eb6935
> prerequisite-patch-id: fe1f07794ce72c9742c3a5edde4a3db5a91b70aa
> prerequisite-patch-id: e7070ad99564ab1c928056861b9a86f945fa74ef
> prerequisite-patch-id: 449ac68eeee32858e7170d1bfd059e64c9d4031c
> prerequisite-patch-id: 53fa4975acc114a8d64d2198ef39c3b0f61b7529
> prerequisite-patch-id: ce7d4c9d69af03d53b6da8662ff18be122dad115
> prerequisite-patch-id: ac19ff663849aeb5c1ad656b0b18d12717908db0
> prerequisite-patch-id: 599ee973eafe23d1f0e5acf73ec1880e9df4900f
> prerequisite-patch-id: 41c6b94eb40162d791820572f56eaf205b6e7b36
> prerequisite-patch-id: adc10c1a1ad994f547d02fea9f987ef4a69cfa2f
> prerequisite-patch-id: 3f522ca950bc68b6a3344edf5e726eca5fbb9402
> prerequisite-patch-id: 0f20be7bed01d81a5550b3cc940bddc5e570eea2
> prerequisite-patch-id: 55bd69bfb5cb5c89227268bf5b129aa8587cb90c
> prerequisite-patch-id: c9e8564d70c93eae553f775c8296e25beff9cceb
> prerequisite-patch-id: 9eaa21b37ba491a88fae54ef57c3f182b4e5ba58
> prerequisite-patch-id: d892d900b92a81dc8fa5ef8c801216e3f08b68c0
> prerequisite-patch-id: 05ed97b6d536814377e58810752b0ebe1560ac30
> prerequisite-patch-id: 06bc3a727a8006d33c965d2dd1ca4fd9e10b1044
> prerequisite-patch-id: 74ddbe407185335c57318c6c5b83c79a778762a1
> prerequisite-patch-id: 70fb3c56eea26a5165e7a42a5de78541e608dfd2
> prerequisite-patch-id: 35a6c1aeae01dcee9e3a2e68f41ded2f3cace206
> prerequisite-patch-id: 7ca502dadb86ab7b5f680e940db8e6e2de9023d8
> prerequisite-patch-id: 53ecb9365d673fccd619305b378900e18b5ffb19
> prerequisite-patch-id: 9c94d11254ffc6dfc60e35d2c6770ea7283f54ff
> prerequisite-patch-id: b764766d53848609bf36f6282055c66645461916
> prerequisite-patch-id: 8d530d4c952f2059ecd183118e1bbc0d3b180672
> prerequisite-patch-id: 0a647ccc3a322cd3b34eaa4bc1567667aaa59303
> prerequisite-patch-id: 07f7f3c08162d567cad404bb0b4f177bbb69d51f
> prerequisite-patch-id: 05bbca8d4bb046ed63e985c15e4a1f2d5d30da24
> prerequisite-patch-id: b51c7df153c0b7b394f72c9ca18225a16b29f2f9
> prerequisite-patch-id: 4e48cf7d2657fc1114467219a514e87d39bd7385
> prerequisite-patch-id: 506bb3c102944737cba45760fdf8167129b3e6e1
> prerequisite-patch-id: e5764f90d243a6cb71ab8ac654b0049f65bd5e98
> prerequisite-patch-id: e4e92a5f20f36ff721e25b2612c68651eda21f68
> prerequisite-patch-id: 5e9462934ba5d832dd9ef4b20e469414dc0012db
> prerequisite-patch-id: e192f60687873b56469bba07067ae9b7713a7d93
> prerequisite-patch-id: 92beefc48299c932373d780bdf9b0a28adcf124a
> prerequisite-patch-id: d815be0f2b1f5b250cff43a190e3d4b4150223ec
> prerequisite-patch-id: ca3776b02411fc05e006ee8355ebef716c5d3bdc
> prerequisite-patch-id: 726650d328ebeba82b020e45aba70c9dab5c011c
> prerequisite-patch-id: 8a510facb9629b418884fb295836908ad9c41538
> prerequisite-patch-id: db9740af35462466e97cb3811fda342400c93b31
> prerequisite-patch-id: f7da835561c853eaba842f6c95cb7c807df31f5e
> prerequisite-patch-id: 4e367d5e94c77c2be60ca40b15c4e4377b55b016
> prerequisite-patch-id: c408032196dc6353a978372d31623376bbb9fae2
> prerequisite-patch-id: 2c7781d40de858b34583f03f543f6e846eb5de87
> prerequisite-patch-id: c42defb7cc441fdf0ff202513ffbcd140a7aaccc
> prerequisite-patch-id: cd29918433721dbeb650644f979cd29971cdb29d
> prerequisite-patch-id: d5dca38dcd4e1765f3bfd321ab7818a7a0adac9c
> prerequisite-patch-id: 85d3579f01bafeeba6662623dc5c27501e50b4e3
> prerequisite-patch-id: b6141944ccbeb3f41a7706b7bb275aab3e59f368
> prerequisite-patch-id: 7ca22f7338dbf52dba3e30fc13e9604617bf0efc
> prerequisite-patch-id: c2c1c5117ff1afabd76d0d8faaa01ebc2ee15466
> prerequisite-patch-id: 77f5056635ebce372928d4e68bb5430b72d713e3
> prerequisite-patch-id: c95cfe8c02abd4da3984117320a1be2961256175
> prerequisite-patch-id: 45ac2515b4263dc42b518683b922c35dcb4c3a83
> prerequisite-patch-id: 1750a6d7ed3ba3351c90c778097e41cfc36a4d6c
> prerequisite-change-id: 20241022-tisci-pd-boot-state-33cf02efd378:v1
> prerequisite-patch-id: cf8fb33911aee10216167479f15b6cc301448eee
>
> Best regards,
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 57+ messages in thread