Re: [PATCH] drm/panel: Avoid warnings w/ panel-simple/panel-edp at shutdown

From: Daniel Vetter
Date: Wed Jun 12 2024 - 04:59:02 EST


On Tue, Jun 11, 2024 at 07:48:51AM -0700, Douglas Anderson wrote:
> At shutdown if you've got a _properly_ coded DRM modeset driver then
> you'll get these two warnings at shutdown time:
>
> Skipping disable of already disabled panel
> Skipping unprepare of already unprepared panel
>
> These warnings are ugly and sound concerning, but they're actually a
> sign of a properly working system. That's not great.
>
> It's not easy to get rid of these warnings. Until we know that all DRM
> modeset drivers used with panel-simple and panel-edp are properly
> calling drm_atomic_helper_shutdown() or drm_helper_force_disable_all()
> then the panel drivers _need_ to disable/unprepare themselves in order
> to power off the panel cleanly. However, there are lots of DRM modeset
> drivers used with panel-edp and panel-simple and it's hard to know
> when we've got them all. Since the warning happens only on the drivers
> that _are_ updated there's nothing to encourage broken DRM modeset
> drivers to get fixed.
>
> In order to flip the warning to the proper place, we need to know
> which modeset drivers are going to shutdown properly. Though ugly, do
> this by creating a list of everyone that shuts down properly. This
> allows us to generate a warning for the correct case and also lets us
> get rid of the warning for drivers that are shutting down properly.
>
> Maintaining this list is ugly, but the idea is that it's only short
> term. Once everyone is converted we can delete the list and call it
> done. The list is ugly enough and adding to it is annoying enough that
> people should push to make this happen.
>
> Implement this all in a shared "header" file included by the two panel
> drivers that need it. This avoids us adding an new exports while still
> allowing the panel drivers to be modules. The code waste should be
> small and, as per above, the whole solution is temporary.
>
> Signed-off-by: Douglas Anderson <dianders@xxxxxxxxxxxx>
> ---
> I came up with this idea to help us move forward since otherwise I
> couldn't see how we were ever going to fix panel-simple and panel-edp
> since they're used by so many DRM Modeset drivers. It's a bit ugly but
> I don't hate it. What do others think?

I think it's terrible :-)

Why does something like this now work?

drm_panel_shutdown_fixup(panel)
{
/* if you get warnings here, fix your main drm driver to call
* drm_atomic_helper_shutdown()
*/
if (WARN_ON(panel->enabled))
drm_panel_disable(panel);

if (WARN_ON(panel->prepared))
drm_panel_unprepare(panel);
}

And then call that little helper in the relevant panel drivers? Also feel
free to bikeshed the name and maybe put a more lengthly explainer into the
kerneldoc for that ...

Or am I completely missing the point here?
-Sima

