diff mbox

[v2,5/6] drm/vc4: Support the case where the DSI device is disabled

Message ID 20180503164009.14395-6-boris.brezillon@bootlin.com (mailing list archive)
State New, archived
Headers show

Commit Message

Boris Brezillon May 3, 2018, 4:40 p.m. UTC
Having a device with a status property != "okay" in the DT is a valid
use case, and we should not prevent the registration of the DRM device
when the DSI device connected to the DSI controller is disabled.

Consider the ENODEV return code as a valid result and do not expose the
DSI encoder/connector when it happens.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
---
 drivers/gpu/drm/vc4/vc4_dsi.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

Comments

Thierry Reding May 4, 2018, 10:28 a.m. UTC | #1
On Thu, May 03, 2018 at 06:40:08PM +0200, Boris Brezillon wrote:
> Having a device with a status property != "okay" in the DT is a valid
> use case, and we should not prevent the registration of the DRM device
> when the DSI device connected to the DSI controller is disabled.
> 
> Consider the ENODEV return code as a valid result and do not expose the
> DSI encoder/connector when it happens.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> ---
>  drivers/gpu/drm/vc4/vc4_dsi.c | 15 +++++++++++++--
>  1 file changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> index 8aa897835118..db2f137f8b7b 100644
> --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> @@ -1606,8 +1606,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
>  
>  	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
>  					  &panel, &dsi->bridge);
> -	if (ret)
> +	if (ret) {
> +		/* If the bridge or panel pointed by dev->of_node is not
> +		 * enabled, just return 0 here so that we don't prevent the DRM
> +		 * dev from being registered. Of course that means the DSI
> +		 * encoder won't be exposed, but that's not a problem since
> +		 * nothing is connected to it.
> +		 */
> +		if (ret == -ENODEV)
> +			return 0;
> +
>  		return ret;
> +	}
>  
>  	if (panel) {
>  		dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
> @@ -1652,7 +1662,8 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master,
>  	struct vc4_dev *vc4 = to_vc4_dev(drm);
>  	struct vc4_dsi *dsi = dev_get_drvdata(dev);
>  
> -	pm_runtime_disable(dev);
> +	if (dsi->bridge)
> +		pm_runtime_disable(dev);

Is this safe? This uses component/master, so dsi->bridge is going to
remain valid until the driver's ->remove() is called. So technically you
could have a situation where drm_of_find_panel_or_bridge() returned some
error code that remains stored in dsi->bridge and cause the above
condition to be incorrectly true.

Thierry
Thierry Reding May 4, 2018, 10:30 a.m. UTC | #2
On Thu, May 03, 2018 at 06:40:08PM +0200, Boris Brezillon wrote:
> Having a device with a status property != "okay" in the DT is a valid
> use case, and we should not prevent the registration of the DRM device
> when the DSI device connected to the DSI controller is disabled.
> 
> Consider the ENODEV return code as a valid result and do not expose the
> DSI encoder/connector when it happens.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> ---
>  drivers/gpu/drm/vc4/vc4_dsi.c | 15 +++++++++++++--
>  1 file changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> index 8aa897835118..db2f137f8b7b 100644
> --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> @@ -1606,8 +1606,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
>  
>  	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
>  					  &panel, &dsi->bridge);
> -	if (ret)
> +	if (ret) {
> +		/* If the bridge or panel pointed by dev->of_node is not
> +		 * enabled, just return 0 here so that we don't prevent the DRM
> +		 * dev from being registered. Of course that means the DSI
> +		 * encoder won't be exposed, but that's not a problem since
> +		 * nothing is connected to it.
> +		 */

Also, nit: this isn't the correct style for block comments.

Thierry
Boris Brezillon May 4, 2018, noon UTC | #3
On Fri, 4 May 2018 12:30:25 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Thu, May 03, 2018 at 06:40:08PM +0200, Boris Brezillon wrote:
> > Having a device with a status property != "okay" in the DT is a valid
> > use case, and we should not prevent the registration of the DRM device
> > when the DSI device connected to the DSI controller is disabled.
> > 
> > Consider the ENODEV return code as a valid result and do not expose the
> > DSI encoder/connector when it happens.
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > ---
> >  drivers/gpu/drm/vc4/vc4_dsi.c | 15 +++++++++++++--
> >  1 file changed, 13 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> > index 8aa897835118..db2f137f8b7b 100644
> > --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> > +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> > @@ -1606,8 +1606,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
> >  
> >  	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
> >  					  &panel, &dsi->bridge);
> > -	if (ret)
> > +	if (ret) {
> > +		/* If the bridge or panel pointed by dev->of_node is not
> > +		 * enabled, just return 0 here so that we don't prevent the DRM
> > +		 * dev from being registered. Of course that means the DSI
> > +		 * encoder won't be exposed, but that's not a problem since
> > +		 * nothing is connected to it.
> > +		 */  
> 
> Also, nit: this isn't the correct style for block comments.

Just trying to keep it consistent with the rest of the file.
Boris Brezillon May 4, 2018, 12:05 p.m. UTC | #4
On Fri, 4 May 2018 12:28:33 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Thu, May 03, 2018 at 06:40:08PM +0200, Boris Brezillon wrote:
> > Having a device with a status property != "okay" in the DT is a valid
> > use case, and we should not prevent the registration of the DRM device
> > when the DSI device connected to the DSI controller is disabled.
> > 
> > Consider the ENODEV return code as a valid result and do not expose the
> > DSI encoder/connector when it happens.
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > ---
> >  drivers/gpu/drm/vc4/vc4_dsi.c | 15 +++++++++++++--
> >  1 file changed, 13 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> > index 8aa897835118..db2f137f8b7b 100644
> > --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> > +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> > @@ -1606,8 +1606,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
> >  
> >  	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
> >  					  &panel, &dsi->bridge);
> > -	if (ret)
> > +	if (ret) {
> > +		/* If the bridge or panel pointed by dev->of_node is not
> > +		 * enabled, just return 0 here so that we don't prevent the DRM
> > +		 * dev from being registered. Of course that means the DSI
> > +		 * encoder won't be exposed, but that's not a problem since
> > +		 * nothing is connected to it.
> > +		 */
> > +		if (ret == -ENODEV)
> > +			return 0;
> > +
> >  		return ret;
> > +	}
> >  
> >  	if (panel) {
> >  		dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
> > @@ -1652,7 +1662,8 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master,
> >  	struct vc4_dev *vc4 = to_vc4_dev(drm);
> >  	struct vc4_dsi *dsi = dev_get_drvdata(dev);
> >  
> > -	pm_runtime_disable(dev);
> > +	if (dsi->bridge)
> > +		pm_runtime_disable(dev);  
> 
> Is this safe? This uses component/master, so dsi->bridge is going to
> remain valid until the driver's ->remove() is called. So technically you
> could have a situation where drm_of_find_panel_or_bridge() returned some
> error code that remains stored in dsi->bridge and cause the above
> condition to be incorrectly true.

No, because of_drm_find_bridge() (which is called from
drm_of_find_panel_or_bridge() returns either NULL or a valid bridge
pointer), so dsi->bridge either points to a valid bridge object or is
NULL. Am I missing something?
Thierry Reding May 4, 2018, 1:29 p.m. UTC | #5
On Fri, May 04, 2018 at 02:05:25PM +0200, Boris Brezillon wrote:
> On Fri, 4 May 2018 12:28:33 +0200
> Thierry Reding <thierry.reding@gmail.com> wrote:
> 
> > On Thu, May 03, 2018 at 06:40:08PM +0200, Boris Brezillon wrote:
> > > Having a device with a status property != "okay" in the DT is a valid
> > > use case, and we should not prevent the registration of the DRM device
> > > when the DSI device connected to the DSI controller is disabled.
> > > 
> > > Consider the ENODEV return code as a valid result and do not expose the
> > > DSI encoder/connector when it happens.
> > > 
> > > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > > ---
> > >  drivers/gpu/drm/vc4/vc4_dsi.c | 15 +++++++++++++--
> > >  1 file changed, 13 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> > > index 8aa897835118..db2f137f8b7b 100644
> > > --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> > > +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> > > @@ -1606,8 +1606,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
> > >  
> > >  	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
> > >  					  &panel, &dsi->bridge);
> > > -	if (ret)
> > > +	if (ret) {
> > > +		/* If the bridge or panel pointed by dev->of_node is not
> > > +		 * enabled, just return 0 here so that we don't prevent the DRM
> > > +		 * dev from being registered. Of course that means the DSI
> > > +		 * encoder won't be exposed, but that's not a problem since
> > > +		 * nothing is connected to it.
> > > +		 */
> > > +		if (ret == -ENODEV)
> > > +			return 0;
> > > +
> > >  		return ret;
> > > +	}
> > >  
> > >  	if (panel) {
> > >  		dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
> > > @@ -1652,7 +1662,8 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master,
> > >  	struct vc4_dev *vc4 = to_vc4_dev(drm);
> > >  	struct vc4_dsi *dsi = dev_get_drvdata(dev);
> > >  
> > > -	pm_runtime_disable(dev);
> > > +	if (dsi->bridge)
> > > +		pm_runtime_disable(dev);  
> > 
> > Is this safe? This uses component/master, so dsi->bridge is going to
> > remain valid until the driver's ->remove() is called. So technically you
> > could have a situation where drm_of_find_panel_or_bridge() returned some
> > error code that remains stored in dsi->bridge and cause the above
> > condition to be incorrectly true.
> 
> No, because of_drm_find_bridge() (which is called from
> drm_of_find_panel_or_bridge() returns either NULL or a valid bridge
> pointer), so dsi->bridge either points to a valid bridge object or is
> NULL. Am I missing something?

The return value of devm_drm_panel_bridge_add() is also assigned to
dsi->bridge later on (in the "if (panel)" conditional).

Thierry
Boris Brezillon May 4, 2018, 1:49 p.m. UTC | #6
On Fri, 4 May 2018 15:29:15 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Fri, May 04, 2018 at 02:05:25PM +0200, Boris Brezillon wrote:
> > On Fri, 4 May 2018 12:28:33 +0200
> > Thierry Reding <thierry.reding@gmail.com> wrote:
> >   
> > > On Thu, May 03, 2018 at 06:40:08PM +0200, Boris Brezillon wrote:  
> > > > Having a device with a status property != "okay" in the DT is a valid
> > > > use case, and we should not prevent the registration of the DRM device
> > > > when the DSI device connected to the DSI controller is disabled.
> > > > 
> > > > Consider the ENODEV return code as a valid result and do not expose the
> > > > DSI encoder/connector when it happens.
> > > > 
> > > > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > > > ---
> > > >  drivers/gpu/drm/vc4/vc4_dsi.c | 15 +++++++++++++--
> > > >  1 file changed, 13 insertions(+), 2 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> > > > index 8aa897835118..db2f137f8b7b 100644
> > > > --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> > > > +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> > > > @@ -1606,8 +1606,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
> > > >  
> > > >  	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
> > > >  					  &panel, &dsi->bridge);
> > > > -	if (ret)
> > > > +	if (ret) {
> > > > +		/* If the bridge or panel pointed by dev->of_node is not
> > > > +		 * enabled, just return 0 here so that we don't prevent the DRM
> > > > +		 * dev from being registered. Of course that means the DSI
> > > > +		 * encoder won't be exposed, but that's not a problem since
> > > > +		 * nothing is connected to it.
> > > > +		 */
> > > > +		if (ret == -ENODEV)
> > > > +			return 0;
> > > > +
> > > >  		return ret;
> > > > +	}
> > > >  
> > > >  	if (panel) {
> > > >  		dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
> > > > @@ -1652,7 +1662,8 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master,
> > > >  	struct vc4_dev *vc4 = to_vc4_dev(drm);
> > > >  	struct vc4_dsi *dsi = dev_get_drvdata(dev);
> > > >  
> > > > -	pm_runtime_disable(dev);
> > > > +	if (dsi->bridge)
> > > > +		pm_runtime_disable(dev);    
> > > 
> > > Is this safe? This uses component/master, so dsi->bridge is going to
> > > remain valid until the driver's ->remove() is called. So technically you
> > > could have a situation where drm_of_find_panel_or_bridge() returned some
> > > error code that remains stored in dsi->bridge and cause the above
> > > condition to be incorrectly true.  
> > 
> > No, because of_drm_find_bridge() (which is called from
> > drm_of_find_panel_or_bridge() returns either NULL or a valid bridge
> > pointer), so dsi->bridge either points to a valid bridge object or is
> > NULL. Am I missing something?  
> 
> The return value of devm_drm_panel_bridge_add() is also assigned to
> dsi->bridge later on (in the "if (panel)" conditional).

But then we return an error code if IS_ERR(dsi->bridge) [1], which
should prevent the unbind function from being called, right?

[1]https://elixir.bootlin.com/linux/v4.17-rc3/source/drivers/gpu/drm/vc4/vc4_dsi.c#L1610
Thierry Reding May 4, 2018, 1:56 p.m. UTC | #7
On Fri, May 04, 2018 at 03:49:06PM +0200, Boris Brezillon wrote:
> On Fri, 4 May 2018 15:29:15 +0200
> Thierry Reding <thierry.reding@gmail.com> wrote:
> 
> > On Fri, May 04, 2018 at 02:05:25PM +0200, Boris Brezillon wrote:
> > > On Fri, 4 May 2018 12:28:33 +0200
> > > Thierry Reding <thierry.reding@gmail.com> wrote:
> > >   
> > > > On Thu, May 03, 2018 at 06:40:08PM +0200, Boris Brezillon wrote:  
> > > > > Having a device with a status property != "okay" in the DT is a valid
> > > > > use case, and we should not prevent the registration of the DRM device
> > > > > when the DSI device connected to the DSI controller is disabled.
> > > > > 
> > > > > Consider the ENODEV return code as a valid result and do not expose the
> > > > > DSI encoder/connector when it happens.
> > > > > 
> > > > > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > > > > ---
> > > > >  drivers/gpu/drm/vc4/vc4_dsi.c | 15 +++++++++++++--
> > > > >  1 file changed, 13 insertions(+), 2 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> > > > > index 8aa897835118..db2f137f8b7b 100644
> > > > > --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> > > > > +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> > > > > @@ -1606,8 +1606,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
> > > > >  
> > > > >  	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
> > > > >  					  &panel, &dsi->bridge);
> > > > > -	if (ret)
> > > > > +	if (ret) {
> > > > > +		/* If the bridge or panel pointed by dev->of_node is not
> > > > > +		 * enabled, just return 0 here so that we don't prevent the DRM
> > > > > +		 * dev from being registered. Of course that means the DSI
> > > > > +		 * encoder won't be exposed, but that's not a problem since
> > > > > +		 * nothing is connected to it.
> > > > > +		 */
> > > > > +		if (ret == -ENODEV)
> > > > > +			return 0;
> > > > > +
> > > > >  		return ret;
> > > > > +	}
> > > > >  
> > > > >  	if (panel) {
> > > > >  		dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
> > > > > @@ -1652,7 +1662,8 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master,
> > > > >  	struct vc4_dev *vc4 = to_vc4_dev(drm);
> > > > >  	struct vc4_dsi *dsi = dev_get_drvdata(dev);
> > > > >  
> > > > > -	pm_runtime_disable(dev);
> > > > > +	if (dsi->bridge)
> > > > > +		pm_runtime_disable(dev);    
> > > > 
> > > > Is this safe? This uses component/master, so dsi->bridge is going to
> > > > remain valid until the driver's ->remove() is called. So technically you
> > > > could have a situation where drm_of_find_panel_or_bridge() returned some
> > > > error code that remains stored in dsi->bridge and cause the above
> > > > condition to be incorrectly true.  
> > > 
> > > No, because of_drm_find_bridge() (which is called from
> > > drm_of_find_panel_or_bridge() returns either NULL or a valid bridge
> > > pointer), so dsi->bridge either points to a valid bridge object or is
> > > NULL. Am I missing something?  
> > 
> > The return value of devm_drm_panel_bridge_add() is also assigned to
> > dsi->bridge later on (in the "if (panel)" conditional).
> 
> But then we return an error code if IS_ERR(dsi->bridge) [1], which
> should prevent the unbind function from being called, right?

Right, that should work. Seems safe, then.

Thierry
diff mbox

Patch

diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index 8aa897835118..db2f137f8b7b 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -1606,8 +1606,18 @@  static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
 
 	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
 					  &panel, &dsi->bridge);
-	if (ret)
+	if (ret) {
+		/* If the bridge or panel pointed by dev->of_node is not
+		 * enabled, just return 0 here so that we don't prevent the DRM
+		 * dev from being registered. Of course that means the DSI
+		 * encoder won't be exposed, but that's not a problem since
+		 * nothing is connected to it.
+		 */
+		if (ret == -ENODEV)
+			return 0;
+
 		return ret;
+	}
 
 	if (panel) {
 		dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
@@ -1652,7 +1662,8 @@  static void vc4_dsi_unbind(struct device *dev, struct device *master,
 	struct vc4_dev *vc4 = to_vc4_dev(drm);
 	struct vc4_dsi *dsi = dev_get_drvdata(dev);
 
-	pm_runtime_disable(dev);
+	if (dsi->bridge)
+		pm_runtime_disable(dev);
 
 	vc4_dsi_encoder_destroy(dsi->encoder);