From af509d38bbbcf1b6a731389632ad367db7bc4ef5 Mon Sep 17 00:00:00 2001 From: Lyude Date: Wed, 4 May 2016 11:28:53 -0400 Subject: [PATCH 1/6] drm/fb_helper: Fix a few typos s/modest/modeset/ s/aftert/after/ Signed-off-by: Lyude Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1462375734-8213-3-git-send-email-cpaul@redhat.com --- drivers/gpu/drm/drm_fb_helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 0bb3d4bee24c8..385284bc773cc 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -2177,8 +2177,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) * cmdline option. * * The other option is to just disable fbdev emulation since very likely the - * first modest from userspace will crash in the same way, and is even easier to - * debug. This can be done by setting the drm_kms_helper.fbdev_emulation=0 + * first modeset from userspace will crash in the same way, and is even easier + * to debug. This can be done by setting the drm_kms_helper.fbdev_emulation=0 * kernel cmdline option. * * RETURNS: @@ -2223,7 +2223,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config); * hotplug interrupt). * * Note that drivers may call this even before calling - * drm_fb_helper_initial_config but only aftert drm_fb_helper_init. This allows + * drm_fb_helper_initial_config but only after drm_fb_helper_init. This allows * for a race-free fbcon setup and will make sure that the fbdev emulation will * not miss any hotplug events. * From 0e1a485b275a0f1900bbd1a6d23b31bcc3d3f992 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 4 May 2016 15:42:07 +0200 Subject: [PATCH 2/6] drm: Fix up markup fumble It's & for struct references, not #. Signed-off-by: Daniel Vetter Acked-by: Jani Nikula Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1462369327-26659-1-git-send-email-daniel.vetter@ffwll.ch --- include/drm/drm_modeset_helper_vtables.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index b61c2d45192e1..d4619dc2eecb4 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -672,7 +672,7 @@ struct drm_connector_helper_funcs { * fixed panel can also manually add specific modes using * drm_mode_probed_add(). Drivers which manually add modes should also * make sure that the @display_info, @width_mm and @height_mm fields of the - * struct #drm_connector are filled in. + * struct &drm_connector are filled in. * * Virtual drivers that just want some standard VESA mode with a given * resolution can call drm_add_modes_noedid(), and mark the preferred From f2d580b9a8149735cbc4b59c4a8df60173658140 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 4 May 2016 14:38:26 +0200 Subject: [PATCH 3/6] drm/core: Do not preserve framebuffer on rmfb, v4. It turns out that preserving framebuffers after the rmfb call breaks vmwgfx userspace. This was originally introduced because it was thought nobody relied on the behavior, but unfortunately it seems there are exceptions. drm_framebuffer_remove may fail with -EINTR now, so a straight revert is impossible. There is no way to remove the framebuffer from the lists and active planes without introducing a race because of the different locking requirements. Instead call drm_framebuffer_remove from a workqueue, which is unaffected by signals. Changes since v1: - Add comment. Changes since v2: - Add fastpath for refcount = 1. (danvet) Changes since v3: - Rebased. - Restore lastclose framebuffer removal too. Cc: stable@vger.kernel.org #v4.4+ Fixes: 13803132818c ("drm/core: Preserve the framebuffer after removing it.") Testcase: kms_rmfb_basic References: https://lists.freedesktop.org/archives/dri-devel/2016-March/102876.html Cc: Thomas Hellstrom Cc: David Herrmann Reviewed-by: Daniel Vetter Tested-by: Thomas Hellstrom #v3 Tested-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/6c63ca37-0e7e-ac7f-a6d2-c7822e3d611f@linux.intel.com --- drivers/gpu/drm/drm_crtc.c | 63 +++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index a9c0a43483226..70f9c682d1449 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3462,6 +3462,24 @@ int drm_mode_addfb2(struct drm_device *dev, return 0; } +struct drm_mode_rmfb_work { + struct work_struct work; + struct list_head fbs; +}; + +static void drm_mode_rmfb_work_fn(struct work_struct *w) +{ + struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work); + + while (!list_empty(&arg->fbs)) { + struct drm_framebuffer *fb = + list_first_entry(&arg->fbs, typeof(*fb), filp_head); + + list_del_init(&fb->filp_head); + drm_framebuffer_remove(fb); + } +} + /** * drm_mode_rmfb - remove an FB from the configuration * @dev: drm device for the ioctl @@ -3502,12 +3520,29 @@ int drm_mode_rmfb(struct drm_device *dev, list_del_init(&fb->filp_head); mutex_unlock(&file_priv->fbs_lock); - /* we now own the reference that was stored in the fbs list */ - drm_framebuffer_unreference(fb); - /* drop the reference we picked up in framebuffer lookup */ drm_framebuffer_unreference(fb); + /* + * we now own the reference that was stored in the fbs list + * + * drm_framebuffer_remove may fail with -EINTR on pending signals, + * so run this in a separate stack as there's no way to correctly + * handle this after the fb is already removed from the lookup table. + */ + if (drm_framebuffer_read_refcount(fb) > 1) { + struct drm_mode_rmfb_work arg; + + INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); + INIT_LIST_HEAD(&arg.fbs); + list_add_tail(&fb->filp_head, &arg.fbs); + + schedule_work(&arg.work); + flush_work(&arg.work); + destroy_work_on_stack(&arg.work); + } else + drm_framebuffer_unreference(fb); + return 0; fail_unref: @@ -3657,7 +3692,6 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, return ret; } - /** * drm_fb_release - remove and free the FBs on this file * @priv: drm file for the ioctl @@ -3672,6 +3706,9 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, void drm_fb_release(struct drm_file *priv) { struct drm_framebuffer *fb, *tfb; + struct drm_mode_rmfb_work arg; + + INIT_LIST_HEAD(&arg.fbs); /* * When the file gets released that means no one else can access the fb @@ -3684,10 +3721,22 @@ void drm_fb_release(struct drm_file *priv) * at it any more. */ list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { - list_del_init(&fb->filp_head); + if (drm_framebuffer_read_refcount(fb) > 1) { + list_move_tail(&fb->filp_head, &arg.fbs); + } else { + list_del_init(&fb->filp_head); - /* This drops the fpriv->fbs reference. */ - drm_framebuffer_unreference(fb); + /* This drops the fpriv->fbs reference. */ + drm_framebuffer_unreference(fb); + } + } + + if (!list_empty(&arg.fbs)) { + INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); + + schedule_work(&arg.work); + flush_work(&arg.work); + destroy_work_on_stack(&arg.work); } } From 445d84a42bf17128e22101a04cde17b9a7c2e235 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 May 2016 23:49:40 +0200 Subject: [PATCH 4/6] drm: Add gpu.tmpl docbook to MAINTAINERS entry Patches get misrouted and lost otherwise. And use * to future-proof for sphinx (or whatever the documentation nirvana toolchain will be). Cc: Jonathan Corbet Cc: David Airlie Signed-off-by: Daniel Vetter Acked-by: Emil Velikov Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1462225780-3663-1-git-send-email-daniel.vetter@ffwll.ch --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8c10b4cc4da7b..0971de97a4ce5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3765,6 +3765,7 @@ T: git git://people.freedesktop.org/~airlied/linux S: Maintained F: drivers/gpu/drm/ F: drivers/gpu/vga/ +F: Documentation/DocBook/gpu.* F: include/drm/ F: include/uapi/drm/ From 83127f67e450a9a0882da495d59c88a71da25389 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 6 May 2016 16:01:37 +0200 Subject: [PATCH 5/6] drm/panel: Flesh out kerneldoc Write more complete kerneldoc comments for the DRM panel API and integrate the helpers in the DRM DocBook reference. Signed-off-by: Thierry Reding drm/panel: Add helper for simple panel connector Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20160506140137.GA4641@ulmo.ba.sec --- Documentation/DocBook/gpu.tmpl | 12 +++++-- drivers/gpu/drm/drm_panel.c | 61 ++++++++++++++++++++++++++++++++++ include/drm/drm_panel.h | 59 ++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 3 deletions(-) diff --git a/Documentation/DocBook/gpu.tmpl b/Documentation/DocBook/gpu.tmpl index 56386d3a1b2e1..9dd48f7490df7 100644 --- a/Documentation/DocBook/gpu.tmpl +++ b/Documentation/DocBook/gpu.tmpl @@ -1671,17 +1671,23 @@ void intel_crt_init(struct drm_device *dev) !Pdrivers/gpu/drm/drm_crtc.c Tile group - Bridges + Bridges - Overview + Overview !Pdrivers/gpu/drm/drm_bridge.c overview - Default bridge callback sequence + Default bridge callback sequence !Pdrivers/gpu/drm/drm_bridge.c bridge callbacks !Edrivers/gpu/drm/drm_bridge.c + + Panel Helper Reference +!Iinclude/drm/drm_panel.h +!Edrivers/gpu/drm/drm_panel.c +!Pdrivers/gpu/drm/drm_panel.c drm panel + diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index 2ef988e037b7e..3dfe3c886502d 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -30,12 +30,36 @@ static DEFINE_MUTEX(panel_lock); static LIST_HEAD(panel_list); +/** + * DOC: drm panel + * + * The DRM panel helpers allow drivers to register panel objects with a + * central registry and provide functions to retrieve those panels in display + * drivers. + */ + +/** + * drm_panel_init - initialize a panel + * @panel: DRM panel + * + * Sets up internal fields of the panel so that it can subsequently be added + * to the registry. + */ void drm_panel_init(struct drm_panel *panel) { INIT_LIST_HEAD(&panel->list); } EXPORT_SYMBOL(drm_panel_init); +/** + * drm_panel_add - add a panel to the global registry + * @panel: panel to add + * + * Add a panel to the global registry so that it can be looked up by display + * drivers. + * + * Return: 0 on success or a negative error code on failure. + */ int drm_panel_add(struct drm_panel *panel) { mutex_lock(&panel_lock); @@ -46,6 +70,12 @@ int drm_panel_add(struct drm_panel *panel) } EXPORT_SYMBOL(drm_panel_add); +/** + * drm_panel_remove - remove a panel from the global registry + * @panel: DRM panel + * + * Removes a panel from the global registry. + */ void drm_panel_remove(struct drm_panel *panel) { mutex_lock(&panel_lock); @@ -54,6 +84,18 @@ void drm_panel_remove(struct drm_panel *panel) } EXPORT_SYMBOL(drm_panel_remove); +/** + * drm_panel_attach - attach a panel to a connector + * @panel: DRM panel + * @connector: DRM connector + * + * After obtaining a pointer to a DRM panel a display driver calls this + * function to attach a panel to a connector. + * + * An error is returned if the panel is already attached to another connector. + * + * Return: 0 on success or a negative error code on failure. + */ int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector) { if (panel->connector) @@ -66,6 +108,15 @@ int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector) } EXPORT_SYMBOL(drm_panel_attach); +/** + * drm_panel_detach - detach a panel from a connector + * @panel: DRM panel + * + * Detaches a panel from the connector it is attached to. If a panel is not + * attached to any connector this is effectively a no-op. + * + * Return: 0 on success or a negative error code on failure. + */ int drm_panel_detach(struct drm_panel *panel) { panel->connector = NULL; @@ -76,6 +127,16 @@ int drm_panel_detach(struct drm_panel *panel) EXPORT_SYMBOL(drm_panel_detach); #ifdef CONFIG_OF +/** + * of_drm_find_panel - look up a panel using a device tree node + * @np: device tree node of the panel + * + * Searches the set of registered panels for one that matches the given device + * 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. + */ struct drm_panel *of_drm_find_panel(struct device_node *np) { struct drm_panel *panel; diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 13ff44b28893f..220d1e2b3db17 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -75,6 +75,14 @@ struct drm_panel_funcs { struct display_timing *timings); }; +/** + * struct drm_panel - DRM panel object + * @drm: DRM device owning the panel + * @connector: DRM connector that the panel is attached to + * @dev: parent device of the panel + * @funcs: operations that can be performed on the panel + * @list: panel entry in registry + */ struct drm_panel { struct drm_device *drm; struct drm_connector *connector; @@ -85,6 +93,17 @@ struct drm_panel { struct list_head list; }; +/** + * drm_disable_unprepare - power off a panel + * @panel: DRM panel + * + * Calling this function will completely power off a panel (assert the panel's + * reset, turn off power supplies, ...). After this function has completed, it + * is usually no longer possible to communicate with the panel until another + * call to drm_panel_prepare(). + * + * Return: 0 on success or a negative error code on failure. + */ static inline int drm_panel_unprepare(struct drm_panel *panel) { if (panel && panel->funcs && panel->funcs->unprepare) @@ -93,6 +112,16 @@ static inline int drm_panel_unprepare(struct drm_panel *panel) return panel ? -ENOSYS : -EINVAL; } +/** + * drm_panel_disable - disable a panel + * @panel: DRM panel + * + * This will typically turn off the panel's backlight or disable the display + * drivers. For smart panels it should still be possible to communicate with + * the integrated circuitry via any command bus after this call. + * + * Return: 0 on success or a negative error code on failure. + */ static inline int drm_panel_disable(struct drm_panel *panel) { if (panel && panel->funcs && panel->funcs->disable) @@ -101,6 +130,16 @@ static inline int drm_panel_disable(struct drm_panel *panel) return panel ? -ENOSYS : -EINVAL; } +/** + * drm_panel_prepare - power on a panel + * @panel: DRM panel + * + * Calling this function will enable power and deassert any reset signals to + * the panel. After this has completed it is possible to communicate with any + * integrated circuitry via a command bus. + * + * Return: 0 on success or a negative error code on failure. + */ static inline int drm_panel_prepare(struct drm_panel *panel) { if (panel && panel->funcs && panel->funcs->prepare) @@ -109,6 +148,16 @@ static inline int drm_panel_prepare(struct drm_panel *panel) return panel ? -ENOSYS : -EINVAL; } +/** + * drm_panel_enable - enable a panel + * @panel: DRM panel + * + * Calling this function will cause the panel display drivers to be turned on + * and the backlight to be enabled. Content will be visible on screen after + * this call completes. + * + * Return: 0 on success or a negative error code on failure. + */ static inline int drm_panel_enable(struct drm_panel *panel) { if (panel && panel->funcs && panel->funcs->enable) @@ -117,6 +166,16 @@ static inline int drm_panel_enable(struct drm_panel *panel) return panel ? -ENOSYS : -EINVAL; } +/** + * drm_panel_get_modes - probe the available display modes of a panel + * @panel: DRM panel + * + * The modes probed from the panel are automatically added to the connector + * that the panel is attached to. + * + * Return: The number of modes available from the panel on success or a + * negative error code on failure. + */ static inline int drm_panel_get_modes(struct drm_panel *panel) { if (panel && panel->funcs && panel->funcs->get_modes) From 8863dc7f5642737e49ff681cbb842d2c614bdcf4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 6 May 2016 15:39:03 +0200 Subject: [PATCH 6/6] drm/i915: Correctly refcount connectors in hw state readou This was forgotten when adding the the refcounting to drm_connector_state. v2: Don't forget to unreference existing connectors. This isn't relevant on driver load, but this code also runs on resume, and there we already have an atomic state. Spotted by Chris Wilson. Cc: Gabriel Feceoru Cc: Chris Wilson Cc: Marius Vlad Cc: Dave Airlie Fixes: d2307dea14a4 ("drm/atomic: use connector references (v3)") Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1462541943-19620-1-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/i915/intel_display.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 73299f9e77a81..a297e1ffafb58 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12032,11 +12032,16 @@ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev) struct intel_connector *connector; for_each_intel_connector(dev, connector) { + if (connector->base.state->crtc) + drm_connector_unreference(&connector->base); + if (connector->base.encoder) { connector->base.state->best_encoder = connector->base.encoder; connector->base.state->crtc = connector->base.encoder->crtc; + + drm_connector_reference(&connector->base); } else { connector->base.state->best_encoder = NULL; connector->base.state->crtc = NULL;