Skip to content

Commit

Permalink
drm/dp: Introduce MST topology state to track available link bandwidth
Browse files Browse the repository at this point in the history
Link bandwidth is shared between multiple display streams in DP MST
configurations. The DP MST topology manager structure maintains the
shared link bandwidth for a primary link directly connected to the GPU. For
atomic modesetting drivers, checking if there is sufficient link bandwidth
for a mode needs to be done during the atomic_check phase to avoid failed
modesets. Let's encapsulate the available link bw information in a
private state structure so that bw can be allocated and released atomically
for each of the ports sharing the primary link.

v3: WARN_ON() if connection_mutex is not held (Archit)
v2: Included kernel doc, moved state initialization and switched to
kmemdup() for allocation (Daniel)

Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Archit Taneja <architt@codeaurora.org>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Harry Wentland <Harry.wentland@amd.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1492753893-3748-3-git-send-email-dhinakaran.pandiyan@intel.com
  • Loading branch information
Pandiyan, Dhinakaran authored and Maarten Lankhorst committed May 4, 2017
1 parent b430c27 commit 3f3353b
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 0 deletions.
75 changes: 75 additions & 0 deletions drivers/gpu/drm/drm_dp_mst_topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -2936,6 +2936,69 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
(*mgr->cbs->hotplug)(mgr);
}

void *drm_dp_mst_duplicate_state(struct drm_atomic_state *state, void *obj)
{
struct drm_dp_mst_topology_mgr *mgr = obj;
struct drm_dp_mst_topology_state *new_mst_state;

if (WARN_ON(!mgr->state))
return NULL;

new_mst_state = kmemdup(mgr->state, sizeof(*new_mst_state), GFP_KERNEL);
if (new_mst_state)
new_mst_state->state = state;
return new_mst_state;
}

void drm_dp_mst_swap_state(void *obj, void **obj_state_ptr)
{
struct drm_dp_mst_topology_mgr *mgr = obj;
struct drm_dp_mst_topology_state **topology_state_ptr;

topology_state_ptr = (struct drm_dp_mst_topology_state **)obj_state_ptr;

mgr->state->state = (*topology_state_ptr)->state;
swap(*topology_state_ptr, mgr->state);
mgr->state->state = NULL;
}

void drm_dp_mst_destroy_state(void *obj_state)
{
kfree(obj_state);
}

static const struct drm_private_state_funcs mst_state_funcs = {
.duplicate_state = drm_dp_mst_duplicate_state,
.swap_state = drm_dp_mst_swap_state,
.destroy_state = drm_dp_mst_destroy_state,
};

/**
* drm_atomic_get_mst_topology_state: get MST topology state
*
* @state: global atomic state
* @mgr: MST topology manager, also the private object in this case
*
* This function wraps drm_atomic_get_priv_obj_state() passing in the MST atomic
* state vtable so that the private object state returned is that of a MST
* topology object. Also, drm_atomic_get_private_obj_state() expects the caller
* to care of the locking, so warn if don't hold the connection_mutex.
*
* RETURNS:
*
* The MST topology state or error pointer.
*/
struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr)
{
struct drm_device *dev = mgr->dev;

WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
return drm_atomic_get_private_obj_state(state, mgr,
&mst_state_funcs);
}
EXPORT_SYMBOL(drm_atomic_get_mst_topology_state);

/**
* drm_dp_mst_topology_mgr_init - initialise a topology manager
* @mgr: manager struct to initialise
Expand Down Expand Up @@ -2980,6 +3043,15 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
if (test_calc_pbn_mode() < 0)
DRM_ERROR("MST PBN self-test failed\n");

mgr->state = kzalloc(sizeof(*mgr->state), GFP_KERNEL);
if (mgr->state == NULL)
return -ENOMEM;
mgr->state->mgr = mgr;

/* max. time slots - one slot for MTP header */
mgr->state->avail_slots = 63;
mgr->funcs = &mst_state_funcs;

return 0;
}
EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init);
Expand All @@ -3000,6 +3072,9 @@ void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr)
mutex_unlock(&mgr->payload_lock);
mgr->dev = NULL;
mgr->aux = NULL;
kfree(mgr->state);
mgr->state = NULL;
mgr->funcs = NULL;
}
EXPORT_SYMBOL(drm_dp_mst_topology_mgr_destroy);

Expand Down
20 changes: 20 additions & 0 deletions include/drm/drm_dp_mst_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include <linux/types.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_atomic.h>

struct drm_dp_mst_branch;

Expand Down Expand Up @@ -403,6 +404,12 @@ struct drm_dp_payload {
int vcpi;
};

struct drm_dp_mst_topology_state {
int avail_slots;
struct drm_atomic_state *state;
struct drm_dp_mst_topology_mgr *mgr;
};

/**
* struct drm_dp_mst_topology_mgr - DisplayPort MST manager
*
Expand Down Expand Up @@ -480,6 +487,16 @@ struct drm_dp_mst_topology_mgr {
*/
int pbn_div;

/**
* @state: State information for topology manager
*/
struct drm_dp_mst_topology_state *state;

/**
* @funcs: Atomic helper callbacks
*/
const struct drm_private_state_funcs *funcs;

/**
* @qlock: protects @tx_msg_downq, the &drm_dp_mst_branch.txslost and
* &drm_dp_sideband_msg_tx.state once they are queued
Expand Down Expand Up @@ -596,4 +613,7 @@ 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 drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr);
struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr);

#endif

0 comments on commit 3f3353b

Please sign in to comment.