All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/6] drm/panel: Handle the "panel is missing" case properly
@ 2018-05-03 16:40 Boris Brezillon
  2018-05-03 16:40   ` Boris Brezillon
                   ` (5 more replies)
  0 siblings, 6 replies; 32+ messages in thread
From: Boris Brezillon @ 2018-05-03 16:40 UTC (permalink / raw)
  To: David Airlie, Daniel Vetter, dri-devel, Thierry Reding,
	Eric Anholt, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree
  Cc: Boris Brezillon

Hello,

This is a new attempt at fixing the "panel is missing" issue (described
in this thread [1]). I lost track of Eric's proposal, but I recently
proposed to address this problem through a new ->detect() hook in the
panel_funcs interface [2], which was rejected.

So here is a new version based on the feedback I had from Daniel,
Thierry and Rob.

The idea is to allow of_drm_find_panel() to return -ENODEV and let the
DRM driver decide what to do with that (silently ignore the missing
component and register the DRM device, or fail to register the DRM
device).

Patch 1 is just a fix for an OF node ref leak I found in the tegra
driver while working on this patch series. It can be applied
independently but I send it here since patch 2 depends on it.

Patch 2 changes the semantic of of_drm_find_panel() so that it returns
an ERR_PTR() instead of NULL when the panel is not found. This way
we'll be able to differentiate the "panel is missing" from "panel has
not been probed yet" errors.

Patch 3 and 4 are adding new tests in of_drm_find_panel() and
drm_of_find_panel_or_bridge() to return -ENODEV when the status
property of the DT node is not set to "okay".

Patch 5 is patching the VC4 DSI encoder driver to gracefully handle the
-ENODEV case and allow the registration of the DRM device when the DSI
device is disabled.

And finally, patch 6 is modifying the rpi-touchscreen panel driver to
update the status property of the DT node when the device is not
reachable on the I2C bus. This way, the DSI encoder driver will get an
-ENODEV and the DRM device will be registered even if the DSI panel
is not connected.
Note that the status prop update is currently done in the I2C driver
instead of the I2C or device-model core because I think modifying the
behavior for all I2C devices (or all devices) is too risky.

Feel free to comment on this implementation

Thanks,

Boris

Changes since v1:
- Everything :-)

[1]https://lists.freedesktop.org/archives/dri-devel/2017-November/157688.html
[2]https://www.spinics.net/lists/dri-devel/msg174808.html

Boris Brezillon (6):
  drm/tegra: Fix a device_node leak when the DRM panel is not found
  drm/panel: Make of_drm_find_panel() return an ERR_PTR() instead of
    NULL
  drm/panel: Let of_drm_find_panel() return -ENODEV when the panel is
    disabled
  drm/of: Make drm_of_find_panel_or_bridge() fail when the device is
    disabled
  drm/vc4: Support the case where the DSI device is disabled
  drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails

 drivers/gpu/drm/bridge/cdns-dsi.c                  |  2 +-
 drivers/gpu/drm/bridge/lvds-encoder.c              |  4 +--
 drivers/gpu/drm/drm_of.c                           | 13 ++++++--
 drivers/gpu/drm/drm_panel.c                        | 11 +++++--
 drivers/gpu/drm/exynos/exynos_dp.c                 |  9 ++++--
 drivers/gpu/drm/exynos/exynos_drm_dpi.c            |  9 ++++--
 drivers/gpu/drm/exynos/exynos_drm_dsi.c            |  6 ++--
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c          |  8 +++--
 drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c  |  4 +--
 .../gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c    | 10 +++++--
 drivers/gpu/drm/msm/dsi/dsi_host.c                 |  2 +-
 .../gpu/drm/panel/panel-raspberrypi-touchscreen.c  | 35 ++++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_lvds.c                |  9 ++++--
 drivers/gpu/drm/rockchip/dw-mipi-dsi.c             |  2 +-
 drivers/gpu/drm/sti/sti_dvo.c                      |  7 +++--
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c             |  4 +--
 drivers/gpu/drm/tegra/dsi.c                        |  6 ++--
 drivers/gpu/drm/tegra/output.c                     | 17 ++++++-----
 drivers/gpu/drm/vc4/vc4_dsi.c                      | 15 ++++++++--
 include/drm/drm_panel.h                            |  2 +-
 20 files changed, 131 insertions(+), 44 deletions(-)

-- 
2.14.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v2 1/6] drm/tegra: Fix a device_node leak when the DRM panel is not found
  2018-05-03 16:40 [PATCH v2 0/6] drm/panel: Handle the "panel is missing" case properly Boris Brezillon
@ 2018-05-03 16:40   ` Boris Brezillon
  2018-05-03 16:40 ` [PATCH v2 2/6] drm/panel: Make of_drm_find_panel() return an ERR_PTR() instead of NULL Boris Brezillon
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 32+ messages in thread
From: Boris Brezillon @ 2018-05-03 16:40 UTC (permalink / raw)
  To: David Airlie, Daniel Vetter, dri-devel, Thierry Reding,
	Eric Anholt, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree
  Cc: Boris Brezillon, stable

of_node_put(panel) is not called when of_drm_find_panel(panel) returns
NULL, thus leaking the reference we hold on panel.

Fixes: 9be7d864cf07 ("drm/tegra: Implement panel support")
Cc: <stable@vger.kernel.org>
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
---
 drivers/gpu/drm/tegra/output.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index ffe34bd0bb9d..676fd394836f 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -110,10 +110,9 @@ int tegra_output_probe(struct tegra_output *output)
 	panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
 	if (panel) {
 		output->panel = of_drm_find_panel(panel);
+		of_node_put(panel);
 		if (!output->panel)
 			return -EPROBE_DEFER;
-
-		of_node_put(panel);
 	}
 
 	output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
-- 
2.14.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v2 1/6] drm/tegra: Fix a device_node leak when the DRM panel is not found
@ 2018-05-03 16:40   ` Boris Brezillon
  0 siblings, 0 replies; 32+ messages in thread
From: Boris Brezillon @ 2018-05-03 16:40 UTC (permalink / raw)
  To: David Airlie, Daniel Vetter, dri-devel, Thierry Reding,
	Eric Anholt, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree
  Cc: Boris Brezillon, stable

of_node_put(panel) is not called when of_drm_find_panel(panel) returns
NULL, thus leaking the reference we hold on panel.

Fixes: 9be7d864cf07 ("drm/tegra: Implement panel support")
Cc: <stable@vger.kernel.org>
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
---
 drivers/gpu/drm/tegra/output.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index ffe34bd0bb9d..676fd394836f 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -110,10 +110,9 @@ int tegra_output_probe(struct tegra_output *output)
 	panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
 	if (panel) {
 		output->panel = of_drm_find_panel(panel);
+		of_node_put(panel);
 		if (!output->panel)
 			return -EPROBE_DEFER;
-
-		of_node_put(panel);
 	}
 
 	output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
-- 
2.14.1

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

* [PATCH v2 2/6] drm/panel: Make of_drm_find_panel() return an ERR_PTR() instead of NULL
  2018-05-03 16:40 [PATCH v2 0/6] drm/panel: Handle the "panel is missing" case properly Boris Brezillon
  2018-05-03 16:40   ` Boris Brezillon
@ 2018-05-03 16:40 ` Boris Brezillon
  2018-05-04 10:18   ` Thierry Reding
  2018-05-03 16:40 ` [PATCH v2 3/6] drm/panel: Let of_drm_find_panel() return -ENODEV when the panel is disabled Boris Brezillon
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2018-05-03 16:40 UTC (permalink / raw)
  To: David Airlie, Daniel Vetter, dri-devel, Thierry Reding,
	Eric Anholt, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree
  Cc: Boris Brezillon

Right now, the DRM panel logic returns NULL when a panel pointing to
the passed OF node is not present in the list of registered panels.

Most drivers interpret this NULL value as -EPROBE_DEFER, but we are
about to modify the semantic of of_drm_find_panel() and let the
framework return -ENODEV when the device node we're pointing to has
a status property that is not equal to "okay" or "ok".

Let's first patch the of_drm_find_panel() implementation to return
ERR_PTR(-EPROBE_DEFER) instead of NULL and patch all callers to replace
the '!panel' check by an 'IS_ERR(panel)' one.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
---
 drivers/gpu/drm/bridge/cdns-dsi.c                   |  2 +-
 drivers/gpu/drm/bridge/lvds-encoder.c               |  4 ++--
 drivers/gpu/drm/drm_of.c                            |  8 ++++++--
 drivers/gpu/drm/drm_panel.c                         |  6 ++++--
 drivers/gpu/drm/exynos/exynos_dp.c                  |  9 ++++++---
 drivers/gpu/drm/exynos/exynos_drm_dpi.c             |  9 ++++++---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c             |  6 ++++--
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c           |  8 +++++---
 drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c   |  4 ++--
 drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c | 10 +++++++---
 drivers/gpu/drm/msm/dsi/dsi_host.c                  |  2 +-
 drivers/gpu/drm/rcar-du/rcar_lvds.c                 |  9 ++++++---
 drivers/gpu/drm/rockchip/dw-mipi-dsi.c              |  2 +-
 drivers/gpu/drm/sti/sti_dvo.c                       |  7 +++++--
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c              |  4 ++--
 drivers/gpu/drm/tegra/dsi.c                         |  6 ++++--
 drivers/gpu/drm/tegra/output.c                      | 18 +++++++++++-------
 include/drm/drm_panel.h                             |  2 +-
 18 files changed, 74 insertions(+), 42 deletions(-)

diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c
index c255fc3e1be5..2c5991cf5397 100644
--- a/drivers/gpu/drm/bridge/cdns-dsi.c
+++ b/drivers/gpu/drm/bridge/cdns-dsi.c
@@ -1152,7 +1152,7 @@ static int cdns_dsi_attach(struct mipi_dsi_host *host,
 		np = of_node_get(dev->dev.of_node);
 
 	panel = of_drm_find_panel(np);
-	if (panel) {
+	if (!IS_ERR(panel)) {
 		bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI);
 	} else {
 		bridge = of_drm_find_bridge(dev->dev.of_node);
diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c
index 75b0d3f6e4de..f56c92f7af7c 100644
--- a/drivers/gpu/drm/bridge/lvds-encoder.c
+++ b/drivers/gpu/drm/bridge/lvds-encoder.c
@@ -68,9 +68,9 @@ static int lvds_encoder_probe(struct platform_device *pdev)
 
 	panel = of_drm_find_panel(panel_node);
 	of_node_put(panel_node);
-	if (!panel) {
+	if (IS_ERR(panel)) {
 		dev_dbg(&pdev->dev, "panel not found, deferring probe\n");
-		return -EPROBE_DEFER;
+		return PTR_ERR(panel);
 	}
 
 	lvds_encoder->panel_bridge =
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index 1fe122461298..f413fae6f6dc 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -239,9 +239,13 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
 		return -ENODEV;
 
 	if (panel) {
-		*panel = of_drm_find_panel(remote);
-		if (*panel)
+		struct drm_panel *tmp_panel;
+
+		tmp_panel = of_drm_find_panel(remote);
+		if (!IS_ERR(tmp_panel)) {
+			*panel = tmp_panel;
 			ret = 0;
+		}
 	}
 
 	/* No panel found yet, check for a bridge next. */
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index 308d442a531b..2d9e2684c6c8 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -135,7 +135,9 @@ EXPORT_SYMBOL(drm_panel_detach);
  * tree node. If a matching panel is found, return a pointer to it.
  *
  * Return: A pointer to the panel registered for the specified device tree
- * node or NULL if no panel matching the device tree node can be found.
+ * node or an ERR_PTR() if no panel matching the device tree node can be found.
+ * The only error that can be reported is -EPROBE_DEFER, meaning that the panel
+ * device has not been probed yet, and the caller should re-retry later.
  */
 struct drm_panel *of_drm_find_panel(const struct device_node *np)
 {
@@ -151,7 +153,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
 	}
 
 	mutex_unlock(&panel_lock);
-	return NULL;
+	return ERR_PTR(-EPROBE_DEFER);
 }
 EXPORT_SYMBOL(of_drm_find_panel);
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 86330f396784..962cad0276e5 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -231,10 +231,13 @@ static int exynos_dp_probe(struct platform_device *pdev)
 	/* This is for the backward compatibility. */
 	np = of_parse_phandle(dev->of_node, "panel", 0);
 	if (np) {
-		dp->plat_data.panel = of_drm_find_panel(np);
+		struct drm_panel *panel = of_drm_find_panel(np);
+
 		of_node_put(np);
-		if (!dp->plat_data.panel)
-			return -EPROBE_DEFER;
+		if (IS_ERR(panel))
+			return PTR_ERR(panel);
+
+		dp->plat_data.panel = panel;
 		goto out;
 	}
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index 66945e0dc57f..e9c7d1c1cf8f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -239,9 +239,12 @@ struct drm_encoder *exynos_dpi_probe(struct device *dev)
 	}
 
 	if (ctx->panel_node) {
-		ctx->panel = of_drm_find_panel(ctx->panel_node);
-		if (!ctx->panel)
-			return ERR_PTR(-EPROBE_DEFER);
+		struct drm_panel *panel = of_drm_find_panel(ctx->panel_node);
+
+		if (IS_ERR(panel))
+			return ERR_CAST(panel);
+
+		ctx->panel = panel;
 	}
 
 	return &ctx->encoder;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 7904ffa9abfb..96206deb86a0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1520,6 +1520,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
 {
 	struct exynos_dsi *dsi = host_to_dsi(host);
 	struct drm_device *drm = dsi->connector.dev;
+	struct drm_panel *panel;
 
 	/*
 	 * This is a temporary solution and should be made by more generic way.
@@ -1538,8 +1539,9 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
 	dsi->lanes = device->lanes;
 	dsi->format = device->format;
 	dsi->mode_flags = device->mode_flags;
-	dsi->panel = of_drm_find_panel(device->dev.of_node);
-	if (dsi->panel) {
+	panel = of_drm_find_panel(device->dev.of_node);
+	if (!IS_ERR(panel)) {
+		dsi->panel = panel;
 		drm_panel_attach(dsi->panel, &dsi->connector);
 		dsi->connector.status = connector_status_connected;
 	}
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
index c54806d08dd7..7753b3093472 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
@@ -146,10 +146,12 @@ int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
 	/* This is for backward compatibility */
 	panel_node = of_parse_phandle(fsl_dev->np, "fsl,panel", 0);
 	if (panel_node) {
-		fsl_dev->connector.panel = of_drm_find_panel(panel_node);
+		panel = of_drm_find_panel(panel_node);
 		of_node_put(panel_node);
-		if (!fsl_dev->connector.panel)
-			return -EPROBE_DEFER;
+		if (IS_ERR(panel))
+			return PTR_ERR(panel);
+
+		fsl_dev->connector.panel = panel;
 		return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel);
 	}
 
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
index 4a645926edb7..2bfb39082f54 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
@@ -341,7 +341,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
 	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
 
 	panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
-	if (panel) {
+	if (!IS_ERR(panel)) {
 		drm_panel_disable(panel);
 		drm_panel_unprepare(panel);
 	}
@@ -410,7 +410,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
 		dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
 
 	panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
-	if (panel) {
+	if (!IS_ERR(panel)) {
 		drm_panel_prepare(panel);
 		drm_panel_enable(panel);
 	}
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
index e3b1c86b7aae..c7dd72b428f8 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
@@ -34,9 +34,13 @@ static enum drm_connector_status mdp4_lvds_connector_detect(
 	struct mdp4_lvds_connector *mdp4_lvds_connector =
 			to_mdp4_lvds_connector(connector);
 
-	if (!mdp4_lvds_connector->panel)
-		mdp4_lvds_connector->panel =
-			of_drm_find_panel(mdp4_lvds_connector->panel_node);
+	if (!mdp4_lvds_connector->panel) {
+		struct drm_panel *panel;
+
+		panel = of_drm_find_panel(mdp4_lvds_connector->panel_node);
+		if (!IS_ERR(panel))
+			mdp4_lvds_connector->panel = panel;
+	}
 
 	return mdp4_lvds_connector->panel ?
 			connector_status_connected :
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 7a03a9489708..fffc80b73966 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -1881,7 +1881,7 @@ int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer)
 		 * output
 		 */
 		if (check_defer && msm_host->device_node) {
-			if (!of_drm_find_panel(msm_host->device_node))
+			if (IS_ERR(of_drm_find_panel(msm_host->device_node)))
 				if (!of_drm_find_bridge(msm_host->device_node))
 					return -EPROBE_DEFER;
 		}
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
index 3d2d3bbd1342..d77b8f8bcf94 100644
--- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
@@ -430,9 +430,12 @@ static int rcar_lvds_parse_dt(struct rcar_lvds *lvds)
 		if (!lvds->next_bridge)
 			ret = -EPROBE_DEFER;
 	} else {
-		lvds->panel = of_drm_find_panel(remote);
-		if (!lvds->panel)
-			ret = -EPROBE_DEFER;
+		struct drm_panel *panel = of_drm_find_panel(remote);
+
+		if (IS_ERR(panel))
+			ret = PTR_ERR(panel);
+		else
+			lvds->panel = panel;
 	}
 
 done:
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index d53d5a09547f..01642aaf6127 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -595,7 +595,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
 	dsi->format = device->format;
 	dsi->mode_flags = device->mode_flags;
 	dsi->panel = of_drm_find_panel(device->dev.of_node);
-	if (dsi->panel)
+	if (!IS_ERR(dsi->panel))
 		return drm_panel_attach(dsi->panel, &dsi->connector);
 
 	return -EINVAL;
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
index a5979cd25cc7..3579c0e1ca1c 100644
--- a/drivers/gpu/drm/sti/sti_dvo.c
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -386,9 +386,12 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force)
 	DRM_DEBUG_DRIVER("\n");
 
 	if (!dvo->panel) {
-		dvo->panel = of_drm_find_panel(dvo->panel_node);
-		if (dvo->panel)
+		struct drm_panel *panel = of_drm_find_panel(dvo->panel_node);
+
+		if (!IS_ERR(panel)) {
+			dvo->panel = panel;
 			drm_panel_attach(dvo->panel, connector);
+		}
 	}
 
 	if (dvo->panel)
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index bfbf761f0c1d..ce388d7cebaa 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -812,8 +812,8 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
 
 	dsi->device = device;
 	dsi->panel = of_drm_find_panel(device->dev.of_node);
-	if (!dsi->panel)
-		return -EINVAL;
+	if (IS_ERR(dsi->panel))
+		return PTR_ERR(dsi->panel);
 
 	dev_info(host->dev, "Attached device %s\n", device->name);
 
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index 87c5d89bc9ba..0b1eee4b2fb1 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -1409,9 +1409,11 @@ static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
 	 */
 	if (!dsi->master) {
 		struct tegra_output *output = &dsi->output;
+		struct drm_panel *panel;
 
-		output->panel = of_drm_find_panel(device->dev.of_node);
-		if (output->panel && output->connector.dev) {
+		panel = of_drm_find_panel(device->dev.of_node);
+		if (!IS_ERR(panel) && output->connector.dev) {
+			output->panel = panel;
 			drm_panel_attach(output->panel, &output->connector);
 			drm_helper_hpd_irq_event(output->connector.dev);
 		}
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index 676fd394836f..21d8737f8b49 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -101,18 +101,22 @@ static irqreturn_t hpd_irq(int irq, void *data)
 
 int tegra_output_probe(struct tegra_output *output)
 {
-	struct device_node *ddc, *panel;
+	struct device_node *ddc, *panelnp;
 	int err, size;
 
 	if (!output->of_node)
 		output->of_node = output->dev->of_node;
 
-	panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
-	if (panel) {
-		output->panel = of_drm_find_panel(panel);
-		of_node_put(panel);
-		if (!output->panel)
-			return -EPROBE_DEFER;
+	panelnp = of_parse_phandle(output->of_node, "nvidia,panel", 0);
+	if (panelnp) {
+		struct drm_panel *panel = of_drm_find_panel(panelnp);
+
+		of_node_put(panelnp);
+
+		if (IS_ERR(panel))
+			return PTR_ERR(panel);
+
+		output->panel = panel;
 	}
 
 	output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 14ac240a1f64..3bb91519462e 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -199,7 +199,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np);
 #else
 static inline struct drm_panel *of_drm_find_panel(const struct device_node *np)
 {
-	return NULL;
+	return ERR_PTR(-ENOTSUPP);
 }
 #endif
 
-- 
2.14.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v2 3/6] drm/panel: Let of_drm_find_panel() return -ENODEV when the panel is disabled
  2018-05-03 16:40 [PATCH v2 0/6] drm/panel: Handle the "panel is missing" case properly Boris Brezillon
  2018-05-03 16:40   ` Boris Brezillon
  2018-05-03 16:40 ` [PATCH v2 2/6] drm/panel: Make of_drm_find_panel() return an ERR_PTR() instead of NULL Boris Brezillon
@ 2018-05-03 16:40 ` Boris Brezillon
  2018-05-04 10:20   ` Thierry Reding
  2018-05-03 16:40 ` [PATCH v2 4/6] drm/of: Make drm_of_find_panel_or_bridge() fail when the device " Boris Brezillon
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2018-05-03 16:40 UTC (permalink / raw)
  To: David Airlie, Daniel Vetter, dri-devel, Thierry Reding,
	Eric Anholt, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree
  Cc: Boris Brezillon

