From 16bff572cc660f19e58c99941368dea050b36a05 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 28 Nov 2018 23:12:34 +0100 Subject: drm/dp-mst-helper: Remove hotplug callback When everyone implements it exactly the same way, among all 4 implementations, there's not really a need to overwrite this at all. Aside: drm_kms_helper_hotplug_event is pretty much core functionality at this point. Probably should move it there. Reviewed-by: Lyude Paul Acked-by: Alex Deucher Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20181128221234.15054-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/i915/intel_dp_mst.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_dp_mst.c') diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 4de247ddf05f..f05427b74e34 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -517,20 +517,10 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, drm_connector_put(connector); } -static void intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) -{ - struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr); - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = intel_dig_port->base.base.dev; - - drm_kms_helper_hotplug_event(dev); -} - static const struct drm_dp_mst_topology_cbs mst_cbs = { .add_connector = intel_dp_add_mst_connector, .register_connector = intel_dp_register_mst_connector, .destroy_connector = intel_dp_destroy_mst_connector, - .hotplug = intel_dp_mst_hotplug, }; static struct intel_dp_mst_encoder * -- cgit v1.2.3 From 79a47cd36c8ddbf4435cd658d00c61cc2d9741cd Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Thu, 10 Jan 2019 19:53:33 -0500 Subject: drm/i915: Keep malloc references to MST ports So that the ports stay around until we've destroyed the connectors, in order to ensure that we don't pass an invalid pointer to any MST helpers once we introduce the new MST VCPI helpers. Changes since v1: * Move drm_dp_mst_get_port_malloc() to where we assign intel_connector->port - danvet Signed-off-by: Lyude Paul Reviewed-by: Daniel Vetter Cc: David Airlie Cc: Jerry Zuo Cc: Harry Wentland Cc: Juston Li Link: https://patchwork.freedesktop.org/patch/msgid/20190111005343.17443-11-lyude@redhat.com --- drivers/gpu/drm/i915/intel_connector.c | 4 ++++ drivers/gpu/drm/i915/intel_dp_mst.c | 1 + 2 files changed, 5 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_dp_mst.c') diff --git a/drivers/gpu/drm/i915/intel_connector.c b/drivers/gpu/drm/i915/intel_connector.c index 18e370f607bc..37d2c644f4b8 100644 --- a/drivers/gpu/drm/i915/intel_connector.c +++ b/drivers/gpu/drm/i915/intel_connector.c @@ -95,6 +95,10 @@ void intel_connector_destroy(struct drm_connector *connector) intel_panel_fini(&intel_connector->panel); drm_connector_cleanup(connector); + + if (intel_connector->port) + drm_dp_mst_put_port_malloc(intel_connector->port); + kfree(connector); } diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index f05427b74e34..631fd1537252 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -457,6 +457,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo intel_connector->get_hw_state = intel_dp_mst_get_hw_state; intel_connector->mst_port = intel_dp; intel_connector->port = port; + drm_dp_mst_get_port_malloc(port); connector = &intel_connector->base; ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, -- cgit v1.2.3 From eceae147246749c6dbaeefda802b30f804a3c54c Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Thu, 10 Jan 2019 19:53:41 -0500 Subject: drm/dp_mst: Start tracking per-port VCPI allocations There has been a TODO waiting for quite a long time in drm_dp_mst_topology.c: /* We cannot rely on port->vcpi.num_slots to update * topology_state->avail_slots as the port may not exist if the parent * branch device was unplugged. This should be fixed by tracking * per-port slot allocation in drm_dp_mst_topology_state instead of * depending on the caller to tell us how many slots to release. */ That's not the only reason we should fix this: forcing the driver to track the VCPI allocations throughout a state's atomic check is error prone, because it means that extra care has to be taken with the order that drm_dp_atomic_find_vcpi_slots() and drm_dp_atomic_release_vcpi_slots() are called in in order to ensure idempotency. Currently the only driver actually using these helpers, i915, doesn't even do this correctly: multiple ->best_encoder() checks with i915's current implementation would not be idempotent and would over-allocate VCPI slots, something I learned trying to implement fallback retraining in MST. So: simplify this whole mess, and teach drm_dp_atomic_find_vcpi_slots() and drm_dp_atomic_release_vcpi_slots() to track the VCPI allocations for each port. This allows us to ensure idempotency without having to rely on the driver as much. Additionally: the driver doesn't need to do any kind of VCPI slot tracking anymore if it doesn't need it for it's own internal state. Additionally; this adds a new drm_dp_mst_atomic_check() helper which must be used by atomic drivers to perform validity checks for the new VCPI allocations incurred by a state. Also: update the documentation and make it more obvious that these /must/ be called by /all/ atomic drivers supporting MST. Changes since v9: * Add some missing changes that were requested by danvet that I forgot about after I redid all of the kref stuff: * Remove unnecessary state changes in intel_dp_mst_atomic_check * Cleanup atomic check logic for VCPI allocations - all we need to check in compute_config is whether or not this state disables a CRTC, then free VCPI based off that Changes since v8: * Fix compile errors, whoops! Changes since v7: - Don't check for mixed stale/valid VCPI allocations, just rely on connector registration to stop such erroneous modesets Changes since v6: - Keep a kref to all of the ports we have allocations on. This required a good bit of changing to when we call drm_dp_find_vcpi_slots(), mainly that we need to ensure that we only redo VCPI allocations on actual mode or CRTC changes, not crtc_state->active changes. Additionally, we no longer take the registration of the DRM connector for each port into account because so long as we have a kref to the port in the new or previous atomic state, the connector will stay registered. - Use the small changes to drm_dp_put_port() to add even more error checking to make misusage of the helpers more obvious. I added this after having to chase down various use-after-free conditions that started popping up from the new helpers so no one else has to troubleshoot that. - Move some accidental DRM_DEBUG_KMS() calls to DRM_DEBUG_ATOMIC() - Update documentation again, note that find/release() should both not be called on the same port in a single atomic check phase (but multiple calls to one or the other is OK) Changes since v4: - Don't skip the atomic checks for VCPI allocations if no new VCPI allocations happen in a state. This makes the next change I'm about to list here a lot easier to implement. - Don't ignore VCPI allocations on destroyed ports, instead ensure that when ports are destroyed and still have VCPI allocations in the topology state, the only state changes allowed are releasing said ports' VCPI. This prevents a state with a mix of VCPI allocations from destroyed ports, and allocations from valid ports. Changes since v3: - Don't release VCPI allocations in the topology state immediately in drm_dp_atomic_release_vcpi_slots(), instead mark them as 0 and skip over them in drm_dp_mst_duplicate_state(). This makes it so drm_dp_atomic_release_vcpi_slots() is still idempotent while also throwing warnings if the driver messes up it's book keeping and tries to release VCPI slots on a port that doesn't have any pre-existing VCPI allocation - danvet - Change mst_state/state in some debugging messages to "mst state" Changes since v2: - Use kmemdup() for duplicating MST state - danvet - Move port validation out of duplicate state callback - danvet - Handle looping through MST topology states in drm_dp_mst_atomic_check() so the driver doesn't have to do it - Fix documentation in drm_dp_atomic_find_vcpi_slots() - Move the atomic check for each individual topology state into it's own function, reduces indenting - Don't consider "stale" MST ports when calculating the bandwidth requirements. This is needed because originally we relied on the state duplication functions to prune any stale ports from the new state, which would prevent us from incorrectly considering their bandwidth requirements alongside legitimate new payloads. - Add function references in drm_dp_atomic_release_vcpi_slots() - danvet - Annotate atomic VCPI and atomic check functions with __must_check - danvet Changes since v1: - Don't use the now-removed ->atomic_check() for private objects hook, just give drivers a function to call themselves Signed-off-by: Lyude Paul Reviewed-by: Daniel Vetter Cc: David Airlie Cc: Jerry Zuo Cc: Harry Wentland Cc: Juston Li Link: https://patchwork.freedesktop.org/patch/msgid/20190111005343.17443-19-lyude@redhat.com --- drivers/gpu/drm/drm_dp_mst_topology.c | 247 +++++++++++++++++++++++++++++----- drivers/gpu/drm/i915/intel_display.c | 4 + drivers/gpu/drm/i915/intel_dp_mst.c | 54 ++++---- include/drm/drm_dp_mst_helper.h | 23 +++- 4 files changed, 266 insertions(+), 62 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_dp_mst.c') diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index e3497bc49494..88db6d7e1a36 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -3011,21 +3011,42 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, } /** - * drm_dp_atomic_find_vcpi_slots() - Find and add vcpi slots to the state + * drm_dp_atomic_find_vcpi_slots() - Find and add VCPI slots to the state * @state: global atomic state * @mgr: MST topology manager for the port * @port: port to find vcpi slots for * @pbn: bandwidth required for the mode in PBN * - * RETURNS: - * Total slots in the atomic state assigned for this port or error + * Allocates VCPI slots to @port, replacing any previous VCPI allocations it + * may have had. Any atomic drivers which support MST must call this function + * in their &drm_encoder_helper_funcs.atomic_check() callback to change the + * current VCPI allocation for the new state, but only when + * &drm_crtc_state.mode_changed or &drm_crtc_state.connectors_changed is set + * to ensure compatibility with userspace applications that still use the + * legacy modesetting UAPI. + * + * Allocations set by this function are not checked against the bandwidth + * restraints of @mgr until the driver calls drm_dp_mst_atomic_check(). + * + * Additionally, it is OK to call this function multiple times on the same + * @port as needed. It is not OK however, to call this function and + * drm_dp_atomic_release_vcpi_slots() in the same atomic check phase. + * + * See also: + * drm_dp_atomic_release_vcpi_slots() + * drm_dp_mst_atomic_check() + * + * Returns: + * Total slots in the atomic state assigned for this port, or a negative error + * code if the port no longer exists */ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn) { struct drm_dp_mst_topology_state *topology_state; - int req_slots; + struct drm_dp_vcpi_allocation *pos, *vcpi = NULL; + int prev_slots, req_slots, ret; topology_state = drm_atomic_get_mst_topology_state(state, mgr); if (IS_ERR(topology_state)) @@ -3034,20 +3055,54 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, port = drm_dp_mst_topology_get_port_validated(mgr, port); if (port == NULL) return -EINVAL; - req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); - DRM_DEBUG_KMS("vcpi slots req=%d, avail=%d\n", - req_slots, topology_state->avail_slots); - if (req_slots > topology_state->avail_slots) { - drm_dp_mst_topology_put_port(port); - return -ENOSPC; + /* Find the current allocation for this port, if any */ + list_for_each_entry(pos, &topology_state->vcpis, next) { + if (pos->port == port) { + vcpi = pos; + prev_slots = vcpi->vcpi; + + /* + * This should never happen, unless the driver tries + * releasing and allocating the same VCPI allocation, + * which is an error + */ + if (WARN_ON(!prev_slots)) { + DRM_ERROR("cannot allocate and release VCPI on [MST PORT:%p] in the same state\n", + port); + return -EINVAL; + } + + break; + } } + if (!vcpi) + prev_slots = 0; + + req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); + + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] [MST PORT:%p] VCPI %d -> %d\n", + port->connector->base.id, port->connector->name, + port, prev_slots, req_slots); + + /* Add the new allocation to the state */ + if (!vcpi) { + vcpi = kzalloc(sizeof(*vcpi), GFP_KERNEL); + if (!vcpi) { + ret = -ENOMEM; + goto out; + } - topology_state->avail_slots -= req_slots; - DRM_DEBUG_KMS("vcpi slots avail=%d", topology_state->avail_slots); + drm_dp_mst_get_port_malloc(port); + vcpi->port = port; + list_add(&vcpi->next, &topology_state->vcpis); + } + vcpi->vcpi = req_slots; + ret = req_slots; +out: drm_dp_mst_topology_put_port(port); - return req_slots; + return ret; } EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); @@ -3055,31 +3110,57 @@ EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); * drm_dp_atomic_release_vcpi_slots() - Release allocated vcpi slots * @state: global atomic state * @mgr: MST topology manager for the port - * @slots: number of vcpi slots to release + * @port: The port to release the VCPI slots from * - * RETURNS: - * 0 if @slots were added back to &drm_dp_mst_topology_state->avail_slots or - * negative error code + * Releases any VCPI slots that have been allocated to a port in the atomic + * state. Any atomic drivers which support MST must call this function in + * their &drm_connector_helper_funcs.atomic_check() callback when the + * connector will no longer have VCPI allocated (e.g. because it's CRTC was + * removed) when it had VCPI allocated in the previous atomic state. + * + * It is OK to call this even if @port has been removed from the system. + * Additionally, it is OK to call this function multiple times on the same + * @port as needed. It is not OK however, to call this function and + * drm_dp_atomic_find_vcpi_slots() on the same @port in a single atomic check + * phase. + * + * See also: + * drm_dp_atomic_find_vcpi_slots() + * drm_dp_mst_atomic_check() + * + * Returns: + * 0 if all slots for this port were added back to + * &drm_dp_mst_topology_state.avail_slots or negative error code */ int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr, - int slots) + struct drm_dp_mst_port *port) { struct drm_dp_mst_topology_state *topology_state; + struct drm_dp_vcpi_allocation *pos; + bool found = false; topology_state = drm_atomic_get_mst_topology_state(state, mgr); if (IS_ERR(topology_state)) return PTR_ERR(topology_state); - /* We cannot rely on port->vcpi.num_slots to update - * topology_state->avail_slots as the port may not exist if the parent - * branch device was unplugged. This should be fixed by tracking - * per-port slot allocation in drm_dp_mst_topology_state instead of - * depending on the caller to tell us how many slots to release. - */ - topology_state->avail_slots += slots; - DRM_DEBUG_KMS("vcpi slots released=%d, avail=%d\n", - slots, topology_state->avail_slots); + list_for_each_entry(pos, &topology_state->vcpis, next) { + if (pos->port == port) { + found = true; + break; + } + } + if (WARN_ON(!found)) { + DRM_ERROR("no VCPI for [MST PORT:%p] found in mst state %p\n", + port, &topology_state->base); + return -EINVAL; + } + + DRM_DEBUG_ATOMIC("[MST PORT:%p] VCPI %d -> 0\n", port, pos->vcpi); + if (pos->vcpi) { + drm_dp_mst_put_port_malloc(port); + pos->vcpi = 0; + } return 0; } @@ -3501,15 +3582,41 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) static struct drm_private_state * drm_dp_mst_duplicate_state(struct drm_private_obj *obj) { - struct drm_dp_mst_topology_state *state; + struct drm_dp_mst_topology_state *state, *old_state = + to_dp_mst_topology_state(obj->state); + struct drm_dp_vcpi_allocation *pos, *vcpi; - state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); + state = kmemdup(old_state, sizeof(*state), GFP_KERNEL); if (!state) return NULL; __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); + INIT_LIST_HEAD(&state->vcpis); + + list_for_each_entry(pos, &old_state->vcpis, next) { + /* Prune leftover freed VCPI allocations */ + if (!pos->vcpi) + continue; + + vcpi = kmemdup(pos, sizeof(*vcpi), GFP_KERNEL); + if (!vcpi) + goto fail; + + drm_dp_mst_get_port_malloc(vcpi->port); + list_add(&vcpi->next, &state->vcpis); + } + return &state->base; + +fail: + list_for_each_entry_safe(pos, vcpi, &state->vcpis, next) { + drm_dp_mst_put_port_malloc(pos->port); + kfree(pos); + } + kfree(state); + + return NULL; } static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, @@ -3517,10 +3624,88 @@ static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, { struct drm_dp_mst_topology_state *mst_state = to_dp_mst_topology_state(state); + struct drm_dp_vcpi_allocation *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, &mst_state->vcpis, next) { + /* We only keep references to ports with non-zero VCPIs */ + if (pos->vcpi) + drm_dp_mst_put_port_malloc(pos->port); + kfree(pos); + } kfree(mst_state); } +static inline int +drm_dp_mst_atomic_check_topology_state(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state) +{ + struct drm_dp_vcpi_allocation *vcpi; + int avail_slots = 63; + + list_for_each_entry(vcpi, &mst_state->vcpis, next) { + /* Releasing VCPI is always OK-even if the port is gone */ + if (!vcpi->vcpi) { + DRM_DEBUG_ATOMIC("[MST PORT:%p] releases all VCPI slots\n", + vcpi->port); + continue; + } + + DRM_DEBUG_ATOMIC("[MST PORT:%p] requires %d vcpi slots\n", + vcpi->port, vcpi->vcpi); + + avail_slots -= vcpi->vcpi; + if (avail_slots < 0) { + DRM_DEBUG_ATOMIC("[MST PORT:%p] not enough VCPI slots in mst state %p (avail=%d)\n", + vcpi->port, mst_state, + avail_slots + vcpi->vcpi); + return -ENOSPC; + } + } + DRM_DEBUG_ATOMIC("[MST MGR:%p] mst state %p VCPI avail=%d used=%d\n", + mgr, mst_state, avail_slots, + 63 - avail_slots); + + return 0; +} + +/** + * drm_dp_mst_atomic_check - Check that the new state of an MST topology in an + * atomic update is valid + * @state: Pointer to the new &struct drm_dp_mst_topology_state + * + * Checks the given topology state for an atomic update to ensure that it's + * valid. This includes checking whether there's enough bandwidth to support + * the new VCPI allocations in the atomic update. + * + * Any atomic drivers supporting DP MST must make sure to call this after + * checking the rest of their state in their + * &drm_mode_config_funcs.atomic_check() callback. + * + * See also: + * drm_dp_atomic_find_vcpi_slots() + * drm_dp_atomic_release_vcpi_slots() + * + * Returns: + * + * 0 if the new state is valid, negative error code otherwise. + */ +int drm_dp_mst_atomic_check(struct drm_atomic_state *state) +{ + struct drm_dp_mst_topology_mgr *mgr; + struct drm_dp_mst_topology_state *mst_state; + int i, ret = 0; + + for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { + ret = drm_dp_mst_atomic_check_topology_state(mgr, mst_state); + if (ret) + break; + } + + return ret; +} +EXPORT_SYMBOL(drm_dp_mst_atomic_check); + const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs = { .atomic_duplicate_state = drm_dp_mst_duplicate_state, .atomic_destroy_state = drm_dp_mst_destroy_state, @@ -3603,9 +3788,7 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, return -ENOMEM; mst_state->mgr = mgr; - - /* max. time slots - one slot for MTP header */ - mst_state->avail_slots = 63; + INIT_LIST_HEAD(&mst_state->vcpis); drm_atomic_private_obj_init(dev, &mgr->base, &mst_state->base, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 812ec5ae5c7b..5a679af03a04 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12623,6 +12623,10 @@ static int intel_atomic_check(struct drm_device *dev, "[modeset]" : "[fastset]"); } + ret = drm_dp_mst_atomic_check(state); + if (ret) + return ret; + if (any_ms) { ret = intel_modeset_checks(state); diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 631fd1537252..c8e2215628e6 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -41,8 +41,12 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, struct drm_connector *connector = conn_state->connector; void *port = to_intel_connector(connector)->port; struct drm_atomic_state *state = pipe_config->base.state; + struct drm_crtc *crtc = pipe_config->base.crtc; + struct drm_crtc_state *old_crtc_state = + drm_atomic_get_old_crtc_state(state, crtc); int bpp; - int lane_count, slots = 0; + int lane_count, slots = + to_intel_crtc_state(old_crtc_state)->dp_m_n.tu; const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; int mst_pbn; bool constant_n = drm_dp_has_quirk(&intel_dp->desc, @@ -107,35 +111,39 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, return true; } -static int intel_dp_mst_atomic_check(struct drm_connector *connector, - struct drm_connector_state *new_conn_state) +static int +intel_dp_mst_atomic_check(struct drm_connector *connector, + struct drm_connector_state *new_conn_state) { struct drm_atomic_state *state = new_conn_state->state; - struct drm_connector_state *old_conn_state; - struct drm_crtc *old_crtc; + struct drm_connector_state *old_conn_state = + drm_atomic_get_old_connector_state(state, connector); + struct intel_connector *intel_connector = + to_intel_connector(connector); + struct drm_crtc *new_crtc = new_conn_state->crtc; struct drm_crtc_state *crtc_state; - int slots, ret = 0; + struct drm_dp_mst_topology_mgr *mgr; + int ret = 0; - old_conn_state = drm_atomic_get_old_connector_state(state, connector); - old_crtc = old_conn_state->crtc; - if (!old_crtc) - return ret; - - crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc); - slots = to_intel_crtc_state(crtc_state)->dp_m_n.tu; - if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { - struct drm_dp_mst_topology_mgr *mgr; - struct drm_encoder *old_encoder; + if (!old_conn_state->crtc) + return 0; - old_encoder = old_conn_state->best_encoder; - mgr = &enc_to_mst(old_encoder)->primary->dp.mst_mgr; + /* We only want to free VCPI if this state disables the CRTC on this + * connector + */ + if (new_crtc) { + crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); - ret = drm_dp_atomic_release_vcpi_slots(state, mgr, slots); - if (ret) - DRM_DEBUG_KMS("failed releasing %d vcpi slots:%d\n", slots, ret); - else - to_intel_crtc_state(crtc_state)->dp_m_n.tu = 0; + if (!crtc_state || + !drm_atomic_crtc_needs_modeset(crtc_state) || + crtc_state->enable) + return 0; } + + mgr = &enc_to_mst(old_conn_state->best_encoder)->primary->dp.mst_mgr; + ret = drm_dp_atomic_release_vcpi_slots(state, mgr, + intel_connector->port); + return ret; } diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 581163c8d7d7..451d020f0137 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -425,9 +425,15 @@ struct drm_dp_payload { #define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base) +struct drm_dp_vcpi_allocation { + struct drm_dp_mst_port *port; + int vcpi; + struct list_head next; +}; + struct drm_dp_mst_topology_state { struct drm_private_state base; - int avail_slots; + struct list_head vcpis; struct drm_dp_mst_topology_mgr *mgr; }; @@ -638,14 +644,17 @@ void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr); -int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, - struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_port *port, int pbn); -int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, - struct drm_dp_mst_topology_mgr *mgr, - int slots); +int __must_check +drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, int pbn); +int __must_check +drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port); int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, bool power_up); +int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state); void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port); void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port); -- cgit v1.2.3 From 96550555a78ca3c9fda4b358549a5622810fe32c Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 15 Jan 2019 15:08:00 -0500 Subject: drm/i915: Pass down rc in intel_encoder->compute_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Something that I completely missed when implementing the new MST VCPI atomic helpers is that with those helpers, there's technically a chance of us having to grab additional modeset locks in ->compute_config() and furthermore, that means we have the potential to hit a normal modeset deadlock. However, because ->compute_config() only returns a bool this means we can't return -EDEADLK when we need to drop locks and try again which means we end up just failing the atomic check permanently. Whoops. So, fix this by modifying ->compute_config() to pass down an actual error code instead of a bool so that the atomic check can be restarted on modeset deadlocks. Thanks to Ville Syrjälä for pointing this out! Changes since v1: * Add some newlines * Return only -EINVAL from hsw_crt_compute_config() * Propogate return code from intel_dp_compute_dsc_params() * Change all of the intel_dp_compute_link_config*() variants * Don't miss if (hdmi_port_clock_valid()) branch in intel_hdmi_compute_config() Signed-off-by: Lyude Paul Cc: Ville Syrjälä Fixes: eceae1472467 ("drm/dp_mst: Start tracking per-port VCPI allocations") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=109320 Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20190115200800.3121-1-lyude@redhat.com --- drivers/gpu/drm/i915/icl_dsi.c | 8 ++-- drivers/gpu/drm/i915/intel_crt.c | 35 +++++++++--------- drivers/gpu/drm/i915/intel_ddi.c | 6 +-- drivers/gpu/drm/i915/intel_display.c | 11 ++++-- drivers/gpu/drm/i915/intel_dp.c | 71 +++++++++++++++++++----------------- drivers/gpu/drm/i915/intel_dp_mst.c | 12 +++--- drivers/gpu/drm/i915/intel_drv.h | 18 ++++----- drivers/gpu/drm/i915/intel_dvo.c | 11 +++--- drivers/gpu/drm/i915/intel_hdmi.c | 14 +++---- drivers/gpu/drm/i915/intel_lvds.c | 12 +++--- drivers/gpu/drm/i915/intel_sdvo.c | 14 +++---- drivers/gpu/drm/i915/intel_tv.c | 8 ++-- drivers/gpu/drm/i915/vlv_dsi.c | 14 +++---- 13 files changed, 122 insertions(+), 112 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_dp_mst.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 4dd793b78996..d9dcee4ec51f 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -1178,9 +1178,9 @@ static void gen11_dsi_get_config(struct intel_encoder *encoder, pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI); } -static bool gen11_dsi_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int gen11_dsi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, base); @@ -1205,7 +1205,7 @@ static bool gen11_dsi_compute_config(struct intel_encoder *encoder, pipe_config->clock_set = true; pipe_config->port_clock = intel_dsi_bitrate(intel_dsi) / 5; - return true; + return 0; } static u64 gen11_dsi_get_power_domains(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 68f2fb89ece3..2e0fd9927db2 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -344,51 +344,52 @@ intel_crt_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool intel_crt_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_crt_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - return true; + + return 0; } -static bool pch_crt_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int pch_crt_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; pipe_config->has_pch_encoder = true; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - return true; + return 0; } -static bool hsw_crt_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int hsw_crt_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; /* HSW/BDW FDI limited to 4k */ if (adjusted_mode->crtc_hdisplay > 4096 || adjusted_mode->crtc_hblank_start > 4096) - return false; + return -EINVAL; pipe_config->has_pch_encoder = true; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; @@ -397,7 +398,7 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder, if (HAS_PCH_LPT(dev_priv)) { if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) { DRM_DEBUG_KMS("LPT only supports 24bpp\n"); - return false; + return -EINVAL; } pipe_config->pipe_bpp = 24; @@ -406,7 +407,7 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder, /* FDI must always be 2.7 GHz */ pipe_config->port_clock = 135000 * 2; - return true; + return 0; } static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index f3e1d6a0b7dd..fd06d1fd39d3 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -3875,9 +3875,9 @@ intel_ddi_compute_output_type(struct intel_encoder *encoder, } } -static bool intel_ddi_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_ddi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = encoder->port; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 20beb1977a27..52c63135bc65 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11517,10 +11517,13 @@ encoder_retry: continue; encoder = to_intel_encoder(connector_state->best_encoder); - - if (!(encoder->compute_config(encoder, pipe_config, connector_state))) { - DRM_DEBUG_KMS("Encoder config failure\n"); - return -EINVAL; + ret = encoder->compute_config(encoder, pipe_config, + connector_state); + if (ret < 0) { + if (ret != -EDEADLK) + DRM_DEBUG_KMS("Encoder config failure: %d\n", + ret); + return ret; } } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fdd2cbc56fa3..d18b72b5f0b8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1808,7 +1808,7 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp, } /* Optimize link config in order: max bpp, min clock, min lanes */ -static bool +static int intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, struct intel_crtc_state *pipe_config, const struct link_config_limits *limits) @@ -1834,17 +1834,17 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, pipe_config->pipe_bpp = bpp; pipe_config->port_clock = link_clock; - return true; + return 0; } } } } - return false; + return -EINVAL; } /* Optimize link config in order: max bpp, min lanes, min clock */ -static bool +static int intel_dp_compute_link_config_fast(struct intel_dp *intel_dp, struct intel_crtc_state *pipe_config, const struct link_config_limits *limits) @@ -1870,13 +1870,13 @@ intel_dp_compute_link_config_fast(struct intel_dp *intel_dp, pipe_config->pipe_bpp = bpp; pipe_config->port_clock = link_clock; - return true; + return 0; } } } } - return false; + return -EINVAL; } static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc) @@ -1894,19 +1894,20 @@ static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc) return 0; } -static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state, - struct link_config_limits *limits) +static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state, + struct link_config_limits *limits) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; u8 dsc_max_bpc; int pipe_bpp; + int ret; if (!intel_dp_supports_dsc(intel_dp, pipe_config)) - return false; + return -EINVAL; dsc_max_bpc = min_t(u8, DP_DSC_MAX_SUPPORTED_BPC, conn_state->max_requested_bpc); @@ -1914,7 +1915,7 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, dsc_max_bpc); if (pipe_bpp < DP_DSC_MIN_SUPPORTED_BPC * 3) { DRM_DEBUG_KMS("No DSC support for less than 8bpc\n"); - return false; + return -EINVAL; } /* @@ -1948,7 +1949,7 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, adjusted_mode->crtc_hdisplay); if (!dsc_max_output_bpp || !dsc_dp_slice_count) { DRM_DEBUG_KMS("Compressed BPP/Slice Count not supported\n"); - return false; + return -EINVAL; } pipe_config->dsc_params.compressed_bpp = min_t(u16, dsc_max_output_bpp >> 4, @@ -1965,16 +1966,19 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_config->dsc_params.dsc_split = true; } else { DRM_DEBUG_KMS("Cannot split stream to use 2 VDSC instances\n"); - return false; + return -EINVAL; } } - if (intel_dp_compute_dsc_params(intel_dp, pipe_config) < 0) { + + ret = intel_dp_compute_dsc_params(intel_dp, pipe_config); + if (ret < 0) { DRM_DEBUG_KMS("Cannot compute valid DSC parameters for Input Bpp = %d " "Compressed BPP = %d\n", pipe_config->pipe_bpp, pipe_config->dsc_params.compressed_bpp); - return false; + return ret; } + pipe_config->dsc_params.compression_enable = true; DRM_DEBUG_KMS("DP DSC computed with Input Bpp = %d " "Compressed Bpp = %d Slice Count = %d\n", @@ -1982,10 +1986,10 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_config->dsc_params.compressed_bpp, pipe_config->dsc_params.slice_count); - return true; + return 0; } -static bool +static int intel_dp_compute_link_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) @@ -1994,7 +1998,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); struct link_config_limits limits; int common_len; - bool ret; + int ret; common_len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->max_link_rate); @@ -2051,10 +2055,11 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, &limits); /* enable compression if the mode doesn't fit available BW */ - if (!ret) { - if (!intel_dp_dsc_compute_config(intel_dp, pipe_config, - conn_state, &limits)) - return false; + if (ret) { + ret = intel_dp_dsc_compute_config(intel_dp, pipe_config, + conn_state, &limits); + if (ret < 0) + return ret; } if (pipe_config->dsc_params.compression_enable) { @@ -2079,10 +2084,10 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, intel_dp_max_data_rate(pipe_config->port_clock, pipe_config->lane_count)); } - return true; + return 0; } -bool +int intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) @@ -2098,6 +2103,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, to_intel_digital_connector_state(conn_state); bool constant_n = drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_CONSTANT_N); + int ret; if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A) pipe_config->has_pch_encoder = true; @@ -2119,8 +2125,6 @@ intel_dp_compute_config(struct intel_encoder *encoder, adjusted_mode); if (INTEL_GEN(dev_priv) >= 9) { - int ret; - ret = skl_update_scaler_crtc(pipe_config); if (ret) return ret; @@ -2135,20 +2139,21 @@ intel_dp_compute_config(struct intel_encoder *encoder, } if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; if (HAS_GMCH_DISPLAY(dev_priv) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) - return false; + return -EINVAL; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) - return false; + return -EINVAL; pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) && intel_dp_supports_fec(intel_dp, pipe_config); - if (!intel_dp_compute_link_config(encoder, pipe_config, conn_state)) - return false; + ret = intel_dp_compute_link_config(encoder, pipe_config, conn_state); + if (ret < 0) + return ret; if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) { /* @@ -2196,7 +2201,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_psr_compute_config(intel_dp, pipe_config); - return true; + return 0; } void intel_dp_set_link_params(struct intel_dp *intel_dp, diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index c8e2215628e6..5899debe2184 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -30,9 +30,9 @@ #include #include -static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_dp_mst_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); @@ -53,7 +53,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, DP_DPCD_QUIRK_CONSTANT_N); if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; pipe_config->has_pch_encoder = false; @@ -90,7 +90,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, if (slots < 0) { DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", slots); - return false; + return slots; } } @@ -108,7 +108,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); - return true; + return 0; } static int diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a3252064b8d2..19d9abd2666e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -222,9 +222,9 @@ struct intel_encoder { enum intel_output_type (*compute_output_type)(struct intel_encoder *, struct intel_crtc_state *, struct drm_connector_state *); - bool (*compute_config)(struct intel_encoder *, - struct intel_crtc_state *, - struct drm_connector_state *); + int (*compute_config)(struct intel_encoder *, + struct intel_crtc_state *, + struct drm_connector_state *); void (*pre_pll_enable)(struct intel_encoder *, const struct intel_crtc_state *, const struct drm_connector_state *); @@ -1806,9 +1806,9 @@ void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp, void intel_dp_encoder_reset(struct drm_encoder *encoder); void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder); void intel_dp_encoder_destroy(struct drm_encoder *encoder); -bool intel_dp_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state); +int intel_dp_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state); bool intel_dp_is_edp(struct intel_dp *intel_dp); bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port); enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, @@ -1966,9 +1966,9 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv, i915_reg_t hdmi_reg, void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector); struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); -bool intel_hdmi_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state); +int intel_hdmi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state); bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder, struct drm_connector *connector, bool high_tmds_clock_ratio, diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 0042a7f69387..17a16917e134 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -235,9 +235,9 @@ intel_dvo_mode_valid(struct drm_connector *connector, return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode); } -static bool intel_dvo_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_dvo_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct intel_dvo *intel_dvo = enc_to_dvo(encoder); const struct drm_display_mode *fixed_mode = @@ -254,10 +254,11 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder, intel_fixed_panel_mode(fixed_mode, adjusted_mode); if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - return true; + + return 0; } static void intel_dvo_pre_enable(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 55aeb97dd66d..1da7bb148fca 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1703,9 +1703,9 @@ intel_hdmi_ycbcr420_config(struct drm_connector *connector, return true; } -bool intel_hdmi_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +int intel_hdmi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -1721,7 +1721,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink; @@ -1752,7 +1752,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, &clock_12bpc, &clock_10bpc, &clock_8bpc)) { DRM_ERROR("Can't support YCBCR420 output\n"); - return false; + return -EINVAL; } } @@ -1802,7 +1802,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock, false, force_dvi) != MODE_OK) { DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n"); - return false; + return -EINVAL; } /* Set user selected PAR to incoming mode's member */ @@ -1821,7 +1821,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, } } - return true; + return 0; } static void diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index e6c5d985ea0a..3377d813dbb3 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -379,9 +379,9 @@ intel_lvds_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_lvds_compute_config(struct intel_encoder *intel_encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); struct intel_lvds_encoder *lvds_encoder = @@ -395,7 +395,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, /* Should never happen!! */ if (INTEL_GEN(dev_priv) < 4 && intel_crtc->pipe == 0) { DRM_ERROR("Can't support LVDS on pipe A\n"); - return false; + return -EINVAL; } if (lvds_encoder->a3_power == LVDS_A3_POWER_UP) @@ -421,7 +421,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, adjusted_mode); if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; if (HAS_PCH_SPLIT(dev_priv)) { pipe_config->has_pch_encoder = true; @@ -440,7 +440,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, * user's requested refresh rate. */ - return true; + return 0; } static enum drm_connector_status diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 669fa9faad70..4a03b7f67dd5 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1108,9 +1108,9 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config) pipe_config->clock_set = true; } -static bool intel_sdvo_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_sdvo_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct intel_sdvo *intel_sdvo = to_sdvo(encoder); struct intel_sdvo_connector_state *intel_sdvo_state = @@ -1135,7 +1135,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, */ if (IS_TV(intel_sdvo_connector)) { if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode)) - return false; + return -EINVAL; (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, intel_sdvo_connector, @@ -1145,7 +1145,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, } else if (IS_LVDS(intel_sdvo_connector)) { if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, intel_sdvo_connector->base.panel.fixed_mode)) - return false; + return -EINVAL; (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, intel_sdvo_connector, @@ -1154,7 +1154,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, } if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; /* * Make the CRTC code factor in the SDVO pixel multiplier. The @@ -1194,7 +1194,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, if (intel_sdvo_connector->is_hdmi) adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio; - return true; + return 0; } #define UPDATE_PROPERTY(input, NAME) \ diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 860f306a23ba..9bbe35a0f0f2 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -870,7 +870,7 @@ intel_tv_get_config(struct intel_encoder *encoder, pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock; } -static bool +static int intel_tv_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) @@ -880,10 +880,10 @@ intel_tv_compute_config(struct intel_encoder *encoder, &pipe_config->base.adjusted_mode; if (!tv_mode) - return false; + return -EINVAL; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; adjusted_mode->crtc_clock = tv_mode->clock; @@ -898,7 +898,7 @@ intel_tv_compute_config(struct intel_encoder *encoder, * or whether userspace is doing something stupid. */ - return true; + return 0; } static void diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c index 361e962a7969..9fc8085f76dc 100644 --- a/drivers/gpu/drm/i915/vlv_dsi.c +++ b/drivers/gpu/drm/i915/vlv_dsi.c @@ -257,9 +257,9 @@ static void band_gap_reset(struct drm_i915_private *dev_priv) mutex_unlock(&dev_priv->sb_lock); } -static bool intel_dsi_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_dsi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, @@ -285,7 +285,7 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, } if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; /* DSI uses short packets for sync events, so clear mode flags for DSI */ adjusted_mode->flags = 0; @@ -303,16 +303,16 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, ret = bxt_dsi_pll_compute(encoder, pipe_config); if (ret) - return false; + return -EINVAL; } else { ret = vlv_dsi_pll_compute(encoder, pipe_config); if (ret) - return false; + return -EINVAL; } pipe_config->clock_set = true; - return true; + return 0; } static bool glk_dsi_enable_io(struct intel_encoder *encoder) -- cgit v1.2.3