Re: [PATCH v11 01/19] dyndbg: add _DPRINTK_FLAGS_ENABLED

2022-01-14 Thread Vincent Whitchurch
On Fri, Jan 07, 2022 at 06:29:24AM +0100, Jim Cromie wrote:
>  #ifdef CONFIG_JUMP_LABEL
> - if (dp->flags & _DPRINTK_FLAGS_PRINT) {
> - if (!(modifiers->flags & _DPRINTK_FLAGS_PRINT))
> + if (dp->flags & _DPRINTK_FLAGS_ENABLED) {
> + if (!(modifiers->flags & 
> _DPRINTK_FLAGS_ENABLED))
>   
> static_branch_disable(>key.dd_key_true);
> - } else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
> + } else if (modifiers->flags & _DPRINTK_FLAGS_ENABLED)
>   static_branch_enable(>key.dd_key_true);
>  #endif
>   dp->flags = newflags;
> -- 
> 2.33.1
> 

I haven't tested it so I could be mistaken, but when
_DPRINTK_FLAGS_ENABLED gets two flags in the next patch, it looks like
this code still has the problem which I mentioned in
https://lore.kernel.org/lkml/20211209150910.ga23...@axis.com/?

| I noticed a bug inside the CONFIG_JUMP_LABEL handling (also present
| in the last version I posted) which should be fixed as part of the
| diff below (I've added a comment).
| [...] 
|  #ifdef CONFIG_JUMP_LABEL
| - if (dp->flags & _DPRINTK_FLAGS_PRINT) {
| - if (!(modifiers->flags & _DPRINTK_FLAGS_PRINT))
| + if (dp->flags & _DPRINTK_FLAGS_ENABLE) {
| + /*
| +  * The newflags check is to ensure that the
| +  * static branch doesn't get disabled in step
| +  * 3:
| +  *
| +  * (1) +pf
| +  * (2) +x
| +  * (3) -pf
| +  */
| + if (!(modifiers->flags & _DPRINTK_FLAGS_ENABLE) 
&&
| + !(newflags & _DPRINTK_FLAGS_ENABLE)) {
|   
static_branch_disable(>key.dd_key_true);
| - } else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
| + }
| + } else if (modifiers->flags & _DPRINTK_FLAGS_ENABLE) {
|   static_branch_enable(>key.dd_key_true);
| + }
|  #endif


Re: [PATCH v11 03/19] dyndbg: add write-to-tracefs code

2022-01-14 Thread Vincent Whitchurch
On Fri, Jan 07, 2022 at 06:29:26AM +0100, Jim Cromie wrote:
> adds: dynamic_trace()
>  uses trace_console() temporarily to issue printk:console event
>  uses internal-ish __ftrace_trace_stack code:
>   4-context buffer stack, barriers per Steve
> 
> call it from new funcs:
>   dynamic_printk() - print to both syslog/tracefs
>   dynamic_dev_printk() - dev-print to both syslog/tracefs
> 
> These handle both _DPRINTK_FLAGS_PRINTK and _DPRINTK_FLAGS_TRACE
> cases, allowing to vsnprintf the message once and use it for both,
> skipping past the KERN_DEBUG character for tracing.
> 
> Finally, adjust the callers: __dynamic_{pr_debug,{,net,ib}dev_dbg},
> replacing printk and dev_printk with the new funcs above.
> 
> The _DPRINTK_FLAGS_TRACE flag character s 'T', so the following finds
> all callsites enabled for tracing:
> 
>   grep -P =p?T /proc/dynamic_debug/control
> 
> Enabling debug-to-tracefs is 2 steps:
> 
>   # event enable
>   echo 1 > /sys/kernel/tracing/events/dyndbg/enable
>   # callsite enable
>   echo module foo +T > /proc/dynamic_debug/control
> 
> This patch,~1,~2 are based upon:
>   
> https://lore.kernel.org/lkml/20200825153338.17061-1-vincent.whitchu...@axis.com/
> 
> .. with simplification of temporarily reusing trace_console() rather
> than adding a new printk:dyndbg event.  Soon, add 2 new events
> capturing the pr_debug & dev_dbg() args.

The example above does not match the code in this patch since the
dyndbg:* events are only added in a later patch.  Perhaps you could
reorder this patch stack so that you don't use trace_console() in this
patch just to replace it with the new events in the next patch?

> 
> CC: vincent.whitchu...@axis.com
> Signed-off-by: Jim Cromie 
> ---
>  .../admin-guide/dynamic-debug-howto.rst   |   1 +
>  lib/dynamic_debug.c   | 155 +++---
>  2 files changed, 130 insertions(+), 26 deletions(-)
> 
> diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst 
> b/Documentation/admin-guide/dynamic-debug-howto.rst
[...]
> @@ -723,29 +822,33 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
>  {
>   struct va_format vaf;
>   va_list args;
> + unsigned int flags;
>  
>   va_start(args, fmt);
>  
>   vaf.fmt = fmt;
>   vaf.va = 
> + flags = descriptor->flags;
>  
>   if (ibdev && ibdev->dev.parent) {
>   char buf[PREFIX_SIZE] = "";
>  
> - dev_printk_emit(LOGLEVEL_DEBUG, ibdev->dev.parent,
> - "%s%s %s %s: %pV",
> - dynamic_emit_prefix(descriptor, buf),
> - dev_driver_string(ibdev->dev.parent),
> - dev_name(ibdev->dev.parent),
> - dev_name(>dev),
> - );
> + dynamic_dev_printk(flags, ibdev->dev.parent,
> +"%s%s %s %s: %pV",
> +dynamic_emit_prefix(descriptor, buf),
> +dev_driver_string(ibdev->dev.parent),
> +dev_name(ibdev->dev.parent),
> +dev_name(>dev),
> +);
>   } else if (ibdev) {
> - printk(KERN_DEBUG "%s: %pV", dev_name(>dev), );
> + dynamic_printk(flags, KERN_DEBUG "%s%s: %pV",
> +dev_name(>dev), );
>   } else {
> - printk(KERN_DEBUG "(NULL ib_device): %pV", );
> + dynamic_printk(flags, KERN_DEBUG "(NULL ip_device): %pV",
> +);
>   }
>  
> - va_end(args);
> +va_end(args);

This looks like an unintentional whitespace change?


Re: [PATCH v10 08/10] dyndbg: add print-to-tracefs, selftest with it - RFC

2021-12-09 Thread Vincent Whitchurch
On Wed, Dec 08, 2021 at 06:16:10AM +0100, jim.cro...@gmail.com wrote:
> are you planning to dust this patchset off and resubmit it ?
> 
> Ive been playing with it and learning ftrace (decade+ late),
> I found your boot-line example very helpful as 1st steps
> (still havent even tried the filtering)
> 
> 
> with these adjustments (voiced partly to test my understanding)
> I would support it, and rework my patchset to use it.
> 
> - change flag to -e, good mnemonics for event/trace-event
>T is good too, but uppercase, no need to go there.

Any flag name works for me.

> - include/trace/events/dyndbg.h - separate file, not mixed with print.h
>   dyndbg class, so trace_event=dyndbg:*
> 
> - 1 event type per pr_debug, dev_dbg, netdev_dbg ? ibdev_dbg ?
>   with the extra args: descriptor that Steven wanted,
>   probably also struct <|net|ib>dev

For my use cases I don't see much value in having separate events for
the different debug functions, but since all of them can be easily
enabled (dyndbg:*, as you noted), that works for me too.

> If youre too busy for a while, I'd eventually take a (slow) run at it.

You're welcome to have a go.  I think you've already rebased the
patchset, but here's a diff top of v5.16-rc4 for reference.  I noticed a
bug inside the CONFIG_JUMP_LABEL handling (also present in the last
version I posted) which should be fixed as part of the diff below (I've
added a comment).  Proper tests for this, like the ones you are adding
in your patchset, would certainly be a good idea.  Thanks.

8<-
diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst 
b/Documentation/admin-guide/dynamic-debug-howto.rst
index a89cfa083155..b9c4e808befc 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -228,6 +228,7 @@ of the characters::
 The flags are::
 
   penables the pr_debug() callsite.
+  xenables trace to the printk:dyndbg event
   fInclude the function name in the printed message
   lInclude line number in the printed message
   mInclude module name in the printed message
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index dce631e678dd..bc21bfb0fdc6 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -27,7 +27,7 @@ struct _ddebug {
 * writes commands to /dynamic_debug/control
 */
 #define _DPRINTK_FLAGS_NONE0
-#define _DPRINTK_FLAGS_PRINT   (1<<0) /* printk() a message using the format */
+#define _DPRINTK_FLAGS_PRINTK  (1<<0) /* printk() a message using the format */
 #define _DPRINTK_FLAGS_INCL_MODNAME(1<<1)
 #define _DPRINTK_FLAGS_INCL_FUNCNAME   (1<<2)
 #define _DPRINTK_FLAGS_INCL_LINENO (1<<3)
@@ -37,8 +37,11 @@ struct _ddebug {
(_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME |\
 _DPRINTK_FLAGS_INCL_LINENO  | _DPRINTK_FLAGS_INCL_TID)
 
+#define _DPRINTK_FLAGS_TRACE   (1<<5)
+#define _DPRINTK_FLAGS_ENABLE  (_DPRINTK_FLAGS_PRINTK | \
+_DPRINTK_FLAGS_TRACE)
 #if defined DEBUG
-#define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT
+#define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINTK
 #else
 #define _DPRINTK_FLAGS_DEFAULT 0
 #endif
@@ -120,10 +123,10 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
 
 #ifdef DEBUG
 #define DYNAMIC_DEBUG_BRANCH(descriptor) \
-   likely(descriptor.flags & _DPRINTK_FLAGS_PRINT)
+   likely(descriptor.flags & _DPRINTK_FLAGS_ENABLE)
 #else
 #define DYNAMIC_DEBUG_BRANCH(descriptor) \
-   unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)
+   unlikely(descriptor.flags & _DPRINTK_FLAGS_ENABLE)
 #endif
 
 #endif /* CONFIG_JUMP_LABEL */
diff --git a/include/trace/events/printk.h b/include/trace/events/printk.h
index 13d405b2fd8b..1f78bd237a91 100644
--- a/include/trace/events/printk.h
+++ b/include/trace/events/printk.h
@@ -7,7 +7,7 @@
 
 #include 
 
-TRACE_EVENT(console,
+DECLARE_EVENT_CLASS(printk,
TP_PROTO(const char *text, size_t len),
 
TP_ARGS(text, len),
@@ -31,6 +31,16 @@ TRACE_EVENT(console,
 
TP_printk("%s", __get_str(msg))
 );
+
+DEFINE_EVENT(printk, console,
+   TP_PROTO(const char *text, size_t len),
+   TP_ARGS(text, len)
+);
+
+DEFINE_EVENT(printk, dyndbg,
+   TP_PROTO(const char *text, size_t len),
+   TP_ARGS(text, len)
+);
 #endif /* _TRACE_PRINTK_H */
 
 /* This part must be outside protection */
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index dd7f56af9aed..161454fa0af8 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -36,6 +36,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
@@ -86,11 +87,12 @@ static inline const char *trim_prefix(const char *path)
 }
 
 static struct { unsigned flag:8; char opt_char; } opt_array[] = {
-   { _DPRINTK_FLAGS_PRINT, 'p' },
+   { _DPRINTK_FLAGS_PRINTK, 'p' },
{ _DPRINTK_FLAGS_INCL_MODNAME, 'm' },
{ 

Re: [PATCH v10 08/10] dyndbg: add print-to-tracefs, selftest with it - RFC

2021-11-25 Thread Vincent Whitchurch
On Fri, Nov 19, 2021 at 11:46:31PM +0100, jim.cro...@gmail.com wrote:
> Vincent's code has the macro magic to define that event, which IIUC
> is what  makes it controllable by ftrace, and therefore acceptable in
> principle to Steve.
> Would there be any reason to expand his set of 2 events into dev_dbg,
> pr_debug etc varieties ?
> (ie any value to separating dev, !dev ?, maybe so
> 
> Sean's code uses trace_array_printk primarily, which is EXPORTed,
> which is a virtue.
> 
> Vincents code does
> +/*
> + * This code is heavily based on __ftrace_trace_stack().
> + *
> + * Allow 4 levels of nesting: normal, softirq, irq, NMI.
> + */
> 
> to implement
> 
> +static void dynamic_trace(const char *fmt, va_list args)
> 
> Has this __ftrace_trace_stack() code been bundled into or hidden under
> a supported interface ?
> 
> would it look anything like trace_array_printk() ?
> 
> what problem is that code solving inside dynamic-debug.c ?

I'm not sure I fully understand all of your questions, but perhaps this
thread with Steven's reply to the first version of my patchset will
answer some of them:

 https://lore.kernel.org/lkml/20200723112644.7759f...@oasis.local.home/


Re: [PATCH v10 08/10] dyndbg: add print-to-tracefs, selftest with it - RFC

2021-11-14 Thread Vincent Whitchurch
On Thu, Nov 11, 2021 at 03:02:04PM -0700, Jim Cromie wrote:
> Sean Paul proposed, in:
> https://patchwork.freedesktop.org/series/78133/
> drm/trace: Mirror DRM debug logs to tracefs
> 
> His patchset's objective is to be able to independently steer some of
> the drm.debug stream to an alternate tracing destination, by splitting
> drm_debug_enabled() into syslog & trace flavors, and enabling them
> separately.  2 advantages were identified:
> 
> 1- syslog is heavyweight, tracefs is much lighter
> 2- separate selection of enabled categories means less traffic
> 
> Dynamic-Debug can do 2nd exceedingly well:
> 
> A- all work is behind jump-label's NOOP, zero off cost.
> B- exact site selectivity, precisely the useful traffic.
>can tailor enabled set interactively, at shell.
> 
> Since the tracefs interface is effective for drm (the threads suggest
> so), adding that interface to dynamic-debug has real potential for
> everyone including drm.
> 
> if CONFIG_TRACING:
> 
> Grab Sean's trace_init/cleanup code, use it to provide tracefs
> available by default to all pr_debugs.  This will likely need some
> further per-module treatment; perhaps something reflecting hierarchy
> of module,file,function,line, maybe with a tuned flattening.
> 
> endif CONFIG_TRACING
> 
> Add a new +T flag to enable tracing, independent of +p, and add and
> use 3 macros: dyndbg_site_is_enabled/logging/tracing(), to encapsulate
> the flag checks.  Existing code treats T like other flags.

I posted a patchset a while ago to do something very similar, but that
got stalled for some reason and I unfortunately didn't follow it up:

 
https://lore.kernel.org/lkml/20200825153338.17061-1-vincent.whitchu...@axis.com/

A key difference between that patchset and this patch (besides that
small fact that I used +x instead of +T) was that my patchset allowed
the dyndbg trace to be emitted to the main buffer and did not force them
to be in an instance-specific buffer.

That feature is quite important at least for my use case since I often
use dyndbg combined with function tracing, and the latter doesn't work
on non-main instances according to Documentation/trace/ftrace.rst.

For example, here's a random example of a bootargs from one of my recent
debugging sessions:

 trace_event=printk:* ftrace_filter=_mmc*,mmc*,sd*,dw_mci*,mci*
 ftrace=function trace_buf_size=20M dyndbg="file drivers/mmc/* +x"



Re: [PATCH v3] drm/bridge: adv7511: Fix cec clock EPROBE_DEFER handling

2020-07-15 Thread Vincent Whitchurch
On Thu, Jul 02, 2020 at 04:22:34PM +0200, Andrzej Hajda wrote:
> On 14.05.2020 13:30, Vincent Whitchurch wrote:
> > diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c 
> > b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
> > index a20a45c0b353..ee0ed4fb67c1 100644
> > --- a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
> > +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
> > @@ -286,28 +286,17 @@ static const struct cec_adap_ops adv7511_cec_adap_ops 
> > = {
> > .adap_transmit = adv7511_cec_adap_transmit,
> >   };
> >   
> > -static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 
> > *adv7511)
> > -{
> > -   adv7511->cec_clk = devm_clk_get(dev, "cec");
> > -   if (IS_ERR(adv7511->cec_clk)) {
> > -   int ret = PTR_ERR(adv7511->cec_clk);
> > -
> > -   adv7511->cec_clk = NULL;
> > -   return ret;
> > -   }
> > -   clk_prepare_enable(adv7511->cec_clk);
> > -   adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
> > -   return 0;
> > -}
> > -
> > -int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
> > +void adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
> >   {
> > unsigned int offset = adv7511->type == ADV7533 ?
> > ADV7533_REG_CEC_OFFSET : 0;
> > -   int ret = adv7511_cec_parse_dt(dev, adv7511);
> > +   int ret;
> >   
> > -   if (ret)
> > -   goto err_cec_parse_dt;
> > +   if (!adv7511->cec_clk)
> > +   goto err_cec_no_clock;
> > +
> > +   clk_prepare_enable(adv7511->cec_clk);
> > +   adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
> >   
> > adv7511->cec_adap = cec_allocate_adapter(_cec_adap_ops,
> > adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);
> > @@ -334,7 +323,7 @@ int adv7511_cec_init(struct device *dev, struct adv7511 
> > *adv7511)
> > ret = cec_register_adapter(adv7511->cec_adap, dev);
> > if (ret)
> > goto err_cec_register;
> > -   return 0;
> > +   return;
> >   
> >   err_cec_register:
> > cec_delete_adapter(adv7511->cec_adap);
> > @@ -342,8 +331,11 @@ int adv7511_cec_init(struct device *dev, struct 
> > adv7511 *adv7511)
> >   err_cec_alloc:
> > dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
> >  ret);
> > -err_cec_parse_dt:
> > +   clk_disable_unprepare(adv7511->cec_clk);
> > +   devm_clk_put(dev, adv7511->cec_clk);
> > +   /* Ensure that adv7511_remove() doesn't attempt to disable it again. */
> > +   adv7511->cec_clk = NULL;
> 
> Are you sure these three lines above are necessary? devm mechanism 
> should free the clock and with failed probe remove should not be called.

This driver ignores all failures in CEC registration/initialisation and
does not fail the probe for them.  I find that odd, but it seems to be
done like this on purpose (see commit 1b6fba458c0a2e8513 "drm/bridge:
adv7511/33: Fix adv7511_cec_init() failure handling") and my patch
preserves that behaviour.
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3] drm/bridge: adv7511: Fix cec clock EPROBE_DEFER handling

2020-05-15 Thread Vincent Whitchurch
If adv7511's devm_clk_get() for the cec clock returns -EPROBE_DEFER, we
end up in an infinite probe loop.  This happens:

 (1) adv7511's probe is called.

 (2) adv7511's probe adds some secondary i2c devices which bind to the
 dummy driver and thus call driver_deferred_probe_trigger() and
 increment deferred_trigger_count (see driver_bound()).

 (3) adv7511's probe returns -EPROBE_DEFER, and since the
 deferred_trigger_count has changed during the probe call,
 driver_deferred_probe_trigger() is called immediately (see
 really_probe()) and adv7511's probe is scheduled.

 (4) Goto step 1.

[   61.972915] really_probe: bus: 'i2c': really_probe: probing driver adv7511 
with device 0-0039
[   61.992734] really_probe: bus: 'i2c': really_probe: probing driver dummy 
with device 0-003f
[   61.993343] driver_bound: driver: 'dummy': driver_bound: bound to device 
'0-003f'
[   61.993626] really_probe: bus: 'i2c': really_probe: bound device 0-003f to 
driver dummy
[   61.995604] really_probe: bus: 'i2c': really_probe: probing driver dummy 
with device 0-0038
[   61.996381] driver_bound: driver: 'dummy': driver_bound: bound to device 
'0-0038'
[   61.996663] really_probe: bus: 'i2c': really_probe: bound device 0-0038 to 
driver dummy
[   61.998651] really_probe: bus: 'i2c': really_probe: probing driver dummy 
with device 0-003c
[   61.999222] driver_bound: driver: 'dummy': driver_bound: bound to device 
'0-003c'
[   61.999496] really_probe: bus: 'i2c': really_probe: bound device 0-003c to 
driver dummy
[   62.010050] really_probe: i2c 0-0039: Driver adv7511 requests probe deferral
[   62.011380] really_probe: bus: 'platform': really_probe: probing driver 
pwm-clock with device clock-cec
[   62.012812] really_probe: platform clock-cec: Driver pwm-clock requests 
probe deferral
[   62.024679] really_probe: bus: 'i2c': really_probe: probing driver adv7511 
with device 0-0039

Fix this by calling devm_clk_get() before registering the secondary
devices.

Signed-off-by: Vincent Whitchurch 
---
v3: Make adv7511_cec_init() return void.
v2: Add devm_clk_put() in error path.

 drivers/gpu/drm/bridge/adv7511/adv7511.h |  5 ++-
 drivers/gpu/drm/bridge/adv7511/adv7511_cec.c | 34 
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 15 ++---
 3 files changed, 25 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h 
b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index a9bb734366ae..05a66149b186 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -380,17 +380,16 @@ struct adv7511 {
 };
 
 #ifdef CONFIG_DRM_I2C_ADV7511_CEC
-int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511);
+void adv7511_cec_init(struct device *dev, struct adv7511 *adv7511);
 void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1);
 #else
-static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
+static inline void adv7511_cec_init(struct device *dev, struct adv7511 
*adv7511)
 {
unsigned int offset = adv7511->type == ADV7533 ?
ADV7533_REG_CEC_OFFSET : 0;
 
regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
 ADV7511_CEC_CTRL_POWER_DOWN);
-   return 0;
 }
 #endif
 
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c 
b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
index a20a45c0b353..ee0ed4fb67c1 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
@@ -286,28 +286,17 @@ static const struct cec_adap_ops adv7511_cec_adap_ops = {
.adap_transmit = adv7511_cec_adap_transmit,
 };
 
-static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)
-{
-   adv7511->cec_clk = devm_clk_get(dev, "cec");
-   if (IS_ERR(adv7511->cec_clk)) {
-   int ret = PTR_ERR(adv7511->cec_clk);
-
-   adv7511->cec_clk = NULL;
-   return ret;
-   }
-   clk_prepare_enable(adv7511->cec_clk);
-   adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
-   return 0;
-}
-
-int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
+void adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
 {
unsigned int offset = adv7511->type == ADV7533 ?
ADV7533_REG_CEC_OFFSET : 0;
-   int ret = adv7511_cec_parse_dt(dev, adv7511);
+   int ret;
 
-   if (ret)
-   goto err_cec_parse_dt;
+   if (!adv7511->cec_clk)
+   goto err_cec_no_clock;
+
+   clk_prepare_enable(adv7511->cec_clk);
+   adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
 
adv7511->cec_adap = cec_allocate_adapter(_cec_adap_ops,
adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);
@@ -334,7 +323,7 @@ int adv7511_cec_init(struct device *dev, struct adv751

[PATCH v2] drm/bridge: adv7511: Fix cec clock EPROBE_DEFER handling

2020-05-01 Thread Vincent Whitchurch
If adv7511's devm_clk_get() for the cec clock returns -EPROBE_DEFER, we
end up in an infinite probe loop.  This happens:

 (1) adv7511's probe is called.

 (2) adv7511's probe adds some secondary i2c devices which bind to the
 dummy driver and thus call driver_deferred_probe_trigger() and
 increment deferred_trigger_count (see driver_bound()).

 (3) adv7511's probe returns -EPROBE_DEFER, and since the
 deferred_trigger_count has changed during the probe call,
 driver_deferred_probe_trigger() is called immediately (see
 really_probe()) and adv7511's probe is scheduled.

 (4) Goto step 1.

[   61.972915] really_probe: bus: 'i2c': really_probe: probing driver adv7511 
with device 0-0039
[   61.992734] really_probe: bus: 'i2c': really_probe: probing driver dummy 
with device 0-003f
[   61.993343] driver_bound: driver: 'dummy': driver_bound: bound to device 
'0-003f'
[   61.993626] really_probe: bus: 'i2c': really_probe: bound device 0-003f to 
driver dummy
[   61.995604] really_probe: bus: 'i2c': really_probe: probing driver dummy 
with device 0-0038
[   61.996381] driver_bound: driver: 'dummy': driver_bound: bound to device 
'0-0038'
[   61.996663] really_probe: bus: 'i2c': really_probe: bound device 0-0038 to 
driver dummy
[   61.998651] really_probe: bus: 'i2c': really_probe: probing driver dummy 
with device 0-003c
[   61.999222] driver_bound: driver: 'dummy': driver_bound: bound to device 
'0-003c'
[   61.999496] really_probe: bus: 'i2c': really_probe: bound device 0-003c to 
driver dummy
[   62.010050] really_probe: i2c 0-0039: Driver adv7511 requests probe deferral
[   62.011380] really_probe: bus: 'platform': really_probe: probing driver 
pwm-clock with device clock-cec
[   62.012812] really_probe: platform clock-cec: Driver pwm-clock requests 
probe deferral
[   62.024679] really_probe: bus: 'i2c': really_probe: probing driver adv7511 
with device 0-0039

Fix this by calling devm_clk_get() before registering the secondary
devices.

Signed-off-by: Vincent Whitchurch 
---
v2: Add devm_clk_put() in error path.

 drivers/gpu/drm/bridge/adv7511/adv7511_cec.c | 31 
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 11 +--
 2 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c 
b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
index a20a45c0b353..f5e9d0b238d2 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
@@ -286,28 +286,17 @@ static const struct cec_adap_ops adv7511_cec_adap_ops = {
.adap_transmit = adv7511_cec_adap_transmit,
 };
 
-static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)
-{
-   adv7511->cec_clk = devm_clk_get(dev, "cec");
-   if (IS_ERR(adv7511->cec_clk)) {
-   int ret = PTR_ERR(adv7511->cec_clk);
-
-   adv7511->cec_clk = NULL;
-   return ret;
-   }
-   clk_prepare_enable(adv7511->cec_clk);
-   adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
-   return 0;
-}
-
 int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
 {
unsigned int offset = adv7511->type == ADV7533 ?
ADV7533_REG_CEC_OFFSET : 0;
-   int ret = adv7511_cec_parse_dt(dev, adv7511);
+   int ret;
 
-   if (ret)
-   goto err_cec_parse_dt;
+   if (!adv7511->cec_clk)
+   goto err_cec_no_clock;
+
+   clk_prepare_enable(adv7511->cec_clk);
+   adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
 
adv7511->cec_adap = cec_allocate_adapter(_cec_adap_ops,
adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);
@@ -342,8 +331,12 @@ int adv7511_cec_init(struct device *dev, struct adv7511 
*adv7511)
 err_cec_alloc:
dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
 ret);
-err_cec_parse_dt:
+   clk_disable_unprepare(adv7511->cec_clk);
+   devm_clk_put(dev, adv7511->cec_clk);
+   /* Ensure that adv7511_remove() doesn't attempt to disable it again. */
+   adv7511->cec_clk = NULL;
+err_cec_no_clock:
regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
 ADV7511_CEC_CTRL_POWER_DOWN);
-   return ret == -EPROBE_DEFER ? ret : 0;
+   return 0;
 }
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c 
b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 9e13e466e72c..ebc548e23ece 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -1122,6 +1122,15 @@ static int adv7511_probe(struct i2c_client *i2c, const 
struct i2c_device_id *id)
if (ret)
return ret;
 
+   adv7511->cec_clk = devm_clk_get(dev, "cec");
+   if (IS_ERR(adv7511->cec_clk)) {
+   ret = PTR_ERR(adv7511-

Re: [PATCH] drm/bridge: adv7511: Fix cec clock EPROBE_DEFER handling

2020-05-01 Thread Vincent Whitchurch
On Mon, Apr 06, 2020 at 02:58:17AM +0200, Laurent Pinchart wrote:
> On Tue, Mar 31, 2020 at 04:16:29PM +0200, Vincent Whitchurch wrote:
> >  int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
> >  {
> > unsigned int offset = adv7511->type == ADV7533 ?
> > ADV7533_REG_CEC_OFFSET : 0;
> > -   int ret = adv7511_cec_parse_dt(dev, adv7511);
> > +   int ret;
> >  
> > -   if (ret)
> > -   goto err_cec_parse_dt;
> > +   if (!adv7511->cec_clk)
> > +   goto err_cec_no_clock;
> > +
> > +   clk_prepare_enable(adv7511->cec_clk);
> > +   adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
> >  
> > adv7511->cec_adap = cec_allocate_adapter(_cec_adap_ops,
> > adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);
> > @@ -342,8 +331,11 @@ int adv7511_cec_init(struct device *dev, struct 
> > adv7511 *adv7511)
> >  err_cec_alloc:
> > dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
> >  ret);
> > -err_cec_parse_dt:
> > +   clk_disable_unprepare(adv7511->cec_clk);
> > +   /* Ensure that adv7511_remove() doesn't attempt to disable it again. */
> 
> Would it make sense to call devm_clk_put() here to already release the
> clock ?

I've just sent out a v2 with this added.  Thank you for the review!
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH] drm/bridge: adv7511: Fix cec clock EPROBE_DEFER handling

2020-04-01 Thread Vincent Whitchurch
If adv7511's devm_clk_get() for the cec clock returns -EPROBE_DEFER, we
end up in an infinite probe loop.  This happens:

 (1) adv7511's probe is called.

 (2) adv7511's probe adds some secondary i2c devices which bind to the
 dummy driver and thus call driver_deferred_probe_trigger() and
 increment deferred_trigger_count (see driver_bound()).

 (3) adv7511's probe returns -EPROBE_DEFER, and since the
 deferred_trigger_count has changed during the probe call,
 driver_deferred_probe_trigger() is called immediately (see
 really_probe()) and adv7511's probe is scheduled.

 (4) Goto step 1.

[   61.972915] really_probe: bus: 'i2c': really_probe: probing driver adv7511 
with device 0-0039
[   61.992734] really_probe: bus: 'i2c': really_probe: probing driver dummy 
with device 0-003f
[   61.993343] driver_bound: driver: 'dummy': driver_bound: bound to device 
'0-003f'
[   61.993626] really_probe: bus: 'i2c': really_probe: bound device 0-003f to 
driver dummy
[   61.995604] really_probe: bus: 'i2c': really_probe: probing driver dummy 
with device 0-0038
[   61.996381] driver_bound: driver: 'dummy': driver_bound: bound to device 
'0-0038'
[   61.996663] really_probe: bus: 'i2c': really_probe: bound device 0-0038 to 
driver dummy
[   61.998651] really_probe: bus: 'i2c': really_probe: probing driver dummy 
with device 0-003c
[   61.999222] driver_bound: driver: 'dummy': driver_bound: bound to device 
'0-003c'
[   61.999496] really_probe: bus: 'i2c': really_probe: bound device 0-003c to 
driver dummy
[   62.010050] really_probe: i2c 0-0039: Driver adv7511 requests probe deferral
[   62.011380] really_probe: bus: 'platform': really_probe: probing driver 
pwm-clock with device clock-cec
[   62.012812] really_probe: platform clock-cec: Driver pwm-clock requests 
probe deferral
[   62.024679] really_probe: bus: 'i2c': really_probe: probing driver adv7511 
with device 0-0039

Fix this by calling devm_clk_get() before registering the secondary
devices.

Signed-off-by: Vincent Whitchurch 
---
 drivers/gpu/drm/bridge/adv7511/adv7511_cec.c | 30 +++-
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 11 +--
 2 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c 
b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
index a20a45c0b353..4b0fee32be21 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
@@ -286,28 +286,17 @@ static const struct cec_adap_ops adv7511_cec_adap_ops = {
.adap_transmit = adv7511_cec_adap_transmit,
 };
 
-static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)
-{
-   adv7511->cec_clk = devm_clk_get(dev, "cec");
-   if (IS_ERR(adv7511->cec_clk)) {
-   int ret = PTR_ERR(adv7511->cec_clk);
-
-   adv7511->cec_clk = NULL;
-   return ret;
-   }
-   clk_prepare_enable(adv7511->cec_clk);
-   adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
-   return 0;
-}
-
 int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
 {
unsigned int offset = adv7511->type == ADV7533 ?
ADV7533_REG_CEC_OFFSET : 0;
-   int ret = adv7511_cec_parse_dt(dev, adv7511);
+   int ret;
 
-   if (ret)
-   goto err_cec_parse_dt;
+   if (!adv7511->cec_clk)
+   goto err_cec_no_clock;
+
+   clk_prepare_enable(adv7511->cec_clk);
+   adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
 
adv7511->cec_adap = cec_allocate_adapter(_cec_adap_ops,
adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);
@@ -342,8 +331,11 @@ int adv7511_cec_init(struct device *dev, struct adv7511 
*adv7511)
 err_cec_alloc:
dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
 ret);
-err_cec_parse_dt:
+   clk_disable_unprepare(adv7511->cec_clk);
+   /* Ensure that adv7511_remove() doesn't attempt to disable it again. */
+   adv7511->cec_clk = NULL;
+err_cec_no_clock:
regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
 ADV7511_CEC_CTRL_POWER_DOWN);
-   return ret == -EPROBE_DEFER ? ret : 0;
+   return 0;
 }
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c 
b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 9e13e466e72c..ebc548e23ece 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -1122,6 +1122,15 @@ static int adv7511_probe(struct i2c_client *i2c, const 
struct i2c_device_id *id)
if (ret)
return ret;
 
+   adv7511->cec_clk = devm_clk_get(dev, "cec");
+   if (IS_ERR(adv7511->cec_clk)) {
+   ret = PTR_ERR(adv7511->cec_clk);
+   if (ret == -EPROBE_DEFER)
+   return ret;
+
+