Commit 57c2af79 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'topic/mst-suspend-resume-reprobe-2019-10-29-2' of...

Merge tag 'topic/mst-suspend-resume-reprobe-2019-10-29-2' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

UAPI Changes:

Cross-subsystem Changes:

Core Changes:
* Handle UP requests asynchronously in the DP MST helpers, fixing
  hotplug notifications and allowing us to implement suspend/resume
  reprobing
* Add basic suspend/resume reprobing to the DP MST helpers
* Improve locking for link address reprobing and connection status
  request handling in the DP MST helpers
* Miscellaneous refactoring in the DP MST helpers
* Add a Kconfig option to the DP MST helpers to enable tracking of
  gets/puts for topology references for debugging purposes

Driver Changes:
* nouveau: Resume hotplug interrupts earlier, so that sideband
  messages may be transmitted during resume and thus allow
  suspend/resume reprobing for DP MST to work
* nouveau: Avoid grabbing runtime PM references when handling short DP
  pulses, so that handling sideband messages in resume codepaths with the
  DP MST helpers doesn't deadlock us
* i915, nouveau, amdgpu, radeon: Use detect_ctx for probing MST
  connectors, so that we can grab the topology manager's atomic lock

Note: there's some amdgpu patches that I didn't realize were pushed
upstream already when creating this topic branch. When they fail to
apply, you can just ignore and skip them.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/a74c6446bc960190d195a751cb6d8a00a98f3974.camel@redhat.com
parents 8c84b43f 12a280c7
......@@ -93,6 +93,20 @@ config DRM_KMS_FB_HELPER
help
FBDEV helpers for KMS drivers.
config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
bool "Enable refcount backtrace history in the DP MST helpers"
select STACKDEPOT
depends on DRM_KMS_HELPER
depends on DEBUG_KERNEL
depends on EXPERT
help
Enables debug tracing for topology refs in DRM's DP MST helpers. A
history of each topology reference/dereference will be printed to the
kernel log once a port or branch device's topology refcount reaches 0.
This has the potential to use a lot of memory and print some very
large kernel messages. If in doubt, say "N".
config DRM_FBDEV_EMULATION
bool "Enable legacy fbdev support for your modesetting driver"
depends on DRM
......
......@@ -1028,7 +1028,7 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
if (suspend) {
drm_dp_mst_topology_mgr_suspend(mgr);
} else {
ret = drm_dp_mst_topology_mgr_resume(mgr);
ret = drm_dp_mst_topology_mgr_resume(mgr, true);
if (ret < 0) {
drm_dp_mst_topology_mgr_set_mst(mgr, false);
need_hotplug = true;
......
......@@ -123,21 +123,6 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
return result;
}
static enum drm_connector_status
dm_dp_mst_detect(struct drm_connector *connector, bool force)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
struct amdgpu_dm_connector *master = aconnector->mst_port;
enum drm_connector_status status =
drm_dp_mst_detect_port(
connector,
&master->mst_mgr,
aconnector->port);
return status;
}
static void
dm_dp_mst_connector_destroy(struct drm_connector *connector)
{
......@@ -175,7 +160,6 @@ amdgpu_dm_mst_connector_early_unregister(struct drm_connector *connector)
}
static const struct drm_connector_funcs dm_dp_mst_connector_funcs = {
.detect = dm_dp_mst_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = dm_dp_mst_connector_destroy,
.reset = amdgpu_dm_connector_funcs_reset,
......@@ -250,10 +234,22 @@ dm_mst_atomic_best_encoder(struct drm_connector *connector,
return &to_amdgpu_dm_connector(connector)->mst_encoder->base;
}
static int
dm_dp_mst_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx, bool force)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
struct amdgpu_dm_connector *master = aconnector->mst_port;
return drm_dp_mst_detect_port(connector, ctx, &master->mst_mgr,
aconnector->port);
}
static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs = {
.get_modes = dm_dp_mst_get_modes,
.mode_valid = amdgpu_dm_connector_mode_valid,
.atomic_best_encoder = dm_mst_atomic_best_encoder,
.detect_ctx = dm_dp_mst_detect,
};
static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder)
......
This diff is collapsed.
......@@ -7625,7 +7625,8 @@ void intel_dp_mst_resume(struct drm_i915_private *dev_priv)
if (!intel_dp->can_mst)
continue;
ret = drm_dp_mst_topology_mgr_resume(&intel_dp->mst_mgr);
ret = drm_dp_mst_topology_mgr_resume(&intel_dp->mst_mgr,
true);
if (ret) {
intel_dp->is_mst = false;
drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
......
......@@ -391,20 +391,7 @@ static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
return ret;
}
static enum drm_connector_status
intel_dp_mst_detect(struct drm_connector *connector, 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, &intel_dp->mst_mgr,
intel_connector->port);
}
static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
.detect = intel_dp_mst_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_get_property = intel_digital_connector_atomic_get_property,
.atomic_set_property = intel_digital_connector_atomic_set_property,
......@@ -465,11 +452,26 @@ static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *c
return &intel_dp->mst_encoders[crtc->pipe]->base.base;
}
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);
}
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,
.atomic_best_encoder = intel_mst_atomic_best_encoder,
.atomic_check = intel_dp_mst_atomic_check,
.detect_ctx = intel_dp_mst_detect,
};
static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder)
......
......@@ -986,20 +986,11 @@ nv50_mstc_atomic_check(struct drm_connector *connector,
return drm_dp_atomic_release_vcpi_slots(state, mgr, mstc->port);
}
static const struct drm_connector_helper_funcs
nv50_mstc_help = {
.get_modes = nv50_mstc_get_modes,
.mode_valid = nv50_mstc_mode_valid,
.best_encoder = nv50_mstc_best_encoder,
.atomic_best_encoder = nv50_mstc_atomic_best_encoder,
.atomic_check = nv50_mstc_atomic_check,
};
static enum drm_connector_status
nv50_mstc_detect(struct drm_connector *connector, bool force)
static int
nv50_mstc_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx, bool force)
{
struct nv50_mstc *mstc = nv50_mstc(connector);
enum drm_connector_status conn_status;
int ret;
if (drm_connector_is_unregistered(connector))
......@@ -1009,14 +1000,24 @@ nv50_mstc_detect(struct drm_connector *connector, bool force)
if (ret < 0 && ret != -EACCES)
return connector_status_disconnected;
conn_status = drm_dp_mst_detect_port(connector, mstc->port->mgr,
ret = drm_dp_mst_detect_port(connector, ctx, mstc->port->mgr,
mstc->port);
pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);
return conn_status;
return ret;
}
static const struct drm_connector_helper_funcs
nv50_mstc_help = {
.get_modes = nv50_mstc_get_modes,
.mode_valid = nv50_mstc_mode_valid,
.best_encoder = nv50_mstc_best_encoder,
.atomic_best_encoder = nv50_mstc_atomic_best_encoder,
.atomic_check = nv50_mstc_atomic_check,
.detect_ctx = nv50_mstc_detect,
};
static void
nv50_mstc_destroy(struct drm_connector *connector)
{
......@@ -1031,7 +1032,6 @@ nv50_mstc_destroy(struct drm_connector *connector)
static const struct drm_connector_funcs
nv50_mstc = {
.reset = nouveau_conn_reset,
.detect = nv50_mstc_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = nv50_mstc_destroy,
.atomic_duplicate_state = nouveau_conn_atomic_duplicate_state,
......@@ -1309,14 +1309,14 @@ nv50_mstm_fini(struct nv50_mstm *mstm)
}
static void
nv50_mstm_init(struct nv50_mstm *mstm)
nv50_mstm_init(struct nv50_mstm *mstm, bool runtime)
{
int ret;
if (!mstm || !mstm->mgr.mst_state)
return;
ret = drm_dp_mst_topology_mgr_resume(&mstm->mgr);
ret = drm_dp_mst_topology_mgr_resume(&mstm->mgr, !runtime);
if (ret == -1) {
drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, false);
drm_kms_helper_hotplug_event(mstm->mgr.dev);
......@@ -2263,7 +2263,7 @@ nv50_display_init(struct drm_device *dev, bool resume, bool runtime)
if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) {
struct nouveau_encoder *nv_encoder =
nouveau_encoder(encoder);
nv50_mstm_init(nv_encoder->dp.mstm);
nv50_mstm_init(nv_encoder->dp.mstm, runtime);
}
}
......
......@@ -1130,6 +1130,16 @@ nouveau_connector_hotplug(struct nvif_notify *notify)
const char *name = connector->name;
struct nouveau_encoder *nv_encoder;
int ret;
bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG);
if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) {
NV_DEBUG(drm, "service %s\n", name);
drm_dp_cec_irq(&nv_connector->aux);
if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP)))
nv50_mstm_service(nv_encoder->dp.mstm);
return NVIF_NOTIFY_KEEP;
}
ret = pm_runtime_get(drm->dev->dev);
if (ret == 0) {
......@@ -1150,14 +1160,6 @@ nouveau_connector_hotplug(struct nvif_notify *notify)
return NVIF_NOTIFY_DROP;
}
if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) {
NV_DEBUG(drm, "service %s\n", name);
drm_dp_cec_irq(&nv_connector->aux);
if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP)))
nv50_mstm_service(nv_encoder->dp.mstm);
} else {
bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG);
if (!plugged)
drm_dp_cec_unset_edid(&nv_connector->aux);
NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name);
......@@ -1167,7 +1169,6 @@ nouveau_connector_hotplug(struct nvif_notify *notify)
}
drm_helper_hpd_irq_event(connector->dev);
}
pm_runtime_mark_last_busy(drm->dev->dev);
pm_runtime_put_autosuspend(drm->dev->dev);
......
......@@ -407,6 +407,17 @@ nouveau_display_init(struct drm_device *dev, bool resume, bool runtime)
struct drm_connector_list_iter conn_iter;
int ret;
/*
* Enable hotplug interrupts (done as early as possible, since we need
* them for MST)
*/
drm_connector_list_iter_begin(dev, &conn_iter);
nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
struct nouveau_connector *conn = nouveau_connector(connector);
nvif_notify_get(&conn->hpd);
}
drm_connector_list_iter_end(&conn_iter);
ret = disp->init(dev, resume, runtime);
if (ret)
return ret;
......@@ -416,14 +427,6 @@ nouveau_display_init(struct drm_device *dev, bool resume, bool runtime)
*/
drm_kms_helper_poll_enable(dev);
/* enable hotplug interrupts */
drm_connector_list_iter_begin(dev, &conn_iter);
nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
struct nouveau_connector *conn = nouveau_connector(connector);
nvif_notify_get(&conn->hpd);
}
drm_connector_list_iter_end(&conn_iter);
return ret;
}
......
......@@ -233,21 +233,26 @@ drm_encoder *radeon_mst_best_encoder(struct drm_connector *connector)
return &radeon_connector->mst_encoder->base;
}
static int
radeon_dp_mst_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
{
struct radeon_connector *radeon_connector =
to_radeon_connector(connector);
struct radeon_connector *master = radeon_connector->mst_port;
return drm_dp_mst_detect_port(connector, ctx, &master->mst_mgr,
radeon_connector->port);
}
static const struct drm_connector_helper_funcs radeon_dp_mst_connector_helper_funcs = {
.get_modes = radeon_dp_mst_get_modes,
.mode_valid = radeon_dp_mst_mode_valid,
.best_encoder = radeon_mst_best_encoder,
.detect_ctx = radeon_dp_mst_detect,
};
static enum drm_connector_status
radeon_dp_mst_detect(struct drm_connector *connector, bool force)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector *master = radeon_connector->mst_port;
return drm_dp_mst_detect_port(connector, &master->mst_mgr, radeon_connector->port);
}
static void
radeon_dp_mst_connector_destroy(struct drm_connector *connector)
{
......@@ -262,7 +267,6 @@ radeon_dp_mst_connector_destroy(struct drm_connector *connector)
static const struct drm_connector_funcs radeon_dp_mst_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = radeon_dp_mst_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = radeon_dp_mst_connector_destroy,
};
......
......@@ -26,6 +26,26 @@
#include <drm/drm_dp_helper.h>
#include <drm/drm_atomic.h>
#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS)
#include <linux/stackdepot.h>
#include <linux/timekeeping.h>
enum drm_dp_mst_topology_ref_type {
DRM_DP_MST_TOPOLOGY_REF_GET,
DRM_DP_MST_TOPOLOGY_REF_PUT,
};
struct drm_dp_mst_topology_ref_history {
struct drm_dp_mst_topology_ref_entry {
enum drm_dp_mst_topology_ref_type type;
int count;
ktime_t ts_nsec;
depot_stack_handle_t backtrace;
} *entries;
int len;
};
#endif /* IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) */
struct drm_dp_mst_branch;
/**
......@@ -45,21 +65,31 @@ struct drm_dp_vcpi {
/**
* struct drm_dp_mst_port - MST port
* @port_num: port number
* @input: if this port is an input port.
* @mcs: message capability status - DP 1.2 spec.
* @ddps: DisplayPort Device Plug Status - DP 1.2
* @pdt: Peer Device Type
* @ldps: Legacy Device Plug Status
* @dpcd_rev: DPCD revision of device on this port
* @num_sdp_streams: Number of simultaneous streams
* @num_sdp_stream_sinks: Number of stream sinks
* @available_pbn: Available bandwidth for this port.
* @input: if this port is an input port. Protected by
* &drm_dp_mst_topology_mgr.base.lock.
* @mcs: message capability status - DP 1.2 spec. Protected by
* &drm_dp_mst_topology_mgr.base.lock.
* @ddps: DisplayPort Device Plug Status - DP 1.2. Protected by
* &drm_dp_mst_topology_mgr.base.lock.
* @pdt: Peer Device Type. Protected by
* &drm_dp_mst_topology_mgr.base.lock.
* @ldps: Legacy Device Plug Status. Protected by
* &drm_dp_mst_topology_mgr.base.lock.
* @dpcd_rev: DPCD revision of device on this port. Protected by
* &drm_dp_mst_topology_mgr.base.lock.
* @num_sdp_streams: Number of simultaneous streams. Protected by
* &drm_dp_mst_topology_mgr.base.lock.
* @num_sdp_stream_sinks: Number of stream sinks. Protected by
* &drm_dp_mst_topology_mgr.base.lock.
* @available_pbn: Available bandwidth for this port. Protected by
* &drm_dp_mst_topology_mgr.base.lock.
* @next: link to next port on this branch device
* @mstb: branch device attach below this port
* @aux: i2c aux transport to talk to device connected to this port.
* @aux: i2c aux transport to talk to device connected to this port, protected
* by &drm_dp_mst_topology_mgr.base.lock.
* @parent: branch device parent of this port
* @vcpi: Virtual Channel Payload info for this port.
* @connector: DRM connector this port is connected to.
* @connector: DRM connector this port is connected to. Protected by
* &drm_dp_mst_topology_mgr.base.lock.
* @mgr: topology manager this port lives under.
*
* This structure represents an MST port endpoint on a device somewhere
......@@ -79,6 +109,14 @@ struct drm_dp_mst_port {
*/
struct kref malloc_kref;
#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS)
/**
* @topology_ref_history: A history of each topology
* reference/dereference. See CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS.
*/
struct drm_dp_mst_topology_ref_history topology_ref_history;
#endif
u8 port_num;
bool input;
bool mcs;
......@@ -90,7 +128,17 @@ struct drm_dp_mst_port {
u8 num_sdp_stream_sinks;
uint16_t available_pbn;
struct list_head next;
struct drm_dp_mst_branch *mstb; /* pointer to an mstb if this port has one */
/**
* @mstb: the branch device connected to this port, if there is one.
* This should be considered protected for reading by
* &drm_dp_mst_topology_mgr.lock. There are two exceptions to this:
* &drm_dp_mst_topology_mgr.up_req_work and
* &drm_dp_mst_topology_mgr.work, which do not grab
* &drm_dp_mst_topology_mgr.lock during reads but are the only
* updaters of this list and are protected from writing concurrently
* by &drm_dp_mst_topology_mgr.probe_lock.
*/
struct drm_dp_mst_branch *mstb;
struct drm_dp_aux aux; /* i2c bus for this port? */
struct drm_dp_mst_branch *parent;
......@@ -116,7 +164,6 @@ struct drm_dp_mst_port {
* @lct: Link count total to talk to this branch device.
* @num_ports: number of ports on the branch.
* @msg_slots: one bit per transmitted msg slot.
* @ports: linked list of ports on this branch.
* @port_parent: pointer to the port parent, NULL if toplevel.
* @mgr: topology manager for this branch device.
* @tx_slots: transmission slots for this device.
......@@ -143,11 +190,35 @@ struct drm_dp_mst_branch {
*/
struct kref malloc_kref;
#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS)
/**
* @topology_ref_history: A history of each topology
* reference/dereference. See CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS.
*/
struct drm_dp_mst_topology_ref_history topology_ref_history;
#endif
/**
* @destroy_next: linked-list entry used by
* drm_dp_delayed_destroy_work()
*/
struct list_head destroy_next;
u8 rad[8];
u8 lct;
int num_ports;
int msg_slots;
/**
* @ports: the list of ports on this branch device. This should be
* considered protected for reading by &drm_dp_mst_topology_mgr.lock.
* There are two exceptions to this:
* &drm_dp_mst_topology_mgr.up_req_work and
* &drm_dp_mst_topology_mgr.work, which do not grab
* &drm_dp_mst_topology_mgr.lock during reads but are the only
* updaters of this list and are protected from updating the list
* concurrently by @drm_dp_mst_topology_mgr.probe_lock
*/
struct list_head ports;
/* list of tx ops queue for this port */
......@@ -494,6 +565,13 @@ struct drm_dp_mst_topology_mgr {
*/
struct mutex lock;
/**
* @probe_lock: Prevents @work and @up_req_work, the only writers of
* &drm_dp_mst_port.mstb and &drm_dp_mst_branch.ports, from racing
* while they update the topology.
*/
struct mutex probe_lock;
/**
* @mst_state: If this manager is enabled for an MST capable port. False
* if no MST sink/branch devices is connected.
......@@ -571,18 +649,49 @@ struct drm_dp_mst_topology_mgr {
struct work_struct tx_work;
/**
* @destroy_connector_list: List of to be destroyed connectors.
* @destroy_port_list: List of to be destroyed connectors.
*/
struct list_head destroy_port_list;
/**
* @destroy_branch_device_list: List of to be destroyed branch
* devices.
*/
struct list_head destroy_connector_list;
struct list_head destroy_branch_device_list;
/**
* @destroy_connector_lock: Protects @connector_list.
* @delayed_destroy_lock: Protects @destroy_port_list and
* @destroy_branch_device_list.
*/
struct mutex destroy_connector_lock;
struct mutex delayed_destroy_lock;
/**
* @destroy_connector_work: Work item to destroy connectors. Needed to
* avoid locking inversion.
* @delayed_destroy_work: Work item to destroy MST port and branch
* devices, needed to avoid locking inversion.
*/
struct work_struct destroy_connector_work;
struct work_struct delayed_destroy_work;
/**
* @up_req_list: List of pending up requests from the topology that
* need to be processed, in chronological order.
*/
struct list_head up_req_list;
/**
* @up_req_lock: Protects @up_req_list
*/
struct mutex up_req_lock;
/**
* @up_req_work: Work item to process up requests received from the
* topology. Needed to avoid blocking hotplug handling and sideband
* transmissions.
*/
struct work_struct up_req_work;
#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS)
/**
* @topology_ref_history_lock: protects
* &drm_dp_mst_port.topology_ref_history and
* &drm_dp_mst_branch.topology_ref_history.
*/
struct mutex topology_ref_history_lock;
#endif
};
int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
......@@ -599,7 +708,11 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled);
enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
int
drm_dp_mst_detect_port(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port);
bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port);
......@@ -638,7 +751,8 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr);
int __must_check
drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr);
drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr,
bool sync);
ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux,
unsigned int offset, void *buffer, size_t size);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment