Skip to content

Commit 1c26b8e

Browse files
committed
drm/probe_helper: Add drm_connector_helper_funcs.mode_valid_ctx
This is just an atomic version of mode_valid, which is intended to be used for situations where a driver might need to check the atomic state of objects other than the connector itself. One such example is with MST, where the maximum possible bandwidth on a connector can change dynamically irregardless of the display configuration. Changes since v1: * Use new drm logging functions * Make some corrections in the mode_valid_ctx kdoc * Return error codes or 0 from ->mode_valid_ctx() on fail, and store the drm_mode_status in an additional function parameter Changes since v2: * Don't accidentally assign ret to mode->status on success, or we'll squash legitimate mode validation results * Don't forget to assign MODE_OK to status in drm_connector_mode_valid() if we have no callbacks * Drop leftover hunk in drm_modes.h around enum drm_mode_status Changes since v3: * s/return ret/return 0/ in drm_mode_validate_pipeline() * Minor cleanup in drm_connector_mode_valid() Tested-by: Imre Deak <[email protected]> Reviewed-by: Imre Deak <[email protected]> Cc: Lee Shawn C <[email protected]> Signed-off-by: Lyude Paul <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 1d9221e commit 1c26b8e

File tree

3 files changed

+111
-35
lines changed

3 files changed

+111
-35
lines changed

drivers/gpu/drm/drm_crtc_helper_internal.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,11 @@ enum drm_mode_status drm_crtc_mode_valid(struct drm_crtc *crtc,
7373
const struct drm_display_mode *mode);
7474
enum drm_mode_status drm_encoder_mode_valid(struct drm_encoder *encoder,
7575
const struct drm_display_mode *mode);
76-
enum drm_mode_status drm_connector_mode_valid(struct drm_connector *connector,
77-
struct drm_display_mode *mode);
76+
int
77+
drm_connector_mode_valid(struct drm_connector *connector,
78+
struct drm_display_mode *mode,
79+
struct drm_modeset_acquire_ctx *ctx,
80+
enum drm_mode_status *status);
7881

7982
struct drm_encoder *
8083
drm_connector_get_single_encoder(struct drm_connector *connector);

drivers/gpu/drm/drm_probe_helper.c

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -86,26 +86,28 @@ drm_mode_validate_flag(const struct drm_display_mode *mode,
8686
return MODE_OK;
8787
}
8888

89-
static enum drm_mode_status
89+
static int
9090
drm_mode_validate_pipeline(struct drm_display_mode *mode,
91-
struct drm_connector *connector)
91+
struct drm_connector *connector,
92+
struct drm_modeset_acquire_ctx *ctx,
93+
enum drm_mode_status *status)
9294
{
9395
struct drm_device *dev = connector->dev;
94-
enum drm_mode_status ret = MODE_OK;
9596
struct drm_encoder *encoder;
97+
int ret;
9698

9799
/* Step 1: Validate against connector */
98-
ret = drm_connector_mode_valid(connector, mode);
99-
if (ret != MODE_OK)
100+
ret = drm_connector_mode_valid(connector, mode, ctx, status);
101+
if (ret || *status != MODE_OK)
100102
return ret;
101103

102104
/* Step 2: Validate against encoders and crtcs */
103105
drm_connector_for_each_possible_encoder(connector, encoder) {
104106
struct drm_bridge *bridge;
105107
struct drm_crtc *crtc;
106108

107-
ret = drm_encoder_mode_valid(encoder, mode);
108-
if (ret != MODE_OK) {
109+
*status = drm_encoder_mode_valid(encoder, mode);
110+
if (*status != MODE_OK) {
109111
/* No point in continuing for crtc check as this encoder
110112
* will not accept the mode anyway. If all encoders
111113
* reject the mode then, at exit, ret will not be
@@ -114,8 +116,8 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode,
114116
}
115117

116118
bridge = drm_bridge_chain_get_first_bridge(encoder);
117-
ret = drm_bridge_chain_mode_valid(bridge, mode);
118-
if (ret != MODE_OK) {
119+
*status = drm_bridge_chain_mode_valid(bridge, mode);
120+
if (*status != MODE_OK) {
119121
/* There is also no point in continuing for crtc check
120122
* here. */
121123
continue;
@@ -125,17 +127,17 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode,
125127
if (!drm_encoder_crtc_ok(encoder, crtc))
126128
continue;
127129

128-
ret = drm_crtc_mode_valid(crtc, mode);
129-
if (ret == MODE_OK) {
130+
*status = drm_crtc_mode_valid(crtc, mode);
131+
if (*status == MODE_OK) {
130132
/* If we get to this point there is at least
131133
* one combination of encoder+crtc that works
132134
* for this mode. Lets return now. */
133-
return ret;
135+
return 0;
134136
}
135137
}
136138
}
137139

138-
return ret;
140+
return 0;
139141
}
140142

141143
static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector)
@@ -196,16 +198,27 @@ enum drm_mode_status drm_encoder_mode_valid(struct drm_encoder *encoder,
196198
return encoder_funcs->mode_valid(encoder, mode);
197199
}
198200

199-
enum drm_mode_status drm_connector_mode_valid(struct drm_connector *connector,
200-
struct drm_display_mode *mode)
201+
int
202+
drm_connector_mode_valid(struct drm_connector *connector,
203+
struct drm_display_mode *mode,
204+
struct drm_modeset_acquire_ctx *ctx,
205+
enum drm_mode_status *status)
201206
{
202207
const struct drm_connector_helper_funcs *connector_funcs =
203208
connector->helper_private;
209+
int ret = 0;
210+
211+
if (!connector_funcs)
212+
*status = MODE_OK;
213+
else if (connector_funcs->mode_valid_ctx)
214+
ret = connector_funcs->mode_valid_ctx(connector, mode, ctx,
215+
status);
216+
else if (connector_funcs->mode_valid)
217+
*status = connector_funcs->mode_valid(connector, mode);
218+
else
219+
*status = MODE_OK;
204220

205-
if (!connector_funcs || !connector_funcs->mode_valid)
206-
return MODE_OK;
207-
208-
return connector_funcs->mode_valid(connector, mode);
221+
return ret;
209222
}
210223

211224
#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
@@ -375,8 +388,9 @@ EXPORT_SYMBOL(drm_helper_probe_detect);
375388
* (if specified)
376389
* - drm_mode_validate_flag() checks the modes against basic connector
377390
* capabilities (interlace_allowed,doublescan_allowed,stereo_allowed)
378-
* - the optional &drm_connector_helper_funcs.mode_valid helper can perform
379-
* driver and/or sink specific checks
391+
* - the optional &drm_connector_helper_funcs.mode_valid or
392+
* &drm_connector_helper_funcs.mode_valid_ctx helpers can perform driver
393+
* and/or sink specific checks
380394
* - the optional &drm_crtc_helper_funcs.mode_valid,
381395
* &drm_bridge_funcs.mode_valid and &drm_encoder_helper_funcs.mode_valid
382396
* helpers can perform driver and/or source specific checks which are also
@@ -507,22 +521,39 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
507521
mode_flags |= DRM_MODE_FLAG_3D_MASK;
508522

509523
list_for_each_entry(mode, &connector->modes, head) {
510-
if (mode->status == MODE_OK)
511-
mode->status = drm_mode_validate_driver(dev, mode);
524+
if (mode->status != MODE_OK)
525+
continue;
526+
527+
mode->status = drm_mode_validate_driver(dev, mode);
528+
if (mode->status != MODE_OK)
529+
continue;
512530

513-
if (mode->status == MODE_OK)
514-
mode->status = drm_mode_validate_size(mode, maxX, maxY);
531+
mode->status = drm_mode_validate_size(mode, maxX, maxY);
532+
if (mode->status != MODE_OK)
533+
continue;
515534

516-
if (mode->status == MODE_OK)
517-
mode->status = drm_mode_validate_flag(mode, mode_flags);
535+
mode->status = drm_mode_validate_flag(mode, mode_flags);
536+
if (mode->status != MODE_OK)
537+
continue;
518538

519-
if (mode->status == MODE_OK)
520-
mode->status = drm_mode_validate_pipeline(mode,
521-
connector);
539+
ret = drm_mode_validate_pipeline(mode, connector, &ctx,
540+
&mode->status);
541+
if (ret) {
542+
drm_dbg_kms(dev,
543+
"drm_mode_validate_pipeline failed: %d\n",
544+
ret);
545+
546+
if (drm_WARN_ON_ONCE(dev, ret != -EDEADLK)) {
547+
mode->status = MODE_ERROR;
548+
} else {
549+
drm_modeset_backoff(&ctx);
550+
goto retry;
551+
}
552+
}
522553

523-
if (mode->status == MODE_OK)
524-
mode->status = drm_mode_validate_ycbcr420(mode,
525-
connector);
554+
if (mode->status != MODE_OK)
555+
continue;
556+
mode->status = drm_mode_validate_ycbcr420(mode, connector);
526557
}
527558

528559
prune:

include/drm/drm_modeset_helper_vtables.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,48 @@ struct drm_connector_helper_funcs {
968968
*/
969969
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
970970
struct drm_display_mode *mode);
971+
972+
/**
973+
* @mode_valid_ctx:
974+
*
975+
* Callback to validate a mode for a connector, irrespective of the
976+
* specific display configuration.
977+
*
978+
* This callback is used by the probe helpers to filter the mode list
979+
* (which is usually derived from the EDID data block from the sink).
980+
* See e.g. drm_helper_probe_single_connector_modes().
981+
*
982+
* This function is optional, and is the atomic version of
983+
* &drm_connector_helper_funcs.mode_valid.
984+
*
985+
* To allow for accessing the atomic state of modesetting objects, the
986+
* helper libraries always call this with ctx set to a valid context,
987+
* and &drm_mode_config.connection_mutex will always be locked with
988+
* the ctx parameter set to @ctx. This allows for taking additional
989+
* locks as required.
990+
*
991+
* Even though additional locks may be acquired, this callback is
992+
* still expected not to take any constraints into account which would
993+
* be influenced by the currently set display state - such constraints
994+
* should be handled in the driver's atomic check. For example, if a
995+
* connector shares display bandwidth with other connectors then it
996+
* would be ok to validate the minimum bandwidth requirement of a mode
997+
* against the maximum possible bandwidth of the connector. But it
998+
* wouldn't be ok to take the current bandwidth usage of other
999+
* connectors into account, as this would change depending on the
1000+
* display state.
1001+
*
1002+
* Returns:
1003+
* 0 if &drm_connector_helper_funcs.mode_valid_ctx succeeded and wrote
1004+
* the &enum drm_mode_status value to @status, or a negative error
1005+
* code otherwise.
1006+
*
1007+
*/
1008+
int (*mode_valid_ctx)(struct drm_connector *connector,
1009+
struct drm_display_mode *mode,
1010+
struct drm_modeset_acquire_ctx *ctx,
1011+
enum drm_mode_status *status);
1012+
9711013
/**
9721014
* @best_encoder:
9731015
*

0 commit comments

Comments
 (0)