On Tue, 28 May 2024, Michal Wajdeczko <michal.wajdeczko@xxxxxxxxx> wrote: > This drm printer wrapper can be used to increase the robustness of > the captured output generated by any other drm_printer to make sure > we didn't lost any intermediate lines of the output by adding line > numbers to each output line. Helpful for capturing some crash data. > > Signed-off-by: Michal Wajdeczko <michal.wajdeczko@xxxxxxxxx> > Cc: Jani Nikula <jani.nikula@xxxxxxxxx> > Cc: John Harrison <John.C.Harrison@xxxxxxxxx> Reviewed-by: Jani Nikula <jani.nikula@xxxxxxxxx> > --- > v2: don't abuse prefix, use union instead (Jani) > don't use 'dp' as name, prefer 'p' (Jani) > add support for unique series identifier (John) > --- > drivers/gpu/drm/drm_print.c | 14 ++++++++ > include/drm/drm_print.h | 68 ++++++++++++++++++++++++++++++++++++- > 2 files changed, 81 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c > index cf2efb44722c..be9cbebff5b3 100644 > --- a/drivers/gpu/drm/drm_print.c > +++ b/drivers/gpu/drm/drm_print.c > @@ -214,6 +214,20 @@ void __drm_printfn_err(struct drm_printer *p, struct va_format *vaf) > } > EXPORT_SYMBOL(__drm_printfn_err); > > +void __drm_printfn_line(struct drm_printer *p, struct va_format *vaf) > +{ > + unsigned int counter = ++p->line.counter; > + const char *prefix = p->prefix ?: ""; > + const char *pad = p->prefix ? " " : ""; > + > + if (p->line.series) > + drm_printf(p->arg, "%s%s%u.%u: %pV", > + prefix, pad, p->line.series, counter, vaf); > + else > + drm_printf(p->arg, "%s%s%u: %pV", prefix, pad, counter, vaf); > +} > +EXPORT_SYMBOL(__drm_printfn_line); > + > /** > * drm_puts - print a const string to a &drm_printer stream > * @p: the &drm printer > diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h > index 089950ad8681..f4d9b98d7909 100644 > --- a/include/drm/drm_print.h > +++ b/include/drm/drm_print.h > @@ -176,7 +176,13 @@ struct drm_printer { > void (*puts)(struct drm_printer *p, const char *str); > void *arg; > const char *prefix; > - enum drm_debug_category category; > + union { > + enum drm_debug_category category; > + struct { > + unsigned short series; > + unsigned short counter; > + } line; > + }; > }; > > void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf); > @@ -186,6 +192,7 @@ void __drm_puts_seq_file(struct drm_printer *p, const char *str); > void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf); > void __drm_printfn_dbg(struct drm_printer *p, struct va_format *vaf); > void __drm_printfn_err(struct drm_printer *p, struct va_format *vaf); > +void __drm_printfn_line(struct drm_printer *p, struct va_format *vaf); > > __printf(2, 3) > void drm_printf(struct drm_printer *p, const char *f, ...); > @@ -357,6 +364,65 @@ static inline struct drm_printer drm_err_printer(struct drm_device *drm, > return p; > } > > +/** > + * drm_line_printer - construct a &drm_printer that prefixes outputs with line numbers > + * @p: the &struct drm_printer which actually generates the output > + * @prefix: optional output prefix, or NULL for no prefix > + * @series: optional unique series identifier, or 0 to omit identifier in the output > + * > + * This printer can be used to increase the robustness of the captured output > + * to make sure we didn't lost any intermediate lines of the output. Helpful > + * while capturing some crash data. > + * > + * Example 1:: > + * > + * void crash_dump(struct drm_device *drm) > + * { > + * static unsigned short id; > + * struct drm_printer p = drm_err_printer(drm, "crash"); > + * struct drm_printer lp = drm_line_printer(&p, "dump", ++id); > + * > + * drm_printf(&lp, "foo"); > + * drm_printf(&lp, "bar"); > + * } > + * > + * Above code will print into the dmesg something like:: > + * > + * [ ] 0000:00:00.0: [drm] *ERROR* crash dump 1.1: foo > + * [ ] 0000:00:00.0: [drm] *ERROR* crash dump 1.2: bar > + * > + * Example 2:: > + * > + * void line_dump(struct device *dev) > + * { > + * struct drm_printer p = drm_info_printer(dev); > + * struct drm_printer lp = drm_line_printer(&p, NULL, 0); > + * > + * drm_printf(&lp, "foo"); > + * drm_printf(&lp, "bar"); > + * } > + * > + * Above code will print:: > + * > + * [ ] 0000:00:00.0: [drm] 1: foo > + * [ ] 0000:00:00.0: [drm] 2: bar > + * > + * RETURNS: > + * The &drm_printer object > + */ > +static inline struct drm_printer drm_line_printer(struct drm_printer *p, > + const char *prefix, > + unsigned short series) > +{ > + struct drm_printer lp = { > + .printfn = __drm_printfn_line, > + .arg = p, > + .prefix = prefix, > + .line = { .series = series, }, > + }; > + return lp; > +} > + > /* > * struct device based logging > * -- Jani Nikula, Intel