From f35034f8ac72925591ae96841fcbeebad1af1dc8 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 22 Mar 2016 15:42:14 +0100 Subject: [PATCH 01/18] drm/core: Fix ordering in drm_mode_config_cleanup. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __drm_atomic_helper_plane_destroy_state calls drm_framebuffer_unreference, which means that if drm_framebuffer_free is called before plane->destroy freed memory will be accessed. A similar case happens for the blob list, which was freed before the crtc state was, resulting in the unreference_blob from crtc_destroy_state pointing to garbage memory causing another opportunity for a GPF. Signed-off-by: Maarten Lankhorst Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1458657734-21866-1-git-send-email-maarten.lankhorst@linux.intel.com --- drivers/gpu/drm/drm_crtc.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 55ffde5a3a4a..f7fe9e153dec 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -5914,6 +5914,15 @@ void drm_mode_config_cleanup(struct drm_device *dev) drm_property_destroy(dev, property); } + list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, + head) { + plane->funcs->destroy(plane); + } + + list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { + crtc->funcs->destroy(crtc); + } + list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, head_global) { drm_property_unreference_blob(blob); @@ -5932,15 +5941,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) drm_framebuffer_free(&fb->refcount); } - list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, - head) { - plane->funcs->destroy(plane); - } - - list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { - crtc->funcs->destroy(crtc); - } - ida_destroy(&dev->mode_config.connector_ida); idr_destroy(&dev->mode_config.tile_idr); idr_destroy(&dev->mode_config.crtc_idr); From bd983323e6c0a0c65762064930a11b17f5f93404 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 30 Mar 2016 11:51:19 +0200 Subject: [PATCH 02/18] drm/bochs: Drop fake gamma support Only really needed for fbdev emulation at 8bpp. And bochs doesn't do that. And either way bochs only does 32bit rgb, so this is all pretty much wasted dead code. The only consideration is that we need to not set up any gamma size either. Cc: Gerd Hoffmann Cc: Dave Airlie Reviewed-by: Gerd Hoffmann Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1459331485-28376-5-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/bochs/bochs_fbdev.c | 15 --------------- drivers/gpu/drm/bochs/bochs_kms.c | 7 ------- 2 files changed, 22 deletions(-) diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c index 7520bf81fc25..369f11f10c72 100644 --- a/drivers/gpu/drm/bochs/bochs_fbdev.c +++ b/drivers/gpu/drm/bochs/bochs_fbdev.c @@ -162,22 +162,7 @@ static int bochs_fbdev_destroy(struct bochs_device *bochs) return 0; } -void bochs_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, - u16 blue, int regno) -{ -} - -void bochs_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, int regno) -{ - *red = regno; - *green = regno; - *blue = regno; -} - static const struct drm_fb_helper_funcs bochs_fb_helper_funcs = { - .gamma_set = bochs_fb_gamma_set, - .gamma_get = bochs_fb_gamma_get, .fb_probe = bochsfb_create, }; diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index 96926f09e0c9..89adfd916a7c 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -93,11 +93,6 @@ static void bochs_crtc_commit(struct drm_crtc *crtc) { } -static void bochs_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t start, uint32_t size) -{ -} - static int bochs_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, @@ -120,7 +115,6 @@ static int bochs_crtc_page_flip(struct drm_crtc *crtc, /* These provide the minimum set of functions required to handle a CRTC */ static const struct drm_crtc_funcs bochs_crtc_funcs = { - .gamma_set = bochs_crtc_gamma_set, .set_config = drm_crtc_helper_set_config, .destroy = drm_crtc_cleanup, .page_flip = bochs_crtc_page_flip, @@ -140,7 +134,6 @@ static void bochs_crtc_init(struct drm_device *dev) struct drm_crtc *crtc = &bochs->crtc; drm_crtc_init(dev, crtc, &bochs_crtc_funcs); - drm_mode_crtc_set_gamma_size(crtc, 256); drm_crtc_helper_add(crtc, &bochs_helper_funcs); } From 1b311124a226f3c2b43a7aca08883b5e5acc720c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 30 Mar 2016 11:51:22 +0200 Subject: [PATCH 03/18] drm/virtio: Drop dummy gamma table support No need to confuse userspace like this. Cc: Gerd Hoffmann Cc: Dave Airlie Reviewed-by: Gerd Hoffmann Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1459331485-28376-8-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/virtio/virtgpu_display.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 4854dac87e24..12b72e29678a 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -38,13 +38,6 @@ #define XRES_MAX 8192 #define YRES_MAX 8192 -static void virtio_gpu_crtc_gamma_set(struct drm_crtc *crtc, - u16 *red, u16 *green, u16 *blue, - uint32_t start, uint32_t size) -{ - /* TODO */ -} - static void virtio_gpu_hide_cursor(struct virtio_gpu_device *vgdev, struct virtio_gpu_output *output) @@ -173,7 +166,6 @@ static int virtio_gpu_page_flip(struct drm_crtc *crtc, static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = { .cursor_set2 = virtio_gpu_crtc_cursor_set, .cursor_move = virtio_gpu_crtc_cursor_move, - .gamma_set = virtio_gpu_crtc_gamma_set, .set_config = drm_atomic_helper_set_config, .destroy = drm_crtc_cleanup, @@ -416,7 +408,6 @@ static int vgdev_output_init(struct virtio_gpu_device *vgdev, int index) return PTR_ERR(plane); drm_crtc_init_with_planes(dev, crtc, plane, NULL, &virtio_gpu_crtc_funcs, NULL); - drm_mode_crtc_set_gamma_size(crtc, 256); drm_crtc_helper_add(crtc, &virtio_gpu_crtc_helper_funcs); plane->crtc = crtc; From 6c14838057e4bd5d7b65a1e51310abf3c001c466 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Tue, 5 Apr 2016 16:50:39 +0800 Subject: [PATCH 04/18] drm/crtc_helper: Reset empty plane state in drm_helper_crtc_mode_set_base() Transitional drivers might access the NULL pointer plane->state in drm_helper_crtc_mode_set_base(), which causes NULL pointer dereference. So, let's reset it before handing it over to those drivers. commit e4f31ad2b713 ("drm: reset empty state in transitional helpers") did the same thing for other transitional helpers, but it seems this one was missed. Signed-off-by: Liu Ying Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1459846239-8946-1-git-send-email-gnuiyl@gmail.com --- drivers/gpu/drm/drm_crtc_helper.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 79555d2b1b87..66ca31348546 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1053,10 +1053,12 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, if (plane->funcs->atomic_duplicate_state) plane_state = plane->funcs->atomic_duplicate_state(plane); - else if (plane->state) + else { + if (!plane->state) + drm_atomic_helper_plane_reset(plane); + plane_state = drm_atomic_helper_plane_duplicate_state(plane); - else - plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); + } if (!plane_state) return -ENOMEM; plane_state->plane = plane; From 346fea63a8d25644a5ad06ecd98d6a4747c63885 Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Thu, 14 Apr 2016 10:34:16 -0400 Subject: [PATCH 05/18] include/drm: Reword debug categories comment. The debug category comment mentions 4 categories, but more than 4 categories are listed. Let's change the wording to something a bit more generic. Signed-off-by: Robert Foss Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1460644456-9752-1-git-send-email-robert.foss@collabora.com --- include/drm/drmP.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 3c8422c69572..5de4cff05ac9 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -90,7 +90,7 @@ struct reservation_object; struct dma_buf_attachment; /* - * 4 debug categories are defined: + * The following categories are defined: * * CORE: Used in the generic drm code: drm_ioctl.c, drm_mm.c, drm_memory.c, ... * This is the category used by the DRM_DEBUG() macro. From 59f7c0fa325e5661188a174a435ea4925543985b Mon Sep 17 00:00:00 2001 From: Jim Bride Date: Thu, 14 Apr 2016 10:18:35 -0700 Subject: [PATCH 06/18] drm/edid: Add drm_edid_get_monitor_name() In order to include monitor name information in debugfs output we needed to add a function that would extract the monitor name from the EDID, and that function needed to reside in the file where the rest of the EDID helper functions are implemented. v2: Refactor to have drm_edid_get_monitor_name() and drm_edid_to_eld() use a common helper function to extract the monitor name from the edid. [Jani] + rebase. v3: Minor changes suggested by Jani + rebase. v4: Few more minor changes suggested by Jani + rebase. cc: dri-devel@lists.freedesktop.org cc: Jani Nikula Reviewed-by: Jani Nikula Signed-off-by: Jim Bride Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1460654317-31288-1-git-send-email-jim.bride@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 51 +++++++++++++++++++++++++++++++------- include/drm/drm_crtc.h | 2 ++ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 414d7f61aa05..9a9be9a131de 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3293,6 +3293,46 @@ monitor_name(struct detailed_timing *t, void *data) *(u8 **)data = t->data.other_data.data.str.str; } +static int get_monitor_name(struct edid *edid, char name[13]) +{ + char *edid_name = NULL; + int mnl; + + if (!edid || !name) + return 0; + + drm_for_each_detailed_block((u8 *)edid, monitor_name, &edid_name); + for (mnl = 0; edid_name && mnl < 13; mnl++) { + if (edid_name[mnl] == 0x0a) + break; + + name[mnl] = edid_name[mnl]; + } + + return mnl; +} + +/** + * drm_edid_get_monitor_name - fetch the monitor name from the edid + * @edid: monitor EDID information + * @name: pointer to a character array to hold the name of the monitor + * @bufsize: The size of the name buffer (should be at least 14 chars.) + * + */ +void drm_edid_get_monitor_name(struct edid *edid, char *name, int bufsize) +{ + int name_length; + char buf[13]; + + if (bufsize <= 0) + return; + + name_length = min(get_monitor_name(edid, buf), bufsize - 1); + memcpy(name, buf, name_length); + name[name_length] = '\0'; +} +EXPORT_SYMBOL(drm_edid_get_monitor_name); + /** * drm_edid_to_eld - build ELD from EDID * @connector: connector corresponding to the HDMI/DP sink @@ -3306,7 +3346,6 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) { uint8_t *eld = connector->eld; u8 *cea; - u8 *name; u8 *db; int total_sad_count = 0; int mnl; @@ -3320,14 +3359,8 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) return; } - name = NULL; - drm_for_each_detailed_block((u8 *)edid, monitor_name, &name); - /* max: 13 bytes EDID, 16 bytes ELD */ - for (mnl = 0; name && mnl < 13; mnl++) { - if (name[mnl] == 0x0a) - break; - eld[20 + mnl] = name[mnl]; - } + mnl = get_monitor_name(edid, eld + 20); + eld[4] = (cea[1] << 5) | mnl; DRM_DEBUG_KMS("ELD monitor %s\n", eld + 20); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 8cb377c5eb93..6d4684242a00 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -2500,6 +2500,8 @@ extern int drm_edid_header_is_valid(const u8 *raw_edid); extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, bool *edid_corrupt); extern bool drm_edid_is_valid(struct edid *edid); +extern void drm_edid_get_monitor_name(struct edid *edid, char *name, + int buflen); extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, char topology[8]); From 51108f252b02d3b94527c2416791147b8b8ec939 Mon Sep 17 00:00:00 2001 From: Jim Bride Date: Thu, 14 Apr 2016 10:18:36 -0700 Subject: [PATCH 07/18] drm/dp/mst: Enhance DP MST debugfs output Add some additional information (input vs. output port, sink associated with VC, peer device type, max number of VCs supported) and ensure that any embedded '\0' characters in a branch device's devid string are not written to debugfs. v2: Rebase + change drm_edid_get_monitor_name() call to reflect new signature. v3: Minor changes suggested by Jani + rebase. v4: Rebase cc: dri-devel@lists.freedesktop.org cc: Jani Nikula Reviewed-by: Jani Nikula Signed-off-by: Jim Bride Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1460654317-31288-2-git-send-email-jim.bride@linux.intel.com --- drivers/gpu/drm/drm_dp_mst_topology.c | 29 ++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 27fbd79d0daf..06d8b0a30c1b 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2729,7 +2729,7 @@ static void drm_dp_mst_dump_mstb(struct seq_file *m, seq_printf(m, "%smst: %p, %d\n", prefix, mstb, mstb->num_ports); list_for_each_entry(port, &mstb->ports, next) { - seq_printf(m, "%sport: %d: ddps: %d ldps: %d, sdp: %d/%d, %p, conn: %p\n", prefix, port->port_num, port->ddps, port->ldps, port->num_sdp_streams, port->num_sdp_stream_sinks, port, port->connector); + seq_printf(m, "%sport: %d: input: %d: pdt: %d, ddps: %d ldps: %d, sdp: %d/%d, %p, conn: %p\n", prefix, port->port_num, port->input, port->pdt, port->ddps, port->ldps, port->num_sdp_streams, port->num_sdp_stream_sinks, port, port->connector); if (port->mstb) drm_dp_mst_dump_mstb(m, port->mstb); } @@ -2750,6 +2750,16 @@ static bool dump_dp_payload_table(struct drm_dp_mst_topology_mgr *mgr, return false; } +static void fetch_monitor_name(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, char *name, + int namelen) +{ + struct edid *mst_edid; + + mst_edid = drm_dp_mst_get_edid(port->connector, mgr, port); + drm_edid_get_monitor_name(mst_edid, name, namelen); +} + /** * drm_dp_mst_dump_topology(): dump topology to seq file. * @m: seq_file to dump output to @@ -2762,6 +2772,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, { int i; struct drm_dp_mst_port *port; + mutex_lock(&mgr->lock); if (mgr->mst_primary) drm_dp_mst_dump_mstb(m, mgr->mst_primary); @@ -2770,14 +2781,21 @@ void drm_dp_mst_dump_topology(struct seq_file *m, mutex_unlock(&mgr->lock); mutex_lock(&mgr->payload_lock); - seq_printf(m, "vcpi: %lx %lx\n", mgr->payload_mask, mgr->vcpi_mask); + seq_printf(m, "vcpi: %lx %lx %d\n", mgr->payload_mask, mgr->vcpi_mask, + mgr->max_payloads); for (i = 0; i < mgr->max_payloads; i++) { if (mgr->proposed_vcpis[i]) { + char name[14]; + port = container_of(mgr->proposed_vcpis[i], struct drm_dp_mst_port, vcpi); - seq_printf(m, "vcpi %d: %d %d %d\n", i, port->port_num, port->vcpi.vcpi, port->vcpi.num_slots); + fetch_monitor_name(mgr, port, name, sizeof(name)); + seq_printf(m, "vcpi %d: %d %d %d sink name: %s\n", i, + port->port_num, port->vcpi.vcpi, + port->vcpi.num_slots, + (*name != 0) ? name : "Unknown"); } else - seq_printf(m, "vcpi %d:unsed\n", i); + seq_printf(m, "vcpi %d:unused\n", i); } for (i = 0; i < mgr->max_payloads; i++) { seq_printf(m, "payload %d: %d, %d, %d\n", @@ -2817,8 +2835,9 @@ void drm_dp_mst_dump_topology(struct seq_file *m, for (i = 0; i < 0x3; i++) seq_printf(m, "%02x", buf[i]); seq_printf(m, " devid: "); - for (i = 0x3; i < 0x8; i++) + for (i = 0x3; i < 0x8 && buf[i]; i++) seq_printf(m, "%c", buf[i]); + seq_printf(m, " revision: hw: %x.%x sw: %x.%x", buf[0x9] >> 4, buf[0x9] & 0xf, buf[0xa], buf[0xb]); seq_printf(m, "\n"); bret = dump_dp_payload_table(mgr, buf); From 40ae80cc036df1d90d26cd7885d9da1b9d33744b Mon Sep 17 00:00:00 2001 From: Jim Bride Date: Thu, 14 Apr 2016 10:18:37 -0700 Subject: [PATCH 08/18] drm/i915/dp/mst: Add source port info to debugfs output Modify the debugfs output for i915_dp_mst_info to list the source port for the DP MST topology in question. v2: rebase v3: rebase v4: rebase cc: Jani Nikula Reviewed-by: Jani Nikula Signed-off-by: Jim Bride Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1460654317-31288-3-git-send-email-jim.bride@linux.intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d02f8ce0b1c8..78a1c563a4e7 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3434,7 +3434,8 @@ static int i915_dp_mst_info(struct seq_file *m, void *unused) intel_dig_port = enc_to_dig_port(encoder); if (!intel_dig_port->dp.can_mst) continue; - + seq_printf(m, "MST Source Port %c\n", + port_name(intel_dig_port->port)); drm_dp_mst_dump_topology(m, &intel_dig_port->dp.mst_mgr); } drm_modeset_unlock_all(dev); From f6cd7daecff558fab2c45d15283d3e52f688342d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 15 Apr 2016 12:55:08 +0100 Subject: [PATCH 09/18] drm: Release driver references to handle before making it available again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When userspace closes a handle, we remove it from the file->object_idr and then tell the driver to drop its references to that file/handle. However, as the file/handle is already available again for reuse, it may be reallocated back to userspace and active on a new object before the driver has had a chance to drop the old file/handle references. Whilst calling back into the driver, we have to drop the file->table_lock spinlock and so to prevent reusing the closed handle we mark that handle as stale in the idr, perform the callback and then remove the handle. We set the stale handle to point to the NULL object, then any idr_find() whilst the driver is removing the handle will return NULL, just as if the handle is already removed from idr. Note: This will be used to have a direct handle -> vma lookup table, instead of first a handle -> obj lookup, and then an (obj, vm) -> vma lookup. v2: Use NULL rather than an ERR_PTR to avoid having to adjust callers. idr_alloc() tracks existing handles using an internal bitmap, so we are free to use the NULL object as our stale identifier. v3: Needed to update the return value check after changing from using the stale error pointer to NULL. Signed-off-by: Chris Wilson Cc: dri-devel@lists.freedesktop.org Cc: David Airlie Cc: Daniel Vetter Cc: Rob Clark Cc: Ville Syrjälä Cc: Thierry Reding [danvet: Add note about the use-case.] Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1460721308-32405-1-git-send-email-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_gem.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 2e8c77e71e1f..c24489da73d4 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -279,7 +279,6 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) int drm_gem_handle_delete(struct drm_file *filp, u32 handle) { - struct drm_device *dev; struct drm_gem_object *obj; /* This is gross. The idr system doesn't let us try a delete and @@ -294,18 +293,19 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle) spin_lock(&filp->table_lock); /* Check if we currently have a reference on the object */ - obj = idr_find(&filp->object_idr, handle); - if (obj == NULL) { - spin_unlock(&filp->table_lock); + obj = idr_replace(&filp->object_idr, NULL, handle); + spin_unlock(&filp->table_lock); + if (IS_ERR_OR_NULL(obj)) return -EINVAL; - } - dev = obj->dev; - /* Release reference and decrement refcount. */ + /* Release driver's reference and decrement refcount. */ + drm_gem_object_release_handle(handle, obj, filp); + + /* And finally make the handle available for future allocations. */ + spin_lock(&filp->table_lock); idr_remove(&filp->object_idr, handle); spin_unlock(&filp->table_lock); - drm_gem_object_release_handle(handle, obj, filp); return 0; } EXPORT_SYMBOL(drm_gem_handle_delete); From 1652fce65f70f104ffd0df0284b601d9103e1ebf Mon Sep 17 00:00:00 2001 From: Lyude Date: Wed, 13 Apr 2016 16:50:18 -0400 Subject: [PATCH 10/18] drm/dp/mst: Restore primary hub guid on resume Some hubs are forgetful, and end up forgetting whatever GUID we set previously after we do a suspend/resume cycle. This can lead to hotplugging breaking (along with probably other things) since the hub will start sending connection notifications with the wrong GUID. As such, we need to check on resume whether or not the GUID the hub is giving us is valid. Signed-off-by: Lyude Signed-off-by: Dave Airlie Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1460580618-7421-1-git-send-email-cpaul@redhat.com --- drivers/gpu/drm/drm_dp_mst_topology.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 06d8b0a30c1b..f487bed33599 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2121,6 +2121,8 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr) if (mgr->mst_primary) { int sret; + u8 guid[16]; + sret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, mgr->dpcd, DP_RECEIVER_CAP_SIZE); if (sret != DP_RECEIVER_CAP_SIZE) { DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n"); @@ -2135,6 +2137,16 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr) ret = -1; goto out_unlock; } + + /* Some hubs forget their guids after they resume */ + sret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16); + if (sret != 16) { + DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n"); + ret = -1; + goto out_unlock; + } + drm_dp_check_mstb_guid(mgr->mst_primary, guid); + ret = 0; } else ret = -1; From 8d4d0d700dda04c5095a08e91f59f537995aa024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 18 Apr 2016 14:29:33 +0300 Subject: [PATCH 11/18] drm/atomic-helper: Print an error if vblank wait times out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vblank waits timing out is no a normal thing to happen, so let's inform people when it happens. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1460978973-24945-2-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_atomic_helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 7bf678ee7f81..40c7b268a9bc 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1103,6 +1103,8 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, drm_crtc_vblank_count(crtc), msecs_to_jiffies(50)); + WARN(!ret, "[CRTC:%d] vblank wait timed out\n", crtc->base.id); + drm_crtc_vblank_put(crtc); } } From 644a80508f918e488aad70814b65b7007438ef4c Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Tue, 22 Mar 2016 14:10:33 +0000 Subject: [PATCH 12/18] drm: fix lut value extraction function When extracting the value at full precision (16 bits), no need to round the value. This was spotted by Jani when running sparse. Unfortunately this fix doesn't get rid of the warning. Signed-off-by: Lionel Landwerlin Reported-by: Jani Nikula Cc: Daniel Stone Cc: Daniel Vetter Cc: Matt Roper Cc: dri-devel@lists.freedesktop.org Fixes: 5488dc16fde7 ("drm: introduce pipe color correction properties") Reviewed-by: Emil Velikov Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1458655833-19547-1-git-send-email-lionel.g.landwerlin@intel.com --- include/drm/drm_crtc.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 6d4684242a00..a6fbc9e5e896 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -2592,10 +2592,14 @@ static inline struct drm_property *drm_property_find(struct drm_device *dev, static inline uint32_t drm_color_lut_extract(uint32_t user_input, uint32_t bit_precision) { - uint32_t val = user_input + (1 << (16 - bit_precision - 1)); + uint32_t val = user_input; uint32_t max = 0xffff >> (16 - bit_precision); - val >>= 16 - bit_precision; + /* Round only if we're not using full precision. */ + if (bit_precision < 16) { + val += 1UL << (16 - bit_precision - 1); + val >>= 16 - bit_precision; + } return clamp_val(val, 0, max); } From 54d2c2da0946368b96b63e6daed7920f3681243e Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Tue, 19 Apr 2016 15:24:51 +0300 Subject: [PATCH 13/18] drm: Introduce drm_connector_register_all() helper As a pair to already existing drm_connector_unregister_all() we're adding generic implementation of what is already done in some drivers. Once this helper is implemented we'll be ready to switch existing driver-specific implementations with the generic one. Signed-off-by: Alexey Brodkin Cc: Daniel Vetter Cc: David Airlie Cc: Boris Brezillon Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1461068693-11260-2-git-send-email-abrodkin@synopsys.com --- drivers/gpu/drm/drm_crtc.c | 40 ++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_drv.c | 6 +++++- include/drm/drm_crtc.h | 3 ++- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f7fe9e153dec..ee549a30bff1 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1067,6 +1067,46 @@ void drm_connector_unregister(struct drm_connector *connector) } EXPORT_SYMBOL(drm_connector_unregister); +/** + * drm_connector_register_all - register all connectors + * @dev: drm device + * + * This function registers all connectors in sysfs and other places so that + * userspace can start to access them. Drivers can call it after calling + * drm_dev_register() to complete the device registration, if they don't call + * drm_connector_register() on each connector individually. + * + * When a device is unplugged and should be removed from userspace access, + * call drm_connector_unregister_all(), which is the inverse of this + * function. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_connector_register_all(struct drm_device *dev) +{ + struct drm_connector *connector; + int ret; + + mutex_lock(&dev->mode_config.mutex); + + drm_for_each_connector(connector, dev) { + ret = drm_connector_register(connector); + if (ret) + goto err; + } + + mutex_unlock(&dev->mode_config.mutex); + + return 0; + +err: + mutex_unlock(&dev->mode_config.mutex); + drm_connector_unregister_all(dev); + return ret; +} +EXPORT_SYMBOL(drm_connector_register_all); + /** * drm_connector_unregister_all - unregister connector userspace interfaces * @dev: drm device diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 167c8d3d4a31..2c9a2b6f7a4a 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -715,7 +715,11 @@ EXPORT_SYMBOL(drm_dev_unref); * * Register the DRM device @dev with the system, advertise device to user-space * and start normal device operation. @dev must be allocated via drm_dev_alloc() - * previously. + * previously. Right after drm_dev_register() the driver should call + * drm_connector_register_all() to register all connectors in sysfs. This is + * a separate call for backward compatibility with drivers still using + * the deprecated ->load() callback, where connectors are registered from within + * the ->load() callback. * * Never call this twice on any device! * diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index a6fbc9e5e896..6f43f9487aee 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -2249,7 +2249,8 @@ static inline unsigned drm_connector_index(struct drm_connector *connector) return connector->connector_id; } -/* helper to unregister all connectors from sysfs for device */ +/* helpers to {un}register all connectors from sysfs for device */ +extern int drm_connector_register_all(struct drm_device *dev); extern void drm_connector_unregister_all(struct drm_device *dev); extern int drm_bridge_add(struct drm_bridge *bridge); From b3383f75fc44128ee748938dd70f353aa0001f78 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Tue, 19 Apr 2016 15:24:52 +0300 Subject: [PATCH 14/18] drm: atmel_hldc: Use generic drm_connector_register_all() helper This driver used to have its own implementation of connector_register_all() which actually was taken as a prototype of drm_connector_register_all(). Now when drm_connector_register_all() exists reusing it here. Signed-off-by: Alexey Brodkin Cc: Daniel Vetter Cc: David Airlie Cc: Boris Brezillon Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1461068693-11260-3-git-send-email-abrodkin@synopsys.com --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 30 +------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 8ab4318e57a1..9907dd1ef4d0 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -584,34 +584,6 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev) destroy_workqueue(dc->wq); } -static int atmel_hlcdc_dc_connector_plug_all(struct drm_device *dev) -{ - struct drm_connector *connector, *failed; - int ret; - - mutex_lock(&dev->mode_config.mutex); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - ret = drm_connector_register(connector); - if (ret) { - failed = connector; - goto err; - } - } - mutex_unlock(&dev->mode_config.mutex); - return 0; - -err: - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (failed == connector) - break; - - drm_connector_unregister(connector); - } - mutex_unlock(&dev->mode_config.mutex); - - return ret; -} - static void atmel_hlcdc_dc_connector_unplug_all(struct drm_device *dev) { mutex_lock(&dev->mode_config.mutex); @@ -736,7 +708,7 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev) if (ret) goto err_unload; - ret = atmel_hlcdc_dc_connector_plug_all(ddev); + ret = drm_connector_register_all(ddev); if (ret) goto err_unregister; From d63c25e4245aaf9507bf9484b58910bd89c76ef3 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Tue, 19 Apr 2016 15:24:53 +0300 Subject: [PATCH 15/18] drm: rcar-du: Use generic drm_connector_register_all() helper Now that a generic drm_connector_register_all() helper exists we may safely substitute it for the driver-specific implementation of connectors plugging in sysfs. Signed-off-by: Alexey Brodkin Cc: Daniel Vetter Cc: David Airlie Cc: linux-renesas-soc@vger.kernel.org Acked-by: Laurent Pinchart Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1461068693-11260-4-git-send-email-abrodkin@synopsys.com --- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 644db36d0d20..0f251dc11082 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -361,14 +361,7 @@ static int rcar_du_probe(struct platform_device *pdev) if (ret) goto error; - mutex_lock(&ddev->mode_config.mutex); - drm_for_each_connector(connector, ddev) { - ret = drm_connector_register(connector); - if (ret < 0) - break; - } - mutex_unlock(&ddev->mode_config.mutex); - + ret = drm_connector_register_all(ddev); if (ret < 0) goto error; From ba34d58c5e86c27accb3133fa991cfb6c848c58e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 19 Apr 2016 14:40:37 -0300 Subject: [PATCH 16/18] drm: probe_helper: Hide ugly ifdef Push the ifdef to the drm_edid.h and create a stub, for the DRM_LOAD_EDID_FIRMWARE=n case. This removes some clutter in the code, making it more readable. Signed-off-by: Ezequiel Garcia Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1461087638-16959-1-git-send-email-ezequiel@vanguardiasur.com.ar --- drivers/gpu/drm/drm_probe_helper.c | 2 -- include/drm/drm_edid.h | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index e714b5a7955f..0329080d7f7c 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -264,10 +264,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, count = drm_add_edid_modes(connector, edid); drm_edid_to_eld(connector, edid); } else { -#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE count = drm_load_edid_firmware(connector); if (count == 0) -#endif count = (*connector_funcs->get_modes)(connector); } diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index dec6221e8198..919933d1beb4 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -328,7 +328,15 @@ int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb); int drm_av_sync_delay(struct drm_connector *connector, const struct drm_display_mode *mode); struct drm_connector *drm_select_eld(struct drm_encoder *encoder); + +#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE int drm_load_edid_firmware(struct drm_connector *connector); +#else +static inline int drm_load_edid_firmware(struct drm_connector *connector) +{ + return 0; +} +#endif int drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, From 14ba00316543bb67c81202fd475b605bfa410967 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 21 Apr 2016 01:21:14 +0300 Subject: [PATCH 17/18] drm: Remove warning from drm_connector_unregister_all() Commit 6c87e5c3ec6d ("drm: Rename drm_connector_unplug_all() to drm_connector_unregister_all()") replaced a manual connectors list walk in drm_connector_unregister_all() with drm_for_each_connector(). The list was walked without the mode config mutex locked as that ends up in a clash with sysfs, but drm_connector_unregister_all() warns when the mutex isn't locked. The problem is known and doesn't require a large warning every time drm_connector_unregister_all() is called. Fix it by reverting to manual list walk. Fixes: 6c87e5c3ec6d ("drm: Rename drm_connector_unplug_all() to drm_connector_unregister_all()") Signed-off-by: Laurent Pinchart Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1461190874-32674-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index ee549a30bff1..edcf12c5521d 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1122,7 +1122,7 @@ void drm_connector_unregister_all(struct drm_device *dev) struct drm_connector *connector; /* FIXME: taking the mode config mutex ends up in a clash with sysfs */ - drm_for_each_connector(connector, dev) + list_for_each_entry(connector, &dev->mode_config.connector_list, head) drm_connector_unregister(connector); } EXPORT_SYMBOL(drm_connector_unregister_all); From 6dc3e22ee197095eb6a6b3119f04f9dc6c2bbf91 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 20 Apr 2016 13:45:03 -0300 Subject: [PATCH 18/18] drm: Make drm.debug parameter description more helpful Let's be user-friendly and print an actually helpful parameter description. This makes modinfo output the debug parameter like this: parm: debug:Enable debug output, where each bit enables a debug category. Bit 0 (0x01) will enable CORE messages (drm core code) Bit 1 (0x02) will enable DRIVER messages (drm controller code) Bit 2 (0x04) will enable KMS messages (modesetting code) Bit 3 (0x08) will enable PRIME messages (prime code) Bit 4 (0x10) will enable ATOMIC messages (atomic code) Bit 5 (0x20) will enable VBL messages (vblank code) (int) Changes from v1: * Fixed s/PRMIE/PRIME typo. * Add ATOMIC and VBL debug parameter documentation. * Prefix the continuation lines with two tabs and removed the last new line. * Remove spurious whitespace. Signed-off-by: Ezequiel Garcia Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1461170703-11216-1-git-send-email-ezequiel@vanguardiasur.com.ar --- drivers/gpu/drm/drm_drv.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 2c9a2b6f7a4a..f8a7a6e66b7e 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -37,13 +37,23 @@ #include "drm_legacy.h" #include "drm_internal.h" -unsigned int drm_debug = 0; /* bitmask of DRM_UT_x */ +/* + * drm_debug: Enable debug output. + * Bitmask of DRM_UT_x. See include/drm/drmP.h for details. + */ +unsigned int drm_debug = 0; EXPORT_SYMBOL(drm_debug); MODULE_AUTHOR(CORE_AUTHOR); MODULE_DESCRIPTION(CORE_DESC); MODULE_LICENSE("GPL and additional rights"); -MODULE_PARM_DESC(debug, "Enable debug output"); +MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n" +"\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n" +"\t\tBit 1 (0x02) will enable DRIVER messages (drm controller code)\n" +"\t\tBit 2 (0x04) will enable KMS messages (modesetting code)\n" +"\t\tBit 3 (0x08) will enable PRIME messages (prime code)\n" +"\t\tBit 4 (0x10) will enable ATOMIC messages (atomic code)\n" +"\t\tBit 5 (0x20) will enable VBL messages (vblank code)"); module_param_named(debug, drm_debug, int, 0600); static DEFINE_SPINLOCK(drm_minor_lock);