dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y
@ 2025-01-25  6:45 Jim Cromie
  2025-01-25  6:45 ` [PATCH 01/63] docs/dyndbg: update examples \012 to \n Jim Cromie
                   ` (64 more replies)
  0 siblings, 65 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

This series fixes dynamic-debug's support for DRM debug-categories.
Classmaps-v1 evaded full review, and got committed in 2 chunks:

  b7b4eebdba7b..6ea3bf466ac6	# core dyndbg changes
  0406faf25fb1..ee7d633f2dfb	# drm adoption

DRM-CI found a regression during init with drm.debug=<initval>; the
static-keys under the drm-dbgs in drm.ko got enabled, but those in
drivers & helpers did not.

Root Problem:

DECLARE_DYNDBG_CLASSMAP violated a K&R rule "define once, refer
afterwards".  Replace it with DYNDBG_CLASSMAP_DEFINE (invoked once in
drm-core) and DYNDBG_CLASSMAP_USE (invoked repeatedly, in drivers &
helpers).

_DEFINE exports the classmap it creates (in drm.ko), other modules
_USE the classmap.  The _USE adds a record ref'g the _DEFINEd (&
exported) classmap, in a 2nd __dyndbg_class_users section.

So now at modprobe, dyndbg scans the new section after the 1st
__dyndbg_class_maps section, follows the linkage to the _DEFINEr
module, finds the (optional) kernel-param controlling the classmap,
examines its drm.debug=<initval>, and applies it to the module being
initialized.

To recapitulate the multi-module problem wo DRM involvement, Add:

A. tools/testing/selftests/dynamic_debug/*

This alters pr_debugs in the test-modules, counts the results and
checks them against expectations.  It uses this formula to test most
of the control grammar, including the new class keyword.

B. test_dynamic_debug_submod.ko

This alters the test-module to build both parent & _submod ko's, with
_DEFINE and _USE inside #if/#else blocks.  This recap's DRM's 2 module
failure scenario, allowing A to exersize several cases.

The #if/#else puts the 2 macro uses together for clarity, and gives
the 2 modules identical sets of debugs.

Recent DRM-CI tests are here:
  https://patchwork.freedesktop.org/series/139147/

Previous rev:
  https://lore.kernel.org/lkml/20240716185806.1572048-1-jim.cromie@gmail.com/

Noteworthy Additions:

1- drop class "protection" special case, per JBaron's preference.
   only current use is marked BROKEN so nobody to affect.
   now framed as policy-choice:
   #define ddebug_client_module_protects_classes() false
   subsystems wanting protection can change this.

2- compile-time arg-tests in DYNDBG_CLASSMAP_DEFINE
   implement several required constraints, and fail obviously.

3- modprobe time check of conflicting class-id reservations
   only affects 2+classmaps users.
   compile-time solution not apparent.

4- dyndbg can now cause modprobe to fail.
   needed to catch 3.
   maybe some loose ends here on failure.

5- refactor & rename ddebug_attach_*module_classes
   reduce repetetive boilerplate on 2 types: maps, users.
   rework mostly brought forward in patchset to reduce churn
   TBD: maybe squash more.

Several recent trybot submissions (against drm-tip) have been passing
CI.BAT, and failing one or few CI.IGT tests randomly; re-tests do not
reliably repeat the failures.

its also at github.com:jimc/linux.git
  dd-fix-9[st]-ontip  &  dd-fix-9-13

Ive been running it on my desktop w/o issues.

The drivers/gpu/drm patches are RFC, I think there might be a single
place to call DRM_CLASSMAP_USE(drm_dedbug_classes) to replace the
sprinkling of _USEs in drivers and helpers.  IIRC, I tried adding a
_DEFINE into drm_drv.c, that didn't do it, so I punted for now.

I think the dyndbg core additions are ready for review and merging
into a (next-next) test/integration tree.

Jim Cromie (63):
  docs/dyndbg: update examples \012 to \n
  test-dyndbg: fixup CLASSMAP usage error
  dyndbg: reword "class unknown," to "class:_UNKNOWN_"
  dyndbg: make ddebug_class_param union members same size
  dyndbg: replace classmap list with a vector
  dyndbg: ddebug_apply_class_bitmap - add module arg, select on it
  dyndbg: split param_set_dyndbg_classes to _module & wrapper fns
  dyndbg: drop NUM_TYPE_ARRAY
  dyndbg: reduce verbose/debug clutter
  dyndbg: silence debugs with no-change updates
  dyndbg: tighten ddebug_class_name() 1st arg type
  dyndbg: tighten fn-sig of ddebug_apply_class_bitmap
  dyndbg: reduce verbose=3 messages in ddebug_add_module
  dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code
  checkpatch: add an exception to the do-while wrapper advice
  dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP
  dyndbg: check DYNDBG_CLASSMAP_DEFINE args at compile-time
  dyndbg: add/use for_subvec() to reduce boilerplate
  dyndbg: make proper substructs in _ddebug_info
  dyndbg: drop premature optimization in ddebug_add_module
  dyndbg: allow ddebug_add_module to fail
  dyndbg: rework ddebug_attach_*module_classes()
  dyndbg: fail modprobe on ddebug_class_range_overlap()
  dyndbg: hoist the range-overlap checks
  ddebug: cleanup-range-overlap fails
  dyndbg-test: change do_prints testpoint to accept a loopct
  selftests-dyndbg: add tools/testing/selftests/dynamic_debug/*
  dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API
  dyndbg-doc: add classmap info to howto
  dyndbg: treat comma as a token separator
  selftests-dyndbg: add comma_terminator_tests
  dyndbg: split multi-query strings with %
  selftests-dyndbg: test_percent_splitting
  docs/dyndbg: explain new delimiters: comma, percent
  selftests-dyndbg: add test_mod_submod
  docs/dyndbg: explain flags parse 1st
  dyndbg: change __dynamic_func_call_cls* macros into expressions
  dyndbg: drop "protection" of class'd pr_debugs from legacy queries
  drm: use correct ccflags-y spelling
  checkpatch: dont warn about unused macro arg on empty body
  drm-dyndbg: adapt drm core to use dyndbg classmaps-v2
  drm-dyndbg: adapt DRM to invoke DYNDBG_CLASSMAP_PARAM
  drm-print: fix config-dependent unused variable
  drm-dyndbg: DRM_CLASSMAP_USE in amdgpu driver
  drm-dyndbg: DRM_CLASSMAP_USE in i915 driver
  drm-dyndbg: DRM_CLASSMAP_USE in drm_crtc_helper
  drm-dyndbg: DRM_CLASSMAP_USE in drm_dp_helper
  drm-dyndbg: DRM_CLASSMAP_USE in nouveau
  drm-dyndbg: add DRM_CLASSMAP_USE to Xe driver
  drm-dyndbg: add DRM_CLASSMAP_USE to virtio_gpu
  drm-dyndbg: add DRM_CLASSMAP_USE to simpledrm
  drm-dyndbg: add DRM_CLASSMAP_USE to bochs
  drm-dyndbg: add DRM_CLASSMAP_USE to etnaviv
  drm-dyndbg: add DRM_CLASSMAP_USE to gma500 driver
  drm-dyndbg: add DRM_CLASSMAP_USE to radeon
  drm-dyndbg: add DRM_CLASSMAP_USE to vmwgfx driver
  drm-dyndbg: add DRM_CLASSMAP_USE to vkms driver
  drm-dyndbg: add DRM_CLASSMAP_USE to udl driver
  drm-dyndbg: add DRM_CLASSMAP_USE to mgag200 driver
  drm-dyndbg: add DRM_CLASSMAP_USE to the gud driver
  drm-dyndbg: add DRM_CLASSMAP_USE to the qxl driver
  drm-dyndbg: add DRM_CLASSMAP_USE to the drm_gem_shmem_helper driver
  drm: restore CONFIG_DRM_USE_DYNAMIC_DEBUG un-BROKEN

 .../admin-guide/dynamic-debug-howto.rst       | 116 +++-
 MAINTAINERS                                   |   3 +-
 drivers/gpu/drm/Kconfig                       |   3 +-
 drivers/gpu/drm/Makefile                      |   3 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c       |  12 +-
 drivers/gpu/drm/display/drm_dp_helper.c       |  12 +-
 drivers/gpu/drm/drm_crtc_helper.c             |  12 +-
 drivers/gpu/drm/drm_gem_shmem_helper.c        |   1 +
 drivers/gpu/drm/drm_print.c                   |  38 +-
 drivers/gpu/drm/etnaviv/etnaviv_drv.c         |   2 +
 drivers/gpu/drm/gma500/psb_drv.c              |   2 +
 drivers/gpu/drm/gud/gud_drv.c                 |   2 +
 drivers/gpu/drm/i915/i915_params.c            |  12 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c         |   2 +
 drivers/gpu/drm/nouveau/nouveau_drm.c         |  12 +-
 drivers/gpu/drm/qxl/qxl_drv.c                 |   2 +
 drivers/gpu/drm/radeon/radeon_drv.c           |   2 +
 drivers/gpu/drm/tiny/bochs.c                  |   2 +
 drivers/gpu/drm/tiny/simpledrm.c              |   2 +
 drivers/gpu/drm/udl/udl_main.c                |   2 +
 drivers/gpu/drm/virtio/virtgpu_drv.c          |   2 +
 drivers/gpu/drm/vkms/vkms_drv.c               |   2 +
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c           |   2 +
 drivers/gpu/drm/xe/xe_drm_client.c            |   2 +
 include/asm-generic/vmlinux.lds.h             |   1 +
 include/drm/drm_print.h                       |  12 +
 include/linux/dynamic_debug.h                 | 193 ++++--
 kernel/module/main.c                          |  15 +-
 lib/Kconfig.debug                             |  24 +-
 lib/Makefile                                  |   3 +
 lib/dynamic_debug.c                           | 555 +++++++++++-------
 lib/test_dynamic_debug.c                      | 181 +++---
 lib/test_dynamic_debug_submod.c               |  17 +
 scripts/checkpatch.pl                         |   3 +-
 tools/testing/selftests/Makefile              |   1 +
 .../testing/selftests/dynamic_debug/Makefile  |   9 +
 tools/testing/selftests/dynamic_debug/config  |   2 +
 .../dynamic_debug/dyndbg_selftest.sh          | 364 ++++++++++++
 38 files changed, 1205 insertions(+), 425 deletions(-)
 create mode 100644 lib/test_dynamic_debug_submod.c
 create mode 100644 tools/testing/selftests/dynamic_debug/Makefile
 create mode 100644 tools/testing/selftests/dynamic_debug/config
 create mode 100755 tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh

-- 
2.48.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH 01/63] docs/dyndbg: update examples \012 to \n
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:30   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 02/63] test-dyndbg: fixup CLASSMAP usage error Jim Cromie
                   ` (63 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

commit 47ea6f99d06e ("dyndbg: use ESCAPE_SPACE for cat control")

changed the control-file to display format strings with "\n" rather
than "\012".  Update the docs to match the new reality.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 Documentation/admin-guide/dynamic-debug-howto.rst | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
index 7c036590cd07..691e0f7d4de1 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -57,12 +57,12 @@ query/commands to the control file.  Example::
   # grease the interface
   :#> alias ddcmd='echo $* > /proc/dynamic_debug/control'
 
-  :#> ddcmd '-p; module main func run* +p'
+  :#> ddcmd '-p; module main func run* +p'	# disable all, then enable main
   :#> grep =p /proc/dynamic_debug/control
-  init/main.c:1424 [main]run_init_process =p "  with arguments:\012"
-  init/main.c:1426 [main]run_init_process =p "    %s\012"
-  init/main.c:1427 [main]run_init_process =p "  with environment:\012"
-  init/main.c:1429 [main]run_init_process =p "    %s\012"
+  init/main.c:1424 [main]run_init_process =p "  with arguments:\n"
+  init/main.c:1426 [main]run_init_process =p "    %s\n"
+  init/main.c:1427 [main]run_init_process =p "  with environment:\n"
+  init/main.c:1429 [main]run_init_process =p "    %s\n"
 
 Error messages go to console/syslog::
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 02/63] test-dyndbg: fixup CLASSMAP usage error
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
  2025-01-25  6:45 ` [PATCH 01/63] docs/dyndbg: update examples \012 to \n Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 11:22   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 03/63] dyndbg: reword "class unknown," to "class:_UNKNOWN_" Jim Cromie
                   ` (62 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

A more careful reading of logging output from test_dynamic_debug.ko
reveals:

lib/test_dynamic_debug.c:103 [test_dynamic_debug]do_cats =pmf "doing categories\n"
lib/test_dynamic_debug.c:105 [test_dynamic_debug]do_cats =p "LOW msg\n" class:MID
lib/test_dynamic_debug.c:106 [test_dynamic_debug]do_cats =p "MID msg\n" class:HI
lib/test_dynamic_debug.c:107 [test_dynamic_debug]do_cats =_ "HI msg\n" class unknown, _id:13

107 says: HI is unknown, 105,106 have LOW/MID and MID/HI skew.

The enum's 1st val (explicitly initialized) was wrong; it must be
_base, not _base+1 (a DECLARE_DYNDBG_CLASSMAP param).  So the last
enumeration exceeded the range of mapped class-id's, which triggered
the "class unknown" report.  I coded in an error, intending to verify
err detection, then forgot, and missed that it was there.

So this patch fixes a bad usage of DECLARE_DYNDBG_CLASSMAP(), showing
that it is too error-prone.  As noted in test-mod comments:

 * Using the CLASSMAP api:
 * - classmaps must have corresponding enum
 * - enum symbols must match/correlate with class-name strings in the map.
 * - base must equal enum's 1st value
 * - multiple maps must set their base to share the 0-62 class_id space !!

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/test_dynamic_debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 77c2a669b6af..396144cf351b 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -75,7 +75,7 @@ DD_SYS_WRAP(disjoint_bits, p);
 DD_SYS_WRAP(disjoint_bits, T);
 
 /* symbolic input, independent bits */
-enum cat_disjoint_names { LOW = 11, MID, HI };
+enum cat_disjoint_names { LOW = 10, MID, HI };
 DECLARE_DYNDBG_CLASSMAP(map_disjoint_names, DD_CLASS_TYPE_DISJOINT_NAMES, 10,
 			"LOW", "MID", "HI");
 DD_SYS_WRAP(disjoint_names, p);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 03/63] dyndbg: reword "class unknown," to "class:_UNKNOWN_"
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
  2025-01-25  6:45 ` [PATCH 01/63] docs/dyndbg: update examples \012 to \n Jim Cromie
  2025-01-25  6:45 ` [PATCH 02/63] test-dyndbg: fixup CLASSMAP usage error Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 11:22   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 04/63] dyndbg: make ddebug_class_param union members same size Jim Cromie
                   ` (61 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

When a dyndbg classname is unknown to a kernel module (as before
previous patch), the callsite is un-addressable via >control queries.

The control-file displays this condition as "class unknown,"
currently.  That spelling is sub-optimal/too-generic, so change it to
"class:_UNKNOWN_" to loudly announce the erroneous situation, and to
make it exceedingly greppable.

NB: pr_debugs are only alterable via >control, and to protect class'd
debug's from unintended alteration, "class name" must be given to
change them.  Classmaps map known classes to reserved .class_ids (the
1..64 val range per module).

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 5a007952f7f2..147540c57154 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1154,7 +1154,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
 		if (class)
 			seq_printf(m, " class:%s", class);
 		else
-			seq_printf(m, " class unknown, _id:%d", dp->class_id);
+			seq_printf(m, " class:_UNKNOWN_ _id:%d", dp->class_id);
 	}
 	seq_putc(m, '\n');
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 04/63] dyndbg: make ddebug_class_param union members same size
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (2 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 03/63] dyndbg: reword "class unknown," to "class:_UNKNOWN_" Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 11:24   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 05/63] dyndbg: replace classmap list with a vector Jim Cromie
                   ` (60 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

struct ddebug_class_param keeps a ref to the state-storage of the
param; make both class-types use the same unsigned long storage type.

ISTM this is simpler and safer; it avoids an irrelevant difference,
and if 2 users somehow get class-type mixed up (or refer to the wrong
union member), at least they will both see the same value.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 include/linux/dynamic_debug.h | 2 +-
 lib/dynamic_debug.c           | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index ff44ec346162..b9afc7731b7c 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -124,7 +124,7 @@ struct _ddebug_info {
 struct ddebug_class_param {
 	union {
 		unsigned long *bits;
-		unsigned int *lvl;
+		unsigned long *lvl;
 	};
 	char flags[8];
 	const struct ddebug_class_map *map;
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 147540c57154..55df35df093b 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -799,7 +799,7 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
 
 	case DD_CLASS_TYPE_LEVEL_NAMES:
 	case DD_CLASS_TYPE_LEVEL_NUM:
-		return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl);
+		return scnprintf(buffer, PAGE_SIZE, "%ld\n", *dcp->lvl);
 	default:
 		return -1;
 	}
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 05/63] dyndbg: replace classmap list with a vector
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (3 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 04/63] dyndbg: make ddebug_class_param union members same size Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:08   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 06/63] dyndbg: ddebug_apply_class_bitmap - add module arg, select on it Jim Cromie
                   ` (59 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Classmaps are stored in an elf section/array, but are individually
list-linked onto dyndbg's per-module ddebug_table for operation.

This is unnecessary; even when ddebug_attach_classmap() is handling
the builtin section (with classmaps for multiple builtin modules), its
contents are ordered, so a module's possibly multiple classmaps will
be consecutive in the section, and could be treated as a vector/block,
since both start-address and subrange length are in the ddebug_info arg.

IOW, this treats classmaps similarly to _ddebugs, which are already
kept as vector-refs (address+len).

So this changes:

struct ddebug_class_map drops list-head link.

struct ddebug_table drops the list-head maps, and gets: classes &
num_classes for the start-address and num_classes, placed to improve
struct packing.

The loading: in ddebug_attach_module_classes(), replace the
for-the-modname list-add loop, with a forloop that finds the module's
subrange (start,length) of matching classmaps within the possibly
builtin classmaps vector, and saves those to the ddebug_table.

The reading/using: change list-foreach loops in ddebug_class_name() &
ddebug_find_valid_class() to walk the array from start to length.

Also:
Move #define __outvar up, above an added use in a fn-prototype.
Simplify ddebug_attach_module_classes args, ref has both address & len.

no functional changes

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 include/linux/dynamic_debug.h |  1 -
 lib/dynamic_debug.c           | 61 ++++++++++++++++++-----------------
 2 files changed, 32 insertions(+), 30 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index b9afc7731b7c..2b0057058ecf 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -83,7 +83,6 @@ enum class_map_type {
 };
 
 struct ddebug_class_map {
-	struct list_head link;
 	struct module *mod;
 	const char *mod_name;	/* needed for builtins */
 	const char **class_names;
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 55df35df093b..41cbaa96f83d 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -45,10 +45,11 @@ extern struct ddebug_class_map __start___dyndbg_classes[];
 extern struct ddebug_class_map __stop___dyndbg_classes[];
 
 struct ddebug_table {
-	struct list_head link, maps;
+	struct list_head link;
 	const char *mod_name;
-	unsigned int num_ddebugs;
 	struct _ddebug *ddebugs;
+	struct ddebug_class_map *classes;
+	unsigned int num_ddebugs, num_classes;
 };
 
 struct ddebug_query {
@@ -147,13 +148,15 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 		  query->first_lineno, query->last_lineno, query->class_string);
 }
 
+#define __outvar /* filled by callee */
 static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
-							  const char *class_string, int *class_id)
+							const char *class_string,
+							__outvar int *class_id)
 {
 	struct ddebug_class_map *map;
-	int idx;
+	int i, idx;
 
-	list_for_each_entry(map, &dt->maps, link) {
+	for (map = dt->classes, i = 0; i < dt->num_classes; i++, map++) {
 		idx = match_string(map->class_names, map->length, class_string);
 		if (idx >= 0) {
 			*class_id = idx + map->base;
@@ -164,7 +167,6 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
 	return NULL;
 }
 
-#define __outvar /* filled by callee */
 /*
  * Search the tables for _ddebug's which match the given `query' and
  * apply the `flags' and `mask' to them.  Returns number of matching
@@ -1114,9 +1116,10 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
 
 static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp)
 {
-	struct ddebug_class_map *map;
+	struct ddebug_class_map *map = iter->table->classes;
+	int i, nc = iter->table->num_classes;
 
-	list_for_each_entry(map, &iter->table->maps, link)
+	for (i = 0; i < nc; i++, map++)
 		if (class_in_range(dp->class_id, map))
 			return map->class_names[dp->class_id - map->base];
 
@@ -1200,30 +1203,31 @@ static const struct proc_ops proc_fops = {
 	.proc_write = ddebug_proc_write
 };
 
-static void ddebug_attach_module_classes(struct ddebug_table *dt,
-					 struct ddebug_class_map *classes,
-					 int num_classes)
+static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
 {
 	struct ddebug_class_map *cm;
-	int i, j, ct = 0;
+	int i, nc = 0;
 
-	for (cm = classes, i = 0; i < num_classes; i++, cm++) {
+	/*
+	 * Find this module's classmaps in a subrange/wholerange of
+	 * the builtin/modular classmap vector/section.  Save the start
+	 * and length of the subrange at its edges.
+	 */
+	for (cm = di->classes, i = 0; i < di->num_classes; i++, cm++) {
 
 		if (!strcmp(cm->mod_name, dt->mod_name)) {
-
-			v2pr_info("class[%d]: module:%s base:%d len:%d ty:%d\n", i,
-				  cm->mod_name, cm->base, cm->length, cm->map_type);
-
-			for (j = 0; j < cm->length; j++)
-				v3pr_info(" %d: %d %s\n", j + cm->base, j,
-					  cm->class_names[j]);
-
-			list_add(&cm->link, &dt->maps);
-			ct++;
+			if (!nc) {
+				v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
+					  i, cm->mod_name, cm->base, cm->length, cm->map_type);
+				dt->classes = cm;
+			}
+			nc++;
 		}
 	}
-	if (ct)
-		vpr_info("module:%s attached %d classes\n", dt->mod_name, ct);
+	if (nc) {
+		dt->num_classes = nc;
+		vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
+	}
 }
 
 /*
@@ -1256,10 +1260,9 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 	dt->num_ddebugs = di->num_descs;
 
 	INIT_LIST_HEAD(&dt->link);
-	INIT_LIST_HEAD(&dt->maps);
 
 	if (di->classes && di->num_classes)
-		ddebug_attach_module_classes(dt, di->classes, di->num_classes);
+		ddebug_attach_module_classes(dt, di);
 
 	mutex_lock(&ddebug_lock);
 	list_add_tail(&dt->link, &ddebug_tables);
@@ -1372,8 +1375,8 @@ static void ddebug_remove_all_tables(void)
 	mutex_lock(&ddebug_lock);
 	while (!list_empty(&ddebug_tables)) {
 		struct ddebug_table *dt = list_entry(ddebug_tables.next,
-						      struct ddebug_table,
-						      link);
+						     struct ddebug_table,
+						     link);
 		ddebug_table_free(dt);
 	}
 	mutex_unlock(&ddebug_lock);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 06/63] dyndbg: ddebug_apply_class_bitmap - add module arg, select on it
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (4 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 05/63] dyndbg: replace classmap list with a vector Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:09   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 07/63] dyndbg: split param_set_dyndbg_classes to _module & wrapper fns Jim Cromie
                   ` (58 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Add param: query_module to ddebug_apply_class_bitmap(), and pass it
thru to _ddebug_queries(), replacing NULL with query_module.  This
allows its caller to update just one module, or all (as currently).

We'll use this later to propagate drm.debug to each USEr as they're
modprobed.

No functional change.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---

after `modprobe i915`, heres the module dependencies,
though not all on drm.debug.

bash-5.2# lsmod
Module                  Size  Used by
i915                 3133440  0
drm_buddy              20480  1 i915
ttm                    90112  1 i915
i2c_algo_bit           16384  1 i915
video                  61440  1 i915
wmi                    32768  1 video
drm_display_helper    200704  1 i915
drm_kms_helper        208896  2 drm_display_helper,i915
drm                   606208  5 drm_kms_helper,drm_display_helper,drm_buddy,i915,ttm
cec                    57344  2 drm_display_helper,i915
---
 lib/dynamic_debug.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 41cbaa96f83d..8adb81e75a16 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -605,7 +605,8 @@ static int ddebug_exec_queries(char *query, const char *modname)
 
 /* apply a new bitmap to the sys-knob's current bit-state */
 static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
-				     unsigned long *new_bits, unsigned long *old_bits)
+				     unsigned long *new_bits, unsigned long *old_bits,
+				     const char *query_modname)
 {
 #define QUERY_SIZE 128
 	char query[QUERY_SIZE];
@@ -613,7 +614,8 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 	int matches = 0;
 	int bi, ct;
 
-	v2pr_info("apply: 0x%lx to: 0x%lx\n", *new_bits, *old_bits);
+	v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits,
+		  query_modname ?: "");
 
 	for (bi = 0; bi < map->length; bi++) {
 		if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
@@ -622,12 +624,15 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 		snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi],
 			 test_bit(bi, new_bits) ? '+' : '-', dcp->flags);
 
-		ct = ddebug_exec_queries(query, NULL);
+		ct = ddebug_exec_queries(query, query_modname);
 		matches += ct;
 
 		v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
 			  ct, map->class_names[bi], *new_bits);
 	}
+	v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits,
+		  query_modname ?: "");
+
 	return matches;
 }
 
@@ -682,7 +687,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
 				continue;
 			}
 			curr_bits ^= BIT(cls_id);
-			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits);
+			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits, NULL);
 			*dcp->bits = curr_bits;
 			v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id,
 				  map->class_names[cls_id]);
@@ -692,7 +697,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
 			old_bits = CLASSMAP_BITMASK(*dcp->lvl);
 			curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 ));
 
-			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits);
+			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits, NULL);
 			*dcp->lvl = (cls_id + (wanted ? 1 : 0));
 			v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id,
 				  map->class_names[cls_id], old_bits, curr_bits);
@@ -755,7 +760,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
 			inrep &= CLASSMAP_BITMASK(map->length);
 		}
 		v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp));
-		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits);
+		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits, NULL);
 		*dcp->bits = inrep;
 		break;
 	case DD_CLASS_TYPE_LEVEL_NUM:
@@ -768,7 +773,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
 		old_bits = CLASSMAP_BITMASK(*dcp->lvl);
 		new_bits = CLASSMAP_BITMASK(inrep);
 		v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
-		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits);
+		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits, NULL);
 		*dcp->lvl = inrep;
 		break;
 	default:
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 07/63] dyndbg: split param_set_dyndbg_classes to _module & wrapper fns
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (5 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 06/63] dyndbg: ddebug_apply_class_bitmap - add module arg, select on it Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:09   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 08/63] dyndbg: drop NUM_TYPE_ARRAY Jim Cromie
                   ` (57 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Split api-fn: param_set_dyndbg_classes(), adding modname param and
passing NULL in from api-fn.

The new arg allows caller to specify that only one module is affected
by a prdbgs update.  This selectivity will be used later to narrow the
scope of changes made.

no functional change.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 37 ++++++++++++++++++++++---------------
 1 file changed, 22 insertions(+), 15 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 8adb81e75a16..9adcb9fa7110 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -711,18 +711,9 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
 	return 0;
 }
 
-/**
- * param_set_dyndbg_classes - class FOO >control
- * @instr: string echo>d to sysfs, input depends on map_type
- * @kp:    kp->arg has state: bits/lvl, map, map_type
- *
- * Enable/disable prdbgs by their class, as given in the arguments to
- * DECLARE_DYNDBG_CLASSMAP.  For LEVEL map-types, enforce relative
- * levels by bitpos.
- *
- * Returns: 0 or <0 if error.
- */
-int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
+static int param_set_dyndbg_module_classes(const char *instr,
+					   const struct kernel_param *kp,
+					   const char *modnm)
 {
 	const struct ddebug_class_param *dcp = kp->arg;
 	const struct ddebug_class_map *map = dcp->map;
@@ -759,8 +750,8 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
 				KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length));
 			inrep &= CLASSMAP_BITMASK(map->length);
 		}
-		v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp));
-		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits, NULL);
+		v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp));
+		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits, modnm);
 		*dcp->bits = inrep;
 		break;
 	case DD_CLASS_TYPE_LEVEL_NUM:
@@ -773,7 +764,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
 		old_bits = CLASSMAP_BITMASK(*dcp->lvl);
 		new_bits = CLASSMAP_BITMASK(inrep);
 		v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
-		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits, NULL);
+		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits, modnm);
 		*dcp->lvl = inrep;
 		break;
 	default:
@@ -782,6 +773,22 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
 	vpr_info("%s: total matches: %d\n", KP_NAME(kp), totct);
 	return 0;
 }
+
+/**
+ * param_set_dyndbg_classes - class FOO >control
+ * @instr: string echo>d to sysfs, input depends on map_type
+ * @kp:    kp->arg has state: bits/lvl, map, map_type
+ *
+ * Enable/disable prdbgs by their class, as given in the arguments to
+ * DECLARE_DYNDBG_CLASSMAP.  For LEVEL map-types, enforce relative
+ * levels by bitpos.
+ *
+ * Returns: 0 or <0 if error.
+ */
+int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
+{
+	return param_set_dyndbg_module_classes(instr, kp, NULL);
+}
 EXPORT_SYMBOL(param_set_dyndbg_classes);
 
 /**
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 08/63] dyndbg: drop NUM_TYPE_ARRAY
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (6 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 07/63] dyndbg: split param_set_dyndbg_classes to _module & wrapper fns Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:09   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 09/63] dyndbg: reduce verbose/debug clutter Jim Cromie
                   ` (56 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

ARRAY_SIZE works here, since array decl is complete.

no functional change

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 include/linux/dynamic_debug.h | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 2b0057058ecf..e458d4b838ac 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -106,11 +106,9 @@ struct ddebug_class_map {
 		.mod_name = KBUILD_MODNAME,				\
 		.base = _base,						\
 		.map_type = _maptype,					\
-		.length = NUM_TYPE_ARGS(char*, __VA_ARGS__),		\
+		.length = ARRAY_SIZE(_var##_classnames),		\
 		.class_names = _var##_classnames,			\
 	}
-#define NUM_TYPE_ARGS(eltype, ...)				\
-        (sizeof((eltype[]){__VA_ARGS__}) / sizeof(eltype))
 
 /* encapsulate linker provided built-in (or module) dyndbg data */
 struct _ddebug_info {
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 09/63] dyndbg: reduce verbose/debug clutter
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (7 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 08/63] dyndbg: drop NUM_TYPE_ARRAY Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:10   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 10/63] dyndbg: silence debugs with no-change updates Jim Cromie
                   ` (55 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

currently, for verbose=3, these are logged (blank lines for clarity):

 dyndbg: query 0: "class DRM_UT_CORE +p" mod:*
 dyndbg: split into words: "class" "DRM_UT_CORE" "+p"

 dyndbg: op='+'
 dyndbg: flags=0x1
 dyndbg: *flagsp=0x1 *maskp=0xffffffff

 dyndbg: parsed: func="" file="" module="" format="" lineno=0-0 class=...
 dyndbg: no matches for query
 dyndbg: no-match: func="" file="" module="" format="" lineno=0-0 class=...
 dyndbg: processed 1 queries, with 0 matches, 0 errs

That is excessive, so this patch:
 - shrinks 3 lines of 2nd stanza to single line
 - drops 1st 2 lines of 3rd stanza
   3rd line is like 1st, with result, not procedure.
   2nd line is just status, retold in 4th, with more info.

New output:

 dyndbg: query 0: "class DRM_UT_CORE +p" mod:*
 dyndbg: split into words: "class" "DRM_UT_CORE" "+p"
 dyndbg: op='+' flags=0x1 *flagsp=0x1 *maskp=0xffffffff
 dyndbg: no-match: func="" file="" module="" format="" lineno=0-0 class=...
 dyndbg: processed 1 queries, with 0 matches, 0 errs

no functional change.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 9adcb9fa7110..1b2fb6502e61 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -266,9 +266,6 @@ static int ddebug_change(const struct ddebug_query *query,
 	}
 	mutex_unlock(&ddebug_lock);
 
-	if (!nfound && verbose)
-		pr_info("no matches for query\n");
-
 	return nfound;
 }
 
@@ -501,7 +498,6 @@ static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
 		pr_err("bad flag-op %c, at start of %s\n", *str, str);
 		return -EINVAL;
 	}
-	v3pr_info("op='%c'\n", op);
 
 	for (; *str ; ++str) {
 		for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
@@ -515,7 +511,6 @@ static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
 			return -EINVAL;
 		}
 	}
-	v3pr_info("flags=0x%x\n", modifiers->flags);
 
 	/* calculate final flags, mask based upon op */
 	switch (op) {
@@ -531,7 +526,7 @@ static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
 		modifiers->flags = 0;
 		break;
 	}
-	v3pr_info("*flagsp=0x%x *maskp=0x%x\n", modifiers->flags, modifiers->mask);
+	v3pr_info("op='%c' flags=0x%x maskp=0x%x\n", op, modifiers->flags, modifiers->mask);
 
 	return 0;
 }
@@ -541,7 +536,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
 	struct flag_settings modifiers = {};
 	struct ddebug_query query = {};
 #define MAXWORDS 9
-	int nwords, nfound;
+	int nwords;
 	char *words[MAXWORDS];
 
 	nwords = ddebug_tokenize(query_string, words, MAXWORDS);
@@ -559,10 +554,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
 		return -EINVAL;
 	}
 	/* actually go and implement the change */
-	nfound = ddebug_change(&query, &modifiers);
-	vpr_info_dq(&query, nfound ? "applied" : "no-match");
-
-	return nfound;
+	return ddebug_change(&query, &modifiers);
 }
 
 /* handle multiple queries in query string, continue on error, return
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 10/63] dyndbg: silence debugs with no-change updates
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (8 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 09/63] dyndbg: reduce verbose/debug clutter Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:10   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 11/63] dyndbg: tighten ddebug_class_name() 1st arg type Jim Cromie
                   ` (54 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

In ddebug_apply_class_bitmap(), check for actual changes to the bits
before announcing them, to declutter logs.

no functional change.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 1b2fb6502e61..c27965180a49 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -595,7 +595,7 @@ static int ddebug_exec_queries(char *query, const char *modname)
 	return nfound;
 }
 
-/* apply a new bitmap to the sys-knob's current bit-state */
+/* apply a new class-param setting */
 static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 				     unsigned long *new_bits, unsigned long *old_bits,
 				     const char *query_modname)
@@ -606,8 +606,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 	int matches = 0;
 	int bi, ct;
 
-	v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits,
-		  query_modname ?: "");
+	if (*new_bits != *old_bits)
+		v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
+			  *old_bits, query_modname ?: "'*'");
 
 	for (bi = 0; bi < map->length; bi++) {
 		if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
@@ -622,8 +623,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 		v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
 			  ct, map->class_names[bi], *new_bits);
 	}
-	v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits,
-		  query_modname ?: "");
+	if (*new_bits != *old_bits)
+		v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
+			  *old_bits, query_modname ?: "'*'");
 
 	return matches;
 }
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 11/63] dyndbg: tighten ddebug_class_name() 1st arg type
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (9 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 10/63] dyndbg: silence debugs with no-change updates Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:11   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 12/63] dyndbg: tighten fn-sig of ddebug_apply_class_bitmap Jim Cromie
                   ` (53 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Change function's 1st arg-type, and deref in the caller.
The fn doesn't need any other fields in the struct.

no functional change.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index c27965180a49..a3849ac3be23 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1120,12 +1120,12 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
 #define class_in_range(class_id, map)					\
 	(class_id >= map->base && class_id < map->base + map->length)
 
-static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp)
+static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp)
 {
-	struct ddebug_class_map *map = iter->table->classes;
-	int i, nc = iter->table->num_classes;
+	struct ddebug_class_map *map = dt->classes;
+	int i;
 
-	for (i = 0; i < nc; i++, map++)
+	for (i = 0; i < dt->num_classes; i++, map++)
 		if (class_in_range(dp->class_id, map))
 			return map->class_names[dp->class_id - map->base];
 
@@ -1159,7 +1159,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
 	seq_putc(m, '"');
 
 	if (dp->class_id != _DPRINTK_CLASS_DFLT) {
-		class = ddebug_class_name(iter, dp);
+		class = ddebug_class_name(iter->table, dp);
 		if (class)
 			seq_printf(m, " class:%s", class);
 		else
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 12/63] dyndbg: tighten fn-sig of ddebug_apply_class_bitmap
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (10 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 11/63] dyndbg: tighten ddebug_class_name() 1st arg type Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:12   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 13/63] dyndbg: reduce verbose=3 messages in ddebug_add_module Jim Cromie
                   ` (52 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

old_bits arg is currently a pointer to the input bits, but this could
allow inadvertent changes to the input by the fn.  Disallow this.
And constify new_bits while here.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index a3849ac3be23..fc9bf5d80aa9 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -597,7 +597,8 @@ static int ddebug_exec_queries(char *query, const char *modname)
 
 /* apply a new class-param setting */
 static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
-				     unsigned long *new_bits, unsigned long *old_bits,
+				     const unsigned long *new_bits,
+				     const unsigned long old_bits,
 				     const char *query_modname)
 {
 #define QUERY_SIZE 128
@@ -606,12 +607,12 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 	int matches = 0;
 	int bi, ct;
 
-	if (*new_bits != *old_bits)
+	if (*new_bits != old_bits)
 		v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
-			  *old_bits, query_modname ?: "'*'");
+			  old_bits, query_modname ?: "'*'");
 
 	for (bi = 0; bi < map->length; bi++) {
-		if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
+		if (test_bit(bi, new_bits) == test_bit(bi, &old_bits))
 			continue;
 
 		snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi],
@@ -623,9 +624,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 		v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
 			  ct, map->class_names[bi], *new_bits);
 	}
-	if (*new_bits != *old_bits)
+	if (*new_bits != old_bits)
 		v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
-			  *old_bits, query_modname ?: "'*'");
+			  old_bits, query_modname ?: "'*'");
 
 	return matches;
 }
@@ -681,7 +682,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
 				continue;
 			}
 			curr_bits ^= BIT(cls_id);
-			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits, NULL);
+			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, *dcp->bits, NULL);
 			*dcp->bits = curr_bits;
 			v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id,
 				  map->class_names[cls_id]);
@@ -691,7 +692,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
 			old_bits = CLASSMAP_BITMASK(*dcp->lvl);
 			curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 ));
 
-			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits, NULL);
+			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, old_bits, NULL);
 			*dcp->lvl = (cls_id + (wanted ? 1 : 0));
 			v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id,
 				  map->class_names[cls_id], old_bits, curr_bits);
@@ -745,7 +746,7 @@ static int param_set_dyndbg_module_classes(const char *instr,
 			inrep &= CLASSMAP_BITMASK(map->length);
 		}
 		v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp));
-		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits, modnm);
+		totct += ddebug_apply_class_bitmap(dcp, &inrep, *dcp->bits, modnm);
 		*dcp->bits = inrep;
 		break;
 	case DD_CLASS_TYPE_LEVEL_NUM:
@@ -758,7 +759,7 @@ static int param_set_dyndbg_module_classes(const char *instr,
 		old_bits = CLASSMAP_BITMASK(*dcp->lvl);
 		new_bits = CLASSMAP_BITMASK(inrep);
 		v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
-		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits, modnm);
+		totct += ddebug_apply_class_bitmap(dcp, &new_bits, old_bits, modnm);
 		*dcp->lvl = inrep;
 		break;
 	default:
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 13/63] dyndbg: reduce verbose=3 messages in ddebug_add_module
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (11 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 12/63] dyndbg: tighten fn-sig of ddebug_apply_class_bitmap Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:12   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 14/63] dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code Jim Cromie
                   ` (51 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

When modprobing a module, dyndbg currently logs/says "add-module", and
then "skipping" if the module has no prdbgs.  Instead just check 1st
and return quietly.

no functional change

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index fc9bf5d80aa9..6bac5703dd41 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1245,11 +1245,10 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 {
 	struct ddebug_table *dt;
 
-	v3pr_info("add-module: %s.%d sites\n", modname, di->num_descs);
-	if (!di->num_descs) {
-		v3pr_info(" skip %s\n", modname);
+	if (!di->num_descs)
 		return 0;
-	}
+
+	v3pr_info("add-module: %s %d sites\n", modname, di->num_descs);
 
 	dt = kzalloc(sizeof(*dt), GFP_KERNEL);
 	if (dt == NULL) {
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 14/63] dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (12 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 13/63] dyndbg: reduce verbose=3 messages in ddebug_add_module Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 15/63] checkpatch: add an exception to the do-while wrapper advice Jim Cromie
                   ` (50 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Remove the NAMED class types; these 2 classmap types accept class
names at the PARAM interface, for example:

  echo +DRM_UT_CORE,-DRM_UT_KMS > /sys/module/drm/parameters/debug_names

The code works, but its only used by test-dynamic-debug, and wasn't
asked for by anyone else, so reduce test-surface, simplify things.

also rename enum class_map_type to enum ddebug_class_map_type.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 include/linux/dynamic_debug.h |  23 ++------
 lib/dynamic_debug.c           | 102 +++-------------------------------
 lib/test_dynamic_debug.c      |  26 ---------
 3 files changed, 14 insertions(+), 137 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index e458d4b838ac..c8102e89beb2 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -58,27 +58,16 @@ struct _ddebug {
 #endif
 } __attribute__((aligned(8)));
 
-enum class_map_type {
+enum ddebug_class_map_type {
 	DD_CLASS_TYPE_DISJOINT_BITS,
 	/**
-	 * DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, one per bit.
-	 * expecting hex input. Built for drm.debug, basis for other types.
+	 * DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, mapped to bits[0..N].
+	 * Expects hex input. Built for drm.debug, basis for other types.
 	 */
 	DD_CLASS_TYPE_LEVEL_NUM,
 	/**
-	 * DD_CLASS_TYPE_LEVEL_NUM: input is numeric level, 0-N.
-	 * N turns on just bits N-1 .. 0, so N=0 turns all bits off.
-	 */
-	DD_CLASS_TYPE_DISJOINT_NAMES,
-	/**
-	 * DD_CLASS_TYPE_DISJOINT_NAMES: input is a CSV of [+-]CLASS_NAMES,
-	 * classes are independent, like _DISJOINT_BITS.
-	 */
-	DD_CLASS_TYPE_LEVEL_NAMES,
-	/**
-	 * DD_CLASS_TYPE_LEVEL_NAMES: input is a CSV of [+-]CLASS_NAMES,
-	 * intended for names like: INFO,DEBUG,TRACE, with a module prefix
-	 * avoid EMERG,ALERT,CRIT,ERR,WARNING: they're not debug
+	 * DD_CLASS_TYPE_LEVEL_NUM: input is numeric level, 0..N.
+	 * Input N turns on bits 0..N-1
 	 */
 };
 
@@ -88,7 +77,7 @@ struct ddebug_class_map {
 	const char **class_names;
 	const int length;
 	const int base;		/* index of 1st .class_id, allows split/shared space */
-	enum class_map_type map_type;
+	enum ddebug_class_map_type map_type;
 };
 
 /**
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 6bac5703dd41..094d6e62a9d1 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -636,76 +636,6 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 
 #define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1)
 
-/* accept comma-separated-list of [+-] classnames */
-static int param_set_dyndbg_classnames(const char *instr, const struct kernel_param *kp)
-{
-	const struct ddebug_class_param *dcp = kp->arg;
-	const struct ddebug_class_map *map = dcp->map;
-	unsigned long curr_bits, old_bits;
-	char *cl_str, *p, *tmp;
-	int cls_id, totct = 0;
-	bool wanted;
-
-	cl_str = tmp = kstrdup_and_replace(instr, '\n', '\0', GFP_KERNEL);
-	if (!tmp)
-		return -ENOMEM;
-
-	/* start with previously set state-bits, then modify */
-	curr_bits = old_bits = *dcp->bits;
-	vpr_info("\"%s\" > %s:0x%lx\n", cl_str, KP_NAME(kp), curr_bits);
-
-	for (; cl_str; cl_str = p) {
-		p = strchr(cl_str, ',');
-		if (p)
-			*p++ = '\0';
-
-		if (*cl_str == '-') {
-			wanted = false;
-			cl_str++;
-		} else {
-			wanted = true;
-			if (*cl_str == '+')
-				cl_str++;
-		}
-		cls_id = match_string(map->class_names, map->length, cl_str);
-		if (cls_id < 0) {
-			pr_err("%s unknown to %s\n", cl_str, KP_NAME(kp));
-			continue;
-		}
-
-		/* have one or more valid class_ids of one *_NAMES type */
-		switch (map->map_type) {
-		case DD_CLASS_TYPE_DISJOINT_NAMES:
-			/* the +/- pertains to a single bit */
-			if (test_bit(cls_id, &curr_bits) == wanted) {
-				v3pr_info("no change on %s\n", cl_str);
-				continue;
-			}
-			curr_bits ^= BIT(cls_id);
-			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, *dcp->bits, NULL);
-			*dcp->bits = curr_bits;
-			v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id,
-				  map->class_names[cls_id]);
-			break;
-		case DD_CLASS_TYPE_LEVEL_NAMES:
-			/* cls_id = N in 0..max. wanted +/- determines N or N-1 */
-			old_bits = CLASSMAP_BITMASK(*dcp->lvl);
-			curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 ));
-
-			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, old_bits, NULL);
-			*dcp->lvl = (cls_id + (wanted ? 1 : 0));
-			v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id,
-				  map->class_names[cls_id], old_bits, curr_bits);
-			break;
-		default:
-			pr_err("illegal map-type value %d\n", map->map_type);
-		}
-	}
-	kfree(tmp);
-	vpr_info("total matches: %d\n", totct);
-	return 0;
-}
-
 static int param_set_dyndbg_module_classes(const char *instr,
 					   const struct kernel_param *kp,
 					   const char *modnm)
@@ -714,29 +644,17 @@ static int param_set_dyndbg_module_classes(const char *instr,
 	const struct ddebug_class_map *map = dcp->map;
 	unsigned long inrep, new_bits, old_bits;
 	int rc, totct = 0;
-
-	switch (map->map_type) {
-
-	case DD_CLASS_TYPE_DISJOINT_NAMES:
-	case DD_CLASS_TYPE_LEVEL_NAMES:
-		/* handle [+-]classnames list separately, we are done here */
-		return param_set_dyndbg_classnames(instr, kp);
-
-	case DD_CLASS_TYPE_DISJOINT_BITS:
-	case DD_CLASS_TYPE_LEVEL_NUM:
-		/* numeric input, accept and fall-thru */
-		rc = kstrtoul(instr, 0, &inrep);
-		if (rc) {
-			pr_err("expecting numeric input: %s > %s\n", instr, KP_NAME(kp));
-			return -EINVAL;
-		}
-		break;
-	default:
-		pr_err("%s: bad map type: %d\n", KP_NAME(kp), map->map_type);
+	char *nl;
+
+	rc = kstrtoul(instr, 0, &inrep);
+	if (rc) {
+		nl = strchr(instr, '\n');
+		if (nl)
+			*nl = '\0';
+		pr_err("expecting numeric input, not: %s > %s\n", instr, KP_NAME(kp));
 		return -EINVAL;
 	}
 
-	/* only _BITS,_NUM (numeric) map-types get here */
 	switch (map->map_type) {
 	case DD_CLASS_TYPE_DISJOINT_BITS:
 		/* expect bits. mask and warn if too many */
@@ -801,12 +719,8 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
 	const struct ddebug_class_map *map = dcp->map;
 
 	switch (map->map_type) {
-
-	case DD_CLASS_TYPE_DISJOINT_NAMES:
 	case DD_CLASS_TYPE_DISJOINT_BITS:
 		return scnprintf(buffer, PAGE_SIZE, "0x%lx\n", *dcp->bits);
-
-	case DD_CLASS_TYPE_LEVEL_NAMES:
 	case DD_CLASS_TYPE_LEVEL_NUM:
 		return scnprintf(buffer, PAGE_SIZE, "%ld\n", *dcp->lvl);
 	default:
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 396144cf351b..74d183ebf3e0 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -74,13 +74,6 @@ DECLARE_DYNDBG_CLASSMAP(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS, 0,
 DD_SYS_WRAP(disjoint_bits, p);
 DD_SYS_WRAP(disjoint_bits, T);
 
-/* symbolic input, independent bits */
-enum cat_disjoint_names { LOW = 10, MID, HI };
-DECLARE_DYNDBG_CLASSMAP(map_disjoint_names, DD_CLASS_TYPE_DISJOINT_NAMES, 10,
-			"LOW", "MID", "HI");
-DD_SYS_WRAP(disjoint_names, p);
-DD_SYS_WRAP(disjoint_names, T);
-
 /* numeric verbosity, V2 > V1 related */
 enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
 DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14,
@@ -88,13 +81,6 @@ DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14,
 DD_SYS_WRAP(level_num, p);
 DD_SYS_WRAP(level_num, T);
 
-/* symbolic verbosity */
-enum cat_level_names { L0 = 22, L1, L2, L3, L4, L5, L6, L7 };
-DECLARE_DYNDBG_CLASSMAP(map_level_names, DD_CLASS_TYPE_LEVEL_NAMES, 22,
-			"L0", "L1", "L2", "L3", "L4", "L5", "L6", "L7");
-DD_SYS_WRAP(level_names, p);
-DD_SYS_WRAP(level_names, T);
-
 /* stand-in for all pr_debug etc */
 #define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
 
@@ -102,10 +88,6 @@ static void do_cats(void)
 {
 	pr_debug("doing categories\n");
 
-	prdbg(LOW);
-	prdbg(MID);
-	prdbg(HI);
-
 	prdbg(D2_CORE);
 	prdbg(D2_DRIVER);
 	prdbg(D2_KMS);
@@ -129,14 +111,6 @@ static void do_levels(void)
 	prdbg(V5);
 	prdbg(V6);
 	prdbg(V7);
-
-	prdbg(L1);
-	prdbg(L2);
-	prdbg(L3);
-	prdbg(L4);
-	prdbg(L5);
-	prdbg(L6);
-	prdbg(L7);
 }
 
 static void do_prints(void)
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 15/63] checkpatch: add an exception to the do-while wrapper advice
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (13 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 14/63] dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:12   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 16/63] dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP Jim Cromie
                   ` (49 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie, Andy Whitcroft, Joe Perches, Dwaipayan Ray,
	Lukas Bulwahn

Several new DYNDBG_CLASSMAP_* macros (added in following commits)
expand to multi-statement declarations, like module_param_named does.
They are invoked in file-scope, not in function scope, and cannot be
wrapped by a do-while, so add an exception by name for them.

cc: Andy Whitcroft <apw@canonical.com>
cc: Joe Perches <joe@perches.com>
cc: Dwaipayan Ray <dwaipayanray1@gmail.com>
cc: Lukas Bulwahn <lukas.bulwahn@gmail.com>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 scripts/checkpatch.pl | 1 +
 1 file changed, 1 insertion(+)

diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 9eed3683ad76..4a93b2ede8cd 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -5963,6 +5963,7 @@ sub process {
 				MODULE_PARM_DESC|
 				DECLARE_PER_CPU|
 				DEFINE_PER_CPU|
+				DYNDBG_CLASSMAP|
 				__typeof__\(|
 				union|
 				struct|
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 16/63] dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (14 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 15/63] checkpatch: add an exception to the do-while wrapper advice Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:16   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 17/63] dyndbg: check DYNDBG_CLASSMAP_DEFINE args at compile-time Jim Cromie
                   ` (48 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

DECLARE_DYNDBG_CLASSMAP() has a design error; its usage fails a basic
K&R rule: "define once, refer many times".

It is used across DRM core & drivers, each use re-defines the classmap
understood by that module; and all must match for the modules to
respond together when DRM.debug categories are enabled.  This is
brittle; a maintenance foot-gun.

Further, its culpable in the CONFIG_DRM_USE_DYNAMIC_DEBUG=Y
regression; its use in both core & drivers obfuscates the 2 roles.
So 1st drm.ko loads, and dyndbg initializes its DRM.debug callsites,
then a drm-driver loads, but too late - it missed the DRM.debug
enablement.

So replace it with 2 macros:
  DYNDBG_CLASSMAP_DEFINE - invoked once from core - drm.ko
  DYNDBG_CLASSMAP_USE    - from all drm drivers and helpers.

DYNDBG_CLASSMAP_DEFINE: it just modifies DECLARE_DYNDBG_CLASSMAP,
dropping drop the static qualifier, and exports it instead.

DYNDBG_CLASSMAP_USE: then refers to the exported var by name:
  used from drivers, helper-mods
  lets us drop the repetitive "classname" declarations
  fixes 2nd-defn problem
  creates a ddebug_class_user record in new __dyndbg_class_users section
  this allows ddebug_add_module(etal) to handle users differently.

DECLARE_DYNDBG_CLASSMAP is preserved temporarily, to decouple DRM
adaptation work and avoid compile-errs before its done.  IOW, DRM gets
fixed when they commit the adopt-new-api patches, and remove the
BROKEN marking.

The DEFINE,USE distinction, and the separate classmap-use record,
allows dyndbg to initialize the driver's & helper's DRM.debug
callsites separately after each is modprobed.

Basically, the classmap init-scan is repeated for classmap-users.

To review, dyndbg's existing __dyndbg_classes[] section does:

. catalogs the classmaps defined by a module (or builtin modules)
. tells dyndbg the module has class'd prdbgs, allowing >control
. DYNDBG_CLASSMAP_DEFINE creates classmaps in this section.

This patch adds __dyndbg_class_users[] section:

. catalogs uses/references to the classmap definitions.
. authorizes dyndbg to >control those class'd prdbgs in ref'g module.
. DYNDBG_CLASSMAP_USE() creates classmap-user records in this new section.

Now ddebug_add_module(etal) can handle classmap-uses similar to (and
after) classmaps; when a dependent module is loaded, if it has
classmap-uses (to a classmap-def in another module), that module's
kernel params are scanned to find if it has a kparam that is wired to
dyndbg's param-ops, and whose classmap is the one being ref'd.

To support this, theres a few data/header changes:

new struct ddebug_class_user
  contains: user-module-name, &classmap-defn
  it records drm-driver's use of a classmap in the section, allowing lookup

struct ddebug_info gets 2 new fields for the new sections:
  class_users, num_class_users.
  set by dynamic_debug_init() for builtins.
  or by kernel/module/main:load_info() for loadable modules.

vmlinux.lds.h: new BOUNDED_SECTION for __dyndbg_class_users

dynamic_debug.c has 2 changes in ddebug_add_module(), ddebug_change():

ddebug_add_module() already calls ddebug_attach_module_classes()
to handle classmaps DEFINEd by a module, now it also calls
ddebug_attach_user_module_classes() to handle USEd classmaps.  To
avoid this work when possible, 1st scan the module's descriptors and
count the number of class'd pr_debugs.

ddebug_attach_user_module_classes() scans the module's class_users
section, follows the refs to the parent's classmap, and calls
ddebug_apply_params() on each.  It also avoids work by checking the
module's class-ct.

ddebug_apply_params(new fn):

It scans module's/builtin kernel-params, calls ddebug_match_apply_kparam
for each to find any params/sysfs-nodes which may be wired to a classmap.

ddebug_match_apply_kparam(new fn):

1st, it tests the kernel-param.ops is dyndbg's; this guarantees that
the attached arg is a struct ddebug_class_param, which has a ref to
the param's state, and to the classmap defining the param's handling.

2nd, it requires that the classmap ref'd by the kparam is the one
we're called for; modules can use many separate classmaps (as
test_dynamic_debug does).

Then apply the "parent" kparam's setting to the dependent module,
using ddebug_apply_class_bitmap().

ddebug_change(and callees) also gets adjustments:

ddebug_find_valid_class(): This does a search over the module's
classmaps, looking for the class FOO echo'd to >control.  So now it
searches over __dyndbg_class_users[] after __dyndbg_classes[].

ddebug_class_name(): return class-names for defined AND used classes.

test_dynamic_debug.c, test_dynamic_debug_submod.c:

This demonstrates the 2 types of classmaps & sysfs-params, following
the 4-part recipe:

1. define an enum for the classmap: DRM.debug has DRM_UT_{CORE,KMS,...}
   multiple classes must share 0-62 classid space.
2. DYNDBG_CLASSMAP_DEFINE(.. DRM_UT_{CORE,KMS,...})
3. DYNDBG_CLASSMAP_PARAM* (classmap)
4. DYNDBG_CLASSMAP_USE()
   by _submod only, skipping 2,3

Move all the enum declarations together, to better explain how they
share the 0..62 class-id space available to a module (non-overlapping
subranges).

reorg macros 2,3 by name.  This gives a tabular format, making it easy
to see the pattern of repetition, and the points of change.

And extend the test to replicate the 2-module (parent & dependent)
scenario which caused the CONFIG_DRM_USE_DYNAMIC_DEBUG=y regression
seen in drm & drivers.

The _submod.c is a 2-line file: #define _SUBMOD, #include parent.

This gives identical complements of prdbgs in parent & _submod, and
thus identical print behavior when all of: >control, >params, and
parent->_submod propagation are working correctly.

It also puts all the parent/_submod declarations together in the same
source, with the new ifdef _SUBMOD block invoking DYNDBG_CLASSMAP_USE
for the 2 test-interfaces.  I think this is clearer.

These 2 modules are both tristate, allowing 3 super/sub combos: Y/Y,
Y/M, M/M (not N/N).  Y/Y testing exposed a missing __align(8) in the
_METADATA macro, which M/M didn't see because the module-loader memory
placement constrains it instead.

NB: this patch ignores a checkpatch do-while warning which is fixed by
a preceding commit, which would be wrong for declarative macros like
module_param_named() etc.

Fixes: aad0214f3026 ("dyndbg: add DECLARE_DYNDBG_CLASSMAP macro")
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
v9 - commit-msg tweaks
     DRM:CHECK warnings on macros: add parens
     extern DEFINEd _var, static classnames
     change ddebug_class_user.user_mod_name to .mod_name
     simplify ddebug_find_valid_class
     improve vpr_cm_info msg format
     wrap (base) in macro body
     move __DYNDBG_CLASSMAP_CHECK above kdoc for DYNDBG_CLASSMAP_DEFINE

v8 - split drm parts to separate commits.
     preserve DECLARE_DYNDBG_CLASSMAP to decouple DRM, no flag day.
     fixup block comment

v7 - previous submission-blocking bug:

missing __align(8) in DYNAMIC_DEBUG_DECLARE_METADATA on
ddebug_class_user caused corrupt records, but only for builtin
modules; module loader code probably pinned allocations to the right
alignment naturally, hiding the bug for typical builds.

v6- get rid of WARN_ON_ONCE
v?- fix _var expanded 2x in macro

dyndbg:

This fn formerly returned the map which contained the class (thus
validating it), and as a side-effect set the class-id in an outvar.

But the caller didn't use the map (after checking its not null), only
the valid class-id.  So simplify the fn to return the class-id of the
validated classname, or -ENOENT when the queried classname is not
found.

Convey more useful info in the debug-msg: print class-names[0,last],
and [base,+len] instead of the class-type printout, which is currently
always "type:DISJOINT_BITS".  And drop ddebug_classmap_typenames,
which is now unused.

[root@v6 b0-dd]# modprobe test_dynamic_debug_submod
[   18.864962] dyndbg: loaded classmap: test_dynamic_debug [16..24] V0..V7
[   18.865046] dyndbg:  found kp:p_level_num =0x0
[   18.865048] dyndbg:   mapped to: test_dynamic_debug [16..24] V0..V7
[   18.865164] dyndbg:   p_level_num: lvl:0 bits:0x0
[   18.865217] dyndbg: loaded classmap: test_dynamic_debug [0..10] D2_CORE..D2_DRMRES
[   18.865297] dyndbg:  found kp:p_disjoint_bits =0x0
[   18.865298] dyndbg:   mapped to: test_dynamic_debug [0..10] D2_CORE..D2_DRMRES
[   18.865424] dyndbg:   p_disjoint_bits: classbits: 0x0
[   18.865472] dyndbg: module:test_dynamic_debug attached 2 classmaps
[   18.865533] dyndbg:  23 debug prints in module test_dynamic_debug
[   18.866558] dyndbg: loaded classmap: test_dynamic_debug_submod [16..24] V0..V7
[   18.866698] dyndbg:  found kp:p_level_num =0x0
[   18.866699] dyndbg:   mapped to: test_dynamic_debug_submod [16..24] V0..V7
[   18.866865] dyndbg:   p_level_num: lvl:0 bits:0x0
[   18.866926] dyndbg: loaded classmap: test_dynamic_debug_submod [0..10] D2_CORE..D2_DRMRES
[   18.867026] dyndbg:  found kp:p_disjoint_bits =0x0
[   18.867027] dyndbg:   mapped to: test_dynamic_debug_submod [0..10] D2_CORE..D2_DRMRES
[   18.867193] dyndbg:   p_disjoint_bits: classbits: 0x0
[   18.867255] dyndbg: module:test_dynamic_debug_submod attached 2 classmap uses
[   18.867351] dyndbg:  23 debug prints in module test_dynamic_debug_submod
---
 MAINTAINERS                       |   2 +-
 include/asm-generic/vmlinux.lds.h |   1 +
 include/linux/dynamic_debug.h     |  83 ++++++++++--
 kernel/module/main.c              |   3 +
 lib/Kconfig.debug                 |  24 +++-
 lib/Makefile                      |   3 +
 lib/dynamic_debug.c               | 203 ++++++++++++++++++++++++------
 lib/test_dynamic_debug.c          | 111 +++++++++++-----
 lib/test_dynamic_debug_submod.c   |  10 ++
 9 files changed, 355 insertions(+), 85 deletions(-)
 create mode 100644 lib/test_dynamic_debug_submod.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 0fa7c5728f1e..38afccb3b71e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8041,7 +8041,7 @@ M:	Jim Cromie <jim.cromie@gmail.com>
 S:	Maintained
 F:	include/linux/dynamic_debug.h
 F:	lib/dynamic_debug.c
-F:	lib/test_dynamic_debug.c
+F:	lib/test_dynamic_debug*.c
 
 DYNAMIC INTERRUPT MODERATION
 M:	Tal Gilboa <talgi@nvidia.com>
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 54504013c749..eb93fd09832b 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -366,6 +366,7 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
 	/* implement dynamic printk debug */				\
 	. = ALIGN(8);							\
 	BOUNDED_SECTION_BY(__dyndbg_classes, ___dyndbg_classes)		\
+	BOUNDED_SECTION_BY(__dyndbg_class_users, ___dyndbg_class_users)	\
 	BOUNDED_SECTION_BY(__dyndbg, ___dyndbg)				\
 	CODETAG_SECTIONS()						\
 	LIKELY_PROFILE()		       				\
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index c8102e89beb2..dc610a12b91c 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -71,9 +71,28 @@ enum ddebug_class_map_type {
 	 */
 };
 
+/*
+ * dyndbg-classmaps are devised to support DRM.debug directly:
+ *    10 enum-vals: DRM_UT_* define the categories
+ *   ~23 categorized *_dbg() macros, each passing a DRM_UT_* val as 1st arg
+ *     2 macros below them: drm_dev_dbg, __drm_dbg
+ * ~5000 calls to the categorized macros, across all of drivers/gpu/drm/
+ *
+ * When CONFIG_DRM_USE_DYNAMIC_DEBUG=y, the 2 low macros are redefined
+ * to invoke _dynamic_func_call_cls().  This compiles the category
+ * into each callsite's class_id field, where dyndbg can select on it
+ * and alter a callsite's patch-state, avoiding repeated __drm_debug
+ * checks.
+ *
+ * To make the callsites manageable from the >control file, authors
+ * provide a "classmap" of names to class_ids in use by the module(s),
+ * usually by stringifying the enum-vals.  Modules with multiple
+ * classmaps must arrange to share the 0..62 class_id space.
+ */
+
 struct ddebug_class_map {
-	struct module *mod;
-	const char *mod_name;	/* needed for builtins */
+	const struct module *mod;		/* NULL for builtins */
+	const char *mod_name;
 	const char **class_names;
 	const int length;
 	const int base;		/* index of 1st .class_id, allows split/shared space */
@@ -81,11 +100,34 @@ struct ddebug_class_map {
 };
 
 /**
- * DECLARE_DYNDBG_CLASSMAP - declare classnames known by a module
- * @_var:   a struct ddebug_class_map, passed to module_param_cb
- * @_type:  enum class_map_type, chooses bits/verbose, numeric/symbolic
- * @_base:  offset of 1st class-name. splits .class_id space
- * @classes: class-names used to control class'd prdbgs
+ * DYNDBG_CLASSMAP_DEFINE - define debug classes used by a module.
+ * @_var:   name of the classmap, exported for other modules coordinated use.
+ * @_mapty: enum ddebug_class_map_type: 0:DISJOINT - independent, 1:LEVEL - v2>v1
+ * @_base:  reserve N classids starting at _base, to split 0..62 classid space
+ * @classes: names of the N classes.
+ *
+ * This tells dyndbg what class_ids the module is using: _base..+N, by
+ * mapping names onto them.  This qualifies "class NAME" >controls on
+ * the defining module, ignoring unknown names.
+ */
+#define DYNDBG_CLASSMAP_DEFINE(_var, _mapty, _base, ...)		\
+	static const char *_var##_classnames[] = { __VA_ARGS__ };	\
+	extern struct ddebug_class_map _var;				\
+	struct ddebug_class_map __aligned(8) __used			\
+		__section("__dyndbg_classes") _var = {			\
+		.mod = THIS_MODULE,					\
+		.mod_name = KBUILD_MODNAME,				\
+		.base = (_base),					\
+		.map_type = (_mapty),					\
+		.length = ARRAY_SIZE(_var##_classnames),		\
+		.class_names = _var##_classnames,			\
+	};								\
+	EXPORT_SYMBOL(_var)
+
+/*
+ * XXX: keep this until DRM adapts to use the DEFINE/USE api, it
+ * differs from DYNDBG_CLASSMAP_DEFINE by the static replacing the
+ * extern/EXPORT on the struct init.
  */
 #define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...)		\
 	static const char *_var##_classnames[] = { __VA_ARGS__ };	\
@@ -99,12 +141,37 @@ struct ddebug_class_map {
 		.class_names = _var##_classnames,			\
 	}
 
+struct ddebug_class_user {
+	char *mod_name;
+	struct ddebug_class_map *map;
+};
+
+/**
+ * DYNDBG_CLASSMAP_USE - refer to a classmap, DEFINEd elsewhere.
+ * @_var: name of the exported classmap var
+ *
+ * This tells dyndbg that the module has prdbgs with classids defined
+ * in the named classmap.  This qualifies "class NAME" >controls on
+ * the user module, ignoring unknown names.
+ */
+#define DYNDBG_CLASSMAP_USE(_var)					\
+	DYNDBG_CLASSMAP_USE_(_var, __UNIQUE_ID(ddebug_class_user))
+#define DYNDBG_CLASSMAP_USE_(_var, _uname)				\
+	extern struct ddebug_class_map _var;				\
+	static struct ddebug_class_user __aligned(8) __used		\
+	__section("__dyndbg_class_users") _uname = {			\
+		.mod_name = KBUILD_MODNAME,				\
+		.map = &(_var),						\
+	}
+
 /* encapsulate linker provided built-in (or module) dyndbg data */
 struct _ddebug_info {
 	struct _ddebug *descs;
 	struct ddebug_class_map *classes;
+	struct ddebug_class_user *class_users;
 	unsigned int num_descs;
 	unsigned int num_classes;
+	unsigned int num_class_users;
 };
 
 struct ddebug_class_param {
@@ -205,7 +272,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
  * (|_no_desc):	former gets callsite descriptor as 1st arg (for prdbgs)
  */
 #define __dynamic_func_call_cls(id, cls, fmt, func, ...) do {	\
-	DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt);	\
+	DEFINE_DYNAMIC_DEBUG_METADATA_CLS((id), cls, fmt);	\
 	if (DYNAMIC_DEBUG_BRANCH(id))				\
 		func(&id, ##__VA_ARGS__);			\
 } while (0)
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 5399c182b3cb..c394a0c6e8c6 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2546,6 +2546,9 @@ static int find_module_sections(struct module *mod, struct load_info *info)
 	mod->dyndbg_info.classes = section_objs(info, "__dyndbg_classes",
 						sizeof(*mod->dyndbg_info.classes),
 						&mod->dyndbg_info.num_classes);
+	mod->dyndbg_info.class_users = section_objs(info, "__dyndbg_class_users",
+						    sizeof(*mod->dyndbg_info.class_users),
+						   &mod->dyndbg_info.num_class_users);
 #endif
 
 	return 0;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index f3d723705879..933f69ef87f8 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2884,12 +2884,26 @@ config TEST_STATIC_KEYS
 	  If unsure, say N.
 
 config TEST_DYNAMIC_DEBUG
-	tristate "Test DYNAMIC_DEBUG"
-	depends on DYNAMIC_DEBUG
+	tristate "Build test-dynamic-debug module"
+	depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE
 	help
-	  This module registers a tracer callback to count enabled
-	  pr_debugs in a 'do_debugging' function, then alters their
-	  enablements, calls the function, and compares counts.
+	  This module exercises/demonstrates dyndbg's classmap API, by
+	  creating 2 classes: a DISJOINT classmap (supporting DRM.debug)
+	  and a LEVELS/VERBOSE classmap (like verbose2 > verbose1).
+
+	  If unsure, say N.
+
+config TEST_DYNAMIC_DEBUG_SUBMOD
+	tristate "Build test-dynamic-debug submodule"
+	default m
+	depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE
+	depends on TEST_DYNAMIC_DEBUG
+	help
+	  This sub-module uses a classmap defined and exported by the
+	  parent module, recapitulating drm & driver's shared use of
+	  drm.debug to control enabled debug-categories.
+	  It is tristate, independent of parent, to allow testing all
+	  proper combinations of parent=y/m submod=y/m.
 
 	  If unsure, say N.
 
diff --git a/lib/Makefile b/lib/Makefile
index a8155c972f02..7f66fc1c163d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_TEST_SORT) += test_sort.o
 obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o
 obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o
 obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o
+obj-$(CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD) += test_dynamic_debug_submod.o
 obj-$(CONFIG_TEST_PRINTF) += test_printf.o
 obj-$(CONFIG_TEST_SCANF) += test_scanf.o
 
@@ -228,6 +229,8 @@ obj-$(CONFIG_ARCH_NEED_CMPXCHG_1_EMU) += cmpxchg-emu.o
 obj-$(CONFIG_DYNAMIC_DEBUG_CORE) += dynamic_debug.o
 #ensure exported functions have prototypes
 CFLAGS_dynamic_debug.o := -DDYNAMIC_DEBUG_MODULE
+CFLAGS_test_dynamic_debug.o := -DDYNAMIC_DEBUG_MODULE
+CFLAGS_test_dynamic_debug_submod.o := -DDYNAMIC_DEBUG_MODULE
 
 obj-$(CONFIG_SYMBOLIC_ERRNAME) += errname.o
 
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 094d6e62a9d1..6bca0c6727d4 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -43,13 +43,16 @@ extern struct _ddebug __start___dyndbg[];
 extern struct _ddebug __stop___dyndbg[];
 extern struct ddebug_class_map __start___dyndbg_classes[];
 extern struct ddebug_class_map __stop___dyndbg_classes[];
+extern struct ddebug_class_user __start___dyndbg_class_users[];
+extern struct ddebug_class_user __stop___dyndbg_class_users[];
 
 struct ddebug_table {
 	struct list_head link;
 	const char *mod_name;
 	struct _ddebug *ddebugs;
 	struct ddebug_class_map *classes;
-	unsigned int num_ddebugs, num_classes;
+	struct ddebug_class_user *class_users;
+	unsigned int num_ddebugs, num_classes, num_class_users;
 };
 
 struct ddebug_query {
@@ -148,23 +151,35 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 		  query->first_lineno, query->last_lineno, query->class_string);
 }
 
-#define __outvar /* filled by callee */
-static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
-							const char *class_string,
-							__outvar int *class_id)
+#define vpr_dt_info(dt_p, msg_p, ...) ({				\
+	struct ddebug_table const *_dt = dt_p;				\
+	v2pr_info(msg_p " module:%s nd:%d nc:%d nu:%d\n", ##__VA_ARGS__, \
+		  _dt->mod_name, _dt->num_ddebugs, _dt->num_classes,	\
+		  _dt->num_class_users);				\
+	})
+
+static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *class_string)
 {
 	struct ddebug_class_map *map;
+	struct ddebug_class_user *cli;
 	int i, idx;
 
-	for (map = dt->classes, i = 0; i < dt->num_classes; i++, map++) {
+	for (i = 0, map = dt->classes; i < dt->num_classes; i++, map++) {
 		idx = match_string(map->class_names, map->length, class_string);
 		if (idx >= 0) {
-			*class_id = idx + map->base;
-			return map;
+			vpr_dt_info(dt, "good-class: %s.%s ", map->mod_name, class_string);
+			return idx + map->base;
 		}
 	}
-	*class_id = -ENOENT;
-	return NULL;
+	for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++) {
+		idx = match_string(cli->map->class_names, cli->map->length, class_string);
+		if (idx >= 0) {
+			vpr_dt_info(dt, "class-ref: %s -> %s.%s ",
+				    cli->mod_name, cli->map->mod_name, class_string);
+			return idx + cli->map->base;
+		}
+	}
+	return -ENOENT;
 }
 
 /*
@@ -173,16 +188,14 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
  * callsites, normally the same as number of changes.  If verbose,
  * logs the changes.  Takes ddebug_lock.
  */
-static int ddebug_change(const struct ddebug_query *query,
-			 struct flag_settings *modifiers)
+static int ddebug_change(const struct ddebug_query *query, struct flag_settings *modifiers)
 {
 	int i;
 	struct ddebug_table *dt;
 	unsigned int newflags;
 	unsigned int nfound = 0;
 	struct flagsbuf fbuf, nbuf;
-	struct ddebug_class_map *map = NULL;
-	int __outvar valid_class;
+	int valid_class;
 
 	/* search for matching ddebugs */
 	mutex_lock(&ddebug_lock);
@@ -194,8 +207,8 @@ static int ddebug_change(const struct ddebug_query *query,
 			continue;
 
 		if (query->class_string) {
-			map = ddebug_find_valid_class(dt, query->class_string, &valid_class);
-			if (!map)
+			valid_class = ddebug_find_valid_class(dt, query->class_string);
+			if (valid_class < 0)
 				continue;
 		} else {
 			/* constrain query, do not touch class'd callsites */
@@ -559,7 +572,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
 
 /* handle multiple queries in query string, continue on error, return
    last error or number of matching callsites.  Module name is either
-   in param (for boot arg) or perhaps in query string.
+   in the modname arg (for boot args) or perhaps in query string.
 */
 static int ddebug_exec_queries(char *query, const char *modname)
 {
@@ -688,12 +701,12 @@ static int param_set_dyndbg_module_classes(const char *instr,
 }
 
 /**
- * param_set_dyndbg_classes - class FOO >control
+ * param_set_dyndbg_classes - set all classes in a classmap
  * @instr: string echo>d to sysfs, input depends on map_type
- * @kp:    kp->arg has state: bits/lvl, map, map_type
+ * @kp:    kp->arg has state: bits/lvl, classmap, map_type
  *
- * Enable/disable prdbgs by their class, as given in the arguments to
- * DECLARE_DYNDBG_CLASSMAP.  For LEVEL map-types, enforce relative
+ * For all classes in the classmap, enable/disable them per the input
+ * (depending on map_type).  For LEVEL map-types, enforce relative
  * levels by bitpos.
  *
  * Returns: 0 or <0 if error.
@@ -1038,12 +1051,17 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
 static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp)
 {
 	struct ddebug_class_map *map = dt->classes;
+	struct ddebug_class_user *cli = dt->class_users;
 	int i;
 
 	for (i = 0; i < dt->num_classes; i++, map++)
 		if (class_in_range(dp->class_id, map))
 			return map->class_names[dp->class_id - map->base];
 
+	for (i = 0; i < dt->num_class_users; i++, cli++)
+		if (class_in_range(dp->class_id, cli->map))
+			return cli->map->class_names[dp->class_id - cli->map->base];
+
 	return NULL;
 }
 
@@ -1124,31 +1142,129 @@ static const struct proc_ops proc_fops = {
 	.proc_write = ddebug_proc_write
 };
 
-static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
+#define vpr_cm_info(cm_p, msg_fmt, ...) ({				\
+	struct ddebug_class_map const *_cm = cm_p;			\
+	v2pr_info(msg_fmt " %s [%d..%d] %s..%s\n", ##__VA_ARGS__,	\
+		  _cm->mod_name, _cm->base, _cm->base + _cm->length,	\
+		  _cm->class_names[0], _cm->class_names[_cm->length - 1]); \
+	})
+
+static void ddebug_sync_classbits(const struct kernel_param *kp, const char *modname)
+{
+	const struct ddebug_class_param *dcp = kp->arg;
+
+	/* clamp initial bitvec, mask off hi-bits */
+	if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) {
+		*dcp->bits &= CLASSMAP_BITMASK(dcp->map->length);
+		v2pr_info("preset classbits: %lx\n", *dcp->bits);
+	}
+	/* force class'd prdbgs (in USEr module) to match (DEFINEr module) class-param */
+	ddebug_apply_class_bitmap(dcp, dcp->bits, ~0, modname);
+	ddebug_apply_class_bitmap(dcp, dcp->bits, 0, modname);
+}
+
+static void ddebug_match_apply_kparam(const struct kernel_param *kp,
+				      const struct ddebug_class_map *map,
+				      const char *modnm)
+{
+	struct ddebug_class_param *dcp;
+
+	if (kp->ops != &param_ops_dyndbg_classes)
+		return;
+
+	dcp = (struct ddebug_class_param *)kp->arg;
+
+	if (map == dcp->map) {
+		v2pr_info(" kp:%s.%s =0x%lx", modnm, kp->name, *dcp->bits);
+		vpr_cm_info(map, " %s mapped to: ", modnm);
+		ddebug_sync_classbits(kp, modnm);
+	}
+}
+
+static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *modnm)
+{
+	const struct kernel_param *kp;
+#if IS_ENABLED(CONFIG_MODULES)
+	int i;
+
+	if (cm->mod) {
+		vpr_cm_info(cm, "loaded classmap: %s", modnm);
+		/* ifdef protects the cm->mod->kp deref */
+		for (i = 0, kp = cm->mod->kp; i < cm->mod->num_kp; i++, kp++)
+			ddebug_match_apply_kparam(kp, cm, modnm);
+	}
+#endif
+	if (!cm->mod) {
+		vpr_cm_info(cm, "builtin classmap: %s", modnm);
+		for (kp = __start___param; kp < __stop___param; kp++)
+			ddebug_match_apply_kparam(kp, cm, modnm);
+	}
+}
+
+/*
+ * Find this module's classmaps in a sub/whole-range of the builtin/
+ * modular classmap vector/section.  Save the start and length of the
+ * subrange at its edges.
+ */
+static void ddebug_attach_module_classes(struct ddebug_table *dt,
+					 const struct _ddebug_info *di)
 {
 	struct ddebug_class_map *cm;
 	int i, nc = 0;
 
-	/*
-	 * Find this module's classmaps in a subrange/wholerange of
-	 * the builtin/modular classmap vector/section.  Save the start
-	 * and length of the subrange at its edges.
-	 */
-	for (cm = di->classes, i = 0; i < di->num_classes; i++, cm++) {
-
+	for (i = 0, cm = di->classes; i < di->num_classes; i++, cm++) {
 		if (!strcmp(cm->mod_name, dt->mod_name)) {
-			if (!nc) {
-				v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
-					  i, cm->mod_name, cm->base, cm->length, cm->map_type);
+			vpr_cm_info(cm, "classes[%d]:", i);
+			if (!nc++)
 				dt->classes = cm;
-			}
-			nc++;
 		}
 	}
-	if (nc) {
-		dt->num_classes = nc;
-		vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
+	if (!nc)
+		return;
+
+	vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
+	dt->num_classes = nc;
+
+	for (i = 0, cm = dt->classes; i < dt->num_classes; i++, cm++)
+		ddebug_apply_params(cm, cm->mod_name);
+}
+
+/*
+ * propagates class-params thru their classmaps to class-users.  this
+ * means a query against the dt/module, which means it must be on the
+ * list to be seen by ddebug_change.
+ */
+static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
+					      const struct _ddebug_info *di)
+{
+	struct ddebug_class_user *cli;
+	int i, nc = 0;
+
+	/*
+	 * For builtins: scan the array, find start/length of this
+	 * module's refs, save to dt.  For loadables, this is the
+	 * whole array.
+	 */
+	for (i = 0, cli = di->class_users; i < di->num_class_users; i++, cli++) {
+		if (WARN_ON_ONCE(!cli || !cli->map || !cli->mod_name))
+			continue;
+		if (!strcmp(cli->mod_name, dt->mod_name)) {
+			vpr_cm_info(cli->map, "class_ref[%d] %s -> %s", i,
+				    cli->mod_name, cli->map->mod_name);
+			if (!nc++)
+				dt->class_users = cli;
+		}
 	}
+	if (!nc)
+		return;
+
+	dt->num_class_users = nc;
+
+	/* now iterate dt */
+	for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++)
+		ddebug_apply_params(cli->map, cli->mod_name);
+
+	vpr_dt_info(dt, "attach-client-module: ");
 }
 
 /*
@@ -1158,6 +1274,8 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug
 static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 {
 	struct ddebug_table *dt;
+	struct _ddebug *iter;
+	int i, class_ct = 0;
 
 	if (!di->num_descs)
 		return 0;
@@ -1181,13 +1299,20 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 
 	INIT_LIST_HEAD(&dt->link);
 
-	if (di->classes && di->num_classes)
+	for (i = 0, iter = di->descs; i < di->num_descs; i++, iter++)
+		if (iter->class_id != _DPRINTK_CLASS_DFLT)
+			class_ct++;
+
+	if (class_ct && di->num_classes)
 		ddebug_attach_module_classes(dt, di);
 
 	mutex_lock(&ddebug_lock);
 	list_add_tail(&dt->link, &ddebug_tables);
 	mutex_unlock(&ddebug_lock);
 
+	if (class_ct && di->num_class_users)
+		ddebug_attach_user_module_classes(dt, di);
+
 	vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
 	return 0;
 }
@@ -1337,8 +1462,10 @@ static int __init dynamic_debug_init(void)
 	struct _ddebug_info di = {
 		.descs = __start___dyndbg,
 		.classes = __start___dyndbg_classes,
+		.class_users = __start___dyndbg_class_users,
 		.num_descs = __stop___dyndbg - __start___dyndbg,
 		.num_classes = __stop___dyndbg_classes - __start___dyndbg_classes,
+		.num_class_users = __stop___dyndbg_class_users - __start___dyndbg_class_users,
 	};
 
 #ifdef CONFIG_MODULES
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 74d183ebf3e0..1838f62738c4 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -6,11 +6,15 @@
  *      Jim Cromie	<jim.cromie@gmail.com>
  */
 
-#define pr_fmt(fmt) "test_dd: " fmt
+#if defined(TEST_DYNAMIC_DEBUG_SUBMOD)
+  #define pr_fmt(fmt) "test_dd_submod: " fmt
+#else
+  #define pr_fmt(fmt) "test_dd: " fmt
+#endif
 
 #include <linux/module.h>
 
-/* run tests by reading or writing sysfs node: do_prints */
+/* re-gen output by reading or writing sysfs node: do_prints */
 
 static void do_prints(void); /* device under test */
 static int param_set_do_prints(const char *instr, const struct kernel_param *kp)
@@ -29,24 +33,39 @@ static const struct kernel_param_ops param_ops_do_prints = {
 };
 module_param_cb(do_prints, &param_ops_do_prints, NULL, 0600);
 
-/*
- * Using the CLASSMAP api:
- * - classmaps must have corresponding enum
- * - enum symbols must match/correlate with class-name strings in the map.
- * - base must equal enum's 1st value
- * - multiple maps must set their base to share the 0-30 class_id space !!
- *   (build-bug-on tips welcome)
- * Additionally, here:
- * - tie together sysname, mapname, bitsname, flagsname
- */
-#define DD_SYS_WRAP(_model, _flags)					\
-	static unsigned long bits_##_model;				\
-	static struct ddebug_class_param _flags##_model = {		\
+#define CLASSMAP_BITMASK(width, base) (((1UL << (width)) - 1) << (base))
+
+/* sysfs param wrapper, proto-API */
+#define DYNDBG_CLASSMAP_PARAM_(_model, _flags, _init)			\
+	static unsigned long bits_##_model = _init;			\
+	static struct ddebug_class_param _flags##_##_model = {		\
 		.bits = &bits_##_model,					\
 		.flags = #_flags,					\
 		.map = &map_##_model,					\
 	};								\
-	module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes, &_flags##_model, 0600)
+	module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes,	\
+			&_flags##_##_model, 0600)
+#ifdef DEBUG
+#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, ~0)
+#else
+#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, 0)
+#endif
+
+/*
+ * Demonstrate/test all 4 class-typed classmaps with a sys-param.
+ *
+ * Each is 3 part: client-enum decl, _DEFINE, _PARAM.
+ * Declare them in blocks to show patterns of use (repetitions and
+ * changes) within each.
+ *
+ * 1st, dyndbg expects a client-provided enum-type as source of
+ * category/classid truth.  DRM has DRM_UT_<CORE,DRIVER,KMS,etc>.
+ *
+ * Modules with multiple CLASSMAPS must have enums with distinct
+ * value-ranges, arranged below with explicit enum_sym = X inits.
+ *
+ * Declare all 4 enums now, for different types
+ */
 
 /* numeric input, independent bits */
 enum cat_disjoint_bits {
@@ -60,26 +79,51 @@ enum cat_disjoint_bits {
 	D2_LEASE,
 	D2_DP,
 	D2_DRMRES };
-DECLARE_DYNDBG_CLASSMAP(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS, 0,
-			"D2_CORE",
-			"D2_DRIVER",
-			"D2_KMS",
-			"D2_PRIME",
-			"D2_ATOMIC",
-			"D2_VBL",
-			"D2_STATE",
-			"D2_LEASE",
-			"D2_DP",
-			"D2_DRMRES");
-DD_SYS_WRAP(disjoint_bits, p);
-DD_SYS_WRAP(disjoint_bits, T);
 
 /* numeric verbosity, V2 > V1 related */
 enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
-DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14,
-		       "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
-DD_SYS_WRAP(level_num, p);
-DD_SYS_WRAP(level_num, T);
+
+/* recapitulate DRM's parent(drm.ko) <-- _submod(drivers,helpers) */
+#if !defined(TEST_DYNAMIC_DEBUG_SUBMOD)
+/*
+ * In single user, or parent / coordinator (drm.ko) modules, define
+ * classmaps on the client enums above, and then declares the PARAMS
+ * ref'g the classmaps.  Each is exported.
+ */
+DYNDBG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS,
+		       D2_CORE,
+		       "D2_CORE",
+		       "D2_DRIVER",
+		       "D2_KMS",
+		       "D2_PRIME",
+		       "D2_ATOMIC",
+		       "D2_VBL",
+		       "D2_STATE",
+		       "D2_LEASE",
+		       "D2_DP",
+		       "D2_DRMRES");
+
+DYNDBG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
+		       V0, "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
+
+/*
+ * now add the sysfs-params
+ */
+
+DYNDBG_CLASSMAP_PARAM(disjoint_bits, p);
+DYNDBG_CLASSMAP_PARAM(level_num, p);
+
+#else /* TEST_DYNAMIC_DEBUG_SUBMOD */
+
+/*
+ * in submod/drm-drivers, use the classmaps defined in top/parent
+ * module above.
+ */
+
+DYNDBG_CLASSMAP_USE(map_disjoint_bits);
+DYNDBG_CLASSMAP_USE(map_level_num);
+
+#endif
 
 /* stand-in for all pr_debug etc */
 #define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
@@ -115,6 +159,7 @@ static void do_levels(void)
 
 static void do_prints(void)
 {
+	pr_debug("do_prints:\n");
 	do_cats();
 	do_levels();
 }
diff --git a/lib/test_dynamic_debug_submod.c b/lib/test_dynamic_debug_submod.c
new file mode 100644
index 000000000000..9a893402ce1a
--- /dev/null
+++ b/lib/test_dynamic_debug_submod.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kernel module for testing dynamic_debug
+ *
+ * Authors:
+ *      Jim Cromie	<jim.cromie@gmail.com>
+ */
+
+#define TEST_DYNAMIC_DEBUG_SUBMOD
+#include "test_dynamic_debug.c"
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 17/63] dyndbg: check DYNDBG_CLASSMAP_DEFINE args at compile-time
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (15 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 16/63] dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:17   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 18/63] dyndbg: add/use for_subvec() to reduce boilerplate Jim Cromie
                   ` (47 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Add __DYNDBG_CLASSMAP_CHECK to implement these arg-checks at compile:
	0 <= _base < 63
	class_names is not empty
	class_names[0] is a string
	(class_names.length + _base) < 63

These compile-time checks will prevent several misuses; 4 such
examples are added to test_dynamic_debug_submod.ko, and will fail
compilation if -DDD_MACRO_ARGCHECK is added to cflags.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
- split static-asserts to __DYNDBG_CLASSMAP_CHECK
- move __DYNDBG_CLASSMAP_CHECK above kdoc for DYNDBG_CLASSMAP_DEFINE
  silences kernel-doc warnings
---
 include/linux/dynamic_debug.h |  9 +++++++++
 lib/test_dynamic_debug.c      | 11 +++++++++++
 2 files changed, 20 insertions(+)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index dc610a12b91c..2b0c943af330 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -99,6 +99,14 @@ struct ddebug_class_map {
 	enum ddebug_class_map_type map_type;
 };
 
+#define __DYNDBG_CLASSMAP_CHECK(_clnames, _base)			\
+	static_assert(((_base) >= 0 && (_base) < _DPRINTK_CLASS_DFLT),	\
+		      "_base must be in 0..62");			\
+	static_assert(ARRAY_SIZE(_clnames) > 0,				\
+		      "classnames array size must be > 0");		\
+	static_assert((ARRAY_SIZE(_clnames) + (_base)) < _DPRINTK_CLASS_DFLT, \
+		      "_base + classnames.length exceeds range")
+
 /**
  * DYNDBG_CLASSMAP_DEFINE - define debug classes used by a module.
  * @_var:   name of the classmap, exported for other modules coordinated use.
@@ -112,6 +120,7 @@ struct ddebug_class_map {
  */
 #define DYNDBG_CLASSMAP_DEFINE(_var, _mapty, _base, ...)		\
 	static const char *_var##_classnames[] = { __VA_ARGS__ };	\
+	__DYNDBG_CLASSMAP_CHECK(_var##_classnames, (_base));		\
 	extern struct ddebug_class_map _var;				\
 	struct ddebug_class_map __aligned(8) __used			\
 		__section("__dyndbg_classes") _var = {			\
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 1838f62738c4..b1555b0a2bb1 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -123,8 +123,19 @@ DYNDBG_CLASSMAP_PARAM(level_num, p);
 DYNDBG_CLASSMAP_USE(map_disjoint_bits);
 DYNDBG_CLASSMAP_USE(map_level_num);
 
+#if defined(DD_MACRO_ARGCHECK)
+/*
+ * Exersize compile-time arg-checks in DYNDBG_CLASSMAP_DEFINE.
+ * These will break compilation.
+ */
+DYNDBG_CLASSMAP_DEFINE(fail_base_neg, 0, -1, "NEGATIVE_BASE_ARG");
+DYNDBG_CLASSMAP_DEFINE(fail_base_big, 0, 100, "TOOBIG_BASE_ARG");
+DYNDBG_CLASSMAP_DEFINE(fail_str_type, 0, 0, 1 /* not a string */);
+DYNDBG_CLASSMAP_DEFINE(fail_emptyclass, 0, 0 /* ,empty */);
 #endif
 
+#endif /* TEST_DYNAMIC_DEBUG_SUBMOD */
+
 /* stand-in for all pr_debug etc */
 #define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 18/63] dyndbg: add/use for_subvec() to reduce boilerplate
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (16 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 17/63] dyndbg: check DYNDBG_CLASSMAP_DEFINE args at compile-time Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:18   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 19/63] dyndbg: make proper substructs in _ddebug_info Jim Cromie
                   ` (46 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

add for_subvec() macro to encapsulate a for-loop pattern thats used
repeatedly to iterate over a boxed.vector of N elements.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 30 ++++++++++++++++++++++--------
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 6bca0c6727d4..08b6e4e7489f 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -158,20 +158,34 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 		  _dt->num_class_users);				\
 	})
 
+/*
+ * simplify a repeated for-loop pattern walking N steps in a T _vec
+ * member inside a struct _box.  It expects int i and T *_sp to be
+ * declared in the caller.
+ * @_i:  caller provided counter.
+ * @_sp: cursor into _vec, to examine each item.
+ * @_box: ptr to a struct containing @_vec member
+ * @_vec: name of a sub-struct member in _box, with array-ref and length
+ */
+#define for_subvec(_i, _sp, _box, _vec)				       \
+	for ((_i) = 0, (_sp) = (_box)->_vec;			       \
+	     (_i) < (_box)->num_##_vec;				       \
+	     (_i)++, (_sp)++)
+
 static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *class_string)
 {
 	struct ddebug_class_map *map;
 	struct ddebug_class_user *cli;
 	int i, idx;
 
-	for (i = 0, map = dt->classes; i < dt->num_classes; i++, map++) {
+	for_subvec(i, map, dt, classes) {
 		idx = match_string(map->class_names, map->length, class_string);
 		if (idx >= 0) {
 			vpr_dt_info(dt, "good-class: %s.%s ", map->mod_name, class_string);
 			return idx + map->base;
 		}
 	}
-	for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++) {
+	for_subvec(i, cli, dt, class_users) {
 		idx = match_string(cli->map->class_names, cli->map->length, class_string);
 		if (idx >= 0) {
 			vpr_dt_info(dt, "class-ref: %s -> %s.%s ",
@@ -1190,7 +1204,7 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
 	if (cm->mod) {
 		vpr_cm_info(cm, "loaded classmap: %s", modnm);
 		/* ifdef protects the cm->mod->kp deref */
-		for (i = 0, kp = cm->mod->kp; i < cm->mod->num_kp; i++, kp++)
+		for_subvec(i, kp, cm->mod, kp)
 			ddebug_match_apply_kparam(kp, cm, modnm);
 	}
 #endif
@@ -1212,7 +1226,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
 	struct ddebug_class_map *cm;
 	int i, nc = 0;
 
-	for (i = 0, cm = di->classes; i < di->num_classes; i++, cm++) {
+	for_subvec(i, cm, di, classes) {
 		if (!strcmp(cm->mod_name, dt->mod_name)) {
 			vpr_cm_info(cm, "classes[%d]:", i);
 			if (!nc++)
@@ -1225,7 +1239,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
 	vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
 	dt->num_classes = nc;
 
-	for (i = 0, cm = dt->classes; i < dt->num_classes; i++, cm++)
+	for_subvec(i, cm, dt, classes)
 		ddebug_apply_params(cm, cm->mod_name);
 }
 
@@ -1245,7 +1259,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
 	 * module's refs, save to dt.  For loadables, this is the
 	 * whole array.
 	 */
-	for (i = 0, cli = di->class_users; i < di->num_class_users; i++, cli++) {
+	for_subvec(i, cli, di, class_users) {
 		if (WARN_ON_ONCE(!cli || !cli->map || !cli->mod_name))
 			continue;
 		if (!strcmp(cli->mod_name, dt->mod_name)) {
@@ -1261,7 +1275,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
 	dt->num_class_users = nc;
 
 	/* now iterate dt */
-	for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++)
+	for_subvec(i, cli, di, class_users)
 		ddebug_apply_params(cli->map, cli->mod_name);
 
 	vpr_dt_info(dt, "attach-client-module: ");
@@ -1299,7 +1313,7 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 
 	INIT_LIST_HEAD(&dt->link);
 
-	for (i = 0, iter = di->descs; i < di->num_descs; i++, iter++)
+	for_subvec(i, iter, di, descs)
 		if (iter->class_id != _DPRINTK_CLASS_DFLT)
 			class_ct++;
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 19/63] dyndbg: make proper substructs in _ddebug_info
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (17 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 18/63] dyndbg: add/use for_subvec() to reduce boilerplate Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:19   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 20/63] dyndbg: drop premature optimization in ddebug_add_module Jim Cromie
                   ` (45 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

struct _ddebug_info's jobs is to enapsulate the __sections of dyndbg
data from the linker.  The data started as a single pair of fields:
descs - ref'g an array of descriptors & num_descs - counting the
"pertinent" descriptors.  Then classes & num_classes were added, and
_ddebug_info was invented to contain the 4 fields.

When class_users & num_class_users were added (earlier in this
series), the easy path was to replicate functions and adapt them to
work on ddebug_class_users, instead of class_maps.  This worked, but
made repetitive boilerplate code, leading to (other commits with)
macros walking num_##{classes,class_users} to capture the repetition.

To fix it better, create structs to contain start,len for vectors of
all 3 objects: classmaps, class_users, and pr_debug descriptors, and
adjust field-refs accordingly.

Also recompose struct ddebug_table to contain a _ddebug_info (rather
than repeat the contents, as before), and adjust all array-walks to
use the newly contained info.

This allows ridding the class* macros of the num##<T> paste-up, and
should enable further cleanups.

NB: The __packed attribute on _ddebug_info and the 3 contained structs
closes the holes otherwise created by the structification (which was
the excuse for not doing it originally).

TBD: see if this can precede other patches, to reduce churn

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 include/linux/dynamic_debug.h | 29 ++++++++---
 kernel/module/main.c          | 18 +++----
 lib/dynamic_debug.c           | 93 +++++++++++++++++------------------
 3 files changed, 74 insertions(+), 66 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 2b0c943af330..48d76a273f68 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -173,15 +173,28 @@ struct ddebug_class_user {
 		.map = &(_var),						\
 	}
 
-/* encapsulate linker provided built-in (or module) dyndbg data */
+/*
+ * @_ddebug_info: gathers module/builtin dyndbg_* __sections together.
+ * For builtins, it is used as a cursor, with the inner structs
+ * marking sub-vectors of the builtin __sections in DATA.
+ */
+struct _ddebug_descs {
+	struct _ddebug *start;
+	int len;
+} __packed;
+struct dd_class_maps {
+	struct ddebug_class_map *start;
+	int len;
+} __packed;
+struct dd_class_users {
+	struct ddebug_class_user *start;
+	int len;
+} __packed;
 struct _ddebug_info {
-	struct _ddebug *descs;
-	struct ddebug_class_map *classes;
-	struct ddebug_class_user *class_users;
-	unsigned int num_descs;
-	unsigned int num_classes;
-	unsigned int num_class_users;
-};
+	struct _ddebug_descs descs;
+	struct dd_class_maps maps;
+	struct dd_class_users users;
+} __packed;
 
 struct ddebug_class_param {
 	union {
diff --git a/kernel/module/main.c b/kernel/module/main.c
index c394a0c6e8c6..858882a1eacd 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2540,15 +2540,15 @@ static int find_module_sections(struct module *mod, struct load_info *info)
 		pr_warn("%s: Ignoring obsolete parameters\n", mod->name);
 
 #ifdef CONFIG_DYNAMIC_DEBUG_CORE
-	mod->dyndbg_info.descs = section_objs(info, "__dyndbg",
-					      sizeof(*mod->dyndbg_info.descs),
-					      &mod->dyndbg_info.num_descs);
-	mod->dyndbg_info.classes = section_objs(info, "__dyndbg_classes",
-						sizeof(*mod->dyndbg_info.classes),
-						&mod->dyndbg_info.num_classes);
-	mod->dyndbg_info.class_users = section_objs(info, "__dyndbg_class_users",
-						    sizeof(*mod->dyndbg_info.class_users),
-						   &mod->dyndbg_info.num_class_users);
+	mod->dyndbg_info.descs.start = section_objs(info, "__dyndbg",
+						    sizeof(*mod->dyndbg_info.descs.start),
+						    &mod->dyndbg_info.descs.len);
+	mod->dyndbg_info.maps.start = section_objs(info, "__dyndbg_classes",
+						   sizeof(*mod->dyndbg_info.maps.start),
+						   &mod->dyndbg_info.maps.len);
+	mod->dyndbg_info.users.start = section_objs(info, "__dyndbg_class_users",
+						    sizeof(*mod->dyndbg_info.users.start),
+						    &mod->dyndbg_info.users.len);
 #endif
 
 	return 0;
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 08b6e4e7489f..067db504dd1d 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -49,10 +49,7 @@ extern struct ddebug_class_user __stop___dyndbg_class_users[];
 struct ddebug_table {
 	struct list_head link;
 	const char *mod_name;
-	struct _ddebug *ddebugs;
-	struct ddebug_class_map *classes;
-	struct ddebug_class_user *class_users;
-	unsigned int num_ddebugs, num_classes, num_class_users;
+	struct _ddebug_info info;
 };
 
 struct ddebug_query {
@@ -154,8 +151,8 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 #define vpr_dt_info(dt_p, msg_p, ...) ({				\
 	struct ddebug_table const *_dt = dt_p;				\
 	v2pr_info(msg_p " module:%s nd:%d nc:%d nu:%d\n", ##__VA_ARGS__, \
-		  _dt->mod_name, _dt->num_ddebugs, _dt->num_classes,	\
-		  _dt->num_class_users);				\
+		  _dt->mod_name, _dt->info.descs.len, _dt->info.maps.len, \
+		  _dt->info.users.len);					\
 	})
 
 /*
@@ -168,8 +165,8 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
  * @_vec: name of a sub-struct member in _box, with array-ref and length
  */
 #define for_subvec(_i, _sp, _box, _vec)				       \
-	for ((_i) = 0, (_sp) = (_box)->_vec;			       \
-	     (_i) < (_box)->num_##_vec;				       \
+	for ((_i) = 0, (_sp) = (_box)->_vec.start;		       \
+	     (_i) < (_box)->_vec.len;				       \
 	     (_i)++, (_sp)++)
 
 static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *class_string)
@@ -178,14 +175,14 @@ static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *cl
 	struct ddebug_class_user *cli;
 	int i, idx;
 
-	for_subvec(i, map, dt, classes) {
+	for_subvec(i, map, &dt->info, maps) {
 		idx = match_string(map->class_names, map->length, class_string);
 		if (idx >= 0) {
 			vpr_dt_info(dt, "good-class: %s.%s ", map->mod_name, class_string);
 			return idx + map->base;
 		}
 	}
-	for_subvec(i, cli, dt, class_users) {
+	for_subvec(i, cli, &dt->info, users) {
 		idx = match_string(cli->map->class_names, cli->map->length, class_string);
 		if (idx >= 0) {
 			vpr_dt_info(dt, "class-ref: %s -> %s.%s ",
@@ -229,8 +226,8 @@ static int ddebug_change(const struct ddebug_query *query, struct flag_settings
 			valid_class = _DPRINTK_CLASS_DFLT;
 		}
 
-		for (i = 0; i < dt->num_ddebugs; i++) {
-			struct _ddebug *dp = &dt->ddebugs[i];
+		for (i = 0; i < dt->info.descs.len; i++) {
+			struct _ddebug *dp = &dt->info.descs.start[i];
 
 			/* match site against query-class */
 			if (dp->class_id != valid_class)
@@ -990,8 +987,8 @@ static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
 	}
 	iter->table = list_entry(ddebug_tables.next,
 				 struct ddebug_table, link);
-	iter->idx = iter->table->num_ddebugs;
-	return &iter->table->ddebugs[--iter->idx];
+	iter->idx = iter->table->info.descs.len;
+	return &iter->table->info.descs.start[--iter->idx];
 }
 
 /*
@@ -1012,10 +1009,10 @@ static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
 		}
 		iter->table = list_entry(iter->table->link.next,
 					 struct ddebug_table, link);
-		iter->idx = iter->table->num_ddebugs;
+		iter->idx = iter->table->info.descs.len;
 		--iter->idx;
 	}
-	return &iter->table->ddebugs[iter->idx];
+	return &iter->table->info.descs.start[iter->idx];
 }
 
 /*
@@ -1064,15 +1061,15 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
 
 static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp)
 {
-	struct ddebug_class_map *map = dt->classes;
-	struct ddebug_class_user *cli = dt->class_users;
+	struct ddebug_class_map *map;
+	struct ddebug_class_user *cli;
 	int i;
 
-	for (i = 0; i < dt->num_classes; i++, map++)
+	for_subvec(i, map, &dt->info, maps)
 		if (class_in_range(dp->class_id, map))
 			return map->class_names[dp->class_id - map->base];
 
-	for (i = 0; i < dt->num_class_users; i++, cli++)
+	for_subvec(i, cli, &dt->info, users)
 		if (class_in_range(dp->class_id, cli->map))
 			return cli->map->class_names[dp->class_id - cli->map->base];
 
@@ -1203,8 +1200,7 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
 
 	if (cm->mod) {
 		vpr_cm_info(cm, "loaded classmap: %s", modnm);
-		/* ifdef protects the cm->mod->kp deref */
-		for_subvec(i, kp, cm->mod, kp)
+		for (i = 0, kp = cm->mod->kp; i < cm->mod->num_kp; i++, kp++)
 			ddebug_match_apply_kparam(kp, cm, modnm);
 	}
 #endif
@@ -1226,20 +1222,20 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
 	struct ddebug_class_map *cm;
 	int i, nc = 0;
 
-	for_subvec(i, cm, di, classes) {
+	for_subvec(i, cm, di, maps) {
 		if (!strcmp(cm->mod_name, dt->mod_name)) {
 			vpr_cm_info(cm, "classes[%d]:", i);
 			if (!nc++)
-				dt->classes = cm;
+				dt->info.maps.start = cm;
 		}
 	}
 	if (!nc)
 		return;
 
 	vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
-	dt->num_classes = nc;
+	dt->info.maps.len = nc;
 
-	for_subvec(i, cm, dt, classes)
+	for_subvec(i, cm, &dt->info, maps)
 		ddebug_apply_params(cm, cm->mod_name);
 }
 
@@ -1259,23 +1255,23 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
 	 * module's refs, save to dt.  For loadables, this is the
 	 * whole array.
 	 */
-	for_subvec(i, cli, di, class_users) {
+	for_subvec(i, cli, di, users) {
 		if (WARN_ON_ONCE(!cli || !cli->map || !cli->mod_name))
 			continue;
 		if (!strcmp(cli->mod_name, dt->mod_name)) {
 			vpr_cm_info(cli->map, "class_ref[%d] %s -> %s", i,
 				    cli->mod_name, cli->map->mod_name);
 			if (!nc++)
-				dt->class_users = cli;
+				dt->info.users.start = cli;
 		}
 	}
 	if (!nc)
 		return;
 
-	dt->num_class_users = nc;
+	dt->info.users.len = nc;
 
 	/* now iterate dt */
-	for_subvec(i, cli, di, class_users)
+	for_subvec(i, cli, di, users)
 		ddebug_apply_params(cli->map, cli->mod_name);
 
 	vpr_dt_info(dt, "attach-client-module: ");
@@ -1291,10 +1287,10 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 	struct _ddebug *iter;
 	int i, class_ct = 0;
 
-	if (!di->num_descs)
+	if (!di->descs.len)
 		return 0;
 
-	v3pr_info("add-module: %s %d sites\n", modname, di->num_descs);
+	v3pr_info("add-module: %s %d sites\n", modname, di->descs.len);
 
 	dt = kzalloc(sizeof(*dt), GFP_KERNEL);
 	if (dt == NULL) {
@@ -1308,8 +1304,7 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 	 * this struct ddebug_table.
 	 */
 	dt->mod_name = modname;
-	dt->ddebugs = di->descs;
-	dt->num_ddebugs = di->num_descs;
+	dt->info.descs = di->descs;
 
 	INIT_LIST_HEAD(&dt->link);
 
@@ -1317,17 +1312,17 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 		if (iter->class_id != _DPRINTK_CLASS_DFLT)
 			class_ct++;
 
-	if (class_ct && di->num_classes)
+	if (class_ct && di->maps.len)
 		ddebug_attach_module_classes(dt, di);
 
 	mutex_lock(&ddebug_lock);
 	list_add_tail(&dt->link, &ddebug_tables);
 	mutex_unlock(&ddebug_lock);
 
-	if (class_ct && di->num_class_users)
+	if (class_ct && di->users.len)
 		ddebug_attach_user_module_classes(dt, di);
 
-	vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
+	vpr_info("%3u debug prints in module %s\n", di->descs.len, modname);
 	return 0;
 }
 
@@ -1474,12 +1469,12 @@ static int __init dynamic_debug_init(void)
 	char *cmdline;
 
 	struct _ddebug_info di = {
-		.descs = __start___dyndbg,
-		.classes = __start___dyndbg_classes,
-		.class_users = __start___dyndbg_class_users,
-		.num_descs = __stop___dyndbg - __start___dyndbg,
-		.num_classes = __stop___dyndbg_classes - __start___dyndbg_classes,
-		.num_class_users = __stop___dyndbg_class_users - __start___dyndbg_class_users,
+		.descs.start = __start___dyndbg,
+		.maps.start = __start___dyndbg_classes,
+		.users.start = __start___dyndbg_class_users,
+		.descs.len = __stop___dyndbg - __start___dyndbg,
+		.maps.len = __stop___dyndbg_classes - __start___dyndbg_classes,
+		.users.len = __stop___dyndbg_class_users - __start___dyndbg_class_users,
 	};
 
 #ifdef CONFIG_MODULES
@@ -1508,8 +1503,8 @@ static int __init dynamic_debug_init(void)
 
 		if (strcmp(modname, iter->modname)) {
 			mod_ct++;
-			di.num_descs = mod_sites;
-			di.descs = iter_mod_start;
+			di.descs.len = mod_sites;
+			di.descs.start = iter_mod_start;
 			ret = ddebug_add_module(&di, modname);
 			if (ret)
 				goto out_err;
@@ -1519,8 +1514,8 @@ static int __init dynamic_debug_init(void)
 			iter_mod_start = iter;
 		}
 	}
-	di.num_descs = mod_sites;
-	di.descs = iter_mod_start;
+	di.descs.len = mod_sites;
+	di.descs.start = iter_mod_start;
 	ret = ddebug_add_module(&di, modname);
 	if (ret)
 		goto out_err;
@@ -1530,8 +1525,8 @@ static int __init dynamic_debug_init(void)
 		 i, mod_ct, (int)((mod_ct * sizeof(struct ddebug_table)) >> 10),
 		 (int)((i * sizeof(struct _ddebug)) >> 10));
 
-	if (di.num_classes)
-		v2pr_info("  %d builtin ddebug class-maps\n", di.num_classes);
+	if (di.maps.len)
+		v2pr_info("  %d builtin ddebug class-maps\n", di.maps.len);
 
 	/* now that ddebug tables are loaded, process all boot args
 	 * again to find and activate queries given in dyndbg params.
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 20/63] dyndbg: drop premature optimization in ddebug_add_module
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (18 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 19/63] dyndbg: make proper substructs in _ddebug_info Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:26   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 21/63] dyndbg: allow ddebug_add_module to fail Jim Cromie
                   ` (44 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

The class_ct var was added to avoid 2 function calls, but to do this
it loops over all the module's debug callsites to determine the count.
But it doesn't really help, so remove it.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 067db504dd1d..16c9b752822b 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1284,8 +1284,6 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
 static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 {
 	struct ddebug_table *dt;
-	struct _ddebug *iter;
-	int i, class_ct = 0;
 
 	if (!di->descs.len)
 		return 0;
@@ -1308,18 +1306,14 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 
 	INIT_LIST_HEAD(&dt->link);
 
-	for_subvec(i, iter, di, descs)
-		if (iter->class_id != _DPRINTK_CLASS_DFLT)
-			class_ct++;
-
-	if (class_ct && di->maps.len)
+	if (di->maps.len)
 		ddebug_attach_module_classes(dt, di);
 
 	mutex_lock(&ddebug_lock);
 	list_add_tail(&dt->link, &ddebug_tables);
 	mutex_unlock(&ddebug_lock);
 
-	if (class_ct && di->users.len)
+	if (di->users.len)
 		ddebug_attach_user_module_classes(dt, di);
 
 	vpr_info("%3u debug prints in module %s\n", di->descs.len, modname);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 21/63] dyndbg: allow ddebug_add_module to fail
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (19 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 20/63] dyndbg: drop premature optimization in ddebug_add_module Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:26   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 22/63] dyndbg: rework ddebug_attach_*module_classes() Jim Cromie
                   ` (43 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

To prep for failing modprobe on classid conflicts, upgrade the
call-chain around ddebug_add_module(), in 2 ways:

1. in ddebug_add_module() add local reserved_ids to accumulate
reservations, pass it by ref to ddebug_attach_{,user_}module_classes()
so they can examine the reservations as they work.

2. return int from both ddebug_attach_{,user_}module_classes(), up to
ddebug_add_module(), then to ddebug_module_notify().

No conflicts are currently detected or returned.

TBD: This is updated further by hoisting the reservation-check, which
obsoletes part of 2, creating churn, maybe squash it away.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 40 +++++++++++++++++++++++++++++-----------
 1 file changed, 29 insertions(+), 11 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 16c9b752822b..0ef243e30663 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1216,8 +1216,9 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
  * modular classmap vector/section.  Save the start and length of the
  * subrange at its edges.
  */
-static void ddebug_attach_module_classes(struct ddebug_table *dt,
-					 const struct _ddebug_info *di)
+static int ddebug_attach_module_classes(struct ddebug_table *dt,
+					const struct _ddebug_info *di,
+					u64 *reserved_ids)
 {
 	struct ddebug_class_map *cm;
 	int i, nc = 0;
@@ -1230,13 +1231,14 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
 		}
 	}
 	if (!nc)
-		return;
+		return 0;
 
 	vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
 	dt->info.maps.len = nc;
 
 	for_subvec(i, cm, &dt->info, maps)
 		ddebug_apply_params(cm, cm->mod_name);
+	return 0;
 }
 
 /*
@@ -1244,8 +1246,9 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
  * means a query against the dt/module, which means it must be on the
  * list to be seen by ddebug_change.
  */
-static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
-					      const struct _ddebug_info *di)
+static int ddebug_attach_user_module_classes(struct ddebug_table *dt,
+					      const struct _ddebug_info *di,
+					      u64 *reserved_ids)
 {
 	struct ddebug_class_user *cli;
 	int i, nc = 0;
@@ -1266,7 +1269,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
 		}
 	}
 	if (!nc)
-		return;
+		return 0;
 
 	dt->info.users.len = nc;
 
@@ -1275,6 +1278,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
 		ddebug_apply_params(cli->map, cli->mod_name);
 
 	vpr_dt_info(dt, "attach-client-module: ");
+	return 0;
 }
 
 /*
@@ -1284,6 +1288,8 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
 static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 {
 	struct ddebug_table *dt;
+	u64 reserved_ids = 0;
+	int rc;
 
 	if (!di->descs.len)
 		return 0;
@@ -1306,16 +1312,23 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 
 	INIT_LIST_HEAD(&dt->link);
 
-	if (di->maps.len)
-		ddebug_attach_module_classes(dt, di);
-
+	if (di->maps.len) {
+		rc = ddebug_attach_module_classes(dt, di, &reserved_ids);
+		if (rc) {
+			kfree(dt);
+			return rc;
+		}
+	}
 	mutex_lock(&ddebug_lock);
 	list_add_tail(&dt->link, &ddebug_tables);
 	mutex_unlock(&ddebug_lock);
 
-	if (di->users.len)
-		ddebug_attach_user_module_classes(dt, di);
 
+	if (di->users.len) {
+		rc = ddebug_attach_user_module_classes(dt, di, &reserved_ids);
+		if (rc)
+			return rc;
+	}
 	vpr_info("%3u debug prints in module %s\n", di->descs.len, modname);
 	return 0;
 }
@@ -1400,6 +1413,11 @@ static int ddebug_module_notify(struct notifier_block *self, unsigned long val,
 	switch (val) {
 	case MODULE_STATE_COMING:
 		ret = ddebug_add_module(&mod->dyndbg_info, mod->name);
+		if (ret == -EINVAL) {
+			pr_err("conflicting dyndbg-classmap reservations\n");
+			ddebug_remove_module(mod->name);
+			break;
+		}
 		if (ret)
 			WARN(1, "Failed to allocate memory: dyndbg may not work properly.\n");
 		break;
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 22/63] dyndbg: rework ddebug_attach_*module_classes()
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (20 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 21/63] dyndbg: allow ddebug_add_module to fail Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 23/63] dyndbg: fail modprobe on ddebug_class_range_overlap() Jim Cromie
                   ` (42 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

These 2 fns both start with a codeblock which cleans up the classmaps
arrays, finding the few that pertain to the module being added.

Reduce this repetition to a macro: dd_mark_vector_subrange() and call
it 2x.  This macro finds the matching-on-modname subrange of a linker
ordered array of builtin classmaps/users, and saves the subrange into
the dt/debug-table's ddebug-info record.

Then hoist those calls from ddebug_attach*() up to ddebug_add_module().
This puts the "cleanup" of class* arrays into ddebug_add_module(), not
cluttering the original purpose of the 2 routines.

And with ddebug_add_module() now updating dt with the classmaps for
the module, the di arg to ddebug_attach_{,user}module_classes() is no
longer needed, so drop it.

Finally, rename the 2 functions, from *attach* (describing the dt
update in the macro) to module_apply_class_{maps,users} to reflect the
tighter focus.

NB: The macro's main purpose is to handle multiple builtin classmaps
or users, which is the only circumstance where less than the full
array of classmaps is pertinent.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
---
 lib/dynamic_debug.c | 104 ++++++++++++++++++++------------------------
 1 file changed, 48 insertions(+), 56 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 0ef243e30663..8afcd4111531 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1212,72 +1212,54 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
 }
 
 /*
- * Find this module's classmaps in a sub/whole-range of the builtin/
- * modular classmap vector/section.  Save the start and length of the
- * subrange at its edges.
+ * scan the named array: @_vec, ref'd from inside @_box, for the
+ * start,len of the sub-array of elements matching on ->mod_name;
+ * remember them in _dst.  Macro depends upon the fields being in both
+ * _box and _dst.
+ * @_i:   caller provided counter var.
+ * @_sp:  cursor into @_vec.
+ * @_box: ptr to a struct with @_vec, num__##@_vec, mod_name fields.
+ * @_vec: name of ref into array[T] of builtin/modular __section data.
+ * @_dst: ptr to struct with @_vec and num__##@_vec fields, both updated.
  */
-static int ddebug_attach_module_classes(struct ddebug_table *dt,
-					const struct _ddebug_info *di,
-					u64 *reserved_ids)
+#define dd_mark_vector_subrange(_i, _dst, _sp, _box, _vec) ({		\
+	int nc = 0;							\
+	for_subvec(_i, _sp, _box, _vec) {				\
+		if (!strcmp((_sp)->mod_name, (_dst)->mod_name)) {	\
+			if (!nc++)					\
+				(_dst)->info._vec.start = (_sp);	\
+		} else {						\
+			if (nc)						\
+				break; /* end of consecutive matches */ \
+		}							\
+	}								\
+	(_dst)->info._vec.len = nc;					\
+})
+
+static int ddebug_module_apply_class_maps(struct ddebug_table *dt,
+					  u64 *reserved_ids)
 {
 	struct ddebug_class_map *cm;
-	int i, nc = 0;
-
-	for_subvec(i, cm, di, maps) {
-		if (!strcmp(cm->mod_name, dt->mod_name)) {
-			vpr_cm_info(cm, "classes[%d]:", i);
-			if (!nc++)
-				dt->info.maps.start = cm;
-		}
-	}
-	if (!nc)
-		return 0;
-
-	vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
-	dt->info.maps.len = nc;
+	int i;
 
 	for_subvec(i, cm, &dt->info, maps)
 		ddebug_apply_params(cm, cm->mod_name);
+
+	vpr_info("module:%s attached %d classmaps\n", dt->mod_name, dt->info.maps.len);
 	return 0;
 }
 
-/*
- * propagates class-params thru their classmaps to class-users.  this
- * means a query against the dt/module, which means it must be on the
- * list to be seen by ddebug_change.
- */
-static int ddebug_attach_user_module_classes(struct ddebug_table *dt,
-					      const struct _ddebug_info *di,
-					      u64 *reserved_ids)
+static int ddebug_module_apply_class_users(struct ddebug_table *dt,
+					   u64 *reserved_ids)
 {
 	struct ddebug_class_user *cli;
-	int i, nc = 0;
-
-	/*
-	 * For builtins: scan the array, find start/length of this
-	 * module's refs, save to dt.  For loadables, this is the
-	 * whole array.
-	 */
-	for_subvec(i, cli, di, users) {
-		if (WARN_ON_ONCE(!cli || !cli->map || !cli->mod_name))
-			continue;
-		if (!strcmp(cli->mod_name, dt->mod_name)) {
-			vpr_cm_info(cli->map, "class_ref[%d] %s -> %s", i,
-				    cli->mod_name, cli->map->mod_name);
-			if (!nc++)
-				dt->info.users.start = cli;
-		}
-	}
-	if (!nc)
-		return 0;
-
-	dt->info.users.len = nc;
+	int i;
 
 	/* now iterate dt */
-	for_subvec(i, cli, di, users)
+	for_subvec(i, cli, &dt->info, users)
 		ddebug_apply_params(cli->map, cli->mod_name);
 
-	vpr_dt_info(dt, "attach-client-module: ");
+	vpr_info("module:%s attached %d classmap uses\n", dt->mod_name, dt->info.users.len);
 	return 0;
 }
 
@@ -1288,8 +1270,10 @@ static int ddebug_attach_user_module_classes(struct ddebug_table *dt,
 static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 {
 	struct ddebug_table *dt;
+	struct ddebug_class_map *cm;
+	struct ddebug_class_user *cli;
 	u64 reserved_ids = 0;
-	int rc;
+	int rc, i;
 
 	if (!di->descs.len)
 		return 0;
@@ -1311,9 +1295,17 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 	dt->info.descs = di->descs;
 
 	INIT_LIST_HEAD(&dt->link);
+	/*
+	 * for builtin modules, ddebug_init() insures that the di
+	 * cursor marks just the module's descriptors, but it doesn't
+	 * do so for the builtin class _maps & _users.  find the
+	 * start,len of the vectors by mod_name, save to dt.
+	 */
+	dd_mark_vector_subrange(i, dt, cm, di, maps);
+	dd_mark_vector_subrange(i, dt, cli, di, users);
 
-	if (di->maps.len) {
-		rc = ddebug_attach_module_classes(dt, di, &reserved_ids);
+	if (dt->info.maps.len) {
+		rc = ddebug_module_apply_class_maps(dt, &reserved_ids);
 		if (rc) {
 			kfree(dt);
 			return rc;
@@ -1324,8 +1316,8 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 	mutex_unlock(&ddebug_lock);
 
 
-	if (di->users.len) {
-		rc = ddebug_attach_user_module_classes(dt, di, &reserved_ids);
+	if (dt->info.users.len) {
+		rc = ddebug_module_apply_class_users(dt, &reserved_ids);
 		if (rc)
 			return rc;
 	}
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 23/63] dyndbg: fail modprobe on ddebug_class_range_overlap()
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (21 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 22/63] dyndbg: rework ddebug_attach_*module_classes() Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:27   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 24/63] dyndbg: hoist the range-overlap checks Jim Cromie
                   ` (41 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

1. All classes used by a module (declared DYNDBG_CLASSMAP_{DEFINE,USE}
by module code) must share 0..62 class-id space; ie their respective
base,+length reservations shouldn't overlap.  Overlaps would lead to
unintended changes in ddebug enablements.

Detecting these class-id range overlaps at compile-time would be ideal
but is not obvious how; failing at modprobe at least insures that the
developer sees and fixes the conflict.

ddebug_class_range_overlap() implements the range check, accumulating
the reserved-ids as it examines each class.  It probably should use
bitmaps.

A previous commit reworked the modprobe callchain to allow failure,
now call ddebug_class_range_overlap() to check when classid conflicts
happen, and signal that failure.

NB: this can only happen when a module defines+uses several classmaps,

TBD: failing modprobe is kinda harsh, maybe warn and proceed ?

test_dynamic_debug*.ko:

If built with -DFORCE_CLASSID_CONFLICT_MODPROBE, the modules get 2 bad
DYNDBG_CLASS_DEFINE declarations, into parent and the _submod.  These
conflict with one of the good ones in the parent (D2_CORE..etc),
causing the modprobe(s) to fail.  TODO: do in submod only, since fail
of parent prevents submod from ever trying.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
---
 lib/dynamic_debug.c      | 30 ++++++++++++++++++++++++------
 lib/test_dynamic_debug.c | 11 ++++++++++-
 2 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 8afcd4111531..8e1e087e07c3 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1211,6 +1211,21 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
 	}
 }
 
+static int ddebug_class_range_overlap(struct ddebug_class_map *cm,
+				      u64 *reserved_ids)
+{
+	u64 range = (((1ULL << cm->length) - 1) << cm->base);
+
+	if (range & *reserved_ids) {
+		pr_err("[%d..%d] on %s conflicts with %llx\n", cm->base,
+		       cm->base + cm->length - 1, cm->class_names[0],
+		       *reserved_ids);
+		return -EINVAL;
+	}
+	*reserved_ids |= range;
+	return 0;
+}
+
 /*
  * scan the named array: @_vec, ref'd from inside @_box, for the
  * start,len of the sub-array of elements matching on ->mod_name;
@@ -1242,9 +1257,11 @@ static int ddebug_module_apply_class_maps(struct ddebug_table *dt,
 	struct ddebug_class_map *cm;
 	int i;
 
-	for_subvec(i, cm, &dt->info, maps)
+	for_subvec(i, cm, &dt->info, maps) {
+		if (ddebug_class_range_overlap(cm, reserved_ids))
+			return -EINVAL;
 		ddebug_apply_params(cm, cm->mod_name);
-
+	}
 	vpr_info("module:%s attached %d classmaps\n", dt->mod_name, dt->info.maps.len);
 	return 0;
 }
@@ -1255,10 +1272,11 @@ static int ddebug_module_apply_class_users(struct ddebug_table *dt,
 	struct ddebug_class_user *cli;
 	int i;
 
-	/* now iterate dt */
-	for_subvec(i, cli, &dt->info, users)
+	for_subvec(i, cli, &dt->info, users) {
+		if (ddebug_class_range_overlap(cli->map, reserved_ids))
+			return -EINVAL;
 		ddebug_apply_params(cli->map, cli->mod_name);
-
+	}
 	vpr_info("module:%s attached %d classmap uses\n", dt->mod_name, dt->info.users.len);
 	return 0;
 }
@@ -1311,11 +1329,11 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 			return rc;
 		}
 	}
+
 	mutex_lock(&ddebug_lock);
 	list_add_tail(&dt->link, &ddebug_tables);
 	mutex_unlock(&ddebug_lock);
 
-
 	if (dt->info.users.len) {
 		rc = ddebug_module_apply_class_users(dt, &reserved_ids);
 		if (rc)
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index b1555b0a2bb1..74b98adc4ed0 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -81,7 +81,7 @@ enum cat_disjoint_bits {
 	D2_DRMRES };
 
 /* numeric verbosity, V2 > V1 related */
-enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
+enum cat_level_num { V0 = 16, V1, V2, V3, V4, V5, V6, V7 };
 
 /* recapitulate DRM's parent(drm.ko) <-- _submod(drivers,helpers) */
 #if !defined(TEST_DYNAMIC_DEBUG_SUBMOD)
@@ -90,6 +90,7 @@ enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
  * classmaps on the client enums above, and then declares the PARAMS
  * ref'g the classmaps.  Each is exported.
  */
+
 DYNDBG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS,
 		       D2_CORE,
 		       "D2_CORE",
@@ -113,6 +114,14 @@ DYNDBG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
 DYNDBG_CLASSMAP_PARAM(disjoint_bits, p);
 DYNDBG_CLASSMAP_PARAM(level_num, p);
 
+#ifdef FORCE_CLASSID_CONFLICT_MODPROBE
+/*
+ * Enable with -Dflag on compile to test overlapping class-id range
+ * detection.  This should break on modprobe.
+ */
+DYNDBG_CLASSMAP_DEFINE(classid_range_conflict, 0, D2_CORE + 1, "D3_CORE");
+#endif
+
 #else /* TEST_DYNAMIC_DEBUG_SUBMOD */
 
 /*
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 24/63] dyndbg: hoist the range-overlap checks
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (22 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 23/63] dyndbg: fail modprobe on ddebug_class_range_overlap() Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 25/63] ddebug: cleanup-range-overlap fails Jim Cromie
                   ` (40 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

hoist the classmaps range-check up to ddebug_add_module() from
ddebug_module_apply_class*().  THis puts both copies of the task
together, with the other semi-init work.

this allows ddebug_module_apply_class*() to revert back to void
return, but doesn't do that yet.

this is a candidate for squashing back.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 8e1e087e07c3..e57c05c9fb0a 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1257,11 +1257,9 @@ static int ddebug_module_apply_class_maps(struct ddebug_table *dt,
 	struct ddebug_class_map *cm;
 	int i;
 
-	for_subvec(i, cm, &dt->info, maps) {
-		if (ddebug_class_range_overlap(cm, reserved_ids))
-			return -EINVAL;
+	for_subvec(i, cm, &dt->info, maps)
 		ddebug_apply_params(cm, cm->mod_name);
-	}
+
 	vpr_info("module:%s attached %d classmaps\n", dt->mod_name, dt->info.maps.len);
 	return 0;
 }
@@ -1272,11 +1270,9 @@ static int ddebug_module_apply_class_users(struct ddebug_table *dt,
 	struct ddebug_class_user *cli;
 	int i;
 
-	for_subvec(i, cli, &dt->info, users) {
-		if (ddebug_class_range_overlap(cli->map, reserved_ids))
-			return -EINVAL;
+	for_subvec(i, cli, &dt->info, users)
 		ddebug_apply_params(cli->map, cli->mod_name);
-	}
+
 	vpr_info("module:%s attached %d classmap uses\n", dt->mod_name, dt->info.users.len);
 	return 0;
 }
@@ -1322,6 +1318,13 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 	dd_mark_vector_subrange(i, dt, cm, di, maps);
 	dd_mark_vector_subrange(i, dt, cli, di, users);
 
+	for_subvec(i, cm, &dt->info, maps)
+		if (ddebug_class_range_overlap(cm, &reserved_ids))
+			return -EINVAL;
+	for_subvec(i, cli, &dt->info, users)
+		if (ddebug_class_range_overlap(cli->map, &reserved_ids))
+			return -EINVAL;
+
 	if (dt->info.maps.len) {
 		rc = ddebug_module_apply_class_maps(dt, &reserved_ids);
 		if (rc) {
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 25/63] ddebug: cleanup-range-overlap fails
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (23 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 24/63] dyndbg: hoist the range-overlap checks Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 26/63] dyndbg-test: change do_prints testpoint to accept a loopct Jim Cromie
                   ` (39 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

add cleanup block, to handle kfree before dt is added to list.
Once dt is on-list, do ddebug_remove_module to cleanup.

tbd. review some more.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index e57c05c9fb0a..781781835094 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1277,6 +1277,7 @@ static int ddebug_module_apply_class_users(struct ddebug_table *dt,
 	return 0;
 }
 
+static int ddebug_remove_module(const char *mod_name);
 /*
  * Allocate a new ddebug_table for the given module
  * and add it to the global list.
@@ -1318,32 +1319,37 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 	dd_mark_vector_subrange(i, dt, cm, di, maps);
 	dd_mark_vector_subrange(i, dt, cli, di, users);
 
-	for_subvec(i, cm, &dt->info, maps)
-		if (ddebug_class_range_overlap(cm, &reserved_ids))
-			return -EINVAL;
-	for_subvec(i, cli, &dt->info, users)
-		if (ddebug_class_range_overlap(cli->map, &reserved_ids))
-			return -EINVAL;
+	for_subvec(i, cm, &dt->info, maps) {
+		rc = ddebug_class_range_overlap(cm, &reserved_ids);
+		if (rc)
+			goto cleanup;
+	}
+	for_subvec(i, cli, &dt->info, users) {
+		rc = ddebug_class_range_overlap(cli->map, &reserved_ids);
+		if (rc)
+			goto cleanup;
+	}
 
 	if (dt->info.maps.len) {
 		rc = ddebug_module_apply_class_maps(dt, &reserved_ids);
-		if (rc) {
-			kfree(dt);
-			return rc;
-		}
+		if (rc)
+			goto cleanup;
 	}
-
 	mutex_lock(&ddebug_lock);
 	list_add_tail(&dt->link, &ddebug_tables);
 	mutex_unlock(&ddebug_lock);
 
 	if (dt->info.users.len) {
+		/* this needs to find the ref'd class on the ddebug-tables list */
 		rc = ddebug_module_apply_class_users(dt, &reserved_ids);
 		if (rc)
-			return rc;
+			return ddebug_remove_module(dt->mod_name);
 	}
 	vpr_info("%3u debug prints in module %s\n", di->descs.len, modname);
 	return 0;
+cleanup:
+	kfree(dt);
+	return rc; /* tbd might conflict w notify chain */
 }
 
 /* helper for ddebug_dyndbg_(boot|module)_param_cb */
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 26/63] dyndbg-test: change do_prints testpoint to accept a loopct
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (24 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 25/63] ddebug: cleanup-range-overlap fails Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 27/63] selftests-dyndbg: add tools/testing/selftests/dynamic_debug/* Jim Cromie
                   ` (38 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

echo 1000 > /sys/module/test_dynamic_debug/parameters/do_prints

This allows its use as a scriptable load generator, to generate
dynamic-prefix-emits for flag combinations vs undecorated printks.
This will make it easy to assess the cost of the prefixing.

NB: the count is an unsigned int, and is *not* clamped currently, but
probably should be.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/test_dynamic_debug.c | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 74b98adc4ed0..5cfc156ca4bb 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -16,16 +16,24 @@
 
 /* re-gen output by reading or writing sysfs node: do_prints */
 
-static void do_prints(void); /* device under test */
+static void do_prints(unsigned int); /* device under test */
 static int param_set_do_prints(const char *instr, const struct kernel_param *kp)
 {
-	do_prints();
+	int rc;
+	unsigned int ct;
+
+	rc = kstrtouint(instr, 0, &ct);
+	if (rc) {
+		pr_err("expecting numeric input, using 1 instead\n");
+		ct = 1;
+	}
+	do_prints(ct);
 	return 0;
 }
 static int param_get_do_prints(char *buffer, const struct kernel_param *kp)
 {
-	do_prints();
-	return scnprintf(buffer, PAGE_SIZE, "did do_prints\n");
+	do_prints(1);
+	return scnprintf(buffer, PAGE_SIZE, "did 1 do_prints\n");
 }
 static const struct kernel_param_ops param_ops_do_prints = {
 	.set = param_set_do_prints,
@@ -177,17 +185,20 @@ static void do_levels(void)
 	prdbg(V7);
 }
 
-static void do_prints(void)
+static void do_prints(unsigned int ct)
 {
-	pr_debug("do_prints:\n");
-	do_cats();
-	do_levels();
+	/* maybe clamp this */
+	pr_debug("do-prints %d times:\n", ct);
+	for (; ct; ct--) {
+		do_cats();
+		do_levels();
+	}
 }
 
 static int __init test_dynamic_debug_init(void)
 {
 	pr_debug("init start\n");
-	do_prints();
+	do_prints(1);
 	pr_debug("init done\n");
 	return 0;
 }
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 27/63] selftests-dyndbg: add tools/testing/selftests/dynamic_debug/*
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (25 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 26/63] dyndbg-test: change do_prints testpoint to accept a loopct Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 28/63] dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API Jim Cromie
                   ` (37 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Add a selftest script for dynamic-debug.  The config requires
CONFIG_TEST_DYNAMIC_DEBUG=m (and CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD=m),
which tacitly requires either CONFIG_DYNAMIC_DEBUG=y or
CONFIG_DYNAMIC_DEBUG_CORE=y

ATM this has just basic_tests(), which modifies pr_debug flags in
module params, which to handle boot args/options, must be a builtin.

This is backported from another feature branch; the support-fns (thx
Lukas) have unused features at the moment, they'll get used shortly.

The script enables simple virtme-ng testing:

  $> vng V=1 -- ./tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh

virtme: waiting for virtiofsd to start
virtme: use 'microvm' QEMU architecture
...
[    4.136168] virtme-init: Setting hostname to v6.8-32-g30d431000676...
[    4.240874] virtme-init: starting script
...
[    4.474435] virtme-init: script returned {0}
Powering off.
[    4.529318] ACPI: PM: Preparing to enter system sleep state S5
[    4.529991] kvm: exiting hardware virtualization
[    4.530428] reboot: Power down

And add dynamic_debug to TARGETS, so `make run_tests` sees it properly

for the impatient, set TARGETS explicitly:

bash-5.2# make TARGETS=dynamic_debug run_tests
make[1]: ...
TAP version 13
1..1
[   35.552922] dyndbg: read 3 bytes from userspace
[   35.553099] dyndbg: query 0: "=_" mod:*
[   35.553544] dyndbg: processed 1 queries, with 1778 matches, 0 errs
...

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Co-developed-by: Łukasz Bartosik <ukaszb@chromium.org>
Signed-off-by: Łukasz Bartosik <ukaszb@chromium.org>
---

- check KCONFIG_CONFIG to avoid silly fails

Several tests are dependent upon config choices. Lets avoid failing
where that is noise.

The KCONFIG_CONFIG var exists to convey the config-file around.  If
the var names a file, read it and extract the relevant CONFIG items,
and use them to skip the dependent tests, thus avoiding the fails that
would follow, and the disruption to whatever CI is running these
selftests.

If the envar doesn't name a config-file, ".config" is assumed.

CONFIG_DYNAMIC_DEBUG=y:

basic-tests() and comma-terminator-tests() test for the presence of
the builtin pr_debugs in module/main.c, which I deemed stable and
therefore safe to count.  That said, the test fails if only
CONFIG_DYNAMIC_DEBUG_CORE=y is set.  It could be rewritten to test
against test-dynamic-debug.ko, but that just trades one config
dependence for another.

CONFIG_TEST_DYNAMIC_DEBUG=m

As written, test_percent_splitting() modprobes test_dynamic_debug,
enables several classes, and count them.  It could be re-written to
work for the builtin module also, but builtin test modules are not a
common or desirable build/config.

CONFIG_TEST_DYNAMIC_DEBUG=m && CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD=m

test_mod_submod() recaps the bug found in DRM-CI where drivers werent
enabled by drm.debug=<bits>.  It modprobes both test_dynamic_debug &
test_dynamic_debug_submod, so it depends on a loadable modules config.

It could be rewritten to work in a builtin parent config; DRM=y is
common enough to be pertinent, but testing that config also wouldn't
really test anything more fully than all-loadable modules, since they
default together.
---
 MAINTAINERS                                   |   1 +
 tools/testing/selftests/Makefile              |   1 +
 .../testing/selftests/dynamic_debug/Makefile  |   9 +
 tools/testing/selftests/dynamic_debug/config  |   2 +
 .../dynamic_debug/dyndbg_selftest.sh          | 256 ++++++++++++++++++
 5 files changed, 269 insertions(+)
 create mode 100644 tools/testing/selftests/dynamic_debug/Makefile
 create mode 100644 tools/testing/selftests/dynamic_debug/config
 create mode 100755 tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh

diff --git a/MAINTAINERS b/MAINTAINERS
index 38afccb3b71e..b707421229e3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8042,6 +8042,7 @@ S:	Maintained
 F:	include/linux/dynamic_debug.h
 F:	lib/dynamic_debug.c
 F:	lib/test_dynamic_debug*.c
+F:	tools/testing/selftests/dynamic_debug/*
 
 DYNAMIC INTERRUPT MODERATION
 M:	Tal Gilboa <talgi@nvidia.com>
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 2401e973c359..e632f3fc97ac 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -25,6 +25,7 @@ TARGETS += drivers/net/team
 TARGETS += drivers/net/virtio_net
 TARGETS += drivers/platform/x86/intel/ifs
 TARGETS += dt
+TARGETS += dynamic_debug
 TARGETS += efivarfs
 TARGETS += exec
 TARGETS += fchmodat2
diff --git a/tools/testing/selftests/dynamic_debug/Makefile b/tools/testing/selftests/dynamic_debug/Makefile
new file mode 100644
index 000000000000..6d06fa7f1040
--- /dev/null
+++ b/tools/testing/selftests/dynamic_debug/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# borrowed from Makefile for user memory selftests
+
+# No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
+all:
+
+TEST_PROGS := dyndbg_selftest.sh
+
+include ../lib.mk
diff --git a/tools/testing/selftests/dynamic_debug/config b/tools/testing/selftests/dynamic_debug/config
new file mode 100644
index 000000000000..d080da571ac0
--- /dev/null
+++ b/tools/testing/selftests/dynamic_debug/config
@@ -0,0 +1,2 @@
+CONFIG_TEST_DYNAMIC_DEBUG=m
+CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD=m
diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
new file mode 100755
index 000000000000..68a9046405f2
--- /dev/null
+++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
@@ -0,0 +1,256 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+
+V=${V:=0}  # invoke as V=1 $0  for global verbose
+RED="\033[0;31m"
+GREEN="\033[0;32m"
+YELLOW="\033[0;33m"
+BLUE="\033[0;34m"
+MAGENTA="\033[0;35m"
+CYAN="\033[0;36m"
+NC="\033[0;0m"
+error_msg=""
+
+[ -e /proc/dynamic_debug/control ] || {
+    echo -e "${RED}: this test requires CONFIG_DYNAMIC_DEBUG=y ${NC}"
+    exit 0 # nothing to test here, no good reason to fail.
+}
+
+# need info to avoid failures due to untestable configs
+
+[ -f "$KCONFIG_CONFIG" ] || KCONFIG_CONFIG=".config"
+if [ -f "$KCONFIG_CONFIG" ]; then
+    echo "# consulting KCONFIG_CONFIG: $KCONFIG_CONFIG"
+    grep -q "CONFIG_DYNAMIC_DEBUG=y" $KCONFIG_CONFIG ; LACK_DD_BUILTIN=$?
+    grep -q "CONFIG_TEST_DYNAMIC_DEBUG=m" $KCONFIG_CONFIG ; LACK_TMOD=$?
+    grep -q "CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD=m" $KCONFIG_CONFIG ; LACK_TMOD_SUBMOD=$?
+    if [ $V -eq 1 ]; then
+	echo LACK_DD_BUILTIN: $LACK_DD_BUILTIN
+	echo LACK_TMOD: $LACK_TMOD
+	echo LACK_TMOD_SUBMOD: $LACK_TMOD_SUBMOD
+    fi
+else
+    LACK_DD_BUILTIN=0
+    LACK_TMOD=0
+    LACK_TMOD_SUBMOD=0
+fi
+
+function vx () {
+    echo $1 > /sys/module/dynamic_debug/parameters/verbose
+}
+
+function ddgrep () {
+    grep $1 /proc/dynamic_debug/control
+}
+
+function doprints () {
+    cat /sys/module/test_dynamic_debug/parameters/do_prints
+}
+
+function ddcmd () {
+    exp_exit_code=0
+    num_args=$#
+    if [ "${@:$#}" = "pass" ]; then
+	num_args=$#-1
+    elif [ "${@:$#}" = "fail" ]; then
+        num_args=$#-1
+	exp_exit_code=1
+    fi
+    args=${@:1:$num_args}
+    output=$((echo "$args" > /proc/dynamic_debug/control) 2>&1)
+    exit_code=$?
+    error_msg=$(echo $output | cut -d ":" -f 5 | sed -e 's/^[[:space:]]*//')
+    handle_exit_code $BASH_LINENO $FUNCNAME $exit_code $exp_exit_code
+}
+
+function handle_exit_code() {
+    local exp_exit_code=0
+    [ $# == 4 ] && exp_exit_code=$4
+    if [ $3 -ne $exp_exit_code ]; then
+        echo -e "${RED}: $BASH_SOURCE:$1 $2() expected to exit with code $exp_exit_code"
+	[ $3 == 1 ] && echo "Error: '$error_msg'"
+        exit
+    fi
+}
+
+# $1 - pattern to match, pattern in $1 is enclosed by spaces for a match ""\s$1\s"
+# $2 - number of times the pattern passed in $1 is expected to match
+# $3 - optional can be set either to "-r" or "-v"
+#       "-r" means relaxed matching in this case pattern provided in $1 is passed
+#       as is without enclosing it with spaces
+#       "-v" prints matching lines
+# $4 - optional when $3 is set to "-r" then $4 can be used to pass "-v"
+function check_match_ct {
+    pattern="\s$1\s"
+    exp_cnt=0
+
+    [ "$3" == "-r" ] && pattern="$1"
+    let cnt=$(ddgrep "$pattern" | wc -l)
+    if [ $V -eq 1 ] || [ "$3" == "-v" ] || [ "$4" == "-v" ]; then
+        echo -ne "${BLUE}" && ddgrep $pattern && echo -ne "${NC}"
+    fi
+    [ $# -gt 1 ] && exp_cnt=$2
+    if [ $cnt -ne $exp_cnt ]; then
+        echo -e "${RED}: $BASH_SOURCE:$BASH_LINENO check failed expected $exp_cnt on $1, got $cnt"
+        exit
+    else
+        echo ": $cnt matches on $1"
+    fi
+}
+
+# $1 - trace instance name
+# #2 - if > 0 then directory is expected to exist, if <= 0 then otherwise
+# $3 - "-v" for verbose
+function check_trace_instance_dir {
+    if [ -e /sys/kernel/tracing/instances/$1 ]; then
+        if [ "$3" == "-v" ] ; then
+            echo "ls -l /sys/kernel/tracing/instances/$1: "
+            ls -l /sys/kernel/tracing/instances/$1
+        fi
+	if [ $2 -le 0 ]; then
+            echo -e "${RED}: $BASH_SOURCE:$BASH_LINENO error trace instance \
+		    '/sys/kernel/tracing/instances/$1' does exist"
+	    exit
+	fi
+    else
+	if [ $2 -gt 0 ]; then
+            echo -e "${RED}: $BASH_SOURCE:$BASH_LINENO error trace instance \
+		    '/sys/kernel/tracing/instances/$1' does not exist"
+	    exit
+        fi
+    fi
+}
+
+function tmark {
+    echo $* > /sys/kernel/tracing/trace_marker
+}
+
+# $1 - trace instance name
+# $2 - line number
+# $3 - if > 0 then the instance is expected to be opened, otherwise
+# the instance is expected to be closed
+function check_trace_instance {
+    output=$(tail -n9 /proc/dynamic_debug/control | grep ": Opened trace instances" \
+	    | xargs -n1 | grep $1)
+    if [ "$output" != $1 ] && [ $3 -gt 0 ]; then
+        echo -e "${RED}: $BASH_SOURCE:$2 trace instance $1 is not opened"
+        exit
+    fi
+    if [ "$output" == $1 ] && [ $3 -le 0 ]; then
+        echo -e "${RED}: $BASH_SOURCE:$2 trace instance $1 is not closed"
+        exit
+    fi
+}
+
+function is_trace_instance_opened {
+    check_trace_instance $1 $BASH_LINENO 1
+}
+
+function is_trace_instance_closed {
+    check_trace_instance $1 $BASH_LINENO 0
+}
+
+# $1 - trace instance directory to delete
+# $2 - if > 0 then directory is expected to be deleted successfully, if <= 0 then otherwise
+function del_trace_instance_dir() {
+    exp_exit_code=1
+    [ $2 -gt 0 ] && exp_exit_code=0
+    output=$((rmdir /sys/kernel/debug/tracing/instances/$1) 2>&1)
+    exit_code=$?
+    error_msg=$(echo $output | cut -d ":" -f 3 | sed -e 's/^[[:space:]]*//')
+    handle_exit_code $BASH_LINENO $FUNCNAME $exit_code $exp_exit_code
+}
+
+function error_log_ref {
+    # to show what I got
+    : echo "# error-log-ref: $1"
+    : echo cat \$2
+}
+
+function ifrmmod {
+    lsmod | grep $1 2>&1>/dev/null && rmmod $1
+}
+
+# $1 - text to search for
+function search_trace() {
+    search_trace_name 0 1 $1
+}
+
+# $1 - trace instance name, 0 for global event trace
+# $2 - line number counting from the bottom
+# $3 - text to search for
+function search_trace_name() {
+	if [ "$1" = "0" ]; then
+	    buf=$(cat /sys/kernel/debug/tracing/trace)
+	    line=$(tail -$2 /sys/kernel/debug/tracing/trace | head -1 | sed -e 's/^[[:space:]]*//')
+	else
+	    buf=$(cat /sys/kernel/debug/tracing/instances/$1/trace)
+	    line=$(tail -$2 /sys/kernel/debug/tracing/instances/$1/trace | head -1 | \
+		   sed -e 's/^[[:space:]]*//')
+	fi
+	if [ $2 = 0 ]; then
+	    # whole-buf check
+	    output=$(echo $buf | grep "$3")
+	else
+	    output=$(echo $line | grep "$3")
+	fi
+	if [ "$output" = "" ]; then
+            echo -e "${RED}: $BASH_SOURCE:$BASH_LINENO search for '$3' failed \
+		    in line '$line' or '$buf'"
+	    exit
+	fi
+	if [ $V = 1 ]; then
+	    echo -e "${MAGENTA}: search_trace_name in $1 found: \n$output \nin:${BLUE} $buf ${NC}"
+        fi
+}
+
+# $1 - error message to check
+function check_err_msg() {
+    if [ "$error_msg" != "$1" ]; then
+        echo -e "${RED}: $BASH_SOURCE:$BASH_LINENO error message '$error_msg' \
+		does not match with '$1'"
+        exit
+    fi
+}
+
+function basic_tests {
+    echo -e "${GREEN}# BASIC_TESTS ${NC}"
+    if [ $LACK_DD_BUILTIN -eq 1 ]; then
+	echo "SKIP"
+	return
+    fi
+    ddcmd =_ # zero everything
+    check_match_ct =p 0
+
+    # module params are builtin to handle boot args
+    check_match_ct '\[params\]' 4 -r
+    ddcmd module params +mpf
+    check_match_ct =pmf 4
+
+    # multi-cmd input, newline separated, with embedded comments
+    cat <<"EOF" > /proc/dynamic_debug/control
+      module params =_				# clear params
+      module params +mf				# set flags
+      module params func parse_args +sl		# other flags
+EOF
+    check_match_ct =mf 3
+    check_match_ct =mfsl 1
+    ddcmd =_
+}
+
+tests_list=(
+    basic_tests
+)
+
+# Run tests
+
+ifrmmod test_dynamic_debug_submod
+ifrmmod test_dynamic_debug
+
+for test in "${tests_list[@]}"
+do
+    $test
+    echo ""
+done
+echo -en "${GREEN}# Done on: "
+date
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 28/63] dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (26 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 27/63] selftests-dyndbg: add tools/testing/selftests/dynamic_debug/* Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-02-25 14:29   ` Louis Chauvet
  2025-01-25  6:45 ` [PATCH 29/63] dyndbg-doc: add classmap info to howto Jim Cromie
                   ` (36 subsequent siblings)
  64 siblings, 1 reply; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

move the DYNDBG_CLASSMAP_PARAM macro from test-dynamic-debug.c into
the header, and refine it, by distinguishing the 2 use cases:

1.DYNDBG_CLASSMAP_PARAM_REF
    for DRM, to pass in extern __drm_debug by name.
    dyndbg keeps bits in it, so drm can still use it as before

2.DYNDBG_CLASSMAP_PARAM
    new user (test_dynamic_debug) doesn't need to share state,
    decls a static long unsigned int to store the bitvec.

__DYNDBG_CLASSMAP_PARAM
   bottom layer - allocate,init a ddebug-class-param, module-param-cb.

Modify ddebug_sync_classbits() argtype deref inside the fn, to give
access to all kp members.

Also clean up and improve comments in test-code, and add
MODULE_DESCRIPTIONs.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---

-v9
 - fixup drm-print.h  add PARAM_REF forwarding macros
   with DYNDBG_CLASSMAP_PARAM_REF in the API, add DRM_ variant
---
 include/linux/dynamic_debug.h   | 38 +++++++++++++++++++++
 lib/dynamic_debug.c             | 60 ++++++++++++++++++++++-----------
 lib/test_dynamic_debug.c        | 59 +++++++++++++-------------------
 lib/test_dynamic_debug_submod.c |  9 ++++-
 4 files changed, 111 insertions(+), 55 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 48d76a273f68..b47d1088b7ad 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -205,6 +205,44 @@ struct ddebug_class_param {
 	const struct ddebug_class_map *map;
 };
 
+/**
+ * DYNDBG_CLASSMAP_PARAM - control a ddebug-classmap from a sys-param
+ * @_name:  sysfs node name
+ * @_var:   name of the classmap var defining the controlled classes/bits
+ * @_flags: flags to be toggled, typically just 'p'
+ *
+ * Creates a sysfs-param to control the classes defined by the
+ * exported classmap, with bits 0..N-1 mapped to the classes named.
+ * This version keeps class-state in a private long int.
+ */
+#define DYNDBG_CLASSMAP_PARAM(_name, _var, _flags)			\
+	static unsigned long _name##_bvec;				\
+	__DYNDBG_CLASSMAP_PARAM(_name, _name##_bvec, _var, _flags)
+
+/**
+ * DYNDBG_CLASSMAP_PARAM_REF - wrap a classmap with a controlling sys-param
+ * @_name:  sysfs node name
+ * @_bits:  name of the module's unsigned long bit-vector, ex: __drm_debug
+ * @_var:   name of the (exported) classmap var defining the classes/bits
+ * @_flags: flags to be toggled, typically just 'p'
+ *
+ * Creates a sysfs-param to control the classes defined by the
+ * exported clasmap, with bits 0..N-1 mapped to the classes named.
+ * This version keeps class-state in user @_bits.  This lets drm check
+ * __drm_debug elsewhere too.
+ */
+#define DYNDBG_CLASSMAP_PARAM_REF(_name, _bits, _var, _flags)		\
+	__DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags)
+
+#define __DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags)		\
+	static struct ddebug_class_param _name##_##_flags = {		\
+		.bits = &(_bits),					\
+		.flags = #_flags,					\
+		.map = &(_var),						\
+	};								\
+	module_param_cb(_name, &param_ops_dyndbg_classes,		\
+			&_name##_##_flags, 0600)
+
 /*
  * pr_debug() and friends are globally enabled or modules have selectively
  * enabled them.
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 781781835094..9283f2866415 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -660,6 +660,30 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 
 #define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1)
 
+static void ddebug_class_param_clamp_input(unsigned long *inrep, const struct kernel_param *kp)
+{
+	const struct ddebug_class_param *dcp = kp->arg;
+	const struct ddebug_class_map *map = dcp->map;
+
+	switch (map->map_type) {
+	case DD_CLASS_TYPE_DISJOINT_BITS:
+		/* expect bits. mask and warn if too many */
+		if (*inrep & ~CLASSMAP_BITMASK(map->length)) {
+			pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
+				KP_NAME(kp), *inrep, CLASSMAP_BITMASK(map->length));
+			*inrep &= CLASSMAP_BITMASK(map->length);
+		}
+		break;
+	case DD_CLASS_TYPE_LEVEL_NUM:
+		/* input is bitpos, of highest verbosity to be enabled */
+		if (*inrep > map->length) {
+			pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
+				KP_NAME(kp), *inrep, map->length);
+			*inrep = map->length;
+		}
+		break;
+	}
+}
 static int param_set_dyndbg_module_classes(const char *instr,
 					   const struct kernel_param *kp,
 					   const char *modnm)
@@ -678,26 +702,15 @@ static int param_set_dyndbg_module_classes(const char *instr,
 		pr_err("expecting numeric input, not: %s > %s\n", instr, KP_NAME(kp));
 		return -EINVAL;
 	}
+	ddebug_class_param_clamp_input(&inrep, kp);
 
 	switch (map->map_type) {
 	case DD_CLASS_TYPE_DISJOINT_BITS:
-		/* expect bits. mask and warn if too many */
-		if (inrep & ~CLASSMAP_BITMASK(map->length)) {
-			pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
-				KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length));
-			inrep &= CLASSMAP_BITMASK(map->length);
-		}
 		v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp));
 		totct += ddebug_apply_class_bitmap(dcp, &inrep, *dcp->bits, modnm);
 		*dcp->bits = inrep;
 		break;
 	case DD_CLASS_TYPE_LEVEL_NUM:
-		/* input is bitpos, of highest verbosity to be enabled */
-		if (inrep > map->length) {
-			pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
-				KP_NAME(kp), inrep, map->length);
-			inrep = map->length;
-		}
 		old_bits = CLASSMAP_BITMASK(*dcp->lvl);
 		new_bits = CLASSMAP_BITMASK(inrep);
 		v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
@@ -1163,15 +1176,24 @@ static const struct proc_ops proc_fops = {
 static void ddebug_sync_classbits(const struct kernel_param *kp, const char *modname)
 {
 	const struct ddebug_class_param *dcp = kp->arg;
+	unsigned long new_bits;
 
-	/* clamp initial bitvec, mask off hi-bits */
-	if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) {
-		*dcp->bits &= CLASSMAP_BITMASK(dcp->map->length);
-		v2pr_info("preset classbits: %lx\n", *dcp->bits);
+	ddebug_class_param_clamp_input(dcp->bits, kp);
+
+	switch (dcp->map->map_type) {
+	case DD_CLASS_TYPE_DISJOINT_BITS:
+		v2pr_info("  %s: classbits: 0x%lx\n", KP_NAME(kp), *dcp->bits);
+		ddebug_apply_class_bitmap(dcp, dcp->bits, 0UL, modname);
+		break;
+	case DD_CLASS_TYPE_LEVEL_NUM:
+		new_bits = CLASSMAP_BITMASK(*dcp->lvl);
+		v2pr_info("  %s: lvl:%ld bits:0x%lx\n", KP_NAME(kp), *dcp->lvl, new_bits);
+		ddebug_apply_class_bitmap(dcp, &new_bits, 0UL, modname);
+		break;
+	default:
+		pr_err("bad map type %d\n", dcp->map->map_type);
+		return;
 	}
-	/* force class'd prdbgs (in USEr module) to match (DEFINEr module) class-param */
-	ddebug_apply_class_bitmap(dcp, dcp->bits, ~0, modname);
-	ddebug_apply_class_bitmap(dcp, dcp->bits, 0, modname);
 }
 
 static void ddebug_match_apply_kparam(const struct kernel_param *kp,
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 5cfc156ca4bb..32a9d49a7a3b 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Kernel module for testing dynamic_debug
+ * Kernel module to test/demonstrate dynamic_debug features,
+ * particularly classmaps and their support for subsystems like DRM.
  *
  * Authors:
  *      Jim Cromie	<jim.cromie@gmail.com>
@@ -43,36 +44,21 @@ module_param_cb(do_prints, &param_ops_do_prints, NULL, 0600);
 
 #define CLASSMAP_BITMASK(width, base) (((1UL << (width)) - 1) << (base))
 
-/* sysfs param wrapper, proto-API */
-#define DYNDBG_CLASSMAP_PARAM_(_model, _flags, _init)			\
-	static unsigned long bits_##_model = _init;			\
-	static struct ddebug_class_param _flags##_##_model = {		\
-		.bits = &bits_##_model,					\
-		.flags = #_flags,					\
-		.map = &map_##_model,					\
-	};								\
-	module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes,	\
-			&_flags##_##_model, 0600)
-#ifdef DEBUG
-#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, ~0)
-#else
-#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, 0)
-#endif
-
 /*
- * Demonstrate/test all 4 class-typed classmaps with a sys-param.
+ * Demonstrate/test both types of classmaps, each with a sys-param.
  *
  * Each is 3 part: client-enum decl, _DEFINE, _PARAM.
- * Declare them in blocks to show patterns of use (repetitions and
- * changes) within each.
+ * Pair the 6 parts by type, to show the pattern of repetition and
+ * change within each.
  *
- * 1st, dyndbg expects a client-provided enum-type as source of
- * category/classid truth.  DRM has DRM_UT_<CORE,DRIVER,KMS,etc>.
+ * 1st, dyndbg classmaps follows drm.debug convention, and expects a
+ * client-provided enum-type as source of category/classid truth.  DRM
+ * gives DRM_UT_<CORE,DRIVER,KMS,etc>.
  *
  * Modules with multiple CLASSMAPS must have enums with distinct
  * value-ranges, arranged below with explicit enum_sym = X inits.
  *
- * Declare all 4 enums now, for different types
+ * Declare the 2 enums now.
  */
 
 /* numeric input, independent bits */
@@ -91,12 +77,15 @@ enum cat_disjoint_bits {
 /* numeric verbosity, V2 > V1 related */
 enum cat_level_num { V0 = 16, V1, V2, V3, V4, V5, V6, V7 };
 
-/* recapitulate DRM's parent(drm.ko) <-- _submod(drivers,helpers) */
+/*
+ * use/demonstrate multi-module-group classmaps, as for DRM
+ */
 #if !defined(TEST_DYNAMIC_DEBUG_SUBMOD)
 /*
- * In single user, or parent / coordinator (drm.ko) modules, define
- * classmaps on the client enums above, and then declares the PARAMS
- * ref'g the classmaps.  Each is exported.
+ * For module-groups of 1+, define classmaps with names (stringified
+ * enum-symbols) copied from above. 1-to-1 mapping is recommended.
+ * The classmap is exported, so that other modules in the group can
+ * link to it and control their prdbgs.
  */
 
 DYNDBG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS,
@@ -116,11 +105,12 @@ DYNDBG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
 		       V0, "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
 
 /*
- * now add the sysfs-params
+ * for use-cases that want it, provide a sysfs-param to set the
+ * classes in the classmap.  It is at this interface where the
+ * "v3>v2" property is applied to DD_CLASS_TYPE_LEVEL_NUM inputs.
  */
-
-DYNDBG_CLASSMAP_PARAM(disjoint_bits, p);
-DYNDBG_CLASSMAP_PARAM(level_num, p);
+DYNDBG_CLASSMAP_PARAM(p_disjoint_bits,	map_disjoint_bits, p);
+DYNDBG_CLASSMAP_PARAM(p_level_num,	map_level_num, p);
 
 #ifdef FORCE_CLASSID_CONFLICT_MODPROBE
 /*
@@ -131,12 +121,10 @@ DYNDBG_CLASSMAP_DEFINE(classid_range_conflict, 0, D2_CORE + 1, "D3_CORE");
 #endif
 
 #else /* TEST_DYNAMIC_DEBUG_SUBMOD */
-
 /*
- * in submod/drm-drivers, use the classmaps defined in top/parent
- * module above.
+ * the +1 members of a multi-module group refer to the classmap
+ * DEFINEd (and exported) above.
  */
-
 DYNDBG_CLASSMAP_USE(map_disjoint_bits);
 DYNDBG_CLASSMAP_USE(map_level_num);
 
@@ -211,6 +199,7 @@ static void __exit test_dynamic_debug_exit(void)
 module_init(test_dynamic_debug_init);
 module_exit(test_dynamic_debug_exit);
 
+MODULE_DESCRIPTION("test/demonstrate dynamic-debug features");
 MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
 MODULE_DESCRIPTION("Kernel module for testing dynamic_debug");
 MODULE_LICENSE("GPL");
diff --git a/lib/test_dynamic_debug_submod.c b/lib/test_dynamic_debug_submod.c
index 9a893402ce1a..0d15f3ffe466 100644
--- a/lib/test_dynamic_debug_submod.c
+++ b/lib/test_dynamic_debug_submod.c
@@ -1,6 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Kernel module for testing dynamic_debug
+ * Kernel module to test/demonstrate dynamic_debug features,
+ * particularly classmaps and their support for subsystems, like DRM,
+ * which defines its drm_debug classmap in drm module, and uses it in
+ * helpers & drivers.
  *
  * Authors:
  *      Jim Cromie	<jim.cromie@gmail.com>
@@ -8,3 +11,7 @@
 
 #define TEST_DYNAMIC_DEBUG_SUBMOD
 #include "test_dynamic_debug.c"
+
+MODULE_DESCRIPTION("test/demonstrate dynamic-debug subsystem support");
+MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
+MODULE_LICENSE("GPL");
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 29/63] dyndbg-doc: add classmap info to howto
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (27 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 28/63] dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 30/63] dyndbg: treat comma as a token separator Jim Cromie
                   ` (35 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie, linux-doc

Describe the 3 API macros providing dynamic_debug's classmaps

DYNDBG_CLASSMAP_DEFINE - create, exports a module's classmap
DYNDBG_CLASSMAP_USE    - refer to exported map
DYNDBG_CLASSMAP_PARAM  - bind control param to the classmap
DYNDBG_CLASSMAP_PARAM_REF + use module's storage - __drm_debug

cc: linux-doc@vger.kernel.org
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
v5 adjustments per Randy Dunlap
v7 checkpatch fixes
v8 more
v9 rewords
---
 .../admin-guide/dynamic-debug-howto.rst       | 79 ++++++++++++++++++-
 1 file changed, 78 insertions(+), 1 deletion(-)

diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
index 691e0f7d4de1..391e40a510c9 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -230,7 +230,6 @@ the ``p`` flag has meaning, other flags are ignored.
 Note the regexp ``^[-+=][fslmpt_]+$`` matches a flags specification.
 To clear all flags at once, use ``=_`` or ``-fslmpt``.
 
-
 Debug messages during Boot Process
 ==================================
 
@@ -380,3 +379,81 @@ just a shortcut for ``print_hex_dump(KERN_DEBUG)``.
 For ``print_hex_dump_debug()``/``print_hex_dump_bytes()``, format string is
 its ``prefix_str`` argument, if it is constant string; or ``hexdump``
 in case ``prefix_str`` is built dynamically.
+
+Dynamic Debug classmaps
+=======================
+
+The "class" keyword selects prdbgs based on author supplied,
+domain-oriented names.  This complements the nested-scope keywords:
+module, file, function, line.
+
+The main difference from the others: class'd prdbgs must be named to
+be changed.  This protects them from generic overwrite:
+
+  # IOW this cannot undo any DRM.debug settings
+  :#> ddcmd -p
+
+So each class must be enabled individually (no wildcards):
+
+  :#> ddcmd class DRM_UT_CORE +p
+  :#> ddcmd class DRM_UT_KMS +p
+  # or more selectively
+  :#> ddcmd class DRM_UT_CORE module drm +p
+
+Or the legacy/normal (more convenient) way:
+
+  :#> echo 0x1ff > /sys/module/drm/parameters/debug
+
+Dynamic Debug Classmap API
+==========================
+
+DRM.debug is built upon:
+  ~23 macros, all passing a DRM_UT_* constant as arg-1.
+  ~5000 calls to them, across drivers/gpu/drm/*
+  bits in /sys/module/drm/parameters/debug control all DRM_UT_* together
+
+The const short ints are good for optimizing compilers; a classmaps
+design goal was to keep that.  So basically .classid === category.
+
+And since prdbgs are cataloged with just a DRM_UT_* to identify them,
+the "class" keyword maps known classnames to those reserved IDs, and
+by explicitly requiring "class FOO" in queries, we protect FOO class'd
+debugs from overwrite by generic queries.
+
+Its expected that other classmap users will also provide debug-macros
+using an enum-defined categorization scheme like DRM's, and dyndbg can
+be adapted under them similarly.
+
+DYNDBG_CLASSMAP_DEFINE(var,type,_base,classnames) - this maps
+classnames onto class-ids starting at _base, it also maps the
+names onto CLASSMAP_PARAM bits 0..N.
+
+DYNDBG_CLASSMAP_USE(var) - modules call this to refer to the var
+_DEFINEd elsewhere (and exported).
+
+Classmaps are opt-in: modules invoke _DEFINE or _USE to authorize
+dyndbg to update those classes.  "class FOO" queries are validated
+against the classes, this finds the classid to alter; classes are not
+directly selectable by their classid.
+
+There are 2 types of classmaps:
+
+ DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, like DRM.debug
+ DD_CLASS_TYPE_LEVEL_NUM: classes are relative, ordered (V3 > V2)
+
+DYNDBG_CLASSMAP_PARAM - modelled after module_param_cb, it refers to a
+DEFINEd classmap, and associates it to the param's data-store.  This
+state is then applied to DEFINEr and USEr modules when they're modprobed.
+
+The PARAM interface also enforces the DD_CLASS_TYPE_LEVEL_NUM relation
+amongst the contained classnames; all classes are independent in the
+control parser itself; there is no implied meaning in names like "V4".
+
+Modules or module-groups (drm & drivers) can define multiple
+classmaps, as long as they share the limited 0..62 per-module-group
+_class_id range, without overlap.
+
+``#define DEBUG`` will enable all pr_debugs in scope, including any
+class'd ones.  This won't be reflected in the PARAM readback value,
+but the class'd pr_debug callsites can be forced off by toggling the
+classmap-kparam all-on then all-off.
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 30/63] dyndbg: treat comma as a token separator
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (28 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 29/63] dyndbg-doc: add classmap info to howto Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 31/63] selftests-dyndbg: add comma_terminator_tests Jim Cromie
                   ` (34 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Treat comma as a token terminator, just like a space.  This allows a
user to avoid quoting hassles when spaces are otherwise needed:

 :#> modprobe drm dyndbg=class,DRM_UT_CORE,+p\;class,DRM_UT_KMS,+p

or as a boot arg:

 drm.dyndbg=class,DRM_UT_CORE,+p  # todo: support multi-query here

Given the many ways a boot-line +args can be assembled and then passed
in/down/around shell based tools, this may allow side-stepping all
sorts of quoting hassles thru those layers.

existing query format:

 modprobe test_dynamic_debug dyndbg="class D2_CORE +p"

new format:

 modprobe test_dynamic_debug dyndbg=class,D2_CORE,+p

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Co-developed-by: Łukasz Bartosik <ukaszb@chromium.org>
Signed-off-by: Łukasz Bartosik <ukaszb@chromium.org>
---
 lib/dynamic_debug.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 9283f2866415..56e09e878f80 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -293,6 +293,14 @@ static int ddebug_change(const struct ddebug_query *query, struct flag_settings
 	return nfound;
 }
 
+static char *skip_spaces_and_commas(const char *str)
+{
+	str = skip_spaces(str);
+	while (*str == ',')
+		str = skip_spaces(++str);
+	return (char *)str;
+}
+
 /*
  * Split the buffer `buf' into space-separated words.
  * Handles simple " and ' quoting, i.e. without nested,
@@ -306,8 +314,8 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords)
 	while (*buf) {
 		char *end;
 
-		/* Skip leading whitespace */
-		buf = skip_spaces(buf);
+		/* Skip leading whitespace and comma */
+		buf = skip_spaces_and_commas(buf);
 		if (!*buf)
 			break;	/* oh, it was trailing whitespace */
 		if (*buf == '#')
@@ -323,7 +331,7 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords)
 				return -EINVAL;	/* unclosed quote */
 			}
 		} else {
-			for (end = buf; *end && !isspace(*end); end++)
+			for (end = buf; *end && !isspace(*end) && *end != ','; end++)
 				;
 			if (end == buf) {
 				pr_err("parse err after word:%d=%s\n", nwords,
@@ -595,7 +603,8 @@ static int ddebug_exec_queries(char *query, const char *modname)
 		if (split)
 			*split++ = '\0';
 
-		query = skip_spaces(query);
+		query = skip_spaces_and_commas(query);
+
 		if (!query || !*query || *query == '#')
 			continue;
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 31/63] selftests-dyndbg: add comma_terminator_tests
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (29 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 30/63] dyndbg: treat comma as a token separator Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 32/63] dyndbg: split multi-query strings with % Jim Cromie
                   ` (33 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

New fn validates parsing and effect of queries using combinations of
commas and spaces to delimit the tokens.

It manipulates pr-debugs in builtin module/params, so might have deps
I havent foreseen on odd configurations.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
- skip comma tests if no builtins
---
 .../dynamic_debug/dyndbg_selftest.sh          | 21 ++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
index 68a9046405f2..368d10a691a0 100755
--- a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
+++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
@@ -216,7 +216,7 @@ function check_err_msg() {
 function basic_tests {
     echo -e "${GREEN}# BASIC_TESTS ${NC}"
     if [ $LACK_DD_BUILTIN -eq 1 ]; then
-	echo "SKIP"
+	echo "SKIP - test requires params, which is a builtin module"
 	return
     fi
     ddcmd =_ # zero everything
@@ -238,8 +238,27 @@ EOF
     ddcmd =_
 }
 
+function comma_terminator_tests {
+    echo -e "${GREEN}# COMMA_TERMINATOR_TESTS ${NC}"
+    if [ $LACK_DD_BUILTIN -eq 1 ]; then
+	echo "SKIP - test requires params, which is a builtin module"
+	return
+    fi
+    # try combos of spaces & commas
+    check_match_ct '\[params\]' 4 -r
+    ddcmd module,params,=_		# commas as spaces
+    ddcmd module,params,+mpf		# turn on module's pr-debugs
+    check_match_ct =pmf 4
+    ddcmd ,module ,, ,  params, -p
+    check_match_ct =mf 4
+    ddcmd " , module ,,, ,  params, -m"	#
+    check_match_ct =f 4
+    ddcmd =_
+}
+
 tests_list=(
     basic_tests
+    comma_terminator_tests
 )
 
 # Run tests
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 32/63] dyndbg: split multi-query strings with %
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (30 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 31/63] selftests-dyndbg: add comma_terminator_tests Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 33/63] selftests-dyndbg: test_percent_splitting Jim Cromie
                   ` (32 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Since commit
85f7f6c0edb8 ("dynamic_debug: process multiple debug-queries on a line")

Multi-query commands have been allowed:

  modprobe drm dyndbg="class DRM_UT_CORE +p; class DRM_UT_KMS +p"
  modprobe drm dyndbg=<<EOX
     class DRM_UT_CORE +p
     class DRM_UT_KMS +p
  EOX

More recently, the need for quoting was avoided by treating a comma
like a space/token-terminator:

  modprobe drm dyndbg=class,DRM_UT_CORE,+p\;class,DRM_UT_KMS,+p

That works, but it needs the escaped semicolon, which is a shell
special-char (one of the bash control operators), so it is brittle
when passed in/down/around scripts.  In particular, it fails when
passed to vng (virtme-ng).

So this patch adds '%' to the existing ';' and '\n' multi-command
separators, which is more shell-friendly, so you can more fully avoid
quoting and escaping hassles.

NOTE: it does break format matching on '%' patterns:

bash-5.2# ddcmd 'format "find-me: %foo" +p'
[  203.900581] dyndbg: read 26 bytes from userspace
[  203.900883] dyndbg: query 0: "format "find-me: " mod:*
[  203.901118] dyndbg: unclosed quote: find-me:
[  203.901355] dyndbg: tokenize failed
[  203.901529] dyndbg: query 1: "foo" +p" mod:*
[  203.901957] dyndbg: split into words: "foo"" "+p"
[  203.902243] dyndbg: op='+' flags=0x1 maskp=0xffffffff
[  203.902458] dyndbg: expecting pairs of match-spec <value>
[  203.902703] dyndbg: query parse failed
[  203.902871] dyndbg: processed 2 queries, with 0 matches, 2 errs
bash: echo: write error: Invalid argument

The '%' splits the input into 2 queries, and both fail.  Given the
limited utility of matching against the working parts of a format
string "foo: %d bar %s", nothing is actually lost here.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 56e09e878f80..68b5a77c2d79 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -599,7 +599,7 @@ static int ddebug_exec_queries(char *query, const char *modname)
 	int i, errs = 0, exitcode = 0, rc, nfound = 0;
 
 	for (i = 0; query; query = split) {
-		split = strpbrk(query, ";\n");
+		split = strpbrk(query, "%;\n");
 		if (split)
 			*split++ = '\0';
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 33/63] selftests-dyndbg: test_percent_splitting
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (31 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 32/63] dyndbg: split multi-query strings with % Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 34/63] docs/dyndbg: explain new delimiters: comma, percent Jim Cromie
                   ` (31 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

This does basic testing of classmaps using '%' separated
multi-queries.  It modprobes test_dynamic_debug with several classes
enabled, and counts to verify that the expected sites show the
enablement in the control file.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 .../dynamic_debug/dyndbg_selftest.sh          | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
index 368d10a691a0..c97c9391d0f4 100755
--- a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
+++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
@@ -256,9 +256,29 @@ function comma_terminator_tests {
     ddcmd =_
 }
 
+function test_percent_splitting {
+    echo -e "${GREEN}# TEST_PERCENT_SPLITTING - multi-command splitting on % ${NC}"
+    ifrmmod test_dynamic_debug_submod
+    ifrmmod test_dynamic_debug
+    ddcmd =_
+    modprobe test_dynamic_debug dyndbg=class,D2_CORE,+pf%class,D2_KMS,+pt%class,D2_ATOMIC,+pm
+    check_match_ct =pf 1
+    check_match_ct =pt 1
+    check_match_ct =pm 1
+    check_match_ct test_dynamic_debug 23 -r
+    # add flags to those callsites
+    ddcmd class,D2_CORE,+mf%class,D2_KMS,+lt%class,D2_ATOMIC,+ml
+    check_match_ct =pmf 1
+    check_match_ct =plt 1
+    check_match_ct =pml 1
+    check_match_ct test_dynamic_debug 23 -r
+    ifrmmod test_dynamic_debug
+}
+
 tests_list=(
     basic_tests
     comma_terminator_tests
+    test_percent_splitting
 )
 
 # Run tests
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 34/63] docs/dyndbg: explain new delimiters: comma, percent
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (32 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 33/63] selftests-dyndbg: test_percent_splitting Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 35/63] selftests-dyndbg: add test_mod_submod Jim Cromie
                   ` (30 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Add mention of comma and percent delimiters into the respective
paragraphs describing their equivalents: space and newline.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 .../admin-guide/dynamic-debug-howto.rst       | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
index 391e40a510c9..c3537f8689e6 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -78,16 +78,19 @@ Command Language Reference
 ==========================
 
 At the basic lexical level, a command is a sequence of words separated
-by spaces or tabs.  So these are all equivalent::
+by spaces, tabs, or commas.  So these are all equivalent::
 
   :#> ddcmd file svcsock.c line 1603 +p
   :#> ddcmd "file svcsock.c line 1603 +p"
   :#> ddcmd '  file   svcsock.c     line  1603 +p  '
+  :#> ddcmd file,svcsock.c,line,1603,+p
 
-Command submissions are bounded by a write() system call.
-Multiple commands can be written together, separated by ``;`` or ``\n``::
+Command submissions are bounded by a write() system call.  Multiple
+commands can be written together, separated by ``%``, ``;`` or ``\n``::
 
-  :#> ddcmd "func pnpacpi_get_resources +p; func pnp_assign_mem +p"
+  :#> ddcmd func foo +p % func bar +p
+  :#> ddcmd func foo +p \; func bar +p
+  :#> ddcmd "func foo +p ; func bar +p"
   :#> ddcmd <<"EOC"
   func pnpacpi_get_resources +p
   func pnp_assign_mem +p
@@ -109,7 +112,6 @@ The match-spec's select *prdbgs* from the catalog, upon which to apply
 the flags-spec, all constraints are ANDed together.  An absent keyword
 is the same as keyword "*".
 
-
 A match specification is a keyword, which selects the attribute of
 the callsite to be compared, and a value to compare against.  Possible
 keywords are:::
@@ -133,7 +135,6 @@ keywords are:::
   ``line-range`` cannot contain space, e.g.
   "1-30" is valid range but "1 - 30" is not.
 
-
 The meanings of each keyword are:
 
 func
@@ -158,9 +159,11 @@ module
     The given string is compared against the module name
     of each callsite.  The module name is the string as
     seen in ``lsmod``, i.e. without the directory or the ``.ko``
-    suffix and with ``-`` changed to ``_``.  Examples::
+    suffix and with ``-`` changed to ``_``.
+
+    Examples::
 
-	module sunrpc
+	module,sunrpc	# with ',' as token separator
 	module nfsd
 	module drm*	# both drm, drm_kms_helper
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 35/63] selftests-dyndbg: add test_mod_submod
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (33 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 34/63] docs/dyndbg: explain new delimiters: comma, percent Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 36/63] docs/dyndbg: explain flags parse 1st Jim Cromie
                   ` (29 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

This new test-fn runs 3 module/submodule modprobe scenarios, variously
using both the generic dyndbg=<queries> modprobe arg, and the
test-module's classmap-params to manipulate the test-mod*'s pr_debugs.
In all cases, the current flag-settings are counted and tested vs
expectations.

The 3rd scenario recapitulates the DRM_USE_DYNAMIC_DEBUG=y failure.

1. 2 modprobes (super then sub), with separate dyndbg=class-settings
   check module specific flag settings

2. modprobe submod, supermod is auto-loaded
   set supermod class-params
   check expected enablements in super & submod

3. modprobe super, with param=setting (like drm.debug=0x1ef)
   modprobe submod
   validate submod's class'd pr_debugs get properly enabled

The test uses multi-queries, with both commas and percents (to avoid
spaces and quoting).  This is the main reason the test wasn't earlier
in the patchset, closer to the classmap patches its validating.

With some tedium, the tests could be refactored to split out early
tests which avoid multi-cmds, and test only the class-params.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
- drop -v used in test_mod_submod(). V=1 does it for whole test
- ifrmmod at test end (Lukasz)
---
 .../dynamic_debug/dyndbg_selftest.sh          | 69 +++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
index c97c9391d0f4..cfed79b34996 100755
--- a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
+++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
@@ -275,10 +275,79 @@ function test_percent_splitting {
     ifrmmod test_dynamic_debug
 }
 
+function test_mod_submod {
+    echo -e "${GREEN}# TEST_MOD_SUBMOD ${NC}"
+    ifrmmod test_dynamic_debug_submod
+    ifrmmod test_dynamic_debug
+    ddcmd =_
+
+    # modprobe with class enablements
+    modprobe test_dynamic_debug \
+	dyndbg=class,D2_CORE,+pf%class,D2_KMS,+pt%class,D2_ATOMIC,+pm
+
+    check_match_ct '\[test_dynamic_debug\]' 23 -r
+    check_match_ct =pf 1
+    check_match_ct =pt 1
+    check_match_ct =pm 1
+
+    modprobe test_dynamic_debug_submod
+    check_match_ct test_dynamic_debug_submod 23 -r
+    check_match_ct '\[test_dynamic_debug\]' 23 -r
+    check_match_ct test_dynamic_debug 46 -r
+
+    # no enablements propagate here
+    check_match_ct =pf 1
+    check_match_ct =pt 1
+    check_match_ct =pm 1
+
+    # change classes again, this time submod too
+    ddcmd class,D2_CORE,+mf%class,D2_KMS,+lt%class,D2_ATOMIC,+ml "# add some prefixes"
+    check_match_ct =pmf 1
+    check_match_ct =plt 1
+    check_match_ct =pml 1
+    #  submod changed too
+    check_match_ct =mf 1
+    check_match_ct =lt 1
+    check_match_ct =ml 1
+
+    # now work the classmap-params
+    # fresh start, to clear all above flags (test-fn limits)
+    ifrmmod test_dynamic_debug_submod
+    ifrmmod test_dynamic_debug
+    modprobe test_dynamic_debug_submod # get supermod too
+
+    echo 1 > /sys/module/test_dynamic_debug/parameters/p_disjoint_bits
+    echo 4 > /sys/module/test_dynamic_debug/parameters/p_level_num
+    # 2 mods * ( V1-3 + D2_CORE )
+    check_match_ct =p 8
+    echo 3 > /sys/module/test_dynamic_debug/parameters/p_disjoint_bits
+    echo 0 > /sys/module/test_dynamic_debug/parameters/p_level_num
+    # 2 mods * ( D2_CORE, D2_DRIVER )
+    check_match_ct =p 4
+    echo 0x16 > /sys/module/test_dynamic_debug/parameters/p_disjoint_bits
+    echo 0 > /sys/module/test_dynamic_debug/parameters/p_level_num
+    # 2 mods * ( D2_DRIVER, D2_KMS, D2_ATOMIC )
+    check_match_ct =p 6
+
+    # recap DRM_USE_DYNAMIC_DEBUG regression
+    ifrmmod test_dynamic_debug_submod
+    ifrmmod test_dynamic_debug
+    # set super-mod params
+    modprobe test_dynamic_debug p_disjoint_bits=0x16 p_level_num=5
+    check_match_ct =p 7
+    modprobe test_dynamic_debug_submod
+    # see them picked up by submod
+    check_match_ct =p 14
+    ifrmmod test_dynamic_debug_submod
+    ifrmmod test_dynamic_debug
+}
+
 tests_list=(
     basic_tests
+    # these require test_dynamic_debug*.ko
     comma_terminator_tests
     test_percent_splitting
+    test_mod_submod
 )
 
 # Run tests
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 36/63] docs/dyndbg: explain flags parse 1st
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (34 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 35/63] selftests-dyndbg: add test_mod_submod Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 37/63] dyndbg: change __dynamic_func_call_cls* macros into expressions Jim Cromie
                   ` (28 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

When writing queries to >control, flags are parsed 1st, since they are
the only required field, and they require specific compositions.  So
if the flags draw an error (on those specifics), then keyword errors
aren't reported.  This can be mildly confusing/annoying, so explain it
instead.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 Documentation/admin-guide/dynamic-debug-howto.rst | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
index c3537f8689e6..89810ebaca8c 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -112,6 +112,16 @@ The match-spec's select *prdbgs* from the catalog, upon which to apply
 the flags-spec, all constraints are ANDed together.  An absent keyword
 is the same as keyword "*".
 
+Note: because the match-spec can be empty, the flags are checked 1st,
+then the pairs of keyword values.  Flag errs will hide keyword errs:
+
+  bash-5.2# ddcmd mod bar +foo
+  dyndbg: read 13 bytes from userspace
+  dyndbg: query 0: "mod bar +foo" mod:*
+  dyndbg: unknown flag 'o'
+  dyndbg: flags parse failed
+  dyndbg: processed 1 queries, with 0 matches, 1 errs
+
 A match specification is a keyword, which selects the attribute of
 the callsite to be compared, and a value to compare against.  Possible
 keywords are:::
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 37/63] dyndbg: change __dynamic_func_call_cls* macros into expressions
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (35 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 36/63] docs/dyndbg: explain flags parse 1st Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 38/63] dyndbg: drop "protection" of class'd pr_debugs from legacy queries Jim Cromie
                   ` (27 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

The Xe driver's XE_IOCTL_DBG macro calls drm_dbg() from inside an if
(expression).  This breaks when CONFIG_DRM_USE_DYNAMIC_DEBUG=y because
the invoked macro has a do-while-0 wrapper.

   if (cond && (drm_dbg("expr-form"),1)) {
      ... do some more stuff
   }

Fix for this usage by changing __dynamic_func_call_cls{,_no_desc}
macros into expressions, by replacing the do-while-0s with a ({ })
wrapper.  In the common usage, the trailing ';' converts the
expression into a statement.

   drm_dbg("statement form");

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
---
 include/linux/dynamic_debug.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index b47d1088b7ad..1ff7bb6210cf 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -331,20 +331,20 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
  * (|_cls):	adds in _DPRINT_CLASS_DFLT as needed
  * (|_no_desc):	former gets callsite descriptor as 1st arg (for prdbgs)
  */
-#define __dynamic_func_call_cls(id, cls, fmt, func, ...) do {	\
-	DEFINE_DYNAMIC_DEBUG_METADATA_CLS((id), cls, fmt);	\
+#define __dynamic_func_call_cls(id, cls, fmt, func, ...) ({	\
+	DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt);	\
 	if (DYNAMIC_DEBUG_BRANCH(id))				\
-		func(&id, ##__VA_ARGS__);			\
-} while (0)
+		func(&(id), ##__VA_ARGS__);			\
+})
 #define __dynamic_func_call(id, fmt, func, ...)				\
 	__dynamic_func_call_cls(id, _DPRINTK_CLASS_DFLT, fmt,		\
 				func, ##__VA_ARGS__)
 
-#define __dynamic_func_call_cls_no_desc(id, cls, fmt, func, ...) do {	\
+#define __dynamic_func_call_cls_no_desc(id, cls, fmt, func, ...) ({	\
 	DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt);		\
 	if (DYNAMIC_DEBUG_BRANCH(id))					\
 		func(__VA_ARGS__);					\
-} while (0)
+})
 #define __dynamic_func_call_no_desc(id, fmt, func, ...)			\
 	__dynamic_func_call_cls_no_desc(id, _DPRINTK_CLASS_DFLT,	\
 					fmt, func, ##__VA_ARGS__)
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 38/63] dyndbg: drop "protection" of class'd pr_debugs from legacy queries
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (36 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 37/63] dyndbg: change __dynamic_func_call_cls* macros into expressions Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 39/63] drm: use correct ccflags-y spelling Jim Cromie
                   ` (26 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Current classmap code protects class'd pr_debugs from unintended
changes by "legacy" unclassed queries:

  # this doesn't disable all of DRM_UT_* categories
  echo "-p" > /proc/dynamic_debug/control

  # name the class to change it - protective but tedious
  echo "class DRM_UT_CORE +p" > /proc/dynamic_debug/control

  # or do it the subsystem way
  echo 1 > /sys/module/drm/parameters/debug

This "name the class to change it" behavior gave a modicum of
protection to classmap users (ie DRM) so their debug settings aren't
trivially and unintentionally altered underneath them.  Afterall,
__drm_debug is authoritative w/o dyndbg under it.

But this made the class keyword special in some sense; the other
keywords follow the rule: no "keyword value" given means no skipping
on that criterion.

Jason Baron didn't like this special case when I 1st proposed it;
I argued 2 points:
- "protection gives stable-debug, improving utility"
- "class _DFLT" assumed in query is not that special

I thought I'd convinced him back then, (and the patchset got merged),
but he noted it again when he reviewed this series.  So this commit
undoes the special case, indirectly.

The difference in behavior comes down to a choice on how to handle
class-mismatches; ddebug_client_module_protects_classes() names this
choice (and defines it false).  On class-mismatches of this kind, it
is "called" before skipping the legacy cmd on a class'd site.

So this makes it a policy-choice, and reverts to original policy.

Later, if any user/module wants to protect its classes, we could add a
flag to ddebug_table, a means to set it from CLASSMAP_DEFINE, and
check it when applying a classless query/cmd.  Further, runtime mods
to the protection are possible via an exported fn, or a grammar
addition to >control.

NOTES

In ddebug_change(), the 2-part class code is mostly unchanged:

1. query->class_str is validated once per module, and maps good ones
to valid_class, now renamed to slctd_class to convey non-boolean-ness.

2. in the inner per-site loop, site mismatches are now 2 sub-cases:

a. a class_str given explicitly, and site doesn't match it.
   skip/continue.
b. no class_str given, _CLASS_DFLT is inferred
   skip if ddebug_client_module_protects_classes()
   else fall thru to site-change

CC: jbaron@akamai.com
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 lib/dynamic_debug.c | 34 +++++++++++++++++++++++++---------
 1 file changed, 25 insertions(+), 9 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 68b5a77c2d79..9a278c7ca365 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -193,6 +193,17 @@ static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *cl
 	return -ENOENT;
 }
 
+/*
+ * classmaps-v1 protected classes from changes by legacy commands
+ * (those selecting _DPRINTK_CLASS_DFLT by omission), v2 undoes that
+ * special treatment.  State so explicitly.  Later we could give
+ * modules the choice to protect their classes or to keep v2 behavior.
+ */
+static inline bool ddebug_client_module_protects_classes(const struct ddebug_table *dt)
+{
+	return false;
+}
+
 /*
  * Search the tables for _ddebug's which match the given `query' and
  * apply the `flags' and `mask' to them.  Returns number of matching
@@ -206,7 +217,7 @@ static int ddebug_change(const struct ddebug_query *query, struct flag_settings
 	unsigned int newflags;
 	unsigned int nfound = 0;
 	struct flagsbuf fbuf, nbuf;
-	int valid_class;
+	int slctd_class;
 
 	/* search for matching ddebugs */
 	mutex_lock(&ddebug_lock);
@@ -218,21 +229,26 @@ static int ddebug_change(const struct ddebug_query *query, struct flag_settings
 			continue;
 
 		if (query->class_string) {
-			valid_class = ddebug_find_valid_class(dt, query->class_string);
-			if (valid_class < 0)
+			slctd_class = ddebug_find_valid_class(dt, query->class_string);
+			if (slctd_class < 0)
+				/* skip/reject classes unknown by module */
 				continue;
 		} else {
-			/* constrain query, do not touch class'd callsites */
-			valid_class = _DPRINTK_CLASS_DFLT;
+			slctd_class = _DPRINTK_CLASS_DFLT;
 		}
 
 		for (i = 0; i < dt->info.descs.len; i++) {
 			struct _ddebug *dp = &dt->info.descs.start[i];
 
-			/* match site against query-class */
-			if (dp->class_id != valid_class)
-				continue;
-
+			if (dp->class_id != slctd_class) {
+				if (query->class_string)
+					/* site.class != given class */
+					continue;
+				/* legacy query, class'd site */
+				else if (ddebug_client_module_protects_classes(dt))
+					continue;
+				/* allow change on class'd pr_debug */
+			}
 			/* match against the source filename */
 			if (query->filename &&
 			    !match_wildcard(query->filename, dp->filename) &&
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 39/63] drm: use correct ccflags-y spelling
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (37 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 38/63] dyndbg: drop "protection" of class'd pr_debugs from legacy queries Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 40/63] checkpatch: dont warn about unused macro arg on empty body Jim Cromie
                   ` (25 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Incorrectly spelled CFLAGS- failed to add -DDYNAMIC_DEBUG_MODULE,
which disabled dynamic-debug in modules built with:

CONFIG_DYNAMIC_DEBUG=n		# 1
CONFIG_DYNAMIC_DEBUG_CORE=y	# 2
CONFIG_DRM_USE_DYNAMIC_DEBUG=y	# 3

NB: this adds the flag (when 3) more often than strictly needed;
modules built with CONFIG_DYNAMIC_DEBUG=y (!1) don't need the flag.

Fixes: 84ec67288c10 ("drm_print: wrap drm_*_dbg in dyndbg descriptor factory macro")
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/Makefile | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 463afad1b5ca..2d68e6841cde 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -3,7 +3,8 @@
 # Makefile for the drm device driver.  This driver provides support for the
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
-CFLAGS-$(CONFIG_DRM_USE_DYNAMIC_DEBUG)	+= -DDYNAMIC_DEBUG_MODULE
+ccflags-$(CONFIG_DRM_USE_DYNAMIC_DEBUG)		+= -DDYNAMIC_DEBUG_MODULE
+subdir-ccflags-$(CONFIG_DRM_USE_DYNAMIC_DEBUG)	+= -DDYNAMIC_DEBUG_MODULE
 
 # Unconditionally enable W=1 warnings locally
 # --- begin copy-paste W=1 warnings from scripts/Makefile.extrawarn
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 40/63] checkpatch: dont warn about unused macro arg on empty body
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (38 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 39/63] drm: use correct ccflags-y spelling Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 41/63] drm-dyndbg: adapt drm core to use dyndbg classmaps-v2 Jim Cromie
                   ` (24 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie, Andy Whitcroft, Joe Perches, Dwaipayan Ray,
	Lukas Bulwahn

we currently get:
  WARNING: Argument 'name' is not used in function-like macro
on:
  #define DRM_CLASSMAP_USE(name)  /* nothing here */

Following this advice is wrong here, and shouldn't be fixed by
ignoring args altogether; the macro should properly fail if invoked
with 0 or 2+ args.

cc: Andy Whitcroft <apw@canonical.com>
cc: Joe Perches <joe@perches.com>
cc: Dwaipayan Ray <dwaipayanray1@gmail.com>
cc: Lukas Bulwahn <lukas.bulwahn@gmail.com>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 scripts/checkpatch.pl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 4a93b2ede8cd..8933bd30317c 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -6046,7 +6046,7 @@ sub process {
 				}
 
 # check if this is an unused argument
-				if ($define_stmt !~ /\b$arg\b/) {
+				if ($define_stmt !~ /\b$arg\b/ && $define_stmt) {
 					WARN("MACRO_ARG_UNUSED",
 					     "Argument '$arg' is not used in function-like macro\n" . "$herectx");
 				}
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 41/63] drm-dyndbg: adapt drm core to use dyndbg classmaps-v2
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (39 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 40/63] checkpatch: dont warn about unused macro arg on empty body Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 42/63] drm-dyndbg: adapt DRM to invoke DYNDBG_CLASSMAP_PARAM Jim Cromie
                   ` (23 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

dyndbg's CLASSMAP-v1 api was broken; DECLARE_DYNDBG_CLASSMAP tried to
do too much.  Its replaced by DRM_CLASSMAP_DEFINE, which creates &
EXPORTs a classmap (in DRM core), and DRM_CLASSMAP_USE which refers to
the classmap defined elsewhere.

The drivers still use DECLARE_DYNDBG_CLASSMAP for now, so they still
redundantly re-declare the classmap, but we can convert the drivers
later to DYNDBG_CLASSMAP_USE

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
this ignores a checkpatch
 WARNING: Argument 'name' is not used in function-like macro
 #70: FILE: include/drm/drm_print.h:148:
 +#define DRM_CLASSMAP_USE(name)

the macro is empty, and correct. only 1 arg is expected.
---
 drivers/gpu/drm/drm_print.c | 25 +++++++++++++------------
 include/drm/drm_print.h     |  8 ++++++++
 2 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c
index 08cfea04e22b..8f7b2aed81ce 100644
--- a/drivers/gpu/drm/drm_print.c
+++ b/drivers/gpu/drm/drm_print.c
@@ -55,18 +55,19 @@ MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug cat
 #if !defined(CONFIG_DRM_USE_DYNAMIC_DEBUG)
 module_param_named(debug, __drm_debug, ulong, 0600);
 #else
-/* classnames must match vals of enum drm_debug_category */
-DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
-			"DRM_UT_CORE",
-			"DRM_UT_DRIVER",
-			"DRM_UT_KMS",
-			"DRM_UT_PRIME",
-			"DRM_UT_ATOMIC",
-			"DRM_UT_VBL",
-			"DRM_UT_STATE",
-			"DRM_UT_LEASE",
-			"DRM_UT_DP",
-			"DRM_UT_DRMRES");
+/* classnames must match value-symbols of enum drm_debug_category */
+DRM_CLASSMAP_DEFINE(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS,
+		    DRM_UT_CORE,
+		    "DRM_UT_CORE",
+		    "DRM_UT_DRIVER",
+		    "DRM_UT_KMS",
+		    "DRM_UT_PRIME",
+		    "DRM_UT_ATOMIC",
+		    "DRM_UT_VBL",
+		    "DRM_UT_STATE",
+		    "DRM_UT_LEASE",
+		    "DRM_UT_DP",
+		    "DRM_UT_DRMRES");
 
 static struct ddebug_class_param drm_debug_bitmap = {
 	.bits = &__drm_debug,
diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h
index b3906dc04388..46aa1bcee1a2 100644
--- a/include/drm/drm_print.h
+++ b/include/drm/drm_print.h
@@ -140,6 +140,14 @@ enum drm_debug_category {
 	DRM_UT_DRMRES
 };
 
+#ifdef CONFIG_DRM_USE_DYNAMIC_DEBUG
+#define DRM_CLASSMAP_DEFINE(...) DYNDBG_CLASSMAP_DEFINE(__VA_ARGS__)
+#define DRM_CLASSMAP_USE(name)   DYNDBG_CLASSMAP_USE(name)
+#else
+#define DRM_CLASSMAP_DEFINE(...)
+#define DRM_CLASSMAP_USE(name)
+#endif
+
 static inline bool drm_debug_enabled_raw(enum drm_debug_category category)
 {
 	return unlikely(__drm_debug & BIT(category));
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 42/63] drm-dyndbg: adapt DRM to invoke DYNDBG_CLASSMAP_PARAM
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (40 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 41/63] drm-dyndbg: adapt drm core to use dyndbg classmaps-v2 Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 43/63] drm-print: fix config-dependent unused variable Jim Cromie
                   ` (22 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Invoke DYNDBG_CLASSMAP_PARAM to hook drm.debug (__drm_debug) to the
DRM_UT_* classmap, replacing the ad-hoc wiring previously doing it.

Add DRM_CLASSMAP_* adapter macros to selectively use DYNDBG_CLASSMAP_*
when DRM_USE_DYNAMIC_DEBUG=y is configured.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/drm_print.c | 8 ++------
 include/drm/drm_print.h     | 8 ++++++--
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c
index 8f7b2aed81ce..b5fe0c37dcee 100644
--- a/drivers/gpu/drm/drm_print.c
+++ b/drivers/gpu/drm/drm_print.c
@@ -69,12 +69,8 @@ DRM_CLASSMAP_DEFINE(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS,
 		    "DRM_UT_DP",
 		    "DRM_UT_DRMRES");
 
-static struct ddebug_class_param drm_debug_bitmap = {
-	.bits = &__drm_debug,
-	.flags = "p",
-	.map = &drm_debug_classes,
-};
-module_param_cb(debug, &param_ops_dyndbg_classes, &drm_debug_bitmap, 0600);
+DRM_CLASSMAP_PARAM_REF(debug, __drm_debug, drm_debug_classes, p);
+
 #endif
 
 void __drm_puts_coredump(struct drm_printer *p, const char *str)
diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h
index 46aa1bcee1a2..53b62b6459a0 100644
--- a/include/drm/drm_print.h
+++ b/include/drm/drm_print.h
@@ -141,11 +141,15 @@ enum drm_debug_category {
 };
 
 #ifdef CONFIG_DRM_USE_DYNAMIC_DEBUG
-#define DRM_CLASSMAP_DEFINE(...) DYNDBG_CLASSMAP_DEFINE(__VA_ARGS__)
-#define DRM_CLASSMAP_USE(name)   DYNDBG_CLASSMAP_USE(name)
+#define DRM_CLASSMAP_DEFINE(...)    DYNDBG_CLASSMAP_DEFINE(__VA_ARGS__)
+#define DRM_CLASSMAP_USE(name)      DYNDBG_CLASSMAP_USE(name)
+#define DRM_CLASSMAP_PARAM_REF(...) DYNDBG_CLASSMAP_PARAM_REF(__VA_ARGS__)
+#define DRM_CLASSMAP_PARAM(...)     DYNDBG_CLASSMAP_PARAM(__VA_ARGS__)
 #else
 #define DRM_CLASSMAP_DEFINE(...)
 #define DRM_CLASSMAP_USE(name)
+#define DRM_CLASSMAP_PARAM_REF(...)
+#define DRM_CLASSMAP_PARAM(...)
 #endif
 
 static inline bool drm_debug_enabled_raw(enum drm_debug_category category)
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 43/63] drm-print: fix config-dependent unused variable
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (41 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 42/63] drm-dyndbg: adapt DRM to invoke DYNDBG_CLASSMAP_PARAM Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 44/63] drm-dyndbg: DRM_CLASSMAP_USE in amdgpu driver Jim Cromie
                   ` (21 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

With CONFIG_DRM_USE_DYNAMIC_DEBUG=y, __drm_printfn_dbg() gets an
unused variable warning/error on 'category', even though the usage
follows immediately, in drm_debug_enabled(category).

For static-key optimized dyndbg, the macro doesn't actually check the
category var, since the static-key patches in the proper state.  The
compiler evidently sees this lack of reference and complains.

So this drops the local var and refs the field directly in the
macro-call, which avoids the warning/error.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/drm_print.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c
index b5fe0c37dcee..dcdf21eb73f1 100644
--- a/drivers/gpu/drm/drm_print.c
+++ b/drivers/gpu/drm/drm_print.c
@@ -212,9 +212,8 @@ void __drm_printfn_dbg(struct drm_printer *p, struct va_format *vaf)
 {
 	const struct drm_device *drm = p->arg;
 	const struct device *dev = drm ? drm->dev : NULL;
-	enum drm_debug_category category = p->category;
 
-	if (!__drm_debug_enabled(category))
+	if (!__drm_debug_enabled(p->category))
 		return;
 
 	__drm_dev_vprintk(dev, KERN_DEBUG, p->origin, p->prefix, vaf);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 44/63] drm-dyndbg: DRM_CLASSMAP_USE in amdgpu driver
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (42 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 43/63] drm-print: fix config-dependent unused variable Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:45 ` [PATCH 45/63] drm-dyndbg: DRM_CLASSMAP_USE in i915 driver Jim Cromie
                   ` (20 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Following the dyndbg-api-fix, replace DECLARE_DYNDBG_CLASSMAP with
DRM_CLASSMAP_USE.  This refs the defined & exported classmap, rather
than re-declaring it redundantly, and error-prone-ly.

This resolves the appearance of "class:_UNKNOWN_" in the control file
for the driver's drm_dbg()s.

Fixes: f158936b60a7 ("drm: POC drm on dyndbg - use in core, 2 helpers, 3 drivers.")

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 38686203bea6..fab98e8418b4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -232,17 +232,7 @@ int amdgpu_wbrf = -1;
 int amdgpu_damage_clips = -1; /* auto */
 int amdgpu_umsch_mm_fwlog;
 
-DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
-			"DRM_UT_CORE",
-			"DRM_UT_DRIVER",
-			"DRM_UT_KMS",
-			"DRM_UT_PRIME",
-			"DRM_UT_ATOMIC",
-			"DRM_UT_VBL",
-			"DRM_UT_STATE",
-			"DRM_UT_LEASE",
-			"DRM_UT_DP",
-			"DRM_UT_DRMRES");
+DRM_CLASSMAP_USE(drm_debug_classes);
 
 struct amdgpu_mgpu_info mgpu_info = {
 	.mutex = __MUTEX_INITIALIZER(mgpu_info.mutex),
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 45/63] drm-dyndbg: DRM_CLASSMAP_USE in i915 driver
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (43 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 44/63] drm-dyndbg: DRM_CLASSMAP_USE in amdgpu driver Jim Cromie
@ 2025-01-25  6:45 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 46/63] drm-dyndbg: DRM_CLASSMAP_USE in drm_crtc_helper Jim Cromie
                   ` (19 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:45 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Following the dyndbg-api-fix, replace DECLARE_DYNDBG_CLASSMAP with
DRM_CLASSMAP_USE.  This refs the defined & exported classmap, rather
than re-declaring it redundantly, and error-prone-ly.

This resolves the appearance of "class:_UNKNOWN_" in the control file
for the driver's drm_dbg()s.

Fixes: f158936b60a7 ("drm: POC drm on dyndbg - use in core, 2 helpers, 3 drivers.")

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/i915/i915_params.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index 37746dd619fd..2dc0e2c06e09 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -29,17 +29,7 @@
 #include "i915_params.h"
 #include "i915_drv.h"
 
-DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
-			"DRM_UT_CORE",
-			"DRM_UT_DRIVER",
-			"DRM_UT_KMS",
-			"DRM_UT_PRIME",
-			"DRM_UT_ATOMIC",
-			"DRM_UT_VBL",
-			"DRM_UT_STATE",
-			"DRM_UT_LEASE",
-			"DRM_UT_DP",
-			"DRM_UT_DRMRES");
+DRM_CLASSMAP_USE(drm_debug_classes);
 
 #define i915_param_named(name, T, perm, desc) \
 	module_param_named(name, i915_modparams.name, T, perm); \
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 46/63] drm-dyndbg: DRM_CLASSMAP_USE in drm_crtc_helper
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (44 preceding siblings ...)
  2025-01-25  6:45 ` [PATCH 45/63] drm-dyndbg: DRM_CLASSMAP_USE in i915 driver Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 47/63] drm-dyndbg: DRM_CLASSMAP_USE in drm_dp_helper Jim Cromie
                   ` (18 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Following the dyndbg-api-fix, replace DECLARE_DYNDBG_CLASSMAP with
DRM_CLASSMAP_USE.  This refs the defined & exported classmap, rather
than re-declaring it redundantly, and error-prone-ly.

This resolves the appearance of "class:_UNKNOWN_" in the control file
for the driver's drm_dbg()s.

Fixes: f158936b60a7 ("drm: POC drm on dyndbg - use in core, 2 helpers, 3 drivers.")

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/drm_crtc_helper.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 0955f1c385dd..1d08d759f238 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -50,17 +50,7 @@
 
 #include "drm_crtc_helper_internal.h"
 
-DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
-			"DRM_UT_CORE",
-			"DRM_UT_DRIVER",
-			"DRM_UT_KMS",
-			"DRM_UT_PRIME",
-			"DRM_UT_ATOMIC",
-			"DRM_UT_VBL",
-			"DRM_UT_STATE",
-			"DRM_UT_LEASE",
-			"DRM_UT_DP",
-			"DRM_UT_DRMRES");
+DRM_CLASSMAP_USE(drm_debug_classes);
 
 /**
  * DOC: overview
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 47/63] drm-dyndbg: DRM_CLASSMAP_USE in drm_dp_helper
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (45 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 46/63] drm-dyndbg: DRM_CLASSMAP_USE in drm_crtc_helper Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 48/63] drm-dyndbg: DRM_CLASSMAP_USE in nouveau Jim Cromie
                   ` (17 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Following the dyndbg-api-fix, replace DECLARE_DYNDBG_CLASSMAP with
DRM_CLASSMAP_USE.  This refs the defined & exported classmap, rather
than re-declaring it redundantly, and error-prone-ly.

This resolves the appearance of "class:_UNKNOWN_" in the control file
for the driver's drm_dbg()s.

Fixes: f158936b60a7 ("drm: POC drm on dyndbg - use in core, 2 helpers, 3 drivers.")

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/display/drm_dp_helper.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c
index 6ee51003de3c..04884ff96c96 100644
--- a/drivers/gpu/drm/display/drm_dp_helper.c
+++ b/drivers/gpu/drm/display/drm_dp_helper.c
@@ -42,17 +42,7 @@
 
 #include "drm_dp_helper_internal.h"
 
-DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
-			"DRM_UT_CORE",
-			"DRM_UT_DRIVER",
-			"DRM_UT_KMS",
-			"DRM_UT_PRIME",
-			"DRM_UT_ATOMIC",
-			"DRM_UT_VBL",
-			"DRM_UT_STATE",
-			"DRM_UT_LEASE",
-			"DRM_UT_DP",
-			"DRM_UT_DRMRES");
+DRM_CLASSMAP_USE(drm_debug_classes);
 
 struct dp_aux_backlight {
 	struct backlight_device *base;
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 48/63] drm-dyndbg: DRM_CLASSMAP_USE in nouveau
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (46 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 47/63] drm-dyndbg: DRM_CLASSMAP_USE in drm_dp_helper Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 49/63] drm-dyndbg: add DRM_CLASSMAP_USE to Xe driver Jim Cromie
                   ` (16 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Following the dyndbg-api-fix, replace DECLARE_DYNDBG_CLASSMAP with
DRM_CLASSMAP_USE.  This refs the defined & exported classmap, rather
than re-declaring it redundantly, and error-prone-ly.

This resolves the appearance of "class:_UNKNOWN_" in the control file
for the driver's drm_dbg()s.

Fixes: f158936b60a7 ("drm: POC drm on dyndbg - use in core, 2 helpers, 3 drivers.")

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/nouveau/nouveau_drm.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 107f63f08bd9..416e122fa58d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -72,17 +72,7 @@
 #include "nouveau_uvmm.h"
 #include "nouveau_sched.h"
 
-DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
-			"DRM_UT_CORE",
-			"DRM_UT_DRIVER",
-			"DRM_UT_KMS",
-			"DRM_UT_PRIME",
-			"DRM_UT_ATOMIC",
-			"DRM_UT_VBL",
-			"DRM_UT_STATE",
-			"DRM_UT_LEASE",
-			"DRM_UT_DP",
-			"DRM_UT_DRMRES");
+DRM_CLASSMAP_USE(drm_debug_classes);
 
 MODULE_PARM_DESC(config, "option string to pass to driver core");
 static char *nouveau_config;
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 49/63] drm-dyndbg: add DRM_CLASSMAP_USE to Xe driver
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (47 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 48/63] drm-dyndbg: DRM_CLASSMAP_USE in nouveau Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 50/63] drm-dyndbg: add DRM_CLASSMAP_USE to virtio_gpu Jim Cromie
                   ` (15 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Invoke DRM_CLASSMAP_USE from xe_drm_client.c.  When built with
CONFIG_DRM_USE_DYNAMIC_DEBUG=y, this tells dydnbg that Xe uses
has drm.debug calls.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/xe/xe_drm_client.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/xe/xe_drm_client.c b/drivers/gpu/drm/xe/xe_drm_client.c
index 22f0f1a6dfd5..6d36c2ae4f93 100644
--- a/drivers/gpu/drm/xe/xe_drm_client.c
+++ b/drivers/gpu/drm/xe/xe_drm_client.c
@@ -21,6 +21,8 @@
 #include "xe_pm.h"
 #include "xe_trace.h"
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 /**
  * DOC: DRM Client usage stats
  *
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 50/63] drm-dyndbg: add DRM_CLASSMAP_USE to virtio_gpu
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (48 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 49/63] drm-dyndbg: add DRM_CLASSMAP_USE to Xe driver Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 51/63] drm-dyndbg: add DRM_CLASSMAP_USE to simpledrm Jim Cromie
                   ` (14 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

virtio_gpu has 10 DRM_UT_CORE debugs, make them controllable when
CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling dyndbg that the module has
class'd debugs.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/virtio/virtgpu_drv.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c
index ffca6e2e1c9a..fca1a1250161 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.c
@@ -45,6 +45,8 @@ static const struct drm_driver driver;
 
 static int virtio_gpu_modeset = -1;
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
 module_param_named(modeset, virtio_gpu_modeset, int, 0400);
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 51/63] drm-dyndbg: add DRM_CLASSMAP_USE to simpledrm
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (49 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 50/63] drm-dyndbg: add DRM_CLASSMAP_USE to virtio_gpu Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 52/63] drm-dyndbg: add DRM_CLASSMAP_USE to bochs Jim Cromie
                   ` (13 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

tiny/simpledrm has 3 DRM_UT_DRIVER debugs, make them controllable when
CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling dyndbg that the module has
class'd debugs.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/tiny/simpledrm.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 4d4f05dee244..7d9e7420d85f 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -35,6 +35,8 @@
 #define DRIVER_MAJOR	1
 #define DRIVER_MINOR	0
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 /*
  * Helpers for simplefb
  */
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 52/63] drm-dyndbg: add DRM_CLASSMAP_USE to bochs
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (50 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 51/63] drm-dyndbg: add DRM_CLASSMAP_USE to simpledrm Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 53/63] drm-dyndbg: add DRM_CLASSMAP_USE to etnaviv Jim Cromie
                   ` (12 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

tiny/bochs has 5 DRM_UT_* debugs, make them controllable when
CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling dyndbg that the module has
class'd debugs.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/tiny/bochs.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/tiny/bochs.c b/drivers/gpu/drm/tiny/bochs.c
index 6f91ff1dbf7e..d29541aa82ab 100644
--- a/drivers/gpu/drm/tiny/bochs.c
+++ b/drivers/gpu/drm/tiny/bochs.c
@@ -59,6 +59,8 @@ static int bochs_modeset = -1;
 static int defx = 1024;
 static int defy = 768;
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 module_param_named(modeset, bochs_modeset, int, 0444);
 MODULE_PARM_DESC(modeset, "enable/disable kernel modesetting");
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 53/63] drm-dyndbg: add DRM_CLASSMAP_USE to etnaviv
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (51 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 52/63] drm-dyndbg: add DRM_CLASSMAP_USE to bochs Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 54/63] drm-dyndbg: add DRM_CLASSMAP_USE to gma500 driver Jim Cromie
                   ` (11 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

etnaviv has 5 DRM_UT_CORE debugs, make them controllable when
CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling dyndbg that the module has
class'd debugs as well as plain-old pr_debug()s

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index a46f9e4ac09a..9c2bf8b5726a 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -25,6 +25,8 @@
 #include "etnaviv_mmu.h"
 #include "etnaviv_perfmon.h"
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 /*
  * DRM operations:
  */
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 54/63] drm-dyndbg: add DRM_CLASSMAP_USE to gma500 driver
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (52 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 53/63] drm-dyndbg: add DRM_CLASSMAP_USE to etnaviv Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 55/63] drm-dyndbg: add DRM_CLASSMAP_USE to radeon Jim Cromie
                   ` (10 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

The gma500 has 126 DRM_UT_* debugs, make them controllable when
CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling dyndbg that the module has
class'd debugs.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/gma500/psb_drv.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index c419ebbc49ec..0d53806b6f72 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -40,6 +40,8 @@
 static const struct drm_driver driver;
 static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 /*
  * The table below contains a mapping of the PCI vendor ID and the PCI Device ID
  * to the different groups of PowerVR 5-series chip designs
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 55/63] drm-dyndbg: add DRM_CLASSMAP_USE to radeon
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (53 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 54/63] drm-dyndbg: add DRM_CLASSMAP_USE to gma500 driver Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 56/63] drm-dyndbg: add DRM_CLASSMAP_USE to vmwgfx driver Jim Cromie
                   ` (9 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

radeon has some DRM_UT_* debugs, make them controllable when
CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling dyndbg about its use of
the class'd debugs.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/radeon/radeon_drv.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 5e958cc223f4..beea273df8cd 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -253,6 +253,8 @@ static const struct pci_device_id pciidlist[] = {
 };
 MODULE_DEVICE_TABLE(pci, pciidlist);
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 static const struct drm_driver kms_driver;
 
 static int radeon_pci_probe(struct pci_dev *pdev,
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 56/63] drm-dyndbg: add DRM_CLASSMAP_USE to vmwgfx driver
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (54 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 55/63] drm-dyndbg: add DRM_CLASSMAP_USE to radeon Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 57/63] drm-dyndbg: add DRM_CLASSMAP_USE to vkms driver Jim Cromie
                   ` (8 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

The vmwgfx driver has a number of DRM_UT_* debugs, make them
controllable when CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling dyndbg
that the module uses them.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index b19a062592b0..20ad48f3efd0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -279,6 +279,8 @@ static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
 static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
 			      void *ptr);
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 MODULE_PARM_DESC(restrict_iommu, "Try to limit IOMMU usage for TTM pages");
 module_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600);
 MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages");
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 57/63] drm-dyndbg: add DRM_CLASSMAP_USE to vkms driver
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (55 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 56/63] drm-dyndbg: add DRM_CLASSMAP_USE to vmwgfx driver Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 58/63] drm-dyndbg: add DRM_CLASSMAP_USE to udl driver Jim Cromie
                   ` (7 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

The vkms driver has a number of DRM_UT_* debugs, make them
controllable when CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling dyndbg
that the module uses them.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/vkms/vkms_drv.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 2d1e95cb66e5..4d6b525dc5a0 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -40,6 +40,8 @@
 
 static struct vkms_config *default_config;
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 static bool enable_cursor = true;
 module_param_named(enable_cursor, enable_cursor, bool, 0444);
 MODULE_PARM_DESC(enable_cursor, "Enable/Disable cursor support");
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 58/63] drm-dyndbg: add DRM_CLASSMAP_USE to udl driver
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (56 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 57/63] drm-dyndbg: add DRM_CLASSMAP_USE to vkms driver Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 59/63] drm-dyndbg: add DRM_CLASSMAP_USE to mgag200 driver Jim Cromie
                   ` (6 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

The udl driver has a number of DRM_UT_* debugs, make them
controllable when CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling dyndbg
that the module uses them.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/udl/udl_main.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index 3ebe2ce55dfd..ba57c14454e5 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -19,6 +19,8 @@
 
 #define NR_USB_REQUEST_CHANNEL 0x12
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 #define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE)
 #define WRITES_IN_FLIGHT (20)
 #define MAX_VENDOR_DESCRIPTOR_SIZE 256
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 59/63] drm-dyndbg: add DRM_CLASSMAP_USE to mgag200 driver
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (57 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 58/63] drm-dyndbg: add DRM_CLASSMAP_USE to udl driver Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 60/63] drm-dyndbg: add DRM_CLASSMAP_USE to the gud driver Jim Cromie
                   ` (5 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

The mgag200 driver has a number of DRM_UT_* debugs, make them
controllable when CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling dyndbg
that the module uses them.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/mgag200/mgag200_drv.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index 97fd7eb765b4..c6000692b5ce 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -27,6 +27,8 @@ static int mgag200_modeset = -1;
 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
 module_param_named(modeset, mgag200_modeset, int, 0400);
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2)
 {
 	struct device *dev = &pdev->dev;
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 60/63] drm-dyndbg: add DRM_CLASSMAP_USE to the gud driver
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (58 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 59/63] drm-dyndbg: add DRM_CLASSMAP_USE to mgag200 driver Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 61/63] drm-dyndbg: add DRM_CLASSMAP_USE to the qxl driver Jim Cromie
                   ` (4 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

The gud driver has a number of DRM_UT_* debugs, make them
controllable when CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling dyndbg
that the module uses them.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/gud/gud_drv.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c
index 09ccdc1dc1a2..20b526c39392 100644
--- a/drivers/gpu/drm/gud/gud_drv.c
+++ b/drivers/gpu/drm/gud/gud_drv.c
@@ -32,6 +32,8 @@
 
 #include "gud_internal.h"
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 /* Only used internally */
 static const struct drm_format_info gud_drm_format_r1 = {
 	.format = GUD_DRM_FORMAT_R1,
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 61/63] drm-dyndbg: add DRM_CLASSMAP_USE to the qxl driver
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (59 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 60/63] drm-dyndbg: add DRM_CLASSMAP_USE to the gud driver Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 62/63] drm-dyndbg: add DRM_CLASSMAP_USE to the drm_gem_shmem_helper driver Jim Cromie
                   ` (3 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

The qxl driver has a number of DRM_UT_* debugs, make them
controllable when CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling dyndbg
that the module uses them.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/qxl/qxl_drv.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index 21f752644242..4b72ad1ac72e 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -66,6 +66,8 @@ module_param_named(modeset, qxl_modeset, int, 0400);
 MODULE_PARM_DESC(num_heads, "Number of virtual crtcs to expose (default 4)");
 module_param_named(num_heads, qxl_num_crtc, int, 0400);
 
+DRM_CLASSMAP_USE(drm_debug_classes);
+
 static struct drm_driver qxl_driver;
 static struct pci_driver qxl_pci_driver;
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 62/63] drm-dyndbg: add DRM_CLASSMAP_USE to the drm_gem_shmem_helper driver
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (60 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 61/63] drm-dyndbg: add DRM_CLASSMAP_USE to the qxl driver Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 63/63] drm: restore CONFIG_DRM_USE_DYNAMIC_DEBUG un-BROKEN Jim Cromie
                   ` (2 subsequent siblings)
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

The drm_gem_shmem_helper driver has a number of DRM_UT_* debugs, make
them controllable when CONFIG_DRM_USE_DYNAMIC_DEBUG=y by telling
dyndbg that the module uses them.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index 5ab351409312..481d18561688 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -23,6 +23,7 @@
 #include <drm/drm_print.h>
 
 MODULE_IMPORT_NS("DMA_BUF");
+DRM_CLASSMAP_USE(drm_debug_classes);
 
 /**
  * DOC: overview
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 63/63] drm: restore CONFIG_DRM_USE_DYNAMIC_DEBUG un-BROKEN
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (61 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 62/63] drm-dyndbg: add DRM_CLASSMAP_USE to the drm_gem_shmem_helper driver Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-01-25  6:46 ` [PATCH 64/64] This series fixes dyndbg (dynamic debug) classmap support for DRM Jim Cromie
  2025-02-20  8:31 ` [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Greg KH
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Time for some thorough CI.

Also, the previous 18 patches could perhaps be replaced by a single
invocation of DYNDBG_CLASSMAP_USE, from a C-file linked into all drm
drivers & helpers.  I didn't find such a file, nor a drm-client
linkage item in the Makefile.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 drivers/gpu/drm/Kconfig | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 772fc7625639..dde5a5e37680 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -53,8 +53,7 @@ config DRM_DEBUG_MM
 
 config DRM_USE_DYNAMIC_DEBUG
 	bool "use dynamic debug to implement drm.debug"
-	default n
-	depends on BROKEN
+	default y
 	depends on DRM
 	depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE
 	depends on JUMP_LABEL
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH 64/64] This series fixes dyndbg (dynamic debug) classmap support for DRM.
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (62 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 63/63] drm: restore CONFIG_DRM_USE_DYNAMIC_DEBUG un-BROKEN Jim Cromie
@ 2025-01-25  6:46 ` Jim Cromie
  2025-02-20  8:31 ` [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Greg KH
  64 siblings, 0 replies; 103+ messages in thread
From: Jim Cromie @ 2025-01-25  6:46 UTC (permalink / raw)
  To: linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Jim Cromie

Despite a few latent flaws (1-3 below), classmaps-v1 went in with:

ee7d633f2dfb drm-print.h: include dyndbg header
84ec67288c10 drm_print: wrap drm_*_dbg in dyndbg descriptor factory macro
e820f52577b1 drm_print: interpose drm_*dbg with forwarding macros
f158936b60a7 drm: POC drm on dyndbg - use in core, 2 helpers, 3 drivers.
0406faf25fb1 drm_print: condense enum drm_debug_category

and

6ea3bf466ac6 dyndbg: test DECLARE_DYNDBG_CLASSMAP, sysfs nodes
b9400852c080 dyndbg: add drm.debug style (drm/parameters/debug) bitmap support
ace7c4bbb240 doc-dyndbg: edit dynamic-debug-howto for brevity, audience
753914ed85ac doc-dyndbg: describe "class CLASS_NAME" query support
a4a2a427413e dyndbg: validate class FOO by checking with module
c45f67ace832 dyndbg: add ddebug_attach_module_classes
66f4006b6ace kernel/module: add __dyndbg_classes section
aad0214f3026 dyndbg: add DECLARE_DYNDBG_CLASSMAP macro
3fc95d80a536 dyndbg: add __pr_debug_cls for testing
ca90fca7f7b5 dyndbg: add class_id to pr_debug callsites
b7b4eebdba7b dyndbg: gather __dyndbg[] state into struct _ddebug_info

Those flaws:

1. Regression during initialization.  classmaps-v1 inits drm-dbg
callsites' static-keys when drm is "modprobed/initd" with
drm.debug=<initval>, but not during driver & helper modprobes.

Previously __drm_debug vs DRM_UT_* was checked at runtime, which
made this a non-issue.  My test scripts passed dyndbg=<options>,
which obscured this lack of "propagation" to drivers, and I didn't
pick up on it.

2. DECLARE_DYNDBG_CLASSMAP violated a K&R rule "define once, refer
after", and is the root cause under 1.

3. classmaps-v1 was something of a flag-day patchset; dyndbg & DRM
parts were overly coupled, and test-dyndbg didn't validate multi-
module classes.

Consequently we got:
commit bb2ff6c27bc9 ("drm: Disable dynamic debug as broken")

Classmaps-v2 fixes these as follows:

2. replace DECLARE_DYNDBG_CLASSMAP with DYNDBG_CLASSMAP_DEFINE
(invoked once in drm-core) and DYNDBG_CLASSMAP_USE (repeatedly, in
drivers & helpers).

_DEFINE now exports the classmap, which _USE can repeatedly refer to.

_USE adds a usage/linkage record referring to the _DEFINEd (&
exported) classmap, in a new __dyndbg_class_users section.

1. Now at modprobe, dyndbg scans the new section, follows the linkage
to the _DEFINEr module, finds the (optional) kernel-param controlling
the classmap, examines its drm.debug=<initval>, and applies it to the
module being initialized.

3. test/validate dyndbg for multi-module classes wo DRM involvement.

A. add test_dynamic_debug_submod.ko, a clone of parent.
This allows recapitulating various multi-module scenarios.

B. add tools/testing/selftests/dynamic_debug/*

This verifies spec'd behavior, including the multi-module scenarios
made available in 3a.

C. to decouple dyndbg from DRM, DECLARE_DYNDBG_CLASSMAP is preserved
until after DRM adapts to the api change.

Since the last rev sent here/LKML:
  https://lore.kernel.org/lkml/20240716185806.1572048-1-jim.cromie@gmail.com/

Ive rebased onto recent drm-tip, and tested with drm-trybot:
  https://patchwork.freedesktop.org/series/139147/

and made the following additions:

1- drop class "protection" special case, per JBaron's preference.
   current use is marked BROKEN so nobody to affect.
   now framed as policy-choice:
   #define ddebug_client_module_protects_classes false

2- compile-time arg-tests in DYNDBG_CLASSMAP_DEFINE
   implement several required constraints, fail obviously.

3- modprobe time check of conflicting class-id reservations
   only affects 2+classmaps users.
   compile-time solution not apparent.

4- dyndbg can now cause modprobe to fail.
   needed toq catch 3.
   maybe some loose ends here on failure.

5- refactor & rename ddebug_attach_*module_classes
   reduce repetetive boilerplate on 2 types: maps, users.
   rework mostly brought forward in patchset to reduce churn
   TBD: maybe squash more.

The recent trybot submissions (against drm-tip) pass CI.BAT, and fail
one or few CI.IGT tests randomly; re-tests do not repeat the failures.

its also at github.com:jimc/linux.git

commit c0f15eda9c3676149dedbc5a5fc0faee9550a2f7 (HEAD -> dd-fix-9s-ontip, ghlinux/dd-fix-9s-ontip)

Im running it on my laptop & desktop w/o issues.

The drivers/gpu/drm patches are RFC, I think there might be a place to
put a single DRM_CLASSMAP_USE(drm_ddbug_classes) to replace the
sprinkling of USEs in drivers and helpers.  IIRC, I tried adding a
_DEFINE into drm_drv.c, that didn't do it.

I think the dyndbg core additions are ready for review and merging
into a (next-next) test/integration tree, I'd like to find out.

Jim Cromie (63):
pre-cleanup:
  docs/dyndbg: update examples \012 to \n
  test-dyndbg: fixup CLASSMAP usage error
  dyndbg: reword "class unknown," to "class:_UNKNOWN_"
  dyndbg: make ddebug_class_param union members same size
  dyndbg: replace classmap list with a vector
  dyndbg: ddebug_apply_class_bitmap - add module arg, select on it
  dyndbg: split param_set_dyndbg_classes to _module & wrapper fns
  dyndbg: drop NUM_TYPE_ARRAY
  dyndbg: reduce verbose/debug clutter
  dyndbg: silence debugs with no-change updates
  dyndbg: tighten ddebug_class_name() 1st arg type
  dyndbg: tighten fn-sig of ddebug_apply_class_bitmap
  dyndbg: reduce verbose=3 messages in ddebug_add_module
  dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code
  checkpatch: add an exception to the do-while wrapper advice

core change:
  dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP
  dyndbg: check DYNDBG_CLASSMAP_DEFINE args at compile-time
  dyndbg: add/use for_subvec() to reduce boilerplate
  dyndbg: make proper substructs in _ddebug_info
  dyndbg: drop premature optimization in ddebug_add_module
  dyndbg: allow ddebug_add_module to fail
  dyndbg: rework ddebug_attach_*module_classes()
  dyndbg: fail modprobe on ddebug_class_range_overlap()
  dyndbg: hoist the range-overlap checks
  ddebug: cleanup-range-overlap fails
  dyndbg-test: change do_prints testpoint to accept a loopct
  selftests-dyndbg: add tools/testing/selftests/dynamic_debug/*
  dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API
  dyndbg-doc: add classmap info to howto

new features:
  dyndbg: treat comma as a token separator
  selftests-dyndbg: add comma_terminator_tests
  dyndbg: split multi-query strings with %
  selftests-dyndbg: test_percent_splitting
  docs/dyndbg: explain new delimiters: comma, percent

finishing:
  selftests-dyndbg: add test_mod_submod
  docs/dyndbg: explain flags parse 1st
  dyndbg: change __dynamic_func_call_cls* macros into expressions
  dyndbg: drop "protection" of class'd pr_debugs from legacy queries

DRM: (phase 2)
  drm: use correct ccflags-y spelling
  checkpatch: dont warn about unused macro arg on empty body
  drm-dyndbg: adapt drm core to use dyndbg classmaps-v2
  drm-dyndbg: adapt DRM to invoke DYNDBG_CLASSMAP_PARAM
  drm-print: fix config-dependent unused variable
  drm-dyndbg: DRM_CLASSMAP_USE in amdgpu driver
  drm-dyndbg: DRM_CLASSMAP_USE in i915 driver
  drm-dyndbg: DRM_CLASSMAP_USE in drm_crtc_helper
  drm-dyndbg: DRM_CLASSMAP_USE in drm_dp_helper
  drm-dyndbg: DRM_CLASSMAP_USE in nouveau
  drm-dyndbg: add DRM_CLASSMAP_USE to Xe driver
  drm-dyndbg: add DRM_CLASSMAP_USE to virtio_gpu
  drm-dyndbg: add DRM_CLASSMAP_USE to simpledrm
  drm-dyndbg: add DRM_CLASSMAP_USE to bochs
  drm-dyndbg: add DRM_CLASSMAP_USE to etnaviv
  drm-dyndbg: add DRM_CLASSMAP_USE to gma500 driver
  drm-dyndbg: add DRM_CLASSMAP_USE to radeon
  drm-dyndbg: add DRM_CLASSMAP_USE to vmwgfx driver
  drm-dyndbg: add DRM_CLASSMAP_USE to vkms driver
  drm-dyndbg: add DRM_CLASSMAP_USE to udl driver
  drm-dyndbg: add DRM_CLASSMAP_USE to mgag200 driver
  drm-dyndbg: add DRM_CLASSMAP_USE to the gud driver
  drm-dyndbg: add DRM_CLASSMAP_USE to the qxl driver
  drm-dyndbg: add DRM_CLASSMAP_USE to the drm_gem_shmem_helper driver
  drm: restore CONFIG_DRM_USE_DYNAMIC_DEBUG un-BROKEN

 .../admin-guide/dynamic-debug-howto.rst       | 116 +++-
 MAINTAINERS                                   |   3 +-
 drivers/gpu/drm/Kconfig                       |   3 +-
 drivers/gpu/drm/Makefile                      |   3 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c       |  12 +-
 drivers/gpu/drm/display/drm_dp_helper.c       |  12 +-
 drivers/gpu/drm/drm_crtc_helper.c             |  12 +-
 drivers/gpu/drm/drm_gem_shmem_helper.c        |   2 +
 drivers/gpu/drm/drm_print.c                   |  38 +-
 drivers/gpu/drm/etnaviv/etnaviv_drv.c         |   2 +
 drivers/gpu/drm/gma500/psb_drv.c              |   2 +
 drivers/gpu/drm/gud/gud_drv.c                 |   2 +
 drivers/gpu/drm/i915/i915_params.c            |  12 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c         |   2 +
 drivers/gpu/drm/nouveau/nouveau_drm.c         |  12 +-
 drivers/gpu/drm/qxl/qxl_drv.c                 |   2 +
 drivers/gpu/drm/radeon/radeon_drv.c           |   2 +
 drivers/gpu/drm/tiny/bochs.c                  |   2 +
 drivers/gpu/drm/tiny/simpledrm.c              |   2 +
 drivers/gpu/drm/udl/udl_main.c                |   2 +
 drivers/gpu/drm/virtio/virtgpu_drv.c          |   2 +
 drivers/gpu/drm/vkms/vkms_drv.c               |   2 +
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c           |   2 +
 drivers/gpu/drm/xe/xe_drm_client.c            |   2 +
 include/asm-generic/vmlinux.lds.h             |   1 +
 include/drm/drm_print.h                       |  12 +
 include/linux/dynamic_debug.h                 | 193 ++++--
 kernel/module/main.c                          |  15 +-
 lib/Kconfig.debug                             |  24 +-
 lib/Makefile                                  |   3 +
 lib/dynamic_debug.c                           | 555 +++++++++++-------
 lib/test_dynamic_debug.c                      | 181 +++---
 lib/test_dynamic_debug_submod.c               |  17 +
 scripts/checkpatch.pl                         |   3 +-
 tools/testing/selftests/Makefile              |   1 +
 .../testing/selftests/dynamic_debug/Makefile  |   9 +
 tools/testing/selftests/dynamic_debug/config  |   2 +
 .../dynamic_debug/dyndbg_selftest.sh          | 364 ++++++++++++
 38 files changed, 1206 insertions(+), 425 deletions(-)
 create mode 100644 lib/test_dynamic_debug_submod.c
 create mode 100644 tools/testing/selftests/dynamic_debug/Makefile
 create mode 100644 tools/testing/selftests/dynamic_debug/config
 create mode 100755 tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh

--
2.47.0
-- 
2.47.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y
  2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
                   ` (63 preceding siblings ...)
  2025-01-25  6:46 ` [PATCH 64/64] This series fixes dyndbg (dynamic debug) classmap support for DRM Jim Cromie
@ 2025-02-20  8:31 ` Greg KH
  2025-02-20  9:45   ` Simona Vetter
  64 siblings, 1 reply; 103+ messages in thread
From: Greg KH @ 2025-02-20  8:31 UTC (permalink / raw)
  To: Jim Cromie
  Cc: linux-kernel, jbaron, ukaszb, intel-gfx-trybot, dri-devel,
	amd-gfx, intel-gvt-dev, intel-gfx, daniel.vetter, tvrtko.ursulin,
	jani.nikula, ville.syrjala

On Fri, Jan 24, 2025 at 11:45:14PM -0700, Jim Cromie wrote:
> This series fixes dynamic-debug's support for DRM debug-categories.
> Classmaps-v1 evaded full review, and got committed in 2 chunks:
> 
>   b7b4eebdba7b..6ea3bf466ac6	# core dyndbg changes
>   0406faf25fb1..ee7d633f2dfb	# drm adoption
> 
> DRM-CI found a regression during init with drm.debug=<initval>; the
> static-keys under the drm-dbgs in drm.ko got enabled, but those in
> drivers & helpers did not.
> 
> Root Problem:
> 
> DECLARE_DYNDBG_CLASSMAP violated a K&R rule "define once, refer
> afterwards".  Replace it with DYNDBG_CLASSMAP_DEFINE (invoked once in
> drm-core) and DYNDBG_CLASSMAP_USE (invoked repeatedly, in drivers &
> helpers).
> 
> _DEFINE exports the classmap it creates (in drm.ko), other modules
> _USE the classmap.  The _USE adds a record ref'g the _DEFINEd (&
> exported) classmap, in a 2nd __dyndbg_class_users section.
> 
> So now at modprobe, dyndbg scans the new section after the 1st
> __dyndbg_class_maps section, follows the linkage to the _DEFINEr
> module, finds the (optional) kernel-param controlling the classmap,
> examines its drm.debug=<initval>, and applies it to the module being
> initialized.
> 
> To recapitulate the multi-module problem wo DRM involvement, Add:
> 
> A. tools/testing/selftests/dynamic_debug/*
> 
> This alters pr_debugs in the test-modules, counts the results and
> checks them against expectations.  It uses this formula to test most
> of the control grammar, including the new class keyword.
> 
> B. test_dynamic_debug_submod.ko
> 
> This alters the test-module to build both parent & _submod ko's, with
> _DEFINE and _USE inside #if/#else blocks.  This recap's DRM's 2 module
> failure scenario, allowing A to exersize several cases.
> 
> The #if/#else puts the 2 macro uses together for clarity, and gives
> the 2 modules identical sets of debugs.
> 
> Recent DRM-CI tests are here:
>   https://patchwork.freedesktop.org/series/139147/
> 
> Previous rev:
>   https://lore.kernel.org/lkml/20240716185806.1572048-1-jim.cromie@gmail.com/
> 
> Noteworthy Additions:
> 
> 1- drop class "protection" special case, per JBaron's preference.
>    only current use is marked BROKEN so nobody to affect.
>    now framed as policy-choice:
>    #define ddebug_client_module_protects_classes() false
>    subsystems wanting protection can change this.
> 
> 2- compile-time arg-tests in DYNDBG_CLASSMAP_DEFINE
>    implement several required constraints, and fail obviously.
> 
> 3- modprobe time check of conflicting class-id reservations
>    only affects 2+classmaps users.
>    compile-time solution not apparent.
> 
> 4- dyndbg can now cause modprobe to fail.
>    needed to catch 3.
>    maybe some loose ends here on failure.
> 
> 5- refactor & rename ddebug_attach_*module_classes
>    reduce repetetive boilerplate on 2 types: maps, users.
>    rework mostly brought forward in patchset to reduce churn
>    TBD: maybe squash more.
> 
> Several recent trybot submissions (against drm-tip) have been passing
> CI.BAT, and failing one or few CI.IGT tests randomly; re-tests do not
> reliably repeat the failures.
> 
> its also at github.com:jimc/linux.git
>   dd-fix-9[st]-ontip  &  dd-fix-9-13
> 
> Ive been running it on my desktop w/o issues.
> 
> The drivers/gpu/drm patches are RFC, I think there might be a single
> place to call DRM_CLASSMAP_USE(drm_dedbug_classes) to replace the
> sprinkling of _USEs in drivers and helpers.  IIRC, I tried adding a
> _DEFINE into drm_drv.c, that didn't do it, so I punted for now.
> 
> I think the dyndbg core additions are ready for review and merging
> into a (next-next) test/integration tree.

So whose tree should this go through?

And I think the last patch in this series isn't correct, it looks like a
000 email somehow.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y
  2025-02-20  8:31 ` [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Greg KH
@ 2025-02-20  9:45   ` Simona Vetter
  2025-02-28 16:24     ` Louis Chauvet
  0 siblings, 1 reply; 103+ messages in thread
From: Simona Vetter @ 2025-02-20  9:45 UTC (permalink / raw)
  To: Greg KH
  Cc: Jim Cromie, linux-kernel, jbaron, ukaszb, intel-gfx-trybot,
	dri-devel, amd-gfx, intel-gvt-dev, intel-gfx, daniel.vetter,
	tvrtko.ursulin, jani.nikula, ville.syrjala

On Thu, Feb 20, 2025 at 09:31:41AM +0100, Greg KH wrote:
> On Fri, Jan 24, 2025 at 11:45:14PM -0700, Jim Cromie wrote:
> > This series fixes dynamic-debug's support for DRM debug-categories.
> > Classmaps-v1 evaded full review, and got committed in 2 chunks:
> > 
> >   b7b4eebdba7b..6ea3bf466ac6	# core dyndbg changes
> >   0406faf25fb1..ee7d633f2dfb	# drm adoption
> > 
> > DRM-CI found a regression during init with drm.debug=<initval>; the
> > static-keys under the drm-dbgs in drm.ko got enabled, but those in
> > drivers & helpers did not.
> > 
> > Root Problem:
> > 
> > DECLARE_DYNDBG_CLASSMAP violated a K&R rule "define once, refer
> > afterwards".  Replace it with DYNDBG_CLASSMAP_DEFINE (invoked once in
> > drm-core) and DYNDBG_CLASSMAP_USE (invoked repeatedly, in drivers &
> > helpers).
> > 
> > _DEFINE exports the classmap it creates (in drm.ko), other modules
> > _USE the classmap.  The _USE adds a record ref'g the _DEFINEd (&
> > exported) classmap, in a 2nd __dyndbg_class_users section.
> > 
> > So now at modprobe, dyndbg scans the new section after the 1st
> > __dyndbg_class_maps section, follows the linkage to the _DEFINEr
> > module, finds the (optional) kernel-param controlling the classmap,
> > examines its drm.debug=<initval>, and applies it to the module being
> > initialized.
> > 
> > To recapitulate the multi-module problem wo DRM involvement, Add:
> > 
> > A. tools/testing/selftests/dynamic_debug/*
> > 
> > This alters pr_debugs in the test-modules, counts the results and
> > checks them against expectations.  It uses this formula to test most
> > of the control grammar, including the new class keyword.
> > 
> > B. test_dynamic_debug_submod.ko
> > 
> > This alters the test-module to build both parent & _submod ko's, with
> > _DEFINE and _USE inside #if/#else blocks.  This recap's DRM's 2 module
> > failure scenario, allowing A to exersize several cases.
> > 
> > The #if/#else puts the 2 macro uses together for clarity, and gives
> > the 2 modules identical sets of debugs.
> > 
> > Recent DRM-CI tests are here:
> >   https://patchwork.freedesktop.org/series/139147/
> > 
> > Previous rev:
> >   https://lore.kernel.org/lkml/20240716185806.1572048-1-jim.cromie@gmail.com/
> > 
> > Noteworthy Additions:
> > 
> > 1- drop class "protection" special case, per JBaron's preference.
> >    only current use is marked BROKEN so nobody to affect.
> >    now framed as policy-choice:
> >    #define ddebug_client_module_protects_classes() false
> >    subsystems wanting protection can change this.
> > 
> > 2- compile-time arg-tests in DYNDBG_CLASSMAP_DEFINE
> >    implement several required constraints, and fail obviously.
> > 
> > 3- modprobe time check of conflicting class-id reservations
> >    only affects 2+classmaps users.
> >    compile-time solution not apparent.
> > 
> > 4- dyndbg can now cause modprobe to fail.
> >    needed to catch 3.
> >    maybe some loose ends here on failure.
> > 
> > 5- refactor & rename ddebug_attach_*module_classes
> >    reduce repetetive boilerplate on 2 types: maps, users.
> >    rework mostly brought forward in patchset to reduce churn
> >    TBD: maybe squash more.
> > 
> > Several recent trybot submissions (against drm-tip) have been passing
> > CI.BAT, and failing one or few CI.IGT tests randomly; re-tests do not
> > reliably repeat the failures.
> > 
> > its also at github.com:jimc/linux.git
> >   dd-fix-9[st]-ontip  &  dd-fix-9-13
> > 
> > Ive been running it on my desktop w/o issues.
> > 
> > The drivers/gpu/drm patches are RFC, I think there might be a single
> > place to call DRM_CLASSMAP_USE(drm_dedbug_classes) to replace the
> > sprinkling of _USEs in drivers and helpers.  IIRC, I tried adding a
> > _DEFINE into drm_drv.c, that didn't do it, so I punted for now.
> > 
> > I think the dyndbg core additions are ready for review and merging
> > into a (next-next) test/integration tree.
> 
> So whose tree should this go through?

I'm trying to get some drm folks to review/test this, but thus far not
much success :-/ I think it's good stuff, but I'm somewhat hesitant if no
one else agrees that it's useful for CI or in-field crash-recording or
whatever ...

I guess worst case we can land it and hope it attracts more folks?

Wrt tree I don't care, but I guess we should then also land the drm side
too.
-Sima

> And I think the last patch in this series isn't correct, it looks like a
> 000 email somehow.
> 
> thanks,
> 
> greg k-h

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

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 02/63] test-dyndbg: fixup CLASSMAP usage error
  2025-01-25  6:45 ` [PATCH 02/63] test-dyndbg: fixup CLASSMAP usage error Jim Cromie
@ 2025-02-25 11:22   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 11:22 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Konstantin Ryabitsev



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> A more careful reading of logging output from test_dynamic_debug.ko
> reveals:
> 
> lib/test_dynamic_debug.c:103 [test_dynamic_debug]do_cats =pmf "doing categories\n"
> lib/test_dynamic_debug.c:105 [test_dynamic_debug]do_cats =p "LOW msg\n" class:MID
> lib/test_dynamic_debug.c:106 [test_dynamic_debug]do_cats =p "MID msg\n" class:HI
> lib/test_dynamic_debug.c:107 [test_dynamic_debug]do_cats =_ "HI msg\n" class unknown, _id:13
> 
> 107 says: HI is unknown, 105,106 have LOW/MID and MID/HI skew.
> 
> The enum's 1st val (explicitly initialized) was wrong; it must be
> _base, not _base+1 (a DECLARE_DYNDBG_CLASSMAP param).  So the last
> enumeration exceeded the range of mapped class-id's, which triggered
> the "class unknown" report.  I coded in an error, intending to verify
> err detection, then forgot, and missed that it was there.
> 
> So this patch fixes a bad usage of DECLARE_DYNDBG_CLASSMAP(), showing
> that it is too error-prone.  As noted in test-mod comments:
> 
>   * Using the CLASSMAP api:
>   * - classmaps must have corresponding enum
>   * - enum symbols must match/correlate with class-name strings in the map.
>   * - base must equal enum's 1st value
>   * - multiple maps must set their base to share the 0-62 class_id space !!
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
Tested-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   lib/test_dynamic_debug.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
> index 77c2a669b6af..396144cf351b 100644
> --- a/lib/test_dynamic_debug.c
> +++ b/lib/test_dynamic_debug.c
> @@ -75,7 +75,7 @@ DD_SYS_WRAP(disjoint_bits, p);
>   DD_SYS_WRAP(disjoint_bits, T);
>   
>   /* symbolic input, independent bits */
> -enum cat_disjoint_names { LOW = 11, MID, HI };
> +enum cat_disjoint_names { LOW = 10, MID, HI };
>   DECLARE_DYNDBG_CLASSMAP(map_disjoint_names, DD_CLASS_TYPE_DISJOINT_NAMES, 10,
>   			"LOW", "MID", "HI");
>   DD_SYS_WRAP(disjoint_names, p);

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 03/63] dyndbg: reword "class unknown," to "class:_UNKNOWN_"
  2025-01-25  6:45 ` [PATCH 03/63] dyndbg: reword "class unknown," to "class:_UNKNOWN_" Jim Cromie
@ 2025-02-25 11:22   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 11:22 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> When a dyndbg classname is unknown to a kernel module (as before
> previous patch), the callsite is un-addressable via >control queries.
> 
> The control-file displays this condition as "class unknown,"
> currently.  That spelling is sub-optimal/too-generic, so change it to
> "class:_UNKNOWN_" to loudly announce the erroneous situation, and to
> make it exceedingly greppable.
> 
> NB: pr_debugs are only alterable via >control, and to protect class'd
> debug's from unintended alteration, "class name" must be given to
> change them.  Classmaps map known classes to reserved .class_ids (the
> 1..64 val range per module).
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   lib/dynamic_debug.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 5a007952f7f2..147540c57154 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -1154,7 +1154,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
>   		if (class)
>   			seq_printf(m, " class:%s", class);
>   		else
> -			seq_printf(m, " class unknown, _id:%d", dp->class_id);
> +			seq_printf(m, " class:_UNKNOWN_ _id:%d", dp->class_id);
>   	}
>   	seq_putc(m, '\n');
>   

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 04/63] dyndbg: make ddebug_class_param union members same size
  2025-01-25  6:45 ` [PATCH 04/63] dyndbg: make ddebug_class_param union members same size Jim Cromie
@ 2025-02-25 11:24   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 11:24 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> struct ddebug_class_param keeps a ref to the state-storage of the
> param; make both class-types use the same unsigned long storage type.
> 
> ISTM this is simpler and safer; it avoids an irrelevant difference,
> and if 2 users somehow get class-type mixed up (or refer to the wrong
> union member), at least they will both see the same value.
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   include/linux/dynamic_debug.h | 2 +-
>   lib/dynamic_debug.c           | 2 +-
>   2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> index ff44ec346162..b9afc7731b7c 100644
> --- a/include/linux/dynamic_debug.h
> +++ b/include/linux/dynamic_debug.h
> @@ -124,7 +124,7 @@ struct _ddebug_info {
>   struct ddebug_class_param {
>   	union {
>   		unsigned long *bits;
> -		unsigned int *lvl;
> +		unsigned long *lvl;
>   	};
>   	char flags[8];
>   	const struct ddebug_class_map *map;
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 147540c57154..55df35df093b 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -799,7 +799,7 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
>   
>   	case DD_CLASS_TYPE_LEVEL_NAMES:
>   	case DD_CLASS_TYPE_LEVEL_NUM:
> -		return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl);
> +		return scnprintf(buffer, PAGE_SIZE, "%ld\n", *dcp->lvl);
>   	default:
>   		return -1;
>   	}

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 05/63] dyndbg: replace classmap list with a vector
  2025-01-25  6:45 ` [PATCH 05/63] dyndbg: replace classmap list with a vector Jim Cromie
@ 2025-02-25 14:08   ` Louis Chauvet
  2025-03-16 14:04     ` jim.cromie
  0 siblings, 1 reply; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:08 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> Classmaps are stored in an elf section/array, but are individually
> list-linked onto dyndbg's per-module ddebug_table for operation.
> 
> This is unnecessary; even when ddebug_attach_classmap() is handling
> the builtin section (with classmaps for multiple builtin modules), its
> contents are ordered, so a module's possibly multiple classmaps will
> be consecutive in the section, and could be treated as a vector/block,
> since both start-address and subrange length are in the ddebug_info arg.
> 
> IOW, this treats classmaps similarly to _ddebugs, which are already
> kept as vector-refs (address+len).
> 
> So this changes:
> 
> struct ddebug_class_map drops list-head link.
> 
> struct ddebug_table drops the list-head maps, and gets: classes &
> num_classes for the start-address and num_classes, placed to improve
> struct packing.
> 
> The loading: in ddebug_attach_module_classes(), replace the
> for-the-modname list-add loop, with a forloop that finds the module's
> subrange (start,length) of matching classmaps within the possibly
> builtin classmaps vector, and saves those to the ddebug_table.
> 
> The reading/using: change list-foreach loops in ddebug_class_name() &
> ddebug_find_valid_class() to walk the array from start to length.
> 
> Also:
> Move #define __outvar up, above an added use in a fn-prototype.
> Simplify ddebug_attach_module_classes args, ref has both address & len.
> 
> no functional changes
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> ---
>   include/linux/dynamic_debug.h |  1 -
>   lib/dynamic_debug.c           | 61 ++++++++++++++++++-----------------
>   2 files changed, 32 insertions(+), 30 deletions(-)
> 
> diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> index b9afc7731b7c..2b0057058ecf 100644
> --- a/include/linux/dynamic_debug.h
> +++ b/include/linux/dynamic_debug.h
> @@ -83,7 +83,6 @@ enum class_map_type {
>   };
>   
>   struct ddebug_class_map {
> -	struct list_head link;
>   	struct module *mod;
>   	const char *mod_name;	/* needed for builtins */
>   	const char **class_names;
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 55df35df093b..41cbaa96f83d 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -45,10 +45,11 @@ extern struct ddebug_class_map __start___dyndbg_classes[];
>   extern struct ddebug_class_map __stop___dyndbg_classes[];
>   
>   struct ddebug_table {
> -	struct list_head link, maps;
> +	struct list_head link;
>   	const char *mod_name;
> -	unsigned int num_ddebugs;
>   	struct _ddebug *ddebugs;
> +	struct ddebug_class_map *classes;
> +	unsigned int num_ddebugs, num_classes;
>   };
>   
>   struct ddebug_query {
> @@ -147,13 +148,15 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
>   		  query->first_lineno, query->last_lineno, query->class_string);
>   }
>   
> +#define __outvar /* filled by callee */

Hi Jim,

What is the goal of this __outvar define? I can't find any other #define 
of it in the kernel.

>   static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
> -							  const char *class_string, int *class_id)
> +							const char *class_string,
> +							__outvar int *class_id)

The order between __outvar and int is not important? Here you have 
__outvar before int, but later [1] the __outvar is after int.

[1]:https://elixir.bootlin.com/linux/v6.14-rc3/source/lib/dynamic_debug.c#L183

Thanks,
Louis Chauvet

>   {
>   	struct ddebug_class_map *map;
> -	int idx;
> +	int i, idx;
>   
> -	list_for_each_entry(map, &dt->maps, link) {
> +	for (map = dt->classes, i = 0; i < dt->num_classes; i++, map++) {
>   		idx = match_string(map->class_names, map->length, class_string);
>   		if (idx >= 0) {
>   			*class_id = idx + map->base;
> @@ -164,7 +167,6 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
>   	return NULL;
>   }
>   
> -#define __outvar /* filled by callee */
>   /*
>    * Search the tables for _ddebug's which match the given `query' and
>    * apply the `flags' and `mask' to them.  Returns number of matching
> @@ -1114,9 +1116,10 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
>   
>   static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp)
>   {
> -	struct ddebug_class_map *map;
> +	struct ddebug_class_map *map = iter->table->classes;
> +	int i, nc = iter->table->num_classes;
>   
> -	list_for_each_entry(map, &iter->table->maps, link)
> +	for (i = 0; i < nc; i++, map++)
>   		if (class_in_range(dp->class_id, map))
>   			return map->class_names[dp->class_id - map->base];
>   
> @@ -1200,30 +1203,31 @@ static const struct proc_ops proc_fops = {
>   	.proc_write = ddebug_proc_write
>   };
>   
> -static void ddebug_attach_module_classes(struct ddebug_table *dt,
> -					 struct ddebug_class_map *classes,
> -					 int num_classes)
> +static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
>   {
>   	struct ddebug_class_map *cm;
> -	int i, j, ct = 0;
> +	int i, nc = 0;
>   
> -	for (cm = classes, i = 0; i < num_classes; i++, cm++) {
> +	/*
> +	 * Find this module's classmaps in a subrange/wholerange of
> +	 * the builtin/modular classmap vector/section.  Save the start
> +	 * and length of the subrange at its edges.
> +	 */
> +	for (cm = di->classes, i = 0; i < di->num_classes; i++, cm++) {
>   
>   		if (!strcmp(cm->mod_name, dt->mod_name)) {
> -
> -			v2pr_info("class[%d]: module:%s base:%d len:%d ty:%d\n", i,
> -				  cm->mod_name, cm->base, cm->length, cm->map_type);
> -
> -			for (j = 0; j < cm->length; j++)
> -				v3pr_info(" %d: %d %s\n", j + cm->base, j,
> -					  cm->class_names[j]);
> -
> -			list_add(&cm->link, &dt->maps);
> -			ct++;
> +			if (!nc) {
> +				v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
> +					  i, cm->mod_name, cm->base, cm->length, cm->map_type);
> +				dt->classes = cm;
> +			}
> +			nc++;
>   		}
>   	}
> -	if (ct)
> -		vpr_info("module:%s attached %d classes\n", dt->mod_name, ct);
> +	if (nc) {
> +		dt->num_classes = nc;
> +		vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
> +	}
>   }
>   
>   /*
> @@ -1256,10 +1260,9 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   	dt->num_ddebugs = di->num_descs;
>   
>   	INIT_LIST_HEAD(&dt->link);
> -	INIT_LIST_HEAD(&dt->maps);
>   
>   	if (di->classes && di->num_classes)
> -		ddebug_attach_module_classes(dt, di->classes, di->num_classes);
> +		ddebug_attach_module_classes(dt, di);
>   
>   	mutex_lock(&ddebug_lock);
>   	list_add_tail(&dt->link, &ddebug_tables);
> @@ -1372,8 +1375,8 @@ static void ddebug_remove_all_tables(void)
>   	mutex_lock(&ddebug_lock);
>   	while (!list_empty(&ddebug_tables)) {
>   		struct ddebug_table *dt = list_entry(ddebug_tables.next,
> -						      struct ddebug_table,
> -						      link);
> +						     struct ddebug_table,
> +						     link);
>   		ddebug_table_free(dt);
>   	}
>   	mutex_unlock(&ddebug_lock);

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 06/63] dyndbg: ddebug_apply_class_bitmap - add module arg, select on it
  2025-01-25  6:45 ` [PATCH 06/63] dyndbg: ddebug_apply_class_bitmap - add module arg, select on it Jim Cromie
@ 2025-02-25 14:09   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:09 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> Add param: query_module to ddebug_apply_class_bitmap(), and pass it
> thru to _ddebug_queries(), replacing NULL with query_module.  This
> allows its caller to update just one module, or all (as currently).
> 
> We'll use this later to propagate drm.debug to each USEr as they're
> modprobed.
> 
> No functional change.
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
> 
> after `modprobe i915`, heres the module dependencies,
> though not all on drm.debug.
> 
> bash-5.2# lsmod
> Module                  Size  Used by
> i915                 3133440  0
> drm_buddy              20480  1 i915
> ttm                    90112  1 i915
> i2c_algo_bit           16384  1 i915
> video                  61440  1 i915
> wmi                    32768  1 video
> drm_display_helper    200704  1 i915
> drm_kms_helper        208896  2 drm_display_helper,i915
> drm                   606208  5 drm_kms_helper,drm_display_helper,drm_buddy,i915,ttm
> cec                    57344  2 drm_display_helper,i915
> ---
>   lib/dynamic_debug.c | 19 ++++++++++++-------
>   1 file changed, 12 insertions(+), 7 deletions(-)
> 
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 41cbaa96f83d..8adb81e75a16 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -605,7 +605,8 @@ static int ddebug_exec_queries(char *query, const char *modname)
>   
>   /* apply a new bitmap to the sys-knob's current bit-state */
>   static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
> -				     unsigned long *new_bits, unsigned long *old_bits)
> +				     unsigned long *new_bits, unsigned long *old_bits,
> +				     const char *query_modname)
>   {
>   #define QUERY_SIZE 128
>   	char query[QUERY_SIZE];
> @@ -613,7 +614,8 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
>   	int matches = 0;
>   	int bi, ct;
>   
> -	v2pr_info("apply: 0x%lx to: 0x%lx\n", *new_bits, *old_bits);
> +	v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits,
> +		  query_modname ?: "");
>   
>   	for (bi = 0; bi < map->length; bi++) {
>   		if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
> @@ -622,12 +624,15 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
>   		snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi],
>   			 test_bit(bi, new_bits) ? '+' : '-', dcp->flags);
>   
> -		ct = ddebug_exec_queries(query, NULL);
> +		ct = ddebug_exec_queries(query, query_modname);
>   		matches += ct;
>   
>   		v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
>   			  ct, map->class_names[bi], *new_bits);
>   	}
> +	v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits,
> +		  query_modname ?: "");
> +
>   	return matches;
>   }
>   
> @@ -682,7 +687,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
>   				continue;
>   			}
>   			curr_bits ^= BIT(cls_id);
> -			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits);
> +			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits, NULL);
>   			*dcp->bits = curr_bits;
>   			v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id,
>   				  map->class_names[cls_id]);
> @@ -692,7 +697,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
>   			old_bits = CLASSMAP_BITMASK(*dcp->lvl);
>   			curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 ));
>   
> -			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits);
> +			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits, NULL);
>   			*dcp->lvl = (cls_id + (wanted ? 1 : 0));
>   			v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id,
>   				  map->class_names[cls_id], old_bits, curr_bits);
> @@ -755,7 +760,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
>   			inrep &= CLASSMAP_BITMASK(map->length);
>   		}
>   		v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp));
> -		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits);
> +		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits, NULL);
>   		*dcp->bits = inrep;
>   		break;
>   	case DD_CLASS_TYPE_LEVEL_NUM:
> @@ -768,7 +773,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
>   		old_bits = CLASSMAP_BITMASK(*dcp->lvl);
>   		new_bits = CLASSMAP_BITMASK(inrep);
>   		v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
> -		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits);
> +		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits, NULL);
>   		*dcp->lvl = inrep;
>   		break;
>   	default:

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 07/63] dyndbg: split param_set_dyndbg_classes to _module & wrapper fns
  2025-01-25  6:45 ` [PATCH 07/63] dyndbg: split param_set_dyndbg_classes to _module & wrapper fns Jim Cromie
@ 2025-02-25 14:09   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:09 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> Split api-fn: param_set_dyndbg_classes(), adding modname param and
> passing NULL in from api-fn.
> 
> The new arg allows caller to specify that only one module is affected
> by a prdbgs update.  This selectivity will be used later to narrow the
> scope of changes made.
> 
> no functional change.
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   lib/dynamic_debug.c | 37 ++++++++++++++++++++++---------------
>   1 file changed, 22 insertions(+), 15 deletions(-)
> 
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 8adb81e75a16..9adcb9fa7110 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -711,18 +711,9 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
>   	return 0;
>   }
>   
> -/**
> - * param_set_dyndbg_classes - class FOO >control
> - * @instr: string echo>d to sysfs, input depends on map_type
> - * @kp:    kp->arg has state: bits/lvl, map, map_type
> - *
> - * Enable/disable prdbgs by their class, as given in the arguments to
> - * DECLARE_DYNDBG_CLASSMAP.  For LEVEL map-types, enforce relative
> - * levels by bitpos.
> - *
> - * Returns: 0 or <0 if error.
> - */
> -int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
> +static int param_set_dyndbg_module_classes(const char *instr,
> +					   const struct kernel_param *kp,
> +					   const char *modnm)
>   {
>   	const struct ddebug_class_param *dcp = kp->arg;
>   	const struct ddebug_class_map *map = dcp->map;
> @@ -759,8 +750,8 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
>   				KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length));
>   			inrep &= CLASSMAP_BITMASK(map->length);
>   		}
> -		v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp));
> -		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits, NULL);
> +		v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp));
> +		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits, modnm);
>   		*dcp->bits = inrep;
>   		break;
>   	case DD_CLASS_TYPE_LEVEL_NUM:
> @@ -773,7 +764,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
>   		old_bits = CLASSMAP_BITMASK(*dcp->lvl);
>   		new_bits = CLASSMAP_BITMASK(inrep);
>   		v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
> -		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits, NULL);
> +		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits, modnm);
>   		*dcp->lvl = inrep;
>   		break;
>   	default:
> @@ -782,6 +773,22 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
>   	vpr_info("%s: total matches: %d\n", KP_NAME(kp), totct);
>   	return 0;
>   }
> +
> +/**
> + * param_set_dyndbg_classes - class FOO >control
> + * @instr: string echo>d to sysfs, input depends on map_type
> + * @kp:    kp->arg has state: bits/lvl, map, map_type
> + *
> + * Enable/disable prdbgs by their class, as given in the arguments to
> + * DECLARE_DYNDBG_CLASSMAP.  For LEVEL map-types, enforce relative
> + * levels by bitpos.
> + *
> + * Returns: 0 or <0 if error.
> + */
> +int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
> +{
> +	return param_set_dyndbg_module_classes(instr, kp, NULL);
> +}
>   EXPORT_SYMBOL(param_set_dyndbg_classes);
>   
>   /**

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 08/63] dyndbg: drop NUM_TYPE_ARRAY
  2025-01-25  6:45 ` [PATCH 08/63] dyndbg: drop NUM_TYPE_ARRAY Jim Cromie
@ 2025-02-25 14:09   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:09 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> ARRAY_SIZE works here, since array decl is complete.
> 
> no functional change
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   include/linux/dynamic_debug.h | 4 +---
>   1 file changed, 1 insertion(+), 3 deletions(-)
> 
> diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> index 2b0057058ecf..e458d4b838ac 100644
> --- a/include/linux/dynamic_debug.h
> +++ b/include/linux/dynamic_debug.h
> @@ -106,11 +106,9 @@ struct ddebug_class_map {
>   		.mod_name = KBUILD_MODNAME,				\
>   		.base = _base,						\
>   		.map_type = _maptype,					\
> -		.length = NUM_TYPE_ARGS(char*, __VA_ARGS__),		\
> +		.length = ARRAY_SIZE(_var##_classnames),		\
>   		.class_names = _var##_classnames,			\
>   	}
> -#define NUM_TYPE_ARGS(eltype, ...)				\
> -        (sizeof((eltype[]){__VA_ARGS__}) / sizeof(eltype))
>   
>   /* encapsulate linker provided built-in (or module) dyndbg data */
>   struct _ddebug_info {

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 09/63] dyndbg: reduce verbose/debug clutter
  2025-01-25  6:45 ` [PATCH 09/63] dyndbg: reduce verbose/debug clutter Jim Cromie
@ 2025-02-25 14:10   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:10 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> currently, for verbose=3, these are logged (blank lines for clarity):
> 
>   dyndbg: query 0: "class DRM_UT_CORE +p" mod:*
>   dyndbg: split into words: "class" "DRM_UT_CORE" "+p"
> 
>   dyndbg: op='+'
>   dyndbg: flags=0x1
>   dyndbg: *flagsp=0x1 *maskp=0xffffffff
> 
>   dyndbg: parsed: func="" file="" module="" format="" lineno=0-0 class=...
>   dyndbg: no matches for query
>   dyndbg: no-match: func="" file="" module="" format="" lineno=0-0 class=...
>   dyndbg: processed 1 queries, with 0 matches, 0 errs
> 
> That is excessive, so this patch:
>   - shrinks 3 lines of 2nd stanza to single line
>   - drops 1st 2 lines of 3rd stanza
>     3rd line is like 1st, with result, not procedure.
>     2nd line is just status, retold in 4th, with more info.
> 
> New output:
> 
>   dyndbg: query 0: "class DRM_UT_CORE +p" mod:*
>   dyndbg: split into words: "class" "DRM_UT_CORE" "+p"
>   dyndbg: op='+' flags=0x1 *flagsp=0x1 *maskp=0xffffffff
>   dyndbg: no-match: func="" file="" module="" format="" lineno=0-0 class=...
>   dyndbg: processed 1 queries, with 0 matches, 0 errs
> 
> no functional change.
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   lib/dynamic_debug.c | 14 +++-----------
>   1 file changed, 3 insertions(+), 11 deletions(-)
> 
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 9adcb9fa7110..1b2fb6502e61 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -266,9 +266,6 @@ static int ddebug_change(const struct ddebug_query *query,
>   	}
>   	mutex_unlock(&ddebug_lock);
>   
> -	if (!nfound && verbose)
> -		pr_info("no matches for query\n");
> -
>   	return nfound;
>   }
>   
> @@ -501,7 +498,6 @@ static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
>   		pr_err("bad flag-op %c, at start of %s\n", *str, str);
>   		return -EINVAL;
>   	}
> -	v3pr_info("op='%c'\n", op);
>   
>   	for (; *str ; ++str) {
>   		for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
> @@ -515,7 +511,6 @@ static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
>   			return -EINVAL;
>   		}
>   	}
> -	v3pr_info("flags=0x%x\n", modifiers->flags);
>   
>   	/* calculate final flags, mask based upon op */
>   	switch (op) {
> @@ -531,7 +526,7 @@ static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
>   		modifiers->flags = 0;
>   		break;
>   	}
> -	v3pr_info("*flagsp=0x%x *maskp=0x%x\n", modifiers->flags, modifiers->mask);
> +	v3pr_info("op='%c' flags=0x%x maskp=0x%x\n", op, modifiers->flags, modifiers->mask);
>   
>   	return 0;
>   }
> @@ -541,7 +536,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
>   	struct flag_settings modifiers = {};
>   	struct ddebug_query query = {};
>   #define MAXWORDS 9
> -	int nwords, nfound;
> +	int nwords;
>   	char *words[MAXWORDS];
>   
>   	nwords = ddebug_tokenize(query_string, words, MAXWORDS);
> @@ -559,10 +554,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
>   		return -EINVAL;
>   	}
>   	/* actually go and implement the change */
> -	nfound = ddebug_change(&query, &modifiers);
> -	vpr_info_dq(&query, nfound ? "applied" : "no-match");
> -
> -	return nfound;
> +	return ddebug_change(&query, &modifiers);
>   }
>   
>   /* handle multiple queries in query string, continue on error, return

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 10/63] dyndbg: silence debugs with no-change updates
  2025-01-25  6:45 ` [PATCH 10/63] dyndbg: silence debugs with no-change updates Jim Cromie
@ 2025-02-25 14:10   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:10 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> In ddebug_apply_class_bitmap(), check for actual changes to the bits
> before announcing them, to declutter logs.
> 
> no functional change.
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   lib/dynamic_debug.c | 12 +++++++-----
>   1 file changed, 7 insertions(+), 5 deletions(-)
> 
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 1b2fb6502e61..c27965180a49 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -595,7 +595,7 @@ static int ddebug_exec_queries(char *query, const char *modname)
>   	return nfound;
>   }
>   
> -/* apply a new bitmap to the sys-knob's current bit-state */
> +/* apply a new class-param setting */
>   static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
>   				     unsigned long *new_bits, unsigned long *old_bits,
>   				     const char *query_modname)
> @@ -606,8 +606,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
>   	int matches = 0;
>   	int bi, ct;
>   
> -	v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits,
> -		  query_modname ?: "");
> +	if (*new_bits != *old_bits)
> +		v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
> +			  *old_bits, query_modname ?: "'*'");
>   
>   	for (bi = 0; bi < map->length; bi++) {
>   		if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
> @@ -622,8 +623,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
>   		v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
>   			  ct, map->class_names[bi], *new_bits);
>   	}
> -	v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits,
> -		  query_modname ?: "");
> +	if (*new_bits != *old_bits)
> +		v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
> +			  *old_bits, query_modname ?: "'*'");
>   
>   	return matches;
>   }

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 11/63] dyndbg: tighten ddebug_class_name() 1st arg type
  2025-01-25  6:45 ` [PATCH 11/63] dyndbg: tighten ddebug_class_name() 1st arg type Jim Cromie
@ 2025-02-25 14:11   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:11 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> Change function's 1st arg-type, and deref in the caller.
> The fn doesn't need any other fields in the struct.
> 
> no functional change.
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   lib/dynamic_debug.c | 10 +++++-----
>   1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index c27965180a49..a3849ac3be23 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -1120,12 +1120,12 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
>   #define class_in_range(class_id, map)					\
>   	(class_id >= map->base && class_id < map->base + map->length)
>   
> -static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp)
> +static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp)
>   {
> -	struct ddebug_class_map *map = iter->table->classes;
> -	int i, nc = iter->table->num_classes;
> +	struct ddebug_class_map *map = dt->classes;
> +	int i;
>   
> -	for (i = 0; i < nc; i++, map++)
> +	for (i = 0; i < dt->num_classes; i++, map++)
>   		if (class_in_range(dp->class_id, map))
>   			return map->class_names[dp->class_id - map->base];
>   
> @@ -1159,7 +1159,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
>   	seq_putc(m, '"');
>   
>   	if (dp->class_id != _DPRINTK_CLASS_DFLT) {
> -		class = ddebug_class_name(iter, dp);
> +		class = ddebug_class_name(iter->table, dp);
>   		if (class)
>   			seq_printf(m, " class:%s", class);
>   		else

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 12/63] dyndbg: tighten fn-sig of ddebug_apply_class_bitmap
  2025-01-25  6:45 ` [PATCH 12/63] dyndbg: tighten fn-sig of ddebug_apply_class_bitmap Jim Cromie
@ 2025-02-25 14:12   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:12 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> old_bits arg is currently a pointer to the input bits, but this could
> allow inadvertent changes to the input by the fn.  Disallow this.
> And constify new_bits while here.
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   lib/dynamic_debug.c | 21 +++++++++++----------
>   1 file changed, 11 insertions(+), 10 deletions(-)
> 
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index a3849ac3be23..fc9bf5d80aa9 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -597,7 +597,8 @@ static int ddebug_exec_queries(char *query, const char *modname)
>   
>   /* apply a new class-param setting */
>   static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
> -				     unsigned long *new_bits, unsigned long *old_bits,
> +				     const unsigned long *new_bits,
> +				     const unsigned long old_bits,
>   				     const char *query_modname)
>   {
>   #define QUERY_SIZE 128
> @@ -606,12 +607,12 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
>   	int matches = 0;
>   	int bi, ct;
>   
> -	if (*new_bits != *old_bits)
> +	if (*new_bits != old_bits)
>   		v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
> -			  *old_bits, query_modname ?: "'*'");
> +			  old_bits, query_modname ?: "'*'");
>   
>   	for (bi = 0; bi < map->length; bi++) {
> -		if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
> +		if (test_bit(bi, new_bits) == test_bit(bi, &old_bits))
>   			continue;
>   
>   		snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi],
> @@ -623,9 +624,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
>   		v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
>   			  ct, map->class_names[bi], *new_bits);
>   	}
> -	if (*new_bits != *old_bits)
> +	if (*new_bits != old_bits)
>   		v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
> -			  *old_bits, query_modname ?: "'*'");
> +			  old_bits, query_modname ?: "'*'");
>   
>   	return matches;
>   }
> @@ -681,7 +682,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
>   				continue;
>   			}
>   			curr_bits ^= BIT(cls_id);
> -			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits, NULL);
> +			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, *dcp->bits, NULL);
>   			*dcp->bits = curr_bits;
>   			v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id,
>   				  map->class_names[cls_id]);
> @@ -691,7 +692,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
>   			old_bits = CLASSMAP_BITMASK(*dcp->lvl);
>   			curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 ));
>   
> -			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits, NULL);
> +			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, old_bits, NULL);
>   			*dcp->lvl = (cls_id + (wanted ? 1 : 0));
>   			v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id,
>   				  map->class_names[cls_id], old_bits, curr_bits);
> @@ -745,7 +746,7 @@ static int param_set_dyndbg_module_classes(const char *instr,
>   			inrep &= CLASSMAP_BITMASK(map->length);
>   		}
>   		v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp));
> -		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits, modnm);
> +		totct += ddebug_apply_class_bitmap(dcp, &inrep, *dcp->bits, modnm);
>   		*dcp->bits = inrep;
>   		break;
>   	case DD_CLASS_TYPE_LEVEL_NUM:
> @@ -758,7 +759,7 @@ static int param_set_dyndbg_module_classes(const char *instr,
>   		old_bits = CLASSMAP_BITMASK(*dcp->lvl);
>   		new_bits = CLASSMAP_BITMASK(inrep);
>   		v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
> -		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits, modnm);
> +		totct += ddebug_apply_class_bitmap(dcp, &new_bits, old_bits, modnm);
>   		*dcp->lvl = inrep;
>   		break;
>   	default:

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 13/63] dyndbg: reduce verbose=3 messages in ddebug_add_module
  2025-01-25  6:45 ` [PATCH 13/63] dyndbg: reduce verbose=3 messages in ddebug_add_module Jim Cromie
@ 2025-02-25 14:12   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:12 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> When modprobing a module, dyndbg currently logs/says "add-module", and
> then "skipping" if the module has no prdbgs.  Instead just check 1st
> and return quietly.
> 
> no functional change
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   lib/dynamic_debug.c | 7 +++----
>   1 file changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index fc9bf5d80aa9..6bac5703dd41 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -1245,11 +1245,10 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   {
>   	struct ddebug_table *dt;
>   
> -	v3pr_info("add-module: %s.%d sites\n", modname, di->num_descs);
> -	if (!di->num_descs) {
> -		v3pr_info(" skip %s\n", modname);
> +	if (!di->num_descs)
>   		return 0;
> -	}
> +
> +	v3pr_info("add-module: %s %d sites\n", modname, di->num_descs);
>   
>   	dt = kzalloc(sizeof(*dt), GFP_KERNEL);
>   	if (dt == NULL) {

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 15/63] checkpatch: add an exception to the do-while wrapper advice
  2025-01-25  6:45 ` [PATCH 15/63] checkpatch: add an exception to the do-while wrapper advice Jim Cromie
@ 2025-02-25 14:12   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:12 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala,
	Andy Whitcroft, Joe Perches, Dwaipayan Ray, Lukas Bulwahn



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> Several new DYNDBG_CLASSMAP_* macros (added in following commits)
> expand to multi-statement declarations, like module_param_named does.
> They are invoked in file-scope, not in function scope, and cannot be
> wrapped by a do-while, so add an exception by name for them.
> 
> cc: Andy Whitcroft <apw@canonical.com>
> cc: Joe Perches <joe@perches.com>
> cc: Dwaipayan Ray <dwaipayanray1@gmail.com>
> cc: Lukas Bulwahn <lukas.bulwahn@gmail.com>
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   scripts/checkpatch.pl | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
> index 9eed3683ad76..4a93b2ede8cd 100755
> --- a/scripts/checkpatch.pl
> +++ b/scripts/checkpatch.pl
> @@ -5963,6 +5963,7 @@ sub process {
>   				MODULE_PARM_DESC|
>   				DECLARE_PER_CPU|
>   				DEFINE_PER_CPU|
> +				DYNDBG_CLASSMAP|
>   				__typeof__\(|
>   				union|
>   				struct|

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 16/63] dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP
  2025-01-25  6:45 ` [PATCH 16/63] dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP Jim Cromie
@ 2025-02-25 14:16   ` Louis Chauvet
  2025-03-16 19:46     ` jim.cromie
  0 siblings, 1 reply; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:16 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> DECLARE_DYNDBG_CLASSMAP() has a design error; its usage fails a basic
> K&R rule: "define once, refer many times".
> 
> It is used across DRM core & drivers, each use re-defines the classmap
> understood by that module; and all must match for the modules to
> respond together when DRM.debug categories are enabled.  This is
> brittle; a maintenance foot-gun.
> 
> Further, its culpable in the CONFIG_DRM_USE_DYNAMIC_DEBUG=Y
> regression; its use in both core & drivers obfuscates the 2 roles.
> So 1st drm.ko loads, and dyndbg initializes its DRM.debug callsites,
> then a drm-driver loads, but too late - it missed the DRM.debug
> enablement.
> 
> So replace it with 2 macros:
>    DYNDBG_CLASSMAP_DEFINE - invoked once from core - drm.ko
>    DYNDBG_CLASSMAP_USE    - from all drm drivers and helpers.
> 
> DYNDBG_CLASSMAP_DEFINE: it just modifies DECLARE_DYNDBG_CLASSMAP,
> dropping drop the static qualifier, and exports it instead.
> 
> DYNDBG_CLASSMAP_USE: then refers to the exported var by name:
>    used from drivers, helper-mods
>    lets us drop the repetitive "classname" declarations
>    fixes 2nd-defn problem
>    creates a ddebug_class_user record in new __dyndbg_class_users section
>    this allows ddebug_add_module(etal) to handle users differently.
> 
> DECLARE_DYNDBG_CLASSMAP is preserved temporarily, to decouple DRM
> adaptation work and avoid compile-errs before its done.  IOW, DRM gets
> fixed when they commit the adopt-new-api patches, and remove the
> BROKEN marking.
> 
> The DEFINE,USE distinction, and the separate classmap-use record,
> allows dyndbg to initialize the driver's & helper's DRM.debug
> callsites separately after each is modprobed.
> 
> Basically, the classmap init-scan is repeated for classmap-users.
> 
> To review, dyndbg's existing __dyndbg_classes[] section does:
> 
> . catalogs the classmaps defined by a module (or builtin modules)
> . tells dyndbg the module has class'd prdbgs, allowing >control
> . DYNDBG_CLASSMAP_DEFINE creates classmaps in this section.
> 
> This patch adds __dyndbg_class_users[] section:
> 
> . catalogs uses/references to the classmap definitions.
> . authorizes dyndbg to >control those class'd prdbgs in ref'g module.
> . DYNDBG_CLASSMAP_USE() creates classmap-user records in this new section.
> 
> Now ddebug_add_module(etal) can handle classmap-uses similar to (and
> after) classmaps; when a dependent module is loaded, if it has
> classmap-uses (to a classmap-def in another module), that module's
> kernel params are scanned to find if it has a kparam that is wired to
> dyndbg's param-ops, and whose classmap is the one being ref'd.
> 
> To support this, theres a few data/header changes:
> 
> new struct ddebug_class_user
>    contains: user-module-name, &classmap-defn
>    it records drm-driver's use of a classmap in the section, allowing lookup
> 
> struct ddebug_info gets 2 new fields for the new sections:
>    class_users, num_class_users.
>    set by dynamic_debug_init() for builtins.
>    or by kernel/module/main:load_info() for loadable modules.
> 
> vmlinux.lds.h: new BOUNDED_SECTION for __dyndbg_class_users
> 
> dynamic_debug.c has 2 changes in ddebug_add_module(), ddebug_change():
> 
> ddebug_add_module() already calls ddebug_attach_module_classes()
> to handle classmaps DEFINEd by a module, now it also calls
> ddebug_attach_user_module_classes() to handle USEd classmaps.  To
> avoid this work when possible, 1st scan the module's descriptors and
> count the number of class'd pr_debugs.
> 
> ddebug_attach_user_module_classes() scans the module's class_users
> section, follows the refs to the parent's classmap, and calls
> ddebug_apply_params() on each.  It also avoids work by checking the
> module's class-ct.
> 
> ddebug_apply_params(new fn):
> 
> It scans module's/builtin kernel-params, calls ddebug_match_apply_kparam
> for each to find any params/sysfs-nodes which may be wired to a classmap.
> 
> ddebug_match_apply_kparam(new fn):
> 
> 1st, it tests the kernel-param.ops is dyndbg's; this guarantees that
> the attached arg is a struct ddebug_class_param, which has a ref to
> the param's state, and to the classmap defining the param's handling.
> 
> 2nd, it requires that the classmap ref'd by the kparam is the one
> we're called for; modules can use many separate classmaps (as
> test_dynamic_debug does).
> 
> Then apply the "parent" kparam's setting to the dependent module,
> using ddebug_apply_class_bitmap().
> 
> ddebug_change(and callees) also gets adjustments:
> 
> ddebug_find_valid_class(): This does a search over the module's
> classmaps, looking for the class FOO echo'd to >control.  So now it
> searches over __dyndbg_class_users[] after __dyndbg_classes[].
> 
> ddebug_class_name(): return class-names for defined AND used classes.
> 
> test_dynamic_debug.c, test_dynamic_debug_submod.c:
> 
> This demonstrates the 2 types of classmaps & sysfs-params, following
> the 4-part recipe:
> 
> 1. define an enum for the classmap: DRM.debug has DRM_UT_{CORE,KMS,...}
>     multiple classes must share 0-62 classid space.
> 2. DYNDBG_CLASSMAP_DEFINE(.. DRM_UT_{CORE,KMS,...})
> 3. DYNDBG_CLASSMAP_PARAM* (classmap)
> 4. DYNDBG_CLASSMAP_USE()
>     by _submod only, skipping 2,3
> 
> Move all the enum declarations together, to better explain how they
> share the 0..62 class-id space available to a module (non-overlapping
> subranges).
> 
> reorg macros 2,3 by name.  This gives a tabular format, making it easy
> to see the pattern of repetition, and the points of change.
> 
> And extend the test to replicate the 2-module (parent & dependent)
> scenario which caused the CONFIG_DRM_USE_DYNAMIC_DEBUG=y regression
> seen in drm & drivers.
> 
> The _submod.c is a 2-line file: #define _SUBMOD, #include parent.
> 
> This gives identical complements of prdbgs in parent & _submod, and
> thus identical print behavior when all of: >control, >params, and
> parent->_submod propagation are working correctly.
> 
> It also puts all the parent/_submod declarations together in the same
> source, with the new ifdef _SUBMOD block invoking DYNDBG_CLASSMAP_USE
> for the 2 test-interfaces.  I think this is clearer.
> 
> These 2 modules are both tristate, allowing 3 super/sub combos: Y/Y,
> Y/M, M/M (not N/N).  Y/Y testing exposed a missing __align(8) in the
> _METADATA macro, which M/M didn't see because the module-loader memory
> placement constrains it instead.
> 
> NB: this patch ignores a checkpatch do-while warning which is fixed by
> a preceding commit, which would be wrong for declarative macros like
> module_param_named() etc.
> 
> Fixes: aad0214f3026 ("dyndbg: add DECLARE_DYNDBG_CLASSMAP macro")
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> ---
> v9 - commit-msg tweaks
>       DRM:CHECK warnings on macros: add parens
>       extern DEFINEd _var, static classnames
>       change ddebug_class_user.user_mod_name to .mod_name
>       simplify ddebug_find_valid_class
>       improve vpr_cm_info msg format
>       wrap (base) in macro body
>       move __DYNDBG_CLASSMAP_CHECK above kdoc for DYNDBG_CLASSMAP_DEFINE
> 
> v8 - split drm parts to separate commits.
>       preserve DECLARE_DYNDBG_CLASSMAP to decouple DRM, no flag day.
>       fixup block comment
> 
> v7 - previous submission-blocking bug:
> 
> missing __align(8) in DYNAMIC_DEBUG_DECLARE_METADATA on
> ddebug_class_user caused corrupt records, but only for builtin
> modules; module loader code probably pinned allocations to the right
> alignment naturally, hiding the bug for typical builds.
> 
> v6- get rid of WARN_ON_ONCE
> v?- fix _var expanded 2x in macro
> 
> dyndbg:
> 
> This fn formerly returned the map which contained the class (thus
> validating it), and as a side-effect set the class-id in an outvar.
> 
> But the caller didn't use the map (after checking its not null), only
> the valid class-id.  So simplify the fn to return the class-id of the
> validated classname, or -ENOENT when the queried classname is not
> found.
> 
> Convey more useful info in the debug-msg: print class-names[0,last],
> and [base,+len] instead of the class-type printout, which is currently
> always "type:DISJOINT_BITS".  And drop ddebug_classmap_typenames,
> which is now unused.
> 
> [root@v6 b0-dd]# modprobe test_dynamic_debug_submod
> [   18.864962] dyndbg: loaded classmap: test_dynamic_debug [16..24] V0..V7
> [   18.865046] dyndbg:  found kp:p_level_num =0x0
> [   18.865048] dyndbg:   mapped to: test_dynamic_debug [16..24] V0..V7
> [   18.865164] dyndbg:   p_level_num: lvl:0 bits:0x0
> [   18.865217] dyndbg: loaded classmap: test_dynamic_debug [0..10] D2_CORE..D2_DRMRES
> [   18.865297] dyndbg:  found kp:p_disjoint_bits =0x0
> [   18.865298] dyndbg:   mapped to: test_dynamic_debug [0..10] D2_CORE..D2_DRMRES
> [   18.865424] dyndbg:   p_disjoint_bits: classbits: 0x0
> [   18.865472] dyndbg: module:test_dynamic_debug attached 2 classmaps
> [   18.865533] dyndbg:  23 debug prints in module test_dynamic_debug
> [   18.866558] dyndbg: loaded classmap: test_dynamic_debug_submod [16..24] V0..V7
> [   18.866698] dyndbg:  found kp:p_level_num =0x0
> [   18.866699] dyndbg:   mapped to: test_dynamic_debug_submod [16..24] V0..V7
> [   18.866865] dyndbg:   p_level_num: lvl:0 bits:0x0
> [   18.866926] dyndbg: loaded classmap: test_dynamic_debug_submod [0..10] D2_CORE..D2_DRMRES
> [   18.867026] dyndbg:  found kp:p_disjoint_bits =0x0
> [   18.867027] dyndbg:   mapped to: test_dynamic_debug_submod [0..10] D2_CORE..D2_DRMRES
> [   18.867193] dyndbg:   p_disjoint_bits: classbits: 0x0
> [   18.867255] dyndbg: module:test_dynamic_debug_submod attached 2 classmap uses
> [   18.867351] dyndbg:  23 debug prints in module test_dynamic_debug_submod
> ---
>   MAINTAINERS                       |   2 +-
>   include/asm-generic/vmlinux.lds.h |   1 +
>   include/linux/dynamic_debug.h     |  83 ++++++++++--
>   kernel/module/main.c              |   3 +
>   lib/Kconfig.debug                 |  24 +++-
>   lib/Makefile                      |   3 +
>   lib/dynamic_debug.c               | 203 ++++++++++++++++++++++++------
>   lib/test_dynamic_debug.c          | 111 +++++++++++-----
>   lib/test_dynamic_debug_submod.c   |  10 ++

Hi Jim,

While reading the files test_dynamic_debug*, I was wondering, they are 
more samples than tests. Does it make sense to move them in samples/? 
There is no need to do it in this series.

>   9 files changed, 355 insertions(+), 85 deletions(-)
>   create mode 100644 lib/test_dynamic_debug_submod.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 0fa7c5728f1e..38afccb3b71e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -8041,7 +8041,7 @@ M:	Jim Cromie <jim.cromie@gmail.com>
>   S:	Maintained
>   F:	include/linux/dynamic_debug.h
>   F:	lib/dynamic_debug.c
> -F:	lib/test_dynamic_debug.c
> +F:	lib/test_dynamic_debug*.c
>   
>   DYNAMIC INTERRUPT MODERATION
>   M:	Tal Gilboa <talgi@nvidia.com>
> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> index 54504013c749..eb93fd09832b 100644
> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -366,6 +366,7 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
>   	/* implement dynamic printk debug */				\
>   	. = ALIGN(8);							\
>   	BOUNDED_SECTION_BY(__dyndbg_classes, ___dyndbg_classes)		\
> +	BOUNDED_SECTION_BY(__dyndbg_class_users, ___dyndbg_class_users)	\
>   	BOUNDED_SECTION_BY(__dyndbg, ___dyndbg)				\
>   	CODETAG_SECTIONS()						\
>   	LIKELY_PROFILE()		       				\
> diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> index c8102e89beb2..dc610a12b91c 100644
> --- a/include/linux/dynamic_debug.h
> +++ b/include/linux/dynamic_debug.h
> @@ -71,9 +71,28 @@ enum ddebug_class_map_type {
>   	 */
>   };
>   
> +/*
> + * dyndbg-classmaps are devised to support DRM.debug directly:
> + *    10 enum-vals: DRM_UT_* define the categories
> + *   ~23 categorized *_dbg() macros, each passing a DRM_UT_* val as 1st arg
> + *     2 macros below them: drm_dev_dbg, __drm_dbg
> + * ~5000 calls to the categorized macros, across all of drivers/gpu/drm/
> + *
> + * When CONFIG_DRM_USE_DYNAMIC_DEBUG=y, the 2 low macros are redefined
> + * to invoke _dynamic_func_call_cls().  This compiles the category
> + * into each callsite's class_id field, where dyndbg can select on it
> + * and alter a callsite's patch-state, avoiding repeated __drm_debug
> + * checks.
> + *
> + * To make the callsites manageable from the >control file, authors
> + * provide a "classmap" of names to class_ids in use by the module(s),
> + * usually by stringifying the enum-vals.  Modules with multiple
> + * classmaps must arrange to share the 0..62 class_id space.
> + */
> +
>   struct ddebug_class_map {
> -	struct module *mod;
> -	const char *mod_name;	/* needed for builtins */
> +	const struct module *mod;		/* NULL for builtins */
> +	const char *mod_name;

Is this change belongs to this patch? If not can you move this in a 
"cleanup" patch?

>   	const char **class_names;
>   	const int length;
>   	const int base;		/* index of 1st .class_id, allows split/shared space */
> @@ -81,11 +100,34 @@ struct ddebug_class_map {
>   };
>   
>   /**
> - * DECLARE_DYNDBG_CLASSMAP - declare classnames known by a module
> - * @_var:   a struct ddebug_class_map, passed to module_param_cb
> - * @_type:  enum class_map_type, chooses bits/verbose, numeric/symbolic
> - * @_base:  offset of 1st class-name. splits .class_id space
> - * @classes: class-names used to control class'd prdbgs
> + * DYNDBG_CLASSMAP_DEFINE - define debug classes used by a module.
> + * @_var:   name of the classmap, exported for other modules coordinated use.
> + * @_mapty: enum ddebug_class_map_type: 0:DISJOINT - independent, 1:LEVEL - v2>v1> + * @_base:  reserve N classids starting at _base, to split 0..62 
classid space
> + * @classes: names of the N classes.
> + *
> + * This tells dyndbg what class_ids the module is using: _base..+N, by
> + * mapping names onto them.  This qualifies "class NAME" >controls on
> + * the defining module, ignoring unknown names.
> + */
> +#define DYNDBG_CLASSMAP_DEFINE(_var, _mapty, _base, ...)		\
> +	static const char *_var##_classnames[] = { __VA_ARGS__ };	\
> +	extern struct ddebug_class_map _var;				\
> +	struct ddebug_class_map __aligned(8) __used			\
> +		__section("__dyndbg_classes") _var = {			\
> +		.mod = THIS_MODULE,					\
> +		.mod_name = KBUILD_MODNAME,				\
> +		.base = (_base),					\
> +		.map_type = (_mapty),					\
> +		.length = ARRAY_SIZE(_var##_classnames),		\
> +		.class_names = _var##_classnames,			\
> +	};								\
> +	EXPORT_SYMBOL(_var)
> +
> +/*
> + * XXX: keep this until DRM adapts to use the DEFINE/USE api, it
> + * differs from DYNDBG_CLASSMAP_DEFINE by the static replacing the
> + * extern/EXPORT on the struct init.
>    */
>   #define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...)		\
>   	static const char *_var##_classnames[] = { __VA_ARGS__ };	\
> @@ -99,12 +141,37 @@ struct ddebug_class_map {
>   		.class_names = _var##_classnames,			\
>   	}
>   
> +struct ddebug_class_user {
> +	char *mod_name;
> +	struct ddebug_class_map *map;
> +};
> +
> +/**
> + * DYNDBG_CLASSMAP_USE - refer to a classmap, DEFINEd elsewhere.
> + * @_var: name of the exported classmap var
> + *
> + * This tells dyndbg that the module has prdbgs with classids defined
> + * in the named classmap.  This qualifies "class NAME" >controls on
> + * the user module, ignoring unknown names.
> + */
> +#define DYNDBG_CLASSMAP_USE(_var)					\
> +	DYNDBG_CLASSMAP_USE_(_var, __UNIQUE_ID(ddebug_class_user))
> +#define DYNDBG_CLASSMAP_USE_(_var, _uname)				\
> +	extern struct ddebug_class_map _var;				\
> +	static struct ddebug_class_user __aligned(8) __used		\
> +	__section("__dyndbg_class_users") _uname = {			\
> +		.mod_name = KBUILD_MODNAME,				\
> +		.map = &(_var),						\
> +	}
> +

I'm not sure I understand properly how __section works, but can we use 
multiple DYNDBG_CLASSMAP_USE in one module? Can we also use 
DYNDBG_CLASSMAP_DEFINE while also importing an other classmap 
DYNDBG_CLASSMAP_USE?

If not, does it make sense to allow it (for example MFD devices can 
touch multiple subsystems)?

>   /* encapsulate linker provided built-in (or module) dyndbg data */
>   struct _ddebug_info {
>   	struct _ddebug *descs;
>   	struct ddebug_class_map *classes;
> +	struct ddebug_class_user *class_users;
>   	unsigned int num_descs;
>   	unsigned int num_classes;
> +	unsigned int num_class_users;
>   };
>   
>   struct ddebug_class_param {
> @@ -205,7 +272,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
>    * (|_no_desc):	former gets callsite descriptor as 1st arg (for prdbgs)
>    */
>   #define __dynamic_func_call_cls(id, cls, fmt, func, ...) do {	\
> -	DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt);	\
> +	DEFINE_DYNAMIC_DEBUG_METADATA_CLS((id), cls, fmt);	\

Can you move this in a "cleanup" patch?

>   	if (DYNAMIC_DEBUG_BRANCH(id))				\
>   		func(&id, ##__VA_ARGS__);			\
>   } while (0)
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 5399c182b3cb..c394a0c6e8c6 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -2546,6 +2546,9 @@ static int find_module_sections(struct module *mod, struct load_info *info)
>   	mod->dyndbg_info.classes = section_objs(info, "__dyndbg_classes",
>   						sizeof(*mod->dyndbg_info.classes),
>   						&mod->dyndbg_info.num_classes);
> +	mod->dyndbg_info.class_users = section_objs(info, "__dyndbg_class_users",
> +						    sizeof(*mod->dyndbg_info.class_users),
> +						   &mod->dyndbg_info.num_class_users);
>   #endif
>   
>   	return 0;
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index f3d723705879..933f69ef87f8 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -2884,12 +2884,26 @@ config TEST_STATIC_KEYS
>   	  If unsure, say N.
>   
>   config TEST_DYNAMIC_DEBUG
> -	tristate "Test DYNAMIC_DEBUG"
> -	depends on DYNAMIC_DEBUG
> +	tristate "Build test-dynamic-debug module"
> +	depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE
>   	help
> -	  This module registers a tracer callback to count enabled
> -	  pr_debugs in a 'do_debugging' function, then alters their
> -	  enablements, calls the function, and compares counts.
> +	  This module exercises/demonstrates dyndbg's classmap API, by
> +	  creating 2 classes: a DISJOINT classmap (supporting DRM.debug)
> +	  and a LEVELS/VERBOSE classmap (like verbose2 > verbose1).
> +
> +	  If unsure, say N.
> +
> +config TEST_DYNAMIC_DEBUG_SUBMOD
> +	tristate "Build test-dynamic-debug submodule"
> +	default m
> +	depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE
> +	depends on TEST_DYNAMIC_DEBUG
> +	help
> +	  This sub-module uses a classmap defined and exported by the
> +	  parent module, recapitulating drm & driver's shared use of
> +	  drm.debug to control enabled debug-categories.
> +	  It is tristate, independent of parent, to allow testing all
> +	  proper combinations of parent=y/m submod=y/m.
>   
>   	  If unsure, say N.
>   
> diff --git a/lib/Makefile b/lib/Makefile
> index a8155c972f02..7f66fc1c163d 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -84,6 +84,7 @@ obj-$(CONFIG_TEST_SORT) += test_sort.o
>   obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o
>   obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o
>   obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o
> +obj-$(CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD) += test_dynamic_debug_submod.o
>   obj-$(CONFIG_TEST_PRINTF) += test_printf.o
>   obj-$(CONFIG_TEST_SCANF) += test_scanf.o
>   
> @@ -228,6 +229,8 @@ obj-$(CONFIG_ARCH_NEED_CMPXCHG_1_EMU) += cmpxchg-emu.o
>   obj-$(CONFIG_DYNAMIC_DEBUG_CORE) += dynamic_debug.o
>   #ensure exported functions have prototypes
>   CFLAGS_dynamic_debug.o := -DDYNAMIC_DEBUG_MODULE
> +CFLAGS_test_dynamic_debug.o := -DDYNAMIC_DEBUG_MODULE
> +CFLAGS_test_dynamic_debug_submod.o := -DDYNAMIC_DEBUG_MODULE
>   
>   obj-$(CONFIG_SYMBOLIC_ERRNAME) += errname.o
>   
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 094d6e62a9d1..6bca0c6727d4 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -43,13 +43,16 @@ extern struct _ddebug __start___dyndbg[];
>   extern struct _ddebug __stop___dyndbg[];
>   extern struct ddebug_class_map __start___dyndbg_classes[];
>   extern struct ddebug_class_map __stop___dyndbg_classes[];
> +extern struct ddebug_class_user __start___dyndbg_class_users[];
> +extern struct ddebug_class_user __stop___dyndbg_class_users[];
>   
>   struct ddebug_table {
>   	struct list_head link;
>   	const char *mod_name;
>   	struct _ddebug *ddebugs;
>   	struct ddebug_class_map *classes;
> -	unsigned int num_ddebugs, num_classes;
> +	struct ddebug_class_user *class_users;
> +	unsigned int num_ddebugs, num_classes, num_class_users;
>   };
>   
>   struct ddebug_query {
> @@ -148,23 +151,35 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
>   		  query->first_lineno, query->last_lineno, query->class_string);
>   }
>   
> -#define __outvar /* filled by callee */
> -static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
> -							const char *class_string,
> -							__outvar int *class_id)
> +#define vpr_dt_info(dt_p, msg_p, ...) ({				\
> +	struct ddebug_table const *_dt = dt_p;				\
> +	v2pr_info(msg_p " module:%s nd:%d nc:%d nu:%d\n", ##__VA_ARGS__, \
> +		  _dt->mod_name, _dt->num_ddebugs, _dt->num_classes,	\
> +		  _dt->num_class_users);				\
> +	})
> +
> +static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *class_string)
>   {
>   	struct ddebug_class_map *map;
> +	struct ddebug_class_user *cli;
>   	int i, idx;
>   
> -	for (map = dt->classes, i = 0; i < dt->num_classes; i++, map++) {
> +	for (i = 0, map = dt->classes; i < dt->num_classes; i++, map++) {
>   		idx = match_string(map->class_names, map->length, class_string);
>   		if (idx >= 0) {
> -			*class_id = idx + map->base;
> -			return map;
> +			vpr_dt_info(dt, "good-class: %s.%s ", map->mod_name, class_string);
> +			return idx + map->base;
>   		}
>   	}
> -	*class_id = -ENOENT;
> -	return NULL;
> +	for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++) {
> +		idx = match_string(cli->map->class_names, cli->map->length, class_string);
> +		if (idx >= 0) {
> +			vpr_dt_info(dt, "class-ref: %s -> %s.%s ",
> +				    cli->mod_name, cli->map->mod_name, class_string);
> +			return idx + cli->map->base;
> +		}
> +	}
> +	return -ENOENT;
>   }
>   
>   /*
> @@ -173,16 +188,14 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
>    * callsites, normally the same as number of changes.  If verbose,
>    * logs the changes.  Takes ddebug_lock.
>    */
> -static int ddebug_change(const struct ddebug_query *query,
> -			 struct flag_settings *modifiers)
> +static int ddebug_change(const struct ddebug_query *query, struct flag_settings *modifiers)
>   {
>   	int i;
>   	struct ddebug_table *dt;
>   	unsigned int newflags;
>   	unsigned int nfound = 0;
>   	struct flagsbuf fbuf, nbuf;
> -	struct ddebug_class_map *map = NULL;
> -	int __outvar valid_class;
> +	int valid_class;
>   
>   	/* search for matching ddebugs */
>   	mutex_lock(&ddebug_lock);
> @@ -194,8 +207,8 @@ static int ddebug_change(const struct ddebug_query *query,
>   			continue;
>   
>   		if (query->class_string) {
> -			map = ddebug_find_valid_class(dt, query->class_string, &valid_class);
> -			if (!map)
> +			valid_class = ddebug_find_valid_class(dt, query->class_string);
> +			if (valid_class < 0)
>   				continue;
>   		} else {
>   			/* constrain query, do not touch class'd callsites */
> @@ -559,7 +572,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
>   
>   /* handle multiple queries in query string, continue on error, return
>      last error or number of matching callsites.  Module name is either
> -   in param (for boot arg) or perhaps in query string.
> +   in the modname arg (for boot args) or perhaps in query string.
>   */
>   static int ddebug_exec_queries(char *query, const char *modname)
>   {
> @@ -688,12 +701,12 @@ static int param_set_dyndbg_module_classes(const char *instr,
>   }
>   
>   /**
> - * param_set_dyndbg_classes - class FOO >control
> + * param_set_dyndbg_classes - set all classes in a classmap
>    * @instr: string echo>d to sysfs, input depends on map_type
> - * @kp:    kp->arg has state: bits/lvl, map, map_type
> + * @kp:    kp->arg has state: bits/lvl, classmap, map_type
>    *
> - * Enable/disable prdbgs by their class, as given in the arguments to
> - * DECLARE_DYNDBG_CLASSMAP.  For LEVEL map-types, enforce relative
> + * For all classes in the classmap, enable/disable them per the input
> + * (depending on map_type).  For LEVEL map-types, enforce relative
>    * levels by bitpos.
>    *
>    * Returns: 0 or <0 if error.
> @@ -1038,12 +1051,17 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
>   static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp)
>   {
>   	struct ddebug_class_map *map = dt->classes;
> +	struct ddebug_class_user *cli = dt->class_users;
>   	int i;
>   
>   	for (i = 0; i < dt->num_classes; i++, map++)
>   		if (class_in_range(dp->class_id, map))
>   			return map->class_names[dp->class_id - map->base];
>   
> +	for (i = 0; i < dt->num_class_users; i++, cli++)
> +		if (class_in_range(dp->class_id, cli->map))
> +			return cli->map->class_names[dp->class_id - cli->map->base];
> +
>   	return NULL;
>   }
>   
> @@ -1124,31 +1142,129 @@ static const struct proc_ops proc_fops = {
>   	.proc_write = ddebug_proc_write
>   };
>   
> -static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
> +#define vpr_cm_info(cm_p, msg_fmt, ...) ({				\
> +	struct ddebug_class_map const *_cm = cm_p;			\
> +	v2pr_info(msg_fmt " %s [%d..%d] %s..%s\n", ##__VA_ARGS__,	\
> +		  _cm->mod_name, _cm->base, _cm->base + _cm->length,	\
> +		  _cm->class_names[0], _cm->class_names[_cm->length - 1]); \
> +	})
> +
> +static void ddebug_sync_classbits(const struct kernel_param *kp, const char *modname)
> +{
> +	const struct ddebug_class_param *dcp = kp->arg;
> +
> +	/* clamp initial bitvec, mask off hi-bits */
> +	if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) {
> +		*dcp->bits &= CLASSMAP_BITMASK(dcp->map->length);
> +		v2pr_info("preset classbits: %lx\n", *dcp->bits);
> +	}
> +	/* force class'd prdbgs (in USEr module) to match (DEFINEr module) class-param */
> +	ddebug_apply_class_bitmap(dcp, dcp->bits, ~0, modname);
> +	ddebug_apply_class_bitmap(dcp, dcp->bits, 0, modname);
> +}
> +
> +static void ddebug_match_apply_kparam(const struct kernel_param *kp,
> +				      const struct ddebug_class_map *map,
> +				      const char *modnm)
> +{
> +	struct ddebug_class_param *dcp;
> +
> +	if (kp->ops != &param_ops_dyndbg_classes)
> +		return;
> +
> +	dcp = (struct ddebug_class_param *)kp->arg;
> +
> +	if (map == dcp->map) {
> +		v2pr_info(" kp:%s.%s =0x%lx", modnm, kp->name, *dcp->bits);
> +		vpr_cm_info(map, " %s mapped to: ", modnm);
> +		ddebug_sync_classbits(kp, modnm);
> +	}
> +}
> +
> +static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *modnm)
> +{
> +	const struct kernel_param *kp;
> +#if IS_ENABLED(CONFIG_MODULES)
> +	int i;
> +
> +	if (cm->mod) {
> +		vpr_cm_info(cm, "loaded classmap: %s", modnm);
> +		/* ifdef protects the cm->mod->kp deref */
> +		for (i = 0, kp = cm->mod->kp; i < cm->mod->num_kp; i++, kp++)
> +			ddebug_match_apply_kparam(kp, cm, modnm);
> +	}
> +#endif
> +	if (!cm->mod) {
> +		vpr_cm_info(cm, "builtin classmap: %s", modnm);
> +		for (kp = __start___param; kp < __stop___param; kp++)
> +			ddebug_match_apply_kparam(kp, cm, modnm);
> +	}
> +}
> +
> +/*
> + * Find this module's classmaps in a sub/whole-range of the builtin/
> + * modular classmap vector/section.  Save the start and length of the
> + * subrange at its edges.
> + */
> +static void ddebug_attach_module_classes(struct ddebug_table *dt,
> +					 const struct _ddebug_info *di)
>   {
>   	struct ddebug_class_map *cm;
>   	int i, nc = 0;
>   
> -	/*
> -	 * Find this module's classmaps in a subrange/wholerange of
> -	 * the builtin/modular classmap vector/section.  Save the start
> -	 * and length of the subrange at its edges.
> -	 */
> -	for (cm = di->classes, i = 0; i < di->num_classes; i++, cm++) {
> -
> +	for (i = 0, cm = di->classes; i < di->num_classes; i++, cm++) {
>   		if (!strcmp(cm->mod_name, dt->mod_name)) {
> -			if (!nc) {
> -				v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
> -					  i, cm->mod_name, cm->base, cm->length, cm->map_type);
> +			vpr_cm_info(cm, "classes[%d]:", i);
> +			if (!nc++)
>   				dt->classes = cm;
> -			}
> -			nc++;
>   		}
>   	}
> -	if (nc) {
> -		dt->num_classes = nc;
> -		vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
> +	if (!nc)
> +		return;
> +
> +	vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
> +	dt->num_classes = nc;
> +
> +	for (i = 0, cm = dt->classes; i < dt->num_classes; i++, cm++)
> +		ddebug_apply_params(cm, cm->mod_name);
> +}
> +
> +/*
> + * propagates class-params thru their classmaps to class-users.  this
> + * means a query against the dt/module, which means it must be on the
> + * list to be seen by ddebug_change.
> + */
> +static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
> +					      const struct _ddebug_info *di)
> +{
> +	struct ddebug_class_user *cli;
> +	int i, nc = 0;
> +
> +	/*
> +	 * For builtins: scan the array, find start/length of this
> +	 * module's refs, save to dt.  For loadables, this is the
> +	 * whole array.
> +	 */
> +	for (i = 0, cli = di->class_users; i < di->num_class_users; i++, cli++) {
> +		if (WARN_ON_ONCE(!cli || !cli->map || !cli->mod_name))
> +			continue;
> +		if (!strcmp(cli->mod_name, dt->mod_name)) {
> +			vpr_cm_info(cli->map, "class_ref[%d] %s -> %s", i,
> +				    cli->mod_name, cli->map->mod_name);
> +			if (!nc++)
> +				dt->class_users = cli;
> +		}
>   	}
> +	if (!nc)
> +		return;
> +
> +	dt->num_class_users = nc;
> +
> +	/* now iterate dt */
> +	for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++)
> +		ddebug_apply_params(cli->map, cli->mod_name);
> +
> +	vpr_dt_info(dt, "attach-client-module: ");
>   }
>   
>   /*
> @@ -1158,6 +1274,8 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug
>   static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   {
>   	struct ddebug_table *dt;
> +	struct _ddebug *iter;
> +	int i, class_ct = 0;
>   
>   	if (!di->num_descs)
>   		return 0;
> @@ -1181,13 +1299,20 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   
>   	INIT_LIST_HEAD(&dt->link);
>   
> -	if (di->classes && di->num_classes)
> +	for (i = 0, iter = di->descs; i < di->num_descs; i++, iter++)
> +		if (iter->class_id != _DPRINTK_CLASS_DFLT)
> +			class_ct++;
> +
> +	if (class_ct && di->num_classes)
>   		ddebug_attach_module_classes(dt, di);
>   
>   	mutex_lock(&ddebug_lock);
>   	list_add_tail(&dt->link, &ddebug_tables);
>   	mutex_unlock(&ddebug_lock);
>   
> +	if (class_ct && di->num_class_users)
> +		ddebug_attach_user_module_classes(dt, di);
> +
>   	vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
>   	return 0;
>   }
> @@ -1337,8 +1462,10 @@ static int __init dynamic_debug_init(void)
>   	struct _ddebug_info di = {
>   		.descs = __start___dyndbg,
>   		.classes = __start___dyndbg_classes,
> +		.class_users = __start___dyndbg_class_users,
>   		.num_descs = __stop___dyndbg - __start___dyndbg,
>   		.num_classes = __stop___dyndbg_classes - __start___dyndbg_classes,
> +		.num_class_users = __stop___dyndbg_class_users - __start___dyndbg_class_users,
>   	};
>   
>   #ifdef CONFIG_MODULES
> diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
> index 74d183ebf3e0..1838f62738c4 100644
> --- a/lib/test_dynamic_debug.c
> +++ b/lib/test_dynamic_debug.c
> @@ -6,11 +6,15 @@
>    *      Jim Cromie	<jim.cromie@gmail.com>
>    */
>   
> -#define pr_fmt(fmt) "test_dd: " fmt
> +#if defined(TEST_DYNAMIC_DEBUG_SUBMOD)
> +  #define pr_fmt(fmt) "test_dd_submod: " fmt
> +#else
> +  #define pr_fmt(fmt) "test_dd: " fmt
> +#endif
>   
>   #include <linux/module.h>
>   
> -/* run tests by reading or writing sysfs node: do_prints */
> +/* re-gen output by reading or writing sysfs node: do_prints */
>   
>   static void do_prints(void); /* device under test */
>   static int param_set_do_prints(const char *instr, const struct kernel_param *kp)
> @@ -29,24 +33,39 @@ static const struct kernel_param_ops param_ops_do_prints = {
>   };
>   module_param_cb(do_prints, &param_ops_do_prints, NULL, 0600);
>   
> -/*
> - * Using the CLASSMAP api:
> - * - classmaps must have corresponding enum
> - * - enum symbols must match/correlate with class-name strings in the map.
> - * - base must equal enum's 1st value
> - * - multiple maps must set their base to share the 0-30 class_id space !!
> - *   (build-bug-on tips welcome)
> - * Additionally, here:
> - * - tie together sysname, mapname, bitsname, flagsname
> - */
> -#define DD_SYS_WRAP(_model, _flags)					\
> -	static unsigned long bits_##_model;				\
> -	static struct ddebug_class_param _flags##_model = {		\
> +#define CLASSMAP_BITMASK(width, base) (((1UL << (width)) - 1) << (base))
> +
> +/* sysfs param wrapper, proto-API */
> +#define DYNDBG_CLASSMAP_PARAM_(_model, _flags, _init)			\
> +	static unsigned long bits_##_model = _init;			\
> +	static struct ddebug_class_param _flags##_##_model = {		\
>   		.bits = &bits_##_model,					\
>   		.flags = #_flags,					\
>   		.map = &map_##_model,					\
>   	};								\
> -	module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes, &_flags##_model, 0600)
> +	module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes,	\
> +			&_flags##_##_model, 0600)
> +#ifdef DEBUG
> +#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, ~0)
> +#else
> +#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, 0)
> +#endif
> +
> +/*
> + * Demonstrate/test all 4 class-typed classmaps with a sys-param.
> + *
> + * Each is 3 part: client-enum decl, _DEFINE, _PARAM.
> + * Declare them in blocks to show patterns of use (repetitions and
> + * changes) within each.
> + *
> + * 1st, dyndbg expects a client-provided enum-type as source of
> + * category/classid truth.  DRM has DRM_UT_<CORE,DRIVER,KMS,etc>.
> + *
> + * Modules with multiple CLASSMAPS must have enums with distinct
> + * value-ranges, arranged below with explicit enum_sym = X inits.
> + *
> + * Declare all 4 enums now, for different types
> + */
>   
>   /* numeric input, independent bits */
>   enum cat_disjoint_bits {
> @@ -60,26 +79,51 @@ enum cat_disjoint_bits {
>   	D2_LEASE,
>   	D2_DP,
>   	D2_DRMRES };
> -DECLARE_DYNDBG_CLASSMAP(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS, 0,
> -			"D2_CORE",
> -			"D2_DRIVER",
> -			"D2_KMS",
> -			"D2_PRIME",
> -			"D2_ATOMIC",
> -			"D2_VBL",
> -			"D2_STATE",
> -			"D2_LEASE",
> -			"D2_DP",
> -			"D2_DRMRES");
> -DD_SYS_WRAP(disjoint_bits, p);
> -DD_SYS_WRAP(disjoint_bits, T);
>   
>   /* numeric verbosity, V2 > V1 related */
>   enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
> -DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14,
> -		       "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
> -DD_SYS_WRAP(level_num, p);
> -DD_SYS_WRAP(level_num, T);
> +
> +/* recapitulate DRM's parent(drm.ko) <-- _submod(drivers,helpers) */
> +#if !defined(TEST_DYNAMIC_DEBUG_SUBMOD)

It was not clear at first read that the test_dynamic_debug.c code is 
used twice.

What do you think about creating a third file "common" with 
do_prints/do_levels/... implementations and avoid this #if !defined?

> +/*
> + * In single user, or parent / coordinator (drm.ko) modules, define
> + * classmaps on the client enums above, and then declares the PARAMS
> + * ref'g the classmaps.  Each is exported.
> + */
> +DYNDBG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS,

map_disjoint_bits is defined in both test_dynamic_debug.c and 
test_dynamic_debug_submodule.c, is it normal/required?

> +		       D2_CORE,
> +		       "D2_CORE",
> +		       "D2_DRIVER",
> +		       "D2_KMS",
> +		       "D2_PRIME",
> +		       "D2_ATOMIC",
> +		       "D2_VBL",
> +		       "D2_STATE",
> +		       "D2_LEASE",
> +		       "D2_DP",
> +		       "D2_DRMRES");
> +
> +DYNDBG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
> +		       V0, "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
> +
> +/*
> + * now add the sysfs-params
> + */
> +
> +DYNDBG_CLASSMAP_PARAM(disjoint_bits, p);
> +DYNDBG_CLASSMAP_PARAM(level_num, p);
> +
> +#else /* TEST_DYNAMIC_DEBUG_SUBMOD */
> +
> +/*
> + * in submod/drm-drivers, use the classmaps defined in top/parent
> + * module above.
> + */
> +
> +DYNDBG_CLASSMAP_USE(map_disjoint_bits);
> +DYNDBG_CLASSMAP_USE(map_level_num);
> +
> +#endif
>   
>   /* stand-in for all pr_debug etc */
>   #define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
> @@ -115,6 +159,7 @@ static void do_levels(void)
>   
>   static void do_prints(void)
>   {
> +	pr_debug("do_prints:\n");
>   	do_cats();
>   	do_levels();

I just observed it, is the ordering of logs garanteed in 
/proc/dynamic_debug/control?

When I run this test, I have this order:

do_cats =_ "doing categories\n"
[...]
do_levels =_ "doing levels\n"
[...]
do_prints =_ "do_prints:\n"
test_dynamic_debug_init =_ "init start\n"
test_dynamic_debug_init =_ "init done\n"
test_dynamic_debug_exit =_ "exited\n"

Which is clearly not the code execution order.

>   }
> diff --git a/lib/test_dynamic_debug_submod.c b/lib/test_dynamic_debug_submod.c
> new file mode 100644
> index 000000000000..9a893402ce1a
> --- /dev/null
> +++ b/lib/test_dynamic_debug_submod.c
> @@ -0,0 +1,10 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Kernel module for testing dynamic_debug
> + *
> + * Authors:
> + *      Jim Cromie	<jim.cromie@gmail.com>
> + */
> +
> +#define TEST_DYNAMIC_DEBUG_SUBMOD
> +#include "test_dynamic_debug.c"

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 17/63] dyndbg: check DYNDBG_CLASSMAP_DEFINE args at compile-time
  2025-01-25  6:45 ` [PATCH 17/63] dyndbg: check DYNDBG_CLASSMAP_DEFINE args at compile-time Jim Cromie
@ 2025-02-25 14:17   ` Louis Chauvet
  2025-03-16 20:46     ` jim.cromie
  0 siblings, 1 reply; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:17 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> Add __DYNDBG_CLASSMAP_CHECK to implement these arg-checks at compile:
> 	0 <= _base < 63
> 	class_names is not empty
> 	class_names[0] is a string
> 	(class_names.length + _base) < 63
> 
> These compile-time checks will prevent several misuses; 4 such
> examples are added to test_dynamic_debug_submod.ko, and will fail
> compilation if -DDD_MACRO_ARGCHECK is added to cflags.
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> ---
> - split static-asserts to __DYNDBG_CLASSMAP_CHECK
> - move __DYNDBG_CLASSMAP_CHECK above kdoc for DYNDBG_CLASSMAP_DEFINE
>    silences kernel-doc warnings
> ---
>   include/linux/dynamic_debug.h |  9 +++++++++
>   lib/test_dynamic_debug.c      | 11 +++++++++++
>   2 files changed, 20 insertions(+)
> 
> diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> index dc610a12b91c..2b0c943af330 100644
> --- a/include/linux/dynamic_debug.h
> +++ b/include/linux/dynamic_debug.h
> @@ -99,6 +99,14 @@ struct ddebug_class_map {
>   	enum ddebug_class_map_type map_type;
>   };
>   
> +#define __DYNDBG_CLASSMAP_CHECK(_clnames, _base)			\
> +	static_assert(((_base) >= 0 && (_base) < _DPRINTK_CLASS_DFLT),	\
> +		      "_base must be in 0..62");			\
> +	static_assert(ARRAY_SIZE(_clnames) > 0,				\
> +		      "classnames array size must be > 0");		\
> +	static_assert((ARRAY_SIZE(_clnames) + (_base)) < _DPRINTK_CLASS_DFLT, \
> +		      "_base + classnames.length exceeds range")
> +
>   /**
>    * DYNDBG_CLASSMAP_DEFINE - define debug classes used by a module.
>    * @_var:   name of the classmap, exported for other modules coordinated use.
> @@ -112,6 +120,7 @@ struct ddebug_class_map {
>    */
>   #define DYNDBG_CLASSMAP_DEFINE(_var, _mapty, _base, ...)		\
>   	static const char *_var##_classnames[] = { __VA_ARGS__ };	\
> +	__DYNDBG_CLASSMAP_CHECK(_var##_classnames, (_base));		\
>   	extern struct ddebug_class_map _var;				\
>   	struct ddebug_class_map __aligned(8) __used			\
>   		__section("__dyndbg_classes") _var = {			\
> diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
> index 1838f62738c4..b1555b0a2bb1 100644
> --- a/lib/test_dynamic_debug.c
> +++ b/lib/test_dynamic_debug.c
> @@ -123,8 +123,19 @@ DYNDBG_CLASSMAP_PARAM(level_num, p);
>   DYNDBG_CLASSMAP_USE(map_disjoint_bits);
>   DYNDBG_CLASSMAP_USE(map_level_num);
>   
> +#if defined(DD_MACRO_ARGCHECK)
> +/*
> + * Exersize compile-time arg-checks in DYNDBG_CLASSMAP_DEFINE.
> + * These will break compilation.
> + */
> +DYNDBG_CLASSMAP_DEFINE(fail_base_neg, 0, -1, "NEGATIVE_BASE_ARG");
> +DYNDBG_CLASSMAP_DEFINE(fail_base_big, 0, 100, "TOOBIG_BASE_ARG");
> +DYNDBG_CLASSMAP_DEFINE(fail_str_type, 0, 0, 1 /* not a string */);
> +DYNDBG_CLASSMAP_DEFINE(fail_emptyclass, 0, 0 /* ,empty */);

Hi Jim,

This test is nice, but can we move it in the *_submod.c directly? They 
don't need anything from this file.

Tested-by: Louis Chauvet <louis.chauvet@bootlin.com>

Thanks,
Louis Chauvet

>   #endif
>   
> +#endif /* TEST_DYNAMIC_DEBUG_SUBMOD */
> +
>   /* stand-in for all pr_debug etc */
>   #define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
>   

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 18/63] dyndbg: add/use for_subvec() to reduce boilerplate
  2025-01-25  6:45 ` [PATCH 18/63] dyndbg: add/use for_subvec() to reduce boilerplate Jim Cromie
@ 2025-02-25 14:18   ` Louis Chauvet
  2025-03-16 20:50     ` jim.cromie
  0 siblings, 1 reply; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:18 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> add for_subvec() macro to encapsulate a for-loop pattern thats used
> repeatedly to iterate over a boxed.vector of N elements.
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Hi Jim,

Do you think it is possible to move this patch earlier in the series, so 
you can use it when introducing class_users.

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

Thanks,
Louis Chauvet

> ---
>   lib/dynamic_debug.c | 30 ++++++++++++++++++++++--------
>   1 file changed, 22 insertions(+), 8 deletions(-)
> 
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 6bca0c6727d4..08b6e4e7489f 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -158,20 +158,34 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
>   		  _dt->num_class_users);				\
>   	})
>   
> +/*
> + * simplify a repeated for-loop pattern walking N steps in a T _vec
> + * member inside a struct _box.  It expects int i and T *_sp to be
> + * declared in the caller.
> + * @_i:  caller provided counter.
> + * @_sp: cursor into _vec, to examine each item.
> + * @_box: ptr to a struct containing @_vec member
> + * @_vec: name of a sub-struct member in _box, with array-ref and length
> + */
> +#define for_subvec(_i, _sp, _box, _vec)				       \
> +	for ((_i) = 0, (_sp) = (_box)->_vec;			       \
> +	     (_i) < (_box)->num_##_vec;				       \
> +	     (_i)++, (_sp)++)
> +
>   static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *class_string)
>   {
>   	struct ddebug_class_map *map;
>   	struct ddebug_class_user *cli;
>   	int i, idx;
>   
> -	for (i = 0, map = dt->classes; i < dt->num_classes; i++, map++) {
> +	for_subvec(i, map, dt, classes) {
>   		idx = match_string(map->class_names, map->length, class_string);
>   		if (idx >= 0) {
>   			vpr_dt_info(dt, "good-class: %s.%s ", map->mod_name, class_string);
>   			return idx + map->base;
>   		}
>   	}
> -	for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++) {
> +	for_subvec(i, cli, dt, class_users) {
>   		idx = match_string(cli->map->class_names, cli->map->length, class_string);
>   		if (idx >= 0) {
>   			vpr_dt_info(dt, "class-ref: %s -> %s.%s ",
> @@ -1190,7 +1204,7 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
>   	if (cm->mod) {
>   		vpr_cm_info(cm, "loaded classmap: %s", modnm);
>   		/* ifdef protects the cm->mod->kp deref */
> -		for (i = 0, kp = cm->mod->kp; i < cm->mod->num_kp; i++, kp++)
> +		for_subvec(i, kp, cm->mod, kp)
>   			ddebug_match_apply_kparam(kp, cm, modnm);
>   	}
>   #endif
> @@ -1212,7 +1226,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
>   	struct ddebug_class_map *cm;
>   	int i, nc = 0;
>   
> -	for (i = 0, cm = di->classes; i < di->num_classes; i++, cm++) {
> +	for_subvec(i, cm, di, classes) {
>   		if (!strcmp(cm->mod_name, dt->mod_name)) {
>   			vpr_cm_info(cm, "classes[%d]:", i);
>   			if (!nc++)
> @@ -1225,7 +1239,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
>   	vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
>   	dt->num_classes = nc;
>   
> -	for (i = 0, cm = dt->classes; i < dt->num_classes; i++, cm++)
> +	for_subvec(i, cm, dt, classes)
>   		ddebug_apply_params(cm, cm->mod_name);
>   }
>   
> @@ -1245,7 +1259,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
>   	 * module's refs, save to dt.  For loadables, this is the
>   	 * whole array.
>   	 */
> -	for (i = 0, cli = di->class_users; i < di->num_class_users; i++, cli++) {
> +	for_subvec(i, cli, di, class_users) {
>   		if (WARN_ON_ONCE(!cli || !cli->map || !cli->mod_name))
>   			continue;
>   		if (!strcmp(cli->mod_name, dt->mod_name)) {
> @@ -1261,7 +1275,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
>   	dt->num_class_users = nc;
>   
>   	/* now iterate dt */
> -	for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++)
> +	for_subvec(i, cli, di, class_users)
>   		ddebug_apply_params(cli->map, cli->mod_name);
>   
>   	vpr_dt_info(dt, "attach-client-module: ");
> @@ -1299,7 +1313,7 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   
>   	INIT_LIST_HEAD(&dt->link);
>   
> -	for (i = 0, iter = di->descs; i < di->num_descs; i++, iter++)
> +	for_subvec(i, iter, di, descs)
>   		if (iter->class_id != _DPRINTK_CLASS_DFLT)
>   			class_ct++;
>   

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 19/63] dyndbg: make proper substructs in _ddebug_info
  2025-01-25  6:45 ` [PATCH 19/63] dyndbg: make proper substructs in _ddebug_info Jim Cromie
@ 2025-02-25 14:19   ` Louis Chauvet
  2025-03-16 20:58     ` jim.cromie
  0 siblings, 1 reply; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:19 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> struct _ddebug_info's jobs is to enapsulate the __sections of dyndbg
> data from the linker.  The data started as a single pair of fields:
> descs - ref'g an array of descriptors & num_descs - counting the
> "pertinent" descriptors.  Then classes & num_classes were added, and
> _ddebug_info was invented to contain the 4 fields.
> 
> When class_users & num_class_users were added (earlier in this
> series), the easy path was to replicate functions and adapt them to
> work on ddebug_class_users, instead of class_maps.  This worked, but
> made repetitive boilerplate code, leading to (other commits with)
> macros walking num_##{classes,class_users} to capture the repetition.
> 
> To fix it better, create structs to contain start,len for vectors of
> all 3 objects: classmaps, class_users, and pr_debug descriptors, and
> adjust field-refs accordingly.
> 
> Also recompose struct ddebug_table to contain a _ddebug_info (rather
> than repeat the contents, as before), and adjust all array-walks to
> use the newly contained info.
> 
> This allows ridding the class* macros of the num##<T> paste-up, and
> should enable further cleanups.
> 
> NB: The __packed attribute on _ddebug_info and the 3 contained structs
> closes the holes otherwise created by the structification (which was
> the excuse for not doing it originally).
> 
> TBD: see if this can precede other patches, to reduce churn

Hi Jim,

This could be amazing if possible!

> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   include/linux/dynamic_debug.h | 29 ++++++++---
>   kernel/module/main.c          | 18 +++----
>   lib/dynamic_debug.c           | 93 +++++++++++++++++------------------
>   3 files changed, 74 insertions(+), 66 deletions(-)
> 
> diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> index 2b0c943af330..48d76a273f68 100644
> --- a/include/linux/dynamic_debug.h
> +++ b/include/linux/dynamic_debug.h
> @@ -173,15 +173,28 @@ struct ddebug_class_user {
>   		.map = &(_var),						\
>   	}
>   
> -/* encapsulate linker provided built-in (or module) dyndbg data */
> +/*
> + * @_ddebug_info: gathers module/builtin dyndbg_* __sections together.
> + * For builtins, it is used as a cursor, with the inner structs
> + * marking sub-vectors of the builtin __sections in DATA.
> + */
> +struct _ddebug_descs {
> +	struct _ddebug *start;
> +	int len;
> +} __packed;
> +struct dd_class_maps {
> +	struct ddebug_class_map *start;
> +	int len;
> +} __packed;
> +struct dd_class_users {
> +	struct ddebug_class_user *start;
> +	int len;
> +} __packed;
>   struct _ddebug_info {
> -	struct _ddebug *descs;
> -	struct ddebug_class_map *classes;
> -	struct ddebug_class_user *class_users;
> -	unsigned int num_descs;
> -	unsigned int num_classes;
> -	unsigned int num_class_users;
> -};
> +	struct _ddebug_descs descs;
> +	struct dd_class_maps maps;
> +	struct dd_class_users users;
> +} __packed;
>   
>   struct ddebug_class_param {
>   	union {
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index c394a0c6e8c6..858882a1eacd 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -2540,15 +2540,15 @@ static int find_module_sections(struct module *mod, struct load_info *info)
>   		pr_warn("%s: Ignoring obsolete parameters\n", mod->name);
>   
>   #ifdef CONFIG_DYNAMIC_DEBUG_CORE
> -	mod->dyndbg_info.descs = section_objs(info, "__dyndbg",
> -					      sizeof(*mod->dyndbg_info.descs),
> -					      &mod->dyndbg_info.num_descs);
> -	mod->dyndbg_info.classes = section_objs(info, "__dyndbg_classes",
> -						sizeof(*mod->dyndbg_info.classes),
> -						&mod->dyndbg_info.num_classes);
> -	mod->dyndbg_info.class_users = section_objs(info, "__dyndbg_class_users",
> -						    sizeof(*mod->dyndbg_info.class_users),
> -						   &mod->dyndbg_info.num_class_users);
> +	mod->dyndbg_info.descs.start = section_objs(info, "__dyndbg",
> +						    sizeof(*mod->dyndbg_info.descs.start),
> +						    &mod->dyndbg_info.descs.len);
> +	mod->dyndbg_info.maps.start = section_objs(info, "__dyndbg_classes",
> +						   sizeof(*mod->dyndbg_info.maps.start),
> +						   &mod->dyndbg_info.maps.len);
> +	mod->dyndbg_info.users.start = section_objs(info, "__dyndbg_class_users",
> +						    sizeof(*mod->dyndbg_info.users.start),
> +						    &mod->dyndbg_info.users.len);
>   #endif
>   
>   	return 0;
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 08b6e4e7489f..067db504dd1d 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -49,10 +49,7 @@ extern struct ddebug_class_user __stop___dyndbg_class_users[];
>   struct ddebug_table {
>   	struct list_head link;
>   	const char *mod_name;
> -	struct _ddebug *ddebugs;
> -	struct ddebug_class_map *classes;
> -	struct ddebug_class_user *class_users;
> -	unsigned int num_ddebugs, num_classes, num_class_users;
> +	struct _ddebug_info info;
>   };
>   
>   struct ddebug_query {
> @@ -154,8 +151,8 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
>   #define vpr_dt_info(dt_p, msg_p, ...) ({				\
>   	struct ddebug_table const *_dt = dt_p;				\
>   	v2pr_info(msg_p " module:%s nd:%d nc:%d nu:%d\n", ##__VA_ARGS__, \
> -		  _dt->mod_name, _dt->num_ddebugs, _dt->num_classes,	\
> -		  _dt->num_class_users);				\
> +		  _dt->mod_name, _dt->info.descs.len, _dt->info.maps.len, \
> +		  _dt->info.users.len);					\
>   	})
>   
>   /*
> @@ -168,8 +165,8 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
>    * @_vec: name of a sub-struct member in _box, with array-ref and length
>    */
>   #define for_subvec(_i, _sp, _box, _vec)				       \
> -	for ((_i) = 0, (_sp) = (_box)->_vec;			       \
> -	     (_i) < (_box)->num_##_vec;				       \
> +	for ((_i) = 0, (_sp) = (_box)->_vec.start;		       \
> +	     (_i) < (_box)->_vec.len;				       \
>   	     (_i)++, (_sp)++)
>   
>   static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *class_string)
> @@ -178,14 +175,14 @@ static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *cl
>   	struct ddebug_class_user *cli;
>   	int i, idx;
>   
> -	for_subvec(i, map, dt, classes) {
> +	for_subvec(i, map, &dt->info, maps) {
>   		idx = match_string(map->class_names, map->length, class_string);
>   		if (idx >= 0) {
>   			vpr_dt_info(dt, "good-class: %s.%s ", map->mod_name, class_string);
>   			return idx + map->base;
>   		}
>   	}
> -	for_subvec(i, cli, dt, class_users) {
> +	for_subvec(i, cli, &dt->info, users) {
>   		idx = match_string(cli->map->class_names, cli->map->length, class_string);
>   		if (idx >= 0) {
>   			vpr_dt_info(dt, "class-ref: %s -> %s.%s ",
> @@ -229,8 +226,8 @@ static int ddebug_change(const struct ddebug_query *query, struct flag_settings
>   			valid_class = _DPRINTK_CLASS_DFLT;
>   		}
>   
> -		for (i = 0; i < dt->num_ddebugs; i++) {
> -			struct _ddebug *dp = &dt->ddebugs[i];
> +		for (i = 0; i < dt->info.descs.len; i++) {
> +			struct _ddebug *dp = &dt->info.descs.start[i];
>   
>   			/* match site against query-class */
>   			if (dp->class_id != valid_class)
> @@ -990,8 +987,8 @@ static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
>   	}
>   	iter->table = list_entry(ddebug_tables.next,
>   				 struct ddebug_table, link);
> -	iter->idx = iter->table->num_ddebugs;
> -	return &iter->table->ddebugs[--iter->idx];
> +	iter->idx = iter->table->info.descs.len;
> +	return &iter->table->info.descs.start[--iter->idx];
>   }
>   
>   /*
> @@ -1012,10 +1009,10 @@ static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
>   		}
>   		iter->table = list_entry(iter->table->link.next,
>   					 struct ddebug_table, link);
> -		iter->idx = iter->table->num_ddebugs;
> +		iter->idx = iter->table->info.descs.len;
>   		--iter->idx;
>   	}
> -	return &iter->table->ddebugs[iter->idx];
> +	return &iter->table->info.descs.start[iter->idx];
>   }
>   
>   /*
> @@ -1064,15 +1061,15 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
>   
>   static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp)
>   {
> -	struct ddebug_class_map *map = dt->classes;
> -	struct ddebug_class_user *cli = dt->class_users;
> +	struct ddebug_class_map *map;
> +	struct ddebug_class_user *cli;
>   	int i;
>   
> -	for (i = 0; i < dt->num_classes; i++, map++)
> +	for_subvec(i, map, &dt->info, maps)
>   		if (class_in_range(dp->class_id, map))
>   			return map->class_names[dp->class_id - map->base];
>   
> -	for (i = 0; i < dt->num_class_users; i++, cli++)
> +	for_subvec(i, cli, &dt->info, users)
>   		if (class_in_range(dp->class_id, cli->map))
>   			return cli->map->class_names[dp->class_id - cli->map->base];
>   
> @@ -1203,8 +1200,7 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
>   
>   	if (cm->mod) {
>   		vpr_cm_info(cm, "loaded classmap: %s", modnm);
> -		/* ifdef protects the cm->mod->kp deref */
> -		for_subvec(i, kp, cm->mod, kp)
> +		for (i = 0, kp = cm->mod->kp; i < cm->mod->num_kp; i++, kp++)
>   			ddebug_match_apply_kparam(kp, cm, modnm);
>   	}
>   #endif
> @@ -1226,20 +1222,20 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
>   	struct ddebug_class_map *cm;
>   	int i, nc = 0;
>   
> -	for_subvec(i, cm, di, classes) {
> +	for_subvec(i, cm, di, maps) {
>   		if (!strcmp(cm->mod_name, dt->mod_name)) {
>   			vpr_cm_info(cm, "classes[%d]:", i);
>   			if (!nc++)
> -				dt->classes = cm;
> +				dt->info.maps.start = cm;
>   		}
>   	}
>   	if (!nc)
>   		return;
>   
>   	vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
> -	dt->num_classes = nc;
> +	dt->info.maps.len = nc;
>   
> -	for_subvec(i, cm, dt, classes)
> +	for_subvec(i, cm, &dt->info, maps)
>   		ddebug_apply_params(cm, cm->mod_name);
>   }
>   
> @@ -1259,23 +1255,23 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
>   	 * module's refs, save to dt.  For loadables, this is the
>   	 * whole array.
>   	 */
> -	for_subvec(i, cli, di, class_users) {
> +	for_subvec(i, cli, di, users) {
>   		if (WARN_ON_ONCE(!cli || !cli->map || !cli->mod_name))
>   			continue;
>   		if (!strcmp(cli->mod_name, dt->mod_name)) {
>   			vpr_cm_info(cli->map, "class_ref[%d] %s -> %s", i,
>   				    cli->mod_name, cli->map->mod_name);
>   			if (!nc++)
> -				dt->class_users = cli;
> +				dt->info.users.start = cli;
>   		}
>   	}
>   	if (!nc)
>   		return;
>   
> -	dt->num_class_users = nc;
> +	dt->info.users.len = nc;
>   
>   	/* now iterate dt */
> -	for_subvec(i, cli, di, class_users)
> +	for_subvec(i, cli, di, users)
>   		ddebug_apply_params(cli->map, cli->mod_name);
>   
>   	vpr_dt_info(dt, "attach-client-module: ");
> @@ -1291,10 +1287,10 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   	struct _ddebug *iter;
>   	int i, class_ct = 0;
>   
> -	if (!di->num_descs)
> +	if (!di->descs.len)
>   		return 0;
>   
> -	v3pr_info("add-module: %s %d sites\n", modname, di->num_descs);
> +	v3pr_info("add-module: %s %d sites\n", modname, di->descs.len);
>   
>   	dt = kzalloc(sizeof(*dt), GFP_KERNEL);
>   	if (dt == NULL) {
> @@ -1308,8 +1304,7 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   	 * this struct ddebug_table.
>   	 */
>   	dt->mod_name = modname;
> -	dt->ddebugs = di->descs;
> -	dt->num_ddebugs = di->num_descs;
> +	dt->info.descs = di->descs;
>   
>   	INIT_LIST_HEAD(&dt->link);
>   
> @@ -1317,17 +1312,17 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   		if (iter->class_id != _DPRINTK_CLASS_DFLT)
>   			class_ct++;
>   
> -	if (class_ct && di->num_classes)
> +	if (class_ct && di->maps.len)
>   		ddebug_attach_module_classes(dt, di);
>   
>   	mutex_lock(&ddebug_lock);
>   	list_add_tail(&dt->link, &ddebug_tables);
>   	mutex_unlock(&ddebug_lock);
>   
> -	if (class_ct && di->num_class_users)
> +	if (class_ct && di->users.len)
>   		ddebug_attach_user_module_classes(dt, di);
>   
> -	vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
> +	vpr_info("%3u debug prints in module %s\n", di->descs.len, modname);
>   	return 0;
>   }
>   
> @@ -1474,12 +1469,12 @@ static int __init dynamic_debug_init(void)
>   	char *cmdline;
>   
>   	struct _ddebug_info di = {
> -		.descs = __start___dyndbg,
> -		.classes = __start___dyndbg_classes,
> -		.class_users = __start___dyndbg_class_users,
> -		.num_descs = __stop___dyndbg - __start___dyndbg,
> -		.num_classes = __stop___dyndbg_classes - __start___dyndbg_classes,
> -		.num_class_users = __stop___dyndbg_class_users - __start___dyndbg_class_users,
> +		.descs.start = __start___dyndbg,
> +		.maps.start = __start___dyndbg_classes,
> +		.users.start = __start___dyndbg_class_users,
> +		.descs.len = __stop___dyndbg - __start___dyndbg,
> +		.maps.len = __stop___dyndbg_classes - __start___dyndbg_classes,
> +		.users.len = __stop___dyndbg_class_users - __start___dyndbg_class_users,
>   	};
>   
>   #ifdef CONFIG_MODULES
> @@ -1508,8 +1503,8 @@ static int __init dynamic_debug_init(void)
>   
>   		if (strcmp(modname, iter->modname)) {
>   			mod_ct++;
> -			di.num_descs = mod_sites;
> -			di.descs = iter_mod_start;
> +			di.descs.len = mod_sites;
> +			di.descs.start = iter_mod_start;
>   			ret = ddebug_add_module(&di, modname);
>   			if (ret)
>   				goto out_err;
> @@ -1519,8 +1514,8 @@ static int __init dynamic_debug_init(void)
>   			iter_mod_start = iter;
>   		}
>   	}
> -	di.num_descs = mod_sites;
> -	di.descs = iter_mod_start;
> +	di.descs.len = mod_sites;
> +	di.descs.start = iter_mod_start;
>   	ret = ddebug_add_module(&di, modname);
>   	if (ret)
>   		goto out_err;
> @@ -1530,8 +1525,8 @@ static int __init dynamic_debug_init(void)
>   		 i, mod_ct, (int)((mod_ct * sizeof(struct ddebug_table)) >> 10),
>   		 (int)((i * sizeof(struct _ddebug)) >> 10));
>   
> -	if (di.num_classes)
> -		v2pr_info("  %d builtin ddebug class-maps\n", di.num_classes);
> +	if (di.maps.len)
> +		v2pr_info("  %d builtin ddebug class-maps\n", di.maps.len);
>   
>   	/* now that ddebug tables are loaded, process all boot args
>   	 * again to find and activate queries given in dyndbg params.

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 20/63] dyndbg: drop premature optimization in ddebug_add_module
  2025-01-25  6:45 ` [PATCH 20/63] dyndbg: drop premature optimization in ddebug_add_module Jim Cromie
@ 2025-02-25 14:26   ` Louis Chauvet
  0 siblings, 0 replies; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:26 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> The class_ct var was added to avoid 2 function calls, but to do this
> it loops over all the module's debug callsites to determine the count.
> But it doesn't really help, so remove it.
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Hi Jim,

If you move the other patch earlier, can you also move this one before 
"for_subvec", so you don't change the same lines twice.

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

Thanks,
Louis Chauvet

> ---
>   lib/dynamic_debug.c | 10 ++--------
>   1 file changed, 2 insertions(+), 8 deletions(-)
> 
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 067db504dd1d..16c9b752822b 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -1284,8 +1284,6 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
>   static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   {
>   	struct ddebug_table *dt;
> -	struct _ddebug *iter;
> -	int i, class_ct = 0;
>   
>   	if (!di->descs.len)
>   		return 0;
> @@ -1308,18 +1306,14 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   
>   	INIT_LIST_HEAD(&dt->link);
>   
> -	for_subvec(i, iter, di, descs)
> -		if (iter->class_id != _DPRINTK_CLASS_DFLT)
> -			class_ct++;
> -
> -	if (class_ct && di->maps.len)
> +	if (di->maps.len)
>   		ddebug_attach_module_classes(dt, di);
>   
>   	mutex_lock(&ddebug_lock);
>   	list_add_tail(&dt->link, &ddebug_tables);
>   	mutex_unlock(&ddebug_lock);
>   
> -	if (class_ct && di->users.len)
> +	if (di->users.len)
>   		ddebug_attach_user_module_classes(dt, di);
>   
>   	vpr_info("%3u debug prints in module %s\n", di->descs.len, modname);

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 21/63] dyndbg: allow ddebug_add_module to fail
  2025-01-25  6:45 ` [PATCH 21/63] dyndbg: allow ddebug_add_module to fail Jim Cromie
@ 2025-02-25 14:26   ` Louis Chauvet
  2025-03-16 21:04     ` jim.cromie
  0 siblings, 1 reply; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:26 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> To prep for failing modprobe on classid conflicts, upgrade the
> call-chain around ddebug_add_module(), in 2 ways:
> 
> 1. in ddebug_add_module() add local reserved_ids to accumulate
> reservations, pass it by ref to ddebug_attach_{,user_}module_classes()
> so they can examine the reservations as they work.
> 
> 2. return int from both ddebug_attach_{,user_}module_classes(), up to
> ddebug_add_module(), then to ddebug_module_notify().
> 
> No conflicts are currently detected or returned.
> 
> TBD: This is updated further by hoisting the reservation-check, which
> obsoletes part of 2, creating churn, maybe squash it away.

Hi Jim,

It could be very nice to squash when possible yes!

> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

> ---
>   lib/dynamic_debug.c | 40 +++++++++++++++++++++++++++++-----------
>   1 file changed, 29 insertions(+), 11 deletions(-)
> 
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 16c9b752822b..0ef243e30663 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -1216,8 +1216,9 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
>    * modular classmap vector/section.  Save the start and length of the
>    * subrange at its edges.
>    */
> -static void ddebug_attach_module_classes(struct ddebug_table *dt,
> -					 const struct _ddebug_info *di)
> +static int ddebug_attach_module_classes(struct ddebug_table *dt,
> +					const struct _ddebug_info *di,
> +					u64 *reserved_ids)
>   {
>   	struct ddebug_class_map *cm;
>   	int i, nc = 0;
> @@ -1230,13 +1231,14 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
>   		}
>   	}
>   	if (!nc)
> -		return;
> +		return 0;
>   
>   	vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
>   	dt->info.maps.len = nc;
>   
>   	for_subvec(i, cm, &dt->info, maps)
>   		ddebug_apply_params(cm, cm->mod_name);
> +	return 0;
>   }
>   
>   /*
> @@ -1244,8 +1246,9 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
>    * means a query against the dt/module, which means it must be on the
>    * list to be seen by ddebug_change.
>    */
> -static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
> -					      const struct _ddebug_info *di)
> +static int ddebug_attach_user_module_classes(struct ddebug_table *dt,
> +					      const struct _ddebug_info *di,
> +					      u64 *reserved_ids)
>   {
>   	struct ddebug_class_user *cli;
>   	int i, nc = 0;
> @@ -1266,7 +1269,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
>   		}
>   	}
>   	if (!nc)
> -		return;
> +		return 0;
>   
>   	dt->info.users.len = nc;
>   
> @@ -1275,6 +1278,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
>   		ddebug_apply_params(cli->map, cli->mod_name);
>   
>   	vpr_dt_info(dt, "attach-client-module: ");
> +	return 0;
>   }
>   
>   /*
> @@ -1284,6 +1288,8 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
>   static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   {
>   	struct ddebug_table *dt;
> +	u64 reserved_ids = 0;
> +	int rc;
>   
>   	if (!di->descs.len)
>   		return 0;
> @@ -1306,16 +1312,23 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   
>   	INIT_LIST_HEAD(&dt->link);
>   
> -	if (di->maps.len)
> -		ddebug_attach_module_classes(dt, di);
> -
> +	if (di->maps.len) {
> +		rc = ddebug_attach_module_classes(dt, di, &reserved_ids);
> +		if (rc) {
> +			kfree(dt);
> +			return rc;
> +		}
> +	}
>   	mutex_lock(&ddebug_lock);
>   	list_add_tail(&dt->link, &ddebug_tables);
>   	mutex_unlock(&ddebug_lock);
>   
> -	if (di->users.len)
> -		ddebug_attach_user_module_classes(dt, di);
>   
> +	if (di->users.len) {
> +		rc = ddebug_attach_user_module_classes(dt, di, &reserved_ids);
> +		if (rc)
> +			return rc;
> +	}
>   	vpr_info("%3u debug prints in module %s\n", di->descs.len, modname);
>   	return 0;
>   }
> @@ -1400,6 +1413,11 @@ static int ddebug_module_notify(struct notifier_block *self, unsigned long val,
>   	switch (val) {
>   	case MODULE_STATE_COMING:
>   		ret = ddebug_add_module(&mod->dyndbg_info, mod->name);
> +		if (ret == -EINVAL) {
> +			pr_err("conflicting dyndbg-classmap reservations\n");
> +			ddebug_remove_module(mod->name);
> +			break;
> +		}
>   		if (ret)
>   			WARN(1, "Failed to allocate memory: dyndbg may not work properly.\n");
>   		break;

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 23/63] dyndbg: fail modprobe on ddebug_class_range_overlap()
  2025-01-25  6:45 ` [PATCH 23/63] dyndbg: fail modprobe on ddebug_class_range_overlap() Jim Cromie
@ 2025-02-25 14:27   ` Louis Chauvet
  2025-03-16 21:07     ` jim.cromie
  0 siblings, 1 reply; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:27 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> 1. All classes used by a module (declared DYNDBG_CLASSMAP_{DEFINE,USE}
> by module code) must share 0..62 class-id space; ie their respective
> base,+length reservations shouldn't overlap.  Overlaps would lead to
> unintended changes in ddebug enablements.
> 
> Detecting these class-id range overlaps at compile-time would be ideal
> but is not obvious how; failing at modprobe at least insures that the
> developer sees and fixes the conflict.
> 
> ddebug_class_range_overlap() implements the range check, accumulating
> the reserved-ids as it examines each class.  It probably should use
> bitmaps.
> 
> A previous commit reworked the modprobe callchain to allow failure,
> now call ddebug_class_range_overlap() to check when classid conflicts
> happen, and signal that failure.
> 
> NB: this can only happen when a module defines+uses several classmaps,
> 
> TBD: failing modprobe is kinda harsh, maybe warn and proceed ?
> 
> test_dynamic_debug*.ko:
> 
> If built with -DFORCE_CLASSID_CONFLICT_MODPROBE, the modules get 2 bad
> DYNDBG_CLASS_DEFINE declarations, into parent and the _submod.  These
> conflict with one of the good ones in the parent (D2_CORE..etc),
> causing the modprobe(s) to fail.  TODO: do in submod only, since fail
> of parent prevents submod from ever trying.
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> ---
> ---
>   lib/dynamic_debug.c      | 30 ++++++++++++++++++++++++------
>   lib/test_dynamic_debug.c | 11 ++++++++++-
>   2 files changed, 34 insertions(+), 7 deletions(-)
> 
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 8afcd4111531..8e1e087e07c3 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -1211,6 +1211,21 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
>   	}
>   }
>   
> +static int ddebug_class_range_overlap(struct ddebug_class_map *cm,
> +				      u64 *reserved_ids)
> +{
> +	u64 range = (((1ULL << cm->length) - 1) << cm->base);
> +
> +	if (range & *reserved_ids) {
> +		pr_err("[%d..%d] on %s conflicts with %llx\n", cm->base,
> +		       cm->base + cm->length - 1, cm->class_names[0],
> +		       *reserved_ids);
> +		return -EINVAL;
> +	}
> +	*reserved_ids |= range;
> +	return 0;
> +}
> +
>   /*
>    * scan the named array: @_vec, ref'd from inside @_box, for the
>    * start,len of the sub-array of elements matching on ->mod_name;
> @@ -1242,9 +1257,11 @@ static int ddebug_module_apply_class_maps(struct ddebug_table *dt,
>   	struct ddebug_class_map *cm;
>   	int i;
>   
> -	for_subvec(i, cm, &dt->info, maps)
> +	for_subvec(i, cm, &dt->info, maps) {
> +		if (ddebug_class_range_overlap(cm, reserved_ids))
> +			return -EINVAL;
>   		ddebug_apply_params(cm, cm->mod_name);
> -
> +	}
>   	vpr_info("module:%s attached %d classmaps\n", dt->mod_name, dt->info.maps.len);
>   	return 0;
>   }
> @@ -1255,10 +1272,11 @@ static int ddebug_module_apply_class_users(struct ddebug_table *dt,
>   	struct ddebug_class_user *cli;
>   	int i;
>   
> -	/* now iterate dt */
> -	for_subvec(i, cli, &dt->info, users)
> +	for_subvec(i, cli, &dt->info, users) {
> +		if (ddebug_class_range_overlap(cli->map, reserved_ids))
> +			return -EINVAL;
>   		ddebug_apply_params(cli->map, cli->mod_name);
> -
> +	}
>   	vpr_info("module:%s attached %d classmap uses\n", dt->mod_name, dt->info.users.len);
>   	return 0;
>   }
> @@ -1311,11 +1329,11 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>   			return rc;
>   		}
>   	}
> +
>   	mutex_lock(&ddebug_lock);
>   	list_add_tail(&dt->link, &ddebug_tables);
>   	mutex_unlock(&ddebug_lock);
>   
> -

Hi Jim,

Strange line issues, can you squash it with the correct patch?

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>

Thanks,

>   	if (dt->info.users.len) {
>   		rc = ddebug_module_apply_class_users(dt, &reserved_ids);
>   		if (rc)
> diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
> index b1555b0a2bb1..74b98adc4ed0 100644
> --- a/lib/test_dynamic_debug.c
> +++ b/lib/test_dynamic_debug.c
> @@ -81,7 +81,7 @@ enum cat_disjoint_bits {
>   	D2_DRMRES };
>   
>   /* numeric verbosity, V2 > V1 related */
> -enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
> +enum cat_level_num { V0 = 16, V1, V2, V3, V4, V5, V6, V7 };
>   
>   /* recapitulate DRM's parent(drm.ko) <-- _submod(drivers,helpers) */
>   #if !defined(TEST_DYNAMIC_DEBUG_SUBMOD)
> @@ -90,6 +90,7 @@ enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
>    * classmaps on the client enums above, and then declares the PARAMS
>    * ref'g the classmaps.  Each is exported.
>    */
> +
>   DYNDBG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS,
>   		       D2_CORE,
>   		       "D2_CORE",
> @@ -113,6 +114,14 @@ DYNDBG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
>   DYNDBG_CLASSMAP_PARAM(disjoint_bits, p);
>   DYNDBG_CLASSMAP_PARAM(level_num, p);
>   
> +#ifdef FORCE_CLASSID_CONFLICT_MODPROBE
> +/*
> + * Enable with -Dflag on compile to test overlapping class-id range
> + * detection.  This should break on modprobe.
> + */
> +DYNDBG_CLASSMAP_DEFINE(classid_range_conflict, 0, D2_CORE + 1, "D3_CORE");
> +#endif
> +
>   #else /* TEST_DYNAMIC_DEBUG_SUBMOD */
>   
>   /*

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 28/63] dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API
  2025-01-25  6:45 ` [PATCH 28/63] dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API Jim Cromie
@ 2025-02-25 14:29   ` Louis Chauvet
  2025-03-16 21:14     ` jim.cromie
  0 siblings, 1 reply; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:29 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> move the DYNDBG_CLASSMAP_PARAM macro from test-dynamic-debug.c into
> the header, and refine it, by distinguishing the 2 use cases:
> 
> 1.DYNDBG_CLASSMAP_PARAM_REF
>      for DRM, to pass in extern __drm_debug by name.
>      dyndbg keeps bits in it, so drm can still use it as before
> 
> 2.DYNDBG_CLASSMAP_PARAM
>      new user (test_dynamic_debug) doesn't need to share state,
>      decls a static long unsigned int to store the bitvec.
> 
> __DYNDBG_CLASSMAP_PARAM
>     bottom layer - allocate,init a ddebug-class-param, module-param-cb.
> 
> Modify ddebug_sync_classbits() argtype deref inside the fn, to give
> access to all kp members.
> 
> Also clean up and improve comments in test-code, and add
> MODULE_DESCRIPTIONs.
>
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> ---
> 
> -v9
>   - fixup drm-print.h  add PARAM_REF forwarding macros
>     with DYNDBG_CLASSMAP_PARAM_REF in the API, add DRM_ variant
> ---
>   include/linux/dynamic_debug.h   | 38 +++++++++++++++++++++
>   lib/dynamic_debug.c             | 60 ++++++++++++++++++++++-----------
>   lib/test_dynamic_debug.c        | 59 +++++++++++++-------------------
>   lib/test_dynamic_debug_submod.c |  9 ++++-
>   4 files changed, 111 insertions(+), 55 deletions(-)
> 
> diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> index 48d76a273f68..b47d1088b7ad 100644
> --- a/include/linux/dynamic_debug.h
> +++ b/include/linux/dynamic_debug.h
> @@ -205,6 +205,44 @@ struct ddebug_class_param {
>   	const struct ddebug_class_map *map;
>   };
>   
> +/**
> + * DYNDBG_CLASSMAP_PARAM - control a ddebug-classmap from a sys-param
> + * @_name:  sysfs node name
> + * @_var:   name of the classmap var defining the controlled classes/bits
> + * @_flags: flags to be toggled, typically just 'p'
> + *
> + * Creates a sysfs-param to control the classes defined by the
> + * exported classmap, with bits 0..N-1 mapped to the classes named.
> + * This version keeps class-state in a private long int.
> + */
> +#define DYNDBG_CLASSMAP_PARAM(_name, _var, _flags)			\
> +	static unsigned long _name##_bvec;				\
> +	__DYNDBG_CLASSMAP_PARAM(_name, _name##_bvec, _var, _flags)
> +
> +/**
> + * DYNDBG_CLASSMAP_PARAM_REF - wrap a classmap with a controlling sys-param
> + * @_name:  sysfs node name
> + * @_bits:  name of the module's unsigned long bit-vector, ex: __drm_debug
> + * @_var:   name of the (exported) classmap var defining the classes/bits
> + * @_flags: flags to be toggled, typically just 'p'
> + *
> + * Creates a sysfs-param to control the classes defined by the
> + * exported clasmap, with bits 0..N-1 mapped to the classes named.
> + * This version keeps class-state in user @_bits.  This lets drm check
> + * __drm_debug elsewhere too.
> + */
> +#define DYNDBG_CLASSMAP_PARAM_REF(_name, _bits, _var, _flags)		\
> +	__DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags)
> +
> +#define __DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags)		\
> +	static struct ddebug_class_param _name##_##_flags = {		\
> +		.bits = &(_bits),					\
> +		.flags = #_flags,					\
> +		.map = &(_var),						\
> +	};								\
> +	module_param_cb(_name, &param_ops_dyndbg_classes,		\
> +			&_name##_##_flags, 0600)
> +
>   /*
>    * pr_debug() and friends are globally enabled or modules have selectively
>    * enabled them.
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 781781835094..9283f2866415 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -660,6 +660,30 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
>   
>   #define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1)
>   
> +static void ddebug_class_param_clamp_input(unsigned long *inrep, const struct kernel_param *kp)
> +{
> +	const struct ddebug_class_param *dcp = kp->arg;
> +	const struct ddebug_class_map *map = dcp->map;
> +
> +	switch (map->map_type) {
> +	case DD_CLASS_TYPE_DISJOINT_BITS:
> +		/* expect bits. mask and warn if too many */
> +		if (*inrep & ~CLASSMAP_BITMASK(map->length)) {
> +			pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
> +				KP_NAME(kp), *inrep, CLASSMAP_BITMASK(map->length));
> +			*inrep &= CLASSMAP_BITMASK(map->length);
> +		}
> +		break;
> +	case DD_CLASS_TYPE_LEVEL_NUM:
> +		/* input is bitpos, of highest verbosity to be enabled */
> +		if (*inrep > map->length) {
> +			pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
> +				KP_NAME(kp), *inrep, map->length);
> +			*inrep = map->length;
> +		}
> +		break;
> +	}
> +}
>   static int param_set_dyndbg_module_classes(const char *instr,
>   					   const struct kernel_param *kp,
>   					   const char *modnm)
> @@ -678,26 +702,15 @@ static int param_set_dyndbg_module_classes(const char *instr,
>   		pr_err("expecting numeric input, not: %s > %s\n", instr, KP_NAME(kp));
>   		return -EINVAL;
>   	}
> +	ddebug_class_param_clamp_input(&inrep, kp);
>   
>   	switch (map->map_type) {
>   	case DD_CLASS_TYPE_DISJOINT_BITS:
> -		/* expect bits. mask and warn if too many */
> -		if (inrep & ~CLASSMAP_BITMASK(map->length)) {
> -			pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
> -				KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length));
> -			inrep &= CLASSMAP_BITMASK(map->length);
> -		}
>   		v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp));
>   		totct += ddebug_apply_class_bitmap(dcp, &inrep, *dcp->bits, modnm);
>   		*dcp->bits = inrep;
>   		break;
>   	case DD_CLASS_TYPE_LEVEL_NUM:
> -		/* input is bitpos, of highest verbosity to be enabled */
> -		if (inrep > map->length) {
> -			pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
> -				KP_NAME(kp), inrep, map->length);
> -			inrep = map->length;
> -		}
>   		old_bits = CLASSMAP_BITMASK(*dcp->lvl);
>   		new_bits = CLASSMAP_BITMASK(inrep);
>   		v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
> @@ -1163,15 +1176,24 @@ static const struct proc_ops proc_fops = {
>   static void ddebug_sync_classbits(const struct kernel_param *kp, const char *modname)
>   {
>   	const struct ddebug_class_param *dcp = kp->arg;
> +	unsigned long new_bits;
>   
> -	/* clamp initial bitvec, mask off hi-bits */
> -	if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) {
> -		*dcp->bits &= CLASSMAP_BITMASK(dcp->map->length);
> -		v2pr_info("preset classbits: %lx\n", *dcp->bits);
> +	ddebug_class_param_clamp_input(dcp->bits, kp);
> +
> +	switch (dcp->map->map_type) {
> +	case DD_CLASS_TYPE_DISJOINT_BITS:
> +		v2pr_info("  %s: classbits: 0x%lx\n", KP_NAME(kp), *dcp->bits);
> +		ddebug_apply_class_bitmap(dcp, dcp->bits, 0UL, modname);
> +		break;
> +	case DD_CLASS_TYPE_LEVEL_NUM:
> +		new_bits = CLASSMAP_BITMASK(*dcp->lvl);
> +		v2pr_info("  %s: lvl:%ld bits:0x%lx\n", KP_NAME(kp), *dcp->lvl, new_bits);
> +		ddebug_apply_class_bitmap(dcp, &new_bits, 0UL, modname);
> +		break;
> +	default:
> +		pr_err("bad map type %d\n", dcp->map->map_type);
> +		return;
>   	}
> -	/* force class'd prdbgs (in USEr module) to match (DEFINEr module) class-param */
> -	ddebug_apply_class_bitmap(dcp, dcp->bits, ~0, modname);
> -	ddebug_apply_class_bitmap(dcp, dcp->bits, 0, modname);

Hi Jim,

We lost the double call with ~0/0, is it normal?

Thanks a lot for your work,
Louis Chauvet

>   }
>   
>   static void ddebug_match_apply_kparam(const struct kernel_param *kp,
> diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
> index 5cfc156ca4bb..32a9d49a7a3b 100644
> --- a/lib/test_dynamic_debug.c
> +++ b/lib/test_dynamic_debug.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
> - * Kernel module for testing dynamic_debug
> + * Kernel module to test/demonstrate dynamic_debug features,
> + * particularly classmaps and their support for subsystems like DRM.
>    *
>    * Authors:
>    *      Jim Cromie	<jim.cromie@gmail.com>
> @@ -43,36 +44,21 @@ module_param_cb(do_prints, &param_ops_do_prints, NULL, 0600);
>   
>   #define CLASSMAP_BITMASK(width, base) (((1UL << (width)) - 1) << (base))
>   
> -/* sysfs param wrapper, proto-API */
> -#define DYNDBG_CLASSMAP_PARAM_(_model, _flags, _init)			\
> -	static unsigned long bits_##_model = _init;			\
> -	static struct ddebug_class_param _flags##_##_model = {		\
> -		.bits = &bits_##_model,					\
> -		.flags = #_flags,					\
> -		.map = &map_##_model,					\
> -	};								\
> -	module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes,	\
> -			&_flags##_##_model, 0600)
> -#ifdef DEBUG
> -#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, ~0)
> -#else
> -#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, 0)
> -#endif
> -
>   /*
> - * Demonstrate/test all 4 class-typed classmaps with a sys-param.
> + * Demonstrate/test both types of classmaps, each with a sys-param.
>    *
>    * Each is 3 part: client-enum decl, _DEFINE, _PARAM.
> - * Declare them in blocks to show patterns of use (repetitions and
> - * changes) within each.
> + * Pair the 6 parts by type, to show the pattern of repetition and
> + * change within each.
>    *
> - * 1st, dyndbg expects a client-provided enum-type as source of
> - * category/classid truth.  DRM has DRM_UT_<CORE,DRIVER,KMS,etc>.
> + * 1st, dyndbg classmaps follows drm.debug convention, and expects a
> + * client-provided enum-type as source of category/classid truth.  DRM
> + * gives DRM_UT_<CORE,DRIVER,KMS,etc>.
>    *
>    * Modules with multiple CLASSMAPS must have enums with distinct
>    * value-ranges, arranged below with explicit enum_sym = X inits.
>    *
> - * Declare all 4 enums now, for different types
> + * Declare the 2 enums now.
>    */
>   
>   /* numeric input, independent bits */
> @@ -91,12 +77,15 @@ enum cat_disjoint_bits {
>   /* numeric verbosity, V2 > V1 related */
>   enum cat_level_num { V0 = 16, V1, V2, V3, V4, V5, V6, V7 };
>   
> -/* recapitulate DRM's parent(drm.ko) <-- _submod(drivers,helpers) */
> +/*
> + * use/demonstrate multi-module-group classmaps, as for DRM
> + */
>   #if !defined(TEST_DYNAMIC_DEBUG_SUBMOD)
>   /*
> - * In single user, or parent / coordinator (drm.ko) modules, define
> - * classmaps on the client enums above, and then declares the PARAMS
> - * ref'g the classmaps.  Each is exported.
> + * For module-groups of 1+, define classmaps with names (stringified
> + * enum-symbols) copied from above. 1-to-1 mapping is recommended.
> + * The classmap is exported, so that other modules in the group can
> + * link to it and control their prdbgs.
>    */
>   
>   DYNDBG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS,
> @@ -116,11 +105,12 @@ DYNDBG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
>   		       V0, "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
>   
>   /*
> - * now add the sysfs-params
> + * for use-cases that want it, provide a sysfs-param to set the
> + * classes in the classmap.  It is at this interface where the
> + * "v3>v2" property is applied to DD_CLASS_TYPE_LEVEL_NUM inputs.
>    */
> -
> -DYNDBG_CLASSMAP_PARAM(disjoint_bits, p);
> -DYNDBG_CLASSMAP_PARAM(level_num, p);
> +DYNDBG_CLASSMAP_PARAM(p_disjoint_bits,	map_disjoint_bits, p);
> +DYNDBG_CLASSMAP_PARAM(p_level_num,	map_level_num, p);
>   
>   #ifdef FORCE_CLASSID_CONFLICT_MODPROBE
>   /*
> @@ -131,12 +121,10 @@ DYNDBG_CLASSMAP_DEFINE(classid_range_conflict, 0, D2_CORE + 1, "D3_CORE");
>   #endif
>   
>   #else /* TEST_DYNAMIC_DEBUG_SUBMOD */
> -
>   /*
> - * in submod/drm-drivers, use the classmaps defined in top/parent
> - * module above.
> + * the +1 members of a multi-module group refer to the classmap
> + * DEFINEd (and exported) above.
>    */
> -
>   DYNDBG_CLASSMAP_USE(map_disjoint_bits);
>   DYNDBG_CLASSMAP_USE(map_level_num);
>   
> @@ -211,6 +199,7 @@ static void __exit test_dynamic_debug_exit(void)
>   module_init(test_dynamic_debug_init);
>   module_exit(test_dynamic_debug_exit);
>   
> +MODULE_DESCRIPTION("test/demonstrate dynamic-debug features");
>   MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
>   MODULE_DESCRIPTION("Kernel module for testing dynamic_debug");
>   MODULE_LICENSE("GPL");
> diff --git a/lib/test_dynamic_debug_submod.c b/lib/test_dynamic_debug_submod.c
> index 9a893402ce1a..0d15f3ffe466 100644
> --- a/lib/test_dynamic_debug_submod.c
> +++ b/lib/test_dynamic_debug_submod.c
> @@ -1,6 +1,9 @@
>   // SPDX-License-Identifier: GPL-2.0
>   /*
> - * Kernel module for testing dynamic_debug
> + * Kernel module to test/demonstrate dynamic_debug features,
> + * particularly classmaps and their support for subsystems, like DRM,
> + * which defines its drm_debug classmap in drm module, and uses it in
> + * helpers & drivers.
>    *
>    * Authors:
>    *      Jim Cromie	<jim.cromie@gmail.com>
> @@ -8,3 +11,7 @@
>   
>   #define TEST_DYNAMIC_DEBUG_SUBMOD
>   #include "test_dynamic_debug.c"
> +
> +MODULE_DESCRIPTION("test/demonstrate dynamic-debug subsystem support");
> +MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
> +MODULE_LICENSE("GPL");

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 01/63] docs/dyndbg: update examples \012 to \n
  2025-01-25  6:45 ` [PATCH 01/63] docs/dyndbg: update examples \012 to \n Jim Cromie
@ 2025-02-25 14:30   ` Louis Chauvet
  2025-03-16 13:50     ` jim.cromie
  0 siblings, 1 reply; 103+ messages in thread
From: Louis Chauvet @ 2025-02-25 14:30 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb
  Cc: intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> commit 47ea6f99d06e ("dyndbg: use ESCAPE_SPACE for cat control")
> 
> changed the control-file to display format strings with "\n" rather
> than "\012".  Update the docs to match the new reality.
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>

Hi Jim,

I think this patch is incomplete, I just tested and the \012 in [1] 
needs to be replaced too.

[1]:https://elixir.bootlin.com/linux/v6.14-rc3/source/Documentation/admin-guide/dynamic-debug-howto.rst#L39-L46

With this change:
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
Tested-by: Louis Chauvet<louis.chauvet@bootlin.com>

> ---
>   Documentation/admin-guide/dynamic-debug-howto.rst | 10 +++++-----
>   1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
> index 7c036590cd07..691e0f7d4de1 100644
> --- a/Documentation/admin-guide/dynamic-debug-howto.rst
> +++ b/Documentation/admin-guide/dynamic-debug-howto.rst
> @@ -57,12 +57,12 @@ query/commands to the control file.  Example::
>     # grease the interface
>     :#> alias ddcmd='echo $* > /proc/dynamic_debug/control'
>   
> -  :#> ddcmd '-p; module main func run* +p'
> +  :#> ddcmd '-p; module main func run* +p'	# disable all, then enable main
>     :#> grep =p /proc/dynamic_debug/control
> -  init/main.c:1424 [main]run_init_process =p "  with arguments:\012"
> -  init/main.c:1426 [main]run_init_process =p "    %s\012"
> -  init/main.c:1427 [main]run_init_process =p "  with environment:\012"
> -  init/main.c:1429 [main]run_init_process =p "    %s\012"
> +  init/main.c:1424 [main]run_init_process =p "  with arguments:\n"
> +  init/main.c:1426 [main]run_init_process =p "    %s\n"
> +  init/main.c:1427 [main]run_init_process =p "  with environment:\n"
> +  init/main.c:1429 [main]run_init_process =p "    %s\n"
>   
>   Error messages go to console/syslog::
>   

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y
  2025-02-20  9:45   ` Simona Vetter
@ 2025-02-28 16:24     ` Louis Chauvet
  2025-03-12 16:26       ` jim.cromie
  0 siblings, 1 reply; 103+ messages in thread
From: Louis Chauvet @ 2025-02-28 16:24 UTC (permalink / raw)
  To: Greg KH, Jim Cromie, linux-kernel, jbaron, ukaszb,
	intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	tvrtko.ursulin, jani.nikula, ville.syrjala



Le 20/02/2025 à 10:45, Simona Vetter a écrit :
> On Thu, Feb 20, 2025 at 09:31:41AM +0100, Greg KH wrote:
>> On Fri, Jan 24, 2025 at 11:45:14PM -0700, Jim Cromie wrote:
>>> This series fixes dynamic-debug's support for DRM debug-categories.
>>> Classmaps-v1 evaded full review, and got committed in 2 chunks:
>>>
>>>    b7b4eebdba7b..6ea3bf466ac6	# core dyndbg changes
>>>    0406faf25fb1..ee7d633f2dfb	# drm adoption
>>>
>>> DRM-CI found a regression during init with drm.debug=<initval>; the
>>> static-keys under the drm-dbgs in drm.ko got enabled, but those in
>>> drivers & helpers did not.
>>>
>>> Root Problem:
>>>
>>> DECLARE_DYNDBG_CLASSMAP violated a K&R rule "define once, refer
>>> afterwards".  Replace it with DYNDBG_CLASSMAP_DEFINE (invoked once in
>>> drm-core) and DYNDBG_CLASSMAP_USE (invoked repeatedly, in drivers &
>>> helpers).
>>>
>>> _DEFINE exports the classmap it creates (in drm.ko), other modules
>>> _USE the classmap.  The _USE adds a record ref'g the _DEFINEd (&
>>> exported) classmap, in a 2nd __dyndbg_class_users section.
>>>
>>> So now at modprobe, dyndbg scans the new section after the 1st
>>> __dyndbg_class_maps section, follows the linkage to the _DEFINEr
>>> module, finds the (optional) kernel-param controlling the classmap,
>>> examines its drm.debug=<initval>, and applies it to the module being
>>> initialized.
>>>
>>> To recapitulate the multi-module problem wo DRM involvement, Add:
>>>
>>> A. tools/testing/selftests/dynamic_debug/*
>>>
>>> This alters pr_debugs in the test-modules, counts the results and
>>> checks them against expectations.  It uses this formula to test most
>>> of the control grammar, including the new class keyword.
>>>
>>> B. test_dynamic_debug_submod.ko
>>>
>>> This alters the test-module to build both parent & _submod ko's, with
>>> _DEFINE and _USE inside #if/#else blocks.  This recap's DRM's 2 module
>>> failure scenario, allowing A to exersize several cases.
>>>
>>> The #if/#else puts the 2 macro uses together for clarity, and gives
>>> the 2 modules identical sets of debugs.
>>>
>>> Recent DRM-CI tests are here:
>>>    https://patchwork.freedesktop.org/series/139147/
>>>
>>> Previous rev:
>>>    https://lore.kernel.org/lkml/20240716185806.1572048-1-jim.cromie@gmail.com/
>>>
>>> Noteworthy Additions:
>>>
>>> 1- drop class "protection" special case, per JBaron's preference.
>>>     only current use is marked BROKEN so nobody to affect.
>>>     now framed as policy-choice:
>>>     #define ddebug_client_module_protects_classes() false
>>>     subsystems wanting protection can change this.
>>>
>>> 2- compile-time arg-tests in DYNDBG_CLASSMAP_DEFINE
>>>     implement several required constraints, and fail obviously.
>>>
>>> 3- modprobe time check of conflicting class-id reservations
>>>     only affects 2+classmaps users.
>>>     compile-time solution not apparent.
>>>
>>> 4- dyndbg can now cause modprobe to fail.
>>>     needed to catch 3.
>>>     maybe some loose ends here on failure.
>>>
>>> 5- refactor & rename ddebug_attach_*module_classes
>>>     reduce repetetive boilerplate on 2 types: maps, users.
>>>     rework mostly brought forward in patchset to reduce churn
>>>     TBD: maybe squash more.
>>>
>>> Several recent trybot submissions (against drm-tip) have been passing
>>> CI.BAT, and failing one or few CI.IGT tests randomly; re-tests do not
>>> reliably repeat the failures.
>>>
>>> its also at github.com:jimc/linux.git
>>>    dd-fix-9[st]-ontip  &  dd-fix-9-13
>>>
>>> Ive been running it on my desktop w/o issues.
>>>
>>> The drivers/gpu/drm patches are RFC, I think there might be a single
>>> place to call DRM_CLASSMAP_USE(drm_dedbug_classes) to replace the
>>> sprinkling of _USEs in drivers and helpers.  IIRC, I tried adding a
>>> _DEFINE into drm_drv.c, that didn't do it, so I punted for now.
>>>
>>> I think the dyndbg core additions are ready for review and merging
>>> into a (next-next) test/integration tree.
>>
>> So whose tree should this go through?
> 
> I'm trying to get some drm folks to review/test this, but thus far not
> much success :-/ I think it's good stuff, but I'm somewhat hesitant if no

I tested the VKMS driver with this, and it works!

Tested-by: Louis Chauvet <louis.chauvet@bootlin.com>

> one else agrees that it's useful for CI or in-field crash-recording or
> whatever ...
> 
> I guess worst case we can land it and hope it attracts more folks?
> 
> Wrt tree I don't care, but I guess we should then also land the drm side
> too.
> -Sima
> 
>> And I think the last patch in this series isn't correct, it looks like a
>> 000 email somehow.
>>
>> thanks,
>>
>> greg k-h
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y
  2025-02-28 16:24     ` Louis Chauvet
@ 2025-03-12 16:26       ` jim.cromie
  0 siblings, 0 replies; 103+ messages in thread
From: jim.cromie @ 2025-03-12 16:26 UTC (permalink / raw)
  To: Louis Chauvet
  Cc: Greg KH, linux-kernel, jbaron, ukaszb, intel-gfx-trybot,
	dri-devel, amd-gfx, intel-gvt-dev, intel-gfx, tvrtko.ursulin,
	jani.nikula, ville.syrjala

hello everyone,

sorry for the late reply.  I have a cleaner version cooking now.
less inter-commit churn, by bringing more cleanups forward.

I'll send a -v2 soon.  (lets forget all the meandering crap versions I sent)

Louis, thanks for testing !!!!!

I wrote the test script and submod.ko so the lib/* parts would stand
by themselves.
And this time, I left the old DECLARE_ macro, so DRM doesnt get a
flag-day breakage :-)

But for ease of testing, I'll keep the DRM parts in the series.
Taking 1st N commits is normal workflow ?

On Fri, Feb 28, 2025 at 9:24 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
>
>
>
> Le 20/02/2025 à 10:45, Simona Vetter a écrit :
> > On Thu, Feb 20, 2025 at 09:31:41AM +0100, Greg KH wrote:
> >> On Fri, Jan 24, 2025 at 11:45:14PM -0700, Jim Cromie wrote:
> >>> This series fixes dynamic-debug's support for DRM debug-categories.
> >>> Classmaps-v1 evaded full review, and got committed in 2 chunks:
> >>>
> >>>    b7b4eebdba7b..6ea3bf466ac6       # core dyndbg changes
> >>>    0406faf25fb1..ee7d633f2dfb       # drm adoption
> >>>
> >>> DRM-CI found a regression during init with drm.debug=<initval>; the
> >>> static-keys under the drm-dbgs in drm.ko got enabled, but those in
> >>> drivers & helpers did not.
> >>>
> >>> Root Problem:
> >>>
> >>> DECLARE_DYNDBG_CLASSMAP violated a K&R rule "define once, refer
> >>> afterwards".  Replace it with DYNDBG_CLASSMAP_DEFINE (invoked once in
> >>> drm-core) and DYNDBG_CLASSMAP_USE (invoked repeatedly, in drivers &
> >>> helpers).
> >>>
> >>> _DEFINE exports the classmap it creates (in drm.ko), other modules
> >>> _USE the classmap.  The _USE adds a record ref'g the _DEFINEd (&
> >>> exported) classmap, in a 2nd __dyndbg_class_users section.
> >>>
> >>> So now at modprobe, dyndbg scans the new section after the 1st
> >>> __dyndbg_class_maps section, follows the linkage to the _DEFINEr
> >>> module, finds the (optional) kernel-param controlling the classmap,
> >>> examines its drm.debug=<initval>, and applies it to the module being
> >>> initialized.
> >>>
> >>> To recapitulate the multi-module problem wo DRM involvement, Add:
> >>>
> >>> A. tools/testing/selftests/dynamic_debug/*
> >>>
> >>> This alters pr_debugs in the test-modules, counts the results and
> >>> checks them against expectations.  It uses this formula to test most
> >>> of the control grammar, including the new class keyword.
> >>>
> >>> B. test_dynamic_debug_submod.ko
> >>>
> >>> This alters the test-module to build both parent & _submod ko's, with
> >>> _DEFINE and _USE inside #if/#else blocks.  This recap's DRM's 2 module
> >>> failure scenario, allowing A to exersize several cases.
> >>>
> >>> The #if/#else puts the 2 macro uses together for clarity, and gives
> >>> the 2 modules identical sets of debugs.
> >>>
> >>> Recent DRM-CI tests are here:
> >>>    https://patchwork.freedesktop.org/series/139147/
> >>>
> >>> Previous rev:
> >>>    https://lore.kernel.org/lkml/20240716185806.1572048-1-jim.cromie@gmail.com/
> >>>
> >>> Noteworthy Additions:
> >>>
> >>> 1- drop class "protection" special case, per JBaron's preference.
> >>>     only current use is marked BROKEN so nobody to affect.
> >>>     now framed as policy-choice:
> >>>     #define ddebug_client_module_protects_classes() false
> >>>     subsystems wanting protection can change this.
> >>>
> >>> 2- compile-time arg-tests in DYNDBG_CLASSMAP_DEFINE
> >>>     implement several required constraints, and fail obviously.
> >>>
> >>> 3- modprobe time check of conflicting class-id reservations
> >>>     only affects 2+classmaps users.
> >>>     compile-time solution not apparent.
> >>>
> >>> 4- dyndbg can now cause modprobe to fail.
> >>>     needed to catch 3.
> >>>     maybe some loose ends here on failure.
> >>>
> >>> 5- refactor & rename ddebug_attach_*module_classes
> >>>     reduce repetetive boilerplate on 2 types: maps, users.
> >>>     rework mostly brought forward in patchset to reduce churn
> >>>     TBD: maybe squash more.
> >>>
> >>> Several recent trybot submissions (against drm-tip) have been passing
> >>> CI.BAT, and failing one or few CI.IGT tests randomly; re-tests do not
> >>> reliably repeat the failures.
> >>>
> >>> its also at github.com:jimc/linux.git
> >>>    dd-fix-9[st]-ontip  &  dd-fix-9-13
> >>>
> >>> Ive been running it on my desktop w/o issues.
> >>>
> >>> The drivers/gpu/drm patches are RFC, I think there might be a single
> >>> place to call DRM_CLASSMAP_USE(drm_dedbug_classes) to replace the
> >>> sprinkling of _USEs in drivers and helpers.  IIRC, I tried adding a
> >>> _DEFINE into drm_drv.c, that didn't do it, so I punted for now.
> >>>
> >>> I think the dyndbg core additions are ready for review and merging
> >>> into a (next-next) test/integration tree.
> >>
> >> So whose tree should this go through?
> >
> > I'm trying to get some drm folks to review/test this, but thus far not
> > much success :-/ I think it's good stuff, but I'm somewhat hesitant if no
>
> I tested the VKMS driver with this, and it works!
>
> Tested-by: Louis Chauvet <louis.chauvet@bootlin.com>
>
> > one else agrees that it's useful for CI or in-field crash-recording or
> > whatever ...
> >
> > I guess worst case we can land it and hope it attracts more folks?
> >
> > Wrt tree I don't care, but I guess we should then also land the drm side
> > too.
> > -Sima
> >
> >> And I think the last patch in this series isn't correct, it looks like a
> >> 000 email somehow.
> >>
> >> thanks,
> >>
> >> greg k-h
> >
>
> --
> Louis Chauvet, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 01/63] docs/dyndbg: update examples \012 to \n
  2025-02-25 14:30   ` Louis Chauvet
@ 2025-03-16 13:50     ` jim.cromie
  0 siblings, 0 replies; 103+ messages in thread
From: jim.cromie @ 2025-03-16 13:50 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb,
	intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala

On Tue, Feb 25, 2025 at 7:30 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
>
>
>
> Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> > commit 47ea6f99d06e ("dyndbg: use ESCAPE_SPACE for cat control")
> >
> > changed the control-file to display format strings with "\n" rather
> > than "\012".  Update the docs to match the new reality.
> >
> > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
>
> Hi Jim,
>
> I think this patch is incomplete, I just tested and the \012 in [1]
> needs to be replaced too.
>

fixed here, thanks.

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 05/63] dyndbg: replace classmap list with a vector
  2025-02-25 14:08   ` Louis Chauvet
@ 2025-03-16 14:04     ` jim.cromie
  0 siblings, 0 replies; 103+ messages in thread
From: jim.cromie @ 2025-03-16 14:04 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb,
	intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala

On Tue, Feb 25, 2025 at 7:08 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
>
>
>
> Le 25/01/2025 ą 07:45, Jim Cromie a écrit :
> > Classmaps are stored in an elf section/array, but are individually
> > list-linked onto dyndbg's per-module ddebug_table for operation.
> >
> > This is unnecessary; even when ddebug_attach_classmap() is handling
> > the builtin section (with classmaps for multiple builtin modules), its
> > contents are ordered, so a module's possibly multiple classmaps will
> > be consecutive in the section, and could be treated as a vector/block,
> > since both start-address and subrange length are in the ddebug_info arg.
> >
> > IOW, this treats classmaps similarly to _ddebugs, which are already
> > kept as vector-refs (address+len).
> >
> > So this changes:
> >
> > struct ddebug_class_map drops list-head link.
> >
> > struct ddebug_table drops the list-head maps, and gets: classes &
> > num_classes for the start-address and num_classes, placed to improve
> > struct packing.
> >
> > The loading: in ddebug_attach_module_classes(), replace the
> > for-the-modname list-add loop, with a forloop that finds the module's
> > subrange (start,length) of matching classmaps within the possibly
> > builtin classmaps vector, and saves those to the ddebug_table.
> >
> > The reading/using: change list-foreach loops in ddebug_class_name() &
> > ddebug_find_valid_class() to walk the array from start to length.
> >
> > Also:
> > Move #define __outvar up, above an added use in a fn-prototype.
> > Simplify ddebug_attach_module_classes args, ref has both address & len.
> >
> > no functional changes
> >
> > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> > ---
> >   include/linux/dynamic_debug.h |  1 -
> >   lib/dynamic_debug.c           | 61 ++++++++++++++++++-----------------
> >   2 files changed, 32 insertions(+), 30 deletions(-)
> >
> > diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> > index b9afc7731b7c..2b0057058ecf 100644
> > --- a/include/linux/dynamic_debug.h
> > +++ b/include/linux/dynamic_debug.h
> > @@ -83,7 +83,6 @@ enum class_map_type {
> >   };
> >
> >   struct ddebug_class_map {
> > -     struct list_head link;
> >       struct module *mod;
> >       const char *mod_name;   /* needed for builtins */
> >       const char **class_names;
> > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> > index 55df35df093b..41cbaa96f83d 100644
> > --- a/lib/dynamic_debug.c
> > +++ b/lib/dynamic_debug.c
> > @@ -45,10 +45,11 @@ extern struct ddebug_class_map __start___dyndbg_classes[];
> >   extern struct ddebug_class_map __stop___dyndbg_classes[];
> >
> >   struct ddebug_table {
> > -     struct list_head link, maps;
> > +     struct list_head link;
> >       const char *mod_name;
> > -     unsigned int num_ddebugs;
> >       struct _ddebug *ddebugs;
> > +     struct ddebug_class_map *classes;
> > +     unsigned int num_ddebugs, num_classes;
> >   };
> >
> >   struct ddebug_query {
> > @@ -147,13 +148,15 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
> >                 query->first_lineno, query->last_lineno, query->class_string);
> >   }
> >
> > +#define __outvar /* filled by callee */
>
> Hi Jim,
>
> What is the goal of this __outvar define? I can't find any other #define
> of it in the kernel.

its basically a comment, trying to be more important.

if its misleading or overwrought, I can yank it :-)

>
> >   static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
> > -                                                       const char *class_string, int *class_id)
> > +                                                     const char *class_string,
> > +                                                     __outvar int *class_id)
>
> The order between __outvar and int is not important? Here you have
> __outvar before int, but later [1] the __outvar is after int.
>


I intended no difference, I used it where I thought it communicated best
in each case, and since the macro is empty, it makes none.



> [1]:https://elixir.bootlin.com/linux/v6.14-rc3/source/lib/dynamic_debug.c#L183
>
> Thanks,
> Louis Chauvet
>
> >   {
> >       struct ddebug_class_map *map;
> > -     int idx;
> > +     int i, idx;
> >
> > -     list_for_each_entry(map, &dt->maps, link) {
> > +     for (map = dt->classes, i = 0; i < dt->num_classes; i++, map++) {
> >               idx = match_string(map->class_names, map->length, class_string);
> >               if (idx >= 0) {
> >                       *class_id = idx + map->base;
> > @@ -164,7 +167,6 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
> >       return NULL;
> >   }
> >
> > -#define __outvar /* filled by callee */
> >   /*
> >    * Search the tables for _ddebug's which match the given `query' and
> >    * apply the `flags' and `mask' to them.  Returns number of matching
> > @@ -1114,9 +1116,10 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
> >
> >   static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp)
> >   {
> > -     struct ddebug_class_map *map;
> > +     struct ddebug_class_map *map = iter->table->classes;
> > +     int i, nc = iter->table->num_classes;
> >
> > -     list_for_each_entry(map, &iter->table->maps, link)
> > +     for (i = 0; i < nc; i++, map++)
> >               if (class_in_range(dp->class_id, map))
> >                       return map->class_names[dp->class_id - map->base];
> >
> > @@ -1200,30 +1203,31 @@ static const struct proc_ops proc_fops = {
> >       .proc_write = ddebug_proc_write
> >   };
> >
> > -static void ddebug_attach_module_classes(struct ddebug_table *dt,
> > -                                      struct ddebug_class_map *classes,
> > -                                      int num_classes)
> > +static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
> >   {
> >       struct ddebug_class_map *cm;
> > -     int i, j, ct = 0;
> > +     int i, nc = 0;
> >
> > -     for (cm = classes, i = 0; i < num_classes; i++, cm++) {
> > +     /*
> > +      * Find this module's classmaps in a subrange/wholerange of
> > +      * the builtin/modular classmap vector/section.  Save the start
> > +      * and length of the subrange at its edges.
> > +      */
> > +     for (cm = di->classes, i = 0; i < di->num_classes; i++, cm++) {
> >
> >               if (!strcmp(cm->mod_name, dt->mod_name)) {
> > -
> > -                     v2pr_info("class[%d]: module:%s base:%d len:%d ty:%d\n", i,
> > -                               cm->mod_name, cm->base, cm->length, cm->map_type);
> > -
> > -                     for (j = 0; j < cm->length; j++)
> > -                             v3pr_info(" %d: %d %s\n", j + cm->base, j,
> > -                                       cm->class_names[j]);
> > -
> > -                     list_add(&cm->link, &dt->maps);
> > -                     ct++;
> > +                     if (!nc) {
> > +                             v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
> > +                                       i, cm->mod_name, cm->base, cm->length, cm->map_type);
> > +                             dt->classes = cm;
> > +                     }
> > +                     nc++;
> >               }
> >       }
> > -     if (ct)
> > -             vpr_info("module:%s attached %d classes\n", dt->mod_name, ct);
> > +     if (nc) {
> > +             dt->num_classes = nc;
> > +             vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
> > +     }
> >   }
> >
> >   /*
> > @@ -1256,10 +1260,9 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
> >       dt->num_ddebugs = di->num_descs;
> >
> >       INIT_LIST_HEAD(&dt->link);
> > -     INIT_LIST_HEAD(&dt->maps);
> >
> >       if (di->classes && di->num_classes)
> > -             ddebug_attach_module_classes(dt, di->classes, di->num_classes);
> > +             ddebug_attach_module_classes(dt, di);
> >
> >       mutex_lock(&ddebug_lock);
> >       list_add_tail(&dt->link, &ddebug_tables);
> > @@ -1372,8 +1375,8 @@ static void ddebug_remove_all_tables(void)
> >       mutex_lock(&ddebug_lock);
> >       while (!list_empty(&ddebug_tables)) {
> >               struct ddebug_table *dt = list_entry(ddebug_tables.next,
> > -                                                   struct ddebug_table,
> > -                                                   link);
> > +                                                  struct ddebug_table,
> > +                                                  link);
> >               ddebug_table_free(dt);
> >       }
> >       mutex_unlock(&ddebug_lock);
>
> --
> Louis Chauvet, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 16/63] dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP
  2025-02-25 14:16   ` Louis Chauvet
@ 2025-03-16 19:46     ` jim.cromie
  2025-03-24 15:07       ` Louis Chauvet
  0 siblings, 1 reply; 103+ messages in thread
From: jim.cromie @ 2025-03-16 19:46 UTC (permalink / raw)
  To: Louis Chauvet, Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb,
	intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala

hi Louis,

On Tue, Feb 25, 2025 at 7:16 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
>
>
>
> Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> > DECLARE_DYNDBG_CLASSMAP() has a design error; its usage fails a basic
> > K&R rule: "define once, refer many times".
> >
> > It is used across DRM core & drivers, each use re-defines the classmap
> > understood by that module; and all must match for the modules to
> > respond together when DRM.debug categories are enabled.  This is
> > brittle; a maintenance foot-gun.
> >
> > Further, its culpable in the CONFIG_DRM_USE_DYNAMIC_DEBUG=Y
> > regression; its use in both core & drivers obfuscates the 2 roles.
> > So 1st drm.ko loads, and dyndbg initializes its DRM.debug callsites,
> > then a drm-driver loads, but too late - it missed the DRM.debug
> > enablement.
> >
> > So replace it with 2 macros:
> >    DYNDBG_CLASSMAP_DEFINE - invoked once from core - drm.ko
> >    DYNDBG_CLASSMAP_USE    - from all drm drivers and helpers.
> >
> > DYNDBG_CLASSMAP_DEFINE: it just modifies DECLARE_DYNDBG_CLASSMAP,
> > dropping drop the static qualifier, and exports it instead.
> >
> > DYNDBG_CLASSMAP_USE: then refers to the exported var by name:
> >    used from drivers, helper-mods
> >    lets us drop the repetitive "classname" declarations
> >    fixes 2nd-defn problem
> >    creates a ddebug_class_user record in new __dyndbg_class_users section
> >    this allows ddebug_add_module(etal) to handle users differently.
> >
> > DECLARE_DYNDBG_CLASSMAP is preserved temporarily, to decouple DRM
> > adaptation work and avoid compile-errs before its done.  IOW, DRM gets
> > fixed when they commit the adopt-new-api patches, and remove the
> > BROKEN marking.
> >
> > The DEFINE,USE distinction, and the separate classmap-use record,
> > allows dyndbg to initialize the driver's & helper's DRM.debug
> > callsites separately after each is modprobed.
> >
> > Basically, the classmap init-scan is repeated for classmap-users.
> >
> > To review, dyndbg's existing __dyndbg_classes[] section does:
> >
> > . catalogs the classmaps defined by a module (or builtin modules)
> > . tells dyndbg the module has class'd prdbgs, allowing >control
> > . DYNDBG_CLASSMAP_DEFINE creates classmaps in this section.
> >
> > This patch adds __dyndbg_class_users[] section:
> >
> > . catalogs uses/references to the classmap definitions.
> > . authorizes dyndbg to >control those class'd prdbgs in ref'g module.
> > . DYNDBG_CLASSMAP_USE() creates classmap-user records in this new section.
> >
> > Now ddebug_add_module(etal) can handle classmap-uses similar to (and
> > after) classmaps; when a dependent module is loaded, if it has
> > classmap-uses (to a classmap-def in another module), that module's
> > kernel params are scanned to find if it has a kparam that is wired to
> > dyndbg's param-ops, and whose classmap is the one being ref'd.
> >
> > To support this, theres a few data/header changes:
> >
> > new struct ddebug_class_user
> >    contains: user-module-name, &classmap-defn
> >    it records drm-driver's use of a classmap in the section, allowing lookup
> >
> > struct ddebug_info gets 2 new fields for the new sections:
> >    class_users, num_class_users.
> >    set by dynamic_debug_init() for builtins.
> >    or by kernel/module/main:load_info() for loadable modules.
> >
> > vmlinux.lds.h: new BOUNDED_SECTION for __dyndbg_class_users
> >
> > dynamic_debug.c has 2 changes in ddebug_add_module(), ddebug_change():
> >
> > ddebug_add_module() already calls ddebug_attach_module_classes()
> > to handle classmaps DEFINEd by a module, now it also calls
> > ddebug_attach_user_module_classes() to handle USEd classmaps.  To
> > avoid this work when possible, 1st scan the module's descriptors and
> > count the number of class'd pr_debugs.
> >
> > ddebug_attach_user_module_classes() scans the module's class_users
> > section, follows the refs to the parent's classmap, and calls
> > ddebug_apply_params() on each.  It also avoids work by checking the
> > module's class-ct.
> >
> > ddebug_apply_params(new fn):
> >
> > It scans module's/builtin kernel-params, calls ddebug_match_apply_kparam
> > for each to find any params/sysfs-nodes which may be wired to a classmap.
> >
> > ddebug_match_apply_kparam(new fn):
> >
> > 1st, it tests the kernel-param.ops is dyndbg's; this guarantees that
> > the attached arg is a struct ddebug_class_param, which has a ref to
> > the param's state, and to the classmap defining the param's handling.
> >
> > 2nd, it requires that the classmap ref'd by the kparam is the one
> > we're called for; modules can use many separate classmaps (as
> > test_dynamic_debug does).
> >
> > Then apply the "parent" kparam's setting to the dependent module,
> > using ddebug_apply_class_bitmap().
> >
> > ddebug_change(and callees) also gets adjustments:
> >
> > ddebug_find_valid_class(): This does a search over the module's
> > classmaps, looking for the class FOO echo'd to >control.  So now it
> > searches over __dyndbg_class_users[] after __dyndbg_classes[].
> >
> > ddebug_class_name(): return class-names for defined AND used classes.
> >
> > test_dynamic_debug.c, test_dynamic_debug_submod.c:
> >
> > This demonstrates the 2 types of classmaps & sysfs-params, following
> > the 4-part recipe:
> >
> > 1. define an enum for the classmap: DRM.debug has DRM_UT_{CORE,KMS,...}
> >     multiple classes must share 0-62 classid space.
> > 2. DYNDBG_CLASSMAP_DEFINE(.. DRM_UT_{CORE,KMS,...})
> > 3. DYNDBG_CLASSMAP_PARAM* (classmap)
> > 4. DYNDBG_CLASSMAP_USE()
> >     by _submod only, skipping 2,3
> >
> > Move all the enum declarations together, to better explain how they
> > share the 0..62 class-id space available to a module (non-overlapping
> > subranges).
> >
> > reorg macros 2,3 by name.  This gives a tabular format, making it easy
> > to see the pattern of repetition, and the points of change.
> >
> > And extend the test to replicate the 2-module (parent & dependent)
> > scenario which caused the CONFIG_DRM_USE_DYNAMIC_DEBUG=y regression
> > seen in drm & drivers.
> >
> > The _submod.c is a 2-line file: #define _SUBMOD, #include parent.
> >
> > This gives identical complements of prdbgs in parent & _submod, and
> > thus identical print behavior when all of: >control, >params, and
> > parent->_submod propagation are working correctly.
> >
> > It also puts all the parent/_submod declarations together in the same
> > source, with the new ifdef _SUBMOD block invoking DYNDBG_CLASSMAP_USE
> > for the 2 test-interfaces.  I think this is clearer.
> >
> > These 2 modules are both tristate, allowing 3 super/sub combos: Y/Y,
> > Y/M, M/M (not N/N).  Y/Y testing exposed a missing __align(8) in the
> > _METADATA macro, which M/M didn't see because the module-loader memory
> > placement constrains it instead.
> >
> > NB: this patch ignores a checkpatch do-while warning which is fixed by
> > a preceding commit, which would be wrong for declarative macros like
> > module_param_named() etc.
> >
> > Fixes: aad0214f3026 ("dyndbg: add DECLARE_DYNDBG_CLASSMAP macro")
> > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> > ---
> > v9 - commit-msg tweaks
> >       DRM:CHECK warnings on macros: add parens
> >       extern DEFINEd _var, static classnames
> >       change ddebug_class_user.user_mod_name to .mod_name
> >       simplify ddebug_find_valid_class
> >       improve vpr_cm_info msg format
> >       wrap (base) in macro body
> >       move __DYNDBG_CLASSMAP_CHECK above kdoc for DYNDBG_CLASSMAP_DEFINE
> >
> > v8 - split drm parts to separate commits.
> >       preserve DECLARE_DYNDBG_CLASSMAP to decouple DRM, no flag day.
> >       fixup block comment
> >
> > v7 - previous submission-blocking bug:
> >
> > missing __align(8) in DYNAMIC_DEBUG_DECLARE_METADATA on
> > ddebug_class_user caused corrupt records, but only for builtin
> > modules; module loader code probably pinned allocations to the right
> > alignment naturally, hiding the bug for typical builds.
> >
> > v6- get rid of WARN_ON_ONCE
> > v?- fix _var expanded 2x in macro
> >
> > dyndbg:
> >
> > This fn formerly returned the map which contained the class (thus
> > validating it), and as a side-effect set the class-id in an outvar.
> >
> > But the caller didn't use the map (after checking its not null), only
> > the valid class-id.  So simplify the fn to return the class-id of the
> > validated classname, or -ENOENT when the queried classname is not
> > found.
> >
> > Convey more useful info in the debug-msg: print class-names[0,last],
> > and [base,+len] instead of the class-type printout, which is currently
> > always "type:DISJOINT_BITS".  And drop ddebug_classmap_typenames,
> > which is now unused.
> >
> > [root@v6 b0-dd]# modprobe test_dynamic_debug_submod
> > [   18.864962] dyndbg: loaded classmap: test_dynamic_debug [16..24] V0..V7
> > [   18.865046] dyndbg:  found kp:p_level_num =0x0
> > [   18.865048] dyndbg:   mapped to: test_dynamic_debug [16..24] V0..V7
> > [   18.865164] dyndbg:   p_level_num: lvl:0 bits:0x0
> > [   18.865217] dyndbg: loaded classmap: test_dynamic_debug [0..10] D2_CORE..D2_DRMRES
> > [   18.865297] dyndbg:  found kp:p_disjoint_bits =0x0
> > [   18.865298] dyndbg:   mapped to: test_dynamic_debug [0..10] D2_CORE..D2_DRMRES
> > [   18.865424] dyndbg:   p_disjoint_bits: classbits: 0x0
> > [   18.865472] dyndbg: module:test_dynamic_debug attached 2 classmaps
> > [   18.865533] dyndbg:  23 debug prints in module test_dynamic_debug
> > [   18.866558] dyndbg: loaded classmap: test_dynamic_debug_submod [16..24] V0..V7
> > [   18.866698] dyndbg:  found kp:p_level_num =0x0
> > [   18.866699] dyndbg:   mapped to: test_dynamic_debug_submod [16..24] V0..V7
> > [   18.866865] dyndbg:   p_level_num: lvl:0 bits:0x0
> > [   18.866926] dyndbg: loaded classmap: test_dynamic_debug_submod [0..10] D2_CORE..D2_DRMRES
> > [   18.867026] dyndbg:  found kp:p_disjoint_bits =0x0
> > [   18.867027] dyndbg:   mapped to: test_dynamic_debug_submod [0..10] D2_CORE..D2_DRMRES
> > [   18.867193] dyndbg:   p_disjoint_bits: classbits: 0x0
> > [   18.867255] dyndbg: module:test_dynamic_debug_submod attached 2 classmap uses
> > [   18.867351] dyndbg:  23 debug prints in module test_dynamic_debug_submod
> > ---
> >   MAINTAINERS                       |   2 +-
> >   include/asm-generic/vmlinux.lds.h |   1 +
> >   include/linux/dynamic_debug.h     |  83 ++++++++++--
> >   kernel/module/main.c              |   3 +
> >   lib/Kconfig.debug                 |  24 +++-
> >   lib/Makefile                      |   3 +
> >   lib/dynamic_debug.c               | 203 ++++++++++++++++++++++++------
> >   lib/test_dynamic_debug.c          | 111 +++++++++++-----
> >   lib/test_dynamic_debug_submod.c   |  10 ++
>
> Hi Jim,
>
> While reading the files test_dynamic_debug*, I was wondering, they are
> more samples than tests. Does it make sense to move them in samples/?
> There is no need to do it in this series.
>
> >   9 files changed, 355 insertions(+), 85 deletions(-)
> >   create mode 100644 lib/test_dynamic_debug_submod.c
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 0fa7c5728f1e..38afccb3b71e 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -8041,7 +8041,7 @@ M:      Jim Cromie <jim.cromie@gmail.com>
> >   S:  Maintained
> >   F:  include/linux/dynamic_debug.h
> >   F:  lib/dynamic_debug.c
> > -F:   lib/test_dynamic_debug.c
> > +F:   lib/test_dynamic_debug*.c
> >
> >   DYNAMIC INTERRUPT MODERATION
> >   M:  Tal Gilboa <talgi@nvidia.com>
> > diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> > index 54504013c749..eb93fd09832b 100644
> > --- a/include/asm-generic/vmlinux.lds.h
> > +++ b/include/asm-generic/vmlinux.lds.h
> > @@ -366,6 +366,7 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
> >       /* implement dynamic printk debug */                            \
> >       . = ALIGN(8);                                                   \
> >       BOUNDED_SECTION_BY(__dyndbg_classes, ___dyndbg_classes)         \
> > +     BOUNDED_SECTION_BY(__dyndbg_class_users, ___dyndbg_class_users) \
> >       BOUNDED_SECTION_BY(__dyndbg, ___dyndbg)                         \
> >       CODETAG_SECTIONS()                                              \
> >       LIKELY_PROFILE()                                                \
> > diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> > index c8102e89beb2..dc610a12b91c 100644
> > --- a/include/linux/dynamic_debug.h
> > +++ b/include/linux/dynamic_debug.h
> > @@ -71,9 +71,28 @@ enum ddebug_class_map_type {
> >        */
> >   };
> >
> > +/*

BTW, Im gonna refine this ...

> > + * dyndbg-classmaps are devised to support DRM.debug directly:
> > + *    10 enum-vals: DRM_UT_* define the categories
> > + *   ~23 categorized *_dbg() macros, each passing a DRM_UT_* val as 1st arg
> > + *     2 macros below them: drm_dev_dbg, __drm_dbg
> > + * ~5000 calls to the categorized macros, across all of drivers/gpu/drm/
> > + *
> > + * When CONFIG_DRM_USE_DYNAMIC_DEBUG=y, the 2 low macros are redefined
> > + * to invoke _dynamic_func_call_cls().  This compiles the category
> > + * into each callsite's class_id field, where dyndbg can select on it
> > + * and alter a callsite's patch-state, avoiding repeated __drm_debug
> > + * checks.
> > + *
> > + * To make the callsites manageable from the >control file, authors
> > + * provide a "classmap" of names to class_ids in use by the module(s),
> > + * usually by stringifying the enum-vals.  Modules with multiple
> > + * classmaps must arrange to share the 0..62 class_id space.
> > + */
> > +
> >   struct ddebug_class_map {
> > -     struct module *mod;
> > -     const char *mod_name;   /* needed for builtins */
> > +     const struct module *mod;               /* NULL for builtins */
> > +     const char *mod_name;
>
> Is this change belongs to this patch? If not can you move this in a
> "cleanup" patch?

It belongs, insofar as the mod field is actually NULL checked to determine
builtin vs modular, mod_name is backup.
Also its more specific than "needed for builtins"

But, grumble, ya, the above was an existing test, not a new one.
OTOH - I guess Ive just written the cleanup commit msg :-)

>
> >       const char **class_names;
> >       const int length;
> >       const int base;         /* index of 1st .class_id, allows split/shared space */
> > @@ -81,11 +100,34 @@ struct ddebug_class_map {
> >   };
> >
> >   /**
> > - * DECLARE_DYNDBG_CLASSMAP - declare classnames known by a module
> > - * @_var:   a struct ddebug_class_map, passed to module_param_cb
> > - * @_type:  enum class_map_type, chooses bits/verbose, numeric/symbolic
> > - * @_base:  offset of 1st class-name. splits .class_id space
> > - * @classes: class-names used to control class'd prdbgs
> > + * DYNDBG_CLASSMAP_DEFINE - define debug classes used by a module.
> > + * @_var:   name of the classmap, exported for other modules coordinated use.
> > + * @_mapty: enum ddebug_class_map_type: 0:DISJOINT - independent, 1:LEVEL - v2>v1> + * @_base:  reserve N classids starting at _base, to split 0..62
> classid space
> > + * @classes: names of the N classes.
> > + *
> > + * This tells dyndbg what class_ids the module is using: _base..+N, by
> > + * mapping names onto them.  This qualifies "class NAME" >controls on
> > + * the defining module, ignoring unknown names.
> > + */
> > +#define DYNDBG_CLASSMAP_DEFINE(_var, _mapty, _base, ...)             \
> > +     static const char *_var##_classnames[] = { __VA_ARGS__ };       \
> > +     extern struct ddebug_class_map _var;                            \
> > +     struct ddebug_class_map __aligned(8) __used                     \
> > +             __section("__dyndbg_classes") _var = {                  \
> > +             .mod = THIS_MODULE,                                     \
> > +             .mod_name = KBUILD_MODNAME,                             \
> > +             .base = (_base),                                        \
> > +             .map_type = (_mapty),                                   \
> > +             .length = ARRAY_SIZE(_var##_classnames),                \
> > +             .class_names = _var##_classnames,                       \
> > +     };                                                              \
> > +     EXPORT_SYMBOL(_var)
> > +
> > +/*
> > + * XXX: keep this until DRM adapts to use the DEFINE/USE api, it
> > + * differs from DYNDBG_CLASSMAP_DEFINE by the static replacing the
> > + * extern/EXPORT on the struct init.
> >    */
> >   #define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...)         \
> >       static const char *_var##_classnames[] = { __VA_ARGS__ };       \
> > @@ -99,12 +141,37 @@ struct ddebug_class_map {
> >               .class_names = _var##_classnames,                       \
> >       }
> >
> > +struct ddebug_class_user {
> > +     char *mod_name;
> > +     struct ddebug_class_map *map;
> > +};
> > +
> > +/**
> > + * DYNDBG_CLASSMAP_USE - refer to a classmap, DEFINEd elsewhere.
> > + * @_var: name of the exported classmap var
> > + *
> > + * This tells dyndbg that the module has prdbgs with classids defined
> > + * in the named classmap.  This qualifies "class NAME" >controls on
> > + * the user module, ignoring unknown names.
> > + */
> > +#define DYNDBG_CLASSMAP_USE(_var)                                    \
> > +     DYNDBG_CLASSMAP_USE_(_var, __UNIQUE_ID(ddebug_class_user))
> > +#define DYNDBG_CLASSMAP_USE_(_var, _uname)                           \
> > +     extern struct ddebug_class_map _var;                            \
> > +     static struct ddebug_class_user __aligned(8) __used             \
> > +     __section("__dyndbg_class_users") _uname = {                    \
> > +             .mod_name = KBUILD_MODNAME,                             \
> > +             .map = &(_var),                                         \
> > +     }
> > +
>
> I'm not sure I understand properly how __section works, but can we use
> multiple DYNDBG_CLASSMAP_USE in one module? Can we also use
> DYNDBG_CLASSMAP_DEFINE while also importing an other classmap
> DYNDBG_CLASSMAP_USE?
>

Yes, its supposed to work that way.

I havent tested that specific scenario (yet), but
a _USEr module, like test-dynamic-debug-submod,
could also _DEFINE its own, as long as it honors
the class-id mapping it is using and therefore sharing.
The on-modprobe conflict check should catch this condition.

And __section (ISTM) accumulates entries, typically static struct var
initializations.
AFAICT, scanning the sections is how these { scoped statics } are
often reachable.

For example, dd's _METADATA_ builds a { static _ddebug } for every pr_debug.
They all go into the __dyndbg section (renamed with _descriptors suffix soon),
in the order their respective definer objects are linked.

include/asm-generic/vmlinux.lds.h  then places the __dyndbg_* sections
into DATA, along with lots of other freight, for the various
mechanisms they serve.




> If not, does it make sense to allow it (for example MFD devices can
> touch multiple subsystems)?

We have another use case !
Do you know your way around that case ?

Note that DEFINEr  & USEr calls set up linkage dependencies,
As long as these are consistent with other module deps,
it should work.


>
> >   /* encapsulate linker provided built-in (or module) dyndbg data */
> >   struct _ddebug_info {
> >       struct _ddebug *descs;
> >       struct ddebug_class_map *classes;
> > +     struct ddebug_class_user *class_users;
> >       unsigned int num_descs;
> >       unsigned int num_classes;
> > +     unsigned int num_class_users;
> >   };
> >
> >   struct ddebug_class_param {
> > @@ -205,7 +272,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
> >    * (|_no_desc):     former gets callsite descriptor as 1st arg (for prdbgs)
> >    */
> >   #define __dynamic_func_call_cls(id, cls, fmt, func, ...) do {       \
> > -     DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt);        \
> > +     DEFINE_DYNAMIC_DEBUG_METADATA_CLS((id), cls, fmt);      \
>
> Can you move this in a "cleanup" patch?
>
> >       if (DYNAMIC_DEBUG_BRANCH(id))                           \
> >               func(&id, ##__VA_ARGS__);                       \
> >   } while (0)
> > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > index 5399c182b3cb..c394a0c6e8c6 100644
> > --- a/kernel/module/main.c
> > +++ b/kernel/module/main.c
> > @@ -2546,6 +2546,9 @@ static int find_module_sections(struct module *mod, struct load_info *info)
> >       mod->dyndbg_info.classes = section_objs(info, "__dyndbg_classes",
> >                                               sizeof(*mod->dyndbg_info.classes),
> >                                               &mod->dyndbg_info.num_classes);
> > +     mod->dyndbg_info.class_users = section_objs(info, "__dyndbg_class_users",
> > +                                                 sizeof(*mod->dyndbg_info.class_users),
> > +                                                &mod->dyndbg_info.num_class_users);
> >   #endif
> >
> >       return 0;
> > diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> > index f3d723705879..933f69ef87f8 100644
> > --- a/lib/Kconfig.debug
> > +++ b/lib/Kconfig.debug
> > @@ -2884,12 +2884,26 @@ config TEST_STATIC_KEYS
> >         If unsure, say N.
> >
> >   config TEST_DYNAMIC_DEBUG
> > -     tristate "Test DYNAMIC_DEBUG"
> > -     depends on DYNAMIC_DEBUG
> > +     tristate "Build test-dynamic-debug module"
> > +     depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE
> >       help
> > -       This module registers a tracer callback to count enabled
> > -       pr_debugs in a 'do_debugging' function, then alters their
> > -       enablements, calls the function, and compares counts.
> > +       This module exercises/demonstrates dyndbg's classmap API, by
> > +       creating 2 classes: a DISJOINT classmap (supporting DRM.debug)
> > +       and a LEVELS/VERBOSE classmap (like verbose2 > verbose1).
> > +
> > +       If unsure, say N.
> > +
> > +config TEST_DYNAMIC_DEBUG_SUBMOD
> > +     tristate "Build test-dynamic-debug submodule"
> > +     default m
> > +     depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE
> > +     depends on TEST_DYNAMIC_DEBUG
> > +     help
> > +       This sub-module uses a classmap defined and exported by the
> > +       parent module, recapitulating drm & driver's shared use of
> > +       drm.debug to control enabled debug-categories.
> > +       It is tristate, independent of parent, to allow testing all
> > +       proper combinations of parent=y/m submod=y/m.
> >
> >         If unsure, say N.
> >
> > diff --git a/lib/Makefile b/lib/Makefile
> > index a8155c972f02..7f66fc1c163d 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> > @@ -84,6 +84,7 @@ obj-$(CONFIG_TEST_SORT) += test_sort.o
> >   obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o
> >   obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o
> >   obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o
> > +obj-$(CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD) += test_dynamic_debug_submod.o
> >   obj-$(CONFIG_TEST_PRINTF) += test_printf.o
> >   obj-$(CONFIG_TEST_SCANF) += test_scanf.o
> >
> > @@ -228,6 +229,8 @@ obj-$(CONFIG_ARCH_NEED_CMPXCHG_1_EMU) += cmpxchg-emu.o
> >   obj-$(CONFIG_DYNAMIC_DEBUG_CORE) += dynamic_debug.o
> >   #ensure exported functions have prototypes
> >   CFLAGS_dynamic_debug.o := -DDYNAMIC_DEBUG_MODULE
> > +CFLAGS_test_dynamic_debug.o := -DDYNAMIC_DEBUG_MODULE
> > +CFLAGS_test_dynamic_debug_submod.o := -DDYNAMIC_DEBUG_MODULE
> >
> >   obj-$(CONFIG_SYMBOLIC_ERRNAME) += errname.o
> >
> > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> > index 094d6e62a9d1..6bca0c6727d4 100644
> > --- a/lib/dynamic_debug.c
> > +++ b/lib/dynamic_debug.c
> > @@ -43,13 +43,16 @@ extern struct _ddebug __start___dyndbg[];
> >   extern struct _ddebug __stop___dyndbg[];
> >   extern struct ddebug_class_map __start___dyndbg_classes[];
> >   extern struct ddebug_class_map __stop___dyndbg_classes[];
> > +extern struct ddebug_class_user __start___dyndbg_class_users[];
> > +extern struct ddebug_class_user __stop___dyndbg_class_users[];
> >
> >   struct ddebug_table {
> >       struct list_head link;
> >       const char *mod_name;
> >       struct _ddebug *ddebugs;
> >       struct ddebug_class_map *classes;
> > -     unsigned int num_ddebugs, num_classes;
> > +     struct ddebug_class_user *class_users;
> > +     unsigned int num_ddebugs, num_classes, num_class_users;
> >   };
> >
> >   struct ddebug_query {
> > @@ -148,23 +151,35 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
> >                 query->first_lineno, query->last_lineno, query->class_string);
> >   }
> >
> > -#define __outvar /* filled by callee */
> > -static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
> > -                                                     const char *class_string,
> > -                                                     __outvar int *class_id)
> > +#define vpr_dt_info(dt_p, msg_p, ...) ({                             \
> > +     struct ddebug_table const *_dt = dt_p;                          \
> > +     v2pr_info(msg_p " module:%s nd:%d nc:%d nu:%d\n", ##__VA_ARGS__, \
> > +               _dt->mod_name, _dt->num_ddebugs, _dt->num_classes,    \
> > +               _dt->num_class_users);                                \
> > +     })
> > +
> > +static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *class_string)
> >   {
> >       struct ddebug_class_map *map;
> > +     struct ddebug_class_user *cli;
> >       int i, idx;
> >
> > -     for (map = dt->classes, i = 0; i < dt->num_classes; i++, map++) {
> > +     for (i = 0, map = dt->classes; i < dt->num_classes; i++, map++) {
> >               idx = match_string(map->class_names, map->length, class_string);
> >               if (idx >= 0) {
> > -                     *class_id = idx + map->base;
> > -                     return map;
> > +                     vpr_dt_info(dt, "good-class: %s.%s ", map->mod_name, class_string);
> > +                     return idx + map->base;
> >               }
> >       }
> > -     *class_id = -ENOENT;
> > -     return NULL;
> > +     for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++) {
> > +             idx = match_string(cli->map->class_names, cli->map->length, class_string);
> > +             if (idx >= 0) {
> > +                     vpr_dt_info(dt, "class-ref: %s -> %s.%s ",
> > +                                 cli->mod_name, cli->map->mod_name, class_string);
> > +                     return idx + cli->map->base;
> > +             }
> > +     }
> > +     return -ENOENT;
> >   }
> >
> >   /*
> > @@ -173,16 +188,14 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
> >    * callsites, normally the same as number of changes.  If verbose,
> >    * logs the changes.  Takes ddebug_lock.
> >    */
> > -static int ddebug_change(const struct ddebug_query *query,
> > -                      struct flag_settings *modifiers)
> > +static int ddebug_change(const struct ddebug_query *query, struct flag_settings *modifiers)
> >   {
> >       int i;
> >       struct ddebug_table *dt;
> >       unsigned int newflags;
> >       unsigned int nfound = 0;
> >       struct flagsbuf fbuf, nbuf;
> > -     struct ddebug_class_map *map = NULL;
> > -     int __outvar valid_class;
> > +     int valid_class;
> >
> >       /* search for matching ddebugs */
> >       mutex_lock(&ddebug_lock);
> > @@ -194,8 +207,8 @@ static int ddebug_change(const struct ddebug_query *query,
> >                       continue;
> >
> >               if (query->class_string) {
> > -                     map = ddebug_find_valid_class(dt, query->class_string, &valid_class);
> > -                     if (!map)
> > +                     valid_class = ddebug_find_valid_class(dt, query->class_string);
> > +                     if (valid_class < 0)
> >                               continue;
> >               } else {
> >                       /* constrain query, do not touch class'd callsites */
> > @@ -559,7 +572,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
> >
> >   /* handle multiple queries in query string, continue on error, return
> >      last error or number of matching callsites.  Module name is either
> > -   in param (for boot arg) or perhaps in query string.
> > +   in the modname arg (for boot args) or perhaps in query string.
> >   */
> >   static int ddebug_exec_queries(char *query, const char *modname)
> >   {
> > @@ -688,12 +701,12 @@ static int param_set_dyndbg_module_classes(const char *instr,
> >   }
> >
> >   /**
> > - * param_set_dyndbg_classes - class FOO >control
> > + * param_set_dyndbg_classes - set all classes in a classmap
> >    * @instr: string echo>d to sysfs, input depends on map_type
> > - * @kp:    kp->arg has state: bits/lvl, map, map_type
> > + * @kp:    kp->arg has state: bits/lvl, classmap, map_type
> >    *
> > - * Enable/disable prdbgs by their class, as given in the arguments to
> > - * DECLARE_DYNDBG_CLASSMAP.  For LEVEL map-types, enforce relative
> > + * For all classes in the classmap, enable/disable them per the input
> > + * (depending on map_type).  For LEVEL map-types, enforce relative
> >    * levels by bitpos.
> >    *
> >    * Returns: 0 or <0 if error.
> > @@ -1038,12 +1051,17 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
> >   static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp)
> >   {
> >       struct ddebug_class_map *map = dt->classes;
> > +     struct ddebug_class_user *cli = dt->class_users;
> >       int i;
> >
> >       for (i = 0; i < dt->num_classes; i++, map++)
> >               if (class_in_range(dp->class_id, map))
> >                       return map->class_names[dp->class_id - map->base];
> >
> > +     for (i = 0; i < dt->num_class_users; i++, cli++)
> > +             if (class_in_range(dp->class_id, cli->map))
> > +                     return cli->map->class_names[dp->class_id - cli->map->base];
> > +
> >       return NULL;
> >   }
> >
> > @@ -1124,31 +1142,129 @@ static const struct proc_ops proc_fops = {
> >       .proc_write = ddebug_proc_write
> >   };
> >
> > -static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
> > +#define vpr_cm_info(cm_p, msg_fmt, ...) ({                           \
> > +     struct ddebug_class_map const *_cm = cm_p;                      \
> > +     v2pr_info(msg_fmt " %s [%d..%d] %s..%s\n", ##__VA_ARGS__,       \
> > +               _cm->mod_name, _cm->base, _cm->base + _cm->length,    \
> > +               _cm->class_names[0], _cm->class_names[_cm->length - 1]); \
> > +     })
> > +
> > +static void ddebug_sync_classbits(const struct kernel_param *kp, const char *modname)
> > +{
> > +     const struct ddebug_class_param *dcp = kp->arg;
> > +
> > +     /* clamp initial bitvec, mask off hi-bits */
> > +     if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) {
> > +             *dcp->bits &= CLASSMAP_BITMASK(dcp->map->length);
> > +             v2pr_info("preset classbits: %lx\n", *dcp->bits);
> > +     }
> > +     /* force class'd prdbgs (in USEr module) to match (DEFINEr module) class-param */
> > +     ddebug_apply_class_bitmap(dcp, dcp->bits, ~0, modname);
> > +     ddebug_apply_class_bitmap(dcp, dcp->bits, 0, modname);
> > +}
> > +
> > +static void ddebug_match_apply_kparam(const struct kernel_param *kp,
> > +                                   const struct ddebug_class_map *map,
> > +                                   const char *modnm)
> > +{
> > +     struct ddebug_class_param *dcp;
> > +
> > +     if (kp->ops != &param_ops_dyndbg_classes)
> > +             return;
> > +
> > +     dcp = (struct ddebug_class_param *)kp->arg;
> > +
> > +     if (map == dcp->map) {
> > +             v2pr_info(" kp:%s.%s =0x%lx", modnm, kp->name, *dcp->bits);
> > +             vpr_cm_info(map, " %s mapped to: ", modnm);
> > +             ddebug_sync_classbits(kp, modnm);
> > +     }
> > +}
> > +
> > +static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *modnm)
> > +{
> > +     const struct kernel_param *kp;
> > +#if IS_ENABLED(CONFIG_MODULES)
> > +     int i;
> > +
> > +     if (cm->mod) {
> > +             vpr_cm_info(cm, "loaded classmap: %s", modnm);
> > +             /* ifdef protects the cm->mod->kp deref */
> > +             for (i = 0, kp = cm->mod->kp; i < cm->mod->num_kp; i++, kp++)
> > +                     ddebug_match_apply_kparam(kp, cm, modnm);
> > +     }
> > +#endif
> > +     if (!cm->mod) {
> > +             vpr_cm_info(cm, "builtin classmap: %s", modnm);
> > +             for (kp = __start___param; kp < __stop___param; kp++)
> > +                     ddebug_match_apply_kparam(kp, cm, modnm);
> > +     }
> > +}
> > +
> > +/*
> > + * Find this module's classmaps in a sub/whole-range of the builtin/
> > + * modular classmap vector/section.  Save the start and length of the
> > + * subrange at its edges.
> > + */
> > +static void ddebug_attach_module_classes(struct ddebug_table *dt,
> > +                                      const struct _ddebug_info *di)
> >   {
> >       struct ddebug_class_map *cm;
> >       int i, nc = 0;
> >
> > -     /*
> > -      * Find this module's classmaps in a subrange/wholerange of
> > -      * the builtin/modular classmap vector/section.  Save the start
> > -      * and length of the subrange at its edges.
> > -      */
> > -     for (cm = di->classes, i = 0; i < di->num_classes; i++, cm++) {
> > -
> > +     for (i = 0, cm = di->classes; i < di->num_classes; i++, cm++) {
> >               if (!strcmp(cm->mod_name, dt->mod_name)) {
> > -                     if (!nc) {
> > -                             v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
> > -                                       i, cm->mod_name, cm->base, cm->length, cm->map_type);
> > +                     vpr_cm_info(cm, "classes[%d]:", i);
> > +                     if (!nc++)
> >                               dt->classes = cm;
> > -                     }
> > -                     nc++;
> >               }
> >       }
> > -     if (nc) {
> > -             dt->num_classes = nc;
> > -             vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
> > +     if (!nc)
> > +             return;
> > +
> > +     vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
> > +     dt->num_classes = nc;
> > +
> > +     for (i = 0, cm = dt->classes; i < dt->num_classes; i++, cm++)
> > +             ddebug_apply_params(cm, cm->mod_name);
> > +}
> > +
> > +/*
> > + * propagates class-params thru their classmaps to class-users.  this
> > + * means a query against the dt/module, which means it must be on the
> > + * list to be seen by ddebug_change.
> > + */
> > +static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
> > +                                           const struct _ddebug_info *di)
> > +{
> > +     struct ddebug_class_user *cli;
> > +     int i, nc = 0;
> > +
> > +     /*
> > +      * For builtins: scan the array, find start/length of this
> > +      * module's refs, save to dt.  For loadables, this is the
> > +      * whole array.
> > +      */
> > +     for (i = 0, cli = di->class_users; i < di->num_class_users; i++, cli++) {
> > +             if (WARN_ON_ONCE(!cli || !cli->map || !cli->mod_name))
> > +                     continue;
> > +             if (!strcmp(cli->mod_name, dt->mod_name)) {
> > +                     vpr_cm_info(cli->map, "class_ref[%d] %s -> %s", i,
> > +                                 cli->mod_name, cli->map->mod_name);
> > +                     if (!nc++)
> > +                             dt->class_users = cli;
> > +             }
> >       }
> > +     if (!nc)
> > +             return;
> > +
> > +     dt->num_class_users = nc;
> > +
> > +     /* now iterate dt */
> > +     for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++)
> > +             ddebug_apply_params(cli->map, cli->mod_name);
> > +
> > +     vpr_dt_info(dt, "attach-client-module: ");
> >   }
> >
> >   /*
> > @@ -1158,6 +1274,8 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug
> >   static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
> >   {
> >       struct ddebug_table *dt;
> > +     struct _ddebug *iter;
> > +     int i, class_ct = 0;
> >
> >       if (!di->num_descs)
> >               return 0;
> > @@ -1181,13 +1299,20 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
> >
> >       INIT_LIST_HEAD(&dt->link);
> >
> > -     if (di->classes && di->num_classes)
> > +     for (i = 0, iter = di->descs; i < di->num_descs; i++, iter++)
> > +             if (iter->class_id != _DPRINTK_CLASS_DFLT)
> > +                     class_ct++;
> > +
> > +     if (class_ct && di->num_classes)
> >               ddebug_attach_module_classes(dt, di);
> >
> >       mutex_lock(&ddebug_lock);
> >       list_add_tail(&dt->link, &ddebug_tables);
> >       mutex_unlock(&ddebug_lock);
> >
> > +     if (class_ct && di->num_class_users)
> > +             ddebug_attach_user_module_classes(dt, di);
> > +
> >       vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
> >       return 0;
> >   }
> > @@ -1337,8 +1462,10 @@ static int __init dynamic_debug_init(void)
> >       struct _ddebug_info di = {
> >               .descs = __start___dyndbg,
> >               .classes = __start___dyndbg_classes,
> > +             .class_users = __start___dyndbg_class_users,
> >               .num_descs = __stop___dyndbg - __start___dyndbg,
> >               .num_classes = __stop___dyndbg_classes - __start___dyndbg_classes,
> > +             .num_class_users = __stop___dyndbg_class_users - __start___dyndbg_class_users,
> >       };
> >
> >   #ifdef CONFIG_MODULES
> > diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
> > index 74d183ebf3e0..1838f62738c4 100644
> > --- a/lib/test_dynamic_debug.c
> > +++ b/lib/test_dynamic_debug.c
> > @@ -6,11 +6,15 @@
> >    *      Jim Cromie  <jim.cromie@gmail.com>
> >    */
> >
> > -#define pr_fmt(fmt) "test_dd: " fmt
> > +#if defined(TEST_DYNAMIC_DEBUG_SUBMOD)
> > +  #define pr_fmt(fmt) "test_dd_submod: " fmt
> > +#else
> > +  #define pr_fmt(fmt) "test_dd: " fmt
> > +#endif
> >
> >   #include <linux/module.h>
> >
> > -/* run tests by reading or writing sysfs node: do_prints */
> > +/* re-gen output by reading or writing sysfs node: do_prints */
> >
> >   static void do_prints(void); /* device under test */
> >   static int param_set_do_prints(const char *instr, const struct kernel_param *kp)
> > @@ -29,24 +33,39 @@ static const struct kernel_param_ops param_ops_do_prints = {
> >   };
> >   module_param_cb(do_prints, &param_ops_do_prints, NULL, 0600);
> >
> > -/*
> > - * Using the CLASSMAP api:
> > - * - classmaps must have corresponding enum
> > - * - enum symbols must match/correlate with class-name strings in the map.
> > - * - base must equal enum's 1st value
> > - * - multiple maps must set their base to share the 0-30 class_id space !!
> > - *   (build-bug-on tips welcome)
> > - * Additionally, here:
> > - * - tie together sysname, mapname, bitsname, flagsname
> > - */
> > -#define DD_SYS_WRAP(_model, _flags)                                  \
> > -     static unsigned long bits_##_model;                             \
> > -     static struct ddebug_class_param _flags##_model = {             \
> > +#define CLASSMAP_BITMASK(width, base) (((1UL << (width)) - 1) << (base))
> > +
> > +/* sysfs param wrapper, proto-API */
> > +#define DYNDBG_CLASSMAP_PARAM_(_model, _flags, _init)                        \
> > +     static unsigned long bits_##_model = _init;                     \
> > +     static struct ddebug_class_param _flags##_##_model = {          \
> >               .bits = &bits_##_model,                                 \
> >               .flags = #_flags,                                       \
> >               .map = &map_##_model,                                   \
> >       };                                                              \
> > -     module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes, &_flags##_model, 0600)
> > +     module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes,   \
> > +                     &_flags##_##_model, 0600)
> > +#ifdef DEBUG
> > +#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, ~0)
> > +#else
> > +#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, 0)
> > +#endif
> > +
> > +/*
> > + * Demonstrate/test all 4 class-typed classmaps with a sys-param.
> > + *
> > + * Each is 3 part: client-enum decl, _DEFINE, _PARAM.
> > + * Declare them in blocks to show patterns of use (repetitions and
> > + * changes) within each.
> > + *
> > + * 1st, dyndbg expects a client-provided enum-type as source of
> > + * category/classid truth.  DRM has DRM_UT_<CORE,DRIVER,KMS,etc>.
> > + *
> > + * Modules with multiple CLASSMAPS must have enums with distinct
> > + * value-ranges, arranged below with explicit enum_sym = X inits.
> > + *
> > + * Declare all 4 enums now, for different types
> > + */
> >
> >   /* numeric input, independent bits */
> >   enum cat_disjoint_bits {
> > @@ -60,26 +79,51 @@ enum cat_disjoint_bits {
> >       D2_LEASE,
> >       D2_DP,
> >       D2_DRMRES };
> > -DECLARE_DYNDBG_CLASSMAP(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS, 0,
> > -                     "D2_CORE",
> > -                     "D2_DRIVER",
> > -                     "D2_KMS",
> > -                     "D2_PRIME",
> > -                     "D2_ATOMIC",
> > -                     "D2_VBL",
> > -                     "D2_STATE",
> > -                     "D2_LEASE",
> > -                     "D2_DP",
> > -                     "D2_DRMRES");
> > -DD_SYS_WRAP(disjoint_bits, p);
> > -DD_SYS_WRAP(disjoint_bits, T);
> >
> >   /* numeric verbosity, V2 > V1 related */
> >   enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
> > -DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14,
> > -                    "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
> > -DD_SYS_WRAP(level_num, p);
> > -DD_SYS_WRAP(level_num, T);
> > +
> > +/* recapitulate DRM's parent(drm.ko) <-- _submod(drivers,helpers) */
> > +#if !defined(TEST_DYNAMIC_DEBUG_SUBMOD)
>
> It was not clear at first read that the test_dynamic_debug.c code is
> used twice.
>

Yes, that was a miss.  Now in big comment block at the top of both,
right before the pr-fmt  mod-name shortening for the logs.


> What do you think about creating a third file "common" with
> do_prints/do_levels/... implementations and avoid this #if !defined?
>

I'd rather not.  I think the multi-module usage is sufficiently interconnected
(common enum, parent side, clone side) that all-in-one presentation
helps to communicate this "linkage".

I hope the new comments clearly elucidate this.  PLMK if not.

> > +/*
> > + * In single user, or parent / coordinator (drm.ko) modules, define
> > + * classmaps on the client enums above, and then declares the PARAMS
> > + * ref'g the classmaps.  Each is exported.
> > + */
> > +DYNDBG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS,
>
> map_disjoint_bits is defined in both test_dynamic_debug.c and
> test_dynamic_debug_submodule.c, is it normal/required?

Its the enum : cat_disjoint_bits, that is defined for both.

the _DEFINE itself is right after the ifdef TEST_MOD_SUBMOD.

do you think it needs a better MOD_SUBMOD name ?
or an ifndef ?

>
> > +                    D2_CORE,
> > +                    "D2_CORE",
> > +                    "D2_DRIVER",
> > +                    "D2_KMS",
> > +                    "D2_PRIME",
> > +                    "D2_ATOMIC",
> > +                    "D2_VBL",
> > +                    "D2_STATE",
> > +                    "D2_LEASE",
> > +                    "D2_DP",
> > +                    "D2_DRMRES");
> > +
> > +DYNDBG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
> > +                    V0, "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
> > +
> > +/*
> > + * now add the sysfs-params
> > + */
> > +
> > +DYNDBG_CLASSMAP_PARAM(disjoint_bits, p);
> > +DYNDBG_CLASSMAP_PARAM(level_num, p);
> > +
> > +#else /* TEST_DYNAMIC_DEBUG_SUBMOD */
> > +
> > +/*
> > + * in submod/drm-drivers, use the classmaps defined in top/parent
> > + * module above.
> > + */
> > +
> > +DYNDBG_CLASSMAP_USE(map_disjoint_bits);
> > +DYNDBG_CLASSMAP_USE(map_level_num);
> > +
> > +#endif
> >
> >   /* stand-in for all pr_debug etc */
> >   #define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
> > @@ -115,6 +159,7 @@ static void do_levels(void)
> >
> >   static void do_prints(void)
> >   {
> > +     pr_debug("do_prints:\n");
> >       do_cats();
> >       do_levels();
>
> I just observed it, is the ordering of logs garanteed in
> /proc/dynamic_debug/control?
>

Yes. the fully ordered table/__section is pretty important.
If its not true for descriptors, its probably not true for class-maps
or users either
and the list-iter --> vector-block conversion a few commits ago isnt
solid either.

its also an explicit assumption under these commits

773beabbb8e8 dyndbg: reverse module.callsite walk in cat control
2ad556f70043 dyndbg: reverse module walk in cat control

All in all, I think something would have broken by now.


> When I run this test, I have this order:
>
> do_cats =_ "doing categories\n"
> [...]
> do_levels =_ "doing levels\n"
> [...]
> do_prints =_ "do_prints:\n"
> test_dynamic_debug_init =_ "init start\n"
> test_dynamic_debug_init =_ "init done\n"
> test_dynamic_debug_exit =_ "exited\n"
>
> Which is clearly not the code execution order.

Youre correct.
the control file reflects compile link order.

Im pretty sure the appearance of init 1st in control derives from init/builtin.a
being built 1st and/or linked 1st.

>
> >   }
> > diff --git a/lib/test_dynamic_debug_submod.c b/lib/test_dynamic_debug_submod.c
> > new file mode 100644
> > index 000000000000..9a893402ce1a
> > --- /dev/null
> > +++ b/lib/test_dynamic_debug_submod.c
> > @@ -0,0 +1,10 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Kernel module for testing dynamic_debug
> > + *
> > + * Authors:
> > + *      Jim Cromie   <jim.cromie@gmail.com>
> > + */
> > +
> > +#define TEST_DYNAMIC_DEBUG_SUBMOD
> > +#include "test_dynamic_debug.c"
>
> --
> Louis Chauvet, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>

thanks again Lous,
Jim

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 17/63] dyndbg: check DYNDBG_CLASSMAP_DEFINE args at compile-time
  2025-02-25 14:17   ` Louis Chauvet
@ 2025-03-16 20:46     ` jim.cromie
  0 siblings, 0 replies; 103+ messages in thread
From: jim.cromie @ 2025-03-16 20:46 UTC (permalink / raw)
  To: Louis Chauvet, Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb,
	intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala

On Tue, Feb 25, 2025 at 7:17 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
>
>
>
> Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> > Add __DYNDBG_CLASSMAP_CHECK to implement these arg-checks at compile:
> >       0 <= _base < 63
> >       class_names is not empty
> >       class_names[0] is a string
> >       (class_names.length + _base) < 63
> >
> > These compile-time checks will prevent several misuses; 4 such
> > examples are added to test_dynamic_debug_submod.ko, and will fail
> > compilation if -DDD_MACRO_ARGCHECK is added to cflags.
> >
> > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> > ---
> > - split static-asserts to __DYNDBG_CLASSMAP_CHECK
> > - move __DYNDBG_CLASSMAP_CHECK above kdoc for DYNDBG_CLASSMAP_DEFINE
> >    silences kernel-doc warnings
> > ---
> >   include/linux/dynamic_debug.h |  9 +++++++++
> >   lib/test_dynamic_debug.c      | 11 +++++++++++
> >   2 files changed, 20 insertions(+)
> >
> > diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> > index dc610a12b91c..2b0c943af330 100644
> > --- a/include/linux/dynamic_debug.h
> > +++ b/include/linux/dynamic_debug.h
> > @@ -99,6 +99,14 @@ struct ddebug_class_map {
> >       enum ddebug_class_map_type map_type;
> >   };
> >
> > +#define __DYNDBG_CLASSMAP_CHECK(_clnames, _base)                     \
> > +     static_assert(((_base) >= 0 && (_base) < _DPRINTK_CLASS_DFLT),  \
> > +                   "_base must be in 0..62");                        \
> > +     static_assert(ARRAY_SIZE(_clnames) > 0,                         \
> > +                   "classnames array size must be > 0");             \
> > +     static_assert((ARRAY_SIZE(_clnames) + (_base)) < _DPRINTK_CLASS_DFLT, \
> > +                   "_base + classnames.length exceeds range")
> > +
> >   /**
> >    * DYNDBG_CLASSMAP_DEFINE - define debug classes used by a module.
> >    * @_var:   name of the classmap, exported for other modules coordinated use.
> > @@ -112,6 +120,7 @@ struct ddebug_class_map {
> >    */
> >   #define DYNDBG_CLASSMAP_DEFINE(_var, _mapty, _base, ...)            \
> >       static const char *_var##_classnames[] = { __VA_ARGS__ };       \
> > +     __DYNDBG_CLASSMAP_CHECK(_var##_classnames, (_base));            \
> >       extern struct ddebug_class_map _var;                            \
> >       struct ddebug_class_map __aligned(8) __used                     \
> >               __section("__dyndbg_classes") _var = {                  \
> > diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
> > index 1838f62738c4..b1555b0a2bb1 100644
> > --- a/lib/test_dynamic_debug.c
> > +++ b/lib/test_dynamic_debug.c
> > @@ -123,8 +123,19 @@ DYNDBG_CLASSMAP_PARAM(level_num, p);
> >   DYNDBG_CLASSMAP_USE(map_disjoint_bits);
> >   DYNDBG_CLASSMAP_USE(map_level_num);
> >
> > +#if defined(DD_MACRO_ARGCHECK)
> > +/*
> > + * Exersize compile-time arg-checks in DYNDBG_CLASSMAP_DEFINE.
> > + * These will break compilation.
> > + */
> > +DYNDBG_CLASSMAP_DEFINE(fail_base_neg, 0, -1, "NEGATIVE_BASE_ARG");
> > +DYNDBG_CLASSMAP_DEFINE(fail_base_big, 0, 100, "TOOBIG_BASE_ARG");
> > +DYNDBG_CLASSMAP_DEFINE(fail_str_type, 0, 0, 1 /* not a string */);
> > +DYNDBG_CLASSMAP_DEFINE(fail_emptyclass, 0, 0 /* ,empty */);
>
> Hi Jim,
>
> This test is nice, but can we move it in the *_submod.c directly? They
> don't need anything from this file.
>

Hi Louis,

Given my strong preference for continued / justified ifdeffery earlier,
I will interpret this as move these corner-case tests into the
submod-only branch.

Im happy to do it, and I see the commit-msg says that specifically,
but Im not sure what it will improve by moving it.
I could fix the commit msg instead.

these compile-time tests will break the build,
so I dont think theyre much good as a CONFIG_ option for example.

So making the breakage submodule specific isnt
much of a reduction in blast radius, and it only opens the why-submod-only ?

Any views or options ?  (both welcomed)


> Tested-by: Louis Chauvet <louis.chauvet@bootlin.com>

ack!

> Thanks,
> Louis Chauvet
>
> >   #endif
> >
> > +#endif /* TEST_DYNAMIC_DEBUG_SUBMOD */
> > +
> >   /* stand-in for all pr_debug etc */
> >   #define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
> >
>
> --
> Louis Chauvet, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 18/63] dyndbg: add/use for_subvec() to reduce boilerplate
  2025-02-25 14:18   ` Louis Chauvet
@ 2025-03-16 20:50     ` jim.cromie
  0 siblings, 0 replies; 103+ messages in thread
From: jim.cromie @ 2025-03-16 20:50 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb,
	intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala

On Tue, Feb 25, 2025 at 7:18 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
>
>
>
> Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> > add for_subvec() macro to encapsulate a for-loop pattern thats used
> > repeatedly to iterate over a boxed.vector of N elements.
> >
> > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
>
> Hi Jim,
>
> Do you think it is possible to move this patch earlier in the series, so
> you can use it when introducing class_users.
>

Yup. :-)

> Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
>
> Thanks,
> Louis Chauvet
>
> > ---
> >   lib/dynamic_debug.c | 30 ++++++++++++++++++++++--------
> >   1 file changed, 22 insertions(+), 8 deletions(-)
> >
> > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> > index 6bca0c6727d4..08b6e4e7489f 100644
> > --- a/lib/dynamic_debug.c
> > +++ b/lib/dynamic_debug.c
> > @@ -158,20 +158,34 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
> >                 _dt->num_class_users);                                \
> >       })
> >
> > +/*
> > + * simplify a repeated for-loop pattern walking N steps in a T _vec
> > + * member inside a struct _box.  It expects int i and T *_sp to be
> > + * declared in the caller.
> > + * @_i:  caller provided counter.
> > + * @_sp: cursor into _vec, to examine each item.
> > + * @_box: ptr to a struct containing @_vec member
> > + * @_vec: name of a sub-struct member in _box, with array-ref and length
> > + */
> > +#define for_subvec(_i, _sp, _box, _vec)                                     \
> > +     for ((_i) = 0, (_sp) = (_box)->_vec;                           \
> > +          (_i) < (_box)->num_##_vec;                                \
> > +          (_i)++, (_sp)++)
> > +
> >   static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *class_string)
> >   {
> >       struct ddebug_class_map *map;
> >       struct ddebug_class_user *cli;
> >       int i, idx;
> >
> > -     for (i = 0, map = dt->classes; i < dt->num_classes; i++, map++) {
> > +     for_subvec(i, map, dt, classes) {
> >               idx = match_string(map->class_names, map->length, class_string);
> >               if (idx >= 0) {
> >                       vpr_dt_info(dt, "good-class: %s.%s ", map->mod_name, class_string);
> >                       return idx + map->base;
> >               }
> >       }
> > -     for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++) {
> > +     for_subvec(i, cli, dt, class_users) {
> >               idx = match_string(cli->map->class_names, cli->map->length, class_string);
> >               if (idx >= 0) {
> >                       vpr_dt_info(dt, "class-ref: %s -> %s.%s ",
> > @@ -1190,7 +1204,7 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
> >       if (cm->mod) {
> >               vpr_cm_info(cm, "loaded classmap: %s", modnm);
> >               /* ifdef protects the cm->mod->kp deref */
> > -             for (i = 0, kp = cm->mod->kp; i < cm->mod->num_kp; i++, kp++)
> > +             for_subvec(i, kp, cm->mod, kp)
> >                       ddebug_match_apply_kparam(kp, cm, modnm);
> >       }
> >   #endif
> > @@ -1212,7 +1226,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
> >       struct ddebug_class_map *cm;
> >       int i, nc = 0;
> >
> > -     for (i = 0, cm = di->classes; i < di->num_classes; i++, cm++) {
> > +     for_subvec(i, cm, di, classes) {
> >               if (!strcmp(cm->mod_name, dt->mod_name)) {
> >                       vpr_cm_info(cm, "classes[%d]:", i);
> >                       if (!nc++)
> > @@ -1225,7 +1239,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
> >       vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
> >       dt->num_classes = nc;
> >
> > -     for (i = 0, cm = dt->classes; i < dt->num_classes; i++, cm++)
> > +     for_subvec(i, cm, dt, classes)
> >               ddebug_apply_params(cm, cm->mod_name);
> >   }
> >
> > @@ -1245,7 +1259,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
> >        * module's refs, save to dt.  For loadables, this is the
> >        * whole array.
> >        */
> > -     for (i = 0, cli = di->class_users; i < di->num_class_users; i++, cli++) {
> > +     for_subvec(i, cli, di, class_users) {
> >               if (WARN_ON_ONCE(!cli || !cli->map || !cli->mod_name))
> >                       continue;
> >               if (!strcmp(cli->mod_name, dt->mod_name)) {
> > @@ -1261,7 +1275,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
> >       dt->num_class_users = nc;
> >
> >       /* now iterate dt */
> > -     for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++)
> > +     for_subvec(i, cli, di, class_users)
> >               ddebug_apply_params(cli->map, cli->mod_name);
> >
> >       vpr_dt_info(dt, "attach-client-module: ");
> > @@ -1299,7 +1313,7 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
> >
> >       INIT_LIST_HEAD(&dt->link);
> >
> > -     for (i = 0, iter = di->descs; i < di->num_descs; i++, iter++)
> > +     for_subvec(i, iter, di, descs)
> >               if (iter->class_id != _DPRINTK_CLASS_DFLT)
> >                       class_ct++;
> >
>
> --
> Louis Chauvet, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 19/63] dyndbg: make proper substructs in _ddebug_info
  2025-02-25 14:19   ` Louis Chauvet
@ 2025-03-16 20:58     ` jim.cromie
  0 siblings, 0 replies; 103+ messages in thread
From: jim.cromie @ 2025-03-16 20:58 UTC (permalink / raw)
  To: Louis Chauvet, Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb,
	intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala

On Tue, Feb 25, 2025 at 7:19 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
>
>
>
> Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> > struct _ddebug_info's jobs is to enapsulate the __sections of dyndbg
> > data from the linker.  The data started as a single pair of fields:
> > descs - ref'g an array of descriptors & num_descs - counting the
> > "pertinent" descriptors.  Then classes & num_classes were added, and
> > _ddebug_info was invented to contain the 4 fields.
> >
> > When class_users & num_class_users were added (earlier in this
> > series), the easy path was to replicate functions and adapt them to
> > work on ddebug_class_users, instead of class_maps.  This worked, but
> > made repetitive boilerplate code, leading to (other commits with)
> > macros walking num_##{classes,class_users} to capture the repetition.
> >
> > To fix it better, create structs to contain start,len for vectors of
> > all 3 objects: classmaps, class_users, and pr_debug descriptors, and
> > adjust field-refs accordingly.
> >
> > Also recompose struct ddebug_table to contain a _ddebug_info (rather
> > than repeat the contents, as before), and adjust all array-walks to
> > use the newly contained info.
> >
> > This allows ridding the class* macros of the num##<T> paste-up, and
> > should enable further cleanups.
> >
> > NB: The __packed attribute on _ddebug_info and the 3 contained structs
> > closes the holes otherwise created by the structification (which was
> > the excuse for not doing it originally).
> >
> > TBD: see if this can precede other patches, to reduce churn
>
> Hi Jim,
>
> This could be amazing if possible!

Yup. this one now immediately follows for-subvec
it does help clean up the set.


>
> > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
>
> Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
>
> > ---
> >   include/linux/dynamic_debug.h | 29 ++++++++---
> >   kernel/module/main.c          | 18 +++----
> >   lib/dynamic_debug.c           | 93 +++++++++++++++++------------------
> >   3 files changed, 74 insertions(+), 66 deletions(-)
> >
> > diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> > index 2b0c943af330..48d76a273f68 100644
> > --- a/include/linux/dynamic_debug.h
> > +++ b/include/linux/dynamic_debug.h
> > @@ -173,15 +173,28 @@ struct ddebug_class_user {
> >               .map = &(_var),                                         \
> >       }
> >
> > -/* encapsulate linker provided built-in (or module) dyndbg data */
> > +/*
> > + * @_ddebug_info: gathers module/builtin dyndbg_* __sections together.
> > + * For builtins, it is used as a cursor, with the inner structs
> > + * marking sub-vectors of the builtin __sections in DATA.
> > + */
> > +struct _ddebug_descs {
> > +     struct _ddebug *start;
> > +     int len;
> > +} __packed;
> > +struct dd_class_maps {
> > +     struct ddebug_class_map *start;
> > +     int len;
> > +} __packed;
> > +struct dd_class_users {
> > +     struct ddebug_class_user *start;
> > +     int len;
> > +} __packed;
> >   struct _ddebug_info {
> > -     struct _ddebug *descs;
> > -     struct ddebug_class_map *classes;
> > -     struct ddebug_class_user *class_users;
> > -     unsigned int num_descs;
> > -     unsigned int num_classes;
> > -     unsigned int num_class_users;
> > -};
> > +     struct _ddebug_descs descs;
> > +     struct dd_class_maps maps;
> > +     struct dd_class_users users;
> > +} __packed;
> >
> >   struct ddebug_class_param {
> >       union {
> > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > index c394a0c6e8c6..858882a1eacd 100644
> > --- a/kernel/module/main.c
> > +++ b/kernel/module/main.c
> > @@ -2540,15 +2540,15 @@ static int find_module_sections(struct module *mod, struct load_info *info)
> >               pr_warn("%s: Ignoring obsolete parameters\n", mod->name);
> >
> >   #ifdef CONFIG_DYNAMIC_DEBUG_CORE
> > -     mod->dyndbg_info.descs = section_objs(info, "__dyndbg",
> > -                                           sizeof(*mod->dyndbg_info.descs),
> > -                                           &mod->dyndbg_info.num_descs);
> > -     mod->dyndbg_info.classes = section_objs(info, "__dyndbg_classes",
> > -                                             sizeof(*mod->dyndbg_info.classes),
> > -                                             &mod->dyndbg_info.num_classes);
> > -     mod->dyndbg_info.class_users = section_objs(info, "__dyndbg_class_users",
> > -                                                 sizeof(*mod->dyndbg_info.class_users),
> > -                                                &mod->dyndbg_info.num_class_users);
> > +     mod->dyndbg_info.descs.start = section_objs(info, "__dyndbg",
> > +                                                 sizeof(*mod->dyndbg_info.descs.start),
> > +                                                 &mod->dyndbg_info.descs.len);
> > +     mod->dyndbg_info.maps.start = section_objs(info, "__dyndbg_classes",
> > +                                                sizeof(*mod->dyndbg_info.maps.start),
> > +                                                &mod->dyndbg_info.maps.len);
> > +     mod->dyndbg_info.users.start = section_objs(info, "__dyndbg_class_users",
> > +                                                 sizeof(*mod->dyndbg_info.users.start),
> > +                                                 &mod->dyndbg_info.users.len);
> >   #endif
> >
> >       return 0;
> > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> > index 08b6e4e7489f..067db504dd1d 100644
> > --- a/lib/dynamic_debug.c
> > +++ b/lib/dynamic_debug.c
> > @@ -49,10 +49,7 @@ extern struct ddebug_class_user __stop___dyndbg_class_users[];
> >   struct ddebug_table {
> >       struct list_head link;
> >       const char *mod_name;
> > -     struct _ddebug *ddebugs;
> > -     struct ddebug_class_map *classes;
> > -     struct ddebug_class_user *class_users;
> > -     unsigned int num_ddebugs, num_classes, num_class_users;
> > +     struct _ddebug_info info;
> >   };
> >
> >   struct ddebug_query {
> > @@ -154,8 +151,8 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
> >   #define vpr_dt_info(dt_p, msg_p, ...) ({                            \
> >       struct ddebug_table const *_dt = dt_p;                          \
> >       v2pr_info(msg_p " module:%s nd:%d nc:%d nu:%d\n", ##__VA_ARGS__, \
> > -               _dt->mod_name, _dt->num_ddebugs, _dt->num_classes,    \
> > -               _dt->num_class_users);                                \
> > +               _dt->mod_name, _dt->info.descs.len, _dt->info.maps.len, \
> > +               _dt->info.users.len);                                 \
> >       })
> >
> >   /*
> > @@ -168,8 +165,8 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
> >    * @_vec: name of a sub-struct member in _box, with array-ref and length
> >    */
> >   #define for_subvec(_i, _sp, _box, _vec)                                    \
> > -     for ((_i) = 0, (_sp) = (_box)->_vec;                           \
> > -          (_i) < (_box)->num_##_vec;                                \
> > +     for ((_i) = 0, (_sp) = (_box)->_vec.start;                     \
> > +          (_i) < (_box)->_vec.len;                                  \
> >            (_i)++, (_sp)++)
> >
> >   static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *class_string)
> > @@ -178,14 +175,14 @@ static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *cl
> >       struct ddebug_class_user *cli;
> >       int i, idx;
> >
> > -     for_subvec(i, map, dt, classes) {
> > +     for_subvec(i, map, &dt->info, maps) {
> >               idx = match_string(map->class_names, map->length, class_string);
> >               if (idx >= 0) {
> >                       vpr_dt_info(dt, "good-class: %s.%s ", map->mod_name, class_string);
> >                       return idx + map->base;
> >               }
> >       }
> > -     for_subvec(i, cli, dt, class_users) {
> > +     for_subvec(i, cli, &dt->info, users) {
> >               idx = match_string(cli->map->class_names, cli->map->length, class_string);
> >               if (idx >= 0) {
> >                       vpr_dt_info(dt, "class-ref: %s -> %s.%s ",
> > @@ -229,8 +226,8 @@ static int ddebug_change(const struct ddebug_query *query, struct flag_settings
> >                       valid_class = _DPRINTK_CLASS_DFLT;
> >               }
> >
> > -             for (i = 0; i < dt->num_ddebugs; i++) {
> > -                     struct _ddebug *dp = &dt->ddebugs[i];
> > +             for (i = 0; i < dt->info.descs.len; i++) {
> > +                     struct _ddebug *dp = &dt->info.descs.start[i];
> >
> >                       /* match site against query-class */
> >                       if (dp->class_id != valid_class)
> > @@ -990,8 +987,8 @@ static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
> >       }
> >       iter->table = list_entry(ddebug_tables.next,
> >                                struct ddebug_table, link);
> > -     iter->idx = iter->table->num_ddebugs;
> > -     return &iter->table->ddebugs[--iter->idx];
> > +     iter->idx = iter->table->info.descs.len;
> > +     return &iter->table->info.descs.start[--iter->idx];
> >   }
> >
> >   /*
> > @@ -1012,10 +1009,10 @@ static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
> >               }
> >               iter->table = list_entry(iter->table->link.next,
> >                                        struct ddebug_table, link);
> > -             iter->idx = iter->table->num_ddebugs;
> > +             iter->idx = iter->table->info.descs.len;
> >               --iter->idx;
> >       }
> > -     return &iter->table->ddebugs[iter->idx];
> > +     return &iter->table->info.descs.start[iter->idx];
> >   }
> >
> >   /*
> > @@ -1064,15 +1061,15 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
> >
> >   static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp)
> >   {
> > -     struct ddebug_class_map *map = dt->classes;
> > -     struct ddebug_class_user *cli = dt->class_users;
> > +     struct ddebug_class_map *map;
> > +     struct ddebug_class_user *cli;
> >       int i;
> >
> > -     for (i = 0; i < dt->num_classes; i++, map++)
> > +     for_subvec(i, map, &dt->info, maps)
> >               if (class_in_range(dp->class_id, map))
> >                       return map->class_names[dp->class_id - map->base];
> >
> > -     for (i = 0; i < dt->num_class_users; i++, cli++)
> > +     for_subvec(i, cli, &dt->info, users)
> >               if (class_in_range(dp->class_id, cli->map))
> >                       return cli->map->class_names[dp->class_id - cli->map->base];
> >
> > @@ -1203,8 +1200,7 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
> >
> >       if (cm->mod) {
> >               vpr_cm_info(cm, "loaded classmap: %s", modnm);
> > -             /* ifdef protects the cm->mod->kp deref */
> > -             for_subvec(i, kp, cm->mod, kp)
> > +             for (i = 0, kp = cm->mod->kp; i < cm->mod->num_kp; i++, kp++)
> >                       ddebug_match_apply_kparam(kp, cm, modnm);
> >       }
> >   #endif
> > @@ -1226,20 +1222,20 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
> >       struct ddebug_class_map *cm;
> >       int i, nc = 0;
> >
> > -     for_subvec(i, cm, di, classes) {
> > +     for_subvec(i, cm, di, maps) {
> >               if (!strcmp(cm->mod_name, dt->mod_name)) {
> >                       vpr_cm_info(cm, "classes[%d]:", i);
> >                       if (!nc++)
> > -                             dt->classes = cm;
> > +                             dt->info.maps.start = cm;
> >               }
> >       }
> >       if (!nc)
> >               return;
> >
> >       vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
> > -     dt->num_classes = nc;
> > +     dt->info.maps.len = nc;
> >
> > -     for_subvec(i, cm, dt, classes)
> > +     for_subvec(i, cm, &dt->info, maps)
> >               ddebug_apply_params(cm, cm->mod_name);
> >   }
> >
> > @@ -1259,23 +1255,23 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
> >        * module's refs, save to dt.  For loadables, this is the
> >        * whole array.
> >        */
> > -     for_subvec(i, cli, di, class_users) {
> > +     for_subvec(i, cli, di, users) {
> >               if (WARN_ON_ONCE(!cli || !cli->map || !cli->mod_name))
> >                       continue;
> >               if (!strcmp(cli->mod_name, dt->mod_name)) {
> >                       vpr_cm_info(cli->map, "class_ref[%d] %s -> %s", i,
> >                                   cli->mod_name, cli->map->mod_name);
> >                       if (!nc++)
> > -                             dt->class_users = cli;
> > +                             dt->info.users.start = cli;
> >               }
> >       }
> >       if (!nc)
> >               return;
> >
> > -     dt->num_class_users = nc;
> > +     dt->info.users.len = nc;
> >
> >       /* now iterate dt */
> > -     for_subvec(i, cli, di, class_users)
> > +     for_subvec(i, cli, di, users)
> >               ddebug_apply_params(cli->map, cli->mod_name);
> >
> >       vpr_dt_info(dt, "attach-client-module: ");
> > @@ -1291,10 +1287,10 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
> >       struct _ddebug *iter;
> >       int i, class_ct = 0;
> >
> > -     if (!di->num_descs)
> > +     if (!di->descs.len)
> >               return 0;
> >
> > -     v3pr_info("add-module: %s %d sites\n", modname, di->num_descs);
> > +     v3pr_info("add-module: %s %d sites\n", modname, di->descs.len);
> >
> >       dt = kzalloc(sizeof(*dt), GFP_KERNEL);
> >       if (dt == NULL) {
> > @@ -1308,8 +1304,7 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
> >        * this struct ddebug_table.
> >        */
> >       dt->mod_name = modname;
> > -     dt->ddebugs = di->descs;
> > -     dt->num_ddebugs = di->num_descs;
> > +     dt->info.descs = di->descs;
> >
> >       INIT_LIST_HEAD(&dt->link);
> >
> > @@ -1317,17 +1312,17 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
> >               if (iter->class_id != _DPRINTK_CLASS_DFLT)
> >                       class_ct++;
> >
> > -     if (class_ct && di->num_classes)
> > +     if (class_ct && di->maps.len)
> >               ddebug_attach_module_classes(dt, di);
> >
> >       mutex_lock(&ddebug_lock);
> >       list_add_tail(&dt->link, &ddebug_tables);
> >       mutex_unlock(&ddebug_lock);
> >
> > -     if (class_ct && di->num_class_users)
> > +     if (class_ct && di->users.len)
> >               ddebug_attach_user_module_classes(dt, di);
> >
> > -     vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
> > +     vpr_info("%3u debug prints in module %s\n", di->descs.len, modname);
> >       return 0;
> >   }
> >
> > @@ -1474,12 +1469,12 @@ static int __init dynamic_debug_init(void)
> >       char *cmdline;
> >
> >       struct _ddebug_info di = {
> > -             .descs = __start___dyndbg,
> > -             .classes = __start___dyndbg_classes,
> > -             .class_users = __start___dyndbg_class_users,
> > -             .num_descs = __stop___dyndbg - __start___dyndbg,
> > -             .num_classes = __stop___dyndbg_classes - __start___dyndbg_classes,
> > -             .num_class_users = __stop___dyndbg_class_users - __start___dyndbg_class_users,
> > +             .descs.start = __start___dyndbg,
> > +             .maps.start = __start___dyndbg_classes,
> > +             .users.start = __start___dyndbg_class_users,
> > +             .descs.len = __stop___dyndbg - __start___dyndbg,
> > +             .maps.len = __stop___dyndbg_classes - __start___dyndbg_classes,
> > +             .users.len = __stop___dyndbg_class_users - __start___dyndbg_class_users,
> >       };
> >
> >   #ifdef CONFIG_MODULES
> > @@ -1508,8 +1503,8 @@ static int __init dynamic_debug_init(void)
> >
> >               if (strcmp(modname, iter->modname)) {
> >                       mod_ct++;
> > -                     di.num_descs = mod_sites;
> > -                     di.descs = iter_mod_start;
> > +                     di.descs.len = mod_sites;
> > +                     di.descs.start = iter_mod_start;
> >                       ret = ddebug_add_module(&di, modname);
> >                       if (ret)
> >                               goto out_err;
> > @@ -1519,8 +1514,8 @@ static int __init dynamic_debug_init(void)
> >                       iter_mod_start = iter;
> >               }
> >       }
> > -     di.num_descs = mod_sites;
> > -     di.descs = iter_mod_start;
> > +     di.descs.len = mod_sites;
> > +     di.descs.start = iter_mod_start;
> >       ret = ddebug_add_module(&di, modname);
> >       if (ret)
> >               goto out_err;
> > @@ -1530,8 +1525,8 @@ static int __init dynamic_debug_init(void)
> >                i, mod_ct, (int)((mod_ct * sizeof(struct ddebug_table)) >> 10),
> >                (int)((i * sizeof(struct _ddebug)) >> 10));
> >
> > -     if (di.num_classes)
> > -             v2pr_info("  %d builtin ddebug class-maps\n", di.num_classes);
> > +     if (di.maps.len)
> > +             v2pr_info("  %d builtin ddebug class-maps\n", di.maps.len);
> >
> >       /* now that ddebug tables are loaded, process all boot args
> >        * again to find and activate queries given in dyndbg params.
>
> --
> Louis Chauvet, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 21/63] dyndbg: allow ddebug_add_module to fail
  2025-02-25 14:26   ` Louis Chauvet
@ 2025-03-16 21:04     ` jim.cromie
  0 siblings, 0 replies; 103+ messages in thread
From: jim.cromie @ 2025-03-16 21:04 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb,
	intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala

On Tue, Feb 25, 2025 at 7:26 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
>
>
>
> Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> > To prep for failing modprobe on classid conflicts, upgrade the
> > call-chain around ddebug_add_module(), in 2 ways:
> >
> > 1. in ddebug_add_module() add local reserved_ids to accumulate
> > reservations, pass it by ref to ddebug_attach_{,user_}module_classes()
> > so they can examine the reservations as they work.
> >
> > 2. return int from both ddebug_attach_{,user_}module_classes(), up to
> > ddebug_add_module(), then to ddebug_module_notify().
> >
> > No conflicts are currently detected or returned.
> >
> > TBD: This is updated further by hoisting the reservation-check, which
> > obsoletes part of 2, creating churn, maybe squash it away.
>

this now done locally as
05b0eed12dcc dyndbg: hoist classmap-filter-by-modname up to ddebug_add_module
sha will change yet..

Though Ive dropped the fail-on-modprobe,
I didn't want to open up another failure mode

Some WARN or pr_error should suffice for now.


> Hi Jim,
>
> It could be very nice to squash when possible yes!
>
> > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
>
> Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
>
> > ---
> >   lib/dynamic_debug.c | 40 +++++++++++++++++++++++++++++-----------
> >   1 file changed, 29 insertions(+), 11 deletions(-)
> >
> > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> > index 16c9b752822b..0ef243e30663 100644
> > --- a/lib/dynamic_debug.c
> > +++ b/lib/dynamic_debug.c
> > @@ -1216,8 +1216,9 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
> >    * modular classmap vector/section.  Save the start and length of the
> >    * subrange at its edges.
> >    */
> > -static void ddebug_attach_module_classes(struct ddebug_table *dt,
> > -                                      const struct _ddebug_info *di)
> > +static int ddebug_attach_module_classes(struct ddebug_table *dt,
> > +                                     const struct _ddebug_info *di,
> > +                                     u64 *reserved_ids)
> >   {
> >       struct ddebug_class_map *cm;
> >       int i, nc = 0;
> > @@ -1230,13 +1231,14 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
> >               }
> >       }
> >       if (!nc)
> > -             return;
> > +             return 0;
> >
> >       vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
> >       dt->info.maps.len = nc;
> >
> >       for_subvec(i, cm, &dt->info, maps)
> >               ddebug_apply_params(cm, cm->mod_name);
> > +     return 0;
> >   }
> >
> >   /*
> > @@ -1244,8 +1246,9 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
> >    * means a query against the dt/module, which means it must be on the
> >    * list to be seen by ddebug_change.
> >    */
> > -static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
> > -                                           const struct _ddebug_info *di)
> > +static int ddebug_attach_user_module_classes(struct ddebug_table *dt,
> > +                                           const struct _ddebug_info *di,
> > +                                           u64 *reserved_ids)
> >   {
> >       struct ddebug_class_user *cli;
> >       int i, nc = 0;
> > @@ -1266,7 +1269,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
> >               }
> >       }
> >       if (!nc)
> > -             return;
> > +             return 0;
> >
> >       dt->info.users.len = nc;
> >
> > @@ -1275,6 +1278,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
> >               ddebug_apply_params(cli->map, cli->mod_name);
> >
> >       vpr_dt_info(dt, "attach-client-module: ");
> > +     return 0;
> >   }
> >
> >   /*
> > @@ -1284,6 +1288,8 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
> >   static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
> >   {
> >       struct ddebug_table *dt;
> > +     u64 reserved_ids = 0;
> > +     int rc;
> >
> >       if (!di->descs.len)
> >               return 0;
> > @@ -1306,16 +1312,23 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
> >
> >       INIT_LIST_HEAD(&dt->link);
> >
> > -     if (di->maps.len)
> > -             ddebug_attach_module_classes(dt, di);
> > -
> > +     if (di->maps.len) {
> > +             rc = ddebug_attach_module_classes(dt, di, &reserved_ids);
> > +             if (rc) {
> > +                     kfree(dt);
> > +                     return rc;
> > +             }
> > +     }
> >       mutex_lock(&ddebug_lock);
> >       list_add_tail(&dt->link, &ddebug_tables);
> >       mutex_unlock(&ddebug_lock);
> >
> > -     if (di->users.len)
> > -             ddebug_attach_user_module_classes(dt, di);
> >
> > +     if (di->users.len) {
> > +             rc = ddebug_attach_user_module_classes(dt, di, &reserved_ids);
> > +             if (rc)
> > +                     return rc;
> > +     }
> >       vpr_info("%3u debug prints in module %s\n", di->descs.len, modname);
> >       return 0;
> >   }
> > @@ -1400,6 +1413,11 @@ static int ddebug_module_notify(struct notifier_block *self, unsigned long val,
> >       switch (val) {
> >       case MODULE_STATE_COMING:
> >               ret = ddebug_add_module(&mod->dyndbg_info, mod->name);
> > +             if (ret == -EINVAL) {
> > +                     pr_err("conflicting dyndbg-classmap reservations\n");
> > +                     ddebug_remove_module(mod->name);
> > +                     break;
> > +             }
> >               if (ret)
> >                       WARN(1, "Failed to allocate memory: dyndbg may not work properly.\n");
> >               break;
>
> --
> Louis Chauvet, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 23/63] dyndbg: fail modprobe on ddebug_class_range_overlap()
  2025-02-25 14:27   ` Louis Chauvet
@ 2025-03-16 21:07     ` jim.cromie
  0 siblings, 0 replies; 103+ messages in thread
From: jim.cromie @ 2025-03-16 21:07 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb,
	intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala

Im dropping the fail-on-modprobe.

theres some unrelated test-mod touches I'll examine and separate if theyre good

On Tue, Feb 25, 2025 at 7:27 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
>
>
>
> Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> > 1. All classes used by a module (declared DYNDBG_CLASSMAP_{DEFINE,USE}
> > by module code) must share 0..62 class-id space; ie their respective
> > base,+length reservations shouldn't overlap.  Overlaps would lead to
> > unintended changes in ddebug enablements.
> >
> > Detecting these class-id range overlaps at compile-time would be ideal
> > but is not obvious how; failing at modprobe at least insures that the
> > developer sees and fixes the conflict.
> >
> > ddebug_class_range_overlap() implements the range check, accumulating
> > the reserved-ids as it examines each class.  It probably should use
> > bitmaps.
> >
> > A previous commit reworked the modprobe callchain to allow failure,
> > now call ddebug_class_range_overlap() to check when classid conflicts
> > happen, and signal that failure.
> >
> > NB: this can only happen when a module defines+uses several classmaps,
> >
> > TBD: failing modprobe is kinda harsh, maybe warn and proceed ?
> >
> > test_dynamic_debug*.ko:
> >
> > If built with -DFORCE_CLASSID_CONFLICT_MODPROBE, the modules get 2 bad
> > DYNDBG_CLASS_DEFINE declarations, into parent and the _submod.  These
> > conflict with one of the good ones in the parent (D2_CORE..etc),
> > causing the modprobe(s) to fail.  TODO: do in submod only, since fail
> > of parent prevents submod from ever trying.
> >
> > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> > ---
> > ---
> >   lib/dynamic_debug.c      | 30 ++++++++++++++++++++++++------
> >   lib/test_dynamic_debug.c | 11 ++++++++++-
> >   2 files changed, 34 insertions(+), 7 deletions(-)
> >
> > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> > index 8afcd4111531..8e1e087e07c3 100644
> > --- a/lib/dynamic_debug.c
> > +++ b/lib/dynamic_debug.c
> > @@ -1211,6 +1211,21 @@ static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *m
> >       }
> >   }
> >
> > +static int ddebug_class_range_overlap(struct ddebug_class_map *cm,
> > +                                   u64 *reserved_ids)
> > +{
> > +     u64 range = (((1ULL << cm->length) - 1) << cm->base);
> > +
> > +     if (range & *reserved_ids) {
> > +             pr_err("[%d..%d] on %s conflicts with %llx\n", cm->base,
> > +                    cm->base + cm->length - 1, cm->class_names[0],
> > +                    *reserved_ids);
> > +             return -EINVAL;
> > +     }
> > +     *reserved_ids |= range;
> > +     return 0;
> > +}
> > +
> >   /*
> >    * scan the named array: @_vec, ref'd from inside @_box, for the
> >    * start,len of the sub-array of elements matching on ->mod_name;
> > @@ -1242,9 +1257,11 @@ static int ddebug_module_apply_class_maps(struct ddebug_table *dt,
> >       struct ddebug_class_map *cm;
> >       int i;
> >
> > -     for_subvec(i, cm, &dt->info, maps)
> > +     for_subvec(i, cm, &dt->info, maps) {
> > +             if (ddebug_class_range_overlap(cm, reserved_ids))
> > +                     return -EINVAL;
> >               ddebug_apply_params(cm, cm->mod_name);
> > -
> > +     }
> >       vpr_info("module:%s attached %d classmaps\n", dt->mod_name, dt->info.maps.len);
> >       return 0;
> >   }
> > @@ -1255,10 +1272,11 @@ static int ddebug_module_apply_class_users(struct ddebug_table *dt,
> >       struct ddebug_class_user *cli;
> >       int i;
> >
> > -     /* now iterate dt */
> > -     for_subvec(i, cli, &dt->info, users)
> > +     for_subvec(i, cli, &dt->info, users) {
> > +             if (ddebug_class_range_overlap(cli->map, reserved_ids))
> > +                     return -EINVAL;
> >               ddebug_apply_params(cli->map, cli->mod_name);
> > -
> > +     }
> >       vpr_info("module:%s attached %d classmap uses\n", dt->mod_name, dt->info.users.len);
> >       return 0;
> >   }
> > @@ -1311,11 +1329,11 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
> >                       return rc;
> >               }
> >       }
> > +
> >       mutex_lock(&ddebug_lock);
> >       list_add_tail(&dt->link, &ddebug_tables);
> >       mutex_unlock(&ddebug_lock);
> >
> > -
>
> Hi Jim,
>
> Strange line issues, can you squash it with the correct patch?
>
> Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
>
> Thanks,
>
> >       if (dt->info.users.len) {
> >               rc = ddebug_module_apply_class_users(dt, &reserved_ids);
> >               if (rc)
> > diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
> > index b1555b0a2bb1..74b98adc4ed0 100644
> > --- a/lib/test_dynamic_debug.c
> > +++ b/lib/test_dynamic_debug.c
> > @@ -81,7 +81,7 @@ enum cat_disjoint_bits {
> >       D2_DRMRES };
> >
> >   /* numeric verbosity, V2 > V1 related */
> > -enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
> > +enum cat_level_num { V0 = 16, V1, V2, V3, V4, V5, V6, V7 };
> >
> >   /* recapitulate DRM's parent(drm.ko) <-- _submod(drivers,helpers) */
> >   #if !defined(TEST_DYNAMIC_DEBUG_SUBMOD)
> > @@ -90,6 +90,7 @@ enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
> >    * classmaps on the client enums above, and then declares the PARAMS
> >    * ref'g the classmaps.  Each is exported.
> >    */
> > +
> >   DYNDBG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS,
> >                      D2_CORE,
> >                      "D2_CORE",
> > @@ -113,6 +114,14 @@ DYNDBG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
> >   DYNDBG_CLASSMAP_PARAM(disjoint_bits, p);
> >   DYNDBG_CLASSMAP_PARAM(level_num, p);
> >
> > +#ifdef FORCE_CLASSID_CONFLICT_MODPROBE
> > +/*
> > + * Enable with -Dflag on compile to test overlapping class-id range
> > + * detection.  This should break on modprobe.
> > + */
> > +DYNDBG_CLASSMAP_DEFINE(classid_range_conflict, 0, D2_CORE + 1, "D3_CORE");
> > +#endif
> > +
> >   #else /* TEST_DYNAMIC_DEBUG_SUBMOD */
> >
> >   /*
>
> --
> Louis Chauvet, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 28/63] dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API
  2025-02-25 14:29   ` Louis Chauvet
@ 2025-03-16 21:14     ` jim.cromie
  2025-03-24 22:58       ` jim.cromie
  0 siblings, 1 reply; 103+ messages in thread
From: jim.cromie @ 2025-03-16 21:14 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb,
	intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala

On Tue, Feb 25, 2025 at 7:29 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
>
>
>
> Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> > move the DYNDBG_CLASSMAP_PARAM macro from test-dynamic-debug.c into
> > the header, and refine it, by distinguishing the 2 use cases:
> >
> > 1.DYNDBG_CLASSMAP_PARAM_REF
> >      for DRM, to pass in extern __drm_debug by name.
> >      dyndbg keeps bits in it, so drm can still use it as before
> >
> > 2.DYNDBG_CLASSMAP_PARAM
> >      new user (test_dynamic_debug) doesn't need to share state,
> >      decls a static long unsigned int to store the bitvec.
> >
> > __DYNDBG_CLASSMAP_PARAM
> >     bottom layer - allocate,init a ddebug-class-param, module-param-cb.
> >
> > Modify ddebug_sync_classbits() argtype deref inside the fn, to give
> > access to all kp members.
> >
> > Also clean up and improve comments in test-code, and add
> > MODULE_DESCRIPTIONs.
> >
> > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> > ---
> >
> > -v9
> >   - fixup drm-print.h  add PARAM_REF forwarding macros
> >     with DYNDBG_CLASSMAP_PARAM_REF in the API, add DRM_ variant
> > ---
> >   include/linux/dynamic_debug.h   | 38 +++++++++++++++++++++
> >   lib/dynamic_debug.c             | 60 ++++++++++++++++++++++-----------
> >   lib/test_dynamic_debug.c        | 59 +++++++++++++-------------------
> >   lib/test_dynamic_debug_submod.c |  9 ++++-
> >   4 files changed, 111 insertions(+), 55 deletions(-)
> >
> > diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> > index 48d76a273f68..b47d1088b7ad 100644
> > --- a/include/linux/dynamic_debug.h
> > +++ b/include/linux/dynamic_debug.h
> > @@ -205,6 +205,44 @@ struct ddebug_class_param {
> >       const struct ddebug_class_map *map;
> >   };
> >
> > +/**
> > + * DYNDBG_CLASSMAP_PARAM - control a ddebug-classmap from a sys-param
> > + * @_name:  sysfs node name
> > + * @_var:   name of the classmap var defining the controlled classes/bits
> > + * @_flags: flags to be toggled, typically just 'p'
> > + *
> > + * Creates a sysfs-param to control the classes defined by the
> > + * exported classmap, with bits 0..N-1 mapped to the classes named.
> > + * This version keeps class-state in a private long int.
> > + */
> > +#define DYNDBG_CLASSMAP_PARAM(_name, _var, _flags)                   \
> > +     static unsigned long _name##_bvec;                              \
> > +     __DYNDBG_CLASSMAP_PARAM(_name, _name##_bvec, _var, _flags)
> > +
> > +/**
> > + * DYNDBG_CLASSMAP_PARAM_REF - wrap a classmap with a controlling sys-param
> > + * @_name:  sysfs node name
> > + * @_bits:  name of the module's unsigned long bit-vector, ex: __drm_debug
> > + * @_var:   name of the (exported) classmap var defining the classes/bits
> > + * @_flags: flags to be toggled, typically just 'p'
> > + *
> > + * Creates a sysfs-param to control the classes defined by the
> > + * exported clasmap, with bits 0..N-1 mapped to the classes named.
> > + * This version keeps class-state in user @_bits.  This lets drm check
> > + * __drm_debug elsewhere too.
> > + */
> > +#define DYNDBG_CLASSMAP_PARAM_REF(_name, _bits, _var, _flags)                \
> > +     __DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags)
> > +
> > +#define __DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags)          \
> > +     static struct ddebug_class_param _name##_##_flags = {           \
> > +             .bits = &(_bits),                                       \
> > +             .flags = #_flags,                                       \
> > +             .map = &(_var),                                         \
> > +     };                                                              \
> > +     module_param_cb(_name, &param_ops_dyndbg_classes,               \
> > +                     &_name##_##_flags, 0600)
> > +
> >   /*
> >    * pr_debug() and friends are globally enabled or modules have selectively
> >    * enabled them.
> > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> > index 781781835094..9283f2866415 100644
> > --- a/lib/dynamic_debug.c
> > +++ b/lib/dynamic_debug.c
> > @@ -660,6 +660,30 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
> >
> >   #define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1)
> >
> > +static void ddebug_class_param_clamp_input(unsigned long *inrep, const struct kernel_param *kp)
> > +{
> > +     const struct ddebug_class_param *dcp = kp->arg;
> > +     const struct ddebug_class_map *map = dcp->map;
> > +
> > +     switch (map->map_type) {
> > +     case DD_CLASS_TYPE_DISJOINT_BITS:
> > +             /* expect bits. mask and warn if too many */
> > +             if (*inrep & ~CLASSMAP_BITMASK(map->length)) {
> > +                     pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
> > +                             KP_NAME(kp), *inrep, CLASSMAP_BITMASK(map->length));
> > +                     *inrep &= CLASSMAP_BITMASK(map->length);
> > +             }
> > +             break;
> > +     case DD_CLASS_TYPE_LEVEL_NUM:
> > +             /* input is bitpos, of highest verbosity to be enabled */
> > +             if (*inrep > map->length) {
> > +                     pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
> > +                             KP_NAME(kp), *inrep, map->length);
> > +                     *inrep = map->length;
> > +             }
> > +             break;
> > +     }
> > +}
> >   static int param_set_dyndbg_module_classes(const char *instr,
> >                                          const struct kernel_param *kp,
> >                                          const char *modnm)
> > @@ -678,26 +702,15 @@ static int param_set_dyndbg_module_classes(const char *instr,
> >               pr_err("expecting numeric input, not: %s > %s\n", instr, KP_NAME(kp));
> >               return -EINVAL;
> >       }
> > +     ddebug_class_param_clamp_input(&inrep, kp);
> >
> >       switch (map->map_type) {
> >       case DD_CLASS_TYPE_DISJOINT_BITS:
> > -             /* expect bits. mask and warn if too many */
> > -             if (inrep & ~CLASSMAP_BITMASK(map->length)) {
> > -                     pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
> > -                             KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length));
> > -                     inrep &= CLASSMAP_BITMASK(map->length);
> > -             }
> >               v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp));
> >               totct += ddebug_apply_class_bitmap(dcp, &inrep, *dcp->bits, modnm);
> >               *dcp->bits = inrep;
> >               break;
> >       case DD_CLASS_TYPE_LEVEL_NUM:
> > -             /* input is bitpos, of highest verbosity to be enabled */
> > -             if (inrep > map->length) {
> > -                     pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
> > -                             KP_NAME(kp), inrep, map->length);
> > -                     inrep = map->length;
> > -             }
> >               old_bits = CLASSMAP_BITMASK(*dcp->lvl);
> >               new_bits = CLASSMAP_BITMASK(inrep);
> >               v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
> > @@ -1163,15 +1176,24 @@ static const struct proc_ops proc_fops = {
> >   static void ddebug_sync_classbits(const struct kernel_param *kp, const char *modname)
> >   {
> >       const struct ddebug_class_param *dcp = kp->arg;
> > +     unsigned long new_bits;
> >
> > -     /* clamp initial bitvec, mask off hi-bits */
> > -     if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) {
> > -             *dcp->bits &= CLASSMAP_BITMASK(dcp->map->length);
> > -             v2pr_info("preset classbits: %lx\n", *dcp->bits);
> > +     ddebug_class_param_clamp_input(dcp->bits, kp);
> > +
> > +     switch (dcp->map->map_type) {
> > +     case DD_CLASS_TYPE_DISJOINT_BITS:
> > +             v2pr_info("  %s: classbits: 0x%lx\n", KP_NAME(kp), *dcp->bits);
> > +             ddebug_apply_class_bitmap(dcp, dcp->bits, 0UL, modname);
> > +             break;
> > +     case DD_CLASS_TYPE_LEVEL_NUM:
> > +             new_bits = CLASSMAP_BITMASK(*dcp->lvl);
> > +             v2pr_info("  %s: lvl:%ld bits:0x%lx\n", KP_NAME(kp), *dcp->lvl, new_bits);
> > +             ddebug_apply_class_bitmap(dcp, &new_bits, 0UL, modname);
> > +             break;
> > +     default:
> > +             pr_err("bad map type %d\n", dcp->map->map_type);
> > +             return;
> >       }
> > -     /* force class'd prdbgs (in USEr module) to match (DEFINEr module) class-param */
> > -     ddebug_apply_class_bitmap(dcp, dcp->bits, ~0, modname);
> > -     ddebug_apply_class_bitmap(dcp, dcp->bits, 0, modname);
>
> Hi Jim,
>
> We lost the double call with ~0/0, is it normal?

Good catch,

I thought so, since it guarantees the pr_debugs' state to
comport with sysfs settings on modprobe.

I will review.

>
> Thanks a lot for your work,
> Louis Chauvet
>
> >   }
> >
> >   static void ddebug_match_apply_kparam(const struct kernel_param *kp,
> > diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
> > index 5cfc156ca4bb..32a9d49a7a3b 100644
> > --- a/lib/test_dynamic_debug.c
> > +++ b/lib/test_dynamic_debug.c
> > @@ -1,6 +1,7 @@
> >   // SPDX-License-Identifier: GPL-2.0-only
> >   /*
> > - * Kernel module for testing dynamic_debug
> > + * Kernel module to test/demonstrate dynamic_debug features,
> > + * particularly classmaps and their support for subsystems like DRM.
> >    *
> >    * Authors:
> >    *      Jim Cromie  <jim.cromie@gmail.com>
> > @@ -43,36 +44,21 @@ module_param_cb(do_prints, &param_ops_do_prints, NULL, 0600);
> >
> >   #define CLASSMAP_BITMASK(width, base) (((1UL << (width)) - 1) << (base))
> >
> > -/* sysfs param wrapper, proto-API */
> > -#define DYNDBG_CLASSMAP_PARAM_(_model, _flags, _init)                        \
> > -     static unsigned long bits_##_model = _init;                     \
> > -     static struct ddebug_class_param _flags##_##_model = {          \
> > -             .bits = &bits_##_model,                                 \
> > -             .flags = #_flags,                                       \
> > -             .map = &map_##_model,                                   \
> > -     };                                                              \
> > -     module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes,   \
> > -                     &_flags##_##_model, 0600)
> > -#ifdef DEBUG
> > -#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, ~0)
> > -#else
> > -#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, 0)
> > -#endif
> > -
> >   /*
> > - * Demonstrate/test all 4 class-typed classmaps with a sys-param.
> > + * Demonstrate/test both types of classmaps, each with a sys-param.
> >    *
> >    * Each is 3 part: client-enum decl, _DEFINE, _PARAM.
> > - * Declare them in blocks to show patterns of use (repetitions and
> > - * changes) within each.
> > + * Pair the 6 parts by type, to show the pattern of repetition and
> > + * change within each.
> >    *
> > - * 1st, dyndbg expects a client-provided enum-type as source of
> > - * category/classid truth.  DRM has DRM_UT_<CORE,DRIVER,KMS,etc>.
> > + * 1st, dyndbg classmaps follows drm.debug convention, and expects a
> > + * client-provided enum-type as source of category/classid truth.  DRM
> > + * gives DRM_UT_<CORE,DRIVER,KMS,etc>.
> >    *
> >    * Modules with multiple CLASSMAPS must have enums with distinct
> >    * value-ranges, arranged below with explicit enum_sym = X inits.
> >    *
> > - * Declare all 4 enums now, for different types
> > + * Declare the 2 enums now.
> >    */
> >
> >   /* numeric input, independent bits */
> > @@ -91,12 +77,15 @@ enum cat_disjoint_bits {
> >   /* numeric verbosity, V2 > V1 related */
> >   enum cat_level_num { V0 = 16, V1, V2, V3, V4, V5, V6, V7 };
> >
> > -/* recapitulate DRM's parent(drm.ko) <-- _submod(drivers,helpers) */
> > +/*
> > + * use/demonstrate multi-module-group classmaps, as for DRM
> > + */
> >   #if !defined(TEST_DYNAMIC_DEBUG_SUBMOD)
> >   /*
> > - * In single user, or parent / coordinator (drm.ko) modules, define
> > - * classmaps on the client enums above, and then declares the PARAMS
> > - * ref'g the classmaps.  Each is exported.
> > + * For module-groups of 1+, define classmaps with names (stringified
> > + * enum-symbols) copied from above. 1-to-1 mapping is recommended.
> > + * The classmap is exported, so that other modules in the group can
> > + * link to it and control their prdbgs.
> >    */
> >
> >   DYNDBG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS,
> > @@ -116,11 +105,12 @@ DYNDBG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
> >                      V0, "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
> >
> >   /*
> > - * now add the sysfs-params
> > + * for use-cases that want it, provide a sysfs-param to set the
> > + * classes in the classmap.  It is at this interface where the
> > + * "v3>v2" property is applied to DD_CLASS_TYPE_LEVEL_NUM inputs.
> >    */
> > -
> > -DYNDBG_CLASSMAP_PARAM(disjoint_bits, p);
> > -DYNDBG_CLASSMAP_PARAM(level_num, p);
> > +DYNDBG_CLASSMAP_PARAM(p_disjoint_bits,       map_disjoint_bits, p);
> > +DYNDBG_CLASSMAP_PARAM(p_level_num,   map_level_num, p);
> >
> >   #ifdef FORCE_CLASSID_CONFLICT_MODPROBE
> >   /*
> > @@ -131,12 +121,10 @@ DYNDBG_CLASSMAP_DEFINE(classid_range_conflict, 0, D2_CORE + 1, "D3_CORE");
> >   #endif
> >
> >   #else /* TEST_DYNAMIC_DEBUG_SUBMOD */
> > -
> >   /*
> > - * in submod/drm-drivers, use the classmaps defined in top/parent
> > - * module above.
> > + * the +1 members of a multi-module group refer to the classmap
> > + * DEFINEd (and exported) above.
> >    */
> > -
> >   DYNDBG_CLASSMAP_USE(map_disjoint_bits);
> >   DYNDBG_CLASSMAP_USE(map_level_num);
> >
> > @@ -211,6 +199,7 @@ static void __exit test_dynamic_debug_exit(void)
> >   module_init(test_dynamic_debug_init);
> >   module_exit(test_dynamic_debug_exit);
> >
> > +MODULE_DESCRIPTION("test/demonstrate dynamic-debug features");
> >   MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
> >   MODULE_DESCRIPTION("Kernel module for testing dynamic_debug");
> >   MODULE_LICENSE("GPL");
> > diff --git a/lib/test_dynamic_debug_submod.c b/lib/test_dynamic_debug_submod.c
> > index 9a893402ce1a..0d15f3ffe466 100644
> > --- a/lib/test_dynamic_debug_submod.c
> > +++ b/lib/test_dynamic_debug_submod.c
> > @@ -1,6 +1,9 @@
> >   // SPDX-License-Identifier: GPL-2.0
> >   /*
> > - * Kernel module for testing dynamic_debug
> > + * Kernel module to test/demonstrate dynamic_debug features,
> > + * particularly classmaps and their support for subsystems, like DRM,
> > + * which defines its drm_debug classmap in drm module, and uses it in
> > + * helpers & drivers.
> >    *
> >    * Authors:
> >    *      Jim Cromie  <jim.cromie@gmail.com>
> > @@ -8,3 +11,7 @@
> >
> >   #define TEST_DYNAMIC_DEBUG_SUBMOD
> >   #include "test_dynamic_debug.c"
> > +
> > +MODULE_DESCRIPTION("test/demonstrate dynamic-debug subsystem support");
> > +MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
> > +MODULE_LICENSE("GPL");
>
> --
> Louis Chauvet, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 16/63] dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP
  2025-03-16 19:46     ` jim.cromie
@ 2025-03-24 15:07       ` Louis Chauvet
  2025-03-25 16:03         ` jim.cromie
  0 siblings, 1 reply; 103+ messages in thread
From: Louis Chauvet @ 2025-03-24 15:07 UTC (permalink / raw)
  To: jim.cromie, linux-kernel, jbaron, gregkh, ukaszb,
	intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala



Le 16/03/2025 à 20:46, jim.cromie@gmail.com a écrit :
> hi Louis,
> 
> On Tue, Feb 25, 2025 at 7:16 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
>>
>>
>>
>> Le 25/01/2025 à 07:45, Jim Cromie a écrit :
>>> DECLARE_DYNDBG_CLASSMAP() has a design error; its usage fails a basic
>>> K&R rule: "define once, refer many times".
>>>
>>> It is used across DRM core & drivers, each use re-defines the classmap
>>> understood by that module; and all must match for the modules to
>>> respond together when DRM.debug categories are enabled.  This is
>>> brittle; a maintenance foot-gun.
>>>
>>> Further, its culpable in the CONFIG_DRM_USE_DYNAMIC_DEBUG=Y
>>> regression; its use in both core & drivers obfuscates the 2 roles.
>>> So 1st drm.ko loads, and dyndbg initializes its DRM.debug callsites,
>>> then a drm-driver loads, but too late - it missed the DRM.debug
>>> enablement.
>>>
>>> So replace it with 2 macros:
>>>     DYNDBG_CLASSMAP_DEFINE - invoked once from core - drm.ko
>>>     DYNDBG_CLASSMAP_USE    - from all drm drivers and helpers.
>>>
>>> DYNDBG_CLASSMAP_DEFINE: it just modifies DECLARE_DYNDBG_CLASSMAP,
>>> dropping drop the static qualifier, and exports it instead.
>>>
>>> DYNDBG_CLASSMAP_USE: then refers to the exported var by name:
>>>     used from drivers, helper-mods
>>>     lets us drop the repetitive "classname" declarations
>>>     fixes 2nd-defn problem
>>>     creates a ddebug_class_user record in new __dyndbg_class_users section
>>>     this allows ddebug_add_module(etal) to handle users differently.
>>>
>>> DECLARE_DYNDBG_CLASSMAP is preserved temporarily, to decouple DRM
>>> adaptation work and avoid compile-errs before its done.  IOW, DRM gets
>>> fixed when they commit the adopt-new-api patches, and remove the
>>> BROKEN marking.
>>>
>>> The DEFINE,USE distinction, and the separate classmap-use record,
>>> allows dyndbg to initialize the driver's & helper's DRM.debug
>>> callsites separately after each is modprobed.
>>>
>>> Basically, the classmap init-scan is repeated for classmap-users.
>>>
>>> To review, dyndbg's existing __dyndbg_classes[] section does:
>>>
>>> . catalogs the classmaps defined by a module (or builtin modules)
>>> . tells dyndbg the module has class'd prdbgs, allowing >control
>>> . DYNDBG_CLASSMAP_DEFINE creates classmaps in this section.
>>>
>>> This patch adds __dyndbg_class_users[] section:
>>>
>>> . catalogs uses/references to the classmap definitions.
>>> . authorizes dyndbg to >control those class'd prdbgs in ref'g module.
>>> . DYNDBG_CLASSMAP_USE() creates classmap-user records in this new section.
>>>
>>> Now ddebug_add_module(etal) can handle classmap-uses similar to (and
>>> after) classmaps; when a dependent module is loaded, if it has
>>> classmap-uses (to a classmap-def in another module), that module's
>>> kernel params are scanned to find if it has a kparam that is wired to
>>> dyndbg's param-ops, and whose classmap is the one being ref'd.
>>>
>>> To support this, theres a few data/header changes:
>>>
>>> new struct ddebug_class_user
>>>     contains: user-module-name, &classmap-defn
>>>     it records drm-driver's use of a classmap in the section, allowing lookup
>>>
>>> struct ddebug_info gets 2 new fields for the new sections:
>>>     class_users, num_class_users.
>>>     set by dynamic_debug_init() for builtins.
>>>     or by kernel/module/main:load_info() for loadable modules.
>>>
>>> vmlinux.lds.h: new BOUNDED_SECTION for __dyndbg_class_users
>>>
>>> dynamic_debug.c has 2 changes in ddebug_add_module(), ddebug_change():
>>>
>>> ddebug_add_module() already calls ddebug_attach_module_classes()
>>> to handle classmaps DEFINEd by a module, now it also calls
>>> ddebug_attach_user_module_classes() to handle USEd classmaps.  To
>>> avoid this work when possible, 1st scan the module's descriptors and
>>> count the number of class'd pr_debugs.
>>>
>>> ddebug_attach_user_module_classes() scans the module's class_users
>>> section, follows the refs to the parent's classmap, and calls
>>> ddebug_apply_params() on each.  It also avoids work by checking the
>>> module's class-ct.
>>>
>>> ddebug_apply_params(new fn):
>>>
>>> It scans module's/builtin kernel-params, calls ddebug_match_apply_kparam
>>> for each to find any params/sysfs-nodes which may be wired to a classmap.
>>>
>>> ddebug_match_apply_kparam(new fn):
>>>
>>> 1st, it tests the kernel-param.ops is dyndbg's; this guarantees that
>>> the attached arg is a struct ddebug_class_param, which has a ref to
>>> the param's state, and to the classmap defining the param's handling.
>>>
>>> 2nd, it requires that the classmap ref'd by the kparam is the one
>>> we're called for; modules can use many separate classmaps (as
>>> test_dynamic_debug does).
>>>
>>> Then apply the "parent" kparam's setting to the dependent module,
>>> using ddebug_apply_class_bitmap().
>>>
>>> ddebug_change(and callees) also gets adjustments:
>>>
>>> ddebug_find_valid_class(): This does a search over the module's
>>> classmaps, looking for the class FOO echo'd to >control.  So now it
>>> searches over __dyndbg_class_users[] after __dyndbg_classes[].
>>>
>>> ddebug_class_name(): return class-names for defined AND used classes.
>>>
>>> test_dynamic_debug.c, test_dynamic_debug_submod.c:
>>>
>>> This demonstrates the 2 types of classmaps & sysfs-params, following
>>> the 4-part recipe:
>>>
>>> 1. define an enum for the classmap: DRM.debug has DRM_UT_{CORE,KMS,...}
>>>      multiple classes must share 0-62 classid space.
>>> 2. DYNDBG_CLASSMAP_DEFINE(.. DRM_UT_{CORE,KMS,...})
>>> 3. DYNDBG_CLASSMAP_PARAM* (classmap)
>>> 4. DYNDBG_CLASSMAP_USE()
>>>      by _submod only, skipping 2,3
>>>
>>> Move all the enum declarations together, to better explain how they
>>> share the 0..62 class-id space available to a module (non-overlapping
>>> subranges).
>>>
>>> reorg macros 2,3 by name.  This gives a tabular format, making it easy
>>> to see the pattern of repetition, and the points of change.
>>>
>>> And extend the test to replicate the 2-module (parent & dependent)
>>> scenario which caused the CONFIG_DRM_USE_DYNAMIC_DEBUG=y regression
>>> seen in drm & drivers.
>>>
>>> The _submod.c is a 2-line file: #define _SUBMOD, #include parent.
>>>
>>> This gives identical complements of prdbgs in parent & _submod, and
>>> thus identical print behavior when all of: >control, >params, and
>>> parent->_submod propagation are working correctly.
>>>
>>> It also puts all the parent/_submod declarations together in the same
>>> source, with the new ifdef _SUBMOD block invoking DYNDBG_CLASSMAP_USE
>>> for the 2 test-interfaces.  I think this is clearer.
>>>
>>> These 2 modules are both tristate, allowing 3 super/sub combos: Y/Y,
>>> Y/M, M/M (not N/N).  Y/Y testing exposed a missing __align(8) in the
>>> _METADATA macro, which M/M didn't see because the module-loader memory
>>> placement constrains it instead.
>>>
>>> NB: this patch ignores a checkpatch do-while warning which is fixed by
>>> a preceding commit, which would be wrong for declarative macros like
>>> module_param_named() etc.
>>>
>>> Fixes: aad0214f3026 ("dyndbg: add DECLARE_DYNDBG_CLASSMAP macro")
>>> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
>>> ---
>>> v9 - commit-msg tweaks
>>>        DRM:CHECK warnings on macros: add parens
>>>        extern DEFINEd _var, static classnames
>>>        change ddebug_class_user.user_mod_name to .mod_name
>>>        simplify ddebug_find_valid_class
>>>        improve vpr_cm_info msg format
>>>        wrap (base) in macro body
>>>        move __DYNDBG_CLASSMAP_CHECK above kdoc for DYNDBG_CLASSMAP_DEFINE
>>>
>>> v8 - split drm parts to separate commits.
>>>        preserve DECLARE_DYNDBG_CLASSMAP to decouple DRM, no flag day.
>>>        fixup block comment
>>>
>>> v7 - previous submission-blocking bug:
>>>
>>> missing __align(8) in DYNAMIC_DEBUG_DECLARE_METADATA on
>>> ddebug_class_user caused corrupt records, but only for builtin
>>> modules; module loader code probably pinned allocations to the right
>>> alignment naturally, hiding the bug for typical builds.
>>>
>>> v6- get rid of WARN_ON_ONCE
>>> v?- fix _var expanded 2x in macro
>>>
>>> dyndbg:
>>>
>>> This fn formerly returned the map which contained the class (thus
>>> validating it), and as a side-effect set the class-id in an outvar.
>>>
>>> But the caller didn't use the map (after checking its not null), only
>>> the valid class-id.  So simplify the fn to return the class-id of the
>>> validated classname, or -ENOENT when the queried classname is not
>>> found.
>>>
>>> Convey more useful info in the debug-msg: print class-names[0,last],
>>> and [base,+len] instead of the class-type printout, which is currently
>>> always "type:DISJOINT_BITS".  And drop ddebug_classmap_typenames,
>>> which is now unused.
>>>
>>> [root@v6 b0-dd]# modprobe test_dynamic_debug_submod
>>> [   18.864962] dyndbg: loaded classmap: test_dynamic_debug [16..24] V0..V7
>>> [   18.865046] dyndbg:  found kp:p_level_num =0x0
>>> [   18.865048] dyndbg:   mapped to: test_dynamic_debug [16..24] V0..V7
>>> [   18.865164] dyndbg:   p_level_num: lvl:0 bits:0x0
>>> [   18.865217] dyndbg: loaded classmap: test_dynamic_debug [0..10] D2_CORE..D2_DRMRES
>>> [   18.865297] dyndbg:  found kp:p_disjoint_bits =0x0
>>> [   18.865298] dyndbg:   mapped to: test_dynamic_debug [0..10] D2_CORE..D2_DRMRES
>>> [   18.865424] dyndbg:   p_disjoint_bits: classbits: 0x0
>>> [   18.865472] dyndbg: module:test_dynamic_debug attached 2 classmaps
>>> [   18.865533] dyndbg:  23 debug prints in module test_dynamic_debug
>>> [   18.866558] dyndbg: loaded classmap: test_dynamic_debug_submod [16..24] V0..V7
>>> [   18.866698] dyndbg:  found kp:p_level_num =0x0
>>> [   18.866699] dyndbg:   mapped to: test_dynamic_debug_submod [16..24] V0..V7
>>> [   18.866865] dyndbg:   p_level_num: lvl:0 bits:0x0
>>> [   18.866926] dyndbg: loaded classmap: test_dynamic_debug_submod [0..10] D2_CORE..D2_DRMRES
>>> [   18.867026] dyndbg:  found kp:p_disjoint_bits =0x0
>>> [   18.867027] dyndbg:   mapped to: test_dynamic_debug_submod [0..10] D2_CORE..D2_DRMRES
>>> [   18.867193] dyndbg:   p_disjoint_bits: classbits: 0x0
>>> [   18.867255] dyndbg: module:test_dynamic_debug_submod attached 2 classmap uses
>>> [   18.867351] dyndbg:  23 debug prints in module test_dynamic_debug_submod
>>> ---
>>>    MAINTAINERS                       |   2 +-
>>>    include/asm-generic/vmlinux.lds.h |   1 +
>>>    include/linux/dynamic_debug.h     |  83 ++++++++++--
>>>    kernel/module/main.c              |   3 +
>>>    lib/Kconfig.debug                 |  24 +++-
>>>    lib/Makefile                      |   3 +
>>>    lib/dynamic_debug.c               | 203 ++++++++++++++++++++++++------
>>>    lib/test_dynamic_debug.c          | 111 +++++++++++-----
>>>    lib/test_dynamic_debug_submod.c   |  10 ++
>>
>> Hi Jim,
>>
>> While reading the files test_dynamic_debug*, I was wondering, they are
>> more samples than tests. Does it make sense to move them in samples/?
>> There is no need to do it in this series.
>>
>>>    9 files changed, 355 insertions(+), 85 deletions(-)
>>>    create mode 100644 lib/test_dynamic_debug_submod.c
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 0fa7c5728f1e..38afccb3b71e 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -8041,7 +8041,7 @@ M:      Jim Cromie <jim.cromie@gmail.com>
>>>    S:  Maintained
>>>    F:  include/linux/dynamic_debug.h
>>>    F:  lib/dynamic_debug.c
>>> -F:   lib/test_dynamic_debug.c
>>> +F:   lib/test_dynamic_debug*.c
>>>
>>>    DYNAMIC INTERRUPT MODERATION
>>>    M:  Tal Gilboa <talgi@nvidia.com>
>>> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
>>> index 54504013c749..eb93fd09832b 100644
>>> --- a/include/asm-generic/vmlinux.lds.h
>>> +++ b/include/asm-generic/vmlinux.lds.h
>>> @@ -366,6 +366,7 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
>>>        /* implement dynamic printk debug */                            \
>>>        . = ALIGN(8);                                                   \
>>>        BOUNDED_SECTION_BY(__dyndbg_classes, ___dyndbg_classes)         \
>>> +     BOUNDED_SECTION_BY(__dyndbg_class_users, ___dyndbg_class_users) \
>>>        BOUNDED_SECTION_BY(__dyndbg, ___dyndbg)                         \
>>>        CODETAG_SECTIONS()                                              \
>>>        LIKELY_PROFILE()                                                \
>>> diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
>>> index c8102e89beb2..dc610a12b91c 100644
>>> --- a/include/linux/dynamic_debug.h
>>> +++ b/include/linux/dynamic_debug.h
>>> @@ -71,9 +71,28 @@ enum ddebug_class_map_type {
>>>         */
>>>    };
>>>
>>> +/*
> 
> BTW, Im gonna refine this ...
> 
>>> + * dyndbg-classmaps are devised to support DRM.debug directly:
>>> + *    10 enum-vals: DRM_UT_* define the categories
>>> + *   ~23 categorized *_dbg() macros, each passing a DRM_UT_* val as 1st arg
>>> + *     2 macros below them: drm_dev_dbg, __drm_dbg
>>> + * ~5000 calls to the categorized macros, across all of drivers/gpu/drm/
>>> + *
>>> + * When CONFIG_DRM_USE_DYNAMIC_DEBUG=y, the 2 low macros are redefined
>>> + * to invoke _dynamic_func_call_cls().  This compiles the category
>>> + * into each callsite's class_id field, where dyndbg can select on it
>>> + * and alter a callsite's patch-state, avoiding repeated __drm_debug
>>> + * checks.
>>> + *
>>> + * To make the callsites manageable from the >control file, authors
>>> + * provide a "classmap" of names to class_ids in use by the module(s),
>>> + * usually by stringifying the enum-vals.  Modules with multiple
>>> + * classmaps must arrange to share the 0..62 class_id space.
>>> + */
>>> +
>>>    struct ddebug_class_map {
>>> -     struct module *mod;
>>> -     const char *mod_name;   /* needed for builtins */
>>> +     const struct module *mod;               /* NULL for builtins */
>>> +     const char *mod_name;
>>
>> Is this change belongs to this patch? If not can you move this in a
>> "cleanup" patch?
> 
> It belongs, insofar as the mod field is actually NULL checked to determine
> builtin vs modular, mod_name is backup.
> Also its more specific than "needed for builtins"
> 
> But, grumble, ya, the above was an existing test, not a new one.
> OTOH - I guess Ive just written the cleanup commit msg :-)
> 
>>
>>>        const char **class_names;
>>>        const int length;
>>>        const int base;         /* index of 1st .class_id, allows split/shared space */
>>> @@ -81,11 +100,34 @@ struct ddebug_class_map {
>>>    };
>>>
>>>    /**
>>> - * DECLARE_DYNDBG_CLASSMAP - declare classnames known by a module
>>> - * @_var:   a struct ddebug_class_map, passed to module_param_cb
>>> - * @_type:  enum class_map_type, chooses bits/verbose, numeric/symbolic
>>> - * @_base:  offset of 1st class-name. splits .class_id space
>>> - * @classes: class-names used to control class'd prdbgs
>>> + * DYNDBG_CLASSMAP_DEFINE - define debug classes used by a module.
>>> + * @_var:   name of the classmap, exported for other modules coordinated use.
>>> + * @_mapty: enum ddebug_class_map_type: 0:DISJOINT - independent, 1:LEVEL - v2>v1> + * @_base:  reserve N classids starting at _base, to split 0..62
>> classid space
>>> + * @classes: names of the N classes.
>>> + *
>>> + * This tells dyndbg what class_ids the module is using: _base..+N, by
>>> + * mapping names onto them.  This qualifies "class NAME" >controls on
>>> + * the defining module, ignoring unknown names.
>>> + */
>>> +#define DYNDBG_CLASSMAP_DEFINE(_var, _mapty, _base, ...)             \
>>> +     static const char *_var##_classnames[] = { __VA_ARGS__ };       \
>>> +     extern struct ddebug_class_map _var;                            \
>>> +     struct ddebug_class_map __aligned(8) __used                     \
>>> +             __section("__dyndbg_classes") _var = {                  \
>>> +             .mod = THIS_MODULE,                                     \
>>> +             .mod_name = KBUILD_MODNAME,                             \
>>> +             .base = (_base),                                        \
>>> +             .map_type = (_mapty),                                   \
>>> +             .length = ARRAY_SIZE(_var##_classnames),                \
>>> +             .class_names = _var##_classnames,                       \
>>> +     };                                                              \
>>> +     EXPORT_SYMBOL(_var)
>>> +
>>> +/*
>>> + * XXX: keep this until DRM adapts to use the DEFINE/USE api, it
>>> + * differs from DYNDBG_CLASSMAP_DEFINE by the static replacing the
>>> + * extern/EXPORT on the struct init.
>>>     */
>>>    #define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...)         \
>>>        static const char *_var##_classnames[] = { __VA_ARGS__ };       \
>>> @@ -99,12 +141,37 @@ struct ddebug_class_map {
>>>                .class_names = _var##_classnames,                       \
>>>        }
>>>
>>> +struct ddebug_class_user {
>>> +     char *mod_name;
>>> +     struct ddebug_class_map *map;
>>> +};
>>> +
>>> +/**
>>> + * DYNDBG_CLASSMAP_USE - refer to a classmap, DEFINEd elsewhere.
>>> + * @_var: name of the exported classmap var
>>> + *
>>> + * This tells dyndbg that the module has prdbgs with classids defined
>>> + * in the named classmap.  This qualifies "class NAME" >controls on
>>> + * the user module, ignoring unknown names.
>>> + */
>>> +#define DYNDBG_CLASSMAP_USE(_var)                                    \
>>> +     DYNDBG_CLASSMAP_USE_(_var, __UNIQUE_ID(ddebug_class_user))
>>> +#define DYNDBG_CLASSMAP_USE_(_var, _uname)                           \
>>> +     extern struct ddebug_class_map _var;                            \
>>> +     static struct ddebug_class_user __aligned(8) __used             \
>>> +     __section("__dyndbg_class_users") _uname = {                    \
>>> +             .mod_name = KBUILD_MODNAME,                             \
>>> +             .map = &(_var),                                         \
>>> +     }
>>> +
>>
>> I'm not sure I understand properly how __section works, but can we use
>> multiple DYNDBG_CLASSMAP_USE in one module? Can we also use
>> DYNDBG_CLASSMAP_DEFINE while also importing an other classmap
>> DYNDBG_CLASSMAP_USE?
>>
> 
> Yes, its supposed to work that way.
> 
> I havent tested that specific scenario (yet), but
> a _USEr module, like test-dynamic-debug-submod,
> could also _DEFINE its own, as long as it honors
> the class-id mapping it is using and therefore sharing.
> The on-modprobe conflict check should catch this condition.
> 
> And __section (ISTM) accumulates entries, typically static struct var
> initializations.
> AFAICT, scanning the sections is how these { scoped statics } are
> often reachable.
> 
> For example, dd's _METADATA_ builds a { static _ddebug } for every pr_debug.
> They all go into the __dyndbg section (renamed with _descriptors suffix soon),
> in the order their respective definer objects are linked.
> 
> include/asm-generic/vmlinux.lds.h  then places the __dyndbg_* sections
> into DATA, along with lots of other freight, for the various
> mechanisms they serve.
> 
> 
> 
> 
>> If not, does it make sense to allow it (for example MFD devices can
>> touch multiple subsystems)?
> 
> We have another use case !
> Do you know your way around that case ?
>

No, I don't have other use cases, I was just thinking about possible 
scenarios of the "include multiple classmap".

So, happy to konw it is not an issue with the section, but do I 
understand properly the code (completly hypotetical example): if drm.ko 
defines classes 0..10 and spi.ko defines classes 0..4, it means 
driver.ko can't use both classmap? (I don't have such use-case, and 
maybe this use-case does not exists!)

The only solution I see is to add more stuff in the _ddebug structure 
(for example a "classmap identifier"). But for now, the current user 
will be DRM, so we don't really need to fix this issue right now.

I just found a possible user for dyndbg classes [1], it seems to 
implement something similar.

[1]:https://elixir.bootlin.com/linux/v6.13.7/source/drivers/block/drbd/drbd_polymorph_printk.h

> Note that DEFINEr  & USEr calls set up linkage dependencies,
> As long as these are consistent with other module deps,
> it should work.
> 
> 
>>
>>>    /* encapsulate linker provided built-in (or module) dyndbg data */
>>>    struct _ddebug_info {
>>>        struct _ddebug *descs;
>>>        struct ddebug_class_map *classes;
>>> +     struct ddebug_class_user *class_users;
>>>        unsigned int num_descs;
>>>        unsigned int num_classes;
>>> +     unsigned int num_class_users;
>>>    };
>>>
>>>    struct ddebug_class_param {
>>> @@ -205,7 +272,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
>>>     * (|_no_desc):     former gets callsite descriptor as 1st arg (for prdbgs)
>>>     */
>>>    #define __dynamic_func_call_cls(id, cls, fmt, func, ...) do {       \
>>> -     DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt);        \
>>> +     DEFINE_DYNAMIC_DEBUG_METADATA_CLS((id), cls, fmt);      \
>>
>> Can you move this in a "cleanup" patch?
>>
>>>        if (DYNAMIC_DEBUG_BRANCH(id))                           \
>>>                func(&id, ##__VA_ARGS__);                       \
>>>    } while (0)
>>> diff --git a/kernel/module/main.c b/kernel/module/main.c
>>> index 5399c182b3cb..c394a0c6e8c6 100644
>>> --- a/kernel/module/main.c
>>> +++ b/kernel/module/main.c
>>> @@ -2546,6 +2546,9 @@ static int find_module_sections(struct module *mod, struct load_info *info)
>>>        mod->dyndbg_info.classes = section_objs(info, "__dyndbg_classes",
>>>                                                sizeof(*mod->dyndbg_info.classes),
>>>                                                &mod->dyndbg_info.num_classes);
>>> +     mod->dyndbg_info.class_users = section_objs(info, "__dyndbg_class_users",
>>> +                                                 sizeof(*mod->dyndbg_info.class_users),
>>> +                                                &mod->dyndbg_info.num_class_users);
>>>    #endif
>>>
>>>        return 0;
>>> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
>>> index f3d723705879..933f69ef87f8 100644
>>> --- a/lib/Kconfig.debug
>>> +++ b/lib/Kconfig.debug
>>> @@ -2884,12 +2884,26 @@ config TEST_STATIC_KEYS
>>>          If unsure, say N.
>>>
>>>    config TEST_DYNAMIC_DEBUG
>>> -     tristate "Test DYNAMIC_DEBUG"
>>> -     depends on DYNAMIC_DEBUG
>>> +     tristate "Build test-dynamic-debug module"
>>> +     depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE
>>>        help
>>> -       This module registers a tracer callback to count enabled
>>> -       pr_debugs in a 'do_debugging' function, then alters their
>>> -       enablements, calls the function, and compares counts.
>>> +       This module exercises/demonstrates dyndbg's classmap API, by
>>> +       creating 2 classes: a DISJOINT classmap (supporting DRM.debug)
>>> +       and a LEVELS/VERBOSE classmap (like verbose2 > verbose1).
>>> +
>>> +       If unsure, say N.
>>> +
>>> +config TEST_DYNAMIC_DEBUG_SUBMOD
>>> +     tristate "Build test-dynamic-debug submodule"
>>> +     default m
>>> +     depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE
>>> +     depends on TEST_DYNAMIC_DEBUG
>>> +     help
>>> +       This sub-module uses a classmap defined and exported by the
>>> +       parent module, recapitulating drm & driver's shared use of
>>> +       drm.debug to control enabled debug-categories.
>>> +       It is tristate, independent of parent, to allow testing all
>>> +       proper combinations of parent=y/m submod=y/m.
>>>
>>>          If unsure, say N.
>>>
>>> diff --git a/lib/Makefile b/lib/Makefile
>>> index a8155c972f02..7f66fc1c163d 100644
>>> --- a/lib/Makefile
>>> +++ b/lib/Makefile
>>> @@ -84,6 +84,7 @@ obj-$(CONFIG_TEST_SORT) += test_sort.o
>>>    obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o
>>>    obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o
>>>    obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o
>>> +obj-$(CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD) += test_dynamic_debug_submod.o
>>>    obj-$(CONFIG_TEST_PRINTF) += test_printf.o
>>>    obj-$(CONFIG_TEST_SCANF) += test_scanf.o
>>>
>>> @@ -228,6 +229,8 @@ obj-$(CONFIG_ARCH_NEED_CMPXCHG_1_EMU) += cmpxchg-emu.o
>>>    obj-$(CONFIG_DYNAMIC_DEBUG_CORE) += dynamic_debug.o
>>>    #ensure exported functions have prototypes
>>>    CFLAGS_dynamic_debug.o := -DDYNAMIC_DEBUG_MODULE
>>> +CFLAGS_test_dynamic_debug.o := -DDYNAMIC_DEBUG_MODULE
>>> +CFLAGS_test_dynamic_debug_submod.o := -DDYNAMIC_DEBUG_MODULE
>>>
>>>    obj-$(CONFIG_SYMBOLIC_ERRNAME) += errname.o
>>>
>>> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
>>> index 094d6e62a9d1..6bca0c6727d4 100644
>>> --- a/lib/dynamic_debug.c
>>> +++ b/lib/dynamic_debug.c
>>> @@ -43,13 +43,16 @@ extern struct _ddebug __start___dyndbg[];
>>>    extern struct _ddebug __stop___dyndbg[];
>>>    extern struct ddebug_class_map __start___dyndbg_classes[];
>>>    extern struct ddebug_class_map __stop___dyndbg_classes[];
>>> +extern struct ddebug_class_user __start___dyndbg_class_users[];
>>> +extern struct ddebug_class_user __stop___dyndbg_class_users[];
>>>
>>>    struct ddebug_table {
>>>        struct list_head link;
>>>        const char *mod_name;
>>>        struct _ddebug *ddebugs;
>>>        struct ddebug_class_map *classes;
>>> -     unsigned int num_ddebugs, num_classes;
>>> +     struct ddebug_class_user *class_users;
>>> +     unsigned int num_ddebugs, num_classes, num_class_users;
>>>    };
>>>
>>>    struct ddebug_query {
>>> @@ -148,23 +151,35 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
>>>                  query->first_lineno, query->last_lineno, query->class_string);
>>>    }
>>>
>>> -#define __outvar /* filled by callee */
>>> -static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
>>> -                                                     const char *class_string,
>>> -                                                     __outvar int *class_id)
>>> +#define vpr_dt_info(dt_p, msg_p, ...) ({                             \
>>> +     struct ddebug_table const *_dt = dt_p;                          \
>>> +     v2pr_info(msg_p " module:%s nd:%d nc:%d nu:%d\n", ##__VA_ARGS__, \
>>> +               _dt->mod_name, _dt->num_ddebugs, _dt->num_classes,    \
>>> +               _dt->num_class_users);                                \
>>> +     })
>>> +
>>> +static int ddebug_find_valid_class(struct ddebug_table const *dt, const char *class_string)
>>>    {
>>>        struct ddebug_class_map *map;
>>> +     struct ddebug_class_user *cli;
>>>        int i, idx;
>>>
>>> -     for (map = dt->classes, i = 0; i < dt->num_classes; i++, map++) {
>>> +     for (i = 0, map = dt->classes; i < dt->num_classes; i++, map++) {
>>>                idx = match_string(map->class_names, map->length, class_string);
>>>                if (idx >= 0) {
>>> -                     *class_id = idx + map->base;
>>> -                     return map;
>>> +                     vpr_dt_info(dt, "good-class: %s.%s ", map->mod_name, class_string);
>>> +                     return idx + map->base;
>>>                }
>>>        }
>>> -     *class_id = -ENOENT;
>>> -     return NULL;
>>> +     for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++) {
>>> +             idx = match_string(cli->map->class_names, cli->map->length, class_string);
>>> +             if (idx >= 0) {
>>> +                     vpr_dt_info(dt, "class-ref: %s -> %s.%s ",
>>> +                                 cli->mod_name, cli->map->mod_name, class_string);
>>> +                     return idx + cli->map->base;
>>> +             }
>>> +     }
>>> +     return -ENOENT;
>>>    }
>>>
>>>    /*
>>> @@ -173,16 +188,14 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
>>>     * callsites, normally the same as number of changes.  If verbose,
>>>     * logs the changes.  Takes ddebug_lock.
>>>     */
>>> -static int ddebug_change(const struct ddebug_query *query,
>>> -                      struct flag_settings *modifiers)
>>> +static int ddebug_change(const struct ddebug_query *query, struct flag_settings *modifiers)
>>>    {
>>>        int i;
>>>        struct ddebug_table *dt;
>>>        unsigned int newflags;
>>>        unsigned int nfound = 0;
>>>        struct flagsbuf fbuf, nbuf;
>>> -     struct ddebug_class_map *map = NULL;
>>> -     int __outvar valid_class;
>>> +     int valid_class;
>>>
>>>        /* search for matching ddebugs */
>>>        mutex_lock(&ddebug_lock);
>>> @@ -194,8 +207,8 @@ static int ddebug_change(const struct ddebug_query *query,
>>>                        continue;
>>>
>>>                if (query->class_string) {
>>> -                     map = ddebug_find_valid_class(dt, query->class_string, &valid_class);
>>> -                     if (!map)
>>> +                     valid_class = ddebug_find_valid_class(dt, query->class_string);
>>> +                     if (valid_class < 0)
>>>                                continue;
>>>                } else {
>>>                        /* constrain query, do not touch class'd callsites */
>>> @@ -559,7 +572,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
>>>
>>>    /* handle multiple queries in query string, continue on error, return
>>>       last error or number of matching callsites.  Module name is either
>>> -   in param (for boot arg) or perhaps in query string.
>>> +   in the modname arg (for boot args) or perhaps in query string.
>>>    */
>>>    static int ddebug_exec_queries(char *query, const char *modname)
>>>    {
>>> @@ -688,12 +701,12 @@ static int param_set_dyndbg_module_classes(const char *instr,
>>>    }
>>>
>>>    /**
>>> - * param_set_dyndbg_classes - class FOO >control
>>> + * param_set_dyndbg_classes - set all classes in a classmap
>>>     * @instr: string echo>d to sysfs, input depends on map_type
>>> - * @kp:    kp->arg has state: bits/lvl, map, map_type
>>> + * @kp:    kp->arg has state: bits/lvl, classmap, map_type
>>>     *
>>> - * Enable/disable prdbgs by their class, as given in the arguments to
>>> - * DECLARE_DYNDBG_CLASSMAP.  For LEVEL map-types, enforce relative
>>> + * For all classes in the classmap, enable/disable them per the input
>>> + * (depending on map_type).  For LEVEL map-types, enforce relative
>>>     * levels by bitpos.
>>>     *
>>>     * Returns: 0 or <0 if error.
>>> @@ -1038,12 +1051,17 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
>>>    static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp)
>>>    {
>>>        struct ddebug_class_map *map = dt->classes;
>>> +     struct ddebug_class_user *cli = dt->class_users;
>>>        int i;
>>>
>>>        for (i = 0; i < dt->num_classes; i++, map++)
>>>                if (class_in_range(dp->class_id, map))
>>>                        return map->class_names[dp->class_id - map->base];
>>>
>>> +     for (i = 0; i < dt->num_class_users; i++, cli++)
>>> +             if (class_in_range(dp->class_id, cli->map))
>>> +                     return cli->map->class_names[dp->class_id - cli->map->base];
>>> +
>>>        return NULL;
>>>    }
>>>
>>> @@ -1124,31 +1142,129 @@ static const struct proc_ops proc_fops = {
>>>        .proc_write = ddebug_proc_write
>>>    };
>>>
>>> -static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
>>> +#define vpr_cm_info(cm_p, msg_fmt, ...) ({                           \
>>> +     struct ddebug_class_map const *_cm = cm_p;                      \
>>> +     v2pr_info(msg_fmt " %s [%d..%d] %s..%s\n", ##__VA_ARGS__,       \
>>> +               _cm->mod_name, _cm->base, _cm->base + _cm->length,    \
>>> +               _cm->class_names[0], _cm->class_names[_cm->length - 1]); \
>>> +     })
>>> +
>>> +static void ddebug_sync_classbits(const struct kernel_param *kp, const char *modname)
>>> +{
>>> +     const struct ddebug_class_param *dcp = kp->arg;
>>> +
>>> +     /* clamp initial bitvec, mask off hi-bits */
>>> +     if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) {
>>> +             *dcp->bits &= CLASSMAP_BITMASK(dcp->map->length);
>>> +             v2pr_info("preset classbits: %lx\n", *dcp->bits);
>>> +     }
>>> +     /* force class'd prdbgs (in USEr module) to match (DEFINEr module) class-param */
>>> +     ddebug_apply_class_bitmap(dcp, dcp->bits, ~0, modname);
>>> +     ddebug_apply_class_bitmap(dcp, dcp->bits, 0, modname);
>>> +}
>>> +
>>> +static void ddebug_match_apply_kparam(const struct kernel_param *kp,
>>> +                                   const struct ddebug_class_map *map,
>>> +                                   const char *modnm)
>>> +{
>>> +     struct ddebug_class_param *dcp;
>>> +
>>> +     if (kp->ops != &param_ops_dyndbg_classes)
>>> +             return;
>>> +
>>> +     dcp = (struct ddebug_class_param *)kp->arg;
>>> +
>>> +     if (map == dcp->map) {
>>> +             v2pr_info(" kp:%s.%s =0x%lx", modnm, kp->name, *dcp->bits);
>>> +             vpr_cm_info(map, " %s mapped to: ", modnm);
>>> +             ddebug_sync_classbits(kp, modnm);
>>> +     }
>>> +}
>>> +
>>> +static void ddebug_apply_params(const struct ddebug_class_map *cm, const char *modnm)
>>> +{
>>> +     const struct kernel_param *kp;
>>> +#if IS_ENABLED(CONFIG_MODULES)
>>> +     int i;
>>> +
>>> +     if (cm->mod) {
>>> +             vpr_cm_info(cm, "loaded classmap: %s", modnm);
>>> +             /* ifdef protects the cm->mod->kp deref */
>>> +             for (i = 0, kp = cm->mod->kp; i < cm->mod->num_kp; i++, kp++)
>>> +                     ddebug_match_apply_kparam(kp, cm, modnm);
>>> +     }
>>> +#endif
>>> +     if (!cm->mod) {
>>> +             vpr_cm_info(cm, "builtin classmap: %s", modnm);
>>> +             for (kp = __start___param; kp < __stop___param; kp++)
>>> +                     ddebug_match_apply_kparam(kp, cm, modnm);
>>> +     }
>>> +}
>>> +
>>> +/*
>>> + * Find this module's classmaps in a sub/whole-range of the builtin/
>>> + * modular classmap vector/section.  Save the start and length of the
>>> + * subrange at its edges.
>>> + */
>>> +static void ddebug_attach_module_classes(struct ddebug_table *dt,
>>> +                                      const struct _ddebug_info *di)
>>>    {
>>>        struct ddebug_class_map *cm;
>>>        int i, nc = 0;
>>>
>>> -     /*
>>> -      * Find this module's classmaps in a subrange/wholerange of
>>> -      * the builtin/modular classmap vector/section.  Save the start
>>> -      * and length of the subrange at its edges.
>>> -      */
>>> -     for (cm = di->classes, i = 0; i < di->num_classes; i++, cm++) {
>>> -
>>> +     for (i = 0, cm = di->classes; i < di->num_classes; i++, cm++) {
>>>                if (!strcmp(cm->mod_name, dt->mod_name)) {
>>> -                     if (!nc) {
>>> -                             v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
>>> -                                       i, cm->mod_name, cm->base, cm->length, cm->map_type);
>>> +                     vpr_cm_info(cm, "classes[%d]:", i);
>>> +                     if (!nc++)
>>>                                dt->classes = cm;
>>> -                     }
>>> -                     nc++;
>>>                }
>>>        }
>>> -     if (nc) {
>>> -             dt->num_classes = nc;
>>> -             vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
>>> +     if (!nc)
>>> +             return;
>>> +
>>> +     vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
>>> +     dt->num_classes = nc;
>>> +
>>> +     for (i = 0, cm = dt->classes; i < dt->num_classes; i++, cm++)
>>> +             ddebug_apply_params(cm, cm->mod_name);
>>> +}
>>> +
>>> +/*
>>> + * propagates class-params thru their classmaps to class-users.  this
>>> + * means a query against the dt/module, which means it must be on the
>>> + * list to be seen by ddebug_change.
>>> + */
>>> +static void ddebug_attach_user_module_classes(struct ddebug_table *dt,
>>> +                                           const struct _ddebug_info *di)
>>> +{
>>> +     struct ddebug_class_user *cli;
>>> +     int i, nc = 0;
>>> +
>>> +     /*
>>> +      * For builtins: scan the array, find start/length of this
>>> +      * module's refs, save to dt.  For loadables, this is the
>>> +      * whole array.
>>> +      */
>>> +     for (i = 0, cli = di->class_users; i < di->num_class_users; i++, cli++) {
>>> +             if (WARN_ON_ONCE(!cli || !cli->map || !cli->mod_name))
>>> +                     continue;
>>> +             if (!strcmp(cli->mod_name, dt->mod_name)) {
>>> +                     vpr_cm_info(cli->map, "class_ref[%d] %s -> %s", i,
>>> +                                 cli->mod_name, cli->map->mod_name);
>>> +                     if (!nc++)
>>> +                             dt->class_users = cli;
>>> +             }
>>>        }
>>> +     if (!nc)
>>> +             return;
>>> +
>>> +     dt->num_class_users = nc;
>>> +
>>> +     /* now iterate dt */
>>> +     for (i = 0, cli = dt->class_users; i < dt->num_class_users; i++, cli++)
>>> +             ddebug_apply_params(cli->map, cli->mod_name);
>>> +
>>> +     vpr_dt_info(dt, "attach-client-module: ");
>>>    }
>>>
>>>    /*
>>> @@ -1158,6 +1274,8 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug
>>>    static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>>>    {
>>>        struct ddebug_table *dt;
>>> +     struct _ddebug *iter;
>>> +     int i, class_ct = 0;
>>>
>>>        if (!di->num_descs)
>>>                return 0;
>>> @@ -1181,13 +1299,20 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
>>>
>>>        INIT_LIST_HEAD(&dt->link);
>>>
>>> -     if (di->classes && di->num_classes)
>>> +     for (i = 0, iter = di->descs; i < di->num_descs; i++, iter++)
>>> +             if (iter->class_id != _DPRINTK_CLASS_DFLT)
>>> +                     class_ct++;
>>> +
>>> +     if (class_ct && di->num_classes)
>>>                ddebug_attach_module_classes(dt, di);
>>>
>>>        mutex_lock(&ddebug_lock);
>>>        list_add_tail(&dt->link, &ddebug_tables);
>>>        mutex_unlock(&ddebug_lock);
>>>
>>> +     if (class_ct && di->num_class_users)
>>> +             ddebug_attach_user_module_classes(dt, di);
>>> +
>>>        vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
>>>        return 0;
>>>    }
>>> @@ -1337,8 +1462,10 @@ static int __init dynamic_debug_init(void)
>>>        struct _ddebug_info di = {
>>>                .descs = __start___dyndbg,
>>>                .classes = __start___dyndbg_classes,
>>> +             .class_users = __start___dyndbg_class_users,
>>>                .num_descs = __stop___dyndbg - __start___dyndbg,
>>>                .num_classes = __stop___dyndbg_classes - __start___dyndbg_classes,
>>> +             .num_class_users = __stop___dyndbg_class_users - __start___dyndbg_class_users,
>>>        };
>>>
>>>    #ifdef CONFIG_MODULES
>>> diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
>>> index 74d183ebf3e0..1838f62738c4 100644
>>> --- a/lib/test_dynamic_debug.c
>>> +++ b/lib/test_dynamic_debug.c
>>> @@ -6,11 +6,15 @@
>>>     *      Jim Cromie  <jim.cromie@gmail.com>
>>>     */
>>>
>>> -#define pr_fmt(fmt) "test_dd: " fmt
>>> +#if defined(TEST_DYNAMIC_DEBUG_SUBMOD)
>>> +  #define pr_fmt(fmt) "test_dd_submod: " fmt
>>> +#else
>>> +  #define pr_fmt(fmt) "test_dd: " fmt
>>> +#endif
>>>
>>>    #include <linux/module.h>
>>>
>>> -/* run tests by reading or writing sysfs node: do_prints */
>>> +/* re-gen output by reading or writing sysfs node: do_prints */
>>>
>>>    static void do_prints(void); /* device under test */
>>>    static int param_set_do_prints(const char *instr, const struct kernel_param *kp)
>>> @@ -29,24 +33,39 @@ static const struct kernel_param_ops param_ops_do_prints = {
>>>    };
>>>    module_param_cb(do_prints, &param_ops_do_prints, NULL, 0600);
>>>
>>> -/*
>>> - * Using the CLASSMAP api:
>>> - * - classmaps must have corresponding enum
>>> - * - enum symbols must match/correlate with class-name strings in the map.
>>> - * - base must equal enum's 1st value
>>> - * - multiple maps must set their base to share the 0-30 class_id space !!
>>> - *   (build-bug-on tips welcome)
>>> - * Additionally, here:
>>> - * - tie together sysname, mapname, bitsname, flagsname
>>> - */
>>> -#define DD_SYS_WRAP(_model, _flags)                                  \
>>> -     static unsigned long bits_##_model;                             \
>>> -     static struct ddebug_class_param _flags##_model = {             \
>>> +#define CLASSMAP_BITMASK(width, base) (((1UL << (width)) - 1) << (base))
>>> +
>>> +/* sysfs param wrapper, proto-API */
>>> +#define DYNDBG_CLASSMAP_PARAM_(_model, _flags, _init)                        \
>>> +     static unsigned long bits_##_model = _init;                     \
>>> +     static struct ddebug_class_param _flags##_##_model = {          \
>>>                .bits = &bits_##_model,                                 \
>>>                .flags = #_flags,                                       \
>>>                .map = &map_##_model,                                   \
>>>        };                                                              \
>>> -     module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes, &_flags##_model, 0600)
>>> +     module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes,   \
>>> +                     &_flags##_##_model, 0600)
>>> +#ifdef DEBUG
>>> +#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, ~0)
>>> +#else
>>> +#define DYNDBG_CLASSMAP_PARAM(_model, _flags)  DYNDBG_CLASSMAP_PARAM_(_model, _flags, 0)
>>> +#endif
>>> +
>>> +/*
>>> + * Demonstrate/test all 4 class-typed classmaps with a sys-param.
>>> + *
>>> + * Each is 3 part: client-enum decl, _DEFINE, _PARAM.
>>> + * Declare them in blocks to show patterns of use (repetitions and
>>> + * changes) within each.
>>> + *
>>> + * 1st, dyndbg expects a client-provided enum-type as source of
>>> + * category/classid truth.  DRM has DRM_UT_<CORE,DRIVER,KMS,etc>.
>>> + *
>>> + * Modules with multiple CLASSMAPS must have enums with distinct
>>> + * value-ranges, arranged below with explicit enum_sym = X inits.
>>> + *
>>> + * Declare all 4 enums now, for different types
>>> + */
>>>
>>>    /* numeric input, independent bits */
>>>    enum cat_disjoint_bits {
>>> @@ -60,26 +79,51 @@ enum cat_disjoint_bits {
>>>        D2_LEASE,
>>>        D2_DP,
>>>        D2_DRMRES };
>>> -DECLARE_DYNDBG_CLASSMAP(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS, 0,
>>> -                     "D2_CORE",
>>> -                     "D2_DRIVER",
>>> -                     "D2_KMS",
>>> -                     "D2_PRIME",
>>> -                     "D2_ATOMIC",
>>> -                     "D2_VBL",
>>> -                     "D2_STATE",
>>> -                     "D2_LEASE",
>>> -                     "D2_DP",
>>> -                     "D2_DRMRES");
>>> -DD_SYS_WRAP(disjoint_bits, p);
>>> -DD_SYS_WRAP(disjoint_bits, T);
>>>
>>>    /* numeric verbosity, V2 > V1 related */
>>>    enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
>>> -DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14,
>>> -                    "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
>>> -DD_SYS_WRAP(level_num, p);
>>> -DD_SYS_WRAP(level_num, T);
>>> +
>>> +/* recapitulate DRM's parent(drm.ko) <-- _submod(drivers,helpers) */
>>> +#if !defined(TEST_DYNAMIC_DEBUG_SUBMOD)
>>
>> It was not clear at first read that the test_dynamic_debug.c code is
>> used twice.
>>
> 
> Yes, that was a miss.  Now in big comment block at the top of both,
> right before the pr-fmt  mod-name shortening for the logs.
> 
> 
>> What do you think about creating a third file "common" with
>> do_prints/do_levels/... implementations and avoid this #if !defined?
>>
> 
> I'd rather not.  I think the multi-module usage is sufficiently interconnected
> (common enum, parent side, clone side) that all-in-one presentation
> helps to communicate this "linkage".
> 
> I hope the new comments clearly elucidate this.  PLMK if not.
> 
>>> +/*
>>> + * In single user, or parent / coordinator (drm.ko) modules, define
>>> + * classmaps on the client enums above, and then declares the PARAMS
>>> + * ref'g the classmaps.  Each is exported.
>>> + */
>>> +DYNDBG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS,
>>
>> map_disjoint_bits is defined in both test_dynamic_debug.c and
>> test_dynamic_debug_submodule.c, is it normal/required?
> 
> Its the enum : cat_disjoint_bits, that is defined for both.
> 
> the _DEFINE itself is right after the ifdef TEST_MOD_SUBMOD.
> 
> do you think it needs a better MOD_SUBMOD name ?
> or an ifndef ?
> 
>>
>>> +                    D2_CORE,
>>> +                    "D2_CORE",
>>> +                    "D2_DRIVER",
>>> +                    "D2_KMS",
>>> +                    "D2_PRIME",
>>> +                    "D2_ATOMIC",
>>> +                    "D2_VBL",
>>> +                    "D2_STATE",
>>> +                    "D2_LEASE",
>>> +                    "D2_DP",
>>> +                    "D2_DRMRES");
>>> +
>>> +DYNDBG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
>>> +                    V0, "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
>>> +
>>> +/*
>>> + * now add the sysfs-params
>>> + */
>>> +
>>> +DYNDBG_CLASSMAP_PARAM(disjoint_bits, p);
>>> +DYNDBG_CLASSMAP_PARAM(level_num, p);
>>> +
>>> +#else /* TEST_DYNAMIC_DEBUG_SUBMOD */
>>> +
>>> +/*
>>> + * in submod/drm-drivers, use the classmaps defined in top/parent
>>> + * module above.
>>> + */
>>> +
>>> +DYNDBG_CLASSMAP_USE(map_disjoint_bits);
>>> +DYNDBG_CLASSMAP_USE(map_level_num);
>>> +
>>> +#endif
>>>
>>>    /* stand-in for all pr_debug etc */
>>>    #define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
>>> @@ -115,6 +159,7 @@ static void do_levels(void)
>>>
>>>    static void do_prints(void)
>>>    {
>>> +     pr_debug("do_prints:\n");
>>>        do_cats();
>>>        do_levels();
>>
>> I just observed it, is the ordering of logs garanteed in
>> /proc/dynamic_debug/control?
>>
> 
> Yes. the fully ordered table/__section is pretty important.
> If its not true for descriptors, its probably not true for class-maps
> or users either
> and the list-iter --> vector-block conversion a few commits ago isnt
> solid either.
> 
> its also an explicit assumption under these commits
> 
> 773beabbb8e8 dyndbg: reverse module.callsite walk in cat control
> 2ad556f70043 dyndbg: reverse module walk in cat control
> 
> All in all, I think something would have broken by now.
> 
> 
>> When I run this test, I have this order:
>>
>> do_cats =_ "doing categories\n"
>> [...]
>> do_levels =_ "doing levels\n"
>> [...]
>> do_prints =_ "do_prints:\n"
>> test_dynamic_debug_init =_ "init start\n"
>> test_dynamic_debug_init =_ "init done\n"
>> test_dynamic_debug_exit =_ "exited\n"
>>
>> Which is clearly not the code execution order.
> 
> Youre correct.
> the control file reflects compile link order.
> 
> Im pretty sure the appearance of init 1st in control derives from init/builtin.a
> being built 1st and/or linked 1st.
> 
>>
>>>    }
>>> diff --git a/lib/test_dynamic_debug_submod.c b/lib/test_dynamic_debug_submod.c
>>> new file mode 100644
>>> index 000000000000..9a893402ce1a
>>> --- /dev/null
>>> +++ b/lib/test_dynamic_debug_submod.c
>>> @@ -0,0 +1,10 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Kernel module for testing dynamic_debug
>>> + *
>>> + * Authors:
>>> + *      Jim Cromie   <jim.cromie@gmail.com>
>>> + */
>>> +
>>> +#define TEST_DYNAMIC_DEBUG_SUBMOD
>>> +#include "test_dynamic_debug.c"
>>
>> --
>> Louis Chauvet, Bootlin
>> Embedded Linux and Kernel engineering
>> https://bootlin.com
>>
> 
> thanks again Lous,
> Jim

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com



^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 28/63] dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API
  2025-03-16 21:14     ` jim.cromie
@ 2025-03-24 22:58       ` jim.cromie
  0 siblings, 0 replies; 103+ messages in thread
From: jim.cromie @ 2025-03-24 22:58 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel, jbaron, gregkh, ukaszb,
	intel-gfx-trybot, dri-devel, amd-gfx, intel-gvt-dev, intel-gfx,
	daniel.vetter, tvrtko.ursulin, jani.nikula, ville.syrjala

On Sun, Mar 16, 2025 at 3:14 PM <jim.cromie@gmail.com> wrote:
>
> On Tue, Feb 25, 2025 at 7:29 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
> >
> >
> >
> > Le 25/01/2025 à 07:45, Jim Cromie a écrit :
> > > move the DYNDBG_CLASSMAP_PARAM macro from test-dynamic-debug.c into
> > > the header, and refine it, by distinguishing the 2 use cases:
> > >
> > > 1.DYNDBG_CLASSMAP_PARAM_REF
> > >      for DRM, to pass in extern __drm_debug by name.
> > >      dyndbg keeps bits in it, so drm can still use it as before
> > >
> > > 2.DYNDBG_CLASSMAP_PARAM
> > >      new user (test_dynamic_debug) doesn't need to share state,
> > >      decls a static long unsigned int to store the bitvec.
> > >
> > > __DYNDBG_CLASSMAP_PARAM
> > >     bottom layer - allocate,init a ddebug-class-param, module-param-cb.
> > >
> > > Modify ddebug_sync_classbits() argtype deref inside the fn, to give
> > > access to all kp members.
> > >
> > > Also clean up and improve comments in test-code, and add
> > > MODULE_DESCRIPTIONs.
> > >
> > > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> > > ---
> > >
> > > -v9
> > >   - fixup drm-print.h  add PARAM_REF forwarding macros
> > >     with DYNDBG_CLASSMAP_PARAM_REF in the API, add DRM_ variant
> > > ---
> > >   include/linux/dynamic_debug.h   | 38 +++++++++++++++++++++
> > >   lib/dynamic_debug.c             | 60 ++++++++++++++++++++++-----------
> > >   lib/test_dynamic_debug.c        | 59 +++++++++++++-------------------
> > >   lib/test_dynamic_debug_submod.c |  9 ++++-
> > >   4 files changed, 111 insertions(+), 55 deletions(-)
> > >
> > > diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> > > index 48d76a273f68..b47d1088b7ad 100644
> > > --- a/include/linux/dynamic_debug.h
> > > +++ b/include/linux/dynamic_debug.h
> > > @@ -205,6 +205,44 @@ struct ddebug_class_param {
> > >       const struct ddebug_class_map *map;
> > >   };
> > >
> > > +/**
> > > + * DYNDBG_CLASSMAP_PARAM - control a ddebug-classmap from a sys-param
> > > + * @_name:  sysfs node name
> > > + * @_var:   name of the classmap var defining the controlled classes/bits
> > > + * @_flags: flags to be toggled, typically just 'p'
> > > + *
> > > + * Creates a sysfs-param to control the classes defined by the
> > > + * exported classmap, with bits 0..N-1 mapped to the classes named.
> > > + * This version keeps class-state in a private long int.
> > > + */
> > > +#define DYNDBG_CLASSMAP_PARAM(_name, _var, _flags)                   \
> > > +     static unsigned long _name##_bvec;                              \
> > > +     __DYNDBG_CLASSMAP_PARAM(_name, _name##_bvec, _var, _flags)
> > > +
> > > +/**
> > > + * DYNDBG_CLASSMAP_PARAM_REF - wrap a classmap with a controlling sys-param
> > > + * @_name:  sysfs node name
> > > + * @_bits:  name of the module's unsigned long bit-vector, ex: __drm_debug
> > > + * @_var:   name of the (exported) classmap var defining the classes/bits
> > > + * @_flags: flags to be toggled, typically just 'p'
> > > + *
> > > + * Creates a sysfs-param to control the classes defined by the
> > > + * exported clasmap, with bits 0..N-1 mapped to the classes named.
> > > + * This version keeps class-state in user @_bits.  This lets drm check
> > > + * __drm_debug elsewhere too.
> > > + */
> > > +#define DYNDBG_CLASSMAP_PARAM_REF(_name, _bits, _var, _flags)                \
> > > +     __DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags)
> > > +
> > > +#define __DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags)          \
> > > +     static struct ddebug_class_param _name##_##_flags = {           \
> > > +             .bits = &(_bits),                                       \
> > > +             .flags = #_flags,                                       \
> > > +             .map = &(_var),                                         \
> > > +     };                                                              \
> > > +     module_param_cb(_name, &param_ops_dyndbg_classes,               \
> > > +                     &_name##_##_flags, 0600)
> > > +
> > >   /*
> > >    * pr_debug() and friends are globally enabled or modules have selectively
> > >    * enabled them.
> > > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> > > index 781781835094..9283f2866415 100644
> > > --- a/lib/dynamic_debug.c
> > > +++ b/lib/dynamic_debug.c
> > > @@ -660,6 +660,30 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
> > >
> > >   #define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1)
> > >
> > > +static void ddebug_class_param_clamp_input(unsigned long *inrep, const struct kernel_param *kp)
> > > +{
> > > +     const struct ddebug_class_param *dcp = kp->arg;
> > > +     const struct ddebug_class_map *map = dcp->map;
> > > +
> > > +     switch (map->map_type) {
> > > +     case DD_CLASS_TYPE_DISJOINT_BITS:
> > > +             /* expect bits. mask and warn if too many */
> > > +             if (*inrep & ~CLASSMAP_BITMASK(map->length)) {
> > > +                     pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
> > > +                             KP_NAME(kp), *inrep, CLASSMAP_BITMASK(map->length));
> > > +                     *inrep &= CLASSMAP_BITMASK(map->length);
> > > +             }
> > > +             break;
> > > +     case DD_CLASS_TYPE_LEVEL_NUM:
> > > +             /* input is bitpos, of highest verbosity to be enabled */
> > > +             if (*inrep > map->length) {
> > > +                     pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
> > > +                             KP_NAME(kp), *inrep, map->length);
> > > +                     *inrep = map->length;
> > > +             }
> > > +             break;
> > > +     }
> > > +}
> > >   static int param_set_dyndbg_module_classes(const char *instr,
> > >                                          const struct kernel_param *kp,
> > >                                          const char *modnm)
> > > @@ -678,26 +702,15 @@ static int param_set_dyndbg_module_classes(const char *instr,
> > >               pr_err("expecting numeric input, not: %s > %s\n", instr, KP_NAME(kp));
> > >               return -EINVAL;
> > >       }
> > > +     ddebug_class_param_clamp_input(&inrep, kp);
> > >
> > >       switch (map->map_type) {
> > >       case DD_CLASS_TYPE_DISJOINT_BITS:
> > > -             /* expect bits. mask and warn if too many */
> > > -             if (inrep & ~CLASSMAP_BITMASK(map->length)) {
> > > -                     pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
> > > -                             KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length));
> > > -                     inrep &= CLASSMAP_BITMASK(map->length);
> > > -             }
> > >               v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp));
> > >               totct += ddebug_apply_class_bitmap(dcp, &inrep, *dcp->bits, modnm);
> > >               *dcp->bits = inrep;
> > >               break;
> > >       case DD_CLASS_TYPE_LEVEL_NUM:
> > > -             /* input is bitpos, of highest verbosity to be enabled */
> > > -             if (inrep > map->length) {
> > > -                     pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
> > > -                             KP_NAME(kp), inrep, map->length);
> > > -                     inrep = map->length;
> > > -             }
> > >               old_bits = CLASSMAP_BITMASK(*dcp->lvl);
> > >               new_bits = CLASSMAP_BITMASK(inrep);
> > >               v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
> > > @@ -1163,15 +1176,24 @@ static const struct proc_ops proc_fops = {
> > >   static void ddebug_sync_classbits(const struct kernel_param *kp, const char *modname)
> > >   {
> > >       const struct ddebug_class_param *dcp = kp->arg;
> > > +     unsigned long new_bits;
> > >
> > > -     /* clamp initial bitvec, mask off hi-bits */
> > > -     if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) {
> > > -             *dcp->bits &= CLASSMAP_BITMASK(dcp->map->length);
> > > -             v2pr_info("preset classbits: %lx\n", *dcp->bits);
> > > +     ddebug_class_param_clamp_input(dcp->bits, kp);
> > > +
> > > +     switch (dcp->map->map_type) {
> > > +     case DD_CLASS_TYPE_DISJOINT_BITS:
> > > +             v2pr_info("  %s: classbits: 0x%lx\n", KP_NAME(kp), *dcp->bits);
> > > +             ddebug_apply_class_bitmap(dcp, dcp->bits, 0UL, modname);
> > > +             break;
> > > +     case DD_CLASS_TYPE_LEVEL_NUM:
> > > +             new_bits = CLASSMAP_BITMASK(*dcp->lvl);
> > > +             v2pr_info("  %s: lvl:%ld bits:0x%lx\n", KP_NAME(kp), *dcp->lvl, new_bits);
> > > +             ddebug_apply_class_bitmap(dcp, &new_bits, 0UL, modname);
> > > +             break;
> > > +     default:
> > > +             pr_err("bad map type %d\n", dcp->map->map_type);
> > > +             return;
> > >       }
> > > -     /* force class'd prdbgs (in USEr module) to match (DEFINEr module) class-param */
> > > -     ddebug_apply_class_bitmap(dcp, dcp->bits, ~0, modname);
> > > -     ddebug_apply_class_bitmap(dcp, dcp->bits, 0, modname);
> >
> > Hi Jim,
> >
> > We lost the double call with ~0/0, is it normal?
>
> Good catch,
>
> I thought so, since it guarantees the pr_debugs' state to
> comport with sysfs settings on modprobe.
>
> I will review.
>

Ok, Im pretty sure I put those in to override DEBUG settings,
ie reset the default print state to whatever the controlling sysfs node,
if it was declared with CLASSMAP_PARAM*, has the var set at.

It now seems like extra work to clean up a corner case
which they asked for, by defining DEBUG

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH 16/63] dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP
  2025-03-24 15:07       ` Louis Chauvet
@ 2025-03-25 16:03         ` jim.cromie
  0 siblings, 0 replies; 103+ messages in thread
From: jim.cromie @ 2025-03-25 16:03 UTC (permalink / raw)
  To: Louis Chauvet
  Cc: linux-kernel, jbaron, gregkh, ukaszb, intel-gfx-trybot, dri-devel,
	amd-gfx, intel-gvt-dev, intel-gfx, daniel.vetter, tvrtko.ursulin,
	jani.nikula, ville.syrjala

On Mon, Mar 24, 2025 at 9:07 AM Louis Chauvet <louis.chauvet@bootlin.com> wrote:
>
trimming

> >>> +     __section("__dyndbg_class_users") _uname = {                    \
> >>> +             .mod_name = KBUILD_MODNAME,                             \
> >>> +             .map = &(_var),                                         \
> >>> +     }
> >>> +
> >>
> >> I'm not sure I understand properly how __section works, but can we use
> >> multiple DYNDBG_CLASSMAP_USE in one module? Can we also use
> >> DYNDBG_CLASSMAP_DEFINE while also importing an other classmap
> >> DYNDBG_CLASSMAP_USE?
> >>
> >
> > Yes, its supposed to work that way.
> >
> > I havent tested that specific scenario (yet), but
> > a _USEr module, like test-dynamic-debug-submod,
> > could also _DEFINE its own, as long as it honors
> > the class-id mapping it is using and therefore sharing.
> > The on-modprobe conflict check should catch this condition.
> >
> > And __section (ISTM) accumulates entries, typically static struct var
> > initializations.
> > AFAICT, scanning the sections is how these { scoped statics } are
> > often reachable.
> >
> > For example, dd's _METADATA_ builds a { static _ddebug } for every pr_debug.
> > They all go into the __dyndbg section (renamed with _descriptors suffix soon),
> > in the order their respective definer objects are linked.
> >
> > include/asm-generic/vmlinux.lds.h  then places the __dyndbg_* sections
> > into DATA, along with lots of other freight, for the various
> > mechanisms they serve.
> >
> >
> >
> >
> >> If not, does it make sense to allow it (for example MFD devices can
> >> touch multiple subsystems)?
> >
> > We have another use case !
> > Do you know your way around that case ?
> >
>
> No, I don't have other use cases, I was just thinking about possible
> scenarios of the "include multiple classmap".
>
> So, happy to konw it is not an issue with the section, but do I
> understand properly the code (completly hypotetical example): if drm.ko
> defines classes 0..10 and spi.ko defines classes 0..4, it means
> driver.ko can't use both classmap? (I don't have such use-case, and
> maybe this use-case does not exists!)
>

It sounds realistic on the face of it, so lets break it down:

1st off, drm drivers/helpers are full dependents on (core) drm.ko.
they are the "subsystem" users I considered.

This dependence is "+1" by _USE ref'g the exported DEFINE product.
If that dependence doesn't suit a situation, it doesn't quite fit.
The dependence dictates module-load order, amongst other things.

So it follows that spi.ko would never be a dependent module on drm.ko,
if there is a relationship, DRM would use spi, and whatever classes it defines.

Suppose spi.ko DEFINEd a classmap:  with ENDPOINT, TRANSPORT, BULK
categories of pr_debugs,  those classes would need to map to different class-ids
than DRM_UT_<*>, cuz the callsites only have the classids, not the
name-->id mapping.

if both DRM_UT_CORE and ENPOINT had class-id = 0,
then both these commands would alter the same set of pr-debugs

  echo class DRM_UT_CORE +p > /proc/dynamic-debug/control
  echo class SPI_ENDPOINT -p > /proc/dynamic-debug/control

Thats not as troublesome as it might seem:

DRM's DRM_UT_<*> vals are only exposed to userspace
by the existence of : /sys/module/drm/parameter/debug,
cuz it exposes the bit values in >debug input.

and this already changed DRM_UT_<*> vals wo anybody caring.
0406faf25fb1 drm_print: condense enum drm_debug_category

DYNAMIC-DEBUG-CLASSMAP-DEFINE() has _base arg,
which offsets the natural/obvious 0..N range to allow sharing of 0..62 range.

The outer edge of inconvenience in coordinating class-id reservations
would be N providers and M consumers. ATM, N=M=1.

Say DRM  used 2 modules defining classmaps:  spi (as discussed),
and (pure wag) gpu_engine.
Those 2 modules dont really have any other connection, but would have
to coordinate
(but maybe gpu_engine needs spi to control its cooling, and would want
to anyway)

DRM (or any classmap-definer/user) is also free to define a 2nd "category"
enum to separate the user facing aspects of DRM_UT_*
from its name->ID mapping (very internal)

Also:  "classnames" are a public-namespace; theres nothing
to stop a module from defining their own version of "DRM_UT_CORE",
and getting their pr_debugs enabled/disabled along with all of DRMs callsites.

Such a use-case would be obvious in review, and would want some justification.

WAG:  a _base arg to the _USE() macro could specify a local user offset.

Theres a saying:  if youre explaining, youre losing.

How'd I do ?

> The only solution I see is to add more stuff in the _ddebug structure
> (for example a "classmap identifier"). But for now, the current user
> will be DRM, so we don't really need to fix this issue right now.
>
> I just found a possible user for dyndbg classes [1], it seems to
> implement something similar.
>
> [1]:https://elixir.bootlin.com/linux/v6.13.7/source/drivers/block/drbd/drbd_polymorph_printk.h
>

thats a pretty impressive stack of macros.
I like the componentry and assembly

One thing that puts it out of scope is its use of KERN_EMERG, CRIT etc.
dyndbg is just KERN_DEBUG

Also those #undef *DYNAMIC_DEBUG*
explicitly unwire  dyndbg apparatus, and plug into __dynamic_pr_debug directly.
Making it an interesting case.


> > Note that DEFINEr  & USEr calls set up linkage dependencies,
> > As long as these are consistent with other module deps,
> > it should work.
> >
> >
> >>

^ permalink raw reply	[flat|nested] 103+ messages in thread

end of thread, other threads:[~2025-03-25 16:04 UTC | newest]

Thread overview: 103+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-25  6:45 [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Jim Cromie
2025-01-25  6:45 ` [PATCH 01/63] docs/dyndbg: update examples \012 to \n Jim Cromie
2025-02-25 14:30   ` Louis Chauvet
2025-03-16 13:50     ` jim.cromie
2025-01-25  6:45 ` [PATCH 02/63] test-dyndbg: fixup CLASSMAP usage error Jim Cromie
2025-02-25 11:22   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 03/63] dyndbg: reword "class unknown," to "class:_UNKNOWN_" Jim Cromie
2025-02-25 11:22   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 04/63] dyndbg: make ddebug_class_param union members same size Jim Cromie
2025-02-25 11:24   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 05/63] dyndbg: replace classmap list with a vector Jim Cromie
2025-02-25 14:08   ` Louis Chauvet
2025-03-16 14:04     ` jim.cromie
2025-01-25  6:45 ` [PATCH 06/63] dyndbg: ddebug_apply_class_bitmap - add module arg, select on it Jim Cromie
2025-02-25 14:09   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 07/63] dyndbg: split param_set_dyndbg_classes to _module & wrapper fns Jim Cromie
2025-02-25 14:09   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 08/63] dyndbg: drop NUM_TYPE_ARRAY Jim Cromie
2025-02-25 14:09   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 09/63] dyndbg: reduce verbose/debug clutter Jim Cromie
2025-02-25 14:10   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 10/63] dyndbg: silence debugs with no-change updates Jim Cromie
2025-02-25 14:10   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 11/63] dyndbg: tighten ddebug_class_name() 1st arg type Jim Cromie
2025-02-25 14:11   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 12/63] dyndbg: tighten fn-sig of ddebug_apply_class_bitmap Jim Cromie
2025-02-25 14:12   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 13/63] dyndbg: reduce verbose=3 messages in ddebug_add_module Jim Cromie
2025-02-25 14:12   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 14/63] dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code Jim Cromie
2025-01-25  6:45 ` [PATCH 15/63] checkpatch: add an exception to the do-while wrapper advice Jim Cromie
2025-02-25 14:12   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 16/63] dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP Jim Cromie
2025-02-25 14:16   ` Louis Chauvet
2025-03-16 19:46     ` jim.cromie
2025-03-24 15:07       ` Louis Chauvet
2025-03-25 16:03         ` jim.cromie
2025-01-25  6:45 ` [PATCH 17/63] dyndbg: check DYNDBG_CLASSMAP_DEFINE args at compile-time Jim Cromie
2025-02-25 14:17   ` Louis Chauvet
2025-03-16 20:46     ` jim.cromie
2025-01-25  6:45 ` [PATCH 18/63] dyndbg: add/use for_subvec() to reduce boilerplate Jim Cromie
2025-02-25 14:18   ` Louis Chauvet
2025-03-16 20:50     ` jim.cromie
2025-01-25  6:45 ` [PATCH 19/63] dyndbg: make proper substructs in _ddebug_info Jim Cromie
2025-02-25 14:19   ` Louis Chauvet
2025-03-16 20:58     ` jim.cromie
2025-01-25  6:45 ` [PATCH 20/63] dyndbg: drop premature optimization in ddebug_add_module Jim Cromie
2025-02-25 14:26   ` Louis Chauvet
2025-01-25  6:45 ` [PATCH 21/63] dyndbg: allow ddebug_add_module to fail Jim Cromie
2025-02-25 14:26   ` Louis Chauvet
2025-03-16 21:04     ` jim.cromie
2025-01-25  6:45 ` [PATCH 22/63] dyndbg: rework ddebug_attach_*module_classes() Jim Cromie
2025-01-25  6:45 ` [PATCH 23/63] dyndbg: fail modprobe on ddebug_class_range_overlap() Jim Cromie
2025-02-25 14:27   ` Louis Chauvet
2025-03-16 21:07     ` jim.cromie
2025-01-25  6:45 ` [PATCH 24/63] dyndbg: hoist the range-overlap checks Jim Cromie
2025-01-25  6:45 ` [PATCH 25/63] ddebug: cleanup-range-overlap fails Jim Cromie
2025-01-25  6:45 ` [PATCH 26/63] dyndbg-test: change do_prints testpoint to accept a loopct Jim Cromie
2025-01-25  6:45 ` [PATCH 27/63] selftests-dyndbg: add tools/testing/selftests/dynamic_debug/* Jim Cromie
2025-01-25  6:45 ` [PATCH 28/63] dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API Jim Cromie
2025-02-25 14:29   ` Louis Chauvet
2025-03-16 21:14     ` jim.cromie
2025-03-24 22:58       ` jim.cromie
2025-01-25  6:45 ` [PATCH 29/63] dyndbg-doc: add classmap info to howto Jim Cromie
2025-01-25  6:45 ` [PATCH 30/63] dyndbg: treat comma as a token separator Jim Cromie
2025-01-25  6:45 ` [PATCH 31/63] selftests-dyndbg: add comma_terminator_tests Jim Cromie
2025-01-25  6:45 ` [PATCH 32/63] dyndbg: split multi-query strings with % Jim Cromie
2025-01-25  6:45 ` [PATCH 33/63] selftests-dyndbg: test_percent_splitting Jim Cromie
2025-01-25  6:45 ` [PATCH 34/63] docs/dyndbg: explain new delimiters: comma, percent Jim Cromie
2025-01-25  6:45 ` [PATCH 35/63] selftests-dyndbg: add test_mod_submod Jim Cromie
2025-01-25  6:45 ` [PATCH 36/63] docs/dyndbg: explain flags parse 1st Jim Cromie
2025-01-25  6:45 ` [PATCH 37/63] dyndbg: change __dynamic_func_call_cls* macros into expressions Jim Cromie
2025-01-25  6:45 ` [PATCH 38/63] dyndbg: drop "protection" of class'd pr_debugs from legacy queries Jim Cromie
2025-01-25  6:45 ` [PATCH 39/63] drm: use correct ccflags-y spelling Jim Cromie
2025-01-25  6:45 ` [PATCH 40/63] checkpatch: dont warn about unused macro arg on empty body Jim Cromie
2025-01-25  6:45 ` [PATCH 41/63] drm-dyndbg: adapt drm core to use dyndbg classmaps-v2 Jim Cromie
2025-01-25  6:45 ` [PATCH 42/63] drm-dyndbg: adapt DRM to invoke DYNDBG_CLASSMAP_PARAM Jim Cromie
2025-01-25  6:45 ` [PATCH 43/63] drm-print: fix config-dependent unused variable Jim Cromie
2025-01-25  6:45 ` [PATCH 44/63] drm-dyndbg: DRM_CLASSMAP_USE in amdgpu driver Jim Cromie
2025-01-25  6:45 ` [PATCH 45/63] drm-dyndbg: DRM_CLASSMAP_USE in i915 driver Jim Cromie
2025-01-25  6:46 ` [PATCH 46/63] drm-dyndbg: DRM_CLASSMAP_USE in drm_crtc_helper Jim Cromie
2025-01-25  6:46 ` [PATCH 47/63] drm-dyndbg: DRM_CLASSMAP_USE in drm_dp_helper Jim Cromie
2025-01-25  6:46 ` [PATCH 48/63] drm-dyndbg: DRM_CLASSMAP_USE in nouveau Jim Cromie
2025-01-25  6:46 ` [PATCH 49/63] drm-dyndbg: add DRM_CLASSMAP_USE to Xe driver Jim Cromie
2025-01-25  6:46 ` [PATCH 50/63] drm-dyndbg: add DRM_CLASSMAP_USE to virtio_gpu Jim Cromie
2025-01-25  6:46 ` [PATCH 51/63] drm-dyndbg: add DRM_CLASSMAP_USE to simpledrm Jim Cromie
2025-01-25  6:46 ` [PATCH 52/63] drm-dyndbg: add DRM_CLASSMAP_USE to bochs Jim Cromie
2025-01-25  6:46 ` [PATCH 53/63] drm-dyndbg: add DRM_CLASSMAP_USE to etnaviv Jim Cromie
2025-01-25  6:46 ` [PATCH 54/63] drm-dyndbg: add DRM_CLASSMAP_USE to gma500 driver Jim Cromie
2025-01-25  6:46 ` [PATCH 55/63] drm-dyndbg: add DRM_CLASSMAP_USE to radeon Jim Cromie
2025-01-25  6:46 ` [PATCH 56/63] drm-dyndbg: add DRM_CLASSMAP_USE to vmwgfx driver Jim Cromie
2025-01-25  6:46 ` [PATCH 57/63] drm-dyndbg: add DRM_CLASSMAP_USE to vkms driver Jim Cromie
2025-01-25  6:46 ` [PATCH 58/63] drm-dyndbg: add DRM_CLASSMAP_USE to udl driver Jim Cromie
2025-01-25  6:46 ` [PATCH 59/63] drm-dyndbg: add DRM_CLASSMAP_USE to mgag200 driver Jim Cromie
2025-01-25  6:46 ` [PATCH 60/63] drm-dyndbg: add DRM_CLASSMAP_USE to the gud driver Jim Cromie
2025-01-25  6:46 ` [PATCH 61/63] drm-dyndbg: add DRM_CLASSMAP_USE to the qxl driver Jim Cromie
2025-01-25  6:46 ` [PATCH 62/63] drm-dyndbg: add DRM_CLASSMAP_USE to the drm_gem_shmem_helper driver Jim Cromie
2025-01-25  6:46 ` [PATCH 63/63] drm: restore CONFIG_DRM_USE_DYNAMIC_DEBUG un-BROKEN Jim Cromie
2025-01-25  6:46 ` [PATCH 64/64] This series fixes dyndbg (dynamic debug) classmap support for DRM Jim Cromie
2025-02-20  8:31 ` [PATCH 00/63] Fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y Greg KH
2025-02-20  9:45   ` Simona Vetter
2025-02-28 16:24     ` Louis Chauvet
2025-03-12 16:26       ` jim.cromie

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).