DT nodes might be present in the DT but with a status property set to
"disabled" or "fail". In this case, we should not return -EPROBE_DEFER
when the caller ask for a drm_panel instance. Return -ENODEV instead.

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

diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index 2d9e2684c6c8..15df28d20194 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -136,13 +136,18 @@ EXPORT_SYMBOL(drm_panel_detach);
  *
  * Return: A pointer to the panel registered for the specified device tree
  * node or an ERR_PTR() if no panel matching the device tree node can be found.
- * The only error that can be reported is -EPROBE_DEFER, meaning that the panel
- * device has not been probed yet, and the caller should re-retry later.
+ * Possible error codes returned by this function:
+ * - EPROBE_DEFER: the panel device has not been probed yet, and the caller
+ *   should re-retry later
+ * - ENODEV: the device is not available (status != "okay" or "ok")
  */
 struct drm_panel *of_drm_find_panel(const struct device_node *np)
 {
 	struct drm_panel *panel;
 
+	if (!of_device_is_available(np))
+		return ERR_PTR(-ENODEV);
+
 	mutex_lock(&panel_lock);
 
 	list_for_each_entry(panel, &panel_list, list) {
-- 
2.14.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v2 4/6] drm/of: Make drm_of_find_panel_or_bridge() fail when the device is disabled
  2018-05-03 16:40 [PATCH v2 0/6] drm/panel: Handle the "panel is missing" case properly Boris Brezillon
                   ` (2 preceding siblings ...)
  2018-05-03 16:40 ` [PATCH v2 3/6] drm/panel: Let of_drm_find_panel() return -ENODEV when the panel is disabled Boris Brezillon
@ 2018-05-03 16:40 ` Boris Brezillon
  2018-05-04 10:20   ` Thierry Reding
  2018-05-03 16:40 ` [PATCH v2 5/6] drm/vc4: Support the case where the DSI " Boris Brezillon
  2018-05-03 16:40 ` [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails Boris Brezillon
  5 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2018-05-03 16:40 UTC (permalink / raw)
  To: David Airlie, Daniel Vetter, dri-devel, Thierry Reding,
	Eric Anholt, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree
  Cc: Boris Brezillon

There's no point searching for a drm_bridge or drm_panel if the OF node
we're pointing has a status property that is not "okay" or "ok". Just
return -ENODEV in this case.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
---
 drivers/gpu/drm/drm_of.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index f413fae6f6dc..f8c1da95c63f 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -238,6 +238,11 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
 	if (!remote)
 		return -ENODEV;
 
+	if (!of_device_is_available(remote)) {
+		of_node_put(remote);
+		return -ENODEV;
+	}
+
 	if (panel) {
 		struct drm_panel *tmp_panel;
 
-- 
2.14.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v2 5/6] drm/vc4: Support the case where the DSI device is disabled
  2018-05-03 16:40 [PATCH v2 0/6] drm/panel: Handle the "panel is missing" case properly Boris Brezillon
                   ` (3 preceding siblings ...)
  2018-05-03 16:40 ` [PATCH v2 4/6] drm/of: Make drm_of_find_panel_or_bridge() fail when the device " Boris Brezillon
@ 2018-05-03 16:40 ` Boris Brezillon
  2018-05-04 10:28   ` Thierry Reding
  2018-05-04 10:30   ` Thierry Reding
  2018-05-03 16:40 ` [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails Boris Brezillon
  5 siblings, 2 replies; 32+ messages in thread
From: Boris Brezillon @ 2018-05-03 16:40 UTC (permalink / raw)
  To: David Airlie, Daniel Vetter, dri-devel, Thierry Reding,
	Eric Anholt, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree
  Cc: Boris Brezillon

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);
 
 	vc4_dsi_encoder_destroy(dsi->encoder);
 
-- 
2.14.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails
  2018-05-03 16:40 [PATCH v2 0/6] drm/panel: Handle the "panel is missing" case properly Boris Brezillon
                   ` (4 preceding siblings ...)
  2018-05-03 16:40 ` [PATCH v2 5/6] drm/vc4: Support the case where the DSI " Boris Brezillon
@ 2018-05-03 16:40 ` Boris Brezillon
  2018-05-03 17:12   ` Rob Herring
  5 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2018-05-03 16:40 UTC (permalink / raw)
  To: David Airlie, Daniel Vetter, dri-devel, Thierry Reding,
	Eric Anholt, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree
  Cc: Boris Brezillon

The device might be described in the device tree but not connected to
the I2C bus. Update the status property so that the DRM panel logic
returns -ENODEV when someone tries to get the panel attached to this
DT node.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
---
 .../gpu/drm/panel/panel-raspberrypi-touchscreen.c  | 35 ++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
index 2c9c9722734f..b8fcb1acef75 100644
--- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
+++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
@@ -358,6 +358,39 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = {
 	.get_modes = rpi_touchscreen_get_modes,
 };
 
+static void rpi_touchscreen_set_status_fail(struct i2c_client *i2c)
+{
+	struct property *newprop;
+
+	newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
+	if (!newprop)
+		return;
+
+	newprop->name = kstrdup("status", GFP_KERNEL);
+	if (!newprop->name)
+		goto err;
+
+	newprop->value = kstrdup("fail", GFP_KERNEL);
+	if (!newprop->value)
+		goto err;
+
+	newprop->length = sizeof("fail");
+
+	if (of_update_property(i2c->dev.of_node, newprop))
+		goto err;
+
+	/* We intentionally leak the memory we allocate here, because the new
+	 * OF property might live longer than the underlying dev, so no way
+	 * we can use devm_kzalloc() here.
+	 */
+	return;
+
+err:
+	kfree(newprop->value);
+	kfree(newprop->name);
+	kfree(newprop);
+}
+
 static int rpi_touchscreen_probe(struct i2c_client *i2c,
 				 const struct i2c_device_id *id)
 {
@@ -382,6 +415,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
 
 	ver = rpi_touchscreen_i2c_read(ts, REG_ID);
 	if (ver < 0) {
+		rpi_touchscreen_set_status_fail(i2c);
 		dev_err(dev, "Atmel I2C read failed: %d\n", ver);
 		return -ENODEV;
 	}
@@ -391,6 +425,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
 	case 0xc3: /* ver 2 */
 		break;
 	default:
+		rpi_touchscreen_set_status_fail(i2c);
 		dev_err(dev, "Unknown Atmel firmware revision: 0x%02x\n", ver);
 		return -ENODEV;
 	}
-- 
2.14.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails
  2018-05-03 16:40 ` [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails Boris Brezillon
@ 2018-05-03 17:12   ` Rob Herring
  2018-05-04  8:06     ` Boris Brezillon
  0 siblings, 1 reply; 32+ messages in thread
From: Rob Herring @ 2018-05-03 17:12 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Thierry Reding, Kumar Gala

On Thu, May 3, 2018 at 11:40 AM, Boris Brezillon
<boris.brezillon@bootlin.com> wrote:
> The device might be described in the device tree but not connected to
> the I2C bus. Update the status property so that the DRM panel logic
> returns -ENODEV when someone tries to get the panel attached to this
> DT node.
>
> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> ---
>  .../gpu/drm/panel/panel-raspberrypi-touchscreen.c  | 35 ++++++++++++++++++++++
>  1 file changed, 35 insertions(+)
>
> diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> index 2c9c9722734f..b8fcb1acef75 100644
> --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> @@ -358,6 +358,39 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = {
>         .get_modes = rpi_touchscreen_get_modes,
>  };
>
> +static void rpi_touchscreen_set_status_fail(struct i2c_client *i2c)
> +{
> +       struct property *newprop;
> +
> +       newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
> +       if (!newprop)
> +               return;
> +
> +       newprop->name = kstrdup("status", GFP_KERNEL);
> +       if (!newprop->name)
> +               goto err;
> +
> +       newprop->value = kstrdup("fail", GFP_KERNEL);
> +       if (!newprop->value)
> +               goto err;
> +
> +       newprop->length = sizeof("fail");
> +
> +       if (of_update_property(i2c->dev.of_node, newprop))
> +               goto err;
> +

As I mentioned on irc, can you make this a common DT function.

I'm not sure if it matters that we set status to fail vs. disabled. I
somewhat prefer the latter as we already have other cases and I'd
rather the api not pass a string in. I can't think of any reason to
distinguish the difference between fail and disabled.

> +       /* We intentionally leak the memory we allocate here, because the new
> +        * OF property might live longer than the underlying dev, so no way
> +        * we can use devm_kzalloc() here.
> +        */
> +       return;
> +
> +err:
> +       kfree(newprop->value);
> +       kfree(newprop->name);
> +       kfree(newprop);
> +}
> +
>  static int rpi_touchscreen_probe(struct i2c_client *i2c,
>                                  const struct i2c_device_id *id)
>  {
> @@ -382,6 +415,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
>
>         ver = rpi_touchscreen_i2c_read(ts, REG_ID);
>         if (ver < 0) {
> +               rpi_touchscreen_set_status_fail(i2c);

I've thought some more about this and I still think this should be
handled in the driver core or i2c core.

The reason is simple. I think the state of the system should be the
same after this as if you booted with 'status = "disabled"' for this
node. And that means the device should be removed completely because
we don't create struct device's for disabled nodes.

Rob
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails
  2018-05-03 17:12   ` Rob Herring
@ 2018-05-04  8:06     ` Boris Brezillon
  2018-05-04  9:47       ` Thierry Reding
  0 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2018-05-04  8:06 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Thierry Reding, Kumar Gala

Hi Rob,

On Thu, 3 May 2018 12:12:39 -0500
Rob Herring <robh+dt@kernel.org> wrote:

> On Thu, May 3, 2018 at 11:40 AM, Boris Brezillon
> <boris.brezillon@bootlin.com> wrote:
> > The device might be described in the device tree but not connected to
> > the I2C bus. Update the status property so that the DRM panel logic
> > returns -ENODEV when someone tries to get the panel attached to this
> > DT node.
> >
> > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > ---
> >  .../gpu/drm/panel/panel-raspberrypi-touchscreen.c  | 35 ++++++++++++++++++++++
> >  1 file changed, 35 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > index 2c9c9722734f..b8fcb1acef75 100644
> > --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > @@ -358,6 +358,39 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = {
> >         .get_modes = rpi_touchscreen_get_modes,
> >  };
> >
> > +static void rpi_touchscreen_set_status_fail(struct i2c_client *i2c)
> > +{
> > +       struct property *newprop;
> > +
> > +       newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
> > +       if (!newprop)
> > +               return;
> > +
> > +       newprop->name = kstrdup("status", GFP_KERNEL);
> > +       if (!newprop->name)
> > +               goto err;
> > +
> > +       newprop->value = kstrdup("fail", GFP_KERNEL);
> > +       if (!newprop->value)
> > +               goto err;
> > +
> > +       newprop->length = sizeof("fail");
> > +
> > +       if (of_update_property(i2c->dev.of_node, newprop))
> > +               goto err;
> > +  
> 
> As I mentioned on irc, can you make this a common DT function.

Yep, will move that to drivers/of/base.c and make it generic.

> 
> I'm not sure if it matters that we set status to fail vs. disabled. I
> somewhat prefer the latter as we already have other cases and I'd
> rather the api not pass a string in. I can't think of any reason to
> distinguish the difference between fail and disabled.

Well, I just read the ePAPR doc pointed by Thierry [1] (section 2.3.4),
and "fail" seemed like a good match for what we are trying to express
here: "we failed to communicate with the device in the probe function
and want to mark it unusable", which is a bit different from "the
device was explicitly disabled by the user".

Anyway, if you think "disabled" is more appropriate, I'll use that.

> 
> > +       /* We intentionally leak the memory we allocate here, because the new
> > +        * OF property might live longer than the underlying dev, so no way
> > +        * we can use devm_kzalloc() here.
> > +        */
> > +       return;
> > +
> > +err:
> > +       kfree(newprop->value);
> > +       kfree(newprop->name);
> > +       kfree(newprop);
> > +}
> > +
> >  static int rpi_touchscreen_probe(struct i2c_client *i2c,
> >                                  const struct i2c_device_id *id)
> >  {
> > @@ -382,6 +415,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
> >
> >         ver = rpi_touchscreen_i2c_read(ts, REG_ID);
> >         if (ver < 0) {
> > +               rpi_touchscreen_set_status_fail(i2c);  
> 
> I've thought some more about this and I still think this should be
> handled in the driver core or i2c core.
> 
> The reason is simple. I think the state of the system should be the
> same after this as if you booted with 'status = "disabled"' for this
> node. And that means the device should be removed completely because
> we don't create struct device's for disabled nodes.

That was my feeling to when first discussing the issue with Daniel and
Thierry on IRC, but after digging a bit in the code I'm no longer sure
this is a good idea. At least, I don't think basing the decision to
disable the device (or mark it unusable) based on the return value of
the probe function is a good idea. What I can do is:

1/ provide a function to change the status prop in of.h
2/ let each driver call this function if they want to
3/ let the I2C core test the status prop again after the probe function
   has returned an error to determine whether the device (I mean struct
   i2c_client/device object) should be removed

Would that work for you?

Regards,

Boris

[1]https://elinux.org/images/c/cf/Power_ePAPR_APPROVED_v1.1.pdf
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails
  2018-05-04  8:06     ` Boris Brezillon
@ 2018-05-04  9:47       ` Thierry Reding
  2018-05-04 12:17         ` Boris Brezillon
  0 siblings, 1 reply; 32+ messages in thread
From: Thierry Reding @ 2018-05-04  9:47 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 4728 bytes --]

On Fri, May 04, 2018 at 10:06:53AM +0200, Boris Brezillon wrote:
> Hi Rob,
> 
> On Thu, 3 May 2018 12:12:39 -0500
> Rob Herring <robh+dt@kernel.org> wrote:
> 
> > On Thu, May 3, 2018 at 11:40 AM, Boris Brezillon
> > <boris.brezillon@bootlin.com> wrote:
> > > The device might be described in the device tree but not connected to
> > > the I2C bus. Update the status property so that the DRM panel logic
> > > returns -ENODEV when someone tries to get the panel attached to this
> > > DT node.
> > >
> > > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > > ---
> > >  .../gpu/drm/panel/panel-raspberrypi-touchscreen.c  | 35 ++++++++++++++++++++++
> > >  1 file changed, 35 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > index 2c9c9722734f..b8fcb1acef75 100644
> > > --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > @@ -358,6 +358,39 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = {
> > >         .get_modes = rpi_touchscreen_get_modes,
> > >  };
> > >
> > > +static void rpi_touchscreen_set_status_fail(struct i2c_client *i2c)
> > > +{
> > > +       struct property *newprop;
> > > +
> > > +       newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
> > > +       if (!newprop)
> > > +               return;
> > > +
> > > +       newprop->name = kstrdup("status", GFP_KERNEL);
> > > +       if (!newprop->name)
> > > +               goto err;
> > > +
> > > +       newprop->value = kstrdup("fail", GFP_KERNEL);
> > > +       if (!newprop->value)
> > > +               goto err;
> > > +
> > > +       newprop->length = sizeof("fail");
> > > +
> > > +       if (of_update_property(i2c->dev.of_node, newprop))
> > > +               goto err;
> > > +  
> > 
> > As I mentioned on irc, can you make this a common DT function.
> 
> Yep, will move that to drivers/of/base.c and make it generic.
> 
> > 
> > I'm not sure if it matters that we set status to fail vs. disabled. I
> > somewhat prefer the latter as we already have other cases and I'd
> > rather the api not pass a string in. I can't think of any reason to
> > distinguish the difference between fail and disabled.
> 
> Well, I just read the ePAPR doc pointed by Thierry [1] (section 2.3.4),
> and "fail" seemed like a good match for what we are trying to express
> here: "we failed to communicate with the device in the probe function
> and want to mark it unusable", which is a bit different from "the
> device was explicitly disabled by the user".
> 
> Anyway, if you think "disabled" is more appropriate, I'll use that.
> 
> > 
> > > +       /* We intentionally leak the memory we allocate here, because the new
> > > +        * OF property might live longer than the underlying dev, so no way
> > > +        * we can use devm_kzalloc() here.
> > > +        */
> > > +       return;
> > > +
> > > +err:
> > > +       kfree(newprop->value);
> > > +       kfree(newprop->name);
> > > +       kfree(newprop);
> > > +}
> > > +
> > >  static int rpi_touchscreen_probe(struct i2c_client *i2c,
> > >                                  const struct i2c_device_id *id)
> > >  {
> > > @@ -382,6 +415,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
> > >
> > >         ver = rpi_touchscreen_i2c_read(ts, REG_ID);
> > >         if (ver < 0) {
> > > +               rpi_touchscreen_set_status_fail(i2c);  
> > 
> > I've thought some more about this and I still think this should be
> > handled in the driver core or i2c core.
> > 
> > The reason is simple. I think the state of the system should be the
> > same after this as if you booted with 'status = "disabled"' for this
> > node. And that means the device should be removed completely because
> > we don't create struct device's for disabled nodes.
> 
> That was my feeling to when first discussing the issue with Daniel and
> Thierry on IRC, but after digging a bit in the code I'm no longer sure
> this is a good idea. At least, I don't think basing the decision to
> disable the device (or mark it unusable) based on the return value of
> the probe function is a good idea.

I'm not so sure about that. -ENODEV seems like a very suitable error
code to base that decision on. A random sampling of a handful of drivers
confirms that this is primarily used to report situations where it is
impossible for the device to ever be probed successfully, so might as
well just remove it.

At the very least I think it is worth proposing the patch and let Greg
and others weigh in.

Thierry

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 1/6] drm/tegra: Fix a device_node leak when the DRM panel is not found
  2018-05-03 16:40   ` Boris Brezillon
  (?)
@ 2018-05-04  9:50   ` Thierry Reding
  2018-05-04  9:53     ` Thierry Reding
  2018-05-04  9:54     ` Boris Brezillon
  -1 siblings, 2 replies; 32+ messages in thread
From: Thierry Reding @ 2018-05-04  9:50 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: David Airlie, Daniel Vetter, dri-devel, Eric Anholt, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	stable

[-- Attachment #1: Type: text/plain, Size: 733 bytes --]

On Thu, May 03, 2018 at 06:40:04PM +0200, Boris Brezillon wrote:
> of_node_put(panel) is not called when of_drm_find_panel(panel) returns
> NULL, thus leaking the reference we hold on panel.
> 
> Fixes: 9be7d864cf07 ("drm/tegra: Implement panel support")
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> ---
>  drivers/gpu/drm/tegra/output.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)

I'm not sure this warrants a backport, it's a very minor reference leak
so doesn't really have an impact on system stability or functionality.

Since this patch is unrelated from the rest of the series, do you mind
if I pick this up into the drm/tegra tree?

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v2 1/6] drm/tegra: Fix a device_node leak when the DRM panel is not found
  2018-05-04  9:50   ` Thierry Reding
@ 2018-05-04  9:53     ` Thierry Reding
  2018-05-04  9:54     ` Boris Brezillon
  1 sibling, 0 replies; 32+ messages in thread
From: Thierry Reding @ 2018-05-04  9:53 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: David Airlie, Daniel Vetter, dri-devel, Eric Anholt, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	stable

[-- Attachment #1: Type: text/plain, Size: 935 bytes --]

On Fri, May 04, 2018 at 11:50:16AM +0200, Thierry Reding wrote:
> On Thu, May 03, 2018 at 06:40:04PM +0200, Boris Brezillon wrote:
> > of_node_put(panel) is not called when of_drm_find_panel(panel) returns
> > NULL, thus leaking the reference we hold on panel.
> > 
> > Fixes: 9be7d864cf07 ("drm/tegra: Implement panel support")
> > Cc: <stable@vger.kernel.org>
> > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > ---
> >  drivers/gpu/drm/tegra/output.c | 3 +--
> >  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> I'm not sure this warrants a backport, it's a very minor reference leak
> so doesn't really have an impact on system stability or functionality.
> 
> Since this patch is unrelated from the rest of the series, do you mind
> if I pick this up into the drm/tegra tree?

Oh, nevermind, I just noticed that patch 2 depends on this, so:

Acked-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v2 1/6] drm/tegra: Fix a device_node leak when the DRM panel is not found
  2018-05-04  9:50   ` Thierry Reding
  2018-05-04  9:53     ` Thierry Reding
@ 2018-05-04  9:54     ` Boris Brezillon
  1 sibling, 0 replies; 32+ messages in thread
From: Boris Brezillon @ 2018-05-04  9:54 UTC (permalink / raw)
  To: Thierry Reding
  Cc: David Airlie, Daniel Vetter, dri-devel, Eric Anholt, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	stable

On Fri, 4 May 2018 11:50:16 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Thu, May 03, 2018 at 06:40:04PM +0200, Boris Brezillon wrote:
> > of_node_put(panel) is not called when of_drm_find_panel(panel) returns
> > NULL, thus leaking the reference we hold on panel.
> > 
> > Fixes: 9be7d864cf07 ("drm/tegra: Implement panel support")
> > Cc: <stable@vger.kernel.org>
> > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > ---
> >  drivers/gpu/drm/tegra/output.c | 3 +--
> >  1 file changed, 1 insertion(+), 2 deletions(-)  
> 
> I'm not sure this warrants a backport, it's a very minor reference leak
> so doesn't really have an impact on system stability or functionality.
> 
> Since this patch is unrelated from the rest of the series, do you mind
> if I pick this up into the drm/tegra tree?

Sure, and feel free to remove the Cc-stable and Fixes tag if you think
they are not necessary.

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

* Re: [PATCH v2 2/6] drm/panel: Make of_drm_find_panel() return an ERR_PTR() instead of NULL
  2018-05-03 16:40 ` [PATCH v2 2/6] drm/panel: Make of_drm_find_panel() return an ERR_PTR() instead of NULL Boris Brezillon
@ 2018-05-04 10:18   ` Thierry Reding
  2018-05-04 11:58     ` Boris Brezillon
  0 siblings, 1 reply; 32+ messages in thread
From: Thierry Reding @ 2018-05-04 10:18 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 17497 bytes --]

On Thu, May 03, 2018 at 06:40:05PM +0200, Boris Brezillon wrote:
> Right now, the DRM panel logic returns NULL when a panel pointing to
> the passed OF node is not present in the list of registered panels.
> 
> Most drivers interpret this NULL value as -EPROBE_DEFER, but we are
> about to modify the semantic of of_drm_find_panel() and let the
> framework return -ENODEV when the device node we're pointing to has
> a status property that is not equal to "okay" or "ok".
> 
> Let's first patch the of_drm_find_panel() implementation to return
> ERR_PTR(-EPROBE_DEFER) instead of NULL and patch all callers to replace
> the '!panel' check by an 'IS_ERR(panel)' one.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> ---
>  drivers/gpu/drm/bridge/cdns-dsi.c                   |  2 +-
>  drivers/gpu/drm/bridge/lvds-encoder.c               |  4 ++--
>  drivers/gpu/drm/drm_of.c                            |  8 ++++++--
>  drivers/gpu/drm/drm_panel.c                         |  6 ++++--
>  drivers/gpu/drm/exynos/exynos_dp.c                  |  9 ++++++---
>  drivers/gpu/drm/exynos/exynos_drm_dpi.c             |  9 ++++++---
>  drivers/gpu/drm/exynos/exynos_drm_dsi.c             |  6 ++++--
>  drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c           |  8 +++++---
>  drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c   |  4 ++--
>  drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c | 10 +++++++---
>  drivers/gpu/drm/msm/dsi/dsi_host.c                  |  2 +-
>  drivers/gpu/drm/rcar-du/rcar_lvds.c                 |  9 ++++++---
>  drivers/gpu/drm/rockchip/dw-mipi-dsi.c              |  2 +-
>  drivers/gpu/drm/sti/sti_dvo.c                       |  7 +++++--
>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c              |  4 ++--
>  drivers/gpu/drm/tegra/dsi.c                         |  6 ++++--
>  drivers/gpu/drm/tegra/output.c                      | 18 +++++++++++-------
>  include/drm/drm_panel.h                             |  2 +-
>  18 files changed, 74 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c
> index c255fc3e1be5..2c5991cf5397 100644
> --- a/drivers/gpu/drm/bridge/cdns-dsi.c
> +++ b/drivers/gpu/drm/bridge/cdns-dsi.c
> @@ -1152,7 +1152,7 @@ static int cdns_dsi_attach(struct mipi_dsi_host *host,
>  		np = of_node_get(dev->dev.of_node);
>  
>  	panel = of_drm_find_panel(np);
> -	if (panel) {
> +	if (!IS_ERR(panel)) {
>  		bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI);
>  	} else {
>  		bridge = of_drm_find_bridge(dev->dev.of_node);
> diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c
> index 75b0d3f6e4de..f56c92f7af7c 100644
> --- a/drivers/gpu/drm/bridge/lvds-encoder.c
> +++ b/drivers/gpu/drm/bridge/lvds-encoder.c
> @@ -68,9 +68,9 @@ static int lvds_encoder_probe(struct platform_device *pdev)
>  
>  	panel = of_drm_find_panel(panel_node);
>  	of_node_put(panel_node);
> -	if (!panel) {
> +	if (IS_ERR(panel)) {
>  		dev_dbg(&pdev->dev, "panel not found, deferring probe\n");
> -		return -EPROBE_DEFER;
> +		return PTR_ERR(panel);
>  	}
>  
>  	lvds_encoder->panel_bridge =
> diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
> index 1fe122461298..f413fae6f6dc 100644
> --- a/drivers/gpu/drm/drm_of.c
> +++ b/drivers/gpu/drm/drm_of.c
> @@ -239,9 +239,13 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
>  		return -ENODEV;
>  
>  	if (panel) {
> -		*panel = of_drm_find_panel(remote);
> -		if (*panel)
> +		struct drm_panel *tmp_panel;
> +
> +		tmp_panel = of_drm_find_panel(remote);
> +		if (!IS_ERR(tmp_panel)) {
> +			*panel = tmp_panel;
>  			ret = 0;
> +		}

I think the introduction of this temporary variable makes the code hard
to read and the diff difficult to understand. Why not just stick with
the original style and make this:

		*panel = of_drm_find_panel(remote);
		if (IS_ERR(*panel))
			*panel = NULL;
		else
			ret = 0;

?

>  	}
>  
>  	/* No panel found yet, check for a bridge next. */
> diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
> index 308d442a531b..2d9e2684c6c8 100644
> --- a/drivers/gpu/drm/drm_panel.c
> +++ b/drivers/gpu/drm/drm_panel.c
> @@ -135,7 +135,9 @@ EXPORT_SYMBOL(drm_panel_detach);
>   * tree node. If a matching panel is found, return a pointer to it.
>   *
>   * Return: A pointer to the panel registered for the specified device tree
> - * node or NULL if no panel matching the device tree node can be found.
> + * node or an ERR_PTR() if no panel matching the device tree node can be found.
> + * The only error that can be reported is -EPROBE_DEFER, meaning that the panel
> + * device has not been probed yet, and the caller should re-retry later.

I think you can drop the extra re- from re-retry.

>   */
>  struct drm_panel *of_drm_find_panel(const struct device_node *np)
>  {
> @@ -151,7 +153,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
>  	}
>  
>  	mutex_unlock(&panel_lock);
> -	return NULL;
> +	return ERR_PTR(-EPROBE_DEFER);
>  }
>  EXPORT_SYMBOL(of_drm_find_panel);
>  #endif
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index 86330f396784..962cad0276e5 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -231,10 +231,13 @@ static int exynos_dp_probe(struct platform_device *pdev)
>  	/* This is for the backward compatibility. */
>  	np = of_parse_phandle(dev->of_node, "panel", 0);
>  	if (np) {
> -		dp->plat_data.panel = of_drm_find_panel(np);
> +		struct drm_panel *panel = of_drm_find_panel(np);
> +
>  		of_node_put(np);
> -		if (!dp->plat_data.panel)
> -			return -EPROBE_DEFER;
> +		if (IS_ERR(panel))
> +			return PTR_ERR(panel);

I don't see the point in the extra variable here. dp is allocated using
devm_kzalloc(), so it will go away on the error return. You shouldn't
need to worry about keeping the dp->plat_data.panel untouched in case of
error.

> +
> +		dp->plat_data.panel = panel;
>  		goto out;
>  	}
>  
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> index 66945e0dc57f..e9c7d1c1cf8f 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> @@ -239,9 +239,12 @@ struct drm_encoder *exynos_dpi_probe(struct device *dev)
>  	}
>  
>  	if (ctx->panel_node) {
> -		ctx->panel = of_drm_find_panel(ctx->panel_node);
> -		if (!ctx->panel)
> -			return ERR_PTR(-EPROBE_DEFER);
> +		struct drm_panel *panel = of_drm_find_panel(ctx->panel_node);
> +
> +		if (IS_ERR(panel))
> +			return ERR_CAST(panel);
> +
> +		ctx->panel = panel;

Same here.

>  	}
>  
>  	return &ctx->encoder;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index 7904ffa9abfb..96206deb86a0 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1520,6 +1520,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
>  {
>  	struct exynos_dsi *dsi = host_to_dsi(host);
>  	struct drm_device *drm = dsi->connector.dev;
> +	struct drm_panel *panel;
>  
>  	/*
>  	 * This is a temporary solution and should be made by more generic way.
> @@ -1538,8 +1539,9 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
>  	dsi->lanes = device->lanes;
>  	dsi->format = device->format;
>  	dsi->mode_flags = device->mode_flags;
> -	dsi->panel = of_drm_find_panel(device->dev.of_node);
> -	if (dsi->panel) {
> +	panel = of_drm_find_panel(device->dev.of_node);
> +	if (!IS_ERR(panel)) {
> +		dsi->panel = panel;
>  		drm_panel_attach(dsi->panel, &dsi->connector);
>  		dsi->connector.status = connector_status_connected;
>  	}

It seems to be a potential problem here if dsi->panel is an ERR_PTR()-
encoded value, but I still think this becomes clearer if you do:

	dsi->panel = of_drm_find_panel(...);
	if (!IS_ERR(dsi->panel)) {
		...
	} else {
		dsi->panel = NULL;
	}

Or maybe even:

	dsi->panel = of_drm_find_panel(...);
	if (IS_ERR(dsi->panel))
		dsi->panel = NULL;

	if (dsi->panel) {
	}

That's more explicitly saying that the panel support is optional.

> diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> index c54806d08dd7..7753b3093472 100644
> --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> @@ -146,10 +146,12 @@ int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
>  	/* This is for backward compatibility */
>  	panel_node = of_parse_phandle(fsl_dev->np, "fsl,panel", 0);
>  	if (panel_node) {
> -		fsl_dev->connector.panel = of_drm_find_panel(panel_node);
> +		panel = of_drm_find_panel(panel_node);
>  		of_node_put(panel_node);
> -		if (!fsl_dev->connector.panel)
> -			return -EPROBE_DEFER;
> +		if (IS_ERR(panel))
> +			return PTR_ERR(panel);
> +
> +		fsl_dev->connector.panel = panel;

Same here, fsl_dev goes away after the error return.

>  		return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel);
>  	}
>  
> diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
> index 4a645926edb7..2bfb39082f54 100644
> --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
> @@ -341,7 +341,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
>  	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
>  
>  	panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
> -	if (panel) {
> +	if (!IS_ERR(panel)) {
>  		drm_panel_disable(panel);
>  		drm_panel_unprepare(panel);
>  	}
> @@ -410,7 +410,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
>  		dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
>  
>  	panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
> -	if (panel) {
> +	if (!IS_ERR(panel)) {
>  		drm_panel_prepare(panel);
>  		drm_panel_enable(panel);
>  	}
> diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
> index e3b1c86b7aae..c7dd72b428f8 100644
> --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
> +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
> @@ -34,9 +34,13 @@ static enum drm_connector_status mdp4_lvds_connector_detect(
>  	struct mdp4_lvds_connector *mdp4_lvds_connector =
>  			to_mdp4_lvds_connector(connector);
>  
> -	if (!mdp4_lvds_connector->panel)
> -		mdp4_lvds_connector->panel =
> -			of_drm_find_panel(mdp4_lvds_connector->panel_node);
> +	if (!mdp4_lvds_connector->panel) {
> +		struct drm_panel *panel;
> +
> +		panel = of_drm_find_panel(mdp4_lvds_connector->panel_node);
> +		if (!IS_ERR(panel))
> +			mdp4_lvds_connector->panel = panel;
> +	}

Huh... this is hacky to begin with. Seems like this driver doesn't care
about waiting for the panel, it'll just retry probing the panel
everytime ->detect() is called on the connector until the panel has
shown up. That's not really how this is supposed to work, but it's been
there before your patch, so should be addressed separately.

>  
>  	return mdp4_lvds_connector->panel ?
>  			connector_status_connected :
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
> index 7a03a9489708..fffc80b73966 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> @@ -1881,7 +1881,7 @@ int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer)
>  		 * output
>  		 */
>  		if (check_defer && msm_host->device_node) {
> -			if (!of_drm_find_panel(msm_host->device_node))
> +			if (IS_ERR(of_drm_find_panel(msm_host->device_node)))
>  				if (!of_drm_find_bridge(msm_host->device_node))
>  					return -EPROBE_DEFER;
>  		}

Again, pretty weird stuff going on here, prior to the patch. But I think
this needs to be changed to take the -ENODEV into account in the next
patch. As it is, this will continue to defer probe even if the panel
node is disabled.

> diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> index 3d2d3bbd1342..d77b8f8bcf94 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> @@ -430,9 +430,12 @@ static int rcar_lvds_parse_dt(struct rcar_lvds *lvds)
>  		if (!lvds->next_bridge)
>  			ret = -EPROBE_DEFER;
>  	} else {
> -		lvds->panel = of_drm_find_panel(remote);
> -		if (!lvds->panel)
> -			ret = -EPROBE_DEFER;
> +		struct drm_panel *panel = of_drm_find_panel(remote);
> +
> +		if (IS_ERR(panel))
> +			ret = PTR_ERR(panel);
> +		else
> +			lvds->panel = panel;
>  	}

Similar to others above, I think this can easily be done without the
extra temporary variable.

>  
>  done:
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index d53d5a09547f..01642aaf6127 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -595,7 +595,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
>  	dsi->format = device->format;
>  	dsi->mode_flags = device->mode_flags;
>  	dsi->panel = of_drm_find_panel(device->dev.of_node);
> -	if (dsi->panel)
> +	if (!IS_ERR(dsi->panel))
>  		return drm_panel_attach(dsi->panel, &dsi->connector);
>  
>  	return -EINVAL;
> diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
> index a5979cd25cc7..3579c0e1ca1c 100644
> --- a/drivers/gpu/drm/sti/sti_dvo.c
> +++ b/drivers/gpu/drm/sti/sti_dvo.c
> @@ -386,9 +386,12 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force)
>  	DRM_DEBUG_DRIVER("\n");
>  
>  	if (!dvo->panel) {
> -		dvo->panel = of_drm_find_panel(dvo->panel_node);
> -		if (dvo->panel)
> +		struct drm_panel *panel = of_drm_find_panel(dvo->panel_node);
> +
> +		if (!IS_ERR(panel)) {
> +			dvo->panel = panel;
>  			drm_panel_attach(dvo->panel, connector);
> +		}
>  	}

Same here.

>  
>  	if (dvo->panel)
> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> index bfbf761f0c1d..ce388d7cebaa 100644
> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> @@ -812,8 +812,8 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
>  
>  	dsi->device = device;
>  	dsi->panel = of_drm_find_panel(device->dev.of_node);
> -	if (!dsi->panel)
> -		return -EINVAL;
> +	if (IS_ERR(dsi->panel))
> +		return PTR_ERR(dsi->panel);
>  
>  	dev_info(host->dev, "Attached device %s\n", device->name);
>  
> diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
> index 87c5d89bc9ba..0b1eee4b2fb1 100644
> --- a/drivers/gpu/drm/tegra/dsi.c
> +++ b/drivers/gpu/drm/tegra/dsi.c
> @@ -1409,9 +1409,11 @@ static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
>  	 */
>  	if (!dsi->master) {
>  		struct tegra_output *output = &dsi->output;
> +		struct drm_panel *panel;
>  
> -		output->panel = of_drm_find_panel(device->dev.of_node);
> -		if (output->panel && output->connector.dev) {
> +		panel = of_drm_find_panel(device->dev.of_node);
> +		if (!IS_ERR(panel) && output->connector.dev) {
> +			output->panel = panel;

And here.

>  			drm_panel_attach(output->panel, &output->connector);
>  			drm_helper_hpd_irq_event(output->connector.dev);
>  		}
> diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
> index 676fd394836f..21d8737f8b49 100644
> --- a/drivers/gpu/drm/tegra/output.c
> +++ b/drivers/gpu/drm/tegra/output.c
> @@ -101,18 +101,22 @@ static irqreturn_t hpd_irq(int irq, void *data)
>  
>  int tegra_output_probe(struct tegra_output *output)
>  {
> -	struct device_node *ddc, *panel;
> +	struct device_node *ddc, *panelnp;
>  	int err, size;
>  
>  	if (!output->of_node)
>  		output->of_node = output->dev->of_node;
>  
> -	panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
> -	if (panel) {
> -		output->panel = of_drm_find_panel(panel);
> -		of_node_put(panel);
> -		if (!output->panel)
> -			return -EPROBE_DEFER;
> +	panelnp = of_parse_phandle(output->of_node, "nvidia,panel", 0);
> +	if (panelnp) {
> +		struct drm_panel *panel = of_drm_find_panel(panelnp);
> +
> +		of_node_put(panelnp);
> +
> +		if (IS_ERR(panel))
> +			return PTR_ERR(panel);
> +
> +		output->panel = panel;
>  	}

And here.

>  	output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
> diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
> index 14ac240a1f64..3bb91519462e 100644
> --- a/include/drm/drm_panel.h
> +++ b/include/drm/drm_panel.h
> @@ -199,7 +199,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np);
>  #else
>  static inline struct drm_panel *of_drm_find_panel(const struct device_node *np)
>  {
> -	return NULL;
> +	return ERR_PTR(-ENOTSUPP);
>  }
>  #endif

Maybe make this return ERR_PTR(-ENODEV) for consistency with the real
function? If we absolutely do need to differentiate, then you should
probably update the kerneldoc for of_drm_find_panel() to mention the
-ENOTSUPP case.

Thierry

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 3/6] drm/panel: Let of_drm_find_panel() return -ENODEV when the panel is disabled
  2018-05-03 16:40 ` [PATCH v2 3/6] drm/panel: Let of_drm_find_panel() return -ENODEV when the panel is disabled Boris Brezillon
@ 2018-05-04 10:20   ` Thierry Reding
  0 siblings, 0 replies; 32+ messages in thread
From: Thierry Reding @ 2018-05-04 10:20 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 558 bytes --]

On Thu, May 03, 2018 at 06:40:06PM +0200, Boris Brezillon wrote:
> DT nodes might be present in the DT but with a status property set to
> "disabled" or "fail". In this case, we should not return -EPROBE_DEFER
> when the caller ask for a drm_panel instance. Return -ENODEV instead.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> ---
>  drivers/gpu/drm/drm_panel.c | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)

Reviewed-by: Thierry Reding <treding@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 4/6] drm/of: Make drm_of_find_panel_or_bridge() fail when the device is disabled
  2018-05-03 16:40 ` [PATCH v2 4/6] drm/of: Make drm_of_find_panel_or_bridge() fail when the device " Boris Brezillon
@ 2018-05-04 10:20   ` Thierry Reding
  0 siblings, 0 replies; 32+ messages in thread
From: Thierry Reding @ 2018-05-04 10:20 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 495 bytes --]

On Thu, May 03, 2018 at 06:40:07PM +0200, Boris Brezillon wrote:
> There's no point searching for a drm_bridge or drm_panel if the OF node
> we're pointing has a status property that is not "okay" or "ok". Just
> return -ENODEV in this case.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> ---
>  drivers/gpu/drm/drm_of.c | 5 +++++
>  1 file changed, 5 insertions(+)

Reviewed-by: Thierry Reding <treding@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 5/6] drm/vc4: Support the case where the DSI device is disabled
  2018-05-03 16:40 ` [PATCH v2 5/6] drm/vc4: Support the case where the DSI " Boris Brezillon
@ 2018-05-04 10:28   ` Thierry Reding
  2018-05-04 12:05     ` Boris Brezillon
  2018-05-04 10:30   ` Thierry Reding
  1 sibling, 1 reply; 32+ messages in thread
From: Thierry Reding @ 2018-05-04 10:28 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 2095 bytes --]

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

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 5/6] drm/vc4: Support the case where the DSI device is disabled
  2018-05-03 16:40 ` [PATCH v2 5/6] drm/vc4: Support the case where the DSI " Boris Brezillon
  2018-05-04 10:28   ` Thierry Reding
@ 2018-05-04 10:30   ` Thierry Reding
  2018-05-04 12:00     ` Boris Brezillon
  1 sibling, 1 reply; 32+ messages in thread
From: Thierry Reding @ 2018-05-04 10:30 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 1406 bytes --]

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

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 2/6] drm/panel: Make of_drm_find_panel() return an ERR_PTR() instead of NULL
  2018-05-04 10:18   ` Thierry Reding
@ 2018-05-04 11:58     ` Boris Brezillon
  2018-05-04 12:11       ` Thierry Reding
  0 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2018-05-04 11:58 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala

Hi Thierry,

On Fri, 4 May 2018 12:18:52 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Thu, May 03, 2018 at 06:40:05PM +0200, Boris Brezillon wrote:
> > Right now, the DRM panel logic returns NULL when a panel pointing to
> > the passed OF node is not present in the list of registered panels.
> > 
> > Most drivers interpret this NULL value as -EPROBE_DEFER, but we are
> > about to modify the semantic of of_drm_find_panel() and let the
> > framework return -ENODEV when the device node we're pointing to has
> > a status property that is not equal to "okay" or "ok".
> > 
> > Let's first patch the of_drm_find_panel() implementation to return
> > ERR_PTR(-EPROBE_DEFER) instead of NULL and patch all callers to replace
> > the '!panel' check by an 'IS_ERR(panel)' one.
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > ---
> >  drivers/gpu/drm/bridge/cdns-dsi.c                   |  2 +-
> >  drivers/gpu/drm/bridge/lvds-encoder.c               |  4 ++--
> >  drivers/gpu/drm/drm_of.c                            |  8 ++++++--
> >  drivers/gpu/drm/drm_panel.c                         |  6 ++++--
> >  drivers/gpu/drm/exynos/exynos_dp.c                  |  9 ++++++---
> >  drivers/gpu/drm/exynos/exynos_drm_dpi.c             |  9 ++++++---
> >  drivers/gpu/drm/exynos/exynos_drm_dsi.c             |  6 ++++--
> >  drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c           |  8 +++++---
> >  drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c   |  4 ++--
> >  drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c | 10 +++++++---
> >  drivers/gpu/drm/msm/dsi/dsi_host.c                  |  2 +-
> >  drivers/gpu/drm/rcar-du/rcar_lvds.c                 |  9 ++++++---
> >  drivers/gpu/drm/rockchip/dw-mipi-dsi.c              |  2 +-
> >  drivers/gpu/drm/sti/sti_dvo.c                       |  7 +++++--
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c              |  4 ++--
> >  drivers/gpu/drm/tegra/dsi.c                         |  6 ++++--
> >  drivers/gpu/drm/tegra/output.c                      | 18 +++++++++++-------
> >  include/drm/drm_panel.h                             |  2 +-
> >  18 files changed, 74 insertions(+), 42 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c
> > index c255fc3e1be5..2c5991cf5397 100644
> > --- a/drivers/gpu/drm/bridge/cdns-dsi.c
> > +++ b/drivers/gpu/drm/bridge/cdns-dsi.c
> > @@ -1152,7 +1152,7 @@ static int cdns_dsi_attach(struct mipi_dsi_host *host,
> >  		np = of_node_get(dev->dev.of_node);
> >  
> >  	panel = of_drm_find_panel(np);
> > -	if (panel) {
> > +	if (!IS_ERR(panel)) {
> >  		bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI);
> >  	} else {
> >  		bridge = of_drm_find_bridge(dev->dev.of_node);
> > diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c
> > index 75b0d3f6e4de..f56c92f7af7c 100644
> > --- a/drivers/gpu/drm/bridge/lvds-encoder.c
> > +++ b/drivers/gpu/drm/bridge/lvds-encoder.c
> > @@ -68,9 +68,9 @@ static int lvds_encoder_probe(struct platform_device *pdev)
> >  
> >  	panel = of_drm_find_panel(panel_node);
> >  	of_node_put(panel_node);
> > -	if (!panel) {
> > +	if (IS_ERR(panel)) {
> >  		dev_dbg(&pdev->dev, "panel not found, deferring probe\n");
> > -		return -EPROBE_DEFER;
> > +		return PTR_ERR(panel);
> >  	}
> >  
> >  	lvds_encoder->panel_bridge =
> > diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
> > index 1fe122461298..f413fae6f6dc 100644
> > --- a/drivers/gpu/drm/drm_of.c
> > +++ b/drivers/gpu/drm/drm_of.c
> > @@ -239,9 +239,13 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
> >  		return -ENODEV;
> >  
> >  	if (panel) {
> > -		*panel = of_drm_find_panel(remote);
> > -		if (*panel)
> > +		struct drm_panel *tmp_panel;
> > +
> > +		tmp_panel = of_drm_find_panel(remote);
> > +		if (!IS_ERR(tmp_panel)) {
> > +			*panel = tmp_panel;
> >  			ret = 0;
> > +		}  
> 
> I think the introduction of this temporary variable makes the code hard
> to read and the diff difficult to understand. Why not just stick with
> the original style and make this:
> 
> 		*panel = of_drm_find_panel(remote);
> 		if (IS_ERR(*panel))
> 			*panel = NULL;
> 		else
> 			ret = 0;
> 
> ?

Sure.

> 
> >  	}
> >  
> >  	/* No panel found yet, check for a bridge next. */
> > diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
> > index 308d442a531b..2d9e2684c6c8 100644
> > --- a/drivers/gpu/drm/drm_panel.c
> > +++ b/drivers/gpu/drm/drm_panel.c
> > @@ -135,7 +135,9 @@ EXPORT_SYMBOL(drm_panel_detach);
> >   * tree node. If a matching panel is found, return a pointer to it.
> >   *
> >   * Return: A pointer to the panel registered for the specified device tree
> > - * node or NULL if no panel matching the device tree node can be found.
> > + * node or an ERR_PTR() if no panel matching the device tree node can be found.
> > + * The only error that can be reported is -EPROBE_DEFER, meaning that the panel
> > + * device has not been probed yet, and the caller should re-retry later.  
> 
> I think you can drop the extra re- from re-retry.

Yep, will fix that.

> 
> >   */
> >  struct drm_panel *of_drm_find_panel(const struct device_node *np)
> >  {
> > @@ -151,7 +153,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
> >  	}
> >  
> >  	mutex_unlock(&panel_lock);
> > -	return NULL;
> > +	return ERR_PTR(-EPROBE_DEFER);
> >  }
> >  EXPORT_SYMBOL(of_drm_find_panel);
> >  #endif
> > diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> > index 86330f396784..962cad0276e5 100644
> > --- a/drivers/gpu/drm/exynos/exynos_dp.c
> > +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> > @@ -231,10 +231,13 @@ static int exynos_dp_probe(struct platform_device *pdev)
> >  	/* This is for the backward compatibility. */
> >  	np = of_parse_phandle(dev->of_node, "panel", 0);
> >  	if (np) {
> > -		dp->plat_data.panel = of_drm_find_panel(np);
> > +		struct drm_panel *panel = of_drm_find_panel(np);
> > +
> >  		of_node_put(np);
> > -		if (!dp->plat_data.panel)
> > -			return -EPROBE_DEFER;
> > +		if (IS_ERR(panel))
> > +			return PTR_ERR(panel);  
> 
> I don't see the point in the extra variable here. dp is allocated using
> devm_kzalloc(), so it will go away on the error return. You shouldn't
> need to worry about keeping the dp->plat_data.panel untouched in case of
> error.

Also true. I'll assign dp->plat_data.panel directly.

> 
> > +
> > +		dp->plat_data.panel = panel;
> >  		goto out;
> >  	}
> >  
> > diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> > index 66945e0dc57f..e9c7d1c1cf8f 100644
> > --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> > +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> > @@ -239,9 +239,12 @@ struct drm_encoder *exynos_dpi_probe(struct device *dev)
> >  	}
> >  
> >  	if (ctx->panel_node) {
> > -		ctx->panel = of_drm_find_panel(ctx->panel_node);
> > -		if (!ctx->panel)
> > -			return ERR_PTR(-EPROBE_DEFER);
> > +		struct drm_panel *panel = of_drm_find_panel(ctx->panel_node);
> > +
> > +		if (IS_ERR(panel))
> > +			return ERR_CAST(panel);
> > +
> > +		ctx->panel = panel;  
> 
> Same here.

Yep.

> 
> >  	}
> >  
> >  	return &ctx->encoder;
> > diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> > index 7904ffa9abfb..96206deb86a0 100644
> > --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> > +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> > @@ -1520,6 +1520,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
> >  {
> >  	struct exynos_dsi *dsi = host_to_dsi(host);
> >  	struct drm_device *drm = dsi->connector.dev;
> > +	struct drm_panel *panel;
> >  
> >  	/*
> >  	 * This is a temporary solution and should be made by more generic way.
> > @@ -1538,8 +1539,9 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
> >  	dsi->lanes = device->lanes;
> >  	dsi->format = device->format;
> >  	dsi->mode_flags = device->mode_flags;
> > -	dsi->panel = of_drm_find_panel(device->dev.of_node);
> > -	if (dsi->panel) {
> > +	panel = of_drm_find_panel(device->dev.of_node);
> > +	if (!IS_ERR(panel)) {
> > +		dsi->panel = panel;
> >  		drm_panel_attach(dsi->panel, &dsi->connector);
> >  		dsi->connector.status = connector_status_connected;
> >  	}  
> 
> It seems to be a potential problem here if dsi->panel is an ERR_PTR()-
> encoded value, but I still think this becomes clearer if you do:
> 
> 	dsi->panel = of_drm_find_panel(...);
> 	if (!IS_ERR(dsi->panel)) {
> 		...
> 	} else {
> 		dsi->panel = NULL;
> 	}
> 
> Or maybe even:
> 
> 	dsi->panel = of_drm_find_panel(...);
> 	if (IS_ERR(dsi->panel))
> 		dsi->panel = NULL;
> 
> 	if (dsi->panel) {
> 	}
> 
> That's more explicitly saying that the panel support is optional.

I'll go for the 2nd option.

> 
> > diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> > index c54806d08dd7..7753b3093472 100644
> > --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> > +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> > @@ -146,10 +146,12 @@ int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
> >  	/* This is for backward compatibility */
> >  	panel_node = of_parse_phandle(fsl_dev->np, "fsl,panel", 0);
> >  	if (panel_node) {
> > -		fsl_dev->connector.panel = of_drm_find_panel(panel_node);
> > +		panel = of_drm_find_panel(panel_node);
> >  		of_node_put(panel_node);
> > -		if (!fsl_dev->connector.panel)
> > -			return -EPROBE_DEFER;
> > +		if (IS_ERR(panel))
> > +			return PTR_ERR(panel);
> > +
> > +		fsl_dev->connector.panel = panel;  
> 
> Same here, fsl_dev goes away after the error return.

Okay, will assign fsl_dev->connector.panel directly.

> 
> >  		return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel);
> >  	}
> >  
> > diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
> > index 4a645926edb7..2bfb39082f54 100644
> > --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
> > +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
> > @@ -341,7 +341,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
> >  	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
> >  
> >  	panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
> > -	if (panel) {
> > +	if (!IS_ERR(panel)) {
> >  		drm_panel_disable(panel);
> >  		drm_panel_unprepare(panel);
> >  	}
> > @@ -410,7 +410,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
> >  		dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
> >  
> >  	panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
> > -	if (panel) {
> > +	if (!IS_ERR(panel)) {
> >  		drm_panel_prepare(panel);
> >  		drm_panel_enable(panel);
> >  	}
> > diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
> > index e3b1c86b7aae..c7dd72b428f8 100644
> > --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
> > +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
> > @@ -34,9 +34,13 @@ static enum drm_connector_status mdp4_lvds_connector_detect(
> >  	struct mdp4_lvds_connector *mdp4_lvds_connector =
> >  			to_mdp4_lvds_connector(connector);
> >  
> > -	if (!mdp4_lvds_connector->panel)
> > -		mdp4_lvds_connector->panel =
> > -			of_drm_find_panel(mdp4_lvds_connector->panel_node);
> > +	if (!mdp4_lvds_connector->panel) {
> > +		struct drm_panel *panel;
> > +
> > +		panel = of_drm_find_panel(mdp4_lvds_connector->panel_node);
> > +		if (!IS_ERR(panel))
> > +			mdp4_lvds_connector->panel = panel;
> > +	}  
> 
> Huh... this is hacky to begin with. Seems like this driver doesn't care
> about waiting for the panel, it'll just retry probing the panel
> everytime ->detect() is called on the connector until the panel has
> shown up. That's not really how this is supposed to work, but it's been
> there before your patch, so should be addressed separately.

Yes, I'm not trying to address this kind of issues here, and I fear
it's not the only driver to do that.

> 
> >  
> >  	return mdp4_lvds_connector->panel ?
> >  			connector_status_connected :
> > diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
> > index 7a03a9489708..fffc80b73966 100644
> > --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> > +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> > @@ -1881,7 +1881,7 @@ int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer)
> >  		 * output
> >  		 */
> >  		if (check_defer && msm_host->device_node) {
> > -			if (!of_drm_find_panel(msm_host->device_node))
> > +			if (IS_ERR(of_drm_find_panel(msm_host->device_node)))
> >  				if (!of_drm_find_bridge(msm_host->device_node))
> >  					return -EPROBE_DEFER;
> >  		}  
> 
> Again, pretty weird stuff going on here, prior to the patch. But I think
> this needs to be changed to take the -ENODEV into account in the next
> patch. As it is, this will continue to defer probe even if the panel
> node is disabled.

Not sure this is a problem. I mean, the code was working before, and we
had no way to differentiate the -ENODEV vs -EPROBE_DEFER, which in turn
means that, any driver that assumed that the device would appear at some
point were just as broken as they are after this patch when the node
they're pointing to has its status set to "disabled".

I'm not trying to patch all drivers to take the return code into
account, just those that might take advantage of it.

> 
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > index 3d2d3bbd1342..d77b8f8bcf94 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > @@ -430,9 +430,12 @@ static int rcar_lvds_parse_dt(struct rcar_lvds *lvds)
> >  		if (!lvds->next_bridge)
> >  			ret = -EPROBE_DEFER;
> >  	} else {
> > -		lvds->panel = of_drm_find_panel(remote);
> > -		if (!lvds->panel)
> > -			ret = -EPROBE_DEFER;
> > +		struct drm_panel *panel = of_drm_find_panel(remote);
> > +
> > +		if (IS_ERR(panel))
> > +			ret = PTR_ERR(panel);
> > +		else
> > +			lvds->panel = panel;
> >  	}  
> 
> Similar to others above, I think this can easily be done without the
> extra temporary variable.

Sure (same goes for all occurrences).

[...]

> 
> >  	output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
> > diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
> > index 14ac240a1f64..3bb91519462e 100644
> > --- a/include/drm/drm_panel.h
> > +++ b/include/drm/drm_panel.h
> > @@ -199,7 +199,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np);
> >  #else
> >  static inline struct drm_panel *of_drm_find_panel(const struct device_node *np)
> >  {
> > -	return NULL;
> > +	return ERR_PTR(-ENOTSUPP);
> >  }
> >  #endif  
> 
> Maybe make this return ERR_PTR(-ENODEV) for consistency with the real
> function? If we absolutely do need to differentiate, then you should
> probably update the kerneldoc for of_drm_find_panel() to mention the
> -ENOTSUPP case.

Will use -ENODEV here.

Thanks for the review.

Boris
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 5/6] drm/vc4: Support the case where the DSI device is disabled
  2018-05-04 10:30   ` Thierry Reding
@ 2018-05-04 12:00     ` Boris Brezillon
  0 siblings, 0 replies; 32+ messages in thread
From: Boris Brezillon @ 2018-05-04 12:00 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala

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.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 5/6] drm/vc4: Support the case where the DSI device is disabled
  2018-05-04 10:28   ` Thierry Reding
@ 2018-05-04 12:05     ` Boris Brezillon
  2018-05-04 13:29       ` Thierry Reding
  0 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2018-05-04 12:05 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala

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?

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 2/6] drm/panel: Make of_drm_find_panel() return an ERR_PTR() instead of NULL
  2018-05-04 11:58     ` Boris Brezillon
@ 2018-05-04 12:11       ` Thierry Reding
  0 siblings, 0 replies; 32+ messages in thread
From: Thierry Reding @ 2018-05-04 12:11 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 1746 bytes --]

On Fri, May 04, 2018 at 01:58:20PM +0200, Boris Brezillon wrote:
> On Fri, 4 May 2018 12:18:52 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > On Thu, May 03, 2018 at 06:40:05PM +0200, Boris Brezillon wrote:
[...]
> > >  	return mdp4_lvds_connector->panel ?
> > >  			connector_status_connected :
> > > diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
> > > index 7a03a9489708..fffc80b73966 100644
> > > --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> > > +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> > > @@ -1881,7 +1881,7 @@ int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer)
> > >  		 * output
> > >  		 */
> > >  		if (check_defer && msm_host->device_node) {
> > > -			if (!of_drm_find_panel(msm_host->device_node))
> > > +			if (IS_ERR(of_drm_find_panel(msm_host->device_node)))
> > >  				if (!of_drm_find_bridge(msm_host->device_node))
> > >  					return -EPROBE_DEFER;
> > >  		}  
> > 
> > Again, pretty weird stuff going on here, prior to the patch. But I think
> > this needs to be changed to take the -ENODEV into account in the next
> > patch. As it is, this will continue to defer probe even if the panel
> > node is disabled.
> 
> Not sure this is a problem. I mean, the code was working before, and we
> had no way to differentiate the -ENODEV vs -EPROBE_DEFER, which in turn
> means that, any driver that assumed that the device would appear at some
> point were just as broken as they are after this patch when the node
> they're pointing to has its status set to "disabled".
> 
> I'm not trying to patch all drivers to take the return code into
> account, just those that might take advantage of it.

Okay, fair enough.

Thierry

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails
  2018-05-04  9:47       ` Thierry Reding
@ 2018-05-04 12:17         ` Boris Brezillon
  2018-05-04 14:20           ` Daniel Vetter
  0 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2018-05-04 12:17 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala

On Fri, 4 May 2018 11:47:48 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Fri, May 04, 2018 at 10:06:53AM +0200, Boris Brezillon wrote:
> > Hi Rob,
> > 
> > On Thu, 3 May 2018 12:12:39 -0500
> > Rob Herring <robh+dt@kernel.org> wrote:
> >   
> > > On Thu, May 3, 2018 at 11:40 AM, Boris Brezillon
> > > <boris.brezillon@bootlin.com> wrote:  
> > > > The device might be described in the device tree but not connected to
> > > > the I2C bus. Update the status property so that the DRM panel logic
> > > > returns -ENODEV when someone tries to get the panel attached to this
> > > > DT node.
> > > >
> > > > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > > > ---
> > > >  .../gpu/drm/panel/panel-raspberrypi-touchscreen.c  | 35 ++++++++++++++++++++++
> > > >  1 file changed, 35 insertions(+)
> > > >
> > > > diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > > index 2c9c9722734f..b8fcb1acef75 100644
> > > > --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > > +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > > @@ -358,6 +358,39 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = {
> > > >         .get_modes = rpi_touchscreen_get_modes,
> > > >  };
> > > >
> > > > +static void rpi_touchscreen_set_status_fail(struct i2c_client *i2c)
> > > > +{
> > > > +       struct property *newprop;
> > > > +
> > > > +       newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
> > > > +       if (!newprop)
> > > > +               return;
> > > > +
> > > > +       newprop->name = kstrdup("status", GFP_KERNEL);
> > > > +       if (!newprop->name)
> > > > +               goto err;
> > > > +
> > > > +       newprop->value = kstrdup("fail", GFP_KERNEL);
> > > > +       if (!newprop->value)
> > > > +               goto err;
> > > > +
> > > > +       newprop->length = sizeof("fail");
> > > > +
> > > > +       if (of_update_property(i2c->dev.of_node, newprop))
> > > > +               goto err;
> > > > +    
> > > 
> > > As I mentioned on irc, can you make this a common DT function.  
> > 
> > Yep, will move that to drivers/of/base.c and make it generic.
> >   
> > > 
> > > I'm not sure if it matters that we set status to fail vs. disabled. I
> > > somewhat prefer the latter as we already have other cases and I'd
> > > rather the api not pass a string in. I can't think of any reason to
> > > distinguish the difference between fail and disabled.  
> > 
> > Well, I just read the ePAPR doc pointed by Thierry [1] (section 2.3.4),
> > and "fail" seemed like a good match for what we are trying to express
> > here: "we failed to communicate with the device in the probe function
> > and want to mark it unusable", which is a bit different from "the
> > device was explicitly disabled by the user".
> > 
> > Anyway, if you think "disabled" is more appropriate, I'll use that.
> >   
> > >   
> > > > +       /* We intentionally leak the memory we allocate here, because the new
> > > > +        * OF property might live longer than the underlying dev, so no way
> > > > +        * we can use devm_kzalloc() here.
> > > > +        */
> > > > +       return;
> > > > +
> > > > +err:
> > > > +       kfree(newprop->value);
> > > > +       kfree(newprop->name);
> > > > +       kfree(newprop);
> > > > +}
> > > > +
> > > >  static int rpi_touchscreen_probe(struct i2c_client *i2c,
> > > >                                  const struct i2c_device_id *id)
> > > >  {
> > > > @@ -382,6 +415,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
> > > >
> > > >         ver = rpi_touchscreen_i2c_read(ts, REG_ID);
> > > >         if (ver < 0) {
> > > > +               rpi_touchscreen_set_status_fail(i2c);    
> > > 
> > > I've thought some more about this and I still think this should be
> > > handled in the driver core or i2c core.
> > > 
> > > The reason is simple. I think the state of the system should be the
> > > same after this as if you booted with 'status = "disabled"' for this
> > > node. And that means the device should be removed completely because
> > > we don't create struct device's for disabled nodes.  
> > 
> > That was my feeling to when first discussing the issue with Daniel and
> > Thierry on IRC, but after digging a bit in the code I'm no longer sure
> > this is a good idea. At least, I don't think basing the decision to
> > disable the device (or mark it unusable) based on the return value of
> > the probe function is a good idea.  
> 
> I'm not so sure about that. -ENODEV seems like a very suitable error
> code to base that decision on. A random sampling of a handful of drivers
> confirms that this is primarily used to report situations where it is
> impossible for the device to ever be probed successfully, so might as
> well just remove it.

It's not that easy. It has to be done from the I2C core since it's the
only one who can call device_unregister() and cleanup the other bits
associated with an I2C device (see i2c_unregister_device()). Now, the
i2c_driver->probe() function is called from a context where I'm almost
sure device_unregister() can't be called since we might still be in the
device_register() path. The solution would be to queue the
unregistration work to a workqueue, but I'm not even sure this is safe
to do that. What if the I2C adapter exposing the device is removed in
the meantime? Of course, all of this can be addressed, I'm just
wondering if it's really worth the trouble (we're likely to introduce
new races or other kind of bugs while doing that), especially since
placing the device in a "fail" state and still keeping it around would
solve the problem without requiring all the extra cleanup we're talking
about here.

> 
> At the very least I think it is worth proposing the patch and let Greg
> and others weigh in.

Well, if it was an easy thing to do, I guess I would have gone for this
approach from the beginning, but I fear doing that will be much more
complicated than we think it is (maybe I'm wrong).
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 5/6] drm/vc4: Support the case where the DSI device is disabled
  2018-05-04 12:05     ` Boris Brezillon
@ 2018-05-04 13:29       ` Thierry Reding
  2018-05-04 13:49         ` Boris Brezillon
  0 siblings, 1 reply; 32+ messages in thread
From: Thierry Reding @ 2018-05-04 13:29 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 2823 bytes --]

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

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 5/6] drm/vc4: Support the case where the DSI device is disabled
  2018-05-04 13:29       ` Thierry Reding
@ 2018-05-04 13:49         ` Boris Brezillon
  2018-05-04 13:56           ` Thierry Reding
  0 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2018-05-04 13:49 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala

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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 5/6] drm/vc4: Support the case where the DSI device is disabled
  2018-05-04 13:49         ` Boris Brezillon
@ 2018-05-04 13:56           ` Thierry Reding
  0 siblings, 0 replies; 32+ messages in thread
From: Thierry Reding @ 2018-05-04 13:56 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Rob Herring, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 3424 bytes --]

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

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails
  2018-05-04 12:17         ` Boris Brezillon
@ 2018-05-04 14:20           ` Daniel Vetter
  2018-05-04 14:24             ` Boris Brezillon
  2018-05-04 19:29             ` Rob Herring
  0 siblings, 2 replies; 32+ messages in thread
From: Daniel Vetter @ 2018-05-04 14:20 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mark Rutland, devicetree, Rob Herring, Pawel Moll, Ian Campbell,
	David Airlie, dri-devel, Thierry Reding, Kumar Gala

On Fri, May 04, 2018 at 02:17:49PM +0200, Boris Brezillon wrote:
> On Fri, 4 May 2018 11:47:48 +0200
> Thierry Reding <thierry.reding@gmail.com> wrote:
> 
> > On Fri, May 04, 2018 at 10:06:53AM +0200, Boris Brezillon wrote:
> > > Hi Rob,
> > > 
> > > On Thu, 3 May 2018 12:12:39 -0500
> > > Rob Herring <robh+dt@kernel.org> wrote:
> > >   
> > > > On Thu, May 3, 2018 at 11:40 AM, Boris Brezillon
> > > > <boris.brezillon@bootlin.com> wrote:  
> > > > > The device might be described in the device tree but not connected to
> > > > > the I2C bus. Update the status property so that the DRM panel logic
> > > > > returns -ENODEV when someone tries to get the panel attached to this
> > > > > DT node.
> > > > >
> > > > > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > > > > ---
> > > > >  .../gpu/drm/panel/panel-raspberrypi-touchscreen.c  | 35 ++++++++++++++++++++++
> > > > >  1 file changed, 35 insertions(+)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > > > index 2c9c9722734f..b8fcb1acef75 100644
> > > > > --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > > > +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > > > @@ -358,6 +358,39 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = {
> > > > >         .get_modes = rpi_touchscreen_get_modes,
> > > > >  };
> > > > >
> > > > > +static void rpi_touchscreen_set_status_fail(struct i2c_client *i2c)
> > > > > +{
> > > > > +       struct property *newprop;
> > > > > +
> > > > > +       newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
> > > > > +       if (!newprop)
> > > > > +               return;
> > > > > +
> > > > > +       newprop->name = kstrdup("status", GFP_KERNEL);
> > > > > +       if (!newprop->name)
> > > > > +               goto err;
> > > > > +
> > > > > +       newprop->value = kstrdup("fail", GFP_KERNEL);
> > > > > +       if (!newprop->value)
> > > > > +               goto err;
> > > > > +
> > > > > +       newprop->length = sizeof("fail");
> > > > > +
> > > > > +       if (of_update_property(i2c->dev.of_node, newprop))
> > > > > +               goto err;
> > > > > +    
> > > > 
> > > > As I mentioned on irc, can you make this a common DT function.  
> > > 
> > > Yep, will move that to drivers/of/base.c and make it generic.
> > >   
> > > > 
> > > > I'm not sure if it matters that we set status to fail vs. disabled. I
> > > > somewhat prefer the latter as we already have other cases and I'd
> > > > rather the api not pass a string in. I can't think of any reason to
> > > > distinguish the difference between fail and disabled.  
> > > 
> > > Well, I just read the ePAPR doc pointed by Thierry [1] (section 2.3.4),
> > > and "fail" seemed like a good match for what we are trying to express
> > > here: "we failed to communicate with the device in the probe function
> > > and want to mark it unusable", which is a bit different from "the
> > > device was explicitly disabled by the user".
> > > 
> > > Anyway, if you think "disabled" is more appropriate, I'll use that.
> > >   
> > > >   
> > > > > +       /* We intentionally leak the memory we allocate here, because the new
> > > > > +        * OF property might live longer than the underlying dev, so no way
> > > > > +        * we can use devm_kzalloc() here.
> > > > > +        */
> > > > > +       return;
> > > > > +
> > > > > +err:
> > > > > +       kfree(newprop->value);
> > > > > +       kfree(newprop->name);
> > > > > +       kfree(newprop);
> > > > > +}
> > > > > +
> > > > >  static int rpi_touchscreen_probe(struct i2c_client *i2c,
> > > > >                                  const struct i2c_device_id *id)
> > > > >  {
> > > > > @@ -382,6 +415,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
> > > > >
> > > > >         ver = rpi_touchscreen_i2c_read(ts, REG_ID);
> > > > >         if (ver < 0) {
> > > > > +               rpi_touchscreen_set_status_fail(i2c);    
> > > > 
> > > > I've thought some more about this and I still think this should be
> > > > handled in the driver core or i2c core.
> > > > 
> > > > The reason is simple. I think the state of the system should be the
> > > > same after this as if you booted with 'status = "disabled"' for this
> > > > node. And that means the device should be removed completely because
> > > > we don't create struct device's for disabled nodes.  
> > > 
> > > That was my feeling to when first discussing the issue with Daniel and
> > > Thierry on IRC, but after digging a bit in the code I'm no longer sure
> > > this is a good idea. At least, I don't think basing the decision to
> > > disable the device (or mark it unusable) based on the return value of
> > > the probe function is a good idea.  
> > 
> > I'm not so sure about that. -ENODEV seems like a very suitable error
> > code to base that decision on. A random sampling of a handful of drivers
> > confirms that this is primarily used to report situations where it is
> > impossible for the device to ever be probed successfully, so might as
> > well just remove it.
> 
> It's not that easy. It has to be done from the I2C core since it's the
> only one who can call device_unregister() and cleanup the other bits
> associated with an I2C device (see i2c_unregister_device()). Now, the
> i2c_driver->probe() function is called from a context where I'm almost
> sure device_unregister() can't be called since we might still be in the
> device_register() path. The solution would be to queue the
> unregistration work to a workqueue, but I'm not even sure this is safe
> to do that. What if the I2C adapter exposing the device is removed in
> the meantime? Of course, all of this can be addressed, I'm just
> wondering if it's really worth the trouble (we're likely to introduce
> new races or other kind of bugs while doing that), especially since
> placing the device in a "fail" state and still keeping it around would
> solve the problem without requiring all the extra cleanup we're talking
> about here.

I think you have to put the device status into "fail" immediately,
otherwise there's a race with deferred probing. Scenario:

1. vc4 loads, panel isn't there yet -> EPROBE_DEFER.
2. rpi driver loads, notices panel isn't there, returns -ENODEV
3. i2c core fires off the worker and finishes it's ->probe callback.
4. device core starts a reprobe trigger
5. vc4 gets loaded, does the of_device_is_available check, but since
that's not yet update it doesn't get the ENODEV, but still EPROBE_DEFER.
6. i2c worker disables the device and unregisters it.

-> vc4 fails to load since nothing triggers another reprobe anymore.

At least afaics device removal does not trigger a reprobe.
-Daniel

> 
> > 
> > At the very least I think it is worth proposing the patch and let Greg
> > and others weigh in.
> 
> Well, if it was an easy thing to do, I guess I would have gone for this
> approach from the beginning, but I fear doing that will be much more
> complicated than we think it is (maybe I'm wrong).

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails
  2018-05-04 14:20           ` Daniel Vetter
@ 2018-05-04 14:24             ` Boris Brezillon
  2018-05-04 15:01               ` Boris Brezillon
  2018-05-04 19:29             ` Rob Herring
  1 sibling, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2018-05-04 14:24 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Mark Rutland, devicetree, Rob Herring, Pawel Moll, Ian Campbell,
	David Airlie, dri-devel, Thierry Reding, Kumar Gala

On Fri, 4 May 2018 16:20:17 +0200
Daniel Vetter <daniel@ffwll.ch> wrote:

> On Fri, May 04, 2018 at 02:17:49PM +0200, Boris Brezillon wrote:
> > On Fri, 4 May 2018 11:47:48 +0200
> > Thierry Reding <thierry.reding@gmail.com> wrote:
> >   
> > > On Fri, May 04, 2018 at 10:06:53AM +0200, Boris Brezillon wrote:  
> > > > Hi Rob,
> > > > 
> > > > On Thu, 3 May 2018 12:12:39 -0500
> > > > Rob Herring <robh+dt@kernel.org> wrote:
> > > >     
> > > > > On Thu, May 3, 2018 at 11:40 AM, Boris Brezillon
> > > > > <boris.brezillon@bootlin.com> wrote:    
> > > > > > The device might be described in the device tree but not connected to
> > > > > > the I2C bus. Update the status property so that the DRM panel logic
> > > > > > returns -ENODEV when someone tries to get the panel attached to this
> > > > > > DT node.
> > > > > >
> > > > > > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > > > > > ---
> > > > > >  .../gpu/drm/panel/panel-raspberrypi-touchscreen.c  | 35 ++++++++++++++++++++++
> > > > > >  1 file changed, 35 insertions(+)
> > > > > >
> > > > > > diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > > > > index 2c9c9722734f..b8fcb1acef75 100644
> > > > > > --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > > > > +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > > > > @@ -358,6 +358,39 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = {
> > > > > >         .get_modes = rpi_touchscreen_get_modes,
> > > > > >  };
> > > > > >
> > > > > > +static void rpi_touchscreen_set_status_fail(struct i2c_client *i2c)
> > > > > > +{
> > > > > > +       struct property *newprop;
> > > > > > +
> > > > > > +       newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
> > > > > > +       if (!newprop)
> > > > > > +               return;
> > > > > > +
> > > > > > +       newprop->name = kstrdup("status", GFP_KERNEL);
> > > > > > +       if (!newprop->name)
> > > > > > +               goto err;
> > > > > > +
> > > > > > +       newprop->value = kstrdup("fail", GFP_KERNEL);
> > > > > > +       if (!newprop->value)
> > > > > > +               goto err;
> > > > > > +
> > > > > > +       newprop->length = sizeof("fail");
> > > > > > +
> > > > > > +       if (of_update_property(i2c->dev.of_node, newprop))
> > > > > > +               goto err;
> > > > > > +      
> > > > > 
> > > > > As I mentioned on irc, can you make this a common DT function.    
> > > > 
> > > > Yep, will move that to drivers/of/base.c and make it generic.
> > > >     
> > > > > 
> > > > > I'm not sure if it matters that we set status to fail vs. disabled. I
> > > > > somewhat prefer the latter as we already have other cases and I'd
> > > > > rather the api not pass a string in. I can't think of any reason to
> > > > > distinguish the difference between fail and disabled.    
> > > > 
> > > > Well, I just read the ePAPR doc pointed by Thierry [1] (section 2.3.4),
> > > > and "fail" seemed like a good match for what we are trying to express
> > > > here: "we failed to communicate with the device in the probe function
> > > > and want to mark it unusable", which is a bit different from "the
> > > > device was explicitly disabled by the user".
> > > > 
> > > > Anyway, if you think "disabled" is more appropriate, I'll use that.
> > > >     
> > > > >     
> > > > > > +       /* We intentionally leak the memory we allocate here, because the new
> > > > > > +        * OF property might live longer than the underlying dev, so no way
> > > > > > +        * we can use devm_kzalloc() here.
> > > > > > +        */
> > > > > > +       return;
> > > > > > +
> > > > > > +err:
> > > > > > +       kfree(newprop->value);
> > > > > > +       kfree(newprop->name);
> > > > > > +       kfree(newprop);
> > > > > > +}
> > > > > > +
> > > > > >  static int rpi_touchscreen_probe(struct i2c_client *i2c,
> > > > > >                                  const struct i2c_device_id *id)
> > > > > >  {
> > > > > > @@ -382,6 +415,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
> > > > > >
> > > > > >         ver = rpi_touchscreen_i2c_read(ts, REG_ID);
> > > > > >         if (ver < 0) {
> > > > > > +               rpi_touchscreen_set_status_fail(i2c);      
> > > > > 
> > > > > I've thought some more about this and I still think this should be
> > > > > handled in the driver core or i2c core.
> > > > > 
> > > > > The reason is simple. I think the state of the system should be the
> > > > > same after this as if you booted with 'status = "disabled"' for this
> > > > > node. And that means the device should be removed completely because
> > > > > we don't create struct device's for disabled nodes.    
> > > > 
> > > > That was my feeling to when first discussing the issue with Daniel and
> > > > Thierry on IRC, but after digging a bit in the code I'm no longer sure
> > > > this is a good idea. At least, I don't think basing the decision to
> > > > disable the device (or mark it unusable) based on the return value of
> > > > the probe function is a good idea.    
> > > 
> > > I'm not so sure about that. -ENODEV seems like a very suitable error
> > > code to base that decision on. A random sampling of a handful of drivers
> > > confirms that this is primarily used to report situations where it is
> > > impossible for the device to ever be probed successfully, so might as
> > > well just remove it.  
> > 
> > It's not that easy. It has to be done from the I2C core since it's the
> > only one who can call device_unregister() and cleanup the other bits
> > associated with an I2C device (see i2c_unregister_device()). Now, the
> > i2c_driver->probe() function is called from a context where I'm almost
> > sure device_unregister() can't be called since we might still be in the
> > device_register() path. The solution would be to queue the
> > unregistration work to a workqueue, but I'm not even sure this is safe
> > to do that. What if the I2C adapter exposing the device is removed in
> > the meantime? Of course, all of this can be addressed, I'm just
> > wondering if it's really worth the trouble (we're likely to introduce
> > new races or other kind of bugs while doing that), especially since
> > placing the device in a "fail" state and still keeping it around would
> > solve the problem without requiring all the extra cleanup we're talking
> > about here.  
> 
> I think you have to put the device status into "fail" immediately,
> otherwise there's a race with deferred probing. Scenario:
> 
> 1. vc4 loads, panel isn't there yet -> EPROBE_DEFER.
> 2. rpi driver loads, notices panel isn't there, returns -ENODEV
> 3. i2c core fires off the worker and finishes it's ->probe callback.
> 4. device core starts a reprobe trigger
> 5. vc4 gets loaded, does the of_device_is_available check, but since
> that's not yet update it doesn't get the ENODEV, but still EPROBE_DEFER.
> 6. i2c worker disables the device and unregisters it.
> 
> -> vc4 fails to load since nothing triggers another reprobe anymore.  
> 
> At least afaics device removal does not trigger a reprobe.

Yep, you're correct. See, one more reason to keep the logic simple and
let each driver change the status prop in their ->probe() function.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails
  2018-05-04 14:24             ` Boris Brezillon
@ 2018-05-04 15:01               ` Boris Brezillon
  0 siblings, 0 replies; 32+ messages in thread
From: Boris Brezillon @ 2018-05-04 15:01 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Mark Rutland, devicetree, Rob Herring, Pawel Moll, Ian Campbell,
	David Airlie, dri-devel, Thierry Reding, Kumar Gala

On Fri, 4 May 2018 16:24:04 +0200
Boris Brezillon <boris.brezillon@bootlin.com> wrote:

> On Fri, 4 May 2018 16:20:17 +0200
> Daniel Vetter <daniel@ffwll.ch> wrote:
> 
> > On Fri, May 04, 2018 at 02:17:49PM +0200, Boris Brezillon wrote:  
> > > On Fri, 4 May 2018 11:47:48 +0200
> > > Thierry Reding <thierry.reding@gmail.com> wrote:
> > >     
> > > > On Fri, May 04, 2018 at 10:06:53AM +0200, Boris Brezillon wrote:    
> > > > > Hi Rob,
> > > > > 
> > > > > On Thu, 3 May 2018 12:12:39 -0500
> > > > > Rob Herring <robh+dt@kernel.org> wrote:
> > > > >       
> > > > > > On Thu, May 3, 2018 at 11:40 AM, Boris Brezillon
> > > > > > <boris.brezillon@bootlin.com> wrote:      
> > > > > > > The device might be described in the device tree but not connected to
> > > > > > > the I2C bus. Update the status property so that the DRM panel logic
> > > > > > > returns -ENODEV when someone tries to get the panel attached to this
> > > > > > > DT node.
> > > > > > >
> > > > > > > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > > > > > > ---
> > > > > > >  .../gpu/drm/panel/panel-raspberrypi-touchscreen.c  | 35 ++++++++++++++++++++++
> > > > > > >  1 file changed, 35 insertions(+)
> > > > > > >
> > > > > > > diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > > > > > index 2c9c9722734f..b8fcb1acef75 100644
> > > > > > > --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > > > > > +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> > > > > > > @@ -358,6 +358,39 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = {
> > > > > > >         .get_modes = rpi_touchscreen_get_modes,
> > > > > > >  };
> > > > > > >
> > > > > > > +static void rpi_touchscreen_set_status_fail(struct i2c_client *i2c)
> > > > > > > +{
> > > > > > > +       struct property *newprop;
> > > > > > > +
> > > > > > > +       newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
> > > > > > > +       if (!newprop)
> > > > > > > +               return;
> > > > > > > +
> > > > > > > +       newprop->name = kstrdup("status", GFP_KERNEL);
> > > > > > > +       if (!newprop->name)
> > > > > > > +               goto err;
> > > > > > > +
> > > > > > > +       newprop->value = kstrdup("fail", GFP_KERNEL);
> > > > > > > +       if (!newprop->value)
> > > > > > > +               goto err;
> > > > > > > +
> > > > > > > +       newprop->length = sizeof("fail");
> > > > > > > +
> > > > > > > +       if (of_update_property(i2c->dev.of_node, newprop))
> > > > > > > +               goto err;
> > > > > > > +        
> > > > > > 
> > > > > > As I mentioned on irc, can you make this a common DT function.      
> > > > > 
> > > > > Yep, will move that to drivers/of/base.c and make it generic.
> > > > >       
> > > > > > 
> > > > > > I'm not sure if it matters that we set status to fail vs. disabled. I
> > > > > > somewhat prefer the latter as we already have other cases and I'd
> > > > > > rather the api not pass a string in. I can't think of any reason to
> > > > > > distinguish the difference between fail and disabled.      
> > > > > 
> > > > > Well, I just read the ePAPR doc pointed by Thierry [1] (section 2.3.4),
> > > > > and "fail" seemed like a good match for what we are trying to express
> > > > > here: "we failed to communicate with the device in the probe function
> > > > > and want to mark it unusable", which is a bit different from "the
> > > > > device was explicitly disabled by the user".
> > > > > 
> > > > > Anyway, if you think "disabled" is more appropriate, I'll use that.
> > > > >       
> > > > > >       
> > > > > > > +       /* We intentionally leak the memory we allocate here, because the new
> > > > > > > +        * OF property might live longer than the underlying dev, so no way
> > > > > > > +        * we can use devm_kzalloc() here.
> > > > > > > +        */
> > > > > > > +       return;
> > > > > > > +
> > > > > > > +err:
> > > > > > > +       kfree(newprop->value);
> > > > > > > +       kfree(newprop->name);
> > > > > > > +       kfree(newprop);
> > > > > > > +}
> > > > > > > +
> > > > > > >  static int rpi_touchscreen_probe(struct i2c_client *i2c,
> > > > > > >                                  const struct i2c_device_id *id)
> > > > > > >  {
> > > > > > > @@ -382,6 +415,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
> > > > > > >
> > > > > > >         ver = rpi_touchscreen_i2c_read(ts, REG_ID);
> > > > > > >         if (ver < 0) {
> > > > > > > +               rpi_touchscreen_set_status_fail(i2c);        
> > > > > > 
> > > > > > I've thought some more about this and I still think this should be
> > > > > > handled in the driver core or i2c core.
> > > > > > 
> > > > > > The reason is simple. I think the state of the system should be the
> > > > > > same after this as if you booted with 'status = "disabled"' for this
> > > > > > node. And that means the device should be removed completely because
> > > > > > we don't create struct device's for disabled nodes.      
> > > > > 
> > > > > That was my feeling to when first discussing the issue with Daniel and
> > > > > Thierry on IRC, but after digging a bit in the code I'm no longer sure
> > > > > this is a good idea. At least, I don't think basing the decision to
> > > > > disable the device (or mark it unusable) based on the return value of
> > > > > the probe function is a good idea.      
> > > > 
> > > > I'm not so sure about that. -ENODEV seems like a very suitable error
> > > > code to base that decision on. A random sampling of a handful of drivers
> > > > confirms that this is primarily used to report situations where it is
> > > > impossible for the device to ever be probed successfully, so might as
> > > > well just remove it.    
> > > 
> > > It's not that easy. It has to be done from the I2C core since it's the
> > > only one who can call device_unregister() and cleanup the other bits
> > > associated with an I2C device (see i2c_unregister_device()). Now, the
> > > i2c_driver->probe() function is called from a context where I'm almost
> > > sure device_unregister() can't be called since we might still be in the
> > > device_register() path. The solution would be to queue the
> > > unregistration work to a workqueue, but I'm not even sure this is safe
> > > to do that. What if the I2C adapter exposing the device is removed in
> > > the meantime? Of course, all of this can be addressed, I'm just
> > > wondering if it's really worth the trouble (we're likely to introduce
> > > new races or other kind of bugs while doing that), especially since
> > > placing the device in a "fail" state and still keeping it around would
> > > solve the problem without requiring all the extra cleanup we're talking
> > > about here.    
> > 
> > I think you have to put the device status into "fail" immediately,
> > otherwise there's a race with deferred probing. Scenario:
> > 
> > 1. vc4 loads, panel isn't there yet -> EPROBE_DEFER.
> > 2. rpi driver loads, notices panel isn't there, returns -ENODEV
> > 3. i2c core fires off the worker and finishes it's ->probe callback.
> > 4. device core starts a reprobe trigger
> > 5. vc4 gets loaded, does the of_device_is_available check, but since
> > that's not yet update it doesn't get the ENODEV, but still EPROBE_DEFER.
> > 6. i2c worker disables the device and unregisters it.
> >   
> > -> vc4 fails to load since nothing triggers another reprobe anymore.    
> > 
> > At least afaics device removal does not trigger a reprobe.  
> 
> Yep, you're correct. See, one more reason to keep the logic simple and
> let each driver change the status prop in their ->probe() function.

Hm, actually it does not work even with my solution because the only
thing that forces a new attempt on all deferred-probe devices is when a
new device is bound to a driver, which will not happen if the rpi-panel
->probe() function returns -ENODEV.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails
  2018-05-04 14:20           ` Daniel Vetter
  2018-05-04 14:24             ` Boris Brezillon
@ 2018-05-04 19:29             ` Rob Herring
  2018-05-07 11:14               ` Boris Brezillon
  1 sibling, 1 reply; 32+ messages in thread
From: Rob Herring @ 2018-05-04 19:29 UTC (permalink / raw)
  To: Daniel Vetter, Boris Brezillon
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Thierry Reding, Kumar Gala

On Fri, May 4, 2018 at 9:20 AM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Fri, May 04, 2018 at 02:17:49PM +0200, Boris Brezillon wrote:
>> On Fri, 4 May 2018 11:47:48 +0200
>> Thierry Reding <thierry.reding@gmail.com> wrote:
>>
>> > On Fri, May 04, 2018 at 10:06:53AM +0200, Boris Brezillon wrote:
>> > > Hi Rob,
>> > >
>> > > On Thu, 3 May 2018 12:12:39 -0500
>> > > Rob Herring <robh+dt@kernel.org> wrote:
>> > >
>> > > > On Thu, May 3, 2018 at 11:40 AM, Boris Brezillon
>> > > > <boris.brezillon@bootlin.com> wrote:
>> > > > > The device might be described in the device tree but not connected to
>> > > > > the I2C bus. Update the status property so that the DRM panel logic
>> > > > > returns -ENODEV when someone tries to get the panel attached to this
>> > > > > DT node.
>> > > > >
>> > > > > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
>> > > > > ---
>> > > > >  .../gpu/drm/panel/panel-raspberrypi-touchscreen.c  | 35 ++++++++++++++++++++++
>> > > > >  1 file changed, 35 insertions(+)
>> > > > >
>> > > > > diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
>> > > > > index 2c9c9722734f..b8fcb1acef75 100644
>> > > > > --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
>> > > > > +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
>> > > > > @@ -358,6 +358,39 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = {
>> > > > >         .get_modes = rpi_touchscreen_get_modes,
>> > > > >  };
>> > > > >
>> > > > > +static void rpi_touchscreen_set_status_fail(struct i2c_client *i2c)
>> > > > > +{
>> > > > > +       struct property *newprop;
>> > > > > +
>> > > > > +       newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
>> > > > > +       if (!newprop)
>> > > > > +               return;
>> > > > > +
>> > > > > +       newprop->name = kstrdup("status", GFP_KERNEL);
>> > > > > +       if (!newprop->name)
>> > > > > +               goto err;
>> > > > > +
>> > > > > +       newprop->value = kstrdup("fail", GFP_KERNEL);
>> > > > > +       if (!newprop->value)
>> > > > > +               goto err;
>> > > > > +
>> > > > > +       newprop->length = sizeof("fail");
>> > > > > +
>> > > > > +       if (of_update_property(i2c->dev.of_node, newprop))
>> > > > > +               goto err;
>> > > > > +
>> > > >
>> > > > As I mentioned on irc, can you make this a common DT function.
>> > >
>> > > Yep, will move that to drivers/of/base.c and make it generic.
>> > >
>> > > >
>> > > > I'm not sure if it matters that we set status to fail vs. disabled. I
>> > > > somewhat prefer the latter as we already have other cases and I'd
>> > > > rather the api not pass a string in. I can't think of any reason to
>> > > > distinguish the difference between fail and disabled.
>> > >
>> > > Well, I just read the ePAPR doc pointed by Thierry [1] (section 2.3.4),
>> > > and "fail" seemed like a good match for what we are trying to express
>> > > here: "we failed to communicate with the device in the probe function
>> > > and want to mark it unusable", which is a bit different from "the
>> > > device was explicitly disabled by the user".
>> > >
>> > > Anyway, if you think "disabled" is more appropriate, I'll use that.
>> > >
>> > > >
>> > > > > +       /* We intentionally leak the memory we allocate here, because the new
>> > > > > +        * OF property might live longer than the underlying dev, so no way
>> > > > > +        * we can use devm_kzalloc() here.
>> > > > > +        */
>> > > > > +       return;
>> > > > > +
>> > > > > +err:
>> > > > > +       kfree(newprop->value);
>> > > > > +       kfree(newprop->name);
>> > > > > +       kfree(newprop);
>> > > > > +}
>> > > > > +
>> > > > >  static int rpi_touchscreen_probe(struct i2c_client *i2c,
>> > > > >                                  const struct i2c_device_id *id)
>> > > > >  {
>> > > > > @@ -382,6 +415,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
>> > > > >
>> > > > >         ver = rpi_touchscreen_i2c_read(ts, REG_ID);
>> > > > >         if (ver < 0) {
>> > > > > +               rpi_touchscreen_set_status_fail(i2c);
>> > > >
>> > > > I've thought some more about this and I still think this should be
>> > > > handled in the driver core or i2c core.
>> > > >
>> > > > The reason is simple. I think the state of the system should be the
>> > > > same after this as if you booted with 'status = "disabled"' for this
>> > > > node. And that means the device should be removed completely because
>> > > > we don't create struct device's for disabled nodes.
>> > >
>> > > That was my feeling to when first discussing the issue with Daniel and
>> > > Thierry on IRC, but after digging a bit in the code I'm no longer sure
>> > > this is a good idea. At least, I don't think basing the decision to
>> > > disable the device (or mark it unusable) based on the return value of
>> > > the probe function is a good idea.
>> >
>> > I'm not so sure about that. -ENODEV seems like a very suitable error
>> > code to base that decision on. A random sampling of a handful of drivers
>> > confirms that this is primarily used to report situations where it is
>> > impossible for the device to ever be probed successfully, so might as
>> > well just remove it.
>>
>> It's not that easy. It has to be done from the I2C core since it's the
>> only one who can call device_unregister() and cleanup the other bits
>> associated with an I2C device (see i2c_unregister_device()). Now, the
>> i2c_driver->probe() function is called from a context where I'm almost
>> sure device_unregister() can't be called since we might still be in the
>> device_register() path. The solution would be to queue the
>> unregistration work to a workqueue, but I'm not even sure this is safe
>> to do that. What if the I2C adapter exposing the device is removed in
>> the meantime? Of course, all of this can be addressed, I'm just
>> wondering if it's really worth the trouble (we're likely to introduce
>> new races or other kind of bugs while doing that), especially since
>> placing the device in a "fail" state and still keeping it around would
>> solve the problem without requiring all the extra cleanup we're talking
>> about here.
>
> I think you have to put the device status into "fail" immediately,
> otherwise there's a race with deferred probing. Scenario:
>
> 1. vc4 loads, panel isn't there yet -> EPROBE_DEFER.
> 2. rpi driver loads, notices panel isn't there, returns -ENODEV

Step 3a: i2c core updates device DT status property
Step 3b: i2c core fires off worker for device_unregister

That solves the race, right?

> 3. i2c core fires off the worker and finishes it's ->probe callback.
> 4. device core starts a reprobe trigger
> 5. vc4 gets loaded, does the of_device_is_available check, but since
> that's not yet update it doesn't get the ENODEV, but still EPROBE_DEFER.
> 6. i2c worker disables the device and unregisters it.
>
> -> vc4 fails to load since nothing triggers another reprobe anymore.
>
> At least afaics device removal does not trigger a reprobe.
> -Daniel
>
>>
>> >
>> > At the very least I think it is worth proposing the patch and let Greg
>> > and others weigh in.
>>
>> Well, if it was an easy thing to do, I guess I would have gone for this
>> approach from the beginning, but I fear doing that will be much more
>> complicated than we think it is (maybe I'm wrong).
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails
  2018-05-04 19:29             ` Rob Herring
@ 2018-05-07 11:14               ` Boris Brezillon
  0 siblings, 0 replies; 32+ messages in thread
From: Boris Brezillon @ 2018-05-07 11:14 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell, David Airlie,
	dri-devel, Thierry Reding, Kumar Gala

On Fri, 4 May 2018 14:29:27 -0500
Rob Herring <robh+dt@kernel.org> wrote:

> On Fri, May 4, 2018 at 9:20 AM, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Fri, May 04, 2018 at 02:17:49PM +0200, Boris Brezillon wrote:  
> >> On Fri, 4 May 2018 11:47:48 +0200
> >> Thierry Reding <thierry.reding@gmail.com> wrote:
> >>  
> >> > On Fri, May 04, 2018 at 10:06:53AM +0200, Boris Brezillon wrote:  
> >> > > Hi Rob,
> >> > >
> >> > > On Thu, 3 May 2018 12:12:39 -0500
> >> > > Rob Herring <robh+dt@kernel.org> wrote:
> >> > >  
> >> > > > On Thu, May 3, 2018 at 11:40 AM, Boris Brezillon
> >> > > > <boris.brezillon@bootlin.com> wrote:  
> >> > > > > The device might be described in the device tree but not connected to
> >> > > > > the I2C bus. Update the status property so that the DRM panel logic
> >> > > > > returns -ENODEV when someone tries to get the panel attached to this
> >> > > > > DT node.
> >> > > > >
> >> > > > > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> >> > > > > ---
> >> > > > >  .../gpu/drm/panel/panel-raspberrypi-touchscreen.c  | 35 ++++++++++++++++++++++
> >> > > > >  1 file changed, 35 insertions(+)
> >> > > > >
> >> > > > > diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> >> > > > > index 2c9c9722734f..b8fcb1acef75 100644
> >> > > > > --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> >> > > > > +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
> >> > > > > @@ -358,6 +358,39 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = {
> >> > > > >         .get_modes = rpi_touchscreen_get_modes,
> >> > > > >  };
> >> > > > >
> >> > > > > +static void rpi_touchscreen_set_status_fail(struct i2c_client *i2c)
> >> > > > > +{
> >> > > > > +       struct property *newprop;
> >> > > > > +
> >> > > > > +       newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
> >> > > > > +       if (!newprop)
> >> > > > > +               return;
> >> > > > > +
> >> > > > > +       newprop->name = kstrdup("status", GFP_KERNEL);
> >> > > > > +       if (!newprop->name)
> >> > > > > +               goto err;
> >> > > > > +
> >> > > > > +       newprop->value = kstrdup("fail", GFP_KERNEL);
> >> > > > > +       if (!newprop->value)
> >> > > > > +               goto err;
> >> > > > > +
> >> > > > > +       newprop->length = sizeof("fail");
> >> > > > > +
> >> > > > > +       if (of_update_property(i2c->dev.of_node, newprop))
> >> > > > > +               goto err;
> >> > > > > +  
> >> > > >
> >> > > > As I mentioned on irc, can you make this a common DT function.  
> >> > >
> >> > > Yep, will move that to drivers/of/base.c and make it generic.
> >> > >  
> >> > > >
> >> > > > I'm not sure if it matters that we set status to fail vs. disabled. I
> >> > > > somewhat prefer the latter as we already have other cases and I'd
> >> > > > rather the api not pass a string in. I can't think of any reason to
> >> > > > distinguish the difference between fail and disabled.  
> >> > >
> >> > > Well, I just read the ePAPR doc pointed by Thierry [1] (section 2.3.4),
> >> > > and "fail" seemed like a good match for what we are trying to express
> >> > > here: "we failed to communicate with the device in the probe function
> >> > > and want to mark it unusable", which is a bit different from "the
> >> > > device was explicitly disabled by the user".
> >> > >
> >> > > Anyway, if you think "disabled" is more appropriate, I'll use that.
> >> > >  
> >> > > >  
> >> > > > > +       /* We intentionally leak the memory we allocate here, because the new
> >> > > > > +        * OF property might live longer than the underlying dev, so no way
> >> > > > > +        * we can use devm_kzalloc() here.
> >> > > > > +        */
> >> > > > > +       return;
> >> > > > > +
> >> > > > > +err:
> >> > > > > +       kfree(newprop->value);
> >> > > > > +       kfree(newprop->name);
> >> > > > > +       kfree(newprop);
> >> > > > > +}
> >> > > > > +
> >> > > > >  static int rpi_touchscreen_probe(struct i2c_client *i2c,
> >> > > > >                                  const struct i2c_device_id *id)
> >> > > > >  {
> >> > > > > @@ -382,6 +415,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
> >> > > > >
> >> > > > >         ver = rpi_touchscreen_i2c_read(ts, REG_ID);
> >> > > > >         if (ver < 0) {
> >> > > > > +               rpi_touchscreen_set_status_fail(i2c);  
> >> > > >
> >> > > > I've thought some more about this and I still think this should be
> >> > > > handled in the driver core or i2c core.
> >> > > >
> >> > > > The reason is simple. I think the state of the system should be the
> >> > > > same after this as if you booted with 'status = "disabled"' for this
> >> > > > node. And that means the device should be removed completely because
> >> > > > we don't create struct device's for disabled nodes.  
> >> > >
> >> > > That was my feeling to when first discussing the issue with Daniel and
> >> > > Thierry on IRC, but after digging a bit in the code I'm no longer sure
> >> > > this is a good idea. At least, I don't think basing the decision to
> >> > > disable the device (or mark it unusable) based on the return value of
> >> > > the probe function is a good idea.  
> >> >
> >> > I'm not so sure about that. -ENODEV seems like a very suitable error
> >> > code to base that decision on. A random sampling of a handful of drivers
> >> > confirms that this is primarily used to report situations where it is
> >> > impossible for the device to ever be probed successfully, so might as
> >> > well just remove it.  
> >>
> >> It's not that easy. It has to be done from the I2C core since it's the
> >> only one who can call device_unregister() and cleanup the other bits
> >> associated with an I2C device (see i2c_unregister_device()). Now, the
> >> i2c_driver->probe() function is called from a context where I'm almost
> >> sure device_unregister() can't be called since we might still be in the
> >> device_register() path. The solution would be to queue the
> >> unregistration work to a workqueue, but I'm not even sure this is safe
> >> to do that. What if the I2C adapter exposing the device is removed in
> >> the meantime? Of course, all of this can be addressed, I'm just
> >> wondering if it's really worth the trouble (we're likely to introduce
> >> new races or other kind of bugs while doing that), especially since
> >> placing the device in a "fail" state and still keeping it around would
> >> solve the problem without requiring all the extra cleanup we're talking
> >> about here.  
> >
> > I think you have to put the device status into "fail" immediately,
> > otherwise there's a race with deferred probing. Scenario:
> >
> > 1. vc4 loads, panel isn't there yet -> EPROBE_DEFER.
> > 2. rpi driver loads, notices panel isn't there, returns -ENODEV  
> 
> Step 3a: i2c core updates device DT status property
> Step 3b: i2c core fires off worker for device_unregister
> 
> That solves the race, right?

Yep, that should solve this particular race, but we still have a
problem with the deferred-probe trigger. The only thing that forces all
devices that have seen -EPROBE_DEFER to be probed again is when a
device is bound to a driver, which in our case won't happen because we
return -ENODEV. If we're lucky, something else in the system will
trigger that after the I2C core has changed the status prop, and if
we're not, the DRM dev will never but probed again.

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

end of thread, other threads:[~2018-05-07 11:14 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-03 16:40 [PATCH v2 0/6] drm/panel: Handle the "panel is missing" case properly Boris Brezillon
2018-05-03 16:40 ` [PATCH v2 1/6] drm/tegra: Fix a device_node leak when the DRM panel is not found Boris Brezillon
2018-05-03 16:40   ` Boris Brezillon
2018-05-04  9:50   ` Thierry Reding
2018-05-04  9:53     ` Thierry Reding
2018-05-04  9:54     ` Boris Brezillon
2018-05-03 16:40 ` [PATCH v2 2/6] drm/panel: Make of_drm_find_panel() return an ERR_PTR() instead of NULL Boris Brezillon
2018-05-04 10:18   ` Thierry Reding
2018-05-04 11:58     ` Boris Brezillon
2018-05-04 12:11       ` Thierry Reding
2018-05-03 16:40 ` [PATCH v2 3/6] drm/panel: Let of_drm_find_panel() return -ENODEV when the panel is disabled Boris Brezillon
2018-05-04 10:20   ` Thierry Reding
2018-05-03 16:40 ` [PATCH v2 4/6] drm/of: Make drm_of_find_panel_or_bridge() fail when the device " Boris Brezillon
2018-05-04 10:20   ` Thierry Reding
2018-05-03 16:40 ` [PATCH v2 5/6] drm/vc4: Support the case where the DSI " Boris Brezillon
2018-05-04 10:28   ` Thierry Reding
2018-05-04 12:05     ` Boris Brezillon
2018-05-04 13:29       ` Thierry Reding
2018-05-04 13:49         ` Boris Brezillon
2018-05-04 13:56           ` Thierry Reding
2018-05-04 10:30   ` Thierry Reding
2018-05-04 12:00     ` Boris Brezillon
2018-05-03 16:40 ` [PATCH v2 6/6] drm/panel: rpi-touchscreen: Set status to "fail" when ->probe() fails Boris Brezillon
2018-05-03 17:12   ` Rob Herring
2018-05-04  8:06     ` Boris Brezillon
2018-05-04  9:47       ` Thierry Reding
2018-05-04 12:17         ` Boris Brezillon
2018-05-04 14:20           ` Daniel Vetter
2018-05-04 14:24             ` Boris Brezillon
2018-05-04 15:01               ` Boris Brezillon
2018-05-04 19:29             ` Rob Herring
2018-05-07 11:14               ` Boris Brezillon

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.