diff mbox

[RFC] drm: adv7511/33: Fix adv7511_cec_init() failure handling

Message ID 1510873179-20786-1-git-send-email-john.stultz@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

John Stultz Nov. 16, 2017, 10:59 p.m. UTC
From: Arnd Bergmann <arnd@arndb.de>

An otherwise correct cleanup patch from Dan Carpenter turned a broken
failure handling from a feature patch by Hans Verkuil into a kernel
Oops, so bisection points to commit 7af35b0addbc ("drm/kirin: Checking
for IS_ERR() instead of NULL") rather than 3b1b975003e4 ("drm:
adv7511/33: add HDMI CEC support").

I've managed to piece together several partial problems, though
I'm still struggling with the bigger picture:

adv7511_probe() registers a drm_bridge structure that was allocated
with devm_kzalloc(). It calls adv7511_cec_init(), which fails for an
unknown reason, which in turn triggers the registered structure to be
removed.

Elsewhere, kirin_drm_platform_probe() gets called, which calls
of_graph_get_remote_node(), and that returns NULL. Before Dan's
patch we would go on with a NULL pointer here and register that,
now kirin_drm_platform_probe() fails with -ENODEV.

In a third driver, dsi_parse_dt() calls drm_of_find_panel_or_bridge(),
which after not finding a panel goes on to call of_drm_find_bridge(),
and that crashes due to the earlier list corruption.

This addresses the first issue by making sure that adv7511_probe()
does not completely fail when the adv7511_cec_init() function fails,
and instead we just disable the CEC feature. This avoids having the
driver entirely fail to load if just the CEC initialization fails.

Reported-by: Naresh Kamboju <naresh.kamboju@linaro.org>
Cc: Xinliang Liu <xinliang.liu@linaro.org>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Archit Taneja <architt@codeaurora.org>
Link: https://bugs.linaro.org/show_bug.cgi?id=3345
Link: https://lkft.validation.linaro.org/scheduler/job/48017#L3551
Fixes: 7af35b0addbc ("drm/kirin: Checking for IS_ERR() instead of NULL")
Fixes: 3b1b975003e4 ("drm: adv7511/33: add HDMI CEC support")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
[jstultz: Reworked so when adv7511_cec_init() fails, we disable the feature instead
of disabling the entire driver, which causes graphics to not funciton]
Signed-off-by: John Stultz <john.stultz@linaro.org>
---
Just wanted to send out my rework of Arnd's patch here.
Feedback would be welcome.

thanks
-john

 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

Comments

Archit Taneja Nov. 26, 2017, 12:56 p.m. UTC | #1
Hi,

On 11/17/2017 04:29 AM, John Stultz wrote:
> From: Arnd Bergmann <arnd@arndb.de>
> 
> An otherwise correct cleanup patch from Dan Carpenter turned a broken
> failure handling from a feature patch by Hans Verkuil into a kernel
> Oops, so bisection points to commit 7af35b0addbc ("drm/kirin: Checking
> for IS_ERR() instead of NULL") rather than 3b1b975003e4 ("drm:
> adv7511/33: add HDMI CEC support").
> 
> I've managed to piece together several partial problems, though
> I'm still struggling with the bigger picture:
> 
> adv7511_probe() registers a drm_bridge structure that was allocated
> with devm_kzalloc(). It calls adv7511_cec_init(), which fails for an
> unknown reason, which in turn triggers the registered structure to be
> removed.
> 
> Elsewhere, kirin_drm_platform_probe() gets called, which calls
> of_graph_get_remote_node(), and that returns NULL. Before Dan's
> patch we would go on with a NULL pointer here and register that,
> now kirin_drm_platform_probe() fails with -ENODEV.
> 
> In a third driver, dsi_parse_dt() calls drm_of_find_panel_or_bridge(),
> which after not finding a panel goes on to call of_drm_find_bridge(),
> and that crashes due to the earlier list corruption.
> 
> This addresses the first issue by making sure that adv7511_probe()
> does not completely fail when the adv7511_cec_init() function fails,
> and instead we just disable the CEC feature. This avoids having the
> driver entirely fail to load if just the CEC initialization fails.
> 
> Reported-by: Naresh Kamboju <naresh.kamboju@linaro.org>
> Cc: Xinliang Liu <xinliang.liu@linaro.org>
> Cc: Dan Carpenter <dan.carpenter@oracle.com>
> Cc: Sean Paul <seanpaul@chromium.org>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: Archit Taneja <architt@codeaurora.org>
> Link: https://bugs.linaro.org/show_bug.cgi?id=3345
> Link: https://lkft.validation.linaro.org/scheduler/job/48017#L3551
> Fixes: 7af35b0addbc ("drm/kirin: Checking for IS_ERR() instead of NULL")
> Fixes: 3b1b975003e4 ("drm: adv7511/33: add HDMI CEC support")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> [jstultz: Reworked so when adv7511_cec_init() fails, we disable the feature instead
> of disabling the entire driver, which causes graphics to not funciton]
> Signed-off-by: John Stultz <john.stultz@linaro.org>
> ---
> Just wanted to send out my rework of Arnd's patch here.
> Feedback would be welcome.
> 
> thanks
> -john
> 
>   drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 8 ++++----
>   1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> index 0e14f15..939c3b9 100644
> --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> @@ -1203,12 +1203,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
>   
>   #ifdef CONFIG_DRM_I2C_ADV7511_CEC
>   	ret = adv7511_cec_init(dev, adv7511, offset);
> -	if (ret)
> -		goto err_unregister_cec;
>   #else
> -	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
> -		     ADV7511_CEC_CTRL_POWER_DOWN);
> +	ret = 1;
>   #endif
> +	if (ret)
> +		regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
> +			     ADV7511_CEC_CTRL_POWER_DOWN);

This would force CEC to be powered off even if adv7511_cec_init() returned 0, right?
We wouldn't want that if we want to use CEC on a platform that supports it.

Do we know why the call to adv7511_cec_init() is failing on the Hikey board? If it's
because there isn't a "cec" clock specified in DT, it's not really a fatal error, it
just means that the platform hasn't been set up to support CEC. In that case, we
should just power down the CEC block. So, if adv7511_cec_init() would return a
-ENOENT, which we could use as a hint to power down CEC. So, maybe something like this?:

#ifdef CONFIG_DRM_I2C_ADV7511_CEC
         ret = adv7511_cec_init(dev, adv7511, offset);
         if (ret && ret != -ENOENT)	
		goto err_unregister_cec;
#endif
	if (ret)
             regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
                         ADV7511_CEC_CTRL_POWER_DOWN);

Apart from this, we should also move adv7511_cec_init() up in the probe so that
it's called before the drm_bridge is registered.

Thanks,
Archit

>   
>   	return 0;
>   
>
John Stultz Nov. 28, 2017, 9:32 p.m. UTC | #2
On Sun, Nov 26, 2017 at 4:56 AM, Archit Taneja <architt@codeaurora.org> wrote:
>
> On 11/17/2017 04:29 AM, John Stultz wrote:
>> diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
>> b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
>> index 0e14f15..939c3b9 100644
>> --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
>> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
>> @@ -1203,12 +1203,12 @@ static int adv7511_probe(struct i2c_client *i2c,
>> const struct i2c_device_id *id)
>>     #ifdef CONFIG_DRM_I2C_ADV7511_CEC
>>         ret = adv7511_cec_init(dev, adv7511, offset);
>> -       if (ret)
>> -               goto err_unregister_cec;
>>   #else
>> -       regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
>> -                    ADV7511_CEC_CTRL_POWER_DOWN);
>> +       ret = 1;
>>   #endif
>> +       if (ret)
>> +               regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL +
>> offset,
>> +                            ADV7511_CEC_CTRL_POWER_DOWN);
>
>
> This would force CEC to be powered off even if adv7511_cec_init() returned
> 0, right?

I don't think so. The initent was its only powered off if
adv7511_cec_init returns an error or if  CONFIG_DRM_I2C_ADV7511_CEC is
not set.

> Do we know why the call to adv7511_cec_init() is failing on the Hikey board?
> If it's
> because there isn't a "cec" clock specified in DT, it's not really a fatal
> error, it
> just means that the platform hasn't been set up to support CEC. In that

Yea. I believe this is the case w/ HiKey.  I don't have deeply
detailed docs on the board so I'm not sure if we will be able to
enable that or not (Xinliang/Guodong: Do you know if its possible?).
In the meantime though, we shouldn't regress.

> case, we
> should just power down the CEC block. So, if adv7511_cec_init() would return
> a
> -ENOENT, which we could use as a hint to power down CEC. So, maybe something
> like this?:
>
> #ifdef CONFIG_DRM_I2C_ADV7511_CEC
>         ret = adv7511_cec_init(dev, adv7511, offset);
>         if (ret && ret != -ENOENT)
>                 goto err_unregister_cec;
> #endif
>         if (ret)
>             regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
>                         ADV7511_CEC_CTRL_POWER_DOWN);
>
> Apart from this, we should also move adv7511_cec_init() up in the probe so
> that
> it's called before the drm_bridge is registered.

Hans has since reworked the patch w/ a new version. You might want to
check his patches and see if they fit what your imagining.

thanks
-john
Archit Taneja Nov. 29, 2017, 5:05 a.m. UTC | #3
On 11/29/2017 03:02 AM, John Stultz wrote:
> On Sun, Nov 26, 2017 at 4:56 AM, Archit Taneja <architt@codeaurora.org> wrote:
>>
>> On 11/17/2017 04:29 AM, John Stultz wrote:
>>> diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
>>> b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
>>> index 0e14f15..939c3b9 100644
>>> --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
>>> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
>>> @@ -1203,12 +1203,12 @@ static int adv7511_probe(struct i2c_client *i2c,
>>> const struct i2c_device_id *id)
>>>      #ifdef CONFIG_DRM_I2C_ADV7511_CEC
>>>          ret = adv7511_cec_init(dev, adv7511, offset);
>>> -       if (ret)
>>> -               goto err_unregister_cec;
>>>    #else
>>> -       regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
>>> -                    ADV7511_CEC_CTRL_POWER_DOWN);
>>> +       ret = 1;
>>>    #endif
>>> +       if (ret)
>>> +               regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL +
>>> offset,
>>> +                            ADV7511_CEC_CTRL_POWER_DOWN);
>>
>>
>> This would force CEC to be powered off even if adv7511_cec_init() returned
>> 0, right?
> 
> I don't think so. The initent was its only powered off if
> adv7511_cec_init returns an error or if  CONFIG_DRM_I2C_ADV7511_CEC is
> not set.
> 
>> Do we know why the call to adv7511_cec_init() is failing on the Hikey board?
>> If it's
>> because there isn't a "cec" clock specified in DT, it's not really a fatal
>> error, it
>> just means that the platform hasn't been set up to support CEC. In that
> 
> Yea. I believe this is the case w/ HiKey.  I don't have deeply
> detailed docs on the board so I'm not sure if we will be able to
> enable that or not (Xinliang/Guodong: Do you know if its possible?).
> In the meantime though, we shouldn't regress.
> 
>> case, we
>> should just power down the CEC block. So, if adv7511_cec_init() would return
>> a
>> -ENOENT, which we could use as a hint to power down CEC. So, maybe something
>> like this?:
>>
>> #ifdef CONFIG_DRM_I2C_ADV7511_CEC
>>          ret = adv7511_cec_init(dev, adv7511, offset);
>>          if (ret && ret != -ENOENT)
>>                  goto err_unregister_cec;
>> #endif
>>          if (ret)
>>              regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
>>                          ADV7511_CEC_CTRL_POWER_DOWN);
>>
>> Apart from this, we should also move adv7511_cec_init() up in the probe so
>> that
>> it's called before the drm_bridge is registered.
> 
> Hans has since reworked the patch w/ a new version. You might want to
> check his patches and see if they fit what your imagining.

Yes, I saw Hans's patch after I wrote to you. That patch looks perfect. I'll
queue that to the drm-misc repo once it's rebased on 4.15-rc1.

Thanks,
Archit

> 
> thanks
> -john
>
Arnd Bergmann Nov. 29, 2017, 8:15 a.m. UTC | #4
On Wed, Nov 29, 2017 at 6:05 AM, Archit Taneja <architt@codeaurora.org> wrote:
> On 11/29/2017 03:02 AM, John Stultz wrote:
>> On Sun, Nov 26, 2017 at 4:56 AM, Archit Taneja <architt@codeaurora.org> wrote:
>>> Apart from this, we should also move adv7511_cec_init() up in the probe
>>> so that it's called before the drm_bridge is registered.
>>
>>
>> Hans has since reworked the patch w/ a new version. You might want to
>> check his patches and see if they fit what your imagining.
>
>
> Yes, I saw Hans's patch after I wrote to you. That patch looks perfect. I'll
> queue that to the drm-misc repo once it's rebased on 4.15-rc1.

It would be nice to get it merged into -rc2 if possible, as this currently
blocks all of the kselftest regression tracking that we're doing on Hikey,
since the arm64 defconfig fails to boot in both mainline and linux-next,
see https://bugs.linaro.org/show_bug.cgi?id=3345

     Arnd
diff mbox

Patch

diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 0e14f15..939c3b9 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -1203,12 +1203,12 @@  static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
 #ifdef CONFIG_DRM_I2C_ADV7511_CEC
 	ret = adv7511_cec_init(dev, adv7511, offset);
-	if (ret)
-		goto err_unregister_cec;
 #else
-	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
-		     ADV7511_CEC_CTRL_POWER_DOWN);
+	ret = 1;
 #endif
+	if (ret)
+		regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
+			     ADV7511_CEC_CTRL_POWER_DOWN);
 
 	return 0;