On 18/05/18 14:51, Andrzej Hajda wrote: > On 26.04.2018 10:07, Jyri Sarha wrote: >> Add device_link from panel device (supplier) to drm device (consumer) >> when drm_panel_attach() is called. This patch should protect the >> master drm driver if an attached panel driver unbinds while it is in >> use. The device_link should make sure the drm device is unbound before >> the panel driver becomes unavailable. >> >> The device_link is removed when drm_panel_detach() is called. The >> drm_panel_detach() should be called by the consumer DRM driver, not the >> panel driver, otherwise both drivers are racing to delete the same link. >> >> Signed-off-by: Jyri Sarha <jsa...@ti.com> >> Reviewed-by: Eric Anholt <e...@anholt.net> > > Hi Jyri, > > This patch breaks few platforms: tm2, tm2e, trats2 - ie all platforms > using exynos_drm_dsi and dsi panels. > Exynos-DSI properly handles panels unbind - ie references to panel are > properly removed on panels removal and respective drm_connector enters > disconnected state, without destroying whole drm device. > And again on panel driver re-bind drm_panel is properly attached to > exynos-dsi and panel pipeline is working again. > This patch will break this behavior, ie it will destroy whole drm device. > > Making device_links for panels optional seems to me the best solution, > what do you think? >
Sounds good to me. Unfortunately I have no time to spend on this in the coming two weeks. If you can come up with a fix, please send patch and put me in cc. I am also fine with reverting the patch. > The funny thing is that due to bug in device link code, your patch has > no effect on these platforms. So it does not hurt these platform yet, > but the bug will be fixed sooner or later. > The trick in case of exynos-dsi is to use mipi_dsi attach/detach > callbacks to get notifications about drm_panel's > appearance/disappearance, I guess ultimately such callbacks should be a > part of drm_panel > framework. > That sounds like an ultimate solution, especially if there is a default behaviour that unbinds the master drm device as the most devices do not need anything else. Best regards, Jyri > Below description how all the code works: > Initialization: > 1. exynos_dsi (component of exynos_drm) at the end of bind callback > registers mipi_dsi bus. > 2. during mipi_dsi bus registration or later (if panel driver was not > yet registered), panel driver is bound ie - its probe callback is called. > 3. during panel's probe drm_panel_add is called, and later mipi_dsi_attach. > 4. mipi_dsi_attach calls dsi .attach callback of exynos_dsi. > 5. exynos_dsi.attach callback looks for drm_panel, calls > drm_panel_attach and changes connector's status to connected. > .... > Panel's unbind: > 1. device_release_driver calls panel's remove callback. > 2. panel's remove callback calls mipi_dsi_detach. > 3. mipi_dsi_detach calls exynos_dsi.detach callback. > 4. exynos_dsi.detach calls drm_panel_detach and changes connector's > state to disconnected. > > Panel's rebind is equivalent of steps 2-4 of Initialization. > > I have wrote the code few years ago, and it seemed to me the only safe > way to handle dynamic panel bind/unbind. > For example please note that step 5 of initialization and steps 2-4 of > unbind are executed always under panel's device_lock so it makes it > safe. Otherwise you risk that between panel lookup and panel attach > panel's driver can be unbind and consumer is left with dangling panel's > pointer, so even with your patch most of the drivers are still buggy. > > And few words about the bug(?) in device_link code: If you call > device_link_add from probe of the supplier(as it is in this case) its > status is set to DL_STATE_DORMANT, and after successful bind it is > changed to DL_STATE_AVAILABLE, which is incorrect (it should be > DL_STATE_ACTIVE), as a result on supplier's unbind consumer is not unbound. > > Regards > Andrzej > >> --- >> drivers/gpu/drm/drm_panel.c | 10 ++++++++++ >> include/drm/drm_panel.h | 1 + >> 2 files changed, 11 insertions(+) >> >> diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c >> index 71e4075..965530a 100644 >> --- a/drivers/gpu/drm/drm_panel.c >> +++ b/drivers/gpu/drm/drm_panel.c >> @@ -24,6 +24,7 @@ >> #include <linux/err.h> >> #include <linux/module.h> >> >> +#include <drm/drm_device.h> >> #include <drm/drm_crtc.h> >> #include <drm/drm_panel.h> >> >> @@ -104,6 +105,13 @@ int drm_panel_attach(struct drm_panel *panel, struct >> drm_connector *connector) >> if (panel->connector) >> return -EBUSY; >> >> + panel->link = device_link_add(connector->dev->dev, panel->dev, 0); >> + if (!panel->link) { >> + dev_err(panel->dev, "failed to link panel to %s\n", >> + dev_name(connector->dev->dev)); >> + return -EINVAL; >> + } >> + >> panel->connector = connector; >> panel->drm = connector->dev; >> >> @@ -125,6 +133,8 @@ EXPORT_SYMBOL(drm_panel_attach); >> */ >> int drm_panel_detach(struct drm_panel *panel) >> { >> + device_link_del(panel->link); >> + >> panel->connector = NULL; >> panel->drm = NULL; >> >> diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h >> index 14ac240..26a1b5f 100644 >> --- a/include/drm/drm_panel.h >> +++ b/include/drm/drm_panel.h >> @@ -89,6 +89,7 @@ struct drm_panel { >> struct drm_device *drm; >> struct drm_connector *connector; >> struct device *dev; >> + struct device_link *link; >> >> const struct drm_panel_funcs *funcs; >> > > -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel