From: "Vivekanandan, Balasubramani" <balasubramani.vivekanandan@intel.com>
To: Gustavo Sousa <gustavo.sousa@intel.com>,
<intel-gfx@lists.freedesktop.org>,
<intel-xe@lists.freedesktop.org>
Subject: Re: [PATCH 2/4] drm/i915/dmc_wl: Add debugfs for untracked offsets
Date: Thu, 23 Jan 2025 21:41:03 +0530 [thread overview]
Message-ID: <Z5JqFwchTpIXdDbJ@bvivekan-mobl1> (raw)
In-Reply-To: <20250117220747.87927-3-gustavo.sousa@intel.com>
On 17.01.2025 19:06, Gustavo Sousa wrote:
> The DMC wakelock code needs to keep track of register offsets that need
> the wakelock for proper access. If one of the necessary offsets are
> missed, then the failure in asserting the wakelock is very likely to
> cause problems down the road.
>
> A miss could happen for at least two different reasons:
>
> - We might have forgotten to add the offset (or range) to the relevant
> tables tracked by the driver in the first place.
>
> - Or updates to either the DMC firmware or the display IP that require
> new offsets to be tracked and we fail to realize that.
>
> To help capture these cases, let's introduce a debugfs interface for the
> DMC wakelock.
>
> In this part, we export a buffer containing offsets of registers that
> were considered not needing the wakelock by our driver. In an upcoming
> change we will also allow defining an extra set of offset ranges to be
> tracked by our driver.
>
> Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
> ---
> drivers/gpu/drm/i915/Makefile | 1 +
> .../drm/i915/display/intel_display_debugfs.c | 2 +
> drivers/gpu/drm/i915/display/intel_dmc_wl.c | 5 +-
> drivers/gpu/drm/i915/display/intel_dmc_wl.h | 2 +
> .../drm/i915/display/intel_dmc_wl_debugfs.c | 251 ++++++++++++++++++
> .../drm/i915/display/intel_dmc_wl_debugfs.h | 29 ++
> drivers/gpu/drm/xe/Makefile | 1 +
> 7 files changed, 290 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/i915/display/intel_dmc_wl_debugfs.c
> create mode 100644 drivers/gpu/drm/i915/display/intel_dmc_wl_debugfs.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 3dda9f0eda82..ac1ab79de9c8 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -251,6 +251,7 @@ i915-y += \
> display/intel_display_wa.o \
> display/intel_dmc.o \
> display/intel_dmc_wl.o \
> + display/intel_dmc_wl_debugfs.o \
> display/intel_dpio_phy.o \
> display/intel_dpll.o \
> display/intel_dpll_mgr.o \
> diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> index f1d76484025a..b032535f4830 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> @@ -26,6 +26,7 @@
> #include "intel_display_power_well.h"
> #include "intel_display_types.h"
> #include "intel_dmc.h"
> +#include "intel_dmc_wl_debugfs.h"
> #include "intel_dp.h"
> #include "intel_dp_link_training.h"
> #include "intel_dp_mst.h"
> @@ -883,6 +884,7 @@ void intel_display_debugfs_register(struct drm_i915_private *i915)
>
> intel_bios_debugfs_register(display);
> intel_cdclk_debugfs_register(display);
> + intel_dmc_wl_debugfs_register(display);
> intel_dmc_debugfs_register(display);
> intel_dp_test_debugfs_register(display);
> intel_fbc_debugfs_register(display);
> diff --git a/drivers/gpu/drm/i915/display/intel_dmc_wl.c b/drivers/gpu/drm/i915/display/intel_dmc_wl.c
> index 330b43a72e08..3686d4e90167 100644
> --- a/drivers/gpu/drm/i915/display/intel_dmc_wl.c
> +++ b/drivers/gpu/drm/i915/display/intel_dmc_wl.c
> @@ -338,6 +338,7 @@ void intel_dmc_wl_init(struct intel_display *display)
> spin_lock_init(&wl->lock);
> refcount_set(&wl->refcount,
> display->params.enable_dmc_wl == ENABLE_DMC_WL_ALWAYS_LOCKED ? 1 : 0);
> + intel_dmc_wl_debugfs_init(display);
> }
>
> /* Must only be called as part of enabling dynamic DC states. */
> @@ -444,8 +445,10 @@ void intel_dmc_wl_get(struct intel_display *display, i915_reg_t reg)
> spin_lock_irqsave(&wl->lock, flags);
>
> if (i915_mmio_reg_valid(reg) &&
> - !intel_dmc_wl_check_range(display, reg, wl->dc_state))
> + !intel_dmc_wl_check_range(display, reg, wl->dc_state)) {
> + intel_dmc_wl_debugfs_log_untracked(display, i915_mmio_reg_offset(reg));
> goto out_unlock;
> + }
>
> if (!wl->enabled) {
> if (!refcount_inc_not_zero(&wl->refcount))
> diff --git a/drivers/gpu/drm/i915/display/intel_dmc_wl.h b/drivers/gpu/drm/i915/display/intel_dmc_wl.h
> index 5488fbdf29b8..d11b0ab50b3c 100644
> --- a/drivers/gpu/drm/i915/display/intel_dmc_wl.h
> +++ b/drivers/gpu/drm/i915/display/intel_dmc_wl.h
> @@ -11,6 +11,7 @@
> #include <linux/refcount.h>
>
> #include "i915_reg_defs.h"
> +#include "intel_dmc_wl_debugfs.h"
>
> struct intel_display;
>
> @@ -27,6 +28,7 @@ struct intel_dmc_wl {
> */
> u32 dc_state;
> struct delayed_work work;
> + struct intel_dmc_wl_dbg dbg;
> };
>
> void intel_dmc_wl_init(struct intel_display *display);
> diff --git a/drivers/gpu/drm/i915/display/intel_dmc_wl_debugfs.c b/drivers/gpu/drm/i915/display/intel_dmc_wl_debugfs.c
> new file mode 100644
> index 000000000000..41e59d775fe5
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_dmc_wl_debugfs.c
> @@ -0,0 +1,251 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright (C) 2025 Intel Corporation
> + */
> +
> +#include <linux/debugfs.h>
> +
> +#include <drm/drm_device.h>
> +#include <drm/drm_managed.h>
> +#include <drm/drm_print.h>
> +
> +#include "intel_display_core.h"
> +#include "intel_dmc_wl_debugfs.h"
> +
> +#define DEBUGFS_UNTRACKED_BUFFER_SIZE_MAX 65536
This macro is not actually the size but the count of offsets stored in
the buffer. This is used as the array size for drmm_kmalloc_array call.
It makes sense to rename this macro as count
> +
> +/*
> + * DOC: DMC wakelock debugfs
> + *
> + * The DMC wakelock code needs to keep track of register offsets that need the
> + * wakelock for proper access. If one of the necessary offsets are missed, then
> + * the failure in asserting the wakelock is very likely to cause problems down
> + * the road.
> + *
> + * A miss could happen for at least two different reasons:
> + *
> + * - We might have forgotten to add the offset (or range) to the relevant
> + * tables tracked by the driver in the first place.
> + *
> + * - Or updates to either the DMC firmware or the display IP that require new
> + * offsets to be tracked and we fail to realize that.
> + *
> + * To help capture these cases, we provide the intel_dmc_wl/ debugfs directory,
> + * which exports a buffer of untracked register offsets.
> + *
> + * Untracked offsets
> + * -----------------
> + *
> + * This is a buffer that records every register offset that went through the
> + * DMC wakelock check and was deemed not needing the wakelock for MMIO access.
> + *
> + * To activate the logging of offsets into such a buffer, one can do::
> + *
> + * # echo -1 > /sys/kernel/debug/dri/(...)/intel_dmc_wl/untracked_size
This knob is setting the count of offsets to be stored and not the size.
I think this should be renamed to indicate it as count.
> + *
> + * This will create a buffer with the maximum number of entries allowed
> + * (DEBUGFS_UNTRACKED_BUFFER_SIZE_MAX). A positive value can be used instead to
> + * define a different size:
> + *
> + * # echo 1024 > /sys/kernel/debug/dri/(...)/intel_dmc_wl/untracked_size
For me passing negative number doesn't look intuitive. Thinking do we
really need the case of passing default buffer size. We can allow just 0
to disable and any positive number to enable with the buffer size set as
value passed.
> + *
> + * Every write to untracked_size will cause the buffer to be reset.
> + *
> + * It is also possible to read untracked_size in order to get the current
> + * value.
> + *
> + * After enabled, the buffer starts getting filled with offsets as MMIOs are
> + * performed by the driver.
> + *
> + * In order to view the content of the buffer, one can do::
> + *
> + * # cat /sys/kernel/debug/dri/(...)/intel_dmc_wl/untracked
> + * 0x000c4000
> + * 0x0016fe50
> + * 0x000c7200
> + * 0x000c7204
> + * 0x00045230
> + * 0x00046440
> + * 0x00045234
> + * 0x0016fa48
> + * 0x0016fa40
> + * 0x0016fa5c
> + * (...)
> + *
> + * The order of those offsets does not reflect the order the checks were done
> + * (some recently seen offsets are skipped to save space).
> + *
> + * Once done with it, the logging can be disabled with::
> + *
> + * # echo 0 > /sys/kernel/debug/dri/(...)/intel_dmc_wl/untracked_size
> + */
> +
> +static int untracked_size_get(void *data, u64 *val)
> +{
> + struct intel_display *display = data;
> + struct intel_dmc_wl_dbg *dbg = &display->wl.dbg;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&dbg->lock, flags);
> + *val = dbg->untracked.size;
> + spin_unlock_irqrestore(&dbg->lock, flags);
> +
> + return 0;
> +}
> +
> +static int untracked_size_set(void *data, u64 val)
> +{
> + struct intel_display *display = data;
> + struct intel_dmc_wl_dbg *dbg = &display->wl.dbg;
> + s64 new_size;
> + u32 *old_offsets;
> + u32 *new_offsets;
> + unsigned long flags;
> +
> + new_size = (s64)val;
> +
> + if (new_size == -1) {
> + new_size = DEBUGFS_UNTRACKED_BUFFER_SIZE_MAX;
> + } else if (new_size < 0) {
> + drm_err(display->drm,
> + "%lld is invalid for untracked_size, the only negative value allowed is -1\n",
> + new_size);
> + return -EINVAL;
> + } else if (new_size > DEBUGFS_UNTRACKED_BUFFER_SIZE_MAX) {
> + drm_err(display->drm,
> + "%lld too big for untracked_size, maximum allowed value is %d\n",
> + new_size,
> + DEBUGFS_UNTRACKED_BUFFER_SIZE_MAX);
> + return -EINVAL;
> + }
> +
> + if (new_size == 0) {
> + new_offsets = NULL;
> + } else {
> + new_offsets = drmm_kmalloc_array(display->drm, new_size, sizeof(*new_offsets),
> + GFP_KERNEL);
> +
> + if (!new_offsets)
> + return -ENOMEM;
> + }
> +
> + spin_lock_irqsave(&dbg->lock, flags);
> + old_offsets = dbg->untracked.offsets;
> + dbg->untracked.offsets = new_offsets;
> + dbg->untracked.size = new_size;
> + dbg->untracked.head = 0;
> + dbg->untracked.len = 0;
> + dbg->untracked.overflow = false;
> + spin_unlock_irqrestore(&dbg->lock, flags);
> +
> + if (old_offsets)
> + drmm_kfree(display->drm, old_offsets);
> +
> + return 0;
> +}
> +
> +DEFINE_SIMPLE_ATTRIBUTE_SIGNED(untracked_size_fops,
> + untracked_size_get,
> + untracked_size_set,
> + "%lld\n");
> +
> +static int untracked_show(struct seq_file *m, void *data)
> +{
> + struct intel_display *display = m->private;
> + struct intel_dmc_wl_dbg *dbg = &display->wl.dbg;
> + unsigned long flags;
> + size_t remaining;
> + size_t i;
> +
> + spin_lock_irqsave(&dbg->lock, flags);
> +
> + remaining = dbg->untracked.len;
> + i = dbg->untracked.head;
> +
> + while (remaining--) {
> + if (i == 0)
> + i = dbg->untracked.size;
> +
> + seq_printf(m, "0x%08x\n", dbg->untracked.offsets[--i]);
> + }
> +
> + spin_unlock_irqrestore(&dbg->lock, flags);
> +
> + return 0;
> +}
> +
> +DEFINE_SHOW_ATTRIBUTE(untracked);
> +
> +void intel_dmc_wl_debugfs_init(struct intel_display *display)
> +{
> + struct intel_dmc_wl_dbg *dbg = &display->wl.dbg;
> +
> + spin_lock_init(&dbg->lock);
> +}
> +
> +void intel_dmc_wl_debugfs_register(struct intel_display *display)
> +{
> + struct dentry *dir;
> +
> + if (!HAS_DMC_WAKELOCK(display))
> + return;
> +
> + dir = debugfs_create_dir("intel_dmc_wl", display->drm->debugfs_root);
> + if (IS_ERR(dir))
> + return;
> +
> + debugfs_create_file("untracked_size", 0644, dir, display,
> + &untracked_size_fops);
> + debugfs_create_file("untracked", 0644, dir, display,
> + &untracked_fops);
> +}
> +
> +static bool untracked_has_recent_offset(struct intel_display *display, u32 offset)
> +{
> + struct intel_dmc_wl_dbg *dbg = &display->wl.dbg;
> + int look_back = 32;
Define a macro for this magic number
> + size_t i;
> +
> + if (look_back > dbg->untracked.len)
> + look_back = dbg->untracked.len;
> +
> + i = dbg->untracked.head;
> +
> + while (look_back--) {
> + if (i == 0)
> + i = dbg->untracked.size;
> +
> + if (dbg->untracked.offsets[--i] == offset)
> + return true;
> + }
> +
> + return false;
> +}
> +
> +void intel_dmc_wl_debugfs_log_untracked(struct intel_display *display, u32 offset)
> +{
> + struct intel_dmc_wl_dbg *dbg = &display->wl.dbg;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&dbg->lock, flags);
As this code never gets called by an interrupt, we can use just the
spin_lock instead of spin_lock_irqsave. Same applies for all the places
where spin_lock/unlock_irqsave/irqrestore is used.
> +
> + if (!dbg->untracked.size)
> + goto out_unlock;
> +
> + /* Save some space by not repeating recent offsets. */
> + if (untracked_has_recent_offset(display, offset))
> + goto out_unlock;
> +
> + dbg->untracked.offsets[dbg->untracked.head] = offset;
> + dbg->untracked.head = (dbg->untracked.head + 1) % dbg->untracked.size;
> + if (dbg->untracked.len < dbg->untracked.size)
> + dbg->untracked.len++;
> +
> + if (dbg->untracked.len == dbg->untracked.size && !dbg->untracked.overflow) {
> + dbg->untracked.overflow = true;
> + drm_warn(display->drm, "Overflow detected in DMC wakelock debugfs untracked offsets\n");
> + }
> +
> +out_unlock:
> + spin_unlock_irqrestore(&dbg->lock, flags);
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_dmc_wl_debugfs.h b/drivers/gpu/drm/i915/display/intel_dmc_wl_debugfs.h
> new file mode 100644
> index 000000000000..9437c324966f
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_dmc_wl_debugfs.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright (C) 2025 Intel Corporation
> + */
> +
> +#ifndef __INTEL_DMC_WL_DEBUGFS_H__
> +#define __INTEL_DMC_WL_DEBUGFS_H__
> +
> +#include <linux/types.h>
> +#include <linux/spinlock.h>
> +
> +struct intel_display;
> +
> +struct intel_dmc_wl_dbg {
> + spinlock_t lock; /* protects everything below */
> + struct {
> + u32 *offsets;
> + size_t head;
> + size_t len;
> + size_t size;
There is no need of both len and size. head will always give the count
of entries in the buffer. During overflow, we are keeping a flag to
indicate a overflow, which indicates the we also have date in the buffer
above head till the end of buffer.
Regards,
Bala
> + bool overflow;
> + } untracked;
> +};
> +
> +void intel_dmc_wl_debugfs_init(struct intel_display *display);
> +void intel_dmc_wl_debugfs_register(struct intel_display *display);
> +void intel_dmc_wl_debugfs_log_untracked(struct intel_display *display, u32 offset);
> +
> +#endif /* __INTEL_DMC_WL_DEBUGFS_H__ */
> diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
> index 81f63258a7e1..f03fbdbcb1a4 100644
> --- a/drivers/gpu/drm/xe/Makefile
> +++ b/drivers/gpu/drm/xe/Makefile
> @@ -221,6 +221,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
> i915-display/intel_display_wa.o \
> i915-display/intel_dkl_phy.o \
> i915-display/intel_dmc.o \
> + i915-display/intel_dmc_wl_debugfs.o \
> i915-display/intel_dp.o \
> i915-display/intel_dp_aux.o \
> i915-display/intel_dp_aux_backlight.o \
> --
> 2.48.0
>
next prev parent reply other threads:[~2025-01-23 16:11 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-17 22:06 [PATCH 0/4] drm/i915/dmc_wl: Introduce debugfs interface Gustavo Sousa
2025-01-17 22:06 ` [PATCH 1/4] drm/i915/dmc_wl: Pass offset instead of reg to range table iterator Gustavo Sousa
2025-01-22 8:23 ` Luca Coelho
2025-01-17 22:06 ` [PATCH 2/4] drm/i915/dmc_wl: Add debugfs for untracked offsets Gustavo Sousa
2025-01-22 9:06 ` Luca Coelho
2025-01-23 14:41 ` Gustavo Sousa
2025-01-30 9:33 ` Luca Coelho
2025-01-23 16:11 ` Vivekanandan, Balasubramani [this message]
2025-01-23 16:41 ` Gustavo Sousa
2025-01-30 8:54 ` Vivekanandan, Balasubramani
2025-01-27 9:47 ` Jani Nikula
2025-01-27 11:17 ` Gustavo Sousa
2025-01-27 11:59 ` Jani Nikula
2025-01-27 12:55 ` Gustavo Sousa
2025-01-17 22:06 ` [PATCH 3/4] drm/i915/dmc_wl: Add extra_ranges debugfs Gustavo Sousa
2025-01-22 10:19 ` Luca Coelho
2025-01-23 15:52 ` Gustavo Sousa
2025-01-30 9:18 ` Luca Coelho
2025-01-30 8:30 ` Vivekanandan, Balasubramani
2025-01-30 8:49 ` Vivekanandan, Balasubramani
2025-01-17 22:06 ` [PATCH 4/4] drm/i915/dmc_wl: Enable the debugfs only with enable_dmc_wl_debugfs=1 Gustavo Sousa
2025-01-22 10:24 ` Luca Coelho
2025-01-23 16:10 ` Gustavo Sousa
2025-01-30 9:28 ` Luca Coelho
2025-01-27 12:01 ` Jani Nikula
2025-01-27 12:02 ` Jani Nikula
2025-01-27 13:24 ` Gustavo Sousa
2025-01-27 13:35 ` Jani Nikula
2025-01-27 13:50 ` Gustavo Sousa
2025-01-27 14:40 ` Jani Nikula
2025-01-30 8:46 ` Vivekanandan, Balasubramani
2025-01-17 22:14 ` ✓ CI.Patch_applied: success for drm/i915/dmc_wl: Introduce debugfs interface Patchwork
2025-01-17 22:15 ` ✗ CI.checkpatch: warning " Patchwork
2025-01-17 22:16 ` ✓ CI.KUnit: success " Patchwork
2025-01-17 22:34 ` ✓ CI.Build: " Patchwork
2025-01-17 22:36 ` ✓ CI.Hooks: " Patchwork
2025-01-17 22:38 ` ✓ CI.checksparse: " Patchwork
2025-01-17 23:06 ` ✓ Xe.CI.BAT: " Patchwork
2025-01-17 23:15 ` ✗ Fi.CI.CHECKPATCH: warning " Patchwork
2025-01-17 23:15 ` ✗ Fi.CI.SPARSE: " Patchwork
2025-01-17 23:28 ` ✓ i915.CI.BAT: success " Patchwork
2025-01-18 13:06 ` ✗ Xe.CI.Full: failure " Patchwork
2025-01-20 12:34 ` ✗ i915.CI.Full: " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Z5JqFwchTpIXdDbJ@bvivekan-mobl1 \
--to=balasubramani.vivekanandan@intel.com \
--cc=gustavo.sousa@intel.com \
--cc=intel-gfx@lists.freedesktop.org \
--cc=intel-xe@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.