>
> This is at the end of the series so even if folks hate it we could
> still land the rest of the series.
> This was a "bonus" extra patch I added at the end of v3 of the series
> ("drm/panel: Remove most store/double-check of prepared/enabled
> state") [1]. There, I had the note: "I came up with this idea to help
> us move forward since otherwise I couldn't see how we were ever going
> to fix panel-simple and panel-edp since they're used by so many DRM
> Modeset drivers. It's a bit ugly but I don't hate it. What do others
> think?"
>
> As requested by Neil, now that the rest of the series has landed I'm
> sending this as a standalone patch so it can get more attention. I'm
> starting it back at "v1". There is no change between v1 and the one
> sent previously except for a typo fix in an error message: Can't't =>
> Can't
>
> [1] https://lore.kernel.org/r/20240605002401.2848541-1-dianders@xxxxxxxxxxxx
>
> drivers/gpu/drm/drm_panel.c | 12 ++
> .../gpu/drm/panel/panel-drm-shutdown-check.h | 151 ++++++++++++++++++
> drivers/gpu/drm/panel/panel-edp.c | 19 +--
> drivers/gpu/drm/panel/panel-simple.c | 19 +--
> 4 files changed, 169 insertions(+), 32 deletions(-)
> create mode 100644 drivers/gpu/drm/panel/panel-drm-shutdown-check.h
>
> diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
> index cfbe020de54e..df3f15f4625e 100644
> --- a/drivers/gpu/drm/drm_panel.c
> +++ b/drivers/gpu/drm/drm_panel.c
> @@ -161,6 +161,12 @@ int drm_panel_unprepare(struct drm_panel *panel)
> if (!panel)
> return -EINVAL;
>
> + /*
> + * If you're seeing this warning, you either need to add your driver
> + * to "drm_drivers_that_shutdown" (if you're seeing it with panel-edp
> + * or panel-simple) or you need to remove the manual call to
> + * drm_panel_unprepare() in your panel driver.
> + */
> if (!panel->prepared) {
> dev_warn(panel->dev, "Skipping unprepare of already unprepared panel\n");
> return 0;
> @@ -245,6 +251,12 @@ int drm_panel_disable(struct drm_panel *panel)
> if (!panel)
> return -EINVAL;
>
> + /*
> + * If you're seeing this warning, you either need to add your driver
> + * to "drm_drivers_that_shutdown" (if you're seeing it with panel-edp
> + * or panel-simple) or you need to remove the manual call to
> + * drm_panel_disable() in your panel driver.
> + */
> if (!panel->enabled) {
> dev_warn(panel->dev, "Skipping disable of already disabled panel\n");
> return 0;
> diff --git a/drivers/gpu/drm/panel/panel-drm-shutdown-check.h b/drivers/gpu/drm/panel/panel-drm-shutdown-check.h
> new file mode 100644
> index 000000000000..dfa8197e09fb
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-drm-shutdown-check.h
> @@ -0,0 +1,151 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright 2024 Google Inc.
> + *
> + * This header is a temporary solution and is intended to be included
> + * directly by panel-edp.c and panel-simple.c.
> + *
> + * This header is needed because panel-edp and panel-simple are used by a
> + * wide variety of DRM drivers and it's hard to know for sure if all of the
> + * DRM drivers used by those panel drivers are properly calling
> + * drm_atomic_helper_shutdown() or drm_helper_force_disable_all() at
> + * shutdown/remove time.
> + *
> + * The plan for this header file:
> + * - Land it and hope that the warning print will encourage DRM drivers to
> + * get fixed.
> + * - Eventually move to a WARN() splat for extra encouragement.
> + * - Assume that everyone has been fixed and remove this header file.
> + */
> +
> +#ifndef __PANEL_DRM_SHUTDOWN_CHECK_H__
> +#define __PANEL_DRM_SHUTDOWN_CHECK_H__
> +
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_drv.h>
> +
> +/*
> + * This is a list of all DRM drivers that appear to properly call
> + * drm_atomic_helper_shutdown() or drm_helper_force_disable_all() at
> + * shutdown and remove time.
> + *
> + * We can't detect this dynamically and are stuck with a list because the panel
> + * driver's shutdown() call might be called _before_ the DRM driver's
> + * shutdown() call.
> + *
> + * NOTE: no verification has been done to confirm that the below drivers
> + * are actually _used_ with panel-simple or panel-edp, only that these drivers
> + * appear to be shutting down properly. It doesn't hurt to have extra drivers
> + * listed here as long as the list doesn't contain any drivers that are
> + * missing the shutdown calls.
> + */
> +static const char * const drm_drivers_that_shutdown[] = {
> + "armada-drm",
> + "aspeed-gfx-drm",
> + "ast",
> + "atmel-hlcdc",
> + "bochs-drm",
> + "cirrus",
> + "exynos",
> + "fsl-dcu-drm",
> + "gm12u320",
> + "gud",
> + "hdlcd",
> + "hibmc",
> + "hx8357d",
> + "hyperv_drm",
> + "ili9163",
> + "ili9225",
> + "ili9341",
> + "ili9486",
> + "imx-dcss",
> + "imx-drm",
> + "imx-lcdc",
> + "imx-lcdif",
> + "ingenic-drm",
> + "kirin",
> + "komeda",
> + "logicvc-drm",
> + "loongson",
> + "mali-dp",
> + "mcde",
> + "meson",
> + "mgag200",
> + "mi0283qt",
> + "msm",
> + "mxsfb-drm",
> + "omapdrm",
> + "panel-mipi-dbi",
> + "pl111",
> + "qxl",
> + "rcar-du",
> + "repaper",
> + "rockchip",
> + "rzg2l-du",
> + "ssd130x",
> + "st7586",
> + "st7735r",
> + "sti",
> + "stm",
> + "sun4i-drm",
> + "tidss",
> + "tilcdc",
> + "tve200",
> + "vboxvideo",
> + "zynqmp-dpsub",
> + ""
> +};
> +
> +static void panel_shutdown_if_drm_driver_needs_fixing(struct drm_panel *panel)
> +{
> + struct drm_bridge *bridge;
> + const struct drm_driver *driver;
> + const char * const *driver_name;
> +
> + /*
> + * Look for a bridge that shares the DT node of this panel. That only
> + * works if we've been linked up with a panel_bridge.
> + */
> + bridge = of_drm_find_bridge(panel->dev->of_node);
> + if (bridge && bridge->dev && bridge->dev->driver) {
> + /*
> + * If the DRM driver for the bridge is known to be fine then
> + * we're done.
> + */
> + driver = bridge->dev->driver;
> + for (driver_name = drm_drivers_that_shutdown; *driver_name; driver_name++) {
> + if (strcmp(*driver_name, driver->name) == 0)
> + return;
> + }
> +
> + /*
> + * If you see the message below then:
> + * 1. Make sure your DRM driver is properly calling
> + * drm_atomic_helper_shutdown() or drm_helper_force_disable_all()
> + * at shutdown time.
> + * 2. Add your driver to the list.
> + */
> + dev_warn(panel->dev,
> + "DRM driver appears buggy; manually disable/unprepare\n");
> + } else {
> + /*
> + * If you see the message below then your setup needs to
> + * be moved to using a panel_bridge. This often happens
> + * by calling devm_drm_of_get_bridge(). Having a panel without
> + * an associated panel_bridge is deprecated.
> + */
> + dev_warn(panel->dev,
> + "Can't find DRM driver; manually disable/unprepare\n");
> + }
> +
> + /*
> + * If we don't know if a DRM driver is properly shutting things down
> + * then we'll manually call the disable/unprepare. This is always a
> + * safe thing to do (in that it won't cause you to crash), but it
> + * does generate a warning.
> + */
> + drm_panel_disable(panel);
> + drm_panel_unprepare(panel);
> +}
> +
> +#endif
> diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c
> index 67ab6915d6e4..26f89858df9d 100644
> --- a/drivers/gpu/drm/panel/panel-edp.c
> +++ b/drivers/gpu/drm/panel/panel-edp.c
> @@ -42,6 +42,8 @@
> #include <drm/drm_edid.h>
> #include <drm/drm_panel.h>
>
> +#include "panel-drm-shutdown-check.h"
> +
> /**
> * struct panel_delay - Describes delays for a simple panel.
> */
> @@ -948,22 +950,7 @@ static void panel_edp_shutdown(struct device *dev)
> {
> struct panel_edp *panel = dev_get_drvdata(dev);
>
> - /*
> - * NOTE: the following two calls don't really belong here. It is the
> - * responsibility of a correctly written DRM modeset driver to call
> - * drm_atomic_helper_shutdown() at shutdown time and that should
> - * cause the panel to be disabled / unprepared if needed. For now,
> - * however, we'll keep these calls due to the sheer number of
> - * different DRM modeset drivers used with panel-edp. The fact that
> - * we're calling these and _also_ the drm_atomic_helper_shutdown()
> - * will try to disable/unprepare means that we can get a warning about
> - * trying to disable/unprepare an already disabled/unprepared panel,
> - * but that's something we'll have to live with until we've confirmed
> - * that all DRM modeset drivers are properly calling
> - * drm_atomic_helper_shutdown().
> - */
> - drm_panel_disable(&panel->base);
> - drm_panel_unprepare(&panel->base);
> + panel_shutdown_if_drm_driver_needs_fixing(&panel->base);
> }
>
> static void panel_edp_remove(struct device *dev)
> diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
> index 8345ed891f5a..f505bc27e5ae 100644
> --- a/drivers/gpu/drm/panel/panel-simple.c
> +++ b/drivers/gpu/drm/panel/panel-simple.c
> @@ -42,6 +42,8 @@
> #include <drm/drm_panel.h>
> #include <drm/drm_of.h>
>
> +#include "panel-drm-shutdown-check.h"
> +
> /**
> * struct panel_desc - Describes a simple panel.
> */
> @@ -720,22 +722,7 @@ static void panel_simple_shutdown(struct device *dev)
> {
> struct panel_simple *panel = dev_get_drvdata(dev);
>
> - /*
> - * NOTE: the following two calls don't really belong here. It is the
> - * responsibility of a correctly written DRM modeset driver to call
> - * drm_atomic_helper_shutdown() at shutdown time and that should
> - * cause the panel to be disabled / unprepared if needed. For now,
> - * however, we'll keep these calls due to the sheer number of
> - * different DRM modeset drivers used with panel-simple. The fact that
> - * we're calling these and _also_ the drm_atomic_helper_shutdown()
> - * will try to disable/unprepare means that we can get a warning about
> - * trying to disable/unprepare an already disabled/unprepared panel,
> - * but that's something we'll have to live with until we've confirmed
> - * that all DRM modeset drivers are properly calling
> - * drm_atomic_helper_shutdown().
> - */
> - drm_panel_disable(&panel->base);
> - drm_panel_unprepare(&panel->base);
> + panel_shutdown_if_drm_driver_needs_fixing(&panel->base);
> }
>
> static void panel_simple_remove(struct device *dev)
> --
> 2.45.2.505.gda0bf45e8d-goog
>

--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch