From d728c8ef8bea6e81f44933c0237531cda499577e Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:56 -0800 Subject: drm/i915: Add a CMD_PARSER_VERSION getparam So userspace can query the kernel for command parser support. v2: Add i915_cmd_parser_get_version(), history log, and kerneldoc OTC-Tracker: AXIA-4631 Change-Id: I58af650db9f6753c2dcac9c54ab432fd31db302f Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- include/uapi/drm/i915_drm.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 126bfaa8bb6b..8a3e4ef00c3d 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -337,6 +337,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_EXEC_NO_RELOC 25 #define I915_PARAM_HAS_EXEC_HANDLE_LUT 26 #define I915_PARAM_HAS_WT 27 +#define I915_PARAM_CMD_PARSER_VERSION 28 typedef struct drm_i915_getparam { int param; -- cgit v1.3-18-gd494 From c2d15359c4b5476c181d8a51bdeba4cead15c120 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 1 Apr 2014 12:59:08 +0300 Subject: drm: Make drm_clflush_virt_range() void* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently drm_cflush_virt_rage() takes a char* so the caller probably has to do pointless casting to avoid compiler warnings. Make the argument void* instead to avoid such issues. v2: Use void* arithmetic (Chris) Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_cache.c | 4 ++-- include/drm/drmP.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index bb8f58012189..4bfad5f5a843 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -125,11 +125,11 @@ drm_clflush_sg(struct sg_table *st) EXPORT_SYMBOL(drm_clflush_sg); void -drm_clflush_virt_range(char *addr, unsigned long length) +drm_clflush_virt_range(void *addr, unsigned long length) { #if defined(CONFIG_X86) if (cpu_has_clflush) { - char *end = addr + length; + void *end = addr + length; mb(); for (; addr < end; addr += boot_cpu_data.x86_clflush_size) clflush(addr); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index daac00a93126..150780bdd66b 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1322,7 +1322,7 @@ extern int drm_remove_magic(struct drm_master *master, drm_magic_t magic); /* Cache management (drm_cache.c) */ void drm_clflush_pages(struct page *pages[], unsigned long num_pages); void drm_clflush_sg(struct sg_table *st); -void drm_clflush_virt_range(char *addr, unsigned long length); +void drm_clflush_virt_range(void *addr, unsigned long length); /* Locking IOCTL support (drm_lock.h) */ extern int drm_lock(struct drm_device *dev, void *data, -- cgit v1.3-18-gd494 From 0967e6a5070e336507ce52f09f7297413b966981 Mon Sep 17 00:00:00 2001 From: Vandana Kannan Date: Tue, 1 Apr 2014 16:26:59 +0530 Subject: drm/edid: Fill PAR in AVI infoframe based on CEA mode list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Populate PAR in infoframe structure. If there is a user setting for PAR, then that value is set. Else, value is taken from CEA mode list if VIC is found. Else, PAR is calculated from resolution. If none of these conditions are satisfied, PAR is NONE as per initialization. v2: Removed the part which sets PAR according to user input, based on Daniel's review comments. A separate patch will be submitted to create a property that would enable a user space app to set aspect ratio for AVI infoframe. v2: Removed the part which sets PAR according to user input, based on Daniel's review comments. v3: Removed calculation of PAR for non-CEA modes as per discussion with Ville. A separate patch will be submitted to create a property that would enable a user space app to set aspect ratio for AVI infoframe. Signed-off-by: Vandana Kannan Cc: Jesse Barnes Cc: Vijay Purushothaman Cc: Ville Syrjälä Cc: intel-gfx@lists.freedesktop.org Reviewed-by: Jesse Barnes [danvet: Squash in fixup for htmldocs.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_edid.c | 22 ++++++++++++++++++++++ include/drm/drm_crtc.h | 1 + 2 files changed, 23 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index d4e3f9d9370f..b8d6c5163575 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2452,6 +2452,22 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) } EXPORT_SYMBOL(drm_match_cea_mode); +/** + * drm_get_cea_aspect_ratio - get the picture aspect ratio corresponding to + * the input VIC from the CEA mode list + * @video_code: ID given to each of the CEA modes + * + * Returns picture aspect ratio + */ +enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code) +{ + /* return picture aspect ratio for video_code - 1 to access the + * right array element + */ + return edid_cea_modes[video_code-1].picture_aspect_ratio; +} +EXPORT_SYMBOL(drm_get_cea_aspect_ratio); + /* * Calculate the alternate clock for HDMI modes (those from the HDMI vendor * specific block). @@ -3613,6 +3629,12 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, frame->video_code = drm_match_cea_mode(mode); frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE; + + /* Populate picture aspect ratio from CEA mode list */ + if (frame->video_code > 0) + frame->picture_aspect = drm_get_cea_aspect_ratio( + frame->video_code); + frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE; frame->scan_mode = HDMI_SCAN_MODE_UNDERSCAN; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index e55fccbe7c42..c061bb372199 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1020,6 +1020,7 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev, extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern u8 drm_match_cea_mode(const struct drm_display_mode *to_match); +extern enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code); extern bool drm_detect_hdmi_monitor(struct edid *edid); extern bool drm_detect_monitor_audio(struct edid *edid); extern bool drm_rgb_quant_range_selectable(struct edid *edid); -- cgit v1.3-18-gd494 From f9b0e251dfbf2c4da642ec9210db29a7ac63b81a Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 2 Apr 2014 12:29:46 +0200 Subject: drm: make mode_valid callback optional Many drm connectors do not need mode validation. The patch makes this callback optional and removes dumb implementations. v2: Rebase: - imx move to a shared (but still dummy) ->mode_valid implementation. - probe helpers have been extracted to drm_probe_helper.c Signed-off-by: Andrzej Hajda (v1) Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 6 +++--- drivers/gpu/drm/ast/ast_mode.c | 7 ------- drivers/gpu/drm/bridge/ptn3460.c | 7 ------- drivers/gpu/drm/cirrus/cirrus_mode.c | 8 -------- drivers/gpu/drm/drm_probe_helper.c | 2 +- drivers/gpu/drm/exynos/exynos_dp_core.c | 7 ------- drivers/gpu/drm/exynos/exynos_drm_dpi.c | 7 ------- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 7 ------- drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c | 7 ------- drivers/gpu/drm/rcar-du/rcar_du_vgacon.c | 7 ------- drivers/gpu/drm/shmobile/shmob_drm_crtc.c | 7 ------- drivers/staging/imx-drm/imx-drm-core.c | 7 ------- drivers/staging/imx-drm/imx-drm.h | 2 -- drivers/staging/imx-drm/imx-hdmi.c | 1 - drivers/staging/imx-drm/imx-ldb.c | 1 - drivers/staging/imx-drm/imx-tve.c | 4 ---- drivers/staging/imx-drm/parallel-display.c | 1 - include/drm/drm_crtc_helper.h | 2 +- 18 files changed, 5 insertions(+), 85 deletions(-) (limited to 'include') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 677a02553ec0..c72e146e58d3 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -1903,8 +1903,8 @@ void intel_crt_init(struct drm_device *dev) The function filters out modes larger than max_width and max_height - if specified. It then calls the connector - mode_valid helper operation for each mode in + if specified. It then calls the optional connector + mode_valid helper operation for each mode in the probed list to check whether the mode is valid for the connector. @@ -2265,7 +2265,7 @@ void intel_crt_init(struct drm_device *dev) Verify whether a mode is valid for the connector. Return MODE_OK for supported modes and one of the enum drm_mode_status values (MODE_*) - for unsupported modes. This operation is mandatory. + for unsupported modes. This operation is optional. As the mode rejection reason is currently not used beside for diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index a4afdc8bb578..e599d64a2620 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -743,12 +743,6 @@ static int ast_get_modes(struct drm_connector *connector) return 0; } -static int ast_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return MODE_OK; -} - static void ast_connector_destroy(struct drm_connector *connector) { struct ast_connector *ast_connector = to_ast_connector(connector); @@ -765,7 +759,6 @@ ast_connector_detect(struct drm_connector *connector, bool force) } static const struct drm_connector_helper_funcs ast_connector_helper_funcs = { - .mode_valid = ast_mode_valid, .get_modes = ast_get_modes, .best_encoder = ast_best_single_encoder, }; diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c index b171901a3553..98fd17ae4916 100644 --- a/drivers/gpu/drm/bridge/ptn3460.c +++ b/drivers/gpu/drm/bridge/ptn3460.c @@ -225,12 +225,6 @@ out: return num_modes; } -static int ptn3460_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return MODE_OK; -} - struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) { struct ptn3460_bridge *ptn_bridge; @@ -242,7 +236,6 @@ struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { .get_modes = ptn3460_get_modes, - .mode_valid = ptn3460_mode_valid, .best_encoder = ptn3460_best_encoder, }; diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index f59433b7610c..49332c5fe35b 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -505,13 +505,6 @@ static int cirrus_vga_get_modes(struct drm_connector *connector) return count; } -static int cirrus_vga_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - /* Any mode we've added is valid */ - return MODE_OK; -} - static struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector *connector) { @@ -546,7 +539,6 @@ static void cirrus_connector_destroy(struct drm_connector *connector) struct drm_connector_helper_funcs cirrus_vga_connector_helper_funcs = { .get_modes = cirrus_vga_get_modes, - .mode_valid = cirrus_vga_mode_valid, .best_encoder = cirrus_connector_best_encoder, }; diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index e70f54d4a581..d06340985a72 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -169,7 +169,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, drm_mode_validate_flag(connector, mode_flags); list_for_each_entry(mode, &connector->modes, head) { - if (mode->status == MODE_OK) + if (mode->status == MODE_OK && connector_funcs->mode_valid) mode->status = connector_funcs->mode_valid(connector, mode); } diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index aed533bbfd31..bb74472b4e4b 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -949,12 +949,6 @@ static int exynos_dp_get_modes(struct drm_connector *connector) return 1; } -static int exynos_dp_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return MODE_OK; -} - static struct drm_encoder *exynos_dp_best_encoder( struct drm_connector *connector) { @@ -965,7 +959,6 @@ static struct drm_encoder *exynos_dp_best_encoder( static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { .get_modes = exynos_dp_get_modes, - .mode_valid = exynos_dp_mode_valid, .best_encoder = exynos_dp_best_encoder, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 2b09c7c0bfcc..82e52c71bccc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -94,12 +94,6 @@ static int exynos_dpi_get_modes(struct drm_connector *connector) return 0; } -static int exynos_dpi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return MODE_OK; -} - static struct drm_encoder * exynos_dpi_best_encoder(struct drm_connector *connector) { @@ -110,7 +104,6 @@ exynos_dpi_best_encoder(struct drm_connector *connector) static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = { .get_modes = exynos_dpi_get_modes, - .mode_valid = exynos_dpi_mode_valid, .best_encoder = exynos_dpi_best_encoder, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 7afead9c3f30..b6980865dd50 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -533,12 +533,6 @@ static int vidi_get_modes(struct drm_connector *connector) return drm_add_edid_modes(connector, edid); } -static int vidi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return MODE_OK; -} - static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector) { struct vidi_context *ctx = ctx_from_connector(connector); @@ -548,7 +542,6 @@ static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector) static struct drm_connector_helper_funcs vidi_connector_helper_funcs = { .get_modes = vidi_get_modes, - .mode_valid = vidi_mode_valid, .best_encoder = vidi_best_encoder, }; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c index 4f3ba93cd91d..289048d1c7b2 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c @@ -57,15 +57,8 @@ static int rcar_du_lvds_connector_get_modes(struct drm_connector *connector) return 1; } -static int rcar_du_lvds_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return MODE_OK; -} - static const struct drm_connector_helper_funcs connector_helper_funcs = { .get_modes = rcar_du_lvds_connector_get_modes, - .mode_valid = rcar_du_lvds_connector_mode_valid, .best_encoder = rcar_du_connector_best_encoder, }; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c index 41d563adfeaa..ccfe64c7188f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c @@ -25,15 +25,8 @@ static int rcar_du_vga_connector_get_modes(struct drm_connector *connector) return 0; } -static int rcar_du_vga_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return MODE_OK; -} - static const struct drm_connector_helper_funcs connector_helper_funcs = { .get_modes = rcar_du_vga_connector_get_modes, - .mode_valid = rcar_du_vga_connector_mode_valid, .best_encoder = rcar_du_connector_best_encoder, }; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index e9e5e6d368cc..faf176b2daf9 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -674,12 +674,6 @@ static int shmob_drm_connector_get_modes(struct drm_connector *connector) return 1; } -static int shmob_drm_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return MODE_OK; -} - static struct drm_encoder * shmob_drm_connector_best_encoder(struct drm_connector *connector) { @@ -690,7 +684,6 @@ shmob_drm_connector_best_encoder(struct drm_connector *connector) static const struct drm_connector_helper_funcs connector_helper_funcs = { .get_modes = shmob_drm_connector_get_modes, - .mode_valid = shmob_drm_connector_mode_valid, .best_encoder = shmob_drm_connector_best_encoder, }; diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c index 4144a75e5f71..53ff005245c5 100644 --- a/drivers/staging/imx-drm/imx-drm-core.c +++ b/drivers/staging/imx-drm/imx-drm-core.c @@ -200,13 +200,6 @@ static const struct file_operations imx_drm_driver_fops = { .llseek = noop_llseek, }; -int imx_drm_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return MODE_OK; -} -EXPORT_SYMBOL(imx_drm_connector_mode_valid); - void imx_drm_connector_destroy(struct drm_connector *connector) { drm_sysfs_connector_remove(connector); diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h index a322bac55414..7453ae00c412 100644 --- a/drivers/staging/imx-drm/imx-drm.h +++ b/drivers/staging/imx-drm/imx-drm.h @@ -50,8 +50,6 @@ int imx_drm_encoder_get_mux_id(struct device_node *node, int imx_drm_encoder_parse_of(struct drm_device *drm, struct drm_encoder *encoder, struct device_node *np); -int imx_drm_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode); void imx_drm_connector_destroy(struct drm_connector *connector); void imx_drm_encoder_destroy(struct drm_encoder *encoder); diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c index d47dedd2cdb4..9fbe6d6a989d 100644 --- a/drivers/staging/imx-drm/imx-hdmi.c +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -1492,7 +1492,6 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = { static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = { .get_modes = imx_hdmi_connector_get_modes, - .mode_valid = imx_drm_connector_mode_valid, .best_encoder = imx_hdmi_connector_best_encoder, }; diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c index fe4c1ef4e7a5..7e3f019d7e72 100644 --- a/drivers/staging/imx-drm/imx-ldb.c +++ b/drivers/staging/imx-drm/imx-ldb.c @@ -317,7 +317,6 @@ static struct drm_connector_funcs imx_ldb_connector_funcs = { static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = { .get_modes = imx_ldb_connector_get_modes, .best_encoder = imx_ldb_connector_best_encoder, - .mode_valid = imx_drm_connector_mode_valid, }; static struct drm_encoder_funcs imx_ldb_encoder_funcs = { diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c index 575533f4fd64..5a5a5287a86a 100644 --- a/drivers/staging/imx-drm/imx-tve.c +++ b/drivers/staging/imx-drm/imx-tve.c @@ -251,10 +251,6 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector, unsigned long rate; int ret; - ret = imx_drm_connector_mode_valid(connector, mode); - if (ret != MODE_OK) - return ret; - /* pixel clock with 2x oversampling */ rate = clk_round_rate(tve->clk, 2000UL * mode->clock) / 2000; if (rate == mode->clock) diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c index c60b6c645f42..52598e489a4b 100644 --- a/drivers/staging/imx-drm/parallel-display.c +++ b/drivers/staging/imx-drm/parallel-display.c @@ -148,7 +148,6 @@ static struct drm_connector_funcs imx_pd_connector_funcs = { static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = { .get_modes = imx_pd_connector_get_modes, .best_encoder = imx_pd_connector_best_encoder, - .mode_valid = imx_drm_connector_mode_valid, }; static struct drm_encoder_funcs imx_pd_encoder_funcs = { diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 36a5febac2a6..7ffb59232e84 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -114,7 +114,7 @@ struct drm_encoder_helper_funcs { /** * drm_connector_helper_funcs - helper operations for connectors * @get_modes: get mode list for this connector - * @mode_valid: is this mode valid on the given connector? + * @mode_valid (optional): is this mode valid on the given connector? * * The helper operations are called by the mid-layer CRTC helper. */ -- cgit v1.3-18-gd494 From eaaf8f0fc32468d4dedbb5b5f9c5bfb27744be4c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 28 Aug 2013 15:19:23 +0200 Subject: drm/pci: fold in irq_by_busid support This is a ums-only ioctl, and we've only ever supported ums (at least in upstream) on pci devices. So no point in keeping that piece of legacy logic abstracted within the drm bus driver. To keep things work without CONFIG_PCI also add a dummy ioctl. v2: Block the irq_by_busid ioctl for modeset drivers. v3: Spelling/whitespace polish (Thierry) Reviewed-by: Thierry Reding Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 27 --------------------------- drivers/gpu/drm/drm_pci.c | 39 +++++++++++++++++++++++++++++++++++++-- include/drm/drmP.h | 1 - 3 files changed, 37 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index d4cc47690d65..e5920e7a4392 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -56,33 +56,6 @@ */ #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 -/** - * Get interrupt from bus id. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument, pointing to a drm_irq_busid structure. - * \return zero on success or a negative number on failure. - * - * Finds the PCI device with the specified bus id and gets its IRQ number. - * This IOCTL is deprecated, and will now return EINVAL for any busid not equal - * to that of the device that this DRM instance attached to. - */ -int drm_irq_by_busid(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_irq_busid *p = data; - - if (!dev->driver->bus->irq_by_busid) - return -EINVAL; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) - return -EINVAL; - - return dev->driver->bus->irq_by_busid(dev, p); -} - /* * Clear vblank timestamp buffer for a crtc. */ diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 9c696a5ad74d..8d4221683af4 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -247,7 +247,6 @@ err: return ret; } - static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) { if ((p->busnum >> 8) != drm_get_pci_domain(dev) || @@ -262,6 +261,37 @@ static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) return 0; } +/** + * Get interrupt from bus id. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument, pointing to a drm_irq_busid structure. + * \return zero on success or a negative number on failure. + * + * Finds the PCI device with the specified bus id and gets its IRQ number. + * This IOCTL is deprecated, and will now return EINVAL for any busid not equal + * to that of the device that this DRM instance attached to. + */ +int drm_irq_by_busid(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_irq_busid *p = data; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + /* UMS was only ever support on PCI devices. */ + if (WARN_ON(!dev->pdev)) + return -EINVAL; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return -EINVAL; + + return drm_pci_irq_by_busid(dev, p); +} + static void drm_pci_agp_init(struct drm_device *dev) { if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { @@ -292,7 +322,6 @@ static struct drm_bus drm_pci_bus = { .get_name = drm_pci_get_name, .set_busid = drm_pci_set_busid, .set_unique = drm_pci_set_unique, - .irq_by_busid = drm_pci_irq_by_busid, }; /** @@ -453,6 +482,12 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver) } void drm_pci_agp_destroy(struct drm_device *dev) {} + +int drm_irq_by_busid(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return -EINVAL; +} #endif EXPORT_SYMBOL(drm_pci_init); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index a7c2a862b4f4..6d7ca98d0143 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -737,7 +737,6 @@ struct drm_bus { int (*set_busid)(struct drm_device *dev, struct drm_master *master); int (*set_unique)(struct drm_device *dev, struct drm_master *master, struct drm_unique *unique); - int (*irq_by_busid)(struct drm_device *dev, struct drm_irq_busid *p); }; /** -- cgit v1.3-18-gd494 From ebfa4324930618e72645d2eb7db1c9773228a868 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 3 Nov 2013 20:27:09 +0100 Subject: drm: remove drm_dev_to_irq from drivers Only used in some legacy pci drivers, and dereferencing the PCI irq is actually shorter ... Since this removes all users for drm_dev_to_irq from the tree except in drm_irq.c, move the inline helper in there. It'll disappear soon, too. v2: Polish commit message (Thierry) Reviewed-by: Thierry Reding Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 5 +++++ drivers/gpu/drm/mga/mga_state.c | 2 +- drivers/gpu/drm/r128/r128_state.c | 2 +- drivers/gpu/drm/radeon/radeon_state.c | 2 +- include/drm/drmP.h | 5 ----- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 06a53f8b618c..589e865832cd 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -233,6 +233,11 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state) } } +static inline int drm_dev_to_irq(struct drm_device *dev) +{ + return dev->driver->bus->get_irq(dev); +} + /** * Install IRQ handler. * diff --git a/drivers/gpu/drm/mga/mga_state.c b/drivers/gpu/drm/mga/mga_state.c index 314685b7f41f..3cb58df5237e 100644 --- a/drivers/gpu/drm/mga/mga_state.c +++ b/drivers/gpu/drm/mga/mga_state.c @@ -1020,7 +1020,7 @@ static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *fil switch (param->param) { case MGA_PARAM_IRQ_NR: - value = drm_dev_to_irq(dev); + value = dev->pdev->irq; break; case MGA_PARAM_CARD_TYPE: value = dev_priv->chipset; diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c index e806dacd452f..97064dd434c2 100644 --- a/drivers/gpu/drm/r128/r128_state.c +++ b/drivers/gpu/drm/r128/r128_state.c @@ -1594,7 +1594,7 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi switch (param->param) { case R128_PARAM_IRQ_NR: - value = drm_dev_to_irq(dev); + value = dev->pdev->irq; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index 956ab7f14e16..b576549fc783 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -3054,7 +3054,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) value = 0; else - value = drm_dev_to_irq(dev); + value = dev->pdev->irq; break; case RADEON_PARAM_GART_BASE: value = dev_priv->gart_vm_start; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 6d7ca98d0143..41839ea0c1ee 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1185,11 +1185,6 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev, return ((dev->driver->driver_features & feature) ? 1 : 0); } -static inline int drm_dev_to_irq(struct drm_device *dev) -{ - return dev->driver->bus->get_irq(dev); -} - static inline void drm_device_set_unplugged(struct drm_device *dev) { smp_wmb(); -- cgit v1.3-18-gd494 From 42b21049fc26513ca8e732f47559b1525b04a992 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 3 Nov 2013 20:30:25 +0100 Subject: drm: kill drm_bus->bus_type Completely unused. Hooray, midlayer mistakes that didn't cause work to undo! v2: Rebase on top of the recent tegra changes which added a host1x drm bus. Reviewed-by: Thierry Reding Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_pci.c | 1 - drivers/gpu/drm/drm_platform.c | 1 - drivers/gpu/drm/drm_usb.c | 1 - drivers/gpu/drm/tegra/bus.c | 1 - include/drm/drmP.h | 6 ------ 5 files changed, 10 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 8d4221683af4..08c76af920d6 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -317,7 +317,6 @@ void drm_pci_agp_destroy(struct drm_device *dev) } static struct drm_bus drm_pci_bus = { - .bus_type = DRIVER_BUS_PCI, .get_irq = drm_pci_get_irq, .get_name = drm_pci_get_name, .set_busid = drm_pci_set_busid, diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 319ff5385601..5cd8c695824f 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -123,7 +123,6 @@ err: } static struct drm_bus drm_platform_bus = { - .bus_type = DRIVER_BUS_PLATFORM, .get_irq = drm_platform_get_irq, .get_name = drm_platform_get_name, .set_busid = drm_platform_set_busid, diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c index c3406aad2944..ed60f887c805 100644 --- a/drivers/gpu/drm/drm_usb.c +++ b/drivers/gpu/drm/drm_usb.c @@ -53,7 +53,6 @@ static int drm_usb_set_busid(struct drm_device *dev, } static struct drm_bus drm_usb_bus = { - .bus_type = DRIVER_BUS_USB, .get_irq = drm_usb_get_irq, .get_name = drm_usb_get_name, .set_busid = drm_usb_set_busid, diff --git a/drivers/gpu/drm/tegra/bus.c b/drivers/gpu/drm/tegra/bus.c index 71cef5c13dc8..6916fa51cfa4 100644 --- a/drivers/gpu/drm/tegra/bus.c +++ b/drivers/gpu/drm/tegra/bus.c @@ -37,7 +37,6 @@ static int drm_host1x_set_busid(struct drm_device *dev, } static struct drm_bus drm_host1x_bus = { - .bus_type = DRIVER_BUS_HOST1X, .set_busid = drm_host1x_set_busid, }; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 41839ea0c1ee..9f1fb8d36b67 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -143,11 +143,6 @@ int drm_err(const char *func, const char *format, ...); #define DRIVER_PRIME 0x4000 #define DRIVER_RENDER 0x8000 -#define DRIVER_BUS_PCI 0x1 -#define DRIVER_BUS_PLATFORM 0x2 -#define DRIVER_BUS_USB 0x3 -#define DRIVER_BUS_HOST1X 0x4 - /***********************************************************************/ /** \name Begin the DRM... */ /*@{*/ @@ -731,7 +726,6 @@ struct drm_master { #define DRM_SCANOUTPOS_ACCURATE (1 << 2) struct drm_bus { - int bus_type; int (*get_irq)(struct drm_device *dev); const char *(*get_name)(struct drm_device *dev); int (*set_busid)(struct drm_device *dev, struct drm_master *master); -- cgit v1.3-18-gd494 From fc8fd40eb29a936cc689d0008863d39a67741c67 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 3 Nov 2013 20:46:34 +0100 Subject: drm: Rip out totally bogus vga_switcheroo->can_switch locking So I just wanted to add a new field to struct drm_device and accidentally stumbled over something. According to comments dev->open_count is protected by dev->count_lock, but that's totally not the case. It's protected by drm_global_mutex. Unfortunately the vga switcheroo callbacks took this comment at face value. The problem is that we can't just take the drm_global_mutex because: - It would lead to a locking inversion with the driver load/unload paths. - It wouldn't actually protect anything, for that we'd need to wrap the entire vga switcheroo code in the drm_global_mutex. And I'm not sure whether that would actually solve anything. What we probably want is a try_to_grab_switcheroo reference kind of thing which is used in the driver's ->open callback. Then we could move all that ->can_switch madness into the vga switcheroo core where it really belongs. But since that would amount to real work take the easy way out and just add a comment. It's definitely not going to make anything worse since doing switcheroo state changes while restarting X just isn't recommended. Even though the delayed switching code does exactly that. v2: - Simplify the ->can_switch implementations more (Thierry) - Fix comment about the dev->open_count locking (Thierry) Cc: Thierry Reding Reviewed-by: Laurent Pinchart (v1) Reviewed-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 11 ++++++----- drivers/gpu/drm/nouveau/nouveau_vga.c | 11 ++++++----- drivers/gpu/drm/radeon/radeon_device.c | 11 ++++++----- include/drm/drmP.h | 2 +- 4 files changed, 19 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 96177eec0a0e..283ff06001bc 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1277,12 +1277,13 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_ static bool i915_switcheroo_can_switch(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - bool can_switch; - spin_lock(&dev->count_lock); - can_switch = (dev->open_count == 0); - spin_unlock(&dev->count_lock); - return can_switch; + /* + * FIXME: open_count is protected by drm_global_mutex but that would lead to + * locking inversion with the driver load path. And the access here is + * completely racy anyway. So don't bother with locking for now. + */ + return dev->open_count == 0; } static const struct vga_switcheroo_client_ops i915_switcheroo_ops = { diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index fb84da3cb50d..4f4c3fec6916 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -64,12 +64,13 @@ static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - bool can_switch; - spin_lock(&dev->count_lock); - can_switch = (dev->open_count == 0); - spin_unlock(&dev->count_lock); - return can_switch; + /* + * FIXME: open_count is protected by drm_global_mutex but that would lead to + * locking inversion with the driver load path. And the access here is + * completely racy anyway. So don't bother with locking for now. + */ + return dev->open_count == 0; } static const struct vga_switcheroo_client_ops diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 511fe26198e4..9aa1afd1786e 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1125,12 +1125,13 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero static bool radeon_switcheroo_can_switch(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - bool can_switch; - spin_lock(&dev->count_lock); - can_switch = (dev->open_count == 0); - spin_unlock(&dev->count_lock); - return can_switch; + /* + * FIXME: open_count is protected by drm_global_mutex but that would lead to + * locking inversion with the driver load path. And the access here is + * completely racy anyway. So don't bother with locking for now. + */ + return dev->open_count == 0; } static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = { diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 9f1fb8d36b67..a20d882ca265 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1076,7 +1076,7 @@ struct drm_device { /** \name Usage Counters */ /*@{ */ - int open_count; /**< Outstanding files open */ + int open_count; /**< Outstanding files open, protected by drm_global_mutex. */ int buf_use; /**< Buffers in use -- cannot alloc */ atomic_t buf_alloc; /**< Buffer allocation in progress */ /*@} */ -- cgit v1.3-18-gd494 From 2177a2182f3f375f64d9938dd884895c3872c380 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 16 Dec 2013 11:21:06 +0100 Subject: drm: rename dev->count_lock to dev->buf_lock Since really that's all it protects - legacy horror stories in drm_bufs.c. Since I don't want to waste any more time on this I didn't bother to actually look at what it protects in there, but it's at least contained now. v2: Move the spurious hunk to the right patch (Thierry). Cc: Thierry Reding Reviewed-by: Thierry Reding Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_bufs.c | 32 ++++++++++++++++---------------- drivers/gpu/drm/drm_stub.c | 2 +- include/drm/drmP.h | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index edec31fe3fed..ef7f0199a0f1 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -656,13 +656,13 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request) DRM_DEBUG("zone invalid\n"); return -EINVAL; } - spin_lock(&dev->count_lock); + spin_lock(&dev->buf_lock); if (dev->buf_use) { - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); return -EBUSY; } atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); mutex_lock(&dev->struct_mutex); entry = &dma->bufs[order]; @@ -805,13 +805,13 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; total = PAGE_SIZE << page_order; - spin_lock(&dev->count_lock); + spin_lock(&dev->buf_lock); if (dev->buf_use) { - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); return -EBUSY; } atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); mutex_lock(&dev->struct_mutex); entry = &dma->bufs[order]; @@ -1015,13 +1015,13 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; - spin_lock(&dev->count_lock); + spin_lock(&dev->buf_lock); if (dev->buf_use) { - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); return -EBUSY; } atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); mutex_lock(&dev->struct_mutex); entry = &dma->bufs[order]; @@ -1175,7 +1175,7 @@ int drm_addbufs(struct drm_device *dev, void *data, * \param arg pointer to a drm_buf_info structure. * \return zero on success or a negative number on failure. * - * Increments drm_device::buf_use while holding the drm_device::count_lock + * Increments drm_device::buf_use while holding the drm_device::buf_lock * lock, preventing of allocating more buffers after this call. Information * about each requested buffer is then copied into user space. */ @@ -1196,13 +1196,13 @@ int drm_infobufs(struct drm_device *dev, void *data, if (!dma) return -EINVAL; - spin_lock(&dev->count_lock); + spin_lock(&dev->buf_lock); if (atomic_read(&dev->buf_alloc)) { - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); return -EBUSY; } ++dev->buf_use; /* Can't allocate more after this call */ - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { if (dma->bufs[i].buf_count) @@ -1381,13 +1381,13 @@ int drm_mapbufs(struct drm_device *dev, void *data, if (!dma) return -EINVAL; - spin_lock(&dev->count_lock); + spin_lock(&dev->buf_lock); if (atomic_read(&dev->buf_alloc)) { - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); return -EBUSY; } dev->buf_use++; /* Can't allocate more after this call */ - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); if (request->count >= dma->buf_count) { if ((dev->agp && (dma->flags & _DRM_DMA_USE_AGP)) diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 4c24c3ac1efa..5394b201c3d0 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -569,7 +569,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, INIT_LIST_HEAD(&dev->maplist); INIT_LIST_HEAD(&dev->vblank_event_list); - spin_lock_init(&dev->count_lock); + spin_lock_init(&dev->buf_lock); spin_lock_init(&dev->event_lock); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index a20d882ca265..85682d959c7e 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1069,7 +1069,6 @@ struct drm_device { /** \name Locks */ /*@{ */ - spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ struct mutex struct_mutex; /**< For others */ struct mutex master_mutex; /**< For drm_minor::master and drm_file::is_master */ /*@} */ @@ -1077,6 +1076,7 @@ struct drm_device { /** \name Usage Counters */ /*@{ */ int open_count; /**< Outstanding files open, protected by drm_global_mutex. */ + spinlock_t buf_lock; /**< For drm_device::buf_use and a few other things. */ int buf_use; /**< Buffers in use -- cannot alloc */ atomic_t buf_alloc; /**< Buffer allocation in progress */ /*@} */ -- cgit v1.3-18-gd494 From 7c1a38e391745cca72627979e5e02924bed5b43d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 16 Dec 2013 11:21:15 +0100 Subject: drm/irq: track the irq installed in drm_irq_install in dev->irq To get rid of the dev->bus->get_irq callback we need to pass in the desired irq explicitly into drm_irq_install. To avoid having to do the same for drm_irq_unistall just track it internally. That leaves drivers with less room to botch things up. v2: Add the hunk lost in an earlier patch to this one (Thierry). v3: Fix up the totally fumbled logic in drm_irq_install and use the local variable consistently. Spotted by both Thierry and Laurent. Shame on me for failing to properly test the rebase version of this patch ... Cc: Thierry Reding Cc: Laurent Pinchart Reviewed-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 18 +++++++++++------- include/drm/drmP.h | 2 ++ 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 589e865832cd..7cf407bbfed5 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -249,14 +249,16 @@ static inline int drm_dev_to_irq(struct drm_device *dev) */ int drm_irq_install(struct drm_device *dev) { - int ret; + int ret, irq; unsigned long sh_flags = 0; char *irqname; + irq = drm_dev_to_irq(dev); + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; - if (drm_dev_to_irq(dev) == 0) + if (irq == 0) return -EINVAL; /* Driver must have been initialized */ @@ -267,7 +269,7 @@ int drm_irq_install(struct drm_device *dev) return -EBUSY; dev->irq_enabled = true; - DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); + DRM_DEBUG("irq=%d\n", irq); /* Before installing handler */ if (dev->driver->irq_preinstall) @@ -282,7 +284,7 @@ int drm_irq_install(struct drm_device *dev) else irqname = dev->driver->name; - ret = request_irq(drm_dev_to_irq(dev), dev->driver->irq_handler, + ret = request_irq(irq, dev->driver->irq_handler, sh_flags, irqname, dev); if (ret < 0) { @@ -301,7 +303,9 @@ int drm_irq_install(struct drm_device *dev) dev->irq_enabled = false; if (!drm_core_check_feature(dev, DRIVER_MODESET)) vga_client_register(dev->pdev, NULL, NULL, NULL); - free_irq(drm_dev_to_irq(dev), dev); + free_irq(irq, dev); + } else { + dev->irq = irq; } return ret; @@ -344,7 +348,7 @@ int drm_irq_uninstall(struct drm_device *dev) if (!irq_enabled) return -EINVAL; - DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); + DRM_DEBUG("irq=%d\n", dev->irq); if (!drm_core_check_feature(dev, DRIVER_MODESET)) vga_client_register(dev->pdev, NULL, NULL, NULL); @@ -352,7 +356,7 @@ int drm_irq_uninstall(struct drm_device *dev) if (dev->driver->irq_uninstall) dev->driver->irq_uninstall(dev); - free_irq(drm_dev_to_irq(dev), dev); + free_irq(dev->irq, dev); return 0; } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 85682d959c7e..8e8c392d6fa8 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1107,6 +1107,8 @@ struct drm_device { /** \name Context support */ /*@{ */ bool irq_enabled; /**< True if irq handler is enabled */ + int irq; + __volatile__ long context_flag; /**< Context swapping flag */ int last_context; /**< Last current context */ /*@} */ -- cgit v1.3-18-gd494 From bb0f1b5c1695b4399cfd2359c114ae63edbb3ad8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 3 Nov 2013 21:09:27 +0100 Subject: drm: pass the irq explicitly to drm_irq_install Unfortunately this requires a drm-wide change, and I didn't see a sane way around that. Luckily it's fairly simple, we just need to inline the respective get_irq implementation from either drm_pci.c or drm_platform.c. With that we can now also remove drm_dev_to_irq from drm_irq.c. Reviewed-by: Thierry Reding Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 10 +--------- drivers/gpu/drm/armada/armada_drv.c | 2 +- drivers/gpu/drm/drm_irq.c | 13 +++---------- drivers/gpu/drm/gma500/psb_drv.c | 2 +- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_drv.c | 4 ++-- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/msm/msm_drv.c | 2 +- drivers/gpu/drm/qxl/qxl_irq.c | 2 +- drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 +- drivers/gpu/drm/shmobile/shmob_drm_drv.c | 2 +- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- include/drm/drmP.h | 2 +- 14 files changed, 17 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 677a02553ec0..83dd0b043c28 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -341,14 +341,6 @@ char *date; Managed IRQ Registration - - Both the drm_irq_install and - drm_irq_uninstall functions get the device IRQ by - calling drm_dev_to_irq. This inline function will - call a bus-specific operation to retrieve the IRQ number. For platform - devices, platform_get_irq(..., 0) is used to - retrieve the IRQ number. - drm_irq_install starts by calling the irq_preinstall driver operation. The operation @@ -356,7 +348,7 @@ char *date; clearing all pending interrupt flags or disabling the interrupt. - The IRQ will then be requested by a call to + The passed-in IRQ will then be requested by a call to request_irq. If the DRIVER_IRQ_SHARED driver feature flag is set, a shared (IRQF_SHARED) IRQ handler will be requested. diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 32982da82694..567cfbde0883 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -173,7 +173,7 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto err_kms; - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); if (ret) goto err_kms; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index cbf6f259bfe4..de38bc9b6581 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -233,11 +233,6 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state) } } -static inline int drm_dev_to_irq(struct drm_device *dev) -{ - return dev->driver->bus->get_irq(dev); -} - /** * Install IRQ handler. * @@ -247,14 +242,12 @@ static inline int drm_dev_to_irq(struct drm_device *dev) * \c irq_preinstall() and \c irq_postinstall() functions * before and after the installation. */ -int drm_irq_install(struct drm_device *dev) +int drm_irq_install(struct drm_device *dev, int irq) { - int ret, irq; + int ret; unsigned long sh_flags = 0; char *irqname; - irq = drm_dev_to_irq(dev); - if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; @@ -399,7 +392,7 @@ int drm_control(struct drm_device *dev, void *data, ctl->irq != irq) return -EINVAL; mutex_lock(&dev->struct_mutex); - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, irq); mutex_unlock(&dev->struct_mutex); return ret; diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index b686e56646eb..0a3101a3db19 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -354,7 +354,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags) PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R); spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); - drm_irq_install(dev); + drm_irq_install(dev, dev->pdev->irq); dev->vblank_disable_allowed = true; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 283ff06001bc..42de2808e53d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1327,7 +1327,7 @@ static int i915_load_modeset_init(struct drm_device *dev) intel_power_domains_init_hw(dev_priv); - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, dev->pdev->irq); if (ret) goto cleanup_gem_stolen; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 87ce105910f2..6124b491a19e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -574,7 +574,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) mutex_unlock(&dev->struct_mutex); /* We need working interrupts for modeset enabling ... */ - drm_irq_install(dev); + drm_irq_install(dev, dev->pdev->irq); intel_modeset_init_hw(dev); @@ -752,7 +752,7 @@ int i915_reset(struct drm_device *dev) * being false when they shouldn't be able to. */ drm_irq_uninstall(dev); - drm_irq_install(dev); + drm_irq_install(dev, dev->pdev->irq); /* rps/rc6 re-init is necessary to restore state lost after the * reset and the re-install of drm irq. Skip for ironlake per diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d2cc19a7023f..a94938f08698 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4523,7 +4523,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, BUG_ON(!list_empty(&dev_priv->gtt.base.active_list)); - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, dev->pdev->irq); if (ret) goto cleanup_ringbuffer; mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index f9de156b9e65..50ec1bed5820 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -288,7 +288,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) } pm_runtime_get_sync(dev->dev); - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); pm_runtime_put_sync(dev->dev); if (ret < 0) { dev_err(dev->dev, "failed to install IRQ handler\n"); diff --git a/drivers/gpu/drm/qxl/qxl_irq.c b/drivers/gpu/drm/qxl/qxl_irq.c index 28f84b4fce32..34d6a85e9023 100644 --- a/drivers/gpu/drm/qxl/qxl_irq.c +++ b/drivers/gpu/drm/qxl/qxl_irq.c @@ -87,7 +87,7 @@ int qxl_irq_init(struct qxl_device *qdev) atomic_set(&qdev->irq_received_cursor, 0); atomic_set(&qdev->irq_received_io_cmd, 0); qdev->irq_received_error = 0; - ret = drm_irq_install(qdev->ddev); + ret = drm_irq_install(qdev->ddev, qdev->ddev->pdev->irq); qdev->ram_header->int_mask = QXL_INTERRUPT_MASK; if (unlikely(ret != 0)) { DRM_ERROR("Failed installing irq: %d\n", ret); diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 089c9ffb0aa9..16807afab362 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -287,7 +287,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev) INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func); rdev->irq.installed = true; - r = drm_irq_install(rdev->ddev); + r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq); if (r) { rdev->irq.installed = false; flush_work(&rdev->hotplug_work); diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index c839c9c89efb..82c84c7fd4f6 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -185,7 +185,7 @@ static int shmob_drm_load(struct drm_device *dev, unsigned long flags) goto done; } - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); if (ret < 0) { dev_err(&pdev->dev, "failed to install IRQ handler\n"); goto done; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 171a8203892c..b20b69488dc9 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -268,7 +268,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) } pm_runtime_get_sync(dev->dev); - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); pm_runtime_put_sync(dev->dev); if (ret < 0) { dev_err(dev->dev, "failed to install IRQ handler\n"); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 4a223bbea3b3..6bdd15eea7e8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -806,7 +806,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) } if (dev_priv->capabilities & SVGA_CAP_IRQMASK) { - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, dev->pdev->irq); if (ret != 0) { DRM_ERROR("Failed installing irq: %d\n", ret); goto out_no_irq; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 8e8c392d6fa8..7a7cfe88b9bf 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1353,7 +1353,7 @@ extern void drm_core_reclaim_buffers(struct drm_device *dev, /* IRQ support (drm_irq.h) */ extern int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_irq_install(struct drm_device *dev); +extern int drm_irq_install(struct drm_device *dev, int irq); extern int drm_irq_uninstall(struct drm_device *dev); extern int drm_vblank_init(struct drm_device *dev, int num_crtcs); -- cgit v1.3-18-gd494 From b2a21aa25a39837d06eb24a7f0fef1733f9843eb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 3 Nov 2013 21:13:09 +0100 Subject: drm: remove bus->get_irq implementations Now that they're all unused we can get rid of them, including the dummy version in drm_usb.c. Reviewed-by: Thierry Reding Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_pci.c | 6 ------ drivers/gpu/drm/drm_platform.c | 6 ------ drivers/gpu/drm/drm_usb.c | 6 ------ include/drm/drmP.h | 1 - 4 files changed, 19 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 08c76af920d6..eff29e311f70 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -137,11 +137,6 @@ static int drm_get_pci_domain(struct drm_device *dev) return pci_domain_nr(dev->pdev->bus); } -static int drm_pci_get_irq(struct drm_device *dev) -{ - return dev->pdev->irq; -} - static const char *drm_pci_get_name(struct drm_device *dev) { struct pci_driver *pdriver = dev->driver->kdriver.pci; @@ -317,7 +312,6 @@ void drm_pci_agp_destroy(struct drm_device *dev) } static struct drm_bus drm_pci_bus = { - .get_irq = drm_pci_get_irq, .get_name = drm_pci_get_name, .set_busid = drm_pci_set_busid, .set_unique = drm_pci_set_unique, diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 5cd8c695824f..5b918212b1c3 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -68,11 +68,6 @@ err_free: return ret; } -static int drm_platform_get_irq(struct drm_device *dev) -{ - return platform_get_irq(dev->platformdev, 0); -} - static const char *drm_platform_get_name(struct drm_device *dev) { return dev->platformdev->name; @@ -123,7 +118,6 @@ err: } static struct drm_bus drm_platform_bus = { - .get_irq = drm_platform_get_irq, .get_name = drm_platform_get_name, .set_busid = drm_platform_set_busid, }; diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c index ed60f887c805..abdc265c9cc8 100644 --- a/drivers/gpu/drm/drm_usb.c +++ b/drivers/gpu/drm/drm_usb.c @@ -36,11 +36,6 @@ err_free: } EXPORT_SYMBOL(drm_get_usb_dev); -static int drm_usb_get_irq(struct drm_device *dev) -{ - return 0; -} - static const char *drm_usb_get_name(struct drm_device *dev) { return "USB"; @@ -53,7 +48,6 @@ static int drm_usb_set_busid(struct drm_device *dev, } static struct drm_bus drm_usb_bus = { - .get_irq = drm_usb_get_irq, .get_name = drm_usb_get_name, .set_busid = drm_usb_set_busid, }; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 7a7cfe88b9bf..f4d0eaa3da46 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -726,7 +726,6 @@ struct drm_master { #define DRM_SCANOUTPOS_ACCURATE (1 << 2) struct drm_bus { - int (*get_irq)(struct drm_device *dev); const char *(*get_name)(struct drm_device *dev); int (*set_busid)(struct drm_device *dev, struct drm_master *master); int (*set_unique)(struct drm_device *dev, struct drm_master *master, -- cgit v1.3-18-gd494 From 53bf2a2bca9b56e23fa8862159c75868672d7f1e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 3 Nov 2013 21:47:18 +0100 Subject: drm: inline drm_pci_set_unique This is only used for drm versions 1.0, and kms drivers have never been there. So we can appropriately restrict this to legacy and hence pci devices and inline everything. v2: Make the dummy function actually return something, caught by Wu Fengguang's 0-day tester. v3: Fix spelling in comment (Thierry) Reviewed-by: Thierry Reding Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_ioctl.c | 10 +++++++--- drivers/gpu/drm/drm_pci.c | 14 ++++++++++---- include/drm/drmP.h | 5 +++-- 3 files changed, 20 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 93a42040bedb..53560ef53f99 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -93,7 +93,8 @@ drm_unset_busid(struct drm_device *dev, * Copies the bus id from userspace into drm_device::unique, and verifies that * it matches the device this DRM is attached to (EINVAL otherwise). Deprecated * in interface version 1.1 and will return EBUSY when setversion has requested - * version 1.1 or greater. + * version 1.1 or greater. Also note that KMS is all version 1.1 and later and + * UMS was only ever supported on pci devices. */ int drm_setunique(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -108,10 +109,13 @@ int drm_setunique(struct drm_device *dev, void *data, if (!u->unique_len || u->unique_len > 1024) return -EINVAL; - if (!dev->driver->bus->set_unique) + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + if (WARN_ON(!dev->pdev)) return -EINVAL; - ret = dev->driver->bus->set_unique(dev, master, u); + ret = drm_pci_set_unique(dev, master, u); if (ret) goto err; diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index eff29e311f70..c550b349f202 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -185,9 +185,9 @@ err: return ret; } -static int drm_pci_set_unique(struct drm_device *dev, - struct drm_master *master, - struct drm_unique *u) +int drm_pci_set_unique(struct drm_device *dev, + struct drm_master *master, + struct drm_unique *u) { int domain, bus, slot, func, ret; const char *bus_name; @@ -314,7 +314,6 @@ void drm_pci_agp_destroy(struct drm_device *dev) static struct drm_bus drm_pci_bus = { .get_name = drm_pci_get_name, .set_busid = drm_pci_set_busid, - .set_unique = drm_pci_set_unique, }; /** @@ -481,6 +480,13 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, { return -EINVAL; } + +int drm_pci_set_unique(struct drm_device *dev, + struct drm_master *master, + struct drm_unique *u) +{ + return -EINVAL; +} #endif EXPORT_SYMBOL(drm_pci_init); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index f4d0eaa3da46..1a9d509bef66 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -728,8 +728,6 @@ struct drm_master { struct drm_bus { const char *(*get_name)(struct drm_device *dev); int (*set_busid)(struct drm_device *dev, struct drm_master *master); - int (*set_unique)(struct drm_device *dev, struct drm_master *master, - struct drm_unique *unique); }; /** @@ -1511,6 +1509,9 @@ extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size, size_t align); extern void __drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); +extern int drm_pci_set_unique(struct drm_device *dev, + struct drm_master *master, + struct drm_unique *u); /* sysfs support (drm_sysfs.c) */ struct drm_sysfs_class; -- cgit v1.3-18-gd494 From 5829d1834e5486e83547f36576b160023c9609c2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 3 Nov 2013 21:48:48 +0100 Subject: drm: rip out dev->devname This was only ever used to pretty-print the irq driver name. And on kms systems due to set_version bonghits we never set up the prettier name, ever. Which make this a bit pointless. Also, we can always dig out the driver-instance/irq relationship through other means, so this isn't that useful. So just rip it out to simplify the set_version/set_busid insanity a bit. Also delete the temporary busname from drm_pci_set_busid, it's now unused. v2: Rebase on top of the new host1x drm_bus for tegra. Reviewed-by: Thierry Reding Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_ioctl.c | 3 --- drivers/gpu/drm/drm_irq.c | 8 +------- drivers/gpu/drm/drm_pci.c | 25 ------------------------- drivers/gpu/drm/drm_platform.c | 11 ----------- drivers/gpu/drm/drm_stub.c | 5 ----- drivers/gpu/drm/tegra/bus.c | 10 ---------- include/drm/drmP.h | 1 - 7 files changed, 1 insertion(+), 62 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 53560ef53f99..38269d5aa333 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -72,9 +72,6 @@ static void drm_unset_busid(struct drm_device *dev, struct drm_master *master) { - kfree(dev->devname); - dev->devname = NULL; - kfree(master->unique); master->unique = NULL; master->unique_len = 0; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index de38bc9b6581..7583767ec619 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -246,7 +246,6 @@ int drm_irq_install(struct drm_device *dev, int irq) { int ret; unsigned long sh_flags = 0; - char *irqname; if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; @@ -272,13 +271,8 @@ int drm_irq_install(struct drm_device *dev, int irq) if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED)) sh_flags = IRQF_SHARED; - if (dev->devname) - irqname = dev->devname; - else - irqname = dev->driver->name; - ret = request_irq(irq, dev->driver->irq_handler, - sh_flags, irqname, dev); + sh_flags, dev->driver->name, dev); if (ret < 0) { dev->irq_enabled = false; diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index c550b349f202..047c51046d94 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -146,7 +146,6 @@ static const char *drm_pci_get_name(struct drm_device *dev) static int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) { int len, ret; - struct pci_driver *pdriver = dev->driver->kdriver.pci; master->unique_len = 40; master->unique_size = master->unique_len; master->unique = kmalloc(master->unique_size, GFP_KERNEL); @@ -168,18 +167,6 @@ static int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) } else master->unique_len = len; - dev->devname = - kmalloc(strlen(pdriver->name) + - master->unique_len + 2, GFP_KERNEL); - - if (dev->devname == NULL) { - ret = -ENOMEM; - goto err; - } - - sprintf(dev->devname, "%s@%s", pdriver->name, - master->unique); - return 0; err: return ret; @@ -190,7 +177,6 @@ int drm_pci_set_unique(struct drm_device *dev, struct drm_unique *u) { int domain, bus, slot, func, ret; - const char *bus_name; master->unique_len = u->unique_len; master->unique_size = u->unique_len + 1; @@ -207,17 +193,6 @@ int drm_pci_set_unique(struct drm_device *dev, master->unique[master->unique_len] = '\0'; - bus_name = dev->driver->bus->get_name(dev); - dev->devname = kmalloc(strlen(bus_name) + - strlen(master->unique) + 2, GFP_KERNEL); - if (!dev->devname) { - ret = -ENOMEM; - goto err; - } - - sprintf(dev->devname, "%s@%s", bus_name, - master->unique); - /* Return error if the busid submitted doesn't match the device's actual * busid. */ diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 5b918212b1c3..b97b11ea2dc4 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -101,17 +101,6 @@ static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *mas goto err; } - dev->devname = - kmalloc(strlen(dev->platformdev->name) + - master->unique_len + 2, GFP_KERNEL); - - if (dev->devname == NULL) { - ret = -ENOMEM; - goto err; - } - - sprintf(dev->devname, "%s@%s", dev->platformdev->name, - master->unique); return 0; err: return ret; diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 5394b201c3d0..3a8e832ad151 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -166,9 +166,6 @@ static void drm_master_destroy(struct kref *kref) master->unique_len = 0; } - kfree(dev->devname); - dev->devname = NULL; - list_for_each_entry_safe(pt, next, &master->magicfree, head) { list_del(&pt->head); drm_ht_remove_item(&master->magiclist, &pt->hash_item); @@ -648,8 +645,6 @@ static void drm_dev_release(struct kref *ref) drm_minor_free(dev, DRM_MINOR_RENDER); drm_minor_free(dev, DRM_MINOR_CONTROL); - kfree(dev->devname); - mutex_destroy(&dev->master_mutex); kfree(dev); } diff --git a/drivers/gpu/drm/tegra/bus.c b/drivers/gpu/drm/tegra/bus.c index 6916fa51cfa4..b3a66d65cb53 100644 --- a/drivers/gpu/drm/tegra/bus.c +++ b/drivers/gpu/drm/tegra/bus.c @@ -12,9 +12,7 @@ static int drm_host1x_set_busid(struct drm_device *dev, struct drm_master *master) { const char *device = dev_name(dev->dev); - const char *driver = dev->driver->name; const char *bus = dev->dev->bus->name; - int length; master->unique_len = strlen(bus) + 1 + strlen(device); master->unique_size = master->unique_len; @@ -25,14 +23,6 @@ static int drm_host1x_set_busid(struct drm_device *dev, snprintf(master->unique, master->unique_len + 1, "%s:%s", bus, device); - length = strlen(driver) + 1 + master->unique_len; - - dev->devname = kmalloc(length + 1, GFP_KERNEL); - if (!dev->devname) - return -ENOMEM; - - snprintf(dev->devname, length + 1, "%s@%s", driver, master->unique); - return 0; } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 1a9d509bef66..56b028d6bc98 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1048,7 +1048,6 @@ struct drm_vblank_crtc { */ struct drm_device { struct list_head legacy_dev_list;/**< list of devices per driver for stealth attach cleanup */ - char *devname; /**< For /proc/interrupts */ int if_version; /**< Highest interface version set */ /** \name Lifetime Management */ -- cgit v1.3-18-gd494 From 9de1b51f1fae6476155350a0670dc637c762e718 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 3 Nov 2013 22:24:37 +0100 Subject: drm: remove drm_bus->get_name The only user is the info debugfs file, so we only need something human readable. Now for both pci and platform devices we've used the name of the underlying device driver, which matches the name of the drm driver in all cases. So we can just use that instead. The exception is usb, which used a generic "USB". Not to harmful with just one usb driver, but better to use "udl", too. With that converted we can rip out all the ->get_name implementations. Reviewed-by: Thierry Reding Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_info.c | 6 ++---- drivers/gpu/drm/drm_pci.c | 7 ------- drivers/gpu/drm/drm_platform.c | 6 ------ drivers/gpu/drm/drm_usb.c | 6 ------ include/drm/drmP.h | 1 - 5 files changed, 2 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index 7473035dd28b..86feedd5e6f6 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c @@ -47,18 +47,16 @@ int drm_name_info(struct seq_file *m, void *data) struct drm_minor *minor = node->minor; struct drm_device *dev = minor->dev; struct drm_master *master = minor->master; - const char *bus_name; if (!master) return 0; - bus_name = dev->driver->bus->get_name(dev); if (master->unique) { seq_printf(m, "%s %s %s\n", - bus_name, + dev->driver->name, dev_name(dev->dev), master->unique); } else { seq_printf(m, "%s %s\n", - bus_name, dev_name(dev->dev)); + dev->driver->name, dev_name(dev->dev)); } return 0; } diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 047c51046d94..1fbe22a254e1 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -137,12 +137,6 @@ static int drm_get_pci_domain(struct drm_device *dev) return pci_domain_nr(dev->pdev->bus); } -static const char *drm_pci_get_name(struct drm_device *dev) -{ - struct pci_driver *pdriver = dev->driver->kdriver.pci; - return pdriver->name; -} - static int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) { int len, ret; @@ -287,7 +281,6 @@ void drm_pci_agp_destroy(struct drm_device *dev) } static struct drm_bus drm_pci_bus = { - .get_name = drm_pci_get_name, .set_busid = drm_pci_set_busid, }; diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index b97b11ea2dc4..c7ec27bbe7c6 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -68,11 +68,6 @@ err_free: return ret; } -static const char *drm_platform_get_name(struct drm_device *dev) -{ - return dev->platformdev->name; -} - static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *master) { int len, ret, id; @@ -107,7 +102,6 @@ err: } static struct drm_bus drm_platform_bus = { - .get_name = drm_platform_get_name, .set_busid = drm_platform_set_busid, }; diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c index abdc265c9cc8..fae4aa4e1426 100644 --- a/drivers/gpu/drm/drm_usb.c +++ b/drivers/gpu/drm/drm_usb.c @@ -36,11 +36,6 @@ err_free: } EXPORT_SYMBOL(drm_get_usb_dev); -static const char *drm_usb_get_name(struct drm_device *dev) -{ - return "USB"; -} - static int drm_usb_set_busid(struct drm_device *dev, struct drm_master *master) { @@ -48,7 +43,6 @@ static int drm_usb_set_busid(struct drm_device *dev, } static struct drm_bus drm_usb_bus = { - .get_name = drm_usb_get_name, .set_busid = drm_usb_set_busid, }; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 56b028d6bc98..493bbbb300e6 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -726,7 +726,6 @@ struct drm_master { #define DRM_SCANOUTPOS_ACCURATE (1 << 2) struct drm_bus { - const char *(*get_name)(struct drm_device *dev); int (*set_busid)(struct drm_device *dev, struct drm_master *master); }; -- cgit v1.3-18-gd494 From f93227759d9bd3b299c288a6bd448161f849cdfd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 3 Nov 2013 22:32:41 +0100 Subject: drm: Remove dev->kdriver With the last patch to ditch the ->get_name callbacks the last user is now gone. Reviewed-by: Thierry Reding Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_pci.c | 1 - drivers/gpu/drm/drm_platform.c | 1 - drivers/gpu/drm/drm_usb.c | 1 - include/drm/drmP.h | 5 ----- 4 files changed, 8 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 1fbe22a254e1..d237de36a07a 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -364,7 +364,6 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver) DRM_DEBUG("\n"); - driver->kdriver.pci = pdriver; driver->bus = &drm_pci_bus; if (driver->driver_features & DRIVER_MODESET) diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index c7ec27bbe7c6..234e0bc1ae51 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -121,7 +121,6 @@ int drm_platform_init(struct drm_driver *driver, struct platform_device *platfor { DRM_DEBUG("\n"); - driver->kdriver.platform_device = platform_device; driver->bus = &drm_platform_bus; return drm_get_platform_dev(platform_device, driver); } diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c index fae4aa4e1426..c6c7c29ad46f 100644 --- a/drivers/gpu/drm/drm_usb.c +++ b/drivers/gpu/drm/drm_usb.c @@ -51,7 +51,6 @@ int drm_usb_init(struct drm_driver *driver, struct usb_driver *udriver) int res; DRM_DEBUG("\n"); - driver->kdriver.usb = udriver; driver->bus = &drm_usb_bus; res = usb_register(udriver); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 493bbbb300e6..19daabeeffbe 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -963,11 +963,6 @@ struct drm_driver { const struct drm_ioctl_desc *ioctls; int num_ioctls; const struct file_operations *fops; - union { - struct pci_driver *pci; - struct platform_device *platform_device; - struct usb_driver *usb; - } kdriver; struct drm_bus *bus; /* List of devices hanging off this driver with stealth attach. */ -- cgit v1.3-18-gd494 From 73dbd77d88e6974d2e30c239cef67e5370c2b7c5 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 29 Apr 2014 11:44:36 +0200 Subject: drm: Fixup flip-work kerneldoc Describe the fifo parameter. It seems like kerneldoc doesn't properly handle fields defined using a macro, so it will end up complaining about this anyway and not generate the documentation for it either. At least the kerneldoc is now complete. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter --- include/drm/drm_flip_work.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/drm/drm_flip_work.h b/include/drm/drm_flip_work.h index 35c776ae7d3b..9eed34dcd6af 100644 --- a/include/drm/drm_flip_work.h +++ b/include/drm/drm_flip_work.h @@ -57,6 +57,7 @@ typedef void (*drm_flip_func_t)(struct drm_flip_work *work, void *val); * @count: number of committed items * @func: callback fxn called for each committed item * @worker: worker which calls @func + * @fifo: queue of committed items */ struct drm_flip_work { const char *name; -- cgit v1.3-18-gd494 From b87577b7c768683736eea28f70779e8c75b4df62 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 1 May 2014 09:26:53 +1000 Subject: drm: try harder to avoid regression when merging mode bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For QXL hw we really want the bits to be replaced as we change the preferred mode on the fly, and the same goes for virgl when I get to it, however the original fix for this seems to have caused a wierd regression on Intel G33 that in a stunning display of failure at opposition to his normal self, Daniel failed to diagnose. So we are left doing this, ugly ugly ugly ugly, Daniel you fixed that G33 yet?, ugly, ugly. Tested-by: Marc-André Lureau Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_modes.c | 9 ++++-- drivers/gpu/drm/drm_probe_helper.c | 64 +++++++++++++++++++++++++------------ drivers/gpu/drm/qxl/qxl_display.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 2 +- include/drm/drm_crtc_helper.h | 4 +++ include/drm/drm_modes.h | 2 +- 6 files changed, 57 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 8b410576fce4..bedf1894e17e 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1013,6 +1013,7 @@ EXPORT_SYMBOL(drm_mode_sort); /** * drm_mode_connector_list_update - update the mode list for the connector * @connector: the connector to update + * @merge_type_bits: whether to merge or overright type bits. * * This moves the modes from the @connector probed_modes list * to the actual mode list. It compares the probed mode against the current @@ -1021,7 +1022,8 @@ EXPORT_SYMBOL(drm_mode_sort); * This is just a helper functions doesn't validate any modes itself and also * doesn't prune any invalid modes. Callers need to do that themselves. */ -void drm_mode_connector_list_update(struct drm_connector *connector) +void drm_mode_connector_list_update(struct drm_connector *connector, + bool merge_type_bits) { struct drm_display_mode *mode; struct drm_display_mode *pmode, *pt; @@ -1039,7 +1041,10 @@ void drm_mode_connector_list_update(struct drm_connector *connector) /* if equal delete the probed mode */ mode->status = pmode->status; /* Merge type bits together */ - mode->type |= pmode->type; + if (merge_type_bits) + mode->type |= pmode->type; + else + mode->type = pmode->type; list_del(&pmode->head); drm_mode_destroy(connector->dev, pmode); break; diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index e70f54d4a581..8afdd0998a8c 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -82,26 +82,8 @@ static void drm_mode_validate_flag(struct drm_connector *connector, return; } -/** - * drm_helper_probe_single_connector_modes - get complete set of display modes - * @connector: connector to probe - * @maxX: max width for modes - * @maxY: max height for modes - * - * Based on the helper callbacks implemented by @connector try to detect all - * valid modes. Modes will first be added to the connector's probed_modes list, - * then culled (based on validity and the @maxX, @maxY parameters) and put into - * the normal modes list. - * - * Intended to be use as a generic implementation of the ->fill_modes() - * @connector vfunc for drivers that use the crtc helpers for output mode - * filtering and detection. - * - * Returns: - * The number of modes found on @connector. - */ -int drm_helper_probe_single_connector_modes(struct drm_connector *connector, - uint32_t maxX, uint32_t maxY) +static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector, + uint32_t maxX, uint32_t maxY, bool merge_type_bits) { struct drm_device *dev = connector->dev; struct drm_display_mode *mode; @@ -155,7 +137,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, if (count == 0) goto prune; - drm_mode_connector_list_update(connector); + drm_mode_connector_list_update(connector, merge_type_bits); if (maxX && maxY) drm_mode_validate_size(dev, &connector->modes, maxX, maxY); @@ -194,8 +176,48 @@ prune: return count; } + +/** + * drm_helper_probe_single_connector_modes - get complete set of display modes + * @connector: connector to probe + * @maxX: max width for modes + * @maxY: max height for modes + * + * Based on the helper callbacks implemented by @connector try to detect all + * valid modes. Modes will first be added to the connector's probed_modes list, + * then culled (based on validity and the @maxX, @maxY parameters) and put into + * the normal modes list. + * + * Intended to be use as a generic implementation of the ->fill_modes() + * @connector vfunc for drivers that use the crtc helpers for output mode + * filtering and detection. + * + * Returns: + * The number of modes found on @connector. + */ +int drm_helper_probe_single_connector_modes(struct drm_connector *connector, + uint32_t maxX, uint32_t maxY) +{ + return drm_helper_probe_single_connector_modes_merge_bits(connector, maxX, maxY, true); +} EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); +/** + * drm_helper_probe_single_connector_modes_nomerge - get complete set of display modes + * @connector: connector to probe + * @maxX: max width for modes + * @maxY: max height for modes + * + * This operates like drm_hehlper_probe_single_connector_modes except it + * replaces the mode bits instead of merging them for preferred modes. + */ +int drm_helper_probe_single_connector_modes_nomerge(struct drm_connector *connector, + uint32_t maxX, uint32_t maxY) +{ + return drm_helper_probe_single_connector_modes_merge_bits(connector, maxX, maxY, false); +} +EXPORT_SYMBOL(drm_helper_probe_single_connector_modes_nomerge); + /** * drm_kms_helper_hotplug_event - fire off KMS hotplug events * @dev: drm_device whose connector state changed diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 41bdd174657e..3ab9072d3623 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -841,7 +841,7 @@ static const struct drm_connector_funcs qxl_connector_funcs = { .save = qxl_conn_save, .restore = qxl_conn_restore, .detect = qxl_conn_detect, - .fill_modes = drm_helper_probe_single_connector_modes, + .fill_modes = drm_helper_probe_single_connector_modes_nomerge, .set_property = qxl_conn_set_property, .destroy = qxl_conn_destroy, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index a2dde5ad8138..e7199b454ca0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2001,7 +2001,7 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, if (du->pref_mode) list_move(&du->pref_mode->head, &connector->probed_modes); - drm_mode_connector_list_update(connector); + drm_mode_connector_list_update(connector, true); return 1; } diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 36a5febac2a6..f51c8393e9a8 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -165,6 +165,10 @@ extern void drm_helper_resume_force_mode(struct drm_device *dev); extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); +extern int drm_helper_probe_single_connector_modes_nomerge(struct drm_connector + *connector, + uint32_t maxX, + uint32_t maxY); extern void drm_kms_helper_poll_init(struct drm_device *dev); extern void drm_kms_helper_poll_fini(struct drm_device *dev); extern bool drm_helper_hpd_irq_event(struct drm_device *dev); diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 2dbbf9976669..91d0582f924e 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -223,7 +223,7 @@ void drm_mode_validate_size(struct drm_device *dev, void drm_mode_prune_invalid(struct drm_device *dev, struct list_head *mode_list, bool verbose); void drm_mode_sort(struct list_head *mode_list); -void drm_mode_connector_list_update(struct drm_connector *connector); +void drm_mode_connector_list_update(struct drm_connector *connector, bool merge_type_bits); /* parsing cmdline modes */ bool -- cgit v1.3-18-gd494 From fd3c269f8ff940cc0fbb3b7f7e84c0572f6f759a Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Thu, 17 Apr 2014 10:37:35 +0800 Subject: drm/i915: Split the BDW device definition to prepare for dual BSD rings on BDW GT3 Based on the hardware spec, the BDW GT3 has the different configuration with the BDW GT1/GT2. So split the BDW device info definition. This is to do the preparation for adding the Dual BSD rings on BDW GT3 machine. V1->V2: Follow Daniel's comment to pay attention to the stolen check for BDW in kernel/early-quirks.c Reviewed-by: Imre Deak Signed-off-by: Zhao Yakui Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 26 ++++++++++++++++++++++++-- include/drm/i915_pciids.h | 22 +++++++++++++++++----- 2 files changed, 41 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f2ca3e929cd7..9f47aab7915f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -279,6 +279,26 @@ static const struct intel_device_info intel_broadwell_m_info = { GEN_DEFAULT_PIPEOFFSETS, }; +static const struct intel_device_info intel_broadwell_gt3d_info = { + .gen = 8, .num_pipes = 3, + .need_gfx_hws = 1, .has_hotplug = 1, + .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, + .has_llc = 1, + .has_ddi = 1, + .has_fbc = 1, + GEN_DEFAULT_PIPEOFFSETS, +}; + +static const struct intel_device_info intel_broadwell_gt3m_info = { + .gen = 8, .is_mobile = 1, .num_pipes = 3, + .need_gfx_hws = 1, .has_hotplug = 1, + .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, + .has_llc = 1, + .has_ddi = 1, + .has_fbc = 1, + GEN_DEFAULT_PIPEOFFSETS, +}; + /* * Make sure any device matches here are from most specific to most * general. For example, since the Quanta match is based on the subsystem @@ -311,8 +331,10 @@ static const struct intel_device_info intel_broadwell_m_info = { INTEL_HSW_M_IDS(&intel_haswell_m_info), \ INTEL_VLV_M_IDS(&intel_valleyview_m_info), \ INTEL_VLV_D_IDS(&intel_valleyview_d_info), \ - INTEL_BDW_M_IDS(&intel_broadwell_m_info), \ - INTEL_BDW_D_IDS(&intel_broadwell_d_info) + INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info), \ + INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info), \ + INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info), \ + INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info) static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_PCI_IDS, diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 940ece4934ba..24f3cad045db 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -223,14 +223,26 @@ _INTEL_BDW_D(gt, 0x160A, info), /* Server */ \ _INTEL_BDW_D(gt, 0x160D, info) /* Workstation */ -#define INTEL_BDW_M_IDS(info) \ +#define INTEL_BDW_GT12M_IDS(info) \ _INTEL_BDW_M_IDS(1, info), \ - _INTEL_BDW_M_IDS(2, info), \ - _INTEL_BDW_M_IDS(3, info) + _INTEL_BDW_M_IDS(2, info) -#define INTEL_BDW_D_IDS(info) \ +#define INTEL_BDW_GT12D_IDS(info) \ _INTEL_BDW_D_IDS(1, info), \ - _INTEL_BDW_D_IDS(2, info), \ + _INTEL_BDW_D_IDS(2, info) + +#define INTEL_BDW_GT3M_IDS(info) \ + _INTEL_BDW_M_IDS(3, info) + +#define INTEL_BDW_GT3D_IDS(info) \ _INTEL_BDW_D_IDS(3, info) +#define INTEL_BDW_M_IDS(info) \ + INTEL_BDW_GT12M_IDS(info), \ + INTEL_BDW_GT3M_IDS(info) + +#define INTEL_BDW_D_IDS(info) \ + INTEL_BDW_GT12D_IDS(info), \ + INTEL_BDW_GT3D_IDS(info) + #endif /* _I915_PCIIDS_H */ -- cgit v1.3-18-gd494 From 7d87a7f709650bde4d7d63117f25ee1c095da5dd Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 9 Apr 2014 18:19:04 +0300 Subject: srm/i915/chv: Add Cherryview PCI IDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Update to also fill in the new num_pipes field. v3: Rebase on top of the pciid extraction. v4: Switch from info->has*ring to info->ring mask. Also add VEBOX support whiel at it. v5: s/CHV_PCI_IDS/CHV_IDS/, and drop the trailing '\' Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 12 +++++++++++- include/drm/i915_pciids.h | 6 ++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 4024e16ae63d..6868bc0eabd3 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -299,6 +299,15 @@ static const struct intel_device_info intel_broadwell_gt3m_info = { GEN_DEFAULT_PIPEOFFSETS, }; +static const struct intel_device_info intel_cherryview_info = { + .is_preliminary = 1, + .gen = 8, .num_pipes = 2, + .need_gfx_hws = 1, .has_hotplug = 1, + .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, + .is_valleyview = 1, + .display_mmio_offset = VLV_DISPLAY_BASE, +}; + /* * Make sure any device matches here are from most specific to most * general. For example, since the Quanta match is based on the subsystem @@ -334,7 +343,8 @@ static const struct intel_device_info intel_broadwell_gt3m_info = { INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info), \ INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info), \ INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info), \ - INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info) + INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info), \ + INTEL_CHV_IDS(&intel_cherryview_info) static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_PCI_IDS, diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 24f3cad045db..d18f31a77987 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -245,4 +245,10 @@ INTEL_BDW_GT12D_IDS(info), \ INTEL_BDW_GT3D_IDS(info) +#define INTEL_CHV_IDS(info) \ + INTEL_VGA_DEVICE(0x22b0, info), \ + INTEL_VGA_DEVICE(0x22b1, info), \ + INTEL_VGA_DEVICE(0x22b2, info), \ + INTEL_VGA_DEVICE(0x22b3, info) + #endif /* _I915_PCIIDS_H */ -- cgit v1.3-18-gd494 From ad222799bec32a2db99c12b4dfa5dc19a1f6eaac Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 2 May 2014 13:22:19 +1000 Subject: drm: fix memory leak around mode_group (v2) This mode group id_list was never being freed. v2: take David's suggestion to free in minor_free. Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 6 ++++++ drivers/gpu/drm/drm_stub.c | 1 + include/drm/drm_crtc.h | 1 + 3 files changed, 8 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d8b7099abece..a3fe32439a5b 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1378,6 +1378,12 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr return 0; } +void drm_mode_group_destroy(struct drm_mode_group *group) +{ + kfree(group->id_list); + group->id_list = NULL; +} + /* * NOTE: Driver's shouldn't ever call drm_mode_group_init_legacy_group - it is * the drm core's responsibility to set up mode control groups. diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 1447b0ee3676..3727ac8bc310 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -294,6 +294,7 @@ static void drm_minor_free(struct drm_device *dev, unsigned int type) slot = drm_minor_get_slot(dev, type); if (*slot) { + drm_mode_group_destroy(&(*slot)->mode_group); kfree(*slot); *slot = NULL; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index e55fccbe7c42..c6b9e8ab0a26 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -915,6 +915,7 @@ extern const char *drm_get_tv_subconnector_name(int val); extern const char *drm_get_tv_select_name(int val); extern void drm_fb_release(struct drm_file *file_priv); extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); +extern void drm_mode_group_destroy(struct drm_mode_group *group); extern bool drm_probe_ddc(struct i2c_adapter *adapter); extern struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); -- cgit v1.3-18-gd494 From 5cc9ed4b9a7ac579362ccebac67f7a4cdb36de06 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 16 May 2014 14:22:37 +0100 Subject: drm/i915: Introduce mapping of user pages into video memory (userptr) ioctl By exporting the ability to map user address and inserting PTEs representing their backing pages into the GTT, we can exploit UMA in order to utilize normal application data as a texture source or even as a render target (depending upon the capabilities of the chipset). This has a number of uses, with zero-copy downloads to the GPU and efficient readback making the intermixed streaming of CPU and GPU operations fairly efficient. This ability has many widespread implications from faster rendering of client-side software rasterisers (chromium), mitigation of stalls due to read back (firefox) and to faster pipelining of texture data (such as pixel buffer objects in GL or data blobs in CL). v2: Compile with CONFIG_MMU_NOTIFIER v3: We can sleep while performing invalidate-range, which we can utilise to drop our page references prior to the kernel manipulating the vma (for either discard or cloning) and so protect normal users. v4: Only run the invalidate notifier if the range intercepts the bo. v5: Prevent userspace from attempting to GTT mmap non-page aligned buffers v6: Recheck after reacquire mutex for lost mmu. v7: Fix implicit padding of ioctl struct by rounding to next 64bit boundary. v8: Fix rebasing error after forwarding porting the back port. v9: Limit the userptr to page aligned entries. We now expect userspace to handle all the offset-in-page adjustments itself. v10: Prevent vma from being copied across fork to avoid issues with cow. v11: Drop vma behaviour changes -- locking is nigh on impossible. Use a worker to load user pages to avoid lock inversions. v12: Use get_task_mm()/mmput() for correct refcounting of mm. v13: Use a worker to release the mmu_notifier to avoid lock inversion v14: Decouple mmu_notifier from struct_mutex using a custom mmu_notifer with its own locking and tree of objects for each mm/mmu_notifier. v15: Prevent overlapping userptr objects, and invalidate all objects within the mmu_notifier range v16: Fix a typo for iterating over multiple objects in the range and rearrange error path to destroy the mmu_notifier locklessly. Also close a race between invalidate_range and the get_pages_worker. v17: Close a race between get_pages_worker/invalidate_range and fresh allocations of the same userptr range - and notice that struct_mutex was presumed to be held when during creation it wasn't. v18: Sigh. Fix the refactor of st_set_pages() to allocate enough memory for the struct sg_table and to clear it before reporting an error. v19: Always error out on read-only userptr requests as we don't have the hardware infrastructure to support them at the moment. v20: Refuse to implement read-only support until we have the required infrastructure - but reserve the bit in flags for future use. v21: use_mm() is not required for get_user_pages(). It is only meant to be used to fix up the kernel thread's current->mm for use with copy_user(). v22: Use sg_alloc_table_from_pages for that chunky feeling v23: Export a function for sanity checking dma-buf rather than encode userptr details elsewhere, and clean up comments based on suggestions by Bradley. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: "Gong, Zhipeng" Cc: Akash Goel Cc: "Volkin, Bradley D" Reviewed-by: Tvrtko Ursulin Reviewed-by: Brad Volkin [danvet: Frob ioctl allocation to pick the next one - will cause a bit of fuss with create2 apparently, but such are the rules.] [danvet2: oops, forgot to git add after manual patch application] [danvet3: Appease sparse.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Kconfig | 1 + drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_dma.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 25 +- drivers/gpu/drm/i915/i915_gem.c | 4 + drivers/gpu/drm/i915/i915_gem_dmabuf.c | 8 + drivers/gpu/drm/i915/i915_gem_userptr.c | 711 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_gpu_error.c | 2 + include/uapi/drm/i915_drm.h | 16 + 9 files changed, 768 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/i915/i915_gem_userptr.c (limited to 'include') diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index e4e3c01b8cbc..437e1824d0bf 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -5,6 +5,7 @@ config DRM_I915 depends on (AGP || AGP=n) select INTEL_GTT select AGP_INTEL if AGP + select INTERVAL_TREE # we need shmfs for the swappable backing store, and in particular # the shmem_readpage() which depends upon tmpfs select SHMEM diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 24469168d550..7b2f3bee3518 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -27,6 +27,7 @@ i915-y += i915_cmd_parser.o \ i915_gem.o \ i915_gem_stolen.o \ i915_gem_tiling.o \ + i915_gem_userptr.o \ i915_gpu_error.o \ i915_irq.o \ i915_trace_points.o \ diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 46f1decab76f..dea455bd889a 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1983,6 +1983,7 @@ const struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9e9e8166a1f3..a270e0773e2d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -178,6 +179,7 @@ enum hpd_pin { if ((intel_connector)->base.encoder == (__encoder)) struct drm_i915_private; +struct i915_mmu_object; enum intel_dpll_id { DPLL_ID_PRIVATE = -1, /* non-shared dpll in use */ @@ -403,6 +405,7 @@ struct drm_i915_error_state { u32 tiling:2; u32 dirty:1; u32 purgeable:1; + u32 userptr:1; s32 ring:4; u32 cache_level:3; } **active_bo, **pinned_bo; @@ -1447,6 +1450,9 @@ struct drm_i915_private { struct i915_gtt gtt; /* VM representing the global address space */ struct i915_gem_mm mm; +#if defined(CONFIG_MMU_NOTIFIER) + DECLARE_HASHTABLE(mmu_notifiers, 7); +#endif /* Kernel Modesetting */ @@ -1580,6 +1586,8 @@ struct drm_i915_gem_object_ops { */ int (*get_pages)(struct drm_i915_gem_object *); void (*put_pages)(struct drm_i915_gem_object *); + int (*dmabuf_export)(struct drm_i915_gem_object *); + void (*release)(struct drm_i915_gem_object *); }; struct drm_i915_gem_object { @@ -1693,8 +1701,20 @@ struct drm_i915_gem_object { /** for phy allocated objects */ struct drm_i915_gem_phys_object *phys_obj; -}; + union { + struct i915_gem_userptr { + uintptr_t ptr; + unsigned read_only :1; + unsigned workers :4; +#define I915_GEM_USERPTR_MAX_WORKERS 15 + + struct mm_struct *mm; + struct i915_mmu_object *mn; + struct work_struct *work; + } userptr; + }; +}; #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base) /** @@ -2119,6 +2139,9 @@ int i915_gem_set_tiling(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_get_tiling(struct drm_device *dev, void *data, struct drm_file *file_priv); +int i915_gem_init_userptr(struct drm_device *dev); +int i915_gem_userptr_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_wait_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f6c03513de52..d5aad0bc71f7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4263,6 +4263,9 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) if (obj->base.import_attach) drm_prime_gem_destroy(&obj->base, NULL); + if (obj->ops->release) + obj->ops->release(obj); + drm_gem_object_release(&obj->base); i915_gem_info_remove_obj(dev_priv, obj->base.size); @@ -4542,6 +4545,7 @@ int i915_gem_init(struct drm_device *dev) DRM_DEBUG_DRIVER("allow wake ack timed out\n"); } + i915_gem_init_userptr(dev); i915_gem_init_global_gtt(dev); ret = i915_gem_context_init(dev); diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c index 321102a8374b..580aa42443ed 100644 --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c @@ -229,6 +229,14 @@ static const struct dma_buf_ops i915_dmabuf_ops = { struct dma_buf *i915_gem_prime_export(struct drm_device *dev, struct drm_gem_object *gem_obj, int flags) { + struct drm_i915_gem_object *obj = to_intel_bo(gem_obj); + + if (obj->ops->dmabuf_export) { + int ret = obj->ops->dmabuf_export(obj); + if (ret) + return ERR_PTR(ret); + } + return dma_buf_export(gem_obj, &i915_dmabuf_ops, gem_obj->size, flags); } diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c new file mode 100644 index 000000000000..21ea92886a56 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -0,0 +1,711 @@ +/* + * Copyright © 2012-2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#include "drmP.h" +#include "i915_drm.h" +#include "i915_drv.h" +#include "i915_trace.h" +#include "intel_drv.h" +#include +#include +#include +#include + +#if defined(CONFIG_MMU_NOTIFIER) +#include + +struct i915_mmu_notifier { + spinlock_t lock; + struct hlist_node node; + struct mmu_notifier mn; + struct rb_root objects; + struct drm_device *dev; + struct mm_struct *mm; + struct work_struct work; + unsigned long count; + unsigned long serial; +}; + +struct i915_mmu_object { + struct i915_mmu_notifier *mmu; + struct interval_tree_node it; + struct drm_i915_gem_object *obj; +}; + +static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, + struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct i915_mmu_notifier *mn = container_of(_mn, struct i915_mmu_notifier, mn); + struct interval_tree_node *it = NULL; + unsigned long serial = 0; + + end--; /* interval ranges are inclusive, but invalidate range is exclusive */ + while (start < end) { + struct drm_i915_gem_object *obj; + + obj = NULL; + spin_lock(&mn->lock); + if (serial == mn->serial) + it = interval_tree_iter_next(it, start, end); + else + it = interval_tree_iter_first(&mn->objects, start, end); + if (it != NULL) { + obj = container_of(it, struct i915_mmu_object, it)->obj; + drm_gem_object_reference(&obj->base); + serial = mn->serial; + } + spin_unlock(&mn->lock); + if (obj == NULL) + return; + + mutex_lock(&mn->dev->struct_mutex); + /* Cancel any active worker and force us to re-evaluate gup */ + obj->userptr.work = NULL; + + if (obj->pages != NULL) { + struct drm_i915_private *dev_priv = to_i915(mn->dev); + struct i915_vma *vma, *tmp; + bool was_interruptible; + + was_interruptible = dev_priv->mm.interruptible; + dev_priv->mm.interruptible = false; + + list_for_each_entry_safe(vma, tmp, &obj->vma_list, vma_link) { + int ret = i915_vma_unbind(vma); + WARN_ON(ret && ret != -EIO); + } + WARN_ON(i915_gem_object_put_pages(obj)); + + dev_priv->mm.interruptible = was_interruptible; + } + + start = obj->userptr.ptr + obj->base.size; + + drm_gem_object_unreference(&obj->base); + mutex_unlock(&mn->dev->struct_mutex); + } +} + +static const struct mmu_notifier_ops i915_gem_userptr_notifier = { + .invalidate_range_start = i915_gem_userptr_mn_invalidate_range_start, +}; + +static struct i915_mmu_notifier * +__i915_mmu_notifier_lookup(struct drm_device *dev, struct mm_struct *mm) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + struct i915_mmu_notifier *mmu; + + /* Protected by dev->struct_mutex */ + hash_for_each_possible(dev_priv->mmu_notifiers, mmu, node, (unsigned long)mm) + if (mmu->mm == mm) + return mmu; + + return NULL; +} + +static struct i915_mmu_notifier * +i915_mmu_notifier_get(struct drm_device *dev, struct mm_struct *mm) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + struct i915_mmu_notifier *mmu; + int ret; + + lockdep_assert_held(&dev->struct_mutex); + + mmu = __i915_mmu_notifier_lookup(dev, mm); + if (mmu) + return mmu; + + mmu = kmalloc(sizeof(*mmu), GFP_KERNEL); + if (mmu == NULL) + return ERR_PTR(-ENOMEM); + + spin_lock_init(&mmu->lock); + mmu->dev = dev; + mmu->mn.ops = &i915_gem_userptr_notifier; + mmu->mm = mm; + mmu->objects = RB_ROOT; + mmu->count = 0; + mmu->serial = 0; + + /* Protected by mmap_sem (write-lock) */ + ret = __mmu_notifier_register(&mmu->mn, mm); + if (ret) { + kfree(mmu); + return ERR_PTR(ret); + } + + /* Protected by dev->struct_mutex */ + hash_add(dev_priv->mmu_notifiers, &mmu->node, (unsigned long)mm); + return mmu; +} + +static void +__i915_mmu_notifier_destroy_worker(struct work_struct *work) +{ + struct i915_mmu_notifier *mmu = container_of(work, typeof(*mmu), work); + mmu_notifier_unregister(&mmu->mn, mmu->mm); + kfree(mmu); +} + +static void +__i915_mmu_notifier_destroy(struct i915_mmu_notifier *mmu) +{ + lockdep_assert_held(&mmu->dev->struct_mutex); + + /* Protected by dev->struct_mutex */ + hash_del(&mmu->node); + + /* Our lock ordering is: mmap_sem, mmu_notifier_scru, struct_mutex. + * We enter the function holding struct_mutex, therefore we need + * to drop our mutex prior to calling mmu_notifier_unregister in + * order to prevent lock inversion (and system-wide deadlock) + * between the mmap_sem and struct-mutex. Hence we defer the + * unregistration to a workqueue where we hold no locks. + */ + INIT_WORK(&mmu->work, __i915_mmu_notifier_destroy_worker); + schedule_work(&mmu->work); +} + +static void __i915_mmu_notifier_update_serial(struct i915_mmu_notifier *mmu) +{ + if (++mmu->serial == 0) + mmu->serial = 1; +} + +static void +i915_mmu_notifier_del(struct i915_mmu_notifier *mmu, + struct i915_mmu_object *mn) +{ + lockdep_assert_held(&mmu->dev->struct_mutex); + + spin_lock(&mmu->lock); + interval_tree_remove(&mn->it, &mmu->objects); + __i915_mmu_notifier_update_serial(mmu); + spin_unlock(&mmu->lock); + + /* Protected against _add() by dev->struct_mutex */ + if (--mmu->count == 0) + __i915_mmu_notifier_destroy(mmu); +} + +static int +i915_mmu_notifier_add(struct i915_mmu_notifier *mmu, + struct i915_mmu_object *mn) +{ + struct interval_tree_node *it; + int ret; + + ret = i915_mutex_lock_interruptible(mmu->dev); + if (ret) + return ret; + + /* Make sure we drop the final active reference (and thereby + * remove the objects from the interval tree) before we do + * the check for overlapping objects. + */ + i915_gem_retire_requests(mmu->dev); + + /* Disallow overlapping userptr objects */ + spin_lock(&mmu->lock); + it = interval_tree_iter_first(&mmu->objects, + mn->it.start, mn->it.last); + if (it) { + struct drm_i915_gem_object *obj; + + /* We only need to check the first object in the range as it + * either has cancelled gup work queued and we need to + * return back to the user to give time for the gup-workers + * to flush their object references upon which the object will + * be removed from the interval-tree, or the the range is + * still in use by another client and the overlap is invalid. + */ + + obj = container_of(it, struct i915_mmu_object, it)->obj; + ret = obj->userptr.workers ? -EAGAIN : -EINVAL; + } else { + interval_tree_insert(&mn->it, &mmu->objects); + __i915_mmu_notifier_update_serial(mmu); + ret = 0; + } + spin_unlock(&mmu->lock); + mutex_unlock(&mmu->dev->struct_mutex); + + return ret; +} + +static void +i915_gem_userptr_release__mmu_notifier(struct drm_i915_gem_object *obj) +{ + struct i915_mmu_object *mn; + + mn = obj->userptr.mn; + if (mn == NULL) + return; + + i915_mmu_notifier_del(mn->mmu, mn); + obj->userptr.mn = NULL; +} + +static int +i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj, + unsigned flags) +{ + struct i915_mmu_notifier *mmu; + struct i915_mmu_object *mn; + int ret; + + if (flags & I915_USERPTR_UNSYNCHRONIZED) + return capable(CAP_SYS_ADMIN) ? 0 : -EPERM; + + down_write(&obj->userptr.mm->mmap_sem); + ret = i915_mutex_lock_interruptible(obj->base.dev); + if (ret == 0) { + mmu = i915_mmu_notifier_get(obj->base.dev, obj->userptr.mm); + if (!IS_ERR(mmu)) + mmu->count++; /* preemptive add to act as a refcount */ + else + ret = PTR_ERR(mmu); + mutex_unlock(&obj->base.dev->struct_mutex); + } + up_write(&obj->userptr.mm->mmap_sem); + if (ret) + return ret; + + mn = kzalloc(sizeof(*mn), GFP_KERNEL); + if (mn == NULL) { + ret = -ENOMEM; + goto destroy_mmu; + } + + mn->mmu = mmu; + mn->it.start = obj->userptr.ptr; + mn->it.last = mn->it.start + obj->base.size - 1; + mn->obj = obj; + + ret = i915_mmu_notifier_add(mmu, mn); + if (ret) + goto free_mn; + + obj->userptr.mn = mn; + return 0; + +free_mn: + kfree(mn); +destroy_mmu: + mutex_lock(&obj->base.dev->struct_mutex); + if (--mmu->count == 0) + __i915_mmu_notifier_destroy(mmu); + mutex_unlock(&obj->base.dev->struct_mutex); + return ret; +} + +#else + +static void +i915_gem_userptr_release__mmu_notifier(struct drm_i915_gem_object *obj) +{ +} + +static int +i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj, + unsigned flags) +{ + if ((flags & I915_USERPTR_UNSYNCHRONIZED) == 0) + return -ENODEV; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + return 0; +} +#endif + +struct get_pages_work { + struct work_struct work; + struct drm_i915_gem_object *obj; + struct task_struct *task; +}; + + +#if IS_ENABLED(CONFIG_SWIOTLB) +#define swiotlb_active() swiotlb_nr_tbl() +#else +#define swiotlb_active() 0 +#endif + +static int +st_set_pages(struct sg_table **st, struct page **pvec, int num_pages) +{ + struct scatterlist *sg; + int ret, n; + + *st = kmalloc(sizeof(**st), GFP_KERNEL); + if (*st == NULL) + return -ENOMEM; + + if (swiotlb_active()) { + ret = sg_alloc_table(*st, num_pages, GFP_KERNEL); + if (ret) + goto err; + + for_each_sg((*st)->sgl, sg, num_pages, n) + sg_set_page(sg, pvec[n], PAGE_SIZE, 0); + } else { + ret = sg_alloc_table_from_pages(*st, pvec, num_pages, + 0, num_pages << PAGE_SHIFT, + GFP_KERNEL); + if (ret) + goto err; + } + + return 0; + +err: + kfree(*st); + *st = NULL; + return ret; +} + +static void +__i915_gem_userptr_get_pages_worker(struct work_struct *_work) +{ + struct get_pages_work *work = container_of(_work, typeof(*work), work); + struct drm_i915_gem_object *obj = work->obj; + struct drm_device *dev = obj->base.dev; + const int num_pages = obj->base.size >> PAGE_SHIFT; + struct page **pvec; + int pinned, ret; + + ret = -ENOMEM; + pinned = 0; + + pvec = kmalloc(num_pages*sizeof(struct page *), + GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); + if (pvec == NULL) + pvec = drm_malloc_ab(num_pages, sizeof(struct page *)); + if (pvec != NULL) { + struct mm_struct *mm = obj->userptr.mm; + + down_read(&mm->mmap_sem); + while (pinned < num_pages) { + ret = get_user_pages(work->task, mm, + obj->userptr.ptr + pinned * PAGE_SIZE, + num_pages - pinned, + !obj->userptr.read_only, 0, + pvec + pinned, NULL); + if (ret < 0) + break; + + pinned += ret; + } + up_read(&mm->mmap_sem); + } + + mutex_lock(&dev->struct_mutex); + if (obj->userptr.work != &work->work) { + ret = 0; + } else if (pinned == num_pages) { + ret = st_set_pages(&obj->pages, pvec, num_pages); + if (ret == 0) { + list_add_tail(&obj->global_list, &to_i915(dev)->mm.unbound_list); + pinned = 0; + } + } + + obj->userptr.work = ERR_PTR(ret); + obj->userptr.workers--; + drm_gem_object_unreference(&obj->base); + mutex_unlock(&dev->struct_mutex); + + release_pages(pvec, pinned, 0); + drm_free_large(pvec); + + put_task_struct(work->task); + kfree(work); +} + +static int +i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) +{ + const int num_pages = obj->base.size >> PAGE_SHIFT; + struct page **pvec; + int pinned, ret; + + /* If userspace should engineer that these pages are replaced in + * the vma between us binding this page into the GTT and completion + * of rendering... Their loss. If they change the mapping of their + * pages they need to create a new bo to point to the new vma. + * + * However, that still leaves open the possibility of the vma + * being copied upon fork. Which falls under the same userspace + * synchronisation issue as a regular bo, except that this time + * the process may not be expecting that a particular piece of + * memory is tied to the GPU. + * + * Fortunately, we can hook into the mmu_notifier in order to + * discard the page references prior to anything nasty happening + * to the vma (discard or cloning) which should prevent the more + * egregious cases from causing harm. + */ + + pvec = NULL; + pinned = 0; + if (obj->userptr.mm == current->mm) { + pvec = kmalloc(num_pages*sizeof(struct page *), + GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); + if (pvec == NULL) { + pvec = drm_malloc_ab(num_pages, sizeof(struct page *)); + if (pvec == NULL) + return -ENOMEM; + } + + pinned = __get_user_pages_fast(obj->userptr.ptr, num_pages, + !obj->userptr.read_only, pvec); + } + if (pinned < num_pages) { + if (pinned < 0) { + ret = pinned; + pinned = 0; + } else { + /* Spawn a worker so that we can acquire the + * user pages without holding our mutex. Access + * to the user pages requires mmap_sem, and we have + * a strict lock ordering of mmap_sem, struct_mutex - + * we already hold struct_mutex here and so cannot + * call gup without encountering a lock inversion. + * + * Userspace will keep on repeating the operation + * (thanks to EAGAIN) until either we hit the fast + * path or the worker completes. If the worker is + * cancelled or superseded, the task is still run + * but the results ignored. (This leads to + * complications that we may have a stray object + * refcount that we need to be wary of when + * checking for existing objects during creation.) + * If the worker encounters an error, it reports + * that error back to this function through + * obj->userptr.work = ERR_PTR. + */ + ret = -EAGAIN; + if (obj->userptr.work == NULL && + obj->userptr.workers < I915_GEM_USERPTR_MAX_WORKERS) { + struct get_pages_work *work; + + work = kmalloc(sizeof(*work), GFP_KERNEL); + if (work != NULL) { + obj->userptr.work = &work->work; + obj->userptr.workers++; + + work->obj = obj; + drm_gem_object_reference(&obj->base); + + work->task = current; + get_task_struct(work->task); + + INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker); + schedule_work(&work->work); + } else + ret = -ENOMEM; + } else { + if (IS_ERR(obj->userptr.work)) { + ret = PTR_ERR(obj->userptr.work); + obj->userptr.work = NULL; + } + } + } + } else { + ret = st_set_pages(&obj->pages, pvec, num_pages); + if (ret == 0) { + obj->userptr.work = NULL; + pinned = 0; + } + } + + release_pages(pvec, pinned, 0); + drm_free_large(pvec); + return ret; +} + +static void +i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj) +{ + struct scatterlist *sg; + int i; + + BUG_ON(obj->userptr.work != NULL); + + if (obj->madv != I915_MADV_WILLNEED) + obj->dirty = 0; + + for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) { + struct page *page = sg_page(sg); + + if (obj->dirty) + set_page_dirty(page); + + mark_page_accessed(page); + page_cache_release(page); + } + obj->dirty = 0; + + sg_free_table(obj->pages); + kfree(obj->pages); +} + +static void +i915_gem_userptr_release(struct drm_i915_gem_object *obj) +{ + i915_gem_userptr_release__mmu_notifier(obj); + + if (obj->userptr.mm) { + mmput(obj->userptr.mm); + obj->userptr.mm = NULL; + } +} + +static int +i915_gem_userptr_dmabuf_export(struct drm_i915_gem_object *obj) +{ + if (obj->userptr.mn) + return 0; + + return i915_gem_userptr_init__mmu_notifier(obj, 0); +} + +static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = { + .dmabuf_export = i915_gem_userptr_dmabuf_export, + .get_pages = i915_gem_userptr_get_pages, + .put_pages = i915_gem_userptr_put_pages, + .release = i915_gem_userptr_release, +}; + +/** + * Creates a new mm object that wraps some normal memory from the process + * context - user memory. + * + * We impose several restrictions upon the memory being mapped + * into the GPU. + * 1. It must be page aligned (both start/end addresses, i.e ptr and size). + * 2. It cannot overlap any other userptr object in the same address space. + * 3. It must be normal system memory, not a pointer into another map of IO + * space (e.g. it must not be a GTT mmapping of another object). + * 4. We only allow a bo as large as we could in theory map into the GTT, + * that is we limit the size to the total size of the GTT. + * 5. The bo is marked as being snoopable. The backing pages are left + * accessible directly by the CPU, but reads and writes by the GPU may + * incur the cost of a snoop (unless you have an LLC architecture). + * + * Synchronisation between multiple users and the GPU is left to userspace + * through the normal set-domain-ioctl. The kernel will enforce that the + * GPU relinquishes the VMA before it is returned back to the system + * i.e. upon free(), munmap() or process termination. However, the userspace + * malloc() library may not immediately relinquish the VMA after free() and + * instead reuse it whilst the GPU is still reading and writing to the VMA. + * Caveat emptor. + * + * Also note, that the object created here is not currently a "first class" + * object, in that several ioctls are banned. These are the CPU access + * ioctls: mmap(), pwrite and pread. In practice, you are expected to use + * direct access via your pointer rather than use those ioctls. + * + * If you think this is a good interface to use to pass GPU memory between + * drivers, please use dma-buf instead. In fact, wherever possible use + * dma-buf instead. + */ +int +i915_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_userptr *args = data; + struct drm_i915_gem_object *obj; + int ret; + u32 handle; + + if (args->flags & ~(I915_USERPTR_READ_ONLY | + I915_USERPTR_UNSYNCHRONIZED)) + return -EINVAL; + + if (offset_in_page(args->user_ptr | args->user_size)) + return -EINVAL; + + if (args->user_size > dev_priv->gtt.base.total) + return -E2BIG; + + if (!access_ok(args->flags & I915_USERPTR_READ_ONLY ? VERIFY_READ : VERIFY_WRITE, + (char __user *)(unsigned long)args->user_ptr, args->user_size)) + return -EFAULT; + + if (args->flags & I915_USERPTR_READ_ONLY) { + /* On almost all of the current hw, we cannot tell the GPU that a + * page is readonly, so this is just a placeholder in the uAPI. + */ + return -ENODEV; + } + + /* Allocate the new object */ + obj = i915_gem_object_alloc(dev); + if (obj == NULL) + return -ENOMEM; + + drm_gem_private_object_init(dev, &obj->base, args->user_size); + i915_gem_object_init(obj, &i915_gem_userptr_ops); + obj->cache_level = I915_CACHE_LLC; + obj->base.write_domain = I915_GEM_DOMAIN_CPU; + obj->base.read_domains = I915_GEM_DOMAIN_CPU; + + obj->userptr.ptr = args->user_ptr; + obj->userptr.read_only = !!(args->flags & I915_USERPTR_READ_ONLY); + + /* And keep a pointer to the current->mm for resolving the user pages + * at binding. This means that we need to hook into the mmu_notifier + * in order to detect if the mmu is destroyed. + */ + ret = -ENOMEM; + if ((obj->userptr.mm = get_task_mm(current))) + ret = i915_gem_userptr_init__mmu_notifier(obj, args->flags); + if (ret == 0) + ret = drm_gem_handle_create(file, &obj->base, &handle); + + /* drop reference from allocate - handle holds it now */ + drm_gem_object_unreference_unlocked(&obj->base); + if (ret) + return ret; + + args->handle = handle; + return 0; +} + +int +i915_gem_init_userptr(struct drm_device *dev) +{ +#if defined(CONFIG_MMU_NOTIFIER) + struct drm_i915_private *dev_priv = to_i915(dev); + hash_init(dev_priv->mmu_notifiers); +#endif + return 0; +} diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 2d819858c19b..dcbec692f60f 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -205,6 +205,7 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m, err_puts(m, tiling_flag(err->tiling)); err_puts(m, dirty_flag(err->dirty)); err_puts(m, purgeable_flag(err->purgeable)); + err_puts(m, err->userptr ? " userptr" : ""); err_puts(m, err->ring != -1 ? " " : ""); err_puts(m, ring_str(err->ring)); err_puts(m, i915_cache_level_str(err->cache_level)); @@ -641,6 +642,7 @@ static void capture_bo(struct drm_i915_error_buffer *err, err->tiling = obj->tiling_mode; err->dirty = obj->dirty; err->purgeable = obj->madv != I915_MADV_WILLNEED; + err->userptr = obj->userptr.mm != NULL; err->ring = obj->ring ? obj->ring->id : -1; err->cache_level = obj->cache_level; } diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 8a3e4ef00c3d..ff57f07c3249 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -223,6 +223,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_GEM_GET_CACHING 0x30 #define DRM_I915_REG_READ 0x31 #define DRM_I915_GET_RESET_STATS 0x32 +#define DRM_I915_GEM_USERPTR 0x33 #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -273,6 +274,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy) #define DRM_IOCTL_I915_REG_READ DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read) #define DRM_IOCTL_I915_GET_RESET_STATS DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GET_RESET_STATS, struct drm_i915_reset_stats) +#define DRM_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_USERPTR, struct drm_i915_gem_userptr) /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. @@ -1050,4 +1052,18 @@ struct drm_i915_reset_stats { __u32 pad; }; +struct drm_i915_gem_userptr { + __u64 user_ptr; + __u64 user_size; + __u32 flags; +#define I915_USERPTR_READ_ONLY 0x1 +#define I915_USERPTR_UNSYNCHRONIZED 0x80000000 + /** + * Returned handle for the object. + * + * Object handles are nonzero. + */ + __u32 handle; +}; + #endif /* _UAPI_I915_DRM_H_ */ -- cgit v1.3-18-gd494 From e69595c2501094d85d5bbca87592acb8a481109a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 19 Feb 2014 19:36:08 +0200 Subject: drm: Make the vblank disable timer per-crtc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently there's one per-device vblank disable timer, and it gets reset wheneven the vblank refcount for any crtc drops to zero. That means that one crtc could accidentally be keeping the vblank interrupts for other crtcs enabled even if there are no users for them. Make the disable timer per-crtc to avoid this issue. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 40 +++++++++++++++++++++------------------- include/drm/drmP.h | 4 +++- 2 files changed, 24 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index ea20c4aa1b6b..90c59a8c820f 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -140,33 +140,34 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) static void vblank_disable_fn(unsigned long arg) { - struct drm_device *dev = (struct drm_device *)arg; + struct drm_vblank_crtc *vblank = (void *)arg; + struct drm_device *dev = vblank->dev; unsigned long irqflags; - int i; + int crtc = vblank->crtc; if (!dev->vblank_disable_allowed) return; - for (i = 0; i < dev->num_crtcs; i++) { - spin_lock_irqsave(&dev->vbl_lock, irqflags); - if (atomic_read(&dev->vblank[i].refcount) == 0 && - dev->vblank[i].enabled) { - DRM_DEBUG("disabling vblank on crtc %d\n", i); - vblank_disable_and_save(dev, i); - } - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + spin_lock_irqsave(&dev->vbl_lock, irqflags); + if (atomic_read(&vblank->refcount) == 0 && vblank->enabled) { + DRM_DEBUG("disabling vblank on crtc %d\n", crtc); + vblank_disable_and_save(dev, crtc); } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } void drm_vblank_cleanup(struct drm_device *dev) { + int crtc; + /* Bail if the driver didn't call drm_vblank_init() */ if (dev->num_crtcs == 0) return; - del_timer_sync(&dev->vblank_disable_timer); - - vblank_disable_fn((unsigned long)dev); + for (crtc = 0; crtc < dev->num_crtcs; crtc++) { + del_timer_sync(&dev->vblank[crtc].disable_timer); + vblank_disable_fn((unsigned long)&dev->vblank[crtc]); + } kfree(dev->vblank); @@ -178,8 +179,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) { int i, ret = -ENOMEM; - setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, - (unsigned long)dev); spin_lock_init(&dev->vbl_lock); spin_lock_init(&dev->vblank_time_lock); @@ -189,8 +188,13 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vblank) goto err; - for (i = 0; i < num_crtcs; i++) + for (i = 0; i < num_crtcs; i++) { + dev->vblank[i].dev = dev; + dev->vblank[i].crtc = i; init_waitqueue_head(&dev->vblank[i].queue); + setup_timer(&dev->vblank[i].disable_timer, vblank_disable_fn, + (unsigned long)&dev->vblank[i]); + } DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n"); @@ -900,7 +904,7 @@ void drm_vblank_put(struct drm_device *dev, int crtc) /* Last user schedules interrupt disable */ if (atomic_dec_and_test(&dev->vblank[crtc].refcount) && (drm_vblank_offdelay > 0)) - mod_timer(&dev->vblank_disable_timer, + mod_timer(&dev->vblank[crtc].disable_timer, jiffies + ((drm_vblank_offdelay * HZ)/1000)); } EXPORT_SYMBOL(drm_vblank_put); @@ -909,8 +913,6 @@ EXPORT_SYMBOL(drm_vblank_put); * drm_vblank_off - disable vblank events on a CRTC * @dev: DRM device * @crtc: CRTC in question - * - * Caller must hold event lock. */ void drm_vblank_off(struct drm_device *dev, int crtc) { diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 12f10bc2395f..9d982d483f12 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1024,14 +1024,17 @@ struct drm_pending_vblank_event { }; struct drm_vblank_crtc { + struct drm_device *dev; /* pointer to the drm_device */ wait_queue_head_t queue; /**< VBLANK wait queue */ struct timeval time[DRM_VBLANKTIME_RBSIZE]; /**< timestamp of current count */ + struct timer_list disable_timer; /* delayed disable timer */ atomic_t count; /**< number of VBLANK interrupts */ atomic_t refcount; /* number of users of vblank interruptsper crtc */ u32 last; /* protected by dev->vbl_lock, used */ /* for wraparound handling */ u32 last_wait; /* Last vblank seqno waited per CRTC */ unsigned int inmodeset; /* Display driver is setting mode */ + int crtc; /* crtc index */ bool enabled; /* so we don't call enable more than once per disable */ }; @@ -1119,7 +1122,6 @@ struct drm_device { spinlock_t vblank_time_lock; /**< Protects vblank count and time updates during vblank enable/disable */ spinlock_t vbl_lock; - struct timer_list vblank_disable_timer; u32 max_vblank_count; /**< size of vblank counter register */ -- cgit v1.3-18-gd494 From f2752282f7f7b566b07113dd5aa130725aa95ac4 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 19 Feb 2014 21:29:49 +0200 Subject: drm: Add drm_vblank_on() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_vblank_off() will turn off vblank interrupts, but as long as the refcount is elevated drm_vblank_get() will not re-enable them. This is a problem is someone is holding a vblank reference while a modeset is happening, and the driver requires vblank interrupt to work during that time. Add drm_vblank_on() as a counterpart to drm_vblank_off() which will re-enabled vblank interrupts if the refcount is already elevated. This will allow drivers to choose the specific places in the modeset sequence at which vblank interrupts get disabled and enabled. Testcase: igt/kms_flip/*-vs-suspend Signed-off-by: Ville Syrjälä [danvet: Add Testcase tag for the igt I've written.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 72 ++++++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_display.c | 8 ++++ include/drm/drmP.h | 1 + 3 files changed, 62 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 13d671ed3421..dd786d84daab 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -839,6 +839,41 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) smp_mb__after_atomic_inc(); } +/** + * drm_vblank_enable - enable the vblank interrupt on a CRTC + * @dev: DRM device + * @crtc: CRTC in question + */ +static int drm_vblank_enable(struct drm_device *dev, int crtc) +{ + int ret = 0; + + assert_spin_locked(&dev->vbl_lock); + + spin_lock(&dev->vblank_time_lock); + + if (!dev->vblank[crtc].enabled) { + /* Enable vblank irqs under vblank_time_lock protection. + * All vblank count & timestamp updates are held off + * until we are done reinitializing master counter and + * timestamps. Filtercode in drm_handle_vblank() will + * prevent double-accounting of same vblank interval. + */ + ret = dev->driver->enable_vblank(dev, crtc); + DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); + if (ret) + atomic_dec(&dev->vblank[crtc].refcount); + else { + dev->vblank[crtc].enabled = true; + drm_update_vblank_count(dev, crtc); + } + } + + spin_unlock(&dev->vblank_time_lock); + + return ret; +} + /** * drm_vblank_get - get a reference count on vblank events * @dev: DRM device @@ -858,25 +893,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc) spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) { - spin_lock(&dev->vblank_time_lock); - if (!dev->vblank[crtc].enabled) { - /* Enable vblank irqs under vblank_time_lock protection. - * All vblank count & timestamp updates are held off - * until we are done reinitializing master counter and - * timestamps. Filtercode in drm_handle_vblank() will - * prevent double-accounting of same vblank interval. - */ - ret = dev->driver->enable_vblank(dev, crtc); - DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", - crtc, ret); - if (ret) - atomic_dec(&dev->vblank[crtc].refcount); - else { - dev->vblank[crtc].enabled = true; - drm_update_vblank_count(dev, crtc); - } - } - spin_unlock(&dev->vblank_time_lock); + ret = drm_vblank_enable(dev, crtc); } else { if (!dev->vblank[crtc].enabled) { atomic_dec(&dev->vblank[crtc].refcount); @@ -945,6 +962,23 @@ void drm_vblank_off(struct drm_device *dev, int crtc) } EXPORT_SYMBOL(drm_vblank_off); +/** + * drm_vblank_on - enable vblank events on a CRTC + * @dev: DRM device + * @crtc: CRTC in question + */ +void drm_vblank_on(struct drm_device *dev, int crtc) +{ + unsigned long irqflags; + + spin_lock_irqsave(&dev->vbl_lock, irqflags); + /* re-enable interrupts if there's are users left */ + if (atomic_read(&dev->vblank[crtc].refcount) != 0) + WARN_ON(drm_vblank_enable(dev, crtc)); + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); +} +EXPORT_SYMBOL(drm_vblank_on); + /** * drm_vblank_pre_modeset - account for vblanks across mode sets * @dev: DRM device diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 72b5c34d8ce7..313f29d1aae2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3737,6 +3737,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) * happening. */ intel_wait_for_vblank(dev, intel_crtc->pipe); + + drm_vblank_on(dev, pipe); } /* IPS only exists on ULT machines and is tied to pipe A. */ @@ -3828,6 +3830,8 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) * to change the workaround. */ haswell_mode_set_planes_workaround(intel_crtc); ilk_crtc_enable_planes(crtc); + + drm_vblank_on(dev, pipe); } static void ironlake_pfit_disable(struct intel_crtc *crtc) @@ -4351,6 +4355,8 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); + + drm_vblank_on(dev, pipe); } static void i9xx_crtc_enable(struct drm_crtc *crtc) @@ -4398,6 +4404,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); + + drm_vblank_on(dev, pipe); } static void i9xx_pfit_disable(struct intel_crtc *crtc) diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 9d982d483f12..7339b2b00724 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1360,6 +1360,7 @@ extern bool drm_handle_vblank(struct drm_device *dev, int crtc); extern int drm_vblank_get(struct drm_device *dev, int crtc); extern void drm_vblank_put(struct drm_device *dev, int crtc); extern void drm_vblank_off(struct drm_device *dev, int crtc); +extern void drm_vblank_on(struct drm_device *dev, int crtc); extern void drm_vblank_cleanup(struct drm_device *dev); extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, struct timeval *tvblank, unsigned flags); -- cgit v1.3-18-gd494 From 89dd6a4b34c5a7658a4017c93b2fe66c964399d0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 15 May 2014 15:32:12 +0200 Subject: drm/irq: Add kms-native crtc interface functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to start somewhere ... With this the only places left in i915 where we use pipe integers is in the interrupt handling code. And there it actually makes some amount of sense. v2: - Polish kerneldoc a bit (Thierry). - Drop "dev" parameter since it's unecessary. - Split out i915 changes (Thierry). Cc: Thierry Reding Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++ include/drm/drmP.h | 5 +++ 2 files changed, 82 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index f3dafccca456..5ba9a614e7ad 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -916,6 +916,8 @@ static int drm_vblank_enable(struct drm_device *dev, int crtc) * Acquire a reference count on vblank events to avoid having them disabled * while in use. * + * This is the legacy version of drm_crtc_vblank_get(). + * * Returns: * Zero on success, nonzero on failure. */ @@ -940,6 +942,24 @@ int drm_vblank_get(struct drm_device *dev, int crtc) } EXPORT_SYMBOL(drm_vblank_get); +/** + * drm_crtc_vblank_get - get a reference count on vblank events + * @crtc: which CRTC to own + * + * Acquire a reference count on vblank events to avoid having them disabled + * while in use. + * + * This is the native kms version of drm_vblank_off(). + * + * Returns: + * Zero on success, nonzero on failure. + */ +int drm_crtc_vblank_get(struct drm_crtc *crtc) +{ + return drm_vblank_get(crtc->dev, drm_crtc_index(crtc)); +} +EXPORT_SYMBOL(drm_crtc_vblank_get); + /** * drm_vblank_put - give up ownership of vblank events * @dev: DRM device @@ -947,6 +967,8 @@ EXPORT_SYMBOL(drm_vblank_get); * * Release ownership of a given vblank counter, turning off interrupts * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. + * + * This is the legacy version of drm_crtc_vblank_put(). */ void drm_vblank_put(struct drm_device *dev, int crtc) { @@ -960,6 +982,21 @@ void drm_vblank_put(struct drm_device *dev, int crtc) } EXPORT_SYMBOL(drm_vblank_put); +/** + * drm_crtc_vblank_put - give up ownership of vblank events + * @crtc: which counter to give up + * + * Release ownership of a given vblank counter, turning off interrupts + * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. + * + * This is the native kms version of drm_vblank_put(). + */ +void drm_crtc_vblank_put(struct drm_crtc *crtc) +{ + drm_vblank_put(crtc->dev, drm_crtc_index(crtc)); +} +EXPORT_SYMBOL(drm_crtc_vblank_put); + /** * drm_vblank_off - disable vblank events on a CRTC * @dev: DRM device @@ -971,6 +1008,8 @@ EXPORT_SYMBOL(drm_vblank_put); * * Drivers must use this function when the hardware vblank counter can get * reset, e.g. when suspending. + * + * This is the legacy version of drm_crtc_vblank_off(). */ void drm_vblank_off(struct drm_device *dev, int crtc) { @@ -1003,6 +1042,25 @@ void drm_vblank_off(struct drm_device *dev, int crtc) } EXPORT_SYMBOL(drm_vblank_off); +/** + * drm_crtc_vblank_off - disable vblank events on a CRTC + * @crtc: CRTC in question + * + * Drivers can use this function to shut down the vblank interrupt handling when + * disabling a crtc. This function ensures that the latest vblank frame count is + * stored so that drm_vblank_on can restore it again. + * + * Drivers must use this function when the hardware vblank counter can get + * reset, e.g. when suspending. + * + * This is the native kms version of drm_vblank_off(). + */ +void drm_crtc_vblank_off(struct drm_crtc *crtc) +{ + drm_vblank_off(crtc->dev, drm_crtc_index(crtc)); +} +EXPORT_SYMBOL(drm_crtc_vblank_off); + /** * drm_vblank_on - enable vblank events on a CRTC * @dev: DRM device @@ -1012,6 +1070,8 @@ EXPORT_SYMBOL(drm_vblank_off); * drm_vblank_off() again. Note that calls to drm_vblank_on() and * drm_vblank_off() can be unbalanced and so can also be unconditionaly called * in driver load code to reflect the current hardware state of the crtc. + * + * This is the legacy version of drm_crtc_vblank_on(). */ void drm_vblank_on(struct drm_device *dev, int crtc) { @@ -1025,6 +1085,23 @@ void drm_vblank_on(struct drm_device *dev, int crtc) } EXPORT_SYMBOL(drm_vblank_on); +/** + * drm_crtc_vblank_on - enable vblank events on a CRTC + * @crtc: CRTC in question + * + * This functions restores the vblank interrupt state captured with + * drm_vblank_off() again. Note that calls to drm_vblank_on() and + * drm_vblank_off() can be unbalanced and so can also be unconditionaly called + * in driver load code to reflect the current hardware state of the crtc. + * + * This is the native kms version of drm_vblank_on(). + */ +void drm_crtc_vblank_on(struct drm_crtc *crtc) +{ + drm_vblank_on(crtc->dev, drm_crtc_index(crtc)); +} +EXPORT_SYMBOL(drm_crtc_vblank_on); + /** * drm_vblank_pre_modeset - account for vblanks across mode sets * @dev: DRM device diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 7339b2b00724..76ccaabd0418 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1359,9 +1359,14 @@ extern void drm_send_vblank_event(struct drm_device *dev, int crtc, extern bool drm_handle_vblank(struct drm_device *dev, int crtc); extern int drm_vblank_get(struct drm_device *dev, int crtc); extern void drm_vblank_put(struct drm_device *dev, int crtc); +extern int drm_crtc_vblank_get(struct drm_crtc *crtc); +extern void drm_crtc_vblank_put(struct drm_crtc *crtc); extern void drm_vblank_off(struct drm_device *dev, int crtc); extern void drm_vblank_on(struct drm_device *dev, int crtc); +extern void drm_crtc_vblank_off(struct drm_crtc *crtc); +extern void drm_crtc_vblank_on(struct drm_crtc *crtc); extern void drm_vblank_cleanup(struct drm_device *dev); + extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, struct timeval *tvblank, unsigned flags); extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, -- cgit v1.3-18-gd494 From 3c8a0922e0b774aa394a6925f11976ccfc852808 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 2 May 2014 11:05:21 +1000 Subject: drm/dp_helper: add defines for DP 1.2 and MST support. (v2) This just adds the defines from the DP 1.2 spec, which we will use later. fix some DP MST to 1.2 MST Signed-off-by: Dave Airlie Reviewed-by: Todd Previte Reviewed-by: Jingoo Han --- include/drm/drm_dp_helper.h | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'include') diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index cfcacec5b89d..c8857e6159a5 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -37,6 +37,7 @@ * eDP: Embedded DisplayPort version 1 * DPI: DisplayPort Interoperability Guideline v1.1a * 1.2: DisplayPort 1.2 + * MST: Multistream Transport - part of DP 1.2a * * 1.2 formally includes both eDP and DPI definitions. */ @@ -103,9 +104,14 @@ #define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */ /* Multiple stream transport */ +#define DP_FAUX_CAP 0x020 /* 1.2 */ +# define DP_FAUX_CAP_1 (1 << 0) + #define DP_MSTM_CAP 0x021 /* 1.2 */ # define DP_MST_CAP (1 << 0) +#define DP_GUID 0x030 /* 1.2 */ + #define DP_PSR_SUPPORT 0x070 /* XXX 1.2? */ # define DP_PSR_IS_SUPPORTED 1 #define DP_PSR_CAPS 0x071 /* XXX 1.2? */ @@ -221,6 +227,16 @@ # define DP_PSR_CRC_VERIFICATION (1 << 2) # define DP_PSR_FRAME_CAPTURE (1 << 3) +#define DP_ADAPTER_CTRL 0x1a0 +# define DP_ADAPTER_CTRL_FORCE_LOAD_SENSE (1 << 0) + +#define DP_BRANCH_DEVICE_CTRL 0x1a1 +# define DP_BRANCH_DEVICE_IRQ_HPD (1 << 0) + +#define DP_PAYLOAD_ALLOCATE_SET 0x1c0 +#define DP_PAYLOAD_ALLOCATE_START_TIME_SLOT 0x1c1 +#define DP_PAYLOAD_ALLOCATE_TIME_SLOT_COUNT 0x1c2 + #define DP_SINK_COUNT 0x200 /* prior to 1.2 bit 7 was reserved mbz */ # define DP_GET_SINK_COUNT(x) ((((x) & 0x80) >> 1) | ((x) & 0x3f)) @@ -230,6 +246,9 @@ # define DP_REMOTE_CONTROL_COMMAND_PENDING (1 << 0) # define DP_AUTOMATED_TEST_REQUEST (1 << 1) # define DP_CP_IRQ (1 << 2) +# define DP_MCCS_IRQ (1 << 3) +# define DP_DOWN_REP_MSG_RDY (1 << 4) /* 1.2 MST */ +# define DP_UP_REQ_MSG_RDY (1 << 5) /* 1.2 MST */ # define DP_SINK_SPECIFIC_IRQ (1 << 6) #define DP_LANE0_1_STATUS 0x202 @@ -294,6 +313,13 @@ #define DP_TEST_SINK 0x270 #define DP_TEST_SINK_START (1 << 0) +#define DP_PAYLOAD_TABLE_UPDATE_STATUS 0x2c0 /* 1.2 MST */ +# define DP_PAYLOAD_TABLE_UPDATED (1 << 0) +# define DP_PAYLOAD_ACT_HANDLED (1 << 1) + +#define DP_VC_PAYLOAD_ID_SLOT_1 0x2c1 /* 1.2 MST */ +/* up to ID_SLOT_63 at 0x2ff */ + #define DP_SOURCE_OUI 0x300 #define DP_SINK_OUI 0x400 #define DP_BRANCH_OUI 0x500 @@ -303,6 +329,21 @@ # define DP_SET_POWER_D3 0x2 # define DP_SET_POWER_MASK 0x3 +#define DP_SIDEBAND_MSG_DOWN_REQ_BASE 0x1000 /* 1.2 MST */ +#define DP_SIDEBAND_MSG_UP_REP_BASE 0x1200 /* 1.2 MST */ +#define DP_SIDEBAND_MSG_DOWN_REP_BASE 0x1400 /* 1.2 MST */ +#define DP_SIDEBAND_MSG_UP_REQ_BASE 0x1600 /* 1.2 MST */ + +#define DP_SINK_COUNT_ESI 0x2002 /* 1.2 */ +/* 0-5 sink count */ +# define DP_SINK_COUNT_CP_READY (1 << 6) + +#define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 0x2003 /* 1.2 */ + +#define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 0x2004 /* 1.2 */ + +#define DP_LINK_SERVICE_IRQ_VECTOR_ESI0 0x2005 /* 1.2 */ + #define DP_PSR_ERROR_STATUS 0x2006 /* XXX 1.2? */ # define DP_PSR_LINK_CRC_ERROR (1 << 0) # define DP_PSR_RFB_STORAGE_ERROR (1 << 1) @@ -319,6 +360,43 @@ # define DP_PSR_SINK_INTERNAL_ERROR 7 # define DP_PSR_SINK_STATE_MASK 0x07 +/* DP 1.2 Sideband message defines */ +/* peer device type - DP 1.2a Table 2-92 */ +#define DP_PEER_DEVICE_NONE 0x0 +#define DP_PEER_DEVICE_SOURCE_OR_SST 0x1 +#define DP_PEER_DEVICE_MST_BRANCHING 0x2 +#define DP_PEER_DEVICE_SST_SINK 0x3 +#define DP_PEER_DEVICE_DP_LEGACY_CONV 0x4 + +/* DP 1.2 MST sideband request names DP 1.2a Table 2-80 */ +#define DP_LINK_ADDRESS 0x01 +#define DP_CONNECTION_STATUS_NOTIFY 0x02 +#define DP_ENUM_PATH_RESOURCES 0x10 +#define DP_ALLOCATE_PAYLOAD 0x11 +#define DP_QUERY_PAYLOAD 0x12 +#define DP_RESOURCE_STATUS_NOTIFY 0x13 +#define DP_CLEAR_PAYLOAD_ID_TABLE 0x14 +#define DP_REMOTE_DPCD_READ 0x20 +#define DP_REMOTE_DPCD_WRITE 0x21 +#define DP_REMOTE_I2C_READ 0x22 +#define DP_REMOTE_I2C_WRITE 0x23 +#define DP_POWER_UP_PHY 0x24 +#define DP_POWER_DOWN_PHY 0x25 +#define DP_SINK_EVENT_NOTIFY 0x30 +#define DP_QUERY_STREAM_ENC_STATUS 0x38 + +/* DP 1.2 MST sideband nak reasons - table 2.84 */ +#define DP_NAK_WRITE_FAILURE 0x01 +#define DP_NAK_INVALID_READ 0x02 +#define DP_NAK_CRC_FAILURE 0x03 +#define DP_NAK_BAD_PARAM 0x04 +#define DP_NAK_DEFER 0x05 +#define DP_NAK_LINK_FAILURE 0x06 +#define DP_NAK_NO_RESOURCES 0x07 +#define DP_NAK_DPCD_FAIL 0x08 +#define DP_NAK_I2C_NAK 0x09 +#define DP_NAK_ALLOCATE_FAIL 0x0a + #define MODE_I2C_START 1 #define MODE_I2C_WRITE 2 #define MODE_I2C_READ 4 -- cgit v1.3-18-gd494 From 59201052dff17d0cc8bc60bc9e89ad4924906ee8 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 23 May 2014 12:58:06 +0900 Subject: drm/ttm: fix kerneldoc of ttm_bo_create The kerneldoc header of ttm_bo_create() was referring to another (nonexisting) function and had a few obsolete or incorrect arguments. Signed-off-by: Alexandre Courbot Reviewed-by: David Herrmann Signed-off-by: Dave Airlie --- include/drm/ttm/ttm_bo_api.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index ee127ec33c60..7526c5bf5610 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -485,13 +485,12 @@ extern int ttm_bo_init(struct ttm_bo_device *bdev, void (*destroy) (struct ttm_buffer_object *)); /** - * ttm_bo_synccpu_object_init + * ttm_bo_create * * @bdev: Pointer to a ttm_bo_device struct. - * @bo: Pointer to a ttm_buffer_object to be initialized. * @size: Requested size of buffer object. * @type: Requested type of buffer object. - * @flags: Initial placement flags. + * @placement: Initial placement. * @page_alignment: Data alignment in pages. * @interruptible: If needing to sleep while waiting for GPU resources, * sleep interruptible. -- cgit v1.3-18-gd494 From b8380580836bf81d032da6099879da9f6b515325 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 23 Apr 2014 15:49:04 +0200 Subject: drm/dp: Add missing kernel-doc Commit 9dc4056026e0 (drm/dp: let drivers specify the name of the I2C- over-AUX adapter) introduced a new field but didn't add the proper kernel-doc for it. Signed-off-by: Thierry Reding Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie --- include/drm/drm_dp_helper.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index c8857e6159a5..efcde2c38cc1 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -509,6 +509,7 @@ struct drm_dp_aux_msg { /** * struct drm_dp_aux - DisplayPort AUX channel + * @name: user-visible name of this AUX channel and the I2C-over-AUX adapter * @ddc: I2C adapter that can be used for I2C-over-AUX communication * @dev: pointer to struct device that is the parent for this AUX channel * @transfer: transfers a message representing a single AUX transaction -- cgit v1.3-18-gd494 From 2abdd3137e78adca69b0722307aa2ef89f2cf3b6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 14 May 2014 16:58:19 +0300 Subject: drm: store connector name in connector struct (v2) This makes drm_get_connector_name() thread safe. [airlied: fix to build.] Reference: http://lkml.kernel.org/r/645ee6e22cad47d38a2b35c21c8d5fe3@DC1-MBX-01.ptsecurity.ru Signed-off-by: Jani Nikula Reviewed-by: David Herrmann Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 36 ++++++++++++++++++++---------------- include/drm/drm_crtc.h | 2 ++ 2 files changed, 22 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 34f0bf18d80d..293eb4c24f35 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -277,21 +277,11 @@ EXPORT_SYMBOL(drm_get_encoder_name); /** * drm_get_connector_name - return a string for connector - * @connector: connector to compute name of - * - * Note that the buffer used by this function is globally shared and owned by - * the function itself. - * - * FIXME: This isn't really multithreading safe. + * @connector: the connector to get name for */ const char *drm_get_connector_name(const struct drm_connector *connector) { - static char buf[32]; - - snprintf(buf, 32, "%s-%d", - drm_connector_enum_list[connector->connector_type].name, - connector->connector_type_id); - return buf; + return connector->name; } EXPORT_SYMBOL(drm_get_connector_name); @@ -824,7 +814,7 @@ int drm_connector_init(struct drm_device *dev, ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR); if (ret) - goto out; + goto out_unlock; connector->base.properties = &connector->properties; connector->dev = dev; @@ -834,9 +824,17 @@ int drm_connector_init(struct drm_device *dev, ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); if (connector->connector_type_id < 0) { ret = connector->connector_type_id; - drm_mode_object_put(dev, &connector->base); - goto out; + goto out_put; } + connector->name = + kasprintf(GFP_KERNEL, "%s-%d", + drm_connector_enum_list[connector_type].name, + connector->connector_type_id); + if (!connector->name) { + ret = -ENOMEM; + goto out_put; + } + INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->modes); connector->edid_blob_ptr = NULL; @@ -853,7 +851,11 @@ int drm_connector_init(struct drm_device *dev, drm_object_attach_property(&connector->base, dev->mode_config.dpms_property, 0); - out: +out_put: + if (ret) + drm_mode_object_put(dev, &connector->base); + +out_unlock: drm_modeset_unlock_all(dev); return ret; @@ -881,6 +883,8 @@ void drm_connector_cleanup(struct drm_connector *connector) connector->connector_type_id); drm_mode_object_put(dev, &connector->base); + kfree(connector->name); + connector->name = NULL; list_del(&connector->head); dev->mode_config.num_connector--; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 698d54e27f39..b5c97d5b2654 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -444,6 +444,7 @@ struct drm_encoder { * @attr: sysfs attributes * @head: list management * @base: base KMS object + * @name: connector name * @connector_type: one of the %DRM_MODE_CONNECTOR_ types from drm_mode.h * @connector_type_id: index into connector type enum * @interlace_allowed: can this connector handle interlaced modes? @@ -482,6 +483,7 @@ struct drm_connector { struct drm_mode_object base; + char *name; int connector_type; int connector_type_id; bool interlace_allowed; -- cgit v1.3-18-gd494 From e5748946e907f767e7bb73e5ed31584981f0ff65 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 14 May 2014 16:58:20 +0300 Subject: drm: store encoder name in encoder struct This makes drm_get_encoder_name() thread safe. Reference: http://lkml.kernel.org/r/645ee6e22cad47d38a2b35c21c8d5fe3@DC1-MBX-01\ .ptsecurity.ru Signed-off-by: Jani Nikula Reviewed-by: David Herrmann Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 31 +++++++++++++++++-------------- include/drm/drm_crtc.h | 2 ++ 2 files changed, 19 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 293eb4c24f35..37a3e0791ddf 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -257,21 +257,11 @@ void drm_connector_ida_destroy(void) /** * drm_get_encoder_name - return a string for encoder - * @encoder: encoder to compute name of - * - * Note that the buffer used by this function is globally shared and owned by - * the function itself. - * - * FIXME: This isn't really multithreading safe. + * @encoder: the encoder to get name for */ const char *drm_get_encoder_name(const struct drm_encoder *encoder) { - static char buf[32]; - - snprintf(buf, 32, "%s-%d", - drm_encoder_enum_list[encoder->encoder_type].name, - encoder->base.id); - return buf; + return encoder->name; } EXPORT_SYMBOL(drm_get_encoder_name); @@ -986,16 +976,27 @@ int drm_encoder_init(struct drm_device *dev, ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); if (ret) - goto out; + goto out_unlock; encoder->dev = dev; encoder->encoder_type = encoder_type; encoder->funcs = funcs; + encoder->name = kasprintf(GFP_KERNEL, "%s-%d", + drm_encoder_enum_list[encoder_type].name, + encoder->base.id); + if (!encoder->name) { + ret = -ENOMEM; + goto out_put; + } list_add_tail(&encoder->head, &dev->mode_config.encoder_list); dev->mode_config.num_encoder++; - out: +out_put: + if (ret) + drm_mode_object_put(dev, &encoder->base); + +out_unlock: drm_modeset_unlock_all(dev); return ret; @@ -1013,6 +1014,8 @@ void drm_encoder_cleanup(struct drm_encoder *encoder) struct drm_device *dev = encoder->dev; drm_modeset_lock_all(dev); drm_mode_object_put(dev, &encoder->base); + kfree(encoder->name); + encoder->name = NULL; list_del(&encoder->head); dev->mode_config.num_encoder--; drm_modeset_unlock_all(dev); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index b5c97d5b2654..5c1c31cc11cd 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -400,6 +400,7 @@ struct drm_encoder_funcs { * @dev: parent DRM device * @head: list management * @base: base KMS object + * @name: encoder name * @encoder_type: one of the %DRM_MODE_ENCODER_ types in drm_mode.h * @possible_crtcs: bitmask of potential CRTC bindings * @possible_clones: bitmask of potential sibling encoders for cloning @@ -416,6 +417,7 @@ struct drm_encoder { struct list_head head; struct drm_mode_object base; + char *name; int encoder_type; uint32_t possible_crtcs; uint32_t possible_clones; -- cgit v1.3-18-gd494 From 182407a6ed5333fc37dd980a8de91a8f826a94f6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 2 May 2014 11:09:54 +1000 Subject: drm: add DP MST encoder type This adds an encoder type for DP MST encoders. Reviewed-by: Todd Previte Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 1 + include/uapi/drm/drm_mode.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 37a3e0791ddf..edee61bccd14 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -227,6 +227,7 @@ static const struct drm_prop_enum_list drm_encoder_enum_list[] = { DRM_MODE_ENCODER_TVDAC, "TV" }, { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, { DRM_MODE_ENCODER_DSI, "DSI" }, + { DRM_MODE_ENCODER_DPMST, "DP MST" }, }; static const struct drm_prop_enum_list drm_subpixel_enum_list[] = diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index f104c2603ebe..719add464f95 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -181,6 +181,7 @@ struct drm_mode_get_plane_res { #define DRM_MODE_ENCODER_TVDAC 4 #define DRM_MODE_ENCODER_VIRTUAL 5 #define DRM_MODE_ENCODER_DSI 6 +#define DRM_MODE_ENCODER_DPMST 7 struct drm_mode_get_encoder { __u32 encoder_id; -- cgit v1.3-18-gd494 From 073ea2ae85629d4074596e2616588b13d4c665f7 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 20:44:51 +0900 Subject: drm/exynos: dp: Use DPCD defines of drm_dp_helper.h Use DPCD defines of drm_dp_helper.h; thus, duplicated DPCD defines of exynos_dp_core.h can be removed. Also, DP_TEST_EDID_CHECKSUM define is added to drm_dp_helper.h. There is no functional change. Signed-off-by: Jingoo Han Reviewed-by: Sean Paul Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_dp_core.c | 98 ++++++++++++++++----------------- drivers/gpu/drm/exynos/exynos_dp_core.h | 59 ++------------------ include/drm/drm_dp_helper.h | 2 + 3 files changed, 55 insertions(+), 104 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 2b30c55ab050..ff63901e14c7 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -144,15 +144,15 @@ static int exynos_dp_read_edid(struct exynos_dp_device *dp) return -EIO; } - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST, + exynos_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, &test_vector); - if (test_vector & DPCD_TEST_EDID_READ) { + if (test_vector & DP_TEST_LINK_EDID_READ) { exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TEST_EDID_CHECKSUM, + DP_TEST_EDID_CHECKSUM, edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TEST_RESPONSE, - DPCD_TEST_EDID_CHECKSUM_WRITE); + DP_TEST_RESPONSE, + DP_TEST_EDID_CHECKSUM_WRITE); } } else { dev_info(dp->dev, "EDID data does not include any extensions.\n"); @@ -174,15 +174,15 @@ static int exynos_dp_read_edid(struct exynos_dp_device *dp) } exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_TEST_REQUEST, + DP_TEST_REQUEST, &test_vector); - if (test_vector & DPCD_TEST_EDID_READ) { + if (test_vector & DP_TEST_LINK_EDID_READ) { exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TEST_EDID_CHECKSUM, + DP_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TEST_RESPONSE, - DPCD_TEST_EDID_CHECKSUM_WRITE); + DP_TEST_RESPONSE, + DP_TEST_EDID_CHECKSUM_WRITE); } } @@ -196,8 +196,8 @@ static int exynos_dp_handle_edid(struct exynos_dp_device *dp) int i; int retval; - /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */ - retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV, + /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */ + retval = exynos_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, 12, buf); if (retval) return retval; @@ -217,14 +217,14 @@ static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp, { u8 data; - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data); + exynos_dp_read_byte_from_dpcd(dp, DP_LANE_COUNT_SET, &data); if (enable) - exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, - DPCD_ENHANCED_FRAME_EN | + exynos_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, + DP_LANE_COUNT_ENHANCED_FRAME_EN | DPCD_LANE_COUNT_SET(data)); else - exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, + exynos_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, DPCD_LANE_COUNT_SET(data)); } @@ -233,7 +233,7 @@ static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp) u8 data; int retval; - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data); + exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); retval = DPCD_ENHANCED_FRAME_CAP(data); return retval; @@ -253,8 +253,8 @@ static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp) exynos_dp_set_training_pattern(dp, DP_NONE); exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - DPCD_TRAINING_PATTERN_DISABLED); + DP_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_DISABLE); } static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp, @@ -298,7 +298,7 @@ static int exynos_dp_link_start(struct exynos_dp_device *dp) /* Setup RX configuration */ buf[0] = dp->link_train.link_rate; buf[1] = dp->link_train.lane_count; - retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET, + retval = exynos_dp_write_bytes_to_dpcd(dp, DP_LINK_BW_SET, 2, buf); if (retval) return retval; @@ -325,16 +325,16 @@ static int exynos_dp_link_start(struct exynos_dp_device *dp) /* Set RX training pattern */ retval = exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1); + DP_TRAINING_PATTERN_SET, + DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1); if (retval) return retval; for (lane = 0; lane < lane_count; lane++) - buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | - DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0; + buf[lane] = DP_TRAIN_PRE_EMPHASIS_0 | + DP_TRAIN_VOLTAGE_SWING_400; - retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, + retval = exynos_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, lane_count, buf); return retval; @@ -355,7 +355,7 @@ static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count) for (lane = 0; lane < lane_count; lane++) { lane_status = exynos_dp_get_lane_status(link_status, lane); - if ((lane_status & DPCD_LANE_CR_DONE) == 0) + if ((lane_status & DP_LANE_CR_DONE) == 0) return -EINVAL; } return 0; @@ -367,13 +367,13 @@ static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align, int lane; u8 lane_status; - if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0) + if ((link_align & DP_INTERLANE_ALIGN_DONE) == 0) return -EINVAL; for (lane = 0; lane < lane_count; lane++) { lane_status = exynos_dp_get_lane_status(link_status, lane); - lane_status &= DPCD_CHANNEL_EQ_BITS; - if (lane_status != DPCD_CHANNEL_EQ_BITS) + lane_status &= DP_CHANNEL_EQ_BITS; + if (lane_status != DP_CHANNEL_EQ_BITS) return -EINVAL; } @@ -471,9 +471,9 @@ static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp, DPCD_PRE_EMPHASIS_SET(pre_emphasis); if (voltage_swing == VOLTAGE_LEVEL_3) - training_lane |= DPCD_MAX_SWING_REACHED; + training_lane |= DP_TRAIN_MAX_SWING_REACHED; if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) - training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; + training_lane |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; dp->link_train.training_lane[lane] = training_lane; } @@ -490,12 +490,12 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) lane_count = dp->link_train.lane_count; retval = exynos_dp_read_bytes_from_dpcd(dp, - DPCD_ADDR_LANE0_1_STATUS, 2, link_status); + DP_LANE0_1_STATUS, 2, link_status); if (retval) return retval; retval = exynos_dp_read_bytes_from_dpcd(dp, - DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); + DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); if (retval) return retval; @@ -504,9 +504,9 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) exynos_dp_set_training_pattern(dp, TRAINING_PTN2); retval = exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - DPCD_SCRAMBLING_DISABLED | - DPCD_TRAINING_PATTERN_2); + DP_TRAINING_PATTERN_SET, + DP_LINK_SCRAMBLING_DISABLE | + DP_TRAINING_PATTERN_2); if (retval) return retval; @@ -546,7 +546,7 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) dp->link_train.training_lane[lane], lane); retval = exynos_dp_write_bytes_to_dpcd(dp, - DPCD_ADDR_TRAINING_LANE0_SET, lane_count, + DP_TRAINING_LANE0_SET, lane_count, dp->link_train.training_lane); if (retval) return retval; @@ -565,7 +565,7 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) lane_count = dp->link_train.lane_count; retval = exynos_dp_read_bytes_from_dpcd(dp, - DPCD_ADDR_LANE0_1_STATUS, 2, link_status); + DP_LANE0_1_STATUS, 2, link_status); if (retval) return retval; @@ -575,12 +575,12 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) } retval = exynos_dp_read_bytes_from_dpcd(dp, - DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); + DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); if (retval) return retval; retval = exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align); + DP_LANE_ALIGN_STATUS_UPDATED, &link_align); if (retval) return retval; @@ -622,7 +622,7 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) exynos_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); - retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, + retval = exynos_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, lane_count, dp->link_train.training_lane); return retval; @@ -637,7 +637,7 @@ static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, * For DP rev.1.1, Maximum link rate of Main Link lanes * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps */ - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data); + exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data); *bandwidth = data; } @@ -650,7 +650,7 @@ static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp, * For DP rev.1.1, Maximum number of Main Link lanes * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes */ - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data); + exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); *lane_count = DPCD_MAX_LANE_COUNT(data); } @@ -822,20 +822,20 @@ static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable) exynos_dp_enable_scrambling(dp); exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_SET, &data); exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - (u8)(data & ~DPCD_SCRAMBLING_DISABLED)); + DP_TRAINING_PATTERN_SET, + (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); } else { exynos_dp_disable_scrambling(dp); exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_SET, &data); exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - (u8)(data | DPCD_SCRAMBLING_DISABLED)); + DP_TRAINING_PATTERN_SET, + (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); } } diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h index 56fa43eb7133..02cc4f9ab903 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.h +++ b/drivers/gpu/drm/exynos/exynos_dp_core.h @@ -14,6 +14,7 @@ #define _EXYNOS_DP_CORE_H #include +#include #include #define DP_TIMEOUT_LOOP_COUNT 100 @@ -262,69 +263,17 @@ void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); #define EDID_EXTENSION_FLAG 0x7e #define EDID_CHECKSUM 0x7f -/* Definition for DPCD Register */ -#define DPCD_ADDR_DPCD_REV 0x0000 -#define DPCD_ADDR_MAX_LINK_RATE 0x0001 -#define DPCD_ADDR_MAX_LANE_COUNT 0x0002 -#define DPCD_ADDR_LINK_BW_SET 0x0100 -#define DPCD_ADDR_LANE_COUNT_SET 0x0101 -#define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102 -#define DPCD_ADDR_TRAINING_LANE0_SET 0x0103 -#define DPCD_ADDR_LANE0_1_STATUS 0x0202 -#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204 -#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206 -#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207 -#define DPCD_ADDR_TEST_REQUEST 0x0218 -#define DPCD_ADDR_TEST_RESPONSE 0x0260 -#define DPCD_ADDR_TEST_EDID_CHECKSUM 0x0261 -#define DPCD_ADDR_SINK_POWER_STATE 0x0600 - -/* DPCD_ADDR_MAX_LANE_COUNT */ +/* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) -/* DPCD_ADDR_LANE_COUNT_SET */ -#define DPCD_ENHANCED_FRAME_EN (0x1 << 7) +/* DP_LANE_COUNT_SET */ #define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f) -/* DPCD_ADDR_TRAINING_PATTERN_SET */ -#define DPCD_SCRAMBLING_DISABLED (0x1 << 5) -#define DPCD_SCRAMBLING_ENABLED (0x0 << 5) -#define DPCD_TRAINING_PATTERN_2 (0x2 << 0) -#define DPCD_TRAINING_PATTERN_1 (0x1 << 0) -#define DPCD_TRAINING_PATTERN_DISABLED (0x0 << 0) - -/* DPCD_ADDR_TRAINING_LANE0_SET */ -#define DPCD_MAX_PRE_EMPHASIS_REACHED (0x1 << 5) +/* DP_TRAINING_LANE0_SET */ #define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3) #define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3) -#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 (0x0 << 3) -#define DPCD_MAX_SWING_REACHED (0x1 << 2) #define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0) #define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3) -#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0 (0x0 << 0) - -/* DPCD_ADDR_LANE0_1_STATUS */ -#define DPCD_LANE_SYMBOL_LOCKED (0x1 << 2) -#define DPCD_LANE_CHANNEL_EQ_DONE (0x1 << 1) -#define DPCD_LANE_CR_DONE (0x1 << 0) -#define DPCD_CHANNEL_EQ_BITS (DPCD_LANE_CR_DONE| \ - DPCD_LANE_CHANNEL_EQ_DONE|\ - DPCD_LANE_SYMBOL_LOCKED) - -/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */ -#define DPCD_LINK_STATUS_UPDATED (0x1 << 7) -#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED (0x1 << 6) -#define DPCD_INTERLANE_ALIGN_DONE (0x1 << 0) - -/* DPCD_ADDR_TEST_REQUEST */ -#define DPCD_TEST_EDID_READ (0x1 << 2) - -/* DPCD_ADDR_TEST_RESPONSE */ -#define DPCD_TEST_EDID_CHECKSUM_WRITE (0x1 << 2) - -/* DPCD_ADDR_SINK_POWER_STATE */ -#define DPCD_SET_POWER_STATE_D0 (0x1 << 0) -#define DPCD_SET_POWER_STATE_D4 (0x2 << 0) #endif /* _EXYNOS_DP_CORE_H */ diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index efcde2c38cc1..488b41635dec 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -310,6 +310,8 @@ # define DP_TEST_NAK (1 << 1) # define DP_TEST_EDID_CHECKSUM_WRITE (1 << 2) +#define DP_TEST_EDID_CHECKSUM 0x261 + #define DP_TEST_SINK 0x270 #define DP_TEST_SINK_START (1 << 0) -- cgit v1.3-18-gd494 From f220e62659e968c3bbe4d96d73008832d19b9f77 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 13 May 2014 12:47:42 +0200 Subject: drm/plane: Fix sparse warnings Include the drm_plane_helper.h header file to fix the following sparse warnings: CHECK drivers/gpu/drm/drm_plane_helper.c drivers/gpu/drm/drm_plane_helper.c:102:5: warning: symbol 'drm_primary_helper_update' was not declared. Should it be static? drivers/gpu/drm/drm_plane_helper.c:219:5: warning: symbol 'drm_primary_helper_disable' was not declared. Should it be static? drivers/gpu/drm/drm_plane_helper.c:233:6: warning: symbol 'drm_primary_helper_destroy' was not declared. Should it be static? drivers/gpu/drm/drm_plane_helper.c:241:30: warning: symbol 'drm_primary_helper_funcs' was not declared. Should it be static? drivers/gpu/drm/drm_plane_helper.c:259:18: warning: symbol 'drm_primary_helper_create_plane' was not declared. Should it be static? Doing that makes gcc complain as follows: CC drivers/gpu/drm/drm_plane_helper.o drivers/gpu/drm/drm_plane_helper.c:260:19: error: conflicting types for 'drm_primary_helper_create_plane' struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, ^ In file included from drivers/gpu/drm/drm_plane_helper.c:29:0: include/drm/drm_plane_helper.h:42:19: note: previous declaration of 'drm_primary_helper_create_plane' was here struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, ^ drivers/gpu/drm/drm_plane_helper.c: In function 'drm_primary_helper_create_plane': drivers/gpu/drm/drm_plane_helper.c:274:11: warning: assignment discards 'const' qualifier from pointer target type formats = safe_modeset_formats; ^ In file included from include/linux/linkage.h:6:0, from include/linux/kernel.h:6, from include/drm/drmP.h:45, from drivers/gpu/drm/drm_plane_helper.c:27: drivers/gpu/drm/drm_plane_helper.c: At top level: drivers/gpu/drm/drm_plane_helper.c:289:15: error: conflicting types for 'drm_primary_helper_create_plane' EXPORT_SYMBOL(drm_primary_helper_create_plane); ^ include/linux/export.h:57:21: note: in definition of macro '__EXPORT_SYMBOL' extern typeof(sym) sym; \ ^ drivers/gpu/drm/drm_plane_helper.c:289:1: note: in expansion of macro 'EXPORT_SYMBOL' EXPORT_SYMBOL(drm_primary_helper_create_plane); ^ In file included from drivers/gpu/drm/drm_plane_helper.c:29:0: include/drm/drm_plane_helper.h:42:19: note: previous declaration of 'drm_primary_helper_create_plane' was here struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, ^ Which can easily be fixed by making the signatures of the implementation and the prototype match. Signed-off-by: Thierry Reding Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_plane_helper.c | 1 + include/drm/drm_plane_helper.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index d966afa7ecae..f16bb92db577 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -26,6 +26,7 @@ #include #include #include +#include #define SUBPIXEL_MASK 0xffff diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index 09824becee3e..c5e7ab9503c8 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -42,7 +42,7 @@ extern int drm_primary_helper_disable(struct drm_plane *plane); extern void drm_primary_helper_destroy(struct drm_plane *plane); extern const struct drm_plane_funcs drm_primary_helper_funcs; extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, - uint32_t *formats, + const uint32_t *formats, int num_formats); -- cgit v1.3-18-gd494 From d0c94692e0a360828745a469bcf90b5c4f9273d0 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Thu, 27 Mar 2014 19:59:39 +0100 Subject: drm/edid: Parse and handle HDMI deep color modes. Check the HDMI cea block for deep color mode bits. If available, assign the highest supported bpc for a hdmi display, corresponding to the given deep color modes. Signed-off-by: Mario Kleiner Signed-off-by: Alex Deucher --- drivers/gpu/drm/drm_edid.c | 110 ++++++++++++++++++++++++++++++++++++++++++++- include/drm/drm_edid.h | 5 +++ 2 files changed, 113 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index d74239fec291..3989c185579f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3422,17 +3422,117 @@ bool drm_rgb_quant_range_selectable(struct edid *edid) } EXPORT_SYMBOL(drm_rgb_quant_range_selectable); +/** + * drm_assign_hdmi_deep_color_info - detect whether monitor supports + * hdmi deep color modes and update drm_display_info if so. + * + * @edid: monitor EDID information + * @info: Updated with maximum supported deep color bpc and color format + * if deep color supported. + * + * Parse the CEA extension according to CEA-861-B. + * Return true if HDMI deep color supported, false if not or unknown. + */ +static bool drm_assign_hdmi_deep_color_info(struct edid *edid, + struct drm_display_info *info, + struct drm_connector *connector) +{ + u8 *edid_ext, *hdmi; + int i; + int start_offset, end_offset; + unsigned int dc_bpc = 0; + + edid_ext = drm_find_cea_extension(edid); + if (!edid_ext) + return false; + + if (cea_db_offsets(edid_ext, &start_offset, &end_offset)) + return false; + + /* + * Because HDMI identifier is in Vendor Specific Block, + * search it from all data blocks of CEA extension. + */ + for_each_cea_db(edid_ext, i, start_offset, end_offset) { + if (cea_db_is_hdmi_vsdb(&edid_ext[i])) { + /* HDMI supports at least 8 bpc */ + info->bpc = 8; + + hdmi = &edid_ext[i]; + if (cea_db_payload_len(hdmi) < 6) + return false; + + if (hdmi[6] & DRM_EDID_HDMI_DC_30) { + dc_bpc = 10; + DRM_DEBUG("%s: HDMI sink does deep color 30.\n", + drm_get_connector_name(connector)); + } + + if (hdmi[6] & DRM_EDID_HDMI_DC_36) { + dc_bpc = 12; + DRM_DEBUG("%s: HDMI sink does deep color 36.\n", + drm_get_connector_name(connector)); + } + + if (hdmi[6] & DRM_EDID_HDMI_DC_48) { + dc_bpc = 16; + DRM_DEBUG("%s: HDMI sink does deep color 48.\n", + drm_get_connector_name(connector)); + } + + if (dc_bpc > 0) { + DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n", + drm_get_connector_name(connector), dc_bpc); + info->bpc = dc_bpc; + + /* + * Deep color support mandates RGB444 support for all video + * modes and forbids YCRCB422 support for all video modes per + * HDMI 1.3 spec. + */ + info->color_formats = DRM_COLOR_FORMAT_RGB444; + + /* YCRCB444 is optional according to spec. */ + if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { + info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; + DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n", + drm_get_connector_name(connector)); + } + + /* + * Spec says that if any deep color mode is supported at all, + * then deep color 36 bit must be supported. + */ + if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) { + DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n", + drm_get_connector_name(connector)); + } + + return true; + } + else { + DRM_DEBUG("%s: No deep color support on this HDMI sink.\n", + drm_get_connector_name(connector)); + } + } + } + + return false; +} + /** * drm_add_display_info - pull display info out if present * @edid: EDID data * @info: display info (attached to connector) + * @connector: connector whose edid is used to build display info * * Grab any available display info and stuff it into the drm_display_info * structure that's part of the connector. Useful for tracking bpp and * color spaces. */ static void drm_add_display_info(struct edid *edid, - struct drm_display_info *info) + struct drm_display_info *info, + struct drm_connector *connector) { u8 *edid_ext; @@ -3462,6 +3562,9 @@ static void drm_add_display_info(struct edid *edid, info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; } + /* HDMI deep color modes supported? Assign to info, if so */ + drm_assign_hdmi_deep_color_info(edid, info, connector); + /* Only defined for 1.4 with digital displays */ if (edid->revision < 4) return; @@ -3491,6 +3594,9 @@ static void drm_add_display_info(struct edid *edid, break; } + DRM_DEBUG("%s: Assigning EDID-1.4 digital sink color depth as %d bpc.\n", + drm_get_connector_name(connector), info->bpc); + info->color_formats |= DRM_COLOR_FORMAT_RGB444; if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444) info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; @@ -3549,7 +3655,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) edid_fixup_preferred(connector, quirks); - drm_add_display_info(edid, &connector->display_info); + drm_add_display_info(edid, &connector->display_info, connector); if (quirks & EDID_QUIRK_FORCE_8BPC) connector->display_info.bpc = 8; diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index a1441c5ac63d..b96031d947a0 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -202,6 +202,11 @@ struct detailed_timing { #define DRM_EDID_FEATURE_PM_SUSPEND (1 << 6) #define DRM_EDID_FEATURE_PM_STANDBY (1 << 7) +#define DRM_EDID_HDMI_DC_48 (1 << 6) +#define DRM_EDID_HDMI_DC_36 (1 << 5) +#define DRM_EDID_HDMI_DC_30 (1 << 4) +#define DRM_EDID_HDMI_DC_Y444 (1 << 3) + struct edid { u8 header[8]; /* Vendor & product info */ -- cgit v1.3-18-gd494 From d5ab2b430b3cec65ba5b30b2e1de8ea46715cb93 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 Jun 2014 14:56:23 +0300 Subject: drm: drop drm_get_connector_name() and drm_get_encoder_name() No longer used or needed as the structs have a name field. Acked-by: David Herrmann Signed-off-by: Jani Nikula Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 20 -------------------- include/drm/drm_crtc.h | 2 -- 2 files changed, 22 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 986531395872..f6664a75ad57 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -256,26 +256,6 @@ void drm_connector_ida_destroy(void) ida_destroy(&drm_connector_enum_list[i].ida); } -/** - * drm_get_encoder_name - return a string for encoder - * @encoder: the encoder to get name for - */ -const char *drm_get_encoder_name(const struct drm_encoder *encoder) -{ - return encoder->name; -} -EXPORT_SYMBOL(drm_get_encoder_name); - -/** - * drm_get_connector_name - return a string for connector - * @connector: the connector to get name for - */ -const char *drm_get_connector_name(const struct drm_connector *connector) -{ - return connector->name; -} -EXPORT_SYMBOL(drm_get_connector_name); - /** * drm_get_connector_status_name - return a string for connector status * @status: connector status to compute name of diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 5c1c31cc11cd..e8fe9d8e135c 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -909,7 +909,6 @@ extern int drm_crtc_check_viewport(const struct drm_crtc *crtc, extern void drm_encoder_cleanup(struct drm_encoder *encoder); -extern const char *drm_get_connector_name(const struct drm_connector *connector); extern const char *drm_get_connector_status_name(enum drm_connector_status status); extern const char *drm_get_subpixel_order_name(enum subpixel_order order); extern const char *drm_get_dpms_name(int val); @@ -972,7 +971,6 @@ extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats char *formats[]); extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); extern int drm_mode_create_dirty_info_property(struct drm_device *dev); -extern const char *drm_get_encoder_name(const struct drm_encoder *encoder); extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); -- cgit v1.3-18-gd494 From a2b34e226ac9fbd20179091fad0ee1a24ad48669 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sat, 5 Oct 2013 16:36:52 -0400 Subject: drm: helpers to find mode objects Add a few more useful helpers to find mode objects. Signed-off-by: Rob Clark Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 90 +++++++++++++++------------------------------- include/drm/drm_crtc.h | 33 +++++++++++++++++ 2 files changed, 61 insertions(+), 62 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f6664a75ad57..c4b44be7d464 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1692,7 +1692,6 @@ int drm_mode_getcrtc(struct drm_device *dev, { struct drm_mode_crtc *crtc_resp = data; struct drm_crtc *crtc; - struct drm_mode_object *obj; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) @@ -1700,13 +1699,11 @@ int drm_mode_getcrtc(struct drm_device *dev, drm_modeset_lock_all(dev); - obj = drm_mode_object_find(dev, crtc_resp->crtc_id, - DRM_MODE_OBJECT_CRTC); - if (!obj) { + crtc = drm_crtc_find(dev, crtc_resp->crtc_id); + if (!crtc) { ret = -ENOENT; goto out; } - crtc = obj_to_crtc(obj); crtc_resp->x = crtc->x; crtc_resp->y = crtc->y; @@ -1760,7 +1757,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_get_connector *out_resp = data; - struct drm_mode_object *obj; struct drm_connector *connector; struct drm_display_mode *mode; int mode_count = 0; @@ -1784,13 +1780,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, mutex_lock(&dev->mode_config.mutex); - obj = drm_mode_object_find(dev, out_resp->connector_id, - DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { + connector = drm_connector_find(dev, out_resp->connector_id); + if (!connector) { ret = -ENOENT; goto out; } - connector = obj_to_connector(obj); props_count = connector->properties.count; @@ -1905,7 +1899,6 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_get_encoder *enc_resp = data; - struct drm_mode_object *obj; struct drm_encoder *encoder; int ret = 0; @@ -1913,13 +1906,11 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, return -EINVAL; drm_modeset_lock_all(dev); - obj = drm_mode_object_find(dev, enc_resp->encoder_id, - DRM_MODE_OBJECT_ENCODER); - if (!obj) { + encoder = drm_encoder_find(dev, enc_resp->encoder_id); + if (!encoder) { ret = -ENOENT; goto out; } - encoder = obj_to_encoder(obj); if (encoder->crtc) enc_resp->crtc_id = encoder->crtc->base.id; @@ -2017,7 +2008,6 @@ int drm_mode_getplane(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_get_plane *plane_resp = data; - struct drm_mode_object *obj; struct drm_plane *plane; uint32_t __user *format_ptr; int ret = 0; @@ -2026,13 +2016,11 @@ int drm_mode_getplane(struct drm_device *dev, void *data, return -EINVAL; drm_modeset_lock_all(dev); - obj = drm_mode_object_find(dev, plane_resp->plane_id, - DRM_MODE_OBJECT_PLANE); - if (!obj) { + plane = drm_plane_find(dev, plane_resp->plane_id); + if (!plane) { ret = -ENOENT; goto out; } - plane = obj_to_plane(obj); if (plane->crtc) plane_resp->crtc_id = plane->crtc->base.id; @@ -2085,7 +2073,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_set_plane *plane_req = data; - struct drm_mode_object *obj; struct drm_plane *plane; struct drm_crtc *crtc; struct drm_framebuffer *fb = NULL, *old_fb = NULL; @@ -2100,14 +2087,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data, * First, find the plane, crtc, and fb objects. If not available, * we don't bother to call the driver. */ - obj = drm_mode_object_find(dev, plane_req->plane_id, - DRM_MODE_OBJECT_PLANE); - if (!obj) { + plane = drm_plane_find(dev, plane_req->plane_id); + if (!plane) { DRM_DEBUG_KMS("Unknown plane ID %d\n", plane_req->plane_id); return -ENOENT; } - plane = obj_to_plane(obj); /* No fb means shut it down */ if (!plane_req->fb_id) { @@ -2124,15 +2109,13 @@ int drm_mode_setplane(struct drm_device *dev, void *data, goto out; } - obj = drm_mode_object_find(dev, plane_req->crtc_id, - DRM_MODE_OBJECT_CRTC); - if (!obj) { + crtc = drm_crtc_find(dev, plane_req->crtc_id); + if (!crtc) { DRM_DEBUG_KMS("Unknown crtc ID %d\n", plane_req->crtc_id); ret = -ENOENT; goto out; } - crtc = obj_to_crtc(obj); fb = drm_framebuffer_lookup(dev, plane_req->fb_id); if (!fb) { @@ -2319,7 +2302,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, { struct drm_mode_config *config = &dev->mode_config; struct drm_mode_crtc *crtc_req = data; - struct drm_mode_object *obj; struct drm_crtc *crtc; struct drm_connector **connector_set = NULL, *connector; struct drm_framebuffer *fb = NULL; @@ -2337,14 +2319,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, return -ERANGE; drm_modeset_lock_all(dev); - obj = drm_mode_object_find(dev, crtc_req->crtc_id, - DRM_MODE_OBJECT_CRTC); - if (!obj) { + crtc = drm_crtc_find(dev, crtc_req->crtc_id); + if (!crtc) { DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); ret = -ENOENT; goto out; } - crtc = obj_to_crtc(obj); DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); if (crtc_req->mode_valid) { @@ -2427,15 +2407,13 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, goto out; } - obj = drm_mode_object_find(dev, out_id, - DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { + connector = drm_connector_find(dev, out_id); + if (!connector) { DRM_DEBUG_KMS("Connector id %d unknown\n", out_id); ret = -ENOENT; goto out; } - connector = obj_to_connector(obj); DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -2467,7 +2445,6 @@ static int drm_mode_cursor_common(struct drm_device *dev, struct drm_mode_cursor2 *req, struct drm_file *file_priv) { - struct drm_mode_object *obj; struct drm_crtc *crtc; int ret = 0; @@ -2477,12 +2454,11 @@ static int drm_mode_cursor_common(struct drm_device *dev, if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) return -EINVAL; - obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); - if (!obj) { + crtc = drm_crtc_find(dev, req->crtc_id); + if (!crtc) { DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); return -ENOENT; } - crtc = obj_to_crtc(obj); mutex_lock(&crtc->mutex); if (req->flags & DRM_MODE_CURSOR_BO) { @@ -3439,7 +3415,6 @@ EXPORT_SYMBOL(drm_object_property_get_value); int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_object *obj; struct drm_mode_get_property *out_resp = data; struct drm_property *property; int enum_count = 0; @@ -3458,12 +3433,11 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, return -EINVAL; drm_modeset_lock_all(dev); - obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); - if (!obj) { + property = drm_property_find(dev, out_resp->prop_id); + if (!property) { ret = -ENOENT; goto done; } - property = obj_to_property(obj); if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) { list_for_each_entry(prop_enum, &property->enum_blob_list, head) @@ -3591,7 +3565,6 @@ static void drm_property_destroy_blob(struct drm_device *dev, int drm_mode_getblob_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_object *obj; struct drm_mode_get_blob *out_resp = data; struct drm_property_blob *blob; int ret = 0; @@ -3601,12 +3574,11 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, return -EINVAL; drm_modeset_lock_all(dev); - obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); - if (!obj) { + blob = drm_property_blob_find(dev, out_resp->blob_id); + if (!blob) { ret = -ENOENT; goto done; } - blob = obj_to_blob(obj); if (out_resp->length == blob->length) { blob_ptr = (void __user *)(unsigned long)out_resp->data; @@ -3988,7 +3960,6 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_crtc_lut *crtc_lut = data; - struct drm_mode_object *obj; struct drm_crtc *crtc; void *r_base, *g_base, *b_base; int size; @@ -3998,12 +3969,11 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, return -EINVAL; drm_modeset_lock_all(dev); - obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); - if (!obj) { + crtc = drm_crtc_find(dev, crtc_lut->crtc_id); + if (!crtc) { ret = -ENOENT; goto out; } - crtc = obj_to_crtc(obj); if (crtc->funcs->gamma_set == NULL) { ret = -ENOSYS; @@ -4062,7 +4032,6 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_crtc_lut *crtc_lut = data; - struct drm_mode_object *obj; struct drm_crtc *crtc; void *r_base, *g_base, *b_base; int size; @@ -4072,12 +4041,11 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, return -EINVAL; drm_modeset_lock_all(dev); - obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); - if (!obj) { + crtc = drm_crtc_find(dev, crtc_lut->crtc_id); + if (!crtc) { ret = -ENOENT; goto out; } - crtc = obj_to_crtc(obj); /* memcpy into gamma store */ if (crtc_lut->gamma_size != crtc->gamma_size) { @@ -4130,7 +4098,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_crtc_page_flip *page_flip = data; - struct drm_mode_object *obj; struct drm_crtc *crtc; struct drm_framebuffer *fb = NULL, *old_fb = NULL; struct drm_pending_vblank_event *e = NULL; @@ -4144,10 +4111,9 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) return -EINVAL; - obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC); - if (!obj) + crtc = drm_crtc_find(dev, page_flip->crtc_id); + if (!crtc) return -ENOENT; - crtc = obj_to_crtc(obj); mutex_lock(&crtc->mutex); if (crtc->primary->fb == NULL) { diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index e8fe9d8e135c..90bd1a25e2c6 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1061,6 +1061,15 @@ extern int drm_format_vert_chroma_subsampling(uint32_t format); extern const char *drm_get_format_name(uint32_t format); /* Helpers */ + +static inline struct drm_plane *drm_plane_find(struct drm_device *dev, + uint32_t id) +{ + struct drm_mode_object *mo; + mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PLANE); + return mo ? obj_to_plane(mo) : NULL; +} + static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev, uint32_t id) { @@ -1077,6 +1086,30 @@ static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev, return mo ? obj_to_encoder(mo) : NULL; } +static inline struct drm_connector *drm_connector_find(struct drm_device *dev, + uint32_t id) +{ + struct drm_mode_object *mo; + mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_CONNECTOR); + return mo ? obj_to_connector(mo) : NULL; +} + +static inline struct drm_property *drm_property_find(struct drm_device *dev, + uint32_t id) +{ + struct drm_mode_object *mo; + mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PROPERTY); + return mo ? obj_to_property(mo) : NULL; +} + +static inline struct drm_property_blob * +drm_property_blob_find(struct drm_device *dev, uint32_t id) +{ + struct drm_mode_object *mo; + mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB); + return mo ? obj_to_blob(mo) : NULL; +} + /* Plane list iterator for legacy (overlay only) planes. */ #define drm_for_each_legacy_plane(plane, planelist) \ list_for_each_entry(plane, planelist, head) \ -- cgit v1.3-18-gd494 From 5ea22f24d77b511d68c4ecaf4e6fd5d6ab462b8f Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 30 May 2014 11:34:01 -0400 Subject: drm: add extended property types If we continue to use bitmask for type, we will quickly run out of room to add new types. Split this up so existing part of bitmask range continues to function as before, but reserve a chunk of the remaining space for an integer type-id. Wrap this all up in some type-check helpers to keep the backwards-compat uglyness contained. Signed-off-by: Rob Clark Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 26 +++++++++++++++++--------- include/drm/drm_crtc.h | 17 +++++++++++++++++ include/uapi/drm/drm_mode.h | 13 +++++++++++++ 3 files changed, 47 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index c4b44be7d464..73f543af4924 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3094,6 +3094,9 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, } list_add_tail(&property->head, &dev->mode_config.property_list); + + WARN_ON(!drm_property_type_valid(property)); + return property; fail: kfree(property->values); @@ -3251,14 +3254,16 @@ int drm_property_add_enum(struct drm_property *property, int index, { struct drm_property_enum *prop_enum; - if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK))) + if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || + drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) return -EINVAL; /* * Bitmask enum properties have the additional constraint of values * from 0 to 63 */ - if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63)) + if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && + (value > 63)) return -EINVAL; if (!list_empty(&property->enum_blob_list)) { @@ -3439,10 +3444,11 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, goto done; } - if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) { + if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || + drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { list_for_each_entry(prop_enum, &property->enum_blob_list, head) enum_count++; - } else if (property->flags & DRM_MODE_PROP_BLOB) { + } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { list_for_each_entry(prop_blob, &property->enum_blob_list, head) blob_count++; } @@ -3464,7 +3470,8 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, } out_resp->count_values = value_count; - if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) { + if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || + drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { copied = 0; enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; @@ -3486,7 +3493,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, out_resp->count_enum_blobs = enum_count; } - if (property->flags & DRM_MODE_PROP_BLOB) { + if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { if ((out_resp->count_enum_blobs >= blob_count) && blob_count) { copied = 0; blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr; @@ -3640,17 +3647,18 @@ static bool drm_property_change_is_valid(struct drm_property *property, { if (property->flags & DRM_MODE_PROP_IMMUTABLE) return false; - if (property->flags & DRM_MODE_PROP_RANGE) { + + if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { if (value < property->values[0] || value > property->values[1]) return false; return true; - } else if (property->flags & DRM_MODE_PROP_BITMASK) { + } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { int i; uint64_t valid_mask = 0; for (i = 0; i < property->num_values; i++) valid_mask |= (1ULL << property->values[i]); return !(value & ~valid_mask); - } else if (property->flags & DRM_MODE_PROP_BLOB) { + } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { /* Only the driver knows */ return true; } else { diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 90bd1a25e2c6..92f6ec2de86a 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -930,6 +930,23 @@ extern void drm_mode_config_cleanup(struct drm_device *dev); extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, struct edid *edid); + +static inline bool drm_property_type_is(struct drm_property *property, + uint32_t type) +{ + /* instanceof for props.. handles extended type vs original types: */ + if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) + return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type; + return property->flags & type; +} + +static inline bool drm_property_type_valid(struct drm_property *property) +{ + if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) + return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE); + return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE); +} + extern int drm_object_property_set_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t val); diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 719add464f95..caeaa6f7ebde 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -252,6 +252,19 @@ struct drm_mode_get_connector { #define DRM_MODE_PROP_BLOB (1<<4) #define DRM_MODE_PROP_BITMASK (1<<5) /* bitmask of enumerated types */ +/* non-extended types: legacy bitmask, one bit per type: */ +#define DRM_MODE_PROP_LEGACY_TYPE ( \ + DRM_MODE_PROP_RANGE | \ + DRM_MODE_PROP_ENUM | \ + DRM_MODE_PROP_BLOB | \ + DRM_MODE_PROP_BITMASK) + +/* extended-types: rather than continue to consume a bit per type, + * grab a chunk of the bits to use as integer type id. + */ +#define DRM_MODE_PROP_EXTENDED_TYPE 0x0000ffc0 +#define DRM_MODE_PROP_TYPE(n) ((n) << 6) + struct drm_mode_property_enum { __u64 value; char name[DRM_PROP_NAME_LEN]; -- cgit v1.3-18-gd494 From 98f75de40e9d83c3a90d294b8fd25fa2874212a9 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 30 May 2014 11:37:03 -0400 Subject: drm: add object property type An object property is an id (idr) for a drm mode object. This will allow a property to be used set/get a framebuffer, CRTC, etc. Signed-off-by: Rob Clark Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 61 +++++++++++++++++++++++++++++++++++++++------ include/drm/drm_crtc.h | 5 ++++ include/uapi/drm/drm_mode.h | 1 + 3 files changed, 60 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 73f543af4924..f990d9f180f0 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -370,6 +370,21 @@ void drm_mode_object_put(struct drm_device *dev, mutex_unlock(&dev->mode_config.idr_mutex); } +static struct drm_mode_object *_object_find(struct drm_device *dev, + uint32_t id, uint32_t type) +{ + struct drm_mode_object *obj = NULL; + + mutex_lock(&dev->mode_config.idr_mutex); + obj = idr_find(&dev->mode_config.crtc_idr, id); + if (!obj || (type != DRM_MODE_OBJECT_ANY && obj->type != type) || + (obj->id != id)) + obj = NULL; + mutex_unlock(&dev->mode_config.idr_mutex); + + return obj; +} + /** * drm_mode_object_find - look up a drm object with static lifetime * @dev: drm device @@ -377,7 +392,9 @@ void drm_mode_object_put(struct drm_device *dev, * @type: type of the mode object * * Note that framebuffers cannot be looked up with this functions - since those - * are reference counted, they need special treatment. + * are reference counted, they need special treatment. Even with + * DRM_MODE_OBJECT_ANY (although that will simply return NULL + * rather than WARN_ON()). */ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) @@ -387,13 +404,10 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, /* Framebuffers are reference counted and need their own lookup * function.*/ WARN_ON(type == DRM_MODE_OBJECT_FB); - - mutex_lock(&dev->mode_config.idr_mutex); - obj = idr_find(&dev->mode_config.crtc_idr, id); - if (!obj || (obj->type != type) || (obj->id != id)) + obj = _object_find(dev, id, type); + /* don't leak out unref'd fb's */ + if (obj && (obj->type == DRM_MODE_OBJECT_FB)) obj = NULL; - mutex_unlock(&dev->mode_config.idr_mutex); - return obj; } EXPORT_SYMBOL(drm_mode_object_find); @@ -3074,6 +3088,8 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, if (!property) return NULL; + property->dev = dev; + if (num_values) { property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL); if (!property->values) @@ -3234,6 +3250,23 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags } EXPORT_SYMBOL(drm_property_create_range); +struct drm_property *drm_property_create_object(struct drm_device *dev, + int flags, const char *name, uint32_t type) +{ + struct drm_property *property; + + flags |= DRM_MODE_PROP_OBJECT; + + property = drm_property_create(dev, flags, name, 1); + if (!property) + return NULL; + + property->values[0] = type; + + return property; +} +EXPORT_SYMBOL(drm_property_create_object); + /** * drm_property_add_enum - add a possible value to an enumeration property * @property: enumeration property to change @@ -3661,6 +3694,20 @@ static bool drm_property_change_is_valid(struct drm_property *property, } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { /* Only the driver knows */ return true; + } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { + struct drm_mode_object *obj; + /* a zero value for an object property translates to null: */ + if (value == 0) + return true; + /* + * NOTE: use _object_find() directly to bypass restriction on + * looking up refcnt'd objects (ie. fb's). For a refcnt'd + * object this could race against object finalization, so it + * simply tells us that the object *was* valid. Which is good + * enough. + */ + obj = _object_find(property->dev, value, property->values[0]); + return obj != NULL; } else { int i; for (i = 0; i < property->num_values; i++) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 92f6ec2de86a..cb2e599f769f 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -50,6 +50,7 @@ struct drm_clip_rect; #define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb #define DRM_MODE_OBJECT_PLANE 0xeeeeeeee #define DRM_MODE_OBJECT_BRIDGE 0xbdbdbdbd +#define DRM_MODE_OBJECT_ANY 0 struct drm_mode_object { uint32_t id; @@ -190,6 +191,7 @@ struct drm_property { char name[DRM_PROP_NAME_LEN]; uint32_t num_values; uint64_t *values; + struct drm_device *dev; struct list_head enum_blob_list; }; @@ -980,6 +982,8 @@ struct drm_property *drm_property_create_bitmask(struct drm_device *dev, struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, const char *name, uint64_t min, uint64_t max); +struct drm_property *drm_property_create_object(struct drm_device *dev, + int flags, const char *name, uint32_t type); extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name); @@ -995,6 +999,7 @@ extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, int gamma_size); extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type); + /* IOCTLs */ extern int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index caeaa6f7ebde..57f46348befe 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -264,6 +264,7 @@ struct drm_mode_get_connector { */ #define DRM_MODE_PROP_EXTENDED_TYPE 0x0000ffc0 #define DRM_MODE_PROP_TYPE(n) ((n) << 6) +#define DRM_MODE_PROP_OBJECT DRM_MODE_PROP_TYPE(1) struct drm_mode_property_enum { __u64 value; -- cgit v1.3-18-gd494 From ebc44cf386734374983922c6fc1ae8ac47f88bef Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 12 Sep 2012 22:22:31 -0500 Subject: drm: add signed-range property type Like range, but values are signed. Signed-off-by: Rob Clark Reviewed-by: David Herrmann --- drivers/gpu/drm/drm_crtc.c | 45 +++++++++++++++++++++++++++++++++------------ include/drm/drm_crtc.h | 12 ++++++++++++ include/uapi/drm/drm_mode.h | 1 + 3 files changed, 46 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f990d9f180f0..6127073407e0 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3213,6 +3213,22 @@ struct drm_property *drm_property_create_bitmask(struct drm_device *dev, } EXPORT_SYMBOL(drm_property_create_bitmask); +static struct drm_property *property_create_range(struct drm_device *dev, + int flags, const char *name, + uint64_t min, uint64_t max) +{ + struct drm_property *property; + + property = drm_property_create(dev, flags, name, 2); + if (!property) + return NULL; + + property->values[0] = min; + property->values[1] = max; + + return property; +} + /** * drm_property_create - create a new ranged property type * @dev: drm device @@ -3235,21 +3251,20 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags const char *name, uint64_t min, uint64_t max) { - struct drm_property *property; - - flags |= DRM_MODE_PROP_RANGE; - - property = drm_property_create(dev, flags, name, 2); - if (!property) - return NULL; - - property->values[0] = min; - property->values[1] = max; - - return property; + return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, + name, min, max); } EXPORT_SYMBOL(drm_property_create_range); +struct drm_property *drm_property_create_signed_range(struct drm_device *dev, + int flags, const char *name, + int64_t min, int64_t max) +{ + return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, + name, I642U64(min), I642U64(max)); +} +EXPORT_SYMBOL(drm_property_create_signed_range); + struct drm_property *drm_property_create_object(struct drm_device *dev, int flags, const char *name, uint32_t type) { @@ -3685,6 +3700,12 @@ static bool drm_property_change_is_valid(struct drm_property *property, if (value < property->values[0] || value > property->values[1]) return false; return true; + } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { + int64_t svalue = U642I64(value); + if (svalue < U642I64(property->values[0]) || + svalue > U642I64(property->values[1])) + return false; + return true; } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { int i; uint64_t valid_mask = 0; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index cb2e599f769f..849cfdccff09 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -65,6 +65,15 @@ struct drm_object_properties { uint64_t values[DRM_OBJECT_MAX_PROPERTY]; }; +static inline int64_t U642I64(uint64_t val) +{ + return (int64_t)*((int64_t *)&val); +} +static inline uint64_t I642U64(int64_t val) +{ + return (uint64_t)*((uint64_t *)&val); +} + enum drm_connector_force { DRM_FORCE_UNSPECIFIED, DRM_FORCE_OFF, @@ -982,6 +991,9 @@ struct drm_property *drm_property_create_bitmask(struct drm_device *dev, struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, const char *name, uint64_t min, uint64_t max); +struct drm_property *drm_property_create_signed_range(struct drm_device *dev, + int flags, const char *name, + int64_t min, int64_t max); struct drm_property *drm_property_create_object(struct drm_device *dev, int flags, const char *name, uint32_t type); extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 57f46348befe..def54f9e07ca 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -265,6 +265,7 @@ struct drm_mode_get_connector { #define DRM_MODE_PROP_EXTENDED_TYPE 0x0000ffc0 #define DRM_MODE_PROP_TYPE(n) ((n) << 6) #define DRM_MODE_PROP_OBJECT DRM_MODE_PROP_TYPE(1) +#define DRM_MODE_PROP_SIGNED_RANGE DRM_MODE_PROP_TYPE(2) struct drm_mode_property_enum { __u64 value; -- cgit v1.3-18-gd494 From 6e9f798d91c526982cca0026cd451e8fdbf18aaf Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 29 May 2014 23:54:47 +0200 Subject: drm: Split connection_mutex out of mode_config.mutex (v3) After the split-out of crtc locks from the big mode_config.mutex there's still two major areas it protects: - Various connector probe states, like connector->status, EDID properties, probed mode lists and similar information. - The links from connector->encoder and encoder->crtc and other modeset-relevant connector state (e.g. properties which control the panel fitter). The later is used by modeset operations. But they don't really care about the former since it's allowed to e.g. enable a disconnected VGA output or with a mode not in the probed list. Thus far this hasn't been a problem, but for the atomic modeset conversion Rob Clark needs to convert all modeset relevant locks into w/w locks. This is required because the order of acquisition is determined by how userspace supplies the atomic modeset data. This has run into troubles in the detect path since the i915 load detect code needs _both_ protections offered by the mode_config.mutex: It updates probe state and it needs to change the modeset configuration to enable the temporary load detect pipe. The big deal here is that for the probe/detect users of this lock a plain mutex fits best, but for atomic modesets we really want a w/w mutex. To fix this lets split out a new connection_mutex lock for the modeset relevant parts. For simplicity I've decided to only add one additional lock for all connector/encoder links and modeset configuration states. We have piles of different modeset objects in addition to those (like bridges or panels), so adding per-object locks would be much more effort. Also, we're guaranteed (at least for now) to do a full modeset if we need to acquire this lock. Which means that fine-grained locking is fairly irrelevant compared to the amount of time the full modeset will take. I've done a full audit, and there's just a few things that justify special focus: - Locking in drm_sysfs.c is almost completely absent. We should sprinkle mode_config.connection_mutex over this file a bit, but since it already lacks mode_config.mutex this patch wont make the situation any worse. This is material for a follow-up patch. - omap has a omap_framebuffer_flush function which walks the connector->encoder->crtc links and is called from many contexts. Some look like they don't acquire mode_config.mutex, so this is already racy. Again fixing this is material for a separate patch. - The radeon hot_plug function to retrain DP links looks at connector->dpms. Currently this happens without any locking, so is already racy. I think radeon_hotplug_work_func should gain mutex_lock/unlock calls for the mode_config.connection_mutex. - Same applies to i915's intel_dp_hot_plug. But again, this is already racy. - i915 load_detect code needs to acquire this lock. Which means the w/w dance due to Rob's work will be nicely contained to _just_ this function. I've added fixme comments everywhere where it looks suspicious but in the sysfs code. After a quick irc discussion with Dave Airlie it sounds like the lack of locking in there is due to sysfs cleanup fun at module unload. v1: original (only compile tested) v2: missing mutex_init(), etc (from Rob Clark) v3: i915 needs more care in the conversion: - Protect the edp pp logic with the connection_mutex. - Use connection_mutex in the backlight code due to get_pipe_from_connector. - Use drm_modeset_lock_all in suspend/resume paths. - Update lock checks in the overlay code. Cc: Alex Deucher Cc: Rob Clark Signed-off-by: Daniel Vetter Reviewed-by: Rob Clark --- drivers/gpu/drm/drm_crtc.c | 8 ++++++++ drivers/gpu/drm/drm_crtc_helper.c | 2 ++ drivers/gpu/drm/drm_edid.c | 2 ++ drivers/gpu/drm/drm_plane_helper.c | 7 +++++++ drivers/gpu/drm/i915/i915_debugfs.c | 4 ++-- drivers/gpu/drm/i915/i915_drv.c | 6 ++---- drivers/gpu/drm/i915/intel_display.c | 16 ++++++++++++---- drivers/gpu/drm/i915/intel_dp.c | 15 ++++++++------- drivers/gpu/drm/i915/intel_opregion.c | 4 ++-- drivers/gpu/drm/i915/intel_overlay.c | 4 ++-- drivers/gpu/drm/i915/intel_panel.c | 8 ++++---- drivers/gpu/drm/omapdrm/omap_fb.c | 1 + drivers/gpu/drm/radeon/radeon_connectors.c | 1 + include/drm/drm_crtc.h | 1 + 14 files changed, 54 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5b3e2920c376..f3b98d4b6f46 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -54,6 +54,8 @@ void drm_modeset_lock_all(struct drm_device *dev) mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev->mode_config.connection_mutex); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); } @@ -72,6 +74,8 @@ void drm_modeset_unlock_all(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) mutex_unlock(&crtc->mutex); + mutex_unlock(&dev->mode_config.connection_mutex); + mutex_unlock(&dev->mode_config.mutex); } EXPORT_SYMBOL(drm_modeset_unlock_all); @@ -93,6 +97,7 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) WARN_ON(!mutex_is_locked(&crtc->mutex)); + WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); } EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); @@ -1793,6 +1798,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev->mode_config.connection_mutex); connector = drm_connector_find(dev, out_resp->connector_id); if (!connector) { @@ -1891,6 +1897,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, out_resp->count_encoders = encoders_count; out: + mutex_unlock(&dev->mode_config.connection_mutex); mutex_unlock(&dev->mode_config.mutex); return ret; @@ -4640,6 +4647,7 @@ EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); void drm_mode_config_init(struct drm_device *dev) { mutex_init(&dev->mode_config.mutex); + mutex_init(&dev->mode_config.connection_mutex); mutex_init(&dev->mode_config.idr_mutex); mutex_init(&dev->mode_config.fb_lock); INIT_LIST_HEAD(&dev->mode_config.fb_list); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 231c9433341f..b55d27c872f6 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -89,6 +89,8 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder) struct drm_device *dev = encoder->dev; WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) if (connector->encoder == encoder) return true; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 085e5550aac5..7be21781d3bd 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3304,6 +3304,8 @@ struct drm_connector *drm_select_eld(struct drm_encoder *encoder, struct drm_connector *connector; struct drm_device *dev = encoder->dev; + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) if (connector->encoder == encoder && connector->eld[0]) return connector; diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index d966afa7ecae..458d9bf09209 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -54,6 +54,13 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc, struct drm_connector *connector; int count = 0; + /* + * Note: Once we change the plane hooks to more fine-grained locking we + * need to grab the connection_mutex here to be able to make these + * checks. + */ + WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) if (connector->encoder && connector->encoder->crtc == crtc) { if (connector_list != NULL && count < num_connectors) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 36f4c15f538b..169fc2d8c554 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2609,7 +2609,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_device *dev, enum pipe pipe, *source = INTEL_PIPE_CRC_SOURCE_PIPE; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { if (!encoder->base.crtc) @@ -2645,7 +2645,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_device *dev, enum pipe pipe, break; } } - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 4619c9e51907..5b5b82c3f570 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -533,13 +533,11 @@ static int i915_drm_freeze(struct drm_device *dev) * Disable CRTCs directly since we want to preserve sw state * for _thaw. */ - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); for_each_crtc(dev, crtc) { - mutex_lock(&crtc->mutex); dev_priv->display.crtc_disable(crtc); - mutex_unlock(&crtc->mutex); } - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); intel_modeset_suspend_hw(dev); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e80b2917e3cb..c2976ade823f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8323,6 +8323,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, connector->base.id, connector->name, encoder->base.id, encoder->name); + mutex_lock(&dev->mode_config.connection_mutex); + /* * Algorithm gets a little messy: * @@ -8365,7 +8367,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, */ if (!crtc) { DRM_DEBUG_KMS("no pipe available for load-detect\n"); - return false; + goto fail_unlock_connector; } mutex_lock(&crtc->mutex); @@ -8419,6 +8421,9 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, else intel_crtc->new_config = NULL; mutex_unlock(&crtc->mutex); +fail_unlock_connector: + mutex_unlock(&dev->mode_config.connection_mutex); + return false; } @@ -8448,6 +8453,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, } mutex_unlock(&crtc->mutex); + mutex_unlock(&connector->dev->mode_config.connection_mutex); return; } @@ -8456,6 +8462,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, connector->funcs->dpms(connector, old->dpms_mode); mutex_unlock(&crtc->mutex); + mutex_unlock(&connector->dev->mode_config.connection_mutex); } static int i9xx_pll_refclk(struct drm_device *dev, @@ -10986,8 +10993,9 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) enum pipe intel_get_pipe_from_connector(struct intel_connector *connector) { struct drm_encoder *encoder = connector->base.encoder; + struct drm_device *dev = connector->base.dev; - WARN_ON(!mutex_is_locked(&connector->base.dev->mode_config.mutex)); + WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); if (!encoder) return INVALID_PIPE; @@ -11756,9 +11764,9 @@ void intel_modeset_init(struct drm_device *dev) /* Just in case the BIOS is doing something questionable. */ intel_disable_fbc(dev); - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(dev, false); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); for_each_intel_crtc(dev, crtc) { if (!crtc->active) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d94f0271e422..c4d883921282 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1154,7 +1154,7 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp) u32 pp; u32 pp_stat_reg, pp_ctrl_reg; - WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); if (!intel_dp->want_panel_vdd && edp_have_panel_vdd(intel_dp)) { struct intel_digital_port *intel_dig_port = @@ -1191,9 +1191,9 @@ static void edp_panel_vdd_work(struct work_struct *__work) struct intel_dp, panel_vdd_work); struct drm_device *dev = intel_dp_to_dev(intel_dp); - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev->mode_config.connection_mutex); edp_panel_vdd_off_sync(intel_dp); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev->mode_config.connection_mutex); } static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) @@ -3235,6 +3235,7 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) u8 sink_irq_vector; u8 link_status[DP_LINK_STATUS_SIZE]; + /* FIXME: This access isn't protected by any locks. */ if (!intel_encoder->connectors_active) return; @@ -3665,9 +3666,9 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) drm_encoder_cleanup(encoder); if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev->mode_config.connection_mutex); edp_panel_vdd_off_sync(intel_dp); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev->mode_config.connection_mutex); } kfree(intel_dig_port); } @@ -4246,9 +4247,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, drm_dp_aux_unregister_i2c_bus(&intel_dp->aux); if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev->mode_config.connection_mutex); edp_panel_vdd_off_sync(intel_dp); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev->mode_config.connection_mutex); } drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index acde2945eb8a..b812e9d39f38 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -410,7 +410,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) if (bclp > 255) return ASLC_BACKLIGHT_FAILED; - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev->mode_config.connection_mutex); /* * Update backlight on all connectors that support backlight (usually @@ -421,7 +421,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) intel_panel_set_backlight(intel_connector, bclp, 255); iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev->mode_config.connection_mutex); return 0; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 27eb820d1b19..e97ea33e0117 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -688,7 +688,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, u32 swidth, swidthsw, sheight, ostride; BUG_ON(!mutex_is_locked(&dev->struct_mutex)); - BUG_ON(!mutex_is_locked(&dev->mode_config.mutex)); + BUG_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); BUG_ON(!overlay); ret = intel_overlay_release_old_vid(overlay); @@ -793,7 +793,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay) int ret; BUG_ON(!mutex_is_locked(&dev->struct_mutex)); - BUG_ON(!mutex_is_locked(&dev->mode_config.mutex)); + BUG_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); ret = intel_overlay_recover_from_interrupt(overlay); if (ret != 0) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 3fb3f939dca5..d4d415665475 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -876,12 +876,12 @@ static int intel_backlight_device_update_status(struct backlight_device *bd) struct intel_connector *connector = bl_get_data(bd); struct drm_device *dev = connector->base.dev; - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev->mode_config.connection_mutex); DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", bd->props.brightness, bd->props.max_brightness); intel_panel_set_backlight(connector, bd->props.brightness, bd->props.max_brightness); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev->mode_config.connection_mutex); return 0; } @@ -893,9 +893,9 @@ static int intel_backlight_device_get_brightness(struct backlight_device *bd) int ret; intel_runtime_pm_get(dev_priv); - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev->mode_config.connection_mutex); ret = intel_panel_get_backlight(connector); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev->mode_config.connection_mutex); intel_runtime_pm_put(dev_priv); return ret; diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 8b019602ffe6..2a5cacdc344b 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -346,6 +346,7 @@ void omap_framebuffer_flush(struct drm_framebuffer *fb, VERB("flush: %d,%d %dx%d, fb=%p", x, y, w, h, fb); + /* FIXME: This is racy - no protection against modeset config changes. */ while ((connector = omap_framebuffer_get_next_connector(fb, connector))) { /* only consider connectors that are part of a chain */ if (connector->encoder && connector->encoder->crtc) { diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 31d4cf60bae3..4522f7dce653 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -48,6 +48,7 @@ void radeon_connector_hotplug(struct drm_connector *connector) radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); /* if the connector is already off, don't turn it back on */ + /* FIXME: This access isn't protected by any locks. */ if (connector->dpms != DRM_MODE_DPMS_ON) return; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 849cfdccff09..6c295df7b0df 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -738,6 +738,7 @@ struct drm_mode_group { */ struct drm_mode_config { struct mutex mutex; /* protects configuration (mode lists etc.) */ + struct mutex connection_mutex; /* protects connector->encoder and encoder->crtc links */ struct mutex idr_mutex; /* for IDR management */ struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ /* this is limited to one for now */ -- cgit v1.3-18-gd494 From 39b9004d1f626b88b775c7655d3f286e135dfec6 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 30 Sep 2013 16:13:39 +0200 Subject: gpu: ipu-v3: Move i.MX IPUv3 core driver out of staging The i.MX Image Processing Unit (IPU) contains a number of image processing blocks that sit right in the middle between DRM and V4L2. Some of the modules, such as Display Controller, Processor, and Interface (DC, DP, DI) or CMOS Sensor Interface (CSI) and their FIFOs could be assigned to either framework, but others, such as the dma controller (IDMAC) and image converter (IC) can be used by both. The IPUv3 core driver provides an internal API to access the modules, to be used by both DRM and V4L2 IPUv3 drivers. Signed-off-by: Lucas Stach Signed-off-by: Philipp Zabel Acked-by: Greg Kroah-Hartman --- drivers/gpu/Makefile | 1 + drivers/gpu/ipu-v3/Kconfig | 7 + drivers/gpu/ipu-v3/Makefile | 3 + drivers/gpu/ipu-v3/ipu-common.c | 1261 +++++++++++++++++++++++++++ drivers/gpu/ipu-v3/ipu-dc.c | 411 +++++++++ drivers/gpu/ipu-v3/ipu-di.c | 730 ++++++++++++++++ drivers/gpu/ipu-v3/ipu-dmfc.c | 415 +++++++++ drivers/gpu/ipu-v3/ipu-dp.c | 338 +++++++ drivers/gpu/ipu-v3/ipu-prv.h | 206 +++++ drivers/staging/imx-drm/Kconfig | 11 +- drivers/staging/imx-drm/Makefile | 1 - drivers/staging/imx-drm/imx-hdmi.c | 2 +- drivers/staging/imx-drm/imx-tve.c | 2 +- drivers/staging/imx-drm/ipu-v3/Makefile | 3 - drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h | 326 ------- drivers/staging/imx-drm/ipu-v3/ipu-common.c | 1261 --------------------------- drivers/staging/imx-drm/ipu-v3/ipu-dc.c | 412 --------- drivers/staging/imx-drm/ipu-v3/ipu-di.c | 730 ---------------- drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c | 415 --------- drivers/staging/imx-drm/ipu-v3/ipu-dp.c | 338 ------- drivers/staging/imx-drm/ipu-v3/ipu-prv.h | 206 ----- drivers/staging/imx-drm/ipuv3-crtc.c | 2 +- drivers/staging/imx-drm/ipuv3-plane.c | 2 +- drivers/video/Kconfig | 1 + include/video/imx-ipu-v3.h | 326 +++++++ 25 files changed, 3704 insertions(+), 3706 deletions(-) create mode 100644 drivers/gpu/ipu-v3/Kconfig create mode 100644 drivers/gpu/ipu-v3/Makefile create mode 100644 drivers/gpu/ipu-v3/ipu-common.c create mode 100644 drivers/gpu/ipu-v3/ipu-dc.c create mode 100644 drivers/gpu/ipu-v3/ipu-di.c create mode 100644 drivers/gpu/ipu-v3/ipu-dmfc.c create mode 100644 drivers/gpu/ipu-v3/ipu-dp.c create mode 100644 drivers/gpu/ipu-v3/ipu-prv.h delete mode 100644 drivers/staging/imx-drm/ipu-v3/Makefile delete mode 100644 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h delete mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-common.c delete mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-dc.c delete mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-di.c delete mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c delete mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-dp.c delete mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-prv.h create mode 100644 include/video/imx-ipu-v3.h (limited to 'include') diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile index d8a22c2a579d..70da9eb52a42 100644 --- a/drivers/gpu/Makefile +++ b/drivers/gpu/Makefile @@ -1,2 +1,3 @@ obj-y += drm/ vga/ obj-$(CONFIG_TEGRA_HOST1X) += host1x/ +obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/ diff --git a/drivers/gpu/ipu-v3/Kconfig b/drivers/gpu/ipu-v3/Kconfig new file mode 100644 index 000000000000..2f228a2f2a48 --- /dev/null +++ b/drivers/gpu/ipu-v3/Kconfig @@ -0,0 +1,7 @@ +config IMX_IPUV3_CORE + tristate "IPUv3 core support" + depends on SOC_IMX5 || SOC_IMX6Q || SOC_IMX6SL || ARCH_MULTIPLATFORM + depends on RESET_CONTROLLER + help + Choose this if you have a i.MX5/6 system and want to use the Image + Processing Unit. This option only enables IPU base support. diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile new file mode 100644 index 000000000000..d21cc37d0498 --- /dev/null +++ b/drivers/gpu/ipu-v3/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o + +imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c new file mode 100644 index 000000000000..7e1f614e7fbc --- /dev/null +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -0,0 +1,1261 @@ +/* + * Copyright (c) 2010 Sascha Hauer + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include