2014-05-02 12:02:48 +08:00
|
|
|
/*
|
|
|
|
* Copyright © 2008 Intel Corporation
|
|
|
|
* 2014 Red Hat Inc.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2015-01-23 08:50:32 +08:00
|
|
|
#include <drm/drm_atomic_helper.h>
|
2014-05-02 12:02:48 +08:00
|
|
|
#include <drm/drm_edid.h>
|
2019-01-18 05:03:34 +08:00
|
|
|
#include <drm/drm_probe_helper.h>
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2019-04-05 19:00:03 +08:00
|
|
|
#include "i915_drv.h"
|
2019-04-29 20:53:31 +08:00
|
|
|
#include "intel_atomic.h"
|
2019-04-05 19:00:03 +08:00
|
|
|
#include "intel_audio.h"
|
2019-04-05 19:00:06 +08:00
|
|
|
#include "intel_connector.h"
|
2019-04-05 19:00:05 +08:00
|
|
|
#include "intel_ddi.h"
|
2019-08-06 19:39:33 +08:00
|
|
|
#include "intel_display_types.h"
|
2019-04-05 19:00:17 +08:00
|
|
|
#include "intel_dp.h"
|
2019-04-29 20:29:33 +08:00
|
|
|
#include "intel_dp_mst.h"
|
2019-05-02 23:02:40 +08:00
|
|
|
#include "intel_dpio_phy.h"
|
2019-04-05 19:00:03 +08:00
|
|
|
|
2019-03-26 22:25:53 +08:00
|
|
|
static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
|
|
|
|
struct intel_crtc_state *crtc_state,
|
|
|
|
struct drm_connector_state *conn_state,
|
|
|
|
struct link_config_limits *limits)
|
|
|
|
{
|
2019-10-31 19:26:03 +08:00
|
|
|
struct drm_atomic_state *state = crtc_state->uapi.state;
|
2019-12-05 02:05:43 +08:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2019-03-26 22:25:53 +08:00
|
|
|
struct intel_dp *intel_dp = &intel_mst->primary->dp;
|
|
|
|
struct intel_connector *connector =
|
|
|
|
to_intel_connector(conn_state->connector);
|
drm/i915/dp_mst: use struct drm_device based logging
Convert all the DRM_* logging macros to the struct drm_device based
macros to provide device specific logging.
No functional changes.
Generated using the following semantic patch, originally written by
Wambui Karuga <wambui.karugax@gmail.com>, with manual fixups on top:
@@
identifier fn, T;
@@
fn(...,struct drm_i915_private *T,...) {
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
@@
identifier fn, T;
@@
fn(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
Cc: Wambui Karuga <wambui.karugax@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5ee3b8040658b5b4ef0b8b1a546fa04f554cdf6a.1584714939.git.jani.nikula@intel.com
2020-03-20 22:36:29 +08:00
|
|
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
2019-03-26 22:25:53 +08:00
|
|
|
const struct drm_display_mode *adjusted_mode =
|
2019-10-31 19:26:02 +08:00
|
|
|
&crtc_state->hw.adjusted_mode;
|
2020-02-12 02:33:46 +08:00
|
|
|
bool constant_n = drm_dp_has_quirk(&intel_dp->desc, 0,
|
2019-03-26 22:25:53 +08:00
|
|
|
DP_DPCD_QUIRK_CONSTANT_N);
|
|
|
|
int bpp, slots = -EINVAL;
|
|
|
|
|
|
|
|
crtc_state->lane_count = limits->max_lane_count;
|
|
|
|
crtc_state->port_clock = limits->max_clock;
|
|
|
|
|
|
|
|
for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
|
|
|
|
crtc_state->pipe_bpp = bpp;
|
|
|
|
|
|
|
|
crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock,
|
2019-08-21 22:33:26 +08:00
|
|
|
crtc_state->pipe_bpp,
|
|
|
|
false);
|
2019-03-26 22:25:53 +08:00
|
|
|
|
|
|
|
slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr,
|
2020-03-11 04:27:52 +08:00
|
|
|
connector->port,
|
|
|
|
crtc_state->pbn, 0);
|
2019-03-26 22:25:53 +08:00
|
|
|
if (slots == -EDEADLK)
|
|
|
|
return slots;
|
|
|
|
if (slots >= 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (slots < 0) {
|
drm/i915/dp_mst: use struct drm_device based logging
Convert all the DRM_* logging macros to the struct drm_device based
macros to provide device specific logging.
No functional changes.
Generated using the following semantic patch, originally written by
Wambui Karuga <wambui.karugax@gmail.com>, with manual fixups on top:
@@
identifier fn, T;
@@
fn(...,struct drm_i915_private *T,...) {
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
@@
identifier fn, T;
@@
fn(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
Cc: Wambui Karuga <wambui.karugax@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5ee3b8040658b5b4ef0b8b1a546fa04f554cdf6a.1584714939.git.jani.nikula@intel.com
2020-03-20 22:36:29 +08:00
|
|
|
drm_dbg_kms(&i915->drm, "failed finding vcpi slots:%d\n",
|
|
|
|
slots);
|
2019-03-26 22:25:53 +08:00
|
|
|
return slots;
|
|
|
|
}
|
|
|
|
|
|
|
|
intel_link_compute_m_n(crtc_state->pipe_bpp,
|
|
|
|
crtc_state->lane_count,
|
|
|
|
adjusted_mode->crtc_clock,
|
|
|
|
crtc_state->port_clock,
|
|
|
|
&crtc_state->dp_m_n,
|
2019-09-25 16:21:09 +08:00
|
|
|
constant_n, crtc_state->fec_enable);
|
2019-03-26 22:25:53 +08:00
|
|
|
crtc_state->dp_m_n.tu = slots;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-16 04:08:00 +08:00
|
|
|
static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
|
|
|
struct intel_crtc_state *pipe_config,
|
|
|
|
struct drm_connector_state *conn_state)
|
2014-05-02 12:02:48 +08:00
|
|
|
{
|
2017-10-24 17:52:14 +08:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
2019-12-05 02:05:43 +08:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2019-03-26 22:25:53 +08:00
|
|
|
struct intel_dp *intel_dp = &intel_mst->primary->dp;
|
|
|
|
struct intel_connector *connector =
|
|
|
|
to_intel_connector(conn_state->connector);
|
2019-03-27 21:19:29 +08:00
|
|
|
struct intel_digital_connector_state *intel_conn_state =
|
|
|
|
to_intel_digital_connector_state(conn_state);
|
2019-03-26 22:25:53 +08:00
|
|
|
const struct drm_display_mode *adjusted_mode =
|
2019-10-31 19:26:02 +08:00
|
|
|
&pipe_config->hw.adjusted_mode;
|
2019-03-26 22:25:53 +08:00
|
|
|
struct link_config_limits limits;
|
|
|
|
int ret;
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2018-05-24 20:54:03 +08:00
|
|
|
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
2019-01-16 04:08:00 +08:00
|
|
|
return -EINVAL;
|
2018-05-24 20:54:03 +08:00
|
|
|
|
2018-10-12 14:23:07 +08:00
|
|
|
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
|
2014-05-02 12:02:48 +08:00
|
|
|
pipe_config->has_pch_encoder = false;
|
2019-03-27 21:19:29 +08:00
|
|
|
|
|
|
|
if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
|
|
|
|
pipe_config->has_audio =
|
2020-03-11 04:27:52 +08:00
|
|
|
drm_dp_mst_port_has_audio(&intel_dp->mst_mgr,
|
|
|
|
connector->port);
|
2019-03-27 21:19:29 +08:00
|
|
|
else
|
|
|
|
pipe_config->has_audio =
|
|
|
|
intel_conn_state->force_audio == HDMI_AUDIO_ON;
|
|
|
|
|
2014-05-02 12:02:48 +08:00
|
|
|
/*
|
|
|
|
* for MST we always configure max link bw - the spec doesn't
|
|
|
|
* seem to suggest we should do otherwise.
|
|
|
|
*/
|
2019-03-26 22:25:53 +08:00
|
|
|
limits.min_clock =
|
|
|
|
limits.max_clock = intel_dp_max_link_rate(intel_dp);
|
2015-03-12 23:10:36 +08:00
|
|
|
|
2019-03-26 22:25:53 +08:00
|
|
|
limits.min_lane_count =
|
|
|
|
limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2019-03-26 22:25:56 +08:00
|
|
|
limits.min_bpp = intel_dp_min_bpp(pipe_config);
|
2019-08-28 18:20:59 +08:00
|
|
|
/*
|
|
|
|
* FIXME: If all the streams can't fit into the link with
|
|
|
|
* their current pipe_bpp we should reduce pipe_bpp across
|
|
|
|
* the board until things start to fit. Until then we
|
|
|
|
* limit to <= 8bpc since that's what was hardcoded for all
|
|
|
|
* MST streams previously. This hack should be removed once
|
|
|
|
* we have the proper retry logic in place.
|
|
|
|
*/
|
|
|
|
limits.max_bpp = min(pipe_config->pipe_bpp, 24);
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2019-03-26 22:25:53 +08:00
|
|
|
intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits);
|
|
|
|
|
|
|
|
ret = intel_dp_mst_compute_link_config(encoder, pipe_config,
|
|
|
|
conn_state, &limits);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2015-03-20 22:18:13 +08:00
|
|
|
|
2019-03-26 22:25:51 +08:00
|
|
|
pipe_config->limited_color_range =
|
|
|
|
intel_dp_limited_color_range(pipe_config, conn_state);
|
|
|
|
|
2017-10-27 21:43:48 +08:00
|
|
|
if (IS_GEN9_LP(dev_priv))
|
|
|
|
pipe_config->lane_lat_optim_mask =
|
|
|
|
bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count);
|
|
|
|
|
2017-10-24 17:52:14 +08:00
|
|
|
intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
|
|
|
|
|
2020-03-14 00:48:19 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Iterate over all connectors and return a mask of
|
|
|
|
* all CPU transcoders streaming over the same DP link.
|
|
|
|
*/
|
|
|
|
static unsigned int
|
|
|
|
intel_dp_mst_transcoder_mask(struct intel_atomic_state *state,
|
|
|
|
struct intel_dp *mst_port)
|
|
|
|
{
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
|
|
|
const struct intel_digital_connector_state *conn_state;
|
|
|
|
struct intel_connector *connector;
|
|
|
|
u8 transcoders = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (INTEL_GEN(dev_priv) < 12)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for_each_new_intel_connector_in_state(state, connector, conn_state, i) {
|
|
|
|
const struct intel_crtc_state *crtc_state;
|
|
|
|
struct intel_crtc *crtc;
|
|
|
|
|
|
|
|
if (connector->mst_port != mst_port || !conn_state->base.crtc)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
crtc = to_intel_crtc(conn_state->base.crtc);
|
|
|
|
crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
|
|
|
|
|
|
|
|
if (!crtc_state->hw.active)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
transcoders |= BIT(crtc_state->cpu_transcoder);
|
|
|
|
}
|
|
|
|
|
|
|
|
return transcoders;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_dp_mst_compute_config_late(struct intel_encoder *encoder,
|
|
|
|
struct intel_crtc_state *crtc_state,
|
|
|
|
struct drm_connector_state *conn_state)
|
|
|
|
{
|
|
|
|
struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state);
|
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
|
|
|
struct intel_dp *intel_dp = &intel_mst->primary->dp;
|
|
|
|
|
|
|
|
/* lowest numbered transcoder will be designated master */
|
|
|
|
crtc_state->mst_master_transcoder =
|
|
|
|
ffs(intel_dp_mst_transcoder_mask(state, intel_dp)) - 1;
|
2019-12-23 09:06:49 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If one of the connectors in a MST stream needs a modeset, mark all CRTCs
|
|
|
|
* that shares the same MST stream as mode changed,
|
|
|
|
* intel_modeset_pipe_config()+intel_crtc_check_fastset() will take care to do
|
|
|
|
* a fastset when possible.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
intel_dp_mst_atomic_master_trans_check(struct intel_connector *connector,
|
|
|
|
struct intel_atomic_state *state)
|
|
|
|
{
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
|
|
|
struct drm_connector_list_iter connector_list_iter;
|
|
|
|
struct intel_connector *connector_iter;
|
|
|
|
|
|
|
|
if (INTEL_GEN(dev_priv) < 12)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!intel_connector_needs_modeset(state, &connector->base))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
drm_connector_list_iter_begin(&dev_priv->drm, &connector_list_iter);
|
|
|
|
for_each_intel_connector_iter(connector_iter, &connector_list_iter) {
|
|
|
|
struct intel_digital_connector_state *conn_iter_state;
|
|
|
|
struct intel_crtc_state *crtc_state;
|
|
|
|
struct intel_crtc *crtc;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (connector_iter->mst_port != connector->mst_port ||
|
|
|
|
connector_iter == connector)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
conn_iter_state = intel_atomic_get_digital_connector_state(state,
|
|
|
|
connector_iter);
|
|
|
|
if (IS_ERR(conn_iter_state)) {
|
|
|
|
drm_connector_list_iter_end(&connector_list_iter);
|
|
|
|
return PTR_ERR(conn_iter_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!conn_iter_state->base.crtc)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
crtc = to_intel_crtc(conn_iter_state->base.crtc);
|
|
|
|
crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
|
|
|
|
if (IS_ERR(crtc_state)) {
|
|
|
|
drm_connector_list_iter_end(&connector_list_iter);
|
|
|
|
return PTR_ERR(crtc_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = drm_atomic_add_affected_planes(&state->base, &crtc->base);
|
|
|
|
if (ret) {
|
|
|
|
drm_connector_list_iter_end(&connector_list_iter);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
crtc_state->uapi.mode_changed = true;
|
|
|
|
}
|
|
|
|
drm_connector_list_iter_end(&connector_list_iter);
|
|
|
|
|
2019-01-16 04:08:00 +08:00
|
|
|
return 0;
|
2017-04-29 07:14:20 +08:00
|
|
|
}
|
2014-05-02 12:02:48 +08:00
|
|
|
|
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 <lyude@redhat.com>
Reviewed-by: Daniel Vetter <daniel@ffwll.ch>
Cc: David Airlie <airlied@redhat.com>
Cc: Jerry Zuo <Jerry.Zuo@amd.com>
Cc: Harry Wentland <harry.wentland@amd.com>
Cc: Juston Li <juston.li@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190111005343.17443-19-lyude@redhat.com
2019-01-11 08:53:41 +08:00
|
|
|
static int
|
|
|
|
intel_dp_mst_atomic_check(struct drm_connector *connector,
|
2019-12-23 09:06:49 +08:00
|
|
|
struct drm_atomic_state *_state)
|
2017-04-29 07:14:20 +08:00
|
|
|
{
|
2019-12-23 09:06:49 +08:00
|
|
|
struct intel_atomic_state *state = to_intel_atomic_state(_state);
|
2019-06-12 00:08:18 +08:00
|
|
|
struct drm_connector_state *new_conn_state =
|
2019-12-23 09:06:49 +08:00
|
|
|
drm_atomic_get_new_connector_state(&state->base, connector);
|
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 <lyude@redhat.com>
Reviewed-by: Daniel Vetter <daniel@ffwll.ch>
Cc: David Airlie <airlied@redhat.com>
Cc: Jerry Zuo <Jerry.Zuo@amd.com>
Cc: Harry Wentland <harry.wentland@amd.com>
Cc: Juston Li <juston.li@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190111005343.17443-19-lyude@redhat.com
2019-01-11 08:53:41 +08:00
|
|
|
struct drm_connector_state *old_conn_state =
|
2019-12-23 09:06:49 +08:00
|
|
|
drm_atomic_get_old_connector_state(&state->base, connector);
|
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 <lyude@redhat.com>
Reviewed-by: Daniel Vetter <daniel@ffwll.ch>
Cc: David Airlie <airlied@redhat.com>
Cc: Jerry Zuo <Jerry.Zuo@amd.com>
Cc: Harry Wentland <harry.wentland@amd.com>
Cc: Juston Li <juston.li@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190111005343.17443-19-lyude@redhat.com
2019-01-11 08:53:41 +08:00
|
|
|
struct intel_connector *intel_connector =
|
|
|
|
to_intel_connector(connector);
|
|
|
|
struct drm_crtc *new_crtc = new_conn_state->crtc;
|
|
|
|
struct drm_dp_mst_topology_mgr *mgr;
|
2019-03-26 22:25:51 +08:00
|
|
|
int ret;
|
|
|
|
|
2019-12-23 09:06:49 +08:00
|
|
|
ret = intel_digital_connector_atomic_check(connector, &state->base);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = intel_dp_mst_atomic_master_trans_check(intel_connector, state);
|
2019-03-26 22:25:51 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
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 <lyude@redhat.com>
Reviewed-by: Daniel Vetter <daniel@ffwll.ch>
Cc: David Airlie <airlied@redhat.com>
Cc: Jerry Zuo <Jerry.Zuo@amd.com>
Cc: Harry Wentland <harry.wentland@amd.com>
Cc: Juston Li <juston.li@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190111005343.17443-19-lyude@redhat.com
2019-01-11 08:53:41 +08:00
|
|
|
|
|
|
|
if (!old_conn_state->crtc)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* We only want to free VCPI if this state disables the CRTC on this
|
|
|
|
* connector
|
|
|
|
*/
|
|
|
|
if (new_crtc) {
|
2019-10-31 19:25:59 +08:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(new_crtc);
|
|
|
|
struct intel_crtc_state *crtc_state =
|
2019-12-23 09:06:49 +08:00
|
|
|
intel_atomic_get_new_crtc_state(state, intel_crtc);
|
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 <lyude@redhat.com>
Reviewed-by: Daniel Vetter <daniel@ffwll.ch>
Cc: David Airlie <airlied@redhat.com>
Cc: Jerry Zuo <Jerry.Zuo@amd.com>
Cc: Harry Wentland <harry.wentland@amd.com>
Cc: Juston Li <juston.li@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190111005343.17443-19-lyude@redhat.com
2019-01-11 08:53:41 +08:00
|
|
|
|
|
|
|
if (!crtc_state ||
|
2019-10-31 19:26:03 +08:00
|
|
|
!drm_atomic_crtc_needs_modeset(&crtc_state->uapi) ||
|
2019-11-16 04:04:30 +08:00
|
|
|
crtc_state->uapi.enable)
|
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 <lyude@redhat.com>
Reviewed-by: Daniel Vetter <daniel@ffwll.ch>
Cc: David Airlie <airlied@redhat.com>
Cc: Jerry Zuo <Jerry.Zuo@amd.com>
Cc: Harry Wentland <harry.wentland@amd.com>
Cc: Juston Li <juston.li@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190111005343.17443-19-lyude@redhat.com
2019-01-11 08:53:41 +08:00
|
|
|
return 0;
|
2017-04-29 07:14:20 +08:00
|
|
|
}
|
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 <lyude@redhat.com>
Reviewed-by: Daniel Vetter <daniel@ffwll.ch>
Cc: David Airlie <airlied@redhat.com>
Cc: Jerry Zuo <Jerry.Zuo@amd.com>
Cc: Harry Wentland <harry.wentland@amd.com>
Cc: Juston Li <juston.li@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190111005343.17443-19-lyude@redhat.com
2019-01-11 08:53:41 +08:00
|
|
|
|
2019-12-05 02:05:43 +08:00
|
|
|
mgr = &enc_to_mst(to_intel_encoder(old_conn_state->best_encoder))->primary->dp.mst_mgr;
|
2019-12-23 09:06:49 +08:00
|
|
|
ret = drm_dp_atomic_release_vcpi_slots(&state->base, mgr,
|
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 <lyude@redhat.com>
Reviewed-by: Daniel Vetter <daniel@ffwll.ch>
Cc: David Airlie <airlied@redhat.com>
Cc: Jerry Zuo <Jerry.Zuo@amd.com>
Cc: Harry Wentland <harry.wentland@amd.com>
Cc: Juston Li <juston.li@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190111005343.17443-19-lyude@redhat.com
2019-01-11 08:53:41 +08:00
|
|
|
intel_connector->port);
|
|
|
|
|
2017-04-29 07:14:20 +08:00
|
|
|
return ret;
|
2014-05-02 12:02:48 +08:00
|
|
|
}
|
|
|
|
|
2020-03-14 00:48:30 +08:00
|
|
|
static void intel_mst_disable_dp(struct intel_atomic_state *state,
|
|
|
|
struct intel_encoder *encoder,
|
2017-08-18 21:49:58 +08:00
|
|
|
const struct intel_crtc_state *old_crtc_state,
|
|
|
|
const struct drm_connector_state *old_conn_state)
|
2014-05-02 12:02:48 +08:00
|
|
|
{
|
2019-12-05 02:05:43 +08:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2014-05-02 12:02:48 +08:00
|
|
|
struct intel_digital_port *intel_dig_port = intel_mst->primary;
|
|
|
|
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
2016-08-09 23:04:12 +08:00
|
|
|
struct intel_connector *connector =
|
|
|
|
to_intel_connector(old_conn_state->connector);
|
drm/i915/dp_mst: use struct drm_device based logging
Convert all the DRM_* logging macros to the struct drm_device based
macros to provide device specific logging.
No functional changes.
Generated using the following semantic patch, originally written by
Wambui Karuga <wambui.karugax@gmail.com>, with manual fixups on top:
@@
identifier fn, T;
@@
fn(...,struct drm_i915_private *T,...) {
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
@@
identifier fn, T;
@@
fn(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
Cc: Wambui Karuga <wambui.karugax@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5ee3b8040658b5b4ef0b8b1a546fa04f554cdf6a.1584714939.git.jani.nikula@intel.com
2020-03-20 22:36:29 +08:00
|
|
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
2014-05-02 12:02:48 +08:00
|
|
|
int ret;
|
|
|
|
|
drm/i915/dp_mst: use struct drm_device based logging
Convert all the DRM_* logging macros to the struct drm_device based
macros to provide device specific logging.
No functional changes.
Generated using the following semantic patch, originally written by
Wambui Karuga <wambui.karugax@gmail.com>, with manual fixups on top:
@@
identifier fn, T;
@@
fn(...,struct drm_i915_private *T,...) {
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
@@
identifier fn, T;
@@
fn(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
Cc: Wambui Karuga <wambui.karugax@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5ee3b8040658b5b4ef0b8b1a546fa04f554cdf6a.1584714939.git.jani.nikula@intel.com
2020-03-20 22:36:29 +08:00
|
|
|
drm_dbg_kms(&i915->drm, "active links %d\n",
|
|
|
|
intel_dp->active_mst_links);
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2016-08-09 23:04:12 +08:00
|
|
|
drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port);
|
2014-05-02 12:02:48 +08:00
|
|
|
|
|
|
|
ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
|
|
|
|
if (ret) {
|
drm/i915/dp_mst: use struct drm_device based logging
Convert all the DRM_* logging macros to the struct drm_device based
macros to provide device specific logging.
No functional changes.
Generated using the following semantic patch, originally written by
Wambui Karuga <wambui.karugax@gmail.com>, with manual fixups on top:
@@
identifier fn, T;
@@
fn(...,struct drm_i915_private *T,...) {
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
@@
identifier fn, T;
@@
fn(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
Cc: Wambui Karuga <wambui.karugax@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5ee3b8040658b5b4ef0b8b1a546fa04f554cdf6a.1584714939.git.jani.nikula@intel.com
2020-03-20 22:36:29 +08:00
|
|
|
drm_dbg_kms(&i915->drm, "failed to update payload %d\n", ret);
|
2014-05-02 12:02:48 +08:00
|
|
|
}
|
2016-12-15 22:29:43 +08:00
|
|
|
if (old_crtc_state->has_audio)
|
2017-10-31 02:46:53 +08:00
|
|
|
intel_audio_codec_disable(encoder,
|
|
|
|
old_crtc_state, old_conn_state);
|
2014-05-02 12:02:48 +08:00
|
|
|
}
|
|
|
|
|
2020-03-14 00:48:30 +08:00
|
|
|
static void intel_mst_post_disable_dp(struct intel_atomic_state *state,
|
|
|
|
struct intel_encoder *encoder,
|
2017-08-18 21:49:58 +08:00
|
|
|
const struct intel_crtc_state *old_crtc_state,
|
|
|
|
const struct drm_connector_state *old_conn_state)
|
2014-05-02 12:02:48 +08:00
|
|
|
{
|
2019-12-05 02:05:43 +08:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2014-05-02 12:02:48 +08:00
|
|
|
struct intel_digital_port *intel_dig_port = intel_mst->primary;
|
|
|
|
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
2016-08-09 23:04:12 +08:00
|
|
|
struct intel_connector *connector =
|
|
|
|
to_intel_connector(old_conn_state->connector);
|
2019-12-06 05:03:49 +08:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
|
|
|
bool last_mst_stream;
|
2019-12-23 09:06:51 +08:00
|
|
|
u32 val;
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2019-12-06 05:03:49 +08:00
|
|
|
intel_dp->active_mst_links--;
|
|
|
|
last_mst_stream = intel_dp->active_mst_links == 0;
|
drm/i915/display: Make WARN* drm specific where drm_device ptr is available
drm specific WARN* calls include device information in the
backtrace, so we know what device the warnings originate from.
Covert all the calls of WARN* with device specific drm_WARN*
variants in functions where drm_device or drm_i915_private struct
pointer is readily available.
The conversion was done automatically with below coccinelle semantic
patch. checkpatch errors/warnings are fixed manually.
@rule1@
identifier func, T;
@@
func(...) {
...
struct drm_device *T = ...;
<...
(
-WARN(
+drm_WARN(T,
...)
|
-WARN_ON(
+drm_WARN_ON(T,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(T,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(T,
...)
)
...>
}
@rule2@
identifier func, T;
@@
func(struct drm_device *T,...) {
<...
(
-WARN(
+drm_WARN(T,
...)
|
-WARN_ON(
+drm_WARN_ON(T,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(T,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(T,
...)
)
...>
}
@rule3@
identifier func, T;
@@
func(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-WARN(
+drm_WARN(&T->drm,
...)
|
-WARN_ON(
+drm_WARN_ON(&T->drm,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(&T->drm,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(&T->drm,
...)
)
...+>
}
@rule4@
identifier func, T;
@@
func(struct drm_i915_private *T,...) {
<+...
(
-WARN(
+drm_WARN(&T->drm,
...)
|
-WARN_ON(
+drm_WARN_ON(&T->drm,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(&T->drm,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(&T->drm,
...)
)
...+>
}
Signed-off-by: Pankaj Bharadiya <pankaj.laxminarayan.bharadiya@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200128181603.27767-20-pankaj.laxminarayan.bharadiya@intel.com
2020-01-29 02:16:01 +08:00
|
|
|
drm_WARN_ON(&dev_priv->drm,
|
|
|
|
INTEL_GEN(dev_priv) >= 12 && last_mst_stream &&
|
|
|
|
!intel_dp_mst_is_master_trans(old_crtc_state));
|
2019-12-06 05:03:49 +08:00
|
|
|
|
2019-12-14 03:52:17 +08:00
|
|
|
intel_crtc_vblank_off(old_crtc_state);
|
|
|
|
|
|
|
|
intel_disable_pipe(old_crtc_state);
|
|
|
|
|
2019-12-23 09:06:51 +08:00
|
|
|
drm_dp_update_payload_part2(&intel_dp->mst_mgr);
|
|
|
|
|
drm/i915/dp_mst: use intel_de_*() functions for register access
The implicit "dev_priv" local variable use has been a long-standing pain
point in the register access macros I915_READ(), I915_WRITE(),
POSTING_READ(), I915_READ_FW(), and I915_WRITE_FW().
Replace them with the corresponding new display engine register
accessors intel_de_read(), intel_de_write(), intel_de_posting_read(),
intel_de_read_fw(), and intel_de_write_fw().
No functional changes.
Generated using the following semantic patch:
@@
expression REG, OFFSET;
@@
- I915_READ(REG)
+ intel_de_read(dev_priv, REG)
@@
expression REG, OFFSET;
@@
- POSTING_READ(REG)
+ intel_de_posting_read(dev_priv, REG)
@@
expression REG, OFFSET;
@@
- I915_WRITE(REG, OFFSET)
+ intel_de_write(dev_priv, REG, OFFSET)
@@
expression REG;
@@
- I915_READ_FW(REG)
+ intel_de_read_fw(dev_priv, REG)
@@
expression REG, OFFSET;
@@
- I915_WRITE_FW(REG, OFFSET)
+ intel_de_write_fw(dev_priv, REG, OFFSET)
Acked-by: Chris Wilson <chris@chris-wilson.co.uk>
Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Acked-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/06ba99067fc506bec4533202b046d63dda5cb1f2.1579871655.git.jani.nikula@intel.com
2020-01-24 21:25:34 +08:00
|
|
|
val = intel_de_read(dev_priv,
|
|
|
|
TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder));
|
2019-12-23 09:06:51 +08:00
|
|
|
val &= ~TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
|
drm/i915/dp_mst: use intel_de_*() functions for register access
The implicit "dev_priv" local variable use has been a long-standing pain
point in the register access macros I915_READ(), I915_WRITE(),
POSTING_READ(), I915_READ_FW(), and I915_WRITE_FW().
Replace them with the corresponding new display engine register
accessors intel_de_read(), intel_de_write(), intel_de_posting_read(),
intel_de_read_fw(), and intel_de_write_fw().
No functional changes.
Generated using the following semantic patch:
@@
expression REG, OFFSET;
@@
- I915_READ(REG)
+ intel_de_read(dev_priv, REG)
@@
expression REG, OFFSET;
@@
- POSTING_READ(REG)
+ intel_de_posting_read(dev_priv, REG)
@@
expression REG, OFFSET;
@@
- I915_WRITE(REG, OFFSET)
+ intel_de_write(dev_priv, REG, OFFSET)
@@
expression REG;
@@
- I915_READ_FW(REG)
+ intel_de_read_fw(dev_priv, REG)
@@
expression REG, OFFSET;
@@
- I915_WRITE_FW(REG, OFFSET)
+ intel_de_write_fw(dev_priv, REG, OFFSET)
Acked-by: Chris Wilson <chris@chris-wilson.co.uk>
Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Acked-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/06ba99067fc506bec4533202b046d63dda5cb1f2.1579871655.git.jani.nikula@intel.com
2020-01-24 21:25:34 +08:00
|
|
|
intel_de_write(dev_priv,
|
|
|
|
TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder),
|
|
|
|
val);
|
2019-12-23 09:06:51 +08:00
|
|
|
|
|
|
|
if (intel_de_wait_for_set(dev_priv, intel_dp->regs.dp_tp_status,
|
|
|
|
DP_TP_STATUS_ACT_SENT, 1))
|
drm/i915/dp_mst: use struct drm_device based logging
Convert all the DRM_* logging macros to the struct drm_device based
macros to provide device specific logging.
No functional changes.
Generated using the following semantic patch, originally written by
Wambui Karuga <wambui.karugax@gmail.com>, with manual fixups on top:
@@
identifier fn, T;
@@
fn(...,struct drm_i915_private *T,...) {
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
@@
identifier fn, T;
@@
fn(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
Cc: Wambui Karuga <wambui.karugax@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5ee3b8040658b5b4ef0b8b1a546fa04f554cdf6a.1584714939.git.jani.nikula@intel.com
2020-03-20 22:36:29 +08:00
|
|
|
drm_err(&dev_priv->drm,
|
|
|
|
"Timed out waiting for ACT sent when disabling\n");
|
2019-12-23 09:06:51 +08:00
|
|
|
drm_dp_check_act_status(&intel_dp->mst_mgr);
|
|
|
|
|
|
|
|
drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port);
|
|
|
|
|
2019-12-14 03:52:17 +08:00
|
|
|
intel_ddi_disable_transcoder_func(old_crtc_state);
|
|
|
|
|
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
2019-12-24 16:40:06 +08:00
|
|
|
skl_scaler_disable(old_crtc_state);
|
2019-12-14 03:52:17 +08:00
|
|
|
else
|
2019-12-24 16:40:09 +08:00
|
|
|
ilk_pfit_disable(old_crtc_state);
|
2019-12-14 03:52:17 +08:00
|
|
|
|
2019-12-23 09:06:51 +08:00
|
|
|
/*
|
|
|
|
* Power down mst path before disabling the port, otherwise we end
|
|
|
|
* up getting interrupts from the sink upon detecting link loss.
|
|
|
|
*/
|
|
|
|
drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port,
|
|
|
|
false);
|
2019-12-06 05:03:49 +08:00
|
|
|
/*
|
|
|
|
* From TGL spec: "If multi-stream slave transcoder: Configure
|
|
|
|
* Transcoder Clock Select to direct no clock to the transcoder"
|
|
|
|
*
|
|
|
|
* From older GENs spec: "Configure Transcoder Clock Select to direct
|
|
|
|
* no clock to the transcoder"
|
|
|
|
*/
|
|
|
|
if (INTEL_GEN(dev_priv) < 12 || !last_mst_stream)
|
|
|
|
intel_ddi_disable_pipe_clock(old_crtc_state);
|
2018-09-01 01:47:39 +08:00
|
|
|
|
2017-10-03 22:22:11 +08:00
|
|
|
|
2016-03-09 09:14:38 +08:00
|
|
|
intel_mst->connector = NULL;
|
2019-12-06 05:03:49 +08:00
|
|
|
if (last_mst_stream)
|
2020-03-14 00:48:30 +08:00
|
|
|
intel_dig_port->base.post_disable(state, &intel_dig_port->base,
|
2017-10-28 03:31:27 +08:00
|
|
|
old_crtc_state, NULL);
|
|
|
|
|
drm/i915/dp_mst: use struct drm_device based logging
Convert all the DRM_* logging macros to the struct drm_device based
macros to provide device specific logging.
No functional changes.
Generated using the following semantic patch, originally written by
Wambui Karuga <wambui.karugax@gmail.com>, with manual fixups on top:
@@
identifier fn, T;
@@
fn(...,struct drm_i915_private *T,...) {
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
@@
identifier fn, T;
@@
fn(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
Cc: Wambui Karuga <wambui.karugax@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5ee3b8040658b5b4ef0b8b1a546fa04f554cdf6a.1584714939.git.jani.nikula@intel.com
2020-03-20 22:36:29 +08:00
|
|
|
drm_dbg_kms(&dev_priv->drm, "active links %d\n",
|
|
|
|
intel_dp->active_mst_links);
|
2014-05-02 12:02:48 +08:00
|
|
|
}
|
|
|
|
|
2020-03-14 00:48:30 +08:00
|
|
|
static void intel_mst_pre_pll_enable_dp(struct intel_atomic_state *state,
|
|
|
|
struct intel_encoder *encoder,
|
2017-10-27 21:43:48 +08:00
|
|
|
const struct intel_crtc_state *pipe_config,
|
|
|
|
const struct drm_connector_state *conn_state)
|
|
|
|
{
|
2019-12-05 02:05:43 +08:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2017-10-27 21:43:48 +08:00
|
|
|
struct intel_digital_port *intel_dig_port = intel_mst->primary;
|
|
|
|
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
|
|
|
|
2018-11-08 07:54:49 +08:00
|
|
|
if (intel_dp->active_mst_links == 0)
|
2020-03-14 00:48:30 +08:00
|
|
|
intel_dig_port->base.pre_pll_enable(state, &intel_dig_port->base,
|
2017-10-27 21:43:48 +08:00
|
|
|
pipe_config, NULL);
|
|
|
|
}
|
|
|
|
|
2020-03-14 00:48:30 +08:00
|
|
|
static void intel_mst_pre_enable_dp(struct intel_atomic_state *state,
|
|
|
|
struct intel_encoder *encoder,
|
2017-08-18 21:49:58 +08:00
|
|
|
const struct intel_crtc_state *pipe_config,
|
|
|
|
const struct drm_connector_state *conn_state)
|
2014-05-02 12:02:48 +08:00
|
|
|
{
|
2019-12-05 02:05:43 +08:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2014-05-02 12:02:48 +08:00
|
|
|
struct intel_digital_port *intel_dig_port = intel_mst->primary;
|
|
|
|
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
2016-08-09 23:04:12 +08:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
|
|
|
struct intel_connector *connector =
|
|
|
|
to_intel_connector(conn_state->connector);
|
2014-05-02 12:02:48 +08:00
|
|
|
int ret;
|
2019-01-16 17:15:19 +08:00
|
|
|
u32 temp;
|
2019-10-30 09:24:46 +08:00
|
|
|
bool first_mst_stream;
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2015-08-27 19:13:31 +08:00
|
|
|
/* MST encoders are bound to a crtc, not to a connector,
|
|
|
|
* force the mapping here for get_hw_state.
|
|
|
|
*/
|
2016-08-09 23:04:12 +08:00
|
|
|
connector->encoder = encoder;
|
|
|
|
intel_mst->connector = connector;
|
2019-10-30 09:24:46 +08:00
|
|
|
first_mst_stream = intel_dp->active_mst_links == 0;
|
drm/i915/display: Make WARN* drm specific where drm_device ptr is available
drm specific WARN* calls include device information in the
backtrace, so we know what device the warnings originate from.
Covert all the calls of WARN* with device specific drm_WARN*
variants in functions where drm_device or drm_i915_private struct
pointer is readily available.
The conversion was done automatically with below coccinelle semantic
patch. checkpatch errors/warnings are fixed manually.
@rule1@
identifier func, T;
@@
func(...) {
...
struct drm_device *T = ...;
<...
(
-WARN(
+drm_WARN(T,
...)
|
-WARN_ON(
+drm_WARN_ON(T,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(T,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(T,
...)
)
...>
}
@rule2@
identifier func, T;
@@
func(struct drm_device *T,...) {
<...
(
-WARN(
+drm_WARN(T,
...)
|
-WARN_ON(
+drm_WARN_ON(T,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(T,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(T,
...)
)
...>
}
@rule3@
identifier func, T;
@@
func(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-WARN(
+drm_WARN(&T->drm,
...)
|
-WARN_ON(
+drm_WARN_ON(&T->drm,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(&T->drm,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(&T->drm,
...)
)
...+>
}
@rule4@
identifier func, T;
@@
func(struct drm_i915_private *T,...) {
<+...
(
-WARN(
+drm_WARN(&T->drm,
...)
|
-WARN_ON(
+drm_WARN_ON(&T->drm,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(&T->drm,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(&T->drm,
...)
)
...+>
}
Signed-off-by: Pankaj Bharadiya <pankaj.laxminarayan.bharadiya@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200128181603.27767-20-pankaj.laxminarayan.bharadiya@intel.com
2020-01-29 02:16:01 +08:00
|
|
|
drm_WARN_ON(&dev_priv->drm,
|
|
|
|
INTEL_GEN(dev_priv) >= 12 && first_mst_stream &&
|
|
|
|
!intel_dp_mst_is_master_trans(pipe_config));
|
2015-08-27 19:13:31 +08:00
|
|
|
|
drm/i915/dp_mst: use struct drm_device based logging
Convert all the DRM_* logging macros to the struct drm_device based
macros to provide device specific logging.
No functional changes.
Generated using the following semantic patch, originally written by
Wambui Karuga <wambui.karugax@gmail.com>, with manual fixups on top:
@@
identifier fn, T;
@@
fn(...,struct drm_i915_private *T,...) {
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
@@
identifier fn, T;
@@
fn(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
Cc: Wambui Karuga <wambui.karugax@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5ee3b8040658b5b4ef0b8b1a546fa04f554cdf6a.1584714939.git.jani.nikula@intel.com
2020-03-20 22:36:29 +08:00
|
|
|
drm_dbg_kms(&dev_priv->drm, "active links %d\n",
|
|
|
|
intel_dp->active_mst_links);
|
2016-03-09 09:14:38 +08:00
|
|
|
|
2019-10-30 09:24:46 +08:00
|
|
|
if (first_mst_stream)
|
2018-04-07 09:10:53 +08:00
|
|
|
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
|
|
|
|
|
2017-10-03 22:22:11 +08:00
|
|
|
drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true);
|
2018-04-07 09:10:53 +08:00
|
|
|
|
2019-10-30 09:24:46 +08:00
|
|
|
if (first_mst_stream)
|
2020-03-14 00:48:30 +08:00
|
|
|
intel_dig_port->base.pre_enable(state, &intel_dig_port->base,
|
2017-03-02 20:58:57 +08:00
|
|
|
pipe_config, NULL);
|
2014-05-02 12:02:48 +08:00
|
|
|
|
|
|
|
ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
|
2016-08-09 23:04:12 +08:00
|
|
|
connector->port,
|
2017-03-16 15:10:26 +08:00
|
|
|
pipe_config->pbn,
|
|
|
|
pipe_config->dp_m_n.tu);
|
2018-07-19 01:19:43 +08:00
|
|
|
if (!ret)
|
drm/i915/dp_mst: use struct drm_device based logging
Convert all the DRM_* logging macros to the struct drm_device based
macros to provide device specific logging.
No functional changes.
Generated using the following semantic patch, originally written by
Wambui Karuga <wambui.karugax@gmail.com>, with manual fixups on top:
@@
identifier fn, T;
@@
fn(...,struct drm_i915_private *T,...) {
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
@@
identifier fn, T;
@@
fn(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
Cc: Wambui Karuga <wambui.karugax@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5ee3b8040658b5b4ef0b8b1a546fa04f554cdf6a.1584714939.git.jani.nikula@intel.com
2020-03-20 22:36:29 +08:00
|
|
|
drm_err(&dev_priv->drm, "failed to allocate vcpi\n");
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2016-08-06 00:05:42 +08:00
|
|
|
intel_dp->active_mst_links++;
|
drm/i915/dp_mst: use intel_de_*() functions for register access
The implicit "dev_priv" local variable use has been a long-standing pain
point in the register access macros I915_READ(), I915_WRITE(),
POSTING_READ(), I915_READ_FW(), and I915_WRITE_FW().
Replace them with the corresponding new display engine register
accessors intel_de_read(), intel_de_write(), intel_de_posting_read(),
intel_de_read_fw(), and intel_de_write_fw().
No functional changes.
Generated using the following semantic patch:
@@
expression REG, OFFSET;
@@
- I915_READ(REG)
+ intel_de_read(dev_priv, REG)
@@
expression REG, OFFSET;
@@
- POSTING_READ(REG)
+ intel_de_posting_read(dev_priv, REG)
@@
expression REG, OFFSET;
@@
- I915_WRITE(REG, OFFSET)
+ intel_de_write(dev_priv, REG, OFFSET)
@@
expression REG;
@@
- I915_READ_FW(REG)
+ intel_de_read_fw(dev_priv, REG)
@@
expression REG, OFFSET;
@@
- I915_WRITE_FW(REG, OFFSET)
+ intel_de_write_fw(dev_priv, REG, OFFSET)
Acked-by: Chris Wilson <chris@chris-wilson.co.uk>
Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Acked-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/06ba99067fc506bec4533202b046d63dda5cb1f2.1579871655.git.jani.nikula@intel.com
2020-01-24 21:25:34 +08:00
|
|
|
temp = intel_de_read(dev_priv, intel_dp->regs.dp_tp_status);
|
|
|
|
intel_de_write(dev_priv, intel_dp->regs.dp_tp_status, temp);
|
2014-05-02 12:02:48 +08:00
|
|
|
|
|
|
|
ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
|
2018-09-01 01:47:39 +08:00
|
|
|
|
2019-10-30 09:24:46 +08:00
|
|
|
/*
|
|
|
|
* Before Gen 12 this is not done as part of
|
|
|
|
* intel_dig_port->base.pre_enable() and should be done here. For
|
|
|
|
* Gen 12+ the step in which this should be done is different for the
|
|
|
|
* first MST stream, so it's done on the DDI for the first stream and
|
|
|
|
* here for the following ones.
|
|
|
|
*/
|
|
|
|
if (INTEL_GEN(dev_priv) < 12 || !first_mst_stream)
|
2020-04-17 21:47:17 +08:00
|
|
|
intel_ddi_enable_pipe_clock(encoder, pipe_config);
|
2019-11-07 05:26:36 +08:00
|
|
|
|
|
|
|
intel_ddi_set_dp_msa(pipe_config, conn_state);
|
2020-02-12 02:50:07 +08:00
|
|
|
|
|
|
|
intel_dp_set_m_n(pipe_config, M1_N1);
|
2014-05-02 12:02:48 +08:00
|
|
|
}
|
|
|
|
|
2020-03-14 00:48:30 +08:00
|
|
|
static void intel_mst_enable_dp(struct intel_atomic_state *state,
|
|
|
|
struct intel_encoder *encoder,
|
2017-08-18 21:49:58 +08:00
|
|
|
const struct intel_crtc_state *pipe_config,
|
|
|
|
const struct drm_connector_state *conn_state)
|
2014-05-02 12:02:48 +08:00
|
|
|
{
|
2019-12-05 02:05:43 +08:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2014-05-02 12:02:48 +08:00
|
|
|
struct intel_digital_port *intel_dig_port = intel_mst->primary;
|
|
|
|
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
2016-08-09 23:04:12 +08:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2020-02-05 16:29:59 +08:00
|
|
|
drm_WARN_ON(&dev_priv->drm, pipe_config->has_pch_encoder);
|
|
|
|
|
2020-04-17 21:47:20 +08:00
|
|
|
intel_ddi_enable_transcoder_func(encoder, pipe_config);
|
2020-04-17 21:47:19 +08:00
|
|
|
|
2020-02-05 16:29:59 +08:00
|
|
|
intel_enable_pipe(pipe_config);
|
|
|
|
|
|
|
|
intel_crtc_vblank_on(pipe_config);
|
|
|
|
|
drm/i915/dp_mst: use struct drm_device based logging
Convert all the DRM_* logging macros to the struct drm_device based
macros to provide device specific logging.
No functional changes.
Generated using the following semantic patch, originally written by
Wambui Karuga <wambui.karugax@gmail.com>, with manual fixups on top:
@@
identifier fn, T;
@@
fn(...,struct drm_i915_private *T,...) {
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
@@
identifier fn, T;
@@
fn(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
Cc: Wambui Karuga <wambui.karugax@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5ee3b8040658b5b4ef0b8b1a546fa04f554cdf6a.1584714939.git.jani.nikula@intel.com
2020-03-20 22:36:29 +08:00
|
|
|
drm_dbg_kms(&dev_priv->drm, "active links %d\n",
|
|
|
|
intel_dp->active_mst_links);
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2019-09-05 05:34:17 +08:00
|
|
|
if (intel_de_wait_for_set(dev_priv, intel_dp->regs.dp_tp_status,
|
2019-08-16 09:23:43 +08:00
|
|
|
DP_TP_STATUS_ACT_SENT, 1))
|
drm/i915/dp_mst: use struct drm_device based logging
Convert all the DRM_* logging macros to the struct drm_device based
macros to provide device specific logging.
No functional changes.
Generated using the following semantic patch, originally written by
Wambui Karuga <wambui.karugax@gmail.com>, with manual fixups on top:
@@
identifier fn, T;
@@
fn(...,struct drm_i915_private *T,...) {
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
@@
identifier fn, T;
@@
fn(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
Cc: Wambui Karuga <wambui.karugax@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5ee3b8040658b5b4ef0b8b1a546fa04f554cdf6a.1584714939.git.jani.nikula@intel.com
2020-03-20 22:36:29 +08:00
|
|
|
drm_err(&dev_priv->drm, "Timed out waiting for ACT sent\n");
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2018-07-20 07:42:17 +08:00
|
|
|
drm_dp_check_act_status(&intel_dp->mst_mgr);
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2018-07-20 07:42:17 +08:00
|
|
|
drm_dp_update_payload_part2(&intel_dp->mst_mgr);
|
2016-12-15 22:29:43 +08:00
|
|
|
if (pipe_config->has_audio)
|
2016-11-28 20:07:07 +08:00
|
|
|
intel_audio_codec_enable(encoder, pipe_config, conn_state);
|
2014-05-02 12:02:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
|
|
|
|
enum pipe *pipe)
|
|
|
|
{
|
2019-12-05 02:05:43 +08:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2014-05-02 12:02:48 +08:00
|
|
|
*pipe = intel_mst->pipe;
|
2016-03-09 09:14:38 +08:00
|
|
|
if (intel_mst->connector)
|
2014-05-02 12:02:48 +08:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
|
2015-01-15 20:55:21 +08:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2014-05-02 12:02:48 +08:00
|
|
|
{
|
2019-12-05 02:05:43 +08:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2014-05-02 12:02:48 +08:00
|
|
|
struct intel_digital_port *intel_dig_port = intel_mst->primary;
|
2017-10-24 17:52:14 +08:00
|
|
|
|
2017-10-28 03:31:28 +08:00
|
|
|
intel_ddi_get_config(&intel_dig_port->base, pipe_config);
|
2014-05-02 12:02:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
|
|
|
|
{
|
|
|
|
struct intel_connector *intel_connector = to_intel_connector(connector);
|
|
|
|
struct intel_dp *intel_dp = intel_connector->mst_port;
|
|
|
|
struct edid *edid;
|
|
|
|
int ret;
|
|
|
|
|
drm/atomic_helper: Stop modesets on unregistered connectors harder
Unfortunately, it appears our fix in:
commit b5d29843d8ef ("drm/atomic_helper: Allow DPMS On<->Off changes
for unregistered connectors")
Which attempted to work around the problems introduced by:
commit 4d80273976bf ("drm/atomic_helper: Disallow new modesets on
unregistered connectors")
Is still not the right solution, as modesets can still be triggered
outside of drm_atomic_set_crtc_for_connector().
So in order to fix this, while still being careful that we don't break
modesets that a driver may perform before being registered with
userspace, we replace connector->registered with a tristate member,
connector->registration_state. This allows us to keep track of whether
or not a connector is still initializing and hasn't been exposed to
userspace, is currently registered and exposed to userspace, or has been
legitimately removed from the system after having once been present.
Using this info, we can prevent userspace from performing new modesets
on unregistered connectors while still allowing the driver to perform
modesets on unregistered connectors before the driver has finished being
registered.
Changes since v1:
- Fix WARN_ON() in drm_connector_cleanup() that CI caught with this
patchset in igt@drv_module_reload@basic-reload-inject and
igt@drv_module_reload@basic-reload by checking if the connector is
registered instead of unregistered, as calling drm_connector_cleanup()
on a connector that hasn't been registered with userspace yet should
stay valid.
- Remove unregistered_connector_check(), and just go back to what we
were doing before in commit 4d80273976bf ("drm/atomic_helper: Disallow
new modesets on unregistered connectors") except replacing
READ_ONCE(connector->registered) with drm_connector_is_unregistered().
This gets rid of the behavior of allowing DPMS On<->Off, but that should
be fine as it's more consistent with the UAPI we had before - danvet
- s/drm_connector_unregistered/drm_connector_is_unregistered/ - danvet
- Update documentation, fix some typos.
Fixes: b5d29843d8ef ("drm/atomic_helper: Allow DPMS On<->Off changes for unregistered connectors")
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: stable@vger.kernel.org
Cc: David Airlie <airlied@linux.ie>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20181016203946.9601-1-lyude@redhat.com
2018-10-17 04:39:46 +08:00
|
|
|
if (drm_connector_is_unregistered(connector))
|
2016-03-09 09:14:38 +08:00
|
|
|
return intel_connector_update_modes(connector, NULL);
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2016-03-09 09:14:38 +08:00
|
|
|
edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port);
|
2014-05-02 12:02:48 +08:00
|
|
|
ret = intel_connector_update_modes(connector, edid);
|
|
|
|
kfree(edid);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-03-11 03:51:21 +08:00
|
|
|
static int
|
|
|
|
intel_dp_mst_connector_late_register(struct drm_connector *connector)
|
|
|
|
{
|
|
|
|
struct intel_connector *intel_connector = to_intel_connector(connector);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = drm_dp_mst_connector_late_register(connector,
|
|
|
|
intel_connector->port);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = intel_connector_register(connector);
|
|
|
|
if (ret < 0)
|
|
|
|
drm_dp_mst_connector_early_unregister(connector,
|
|
|
|
intel_connector->port);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
intel_dp_mst_connector_early_unregister(struct drm_connector *connector)
|
|
|
|
{
|
|
|
|
struct intel_connector *intel_connector = to_intel_connector(connector);
|
|
|
|
|
|
|
|
intel_connector_unregister(connector);
|
|
|
|
drm_dp_mst_connector_early_unregister(connector,
|
|
|
|
intel_connector->port);
|
|
|
|
}
|
|
|
|
|
2014-05-02 12:02:48 +08:00
|
|
|
static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
|
|
|
|
.fill_modes = drm_helper_probe_single_connector_modes,
|
2019-03-26 22:25:51 +08:00
|
|
|
.atomic_get_property = intel_digital_connector_atomic_get_property,
|
|
|
|
.atomic_set_property = intel_digital_connector_atomic_set_property,
|
2020-03-11 03:51:21 +08:00
|
|
|
.late_register = intel_dp_mst_connector_late_register,
|
|
|
|
.early_unregister = intel_dp_mst_connector_early_unregister,
|
2018-10-09 22:11:03 +08:00
|
|
|
.destroy = intel_connector_destroy,
|
2015-01-23 08:50:32 +08:00
|
|
|
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
2019-03-26 22:25:51 +08:00
|
|
|
.atomic_duplicate_state = intel_digital_connector_duplicate_state,
|
2014-05-02 12:02:48 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int intel_dp_mst_get_modes(struct drm_connector *connector)
|
|
|
|
{
|
|
|
|
return intel_dp_mst_get_ddc_modes(connector);
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum drm_mode_status
|
|
|
|
intel_dp_mst_mode_valid(struct drm_connector *connector,
|
|
|
|
struct drm_display_mode *mode)
|
|
|
|
{
|
2019-10-01 23:46:28 +08:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(connector->dev);
|
2016-11-16 04:59:06 +08:00
|
|
|
struct intel_connector *intel_connector = to_intel_connector(connector);
|
|
|
|
struct intel_dp *intel_dp = intel_connector->mst_port;
|
2016-02-02 21:16:40 +08:00
|
|
|
int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
|
2016-11-16 04:59:06 +08:00
|
|
|
int max_rate, mode_rate, max_lanes, max_link_clock;
|
|
|
|
|
drm/atomic_helper: Stop modesets on unregistered connectors harder
Unfortunately, it appears our fix in:
commit b5d29843d8ef ("drm/atomic_helper: Allow DPMS On<->Off changes
for unregistered connectors")
Which attempted to work around the problems introduced by:
commit 4d80273976bf ("drm/atomic_helper: Disallow new modesets on
unregistered connectors")
Is still not the right solution, as modesets can still be triggered
outside of drm_atomic_set_crtc_for_connector().
So in order to fix this, while still being careful that we don't break
modesets that a driver may perform before being registered with
userspace, we replace connector->registered with a tristate member,
connector->registration_state. This allows us to keep track of whether
or not a connector is still initializing and hasn't been exposed to
userspace, is currently registered and exposed to userspace, or has been
legitimately removed from the system after having once been present.
Using this info, we can prevent userspace from performing new modesets
on unregistered connectors while still allowing the driver to perform
modesets on unregistered connectors before the driver has finished being
registered.
Changes since v1:
- Fix WARN_ON() in drm_connector_cleanup() that CI caught with this
patchset in igt@drv_module_reload@basic-reload-inject and
igt@drv_module_reload@basic-reload by checking if the connector is
registered instead of unregistered, as calling drm_connector_cleanup()
on a connector that hasn't been registered with userspace yet should
stay valid.
- Remove unregistered_connector_check(), and just go back to what we
were doing before in commit 4d80273976bf ("drm/atomic_helper: Disallow
new modesets on unregistered connectors") except replacing
READ_ONCE(connector->registered) with drm_connector_is_unregistered().
This gets rid of the behavior of allowing DPMS On<->Off, but that should
be fine as it's more consistent with the UAPI we had before - danvet
- s/drm_connector_unregistered/drm_connector_is_unregistered/ - danvet
- Update documentation, fix some typos.
Fixes: b5d29843d8ef ("drm/atomic_helper: Allow DPMS On<->Off changes for unregistered connectors")
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: stable@vger.kernel.org
Cc: David Airlie <airlied@linux.ie>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20181016203946.9601-1-lyude@redhat.com
2018-10-17 04:39:46 +08:00
|
|
|
if (drm_connector_is_unregistered(connector))
|
2017-08-10 22:50:43 +08:00
|
|
|
return MODE_ERROR;
|
|
|
|
|
2018-05-24 20:54:03 +08:00
|
|
|
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
|
|
|
return MODE_NO_DBLESCAN;
|
|
|
|
|
2016-11-16 04:59:06 +08:00
|
|
|
max_link_clock = intel_dp_max_link_rate(intel_dp);
|
2017-04-06 21:44:14 +08:00
|
|
|
max_lanes = intel_dp_max_lane_count(intel_dp);
|
2016-11-16 04:59:06 +08:00
|
|
|
|
|
|
|
max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
|
2019-03-26 22:25:53 +08:00
|
|
|
mode_rate = intel_dp_link_required(mode->clock, 18);
|
2016-02-02 21:16:40 +08:00
|
|
|
|
2014-05-02 12:02:48 +08:00
|
|
|
/* TODO - validate mode against available PBN for link */
|
|
|
|
if (mode->clock < 10000)
|
|
|
|
return MODE_CLOCK_LOW;
|
|
|
|
|
|
|
|
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
|
|
|
return MODE_H_ILLEGAL;
|
|
|
|
|
2016-11-16 04:59:06 +08:00
|
|
|
if (mode_rate > max_rate || mode->clock > max_dotclk)
|
2016-02-02 21:16:40 +08:00
|
|
|
return MODE_CLOCK_HIGH;
|
|
|
|
|
2019-10-01 23:46:28 +08:00
|
|
|
return intel_mode_valid_max_plane_size(dev_priv, mode);
|
2014-05-02 12:02:48 +08:00
|
|
|
}
|
|
|
|
|
2015-08-03 23:24:09 +08:00
|
|
|
static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector,
|
|
|
|
struct drm_connector_state *state)
|
|
|
|
{
|
|
|
|
struct intel_connector *intel_connector = to_intel_connector(connector);
|
|
|
|
struct intel_dp *intel_dp = intel_connector->mst_port;
|
|
|
|
struct intel_crtc *crtc = to_intel_crtc(state->crtc);
|
|
|
|
|
|
|
|
return &intel_dp->mst_encoders[crtc->pipe]->base.base;
|
|
|
|
}
|
|
|
|
|
drm/dp_mst: Protect drm_dp_mst_port members with locking
This is a complicated one. Essentially, there's currently a problem in the MST
core that hasn't really caused any issues that we're aware of (emphasis on "that
we're aware of"): locking.
When we go through and probe the link addresses and path resources in a
topology, we hold no locks when updating ports with said information. The
members I'm referring to in particular are:
- ldps
- ddps
- mcs
- pdt
- dpcd_rev
- num_sdp_streams
- num_sdp_stream_sinks
- available_pbn
- input
- connector
Now that we're handling UP requests asynchronously and will be using some of
the struct members mentioned above in atomic modesetting in the future for
features such as PBN validation, this is going to become a lot more important.
As well, the next few commits that prepare us for and introduce suspend/resume
reprobing will also need clear locking in order to prevent from additional
racing hilarities that we never could have hit in the past.
So, let's solve this issue by using &mgr->base.lock, the modesetting
lock which currently only protects &mgr->base.state. This works
perfectly because it allows us to avoid blocking connection_mutex
unnecessarily, and we can grab this in connector detection paths since
it's a ww mutex. We start by having drm_dp_mst_handle_up_req() hold this
when updating ports. For drm_dp_mst_handle_link_address_port() things
are a bit more complicated. As I've learned the hard way, we can grab
&mgr->lock.base for everything except for port->connector. See, our
normal driver probing paths end up generating this rather obvious
lockdep chain:
&drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
However, sysfs grabs &drm->mode_config.mutex in order to protect itself
from connector state changing under it. Because this entails grabbing
kn->count, e.g. the lock that the kernel provides for protecting sysfs
contexts, we end up grabbing kn->count followed by
&drm->mode_config.mutex. This ends up creating an extremely rude chain:
&kn->count
-> &drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
I mean, look at that thing! It's just evil!!! This gross thing ends up
making any calls to drm_connector_register()/drm_connector_unregister()
impossible when holding any kind of modesetting lock. This is annoying
because ideally, we always want to ensure that
drm_dp_mst_port->connector never changes when doing an atomic commit or
check that would affect the atomic topology state so that it can
reliably and easily be used from future DRM DP MST helpers to assist
with tasks such as scanning through the current VCPI allocations and
adding connectors which need to have their allocations updated in
response to a bandwidth change or the like.
Being able to hold &mgr->base.lock throughout the entire link probe
process would have been _great_, since we could prevent userspace from
ever seeing any states in-between individual port changes and as a
result likely end up with a much faster probe and more consistent
results from said probes. But without some rework of how we handle
connector probing in sysfs it's not at all currently possible. In the
future, maybe we can try using the sysfs locks to protect updates to
connector probing state and fix this mess.
So for now, to protect everything other than port->connector under
&mgr->base.lock and ensure that we still have the guarantee that atomic
check/commit contexts will never see port->connector change we use a
silly trick. See: port->connector only needs to change in order to
ensure that input ports (see the MST spec) never have a ghost connector
associated with them. But, there's nothing stopping us from simply
throwing the entire port out and creating a new one in order to maintain
that requirement while still keeping port->connector consistent across
the lifetime of the port in atomic check/commit contexts. For all
intended purposes this works fine, as we validate ports in any contexts
we care about before using them and as such will end up reporting the
connector as disconnected until it's port's destruction finalizes. So,
we just do that in cases where we detect port->input has transitioned
from true->false. We don't need to worry about the other direction,
since a port without a connector isn't visible to userspace and as such
doesn't need to be protected by &mgr->base.lock until we finish
registering a connector for it.
For updating members of drm_dp_mst_port other than port->connector, we
simply grab &mgr->base.lock in drm_dp_mst_link_probe_work() for already
registered ports, update said members and drop the lock before
potentially registering a connector and probing the link address of it's
children.
Finally, we modify drm_dp_mst_detect_port() to take a modesetting lock
acquisition context in order to acquire &mgr->base.lock under
&connection_mutex and convert all it's users over to using the
.detect_ctx probe hooks.
With that, we finally have well defined locking.
Changes since v4:
* Get rid of port->mutex, stop using connection_mutex and just use our own
modesetting lock - mgr->base.lock. Also, add a probe_lock that comes
before this patch.
* Just throw out ports that get changed from an output to an input, and
replace them with new ports. This lets us ensure that modesetting
contexts never see port->connector go from having a connector to being
NULL.
* Write an extremely detailed explanation of what problems this is
trying to fix, since there's a _lot_ of context here and I honestly
forgot some of it myself a couple times.
* Don't grab mgr->lock when reading port->mstb in
drm_dp_mst_handle_link_address_port(). It's not needed.
Cc: Juston Li <juston.li@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Harry Wentland <hwentlan@amd.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Sean Paul <sean@poorly.run>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191022023641.8026-7-lyude@redhat.com
2019-06-18 05:59:29 +08:00
|
|
|
static int
|
|
|
|
intel_dp_mst_detect(struct drm_connector *connector,
|
|
|
|
struct drm_modeset_acquire_ctx *ctx, bool force)
|
|
|
|
{
|
|
|
|
struct intel_connector *intel_connector = to_intel_connector(connector);
|
|
|
|
struct intel_dp *intel_dp = intel_connector->mst_port;
|
|
|
|
|
|
|
|
if (drm_connector_is_unregistered(connector))
|
|
|
|
return connector_status_disconnected;
|
|
|
|
|
|
|
|
return drm_dp_mst_detect_port(connector, ctx, &intel_dp->mst_mgr,
|
|
|
|
intel_connector->port);
|
|
|
|
}
|
|
|
|
|
2014-05-02 12:02:48 +08:00
|
|
|
static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = {
|
|
|
|
.get_modes = intel_dp_mst_get_modes,
|
|
|
|
.mode_valid = intel_dp_mst_mode_valid,
|
2015-08-03 23:24:09 +08:00
|
|
|
.atomic_best_encoder = intel_mst_atomic_best_encoder,
|
2017-04-29 07:14:20 +08:00
|
|
|
.atomic_check = intel_dp_mst_atomic_check,
|
drm/dp_mst: Protect drm_dp_mst_port members with locking
This is a complicated one. Essentially, there's currently a problem in the MST
core that hasn't really caused any issues that we're aware of (emphasis on "that
we're aware of"): locking.
When we go through and probe the link addresses and path resources in a
topology, we hold no locks when updating ports with said information. The
members I'm referring to in particular are:
- ldps
- ddps
- mcs
- pdt
- dpcd_rev
- num_sdp_streams
- num_sdp_stream_sinks
- available_pbn
- input
- connector
Now that we're handling UP requests asynchronously and will be using some of
the struct members mentioned above in atomic modesetting in the future for
features such as PBN validation, this is going to become a lot more important.
As well, the next few commits that prepare us for and introduce suspend/resume
reprobing will also need clear locking in order to prevent from additional
racing hilarities that we never could have hit in the past.
So, let's solve this issue by using &mgr->base.lock, the modesetting
lock which currently only protects &mgr->base.state. This works
perfectly because it allows us to avoid blocking connection_mutex
unnecessarily, and we can grab this in connector detection paths since
it's a ww mutex. We start by having drm_dp_mst_handle_up_req() hold this
when updating ports. For drm_dp_mst_handle_link_address_port() things
are a bit more complicated. As I've learned the hard way, we can grab
&mgr->lock.base for everything except for port->connector. See, our
normal driver probing paths end up generating this rather obvious
lockdep chain:
&drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
However, sysfs grabs &drm->mode_config.mutex in order to protect itself
from connector state changing under it. Because this entails grabbing
kn->count, e.g. the lock that the kernel provides for protecting sysfs
contexts, we end up grabbing kn->count followed by
&drm->mode_config.mutex. This ends up creating an extremely rude chain:
&kn->count
-> &drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
I mean, look at that thing! It's just evil!!! This gross thing ends up
making any calls to drm_connector_register()/drm_connector_unregister()
impossible when holding any kind of modesetting lock. This is annoying
because ideally, we always want to ensure that
drm_dp_mst_port->connector never changes when doing an atomic commit or
check that would affect the atomic topology state so that it can
reliably and easily be used from future DRM DP MST helpers to assist
with tasks such as scanning through the current VCPI allocations and
adding connectors which need to have their allocations updated in
response to a bandwidth change or the like.
Being able to hold &mgr->base.lock throughout the entire link probe
process would have been _great_, since we could prevent userspace from
ever seeing any states in-between individual port changes and as a
result likely end up with a much faster probe and more consistent
results from said probes. But without some rework of how we handle
connector probing in sysfs it's not at all currently possible. In the
future, maybe we can try using the sysfs locks to protect updates to
connector probing state and fix this mess.
So for now, to protect everything other than port->connector under
&mgr->base.lock and ensure that we still have the guarantee that atomic
check/commit contexts will never see port->connector change we use a
silly trick. See: port->connector only needs to change in order to
ensure that input ports (see the MST spec) never have a ghost connector
associated with them. But, there's nothing stopping us from simply
throwing the entire port out and creating a new one in order to maintain
that requirement while still keeping port->connector consistent across
the lifetime of the port in atomic check/commit contexts. For all
intended purposes this works fine, as we validate ports in any contexts
we care about before using them and as such will end up reporting the
connector as disconnected until it's port's destruction finalizes. So,
we just do that in cases where we detect port->input has transitioned
from true->false. We don't need to worry about the other direction,
since a port without a connector isn't visible to userspace and as such
doesn't need to be protected by &mgr->base.lock until we finish
registering a connector for it.
For updating members of drm_dp_mst_port other than port->connector, we
simply grab &mgr->base.lock in drm_dp_mst_link_probe_work() for already
registered ports, update said members and drop the lock before
potentially registering a connector and probing the link address of it's
children.
Finally, we modify drm_dp_mst_detect_port() to take a modesetting lock
acquisition context in order to acquire &mgr->base.lock under
&connection_mutex and convert all it's users over to using the
.detect_ctx probe hooks.
With that, we finally have well defined locking.
Changes since v4:
* Get rid of port->mutex, stop using connection_mutex and just use our own
modesetting lock - mgr->base.lock. Also, add a probe_lock that comes
before this patch.
* Just throw out ports that get changed from an output to an input, and
replace them with new ports. This lets us ensure that modesetting
contexts never see port->connector go from having a connector to being
NULL.
* Write an extremely detailed explanation of what problems this is
trying to fix, since there's a _lot_ of context here and I honestly
forgot some of it myself a couple times.
* Don't grab mgr->lock when reading port->mstb in
drm_dp_mst_handle_link_address_port(). It's not needed.
Cc: Juston Li <juston.li@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Harry Wentland <hwentlan@amd.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Sean Paul <sean@poorly.run>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191022023641.8026-7-lyude@redhat.com
2019-06-18 05:59:29 +08:00
|
|
|
.detect_ctx = intel_dp_mst_detect,
|
2014-05-02 12:02:48 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder)
|
|
|
|
{
|
2019-12-05 02:05:43 +08:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(to_intel_encoder(encoder));
|
2014-05-02 12:02:48 +08:00
|
|
|
|
|
|
|
drm_encoder_cleanup(encoder);
|
|
|
|
kfree(intel_mst);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct drm_encoder_funcs intel_dp_mst_enc_funcs = {
|
|
|
|
.destroy = intel_dp_mst_encoder_destroy,
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool intel_dp_mst_get_hw_state(struct intel_connector *connector)
|
|
|
|
{
|
2019-12-05 02:05:45 +08:00
|
|
|
if (intel_attached_encoder(connector) && connector->base.state->crtc) {
|
2014-05-02 12:02:48 +08:00
|
|
|
enum pipe pipe;
|
2019-12-05 02:05:45 +08:00
|
|
|
if (!intel_attached_encoder(connector)->get_hw_state(intel_attached_encoder(connector), &pipe))
|
2014-05-02 12:02:48 +08:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-05-13 17:38:36 +08:00
|
|
|
static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *pathprop)
|
2014-05-02 12:02:48 +08:00
|
|
|
{
|
|
|
|
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;
|
2017-10-13 18:24:46 +08:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2014-05-02 12:02:48 +08:00
|
|
|
struct intel_connector *intel_connector;
|
|
|
|
struct drm_connector *connector;
|
2017-10-13 18:24:46 +08:00
|
|
|
enum pipe pipe;
|
2017-10-14 02:01:44 +08:00
|
|
|
int ret;
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2015-04-10 15:59:10 +08:00
|
|
|
intel_connector = intel_connector_alloc();
|
2014-05-02 12:02:48 +08:00
|
|
|
if (!intel_connector)
|
|
|
|
return NULL;
|
|
|
|
|
2018-11-07 05:30:12 +08:00
|
|
|
intel_connector->get_hw_state = intel_dp_mst_get_hw_state;
|
|
|
|
intel_connector->mst_port = intel_dp;
|
|
|
|
intel_connector->port = port;
|
2019-01-11 08:53:33 +08:00
|
|
|
drm_dp_mst_get_port_malloc(port);
|
2018-11-07 05:30:12 +08:00
|
|
|
|
2014-05-02 12:02:48 +08:00
|
|
|
connector = &intel_connector->base;
|
2017-10-14 02:01:44 +08:00
|
|
|
ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs,
|
|
|
|
DRM_MODE_CONNECTOR_DisplayPort);
|
|
|
|
if (ret) {
|
|
|
|
intel_connector_free(intel_connector);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-05-02 12:02:48 +08:00
|
|
|
drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs);
|
|
|
|
|
2017-10-13 18:24:46 +08:00
|
|
|
for_each_pipe(dev_priv, pipe) {
|
2017-10-14 02:01:44 +08:00
|
|
|
struct drm_encoder *enc =
|
|
|
|
&intel_dp->mst_encoders[pipe]->base.base;
|
|
|
|
|
2018-07-09 16:40:07 +08:00
|
|
|
ret = drm_connector_attach_encoder(&intel_connector->base, enc);
|
2017-10-14 02:01:44 +08:00
|
|
|
if (ret)
|
|
|
|
goto err;
|
2014-05-02 12:02:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
|
2014-10-20 14:30:50 +08:00
|
|
|
drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0);
|
|
|
|
|
2018-07-09 16:40:08 +08:00
|
|
|
ret = drm_connector_set_path_property(connector, pathprop);
|
2017-10-14 02:01:44 +08:00
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
|
2019-03-27 21:19:29 +08:00
|
|
|
intel_attach_force_audio_property(connector);
|
2019-03-26 22:25:51 +08:00
|
|
|
intel_attach_broadcast_rgb_property(connector);
|
2019-08-21 00:16:57 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Reuse the prop from the SST connector because we're
|
|
|
|
* not allowed to create new props after device registration.
|
|
|
|
*/
|
|
|
|
connector->max_bpc_property =
|
|
|
|
intel_dp->attached_connector->base.max_bpc_property;
|
|
|
|
if (connector->max_bpc_property)
|
|
|
|
drm_connector_attach_max_bpc_property(connector, 6, 12);
|
2019-03-26 22:25:51 +08:00
|
|
|
|
2015-09-16 15:55:23 +08:00
|
|
|
return connector;
|
2017-10-14 02:01:44 +08:00
|
|
|
|
|
|
|
err:
|
|
|
|
drm_connector_cleanup(connector);
|
|
|
|
return NULL;
|
2015-09-16 15:55:23 +08:00
|
|
|
}
|
|
|
|
|
2015-12-31 05:20:30 +08:00
|
|
|
static const struct drm_dp_mst_topology_cbs mst_cbs = {
|
2014-05-02 12:02:48 +08:00
|
|
|
.add_connector = intel_dp_add_mst_connector,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct intel_dp_mst_encoder *
|
|
|
|
intel_dp_create_fake_mst_encoder(struct intel_digital_port *intel_dig_port, enum pipe pipe)
|
|
|
|
{
|
|
|
|
struct intel_dp_mst_encoder *intel_mst;
|
|
|
|
struct intel_encoder *intel_encoder;
|
|
|
|
struct drm_device *dev = intel_dig_port->base.base.dev;
|
|
|
|
|
|
|
|
intel_mst = kzalloc(sizeof(*intel_mst), GFP_KERNEL);
|
|
|
|
|
|
|
|
if (!intel_mst)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
intel_mst->pipe = pipe;
|
|
|
|
intel_encoder = &intel_mst->base;
|
|
|
|
intel_mst->primary = intel_dig_port;
|
|
|
|
|
|
|
|
drm_encoder_init(dev, &intel_encoder->base, &intel_dp_mst_enc_funcs,
|
2016-05-28 01:59:24 +08:00
|
|
|
DRM_MODE_ENCODER_DPMST, "DP-MST %c", pipe_name(pipe));
|
2014-05-02 12:02:48 +08:00
|
|
|
|
|
|
|
intel_encoder->type = INTEL_OUTPUT_DP_MST;
|
2017-02-22 14:34:27 +08:00
|
|
|
intel_encoder->power_domain = intel_dig_port->base.power_domain;
|
2017-11-09 23:24:34 +08:00
|
|
|
intel_encoder->port = intel_dig_port->base.port;
|
2014-05-02 12:02:48 +08:00
|
|
|
intel_encoder->cloneable = 0;
|
2019-10-03 00:25:05 +08:00
|
|
|
/*
|
|
|
|
* This is wrong, but broken userspace uses the intersection
|
|
|
|
* of possible_crtcs of all the encoders of a given connector
|
|
|
|
* to figure out which crtcs can drive said connector. What
|
|
|
|
* should be used instead is the union of possible_crtcs.
|
|
|
|
* To keep such userspace functioning we must misconfigure
|
|
|
|
* this to make sure the intersection is not empty :(
|
|
|
|
*/
|
2019-10-03 00:25:04 +08:00
|
|
|
intel_encoder->pipe_mask = ~0;
|
2014-05-02 12:02:48 +08:00
|
|
|
|
|
|
|
intel_encoder->compute_config = intel_dp_mst_compute_config;
|
2020-03-14 00:48:19 +08:00
|
|
|
intel_encoder->compute_config_late = intel_dp_mst_compute_config_late;
|
2014-05-02 12:02:48 +08:00
|
|
|
intel_encoder->disable = intel_mst_disable_dp;
|
|
|
|
intel_encoder->post_disable = intel_mst_post_disable_dp;
|
2017-10-27 21:43:48 +08:00
|
|
|
intel_encoder->pre_pll_enable = intel_mst_pre_pll_enable_dp;
|
2014-05-02 12:02:48 +08:00
|
|
|
intel_encoder->pre_enable = intel_mst_pre_enable_dp;
|
|
|
|
intel_encoder->enable = intel_mst_enable_dp;
|
|
|
|
intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state;
|
|
|
|
intel_encoder->get_config = intel_dp_mst_enc_get_config;
|
|
|
|
|
|
|
|
return intel_mst;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
intel_dp_create_fake_mst_encoders(struct intel_digital_port *intel_dig_port)
|
|
|
|
{
|
|
|
|
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
2017-10-13 18:24:46 +08:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
|
|
|
|
enum pipe pipe;
|
2014-05-02 12:02:48 +08:00
|
|
|
|
2017-10-13 18:24:46 +08:00
|
|
|
for_each_pipe(dev_priv, pipe)
|
|
|
|
intel_dp->mst_encoders[pipe] = intel_dp_create_fake_mst_encoder(intel_dig_port, pipe);
|
2014-05-02 12:02:48 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-08-06 18:07:26 +08:00
|
|
|
int
|
|
|
|
intel_dp_mst_encoder_active_links(struct intel_digital_port *intel_dig_port)
|
|
|
|
{
|
|
|
|
return intel_dig_port->dp.active_mst_links;
|
|
|
|
}
|
|
|
|
|
2014-05-02 12:02:48 +08:00
|
|
|
int
|
|
|
|
intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_base_id)
|
|
|
|
{
|
2019-10-11 09:09:03 +08:00
|
|
|
struct drm_i915_private *i915 = to_i915(intel_dig_port->base.base.dev);
|
2014-05-02 12:02:48 +08:00
|
|
|
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
2019-10-11 09:09:03 +08:00
|
|
|
enum port port = intel_dig_port->base.port;
|
2014-05-02 12:02:48 +08:00
|
|
|
int ret;
|
|
|
|
|
2019-10-11 09:09:03 +08:00
|
|
|
if (!HAS_DP_MST(i915) || intel_dp_is_edp(intel_dp))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (INTEL_GEN(i915) < 12 && port == PORT_A)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (INTEL_GEN(i915) < 11 && port == PORT_E)
|
|
|
|
return 0;
|
|
|
|
|
2014-05-02 12:02:48 +08:00
|
|
|
intel_dp->mst_mgr.cbs = &mst_cbs;
|
|
|
|
|
|
|
|
/* create encoders */
|
|
|
|
intel_dp_create_fake_mst_encoders(intel_dig_port);
|
2019-10-11 09:09:03 +08:00
|
|
|
ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, &i915->drm,
|
2017-01-25 07:49:29 +08:00
|
|
|
&intel_dp->aux, 16, 3, conn_base_id);
|
2019-10-11 09:09:03 +08:00
|
|
|
if (ret)
|
2014-05-02 12:02:48 +08:00
|
|
|
return ret;
|
2019-10-11 09:09:03 +08:00
|
|
|
|
|
|
|
intel_dp->can_mst = true;
|
|
|
|
|
2014-05-02 12:02:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port)
|
|
|
|
{
|
|
|
|
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
|
|
|
|
|
|
|
if (!intel_dp->can_mst)
|
|
|
|
return;
|
|
|
|
|
|
|
|
drm_dp_mst_topology_mgr_destroy(&intel_dp->mst_mgr);
|
|
|
|
/* encoders will get killed by normal cleanup */
|
|
|
|
}
|
2019-12-23 09:06:49 +08:00
|
|
|
|
|
|
|
bool intel_dp_mst_is_master_trans(const struct intel_crtc_state *crtc_state)
|
|
|
|
{
|
|
|
|
return crtc_state->mst_master_transcoder == crtc_state->cpu_transcoder;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool intel_dp_mst_is_slave_trans(const struct intel_crtc_state *crtc_state)
|
|
|
|
{
|
|
|
|
return crtc_state->mst_master_transcoder != INVALID_TRANSCODER &&
|
|
|
|
crtc_state->mst_master_transcoder != crtc_state->cpu_transcoder;
|
|
|
|
}
|