Skip to content

Commit 5aa1dfc

Browse files
Wayne LinLyude
Wayne Lin
authored andcommitted
drm/mst: Refactor the flow for payload allocation/removement
[Why] Today, the allocation/deallocation steps and status is a bit unclear. For instance, payload->vc_start_slot = -1 stands for "the failure of updating DPCD payload ID table" and can also represent as "payload is not allocated yet". These two cases should be handled differently and hence better to distinguish them for better understanding. [How] Define enumeration - ALLOCATION_LOCAL, ALLOCATION_DFP and ALLOCATION_REMOTE to distinguish different allocation status. Adjust the code to handle different status accordingly for better understanding the sequence of payload allocation and payload removement. For payload creation, the procedure should look like this: DRM part 1: * step 1 - update sw mst mgr variables to add a new payload * step 2 - add payload at immediate DFP DPCD payload table Driver: * Add new payload in HW and sync up with DFP by sending ACT DRM Part 2: * Send ALLOCATE_PAYLOAD sideband message to allocate bandwidth along the virtual channel. And as for payload removement, the procedure should look like this: DRM part 1: * step 1 - Send ALLOCATE_PAYLOAD sideband message to release bandwidth along the virtual channel * step 2 - Clear payload allocation at immediate DFP DPCD payload table Driver: * Remove the payload in HW and sync up with DFP by sending ACT DRM part 2: * update sw mst mgr variables to remove the payload Note that it's fine to fail when communicate with the branch device connected at immediate downstrean-facing port, but updating variables of SW mst mgr and HW configuration should be conducted anyway. That's because it's under commit_tail and we need to complete the HW programming. Changes since v1: * Remove the set but not use variable 'old_payload' in function 'nv50_msto_prepare'. Catched by kernel test robot <[email protected]> Signed-off-by: Wayne Lin <[email protected]> Signed-off-by: Lyude Paul <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent ae4d231 commit 5aa1dfc

File tree

5 files changed

+153
-88
lines changed

5 files changed

+153
-88
lines changed

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ static void dm_helpers_construct_old_payload(
219219
/* Set correct time_slots/PBN of old payload.
220220
* other fields (delete & dsc_enabled) in
221221
* struct drm_dp_mst_atomic_payload are don't care fields
222-
* while calling drm_dp_remove_payload()
222+
* while calling drm_dp_remove_payload_part2()
223223
*/
224224
for (i = 0; i < current_link_table.stream_count; i++) {
225225
dc_alloc =
@@ -262,21 +262,20 @@ bool dm_helpers_dp_mst_write_payload_allocation_table(
262262

263263
mst_mgr = &aconnector->mst_root->mst_mgr;
264264
mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state);
265-
266-
/* It's OK for this to fail */
267265
new_payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port);
268266

269267
if (enable) {
270268
target_payload = new_payload;
271269

270+
/* It's OK for this to fail */
272271
drm_dp_add_payload_part1(mst_mgr, mst_state, new_payload);
273272
} else {
274273
/* construct old payload by VCPI*/
275274
dm_helpers_construct_old_payload(stream->link, mst_state->pbn_div,
276275
new_payload, &old_payload);
277276
target_payload = &old_payload;
278277

279-
drm_dp_remove_payload(mst_mgr, mst_state, &old_payload, new_payload);
278+
drm_dp_remove_payload_part1(mst_mgr, mst_state, new_payload);
280279
}
281280

282281
/* mst_mgr->->payloads are VC payload notify MST branch using DPCD or
@@ -342,7 +341,7 @@ bool dm_helpers_dp_mst_send_payload_allocation(
342341
struct amdgpu_dm_connector *aconnector;
343342
struct drm_dp_mst_topology_state *mst_state;
344343
struct drm_dp_mst_topology_mgr *mst_mgr;
345-
struct drm_dp_mst_atomic_payload *payload;
344+
struct drm_dp_mst_atomic_payload *new_payload, *old_payload;
346345
enum mst_progress_status set_flag = MST_ALLOCATE_NEW_PAYLOAD;
347346
enum mst_progress_status clr_flag = MST_CLEAR_ALLOCATED_PAYLOAD;
348347
int ret = 0;
@@ -355,15 +354,20 @@ bool dm_helpers_dp_mst_send_payload_allocation(
355354
mst_mgr = &aconnector->mst_root->mst_mgr;
356355
mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state);
357356

358-
payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port);
357+
new_payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port);
359358

360359
if (!enable) {
361360
set_flag = MST_CLEAR_ALLOCATED_PAYLOAD;
362361
clr_flag = MST_ALLOCATE_NEW_PAYLOAD;
363362
}
364363

365-
if (enable)
366-
ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, payload);
364+
if (enable) {
365+
ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, new_payload);
366+
} else {
367+
dm_helpers_construct_old_payload(stream->link, mst_state->pbn_div,
368+
new_payload, old_payload);
369+
drm_dp_remove_payload_part2(mst_mgr, mst_state, old_payload, new_payload);
370+
}
367371

368372
if (ret) {
369373
amdgpu_dm_set_mst_status(&aconnector->mst_status,

drivers/gpu/drm/display/drm_dp_mst_topology.c

Lines changed: 100 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3255,15 +3255,15 @@ int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr,
32553255
}
32563256
EXPORT_SYMBOL(drm_dp_send_query_stream_enc_status);
32573257

3258-
static int drm_dp_create_payload_step1(struct drm_dp_mst_topology_mgr *mgr,
3259-
struct drm_dp_mst_atomic_payload *payload)
3258+
static int drm_dp_create_payload_at_dfp(struct drm_dp_mst_topology_mgr *mgr,
3259+
struct drm_dp_mst_atomic_payload *payload)
32603260
{
32613261
return drm_dp_dpcd_write_payload(mgr, payload->vcpi, payload->vc_start_slot,
32623262
payload->time_slots);
32633263
}
32643264

3265-
static int drm_dp_create_payload_step2(struct drm_dp_mst_topology_mgr *mgr,
3266-
struct drm_dp_mst_atomic_payload *payload)
3265+
static int drm_dp_create_payload_to_remote(struct drm_dp_mst_topology_mgr *mgr,
3266+
struct drm_dp_mst_atomic_payload *payload)
32673267
{
32683268
int ret;
32693269
struct drm_dp_mst_port *port = drm_dp_mst_topology_get_port_validated(mgr, payload->port);
@@ -3276,17 +3276,20 @@ static int drm_dp_create_payload_step2(struct drm_dp_mst_topology_mgr *mgr,
32763276
return ret;
32773277
}
32783278

3279-
static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr,
3280-
struct drm_dp_mst_topology_state *mst_state,
3281-
struct drm_dp_mst_atomic_payload *payload)
3279+
static void drm_dp_destroy_payload_at_remote_and_dfp(struct drm_dp_mst_topology_mgr *mgr,
3280+
struct drm_dp_mst_topology_state *mst_state,
3281+
struct drm_dp_mst_atomic_payload *payload)
32823282
{
32833283
drm_dbg_kms(mgr->dev, "\n");
32843284

32853285
/* it's okay for these to fail */
3286-
drm_dp_payload_send_msg(mgr, payload->port, payload->vcpi, 0);
3287-
drm_dp_dpcd_write_payload(mgr, payload->vcpi, payload->vc_start_slot, 0);
3286+
if (payload->payload_allocation_status == DRM_DP_MST_PAYLOAD_ALLOCATION_REMOTE) {
3287+
drm_dp_payload_send_msg(mgr, payload->port, payload->vcpi, 0);
3288+
payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_DFP;
3289+
}
32883290

3289-
return 0;
3291+
if (payload->payload_allocation_status == DRM_DP_MST_PAYLOAD_ALLOCATION_DFP)
3292+
drm_dp_dpcd_write_payload(mgr, payload->vcpi, payload->vc_start_slot, 0);
32903293
}
32913294

32923295
/**
@@ -3296,81 +3299,105 @@ static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr,
32963299
* @payload: The payload to write
32973300
*
32983301
* Determines the starting time slot for the given payload, and programs the VCPI for this payload
3299-
* into hardware. After calling this, the driver should generate ACT and payload packets.
3302+
* into the DPCD of DPRX. After calling this, the driver should generate ACT and payload packets.
33003303
*
3301-
* Returns: 0 on success, error code on failure. In the event that this fails,
3302-
* @payload.vc_start_slot will also be set to -1.
3304+
* Returns: 0 on success, error code on failure.
33033305
*/
33043306
int drm_dp_add_payload_part1(struct drm_dp_mst_topology_mgr *mgr,
33053307
struct drm_dp_mst_topology_state *mst_state,
33063308
struct drm_dp_mst_atomic_payload *payload)
33073309
{
33083310
struct drm_dp_mst_port *port;
3309-
int ret;
3311+
int ret = 0;
3312+
bool allocate = true;
3313+
3314+
/* Update mst mgr info */
3315+
if (mgr->payload_count == 0)
3316+
mgr->next_start_slot = mst_state->start_slot;
3317+
3318+
payload->vc_start_slot = mgr->next_start_slot;
3319+
3320+
mgr->payload_count++;
3321+
mgr->next_start_slot += payload->time_slots;
33103322

3323+
/* Allocate payload to immediate downstream facing port */
33113324
port = drm_dp_mst_topology_get_port_validated(mgr, payload->port);
33123325
if (!port) {
33133326
drm_dbg_kms(mgr->dev,
3314-
"VCPI %d for port %p not in topology, not creating a payload\n",
3327+
"VCPI %d for port %p not in topology, not creating a payload to remote\n",
33153328
payload->vcpi, payload->port);
3316-
payload->vc_start_slot = -1;
3317-
return 0;
3329+
allocate = false;
33183330
}
33193331

3320-
if (mgr->payload_count == 0)
3321-
mgr->next_start_slot = mst_state->start_slot;
3322-
3323-
payload->vc_start_slot = mgr->next_start_slot;
3332+
if (allocate) {
3333+
ret = drm_dp_create_payload_at_dfp(mgr, payload);
3334+
if (ret < 0)
3335+
drm_warn(mgr->dev, "Failed to create MST payload for port %p: %d\n",
3336+
payload->port, ret);
33243337

3325-
ret = drm_dp_create_payload_step1(mgr, payload);
3326-
drm_dp_mst_topology_put_port(port);
3327-
if (ret < 0) {
3328-
drm_warn(mgr->dev, "Failed to create MST payload for port %p: %d\n",
3329-
payload->port, ret);
3330-
payload->vc_start_slot = -1;
3331-
return ret;
33323338
}
33333339

3334-
mgr->payload_count++;
3335-
mgr->next_start_slot += payload->time_slots;
3340+
payload->payload_allocation_status =
3341+
(!allocate || ret < 0) ? DRM_DP_MST_PAYLOAD_ALLOCATION_LOCAL :
3342+
DRM_DP_MST_PAYLOAD_ALLOCATION_DFP;
33363343

3337-
return 0;
3344+
drm_dp_mst_topology_put_port(port);
3345+
3346+
return ret;
33383347
}
33393348
EXPORT_SYMBOL(drm_dp_add_payload_part1);
33403349

33413350
/**
3342-
* drm_dp_remove_payload() - Remove an MST payload
3351+
* drm_dp_remove_payload_part1() - Remove an MST payload along the virtual channel
33433352
* @mgr: Manager to use.
33443353
* @mst_state: The MST atomic state
3345-
* @old_payload: The payload with its old state
3346-
* @new_payload: The payload to write
3354+
* @payload: The payload to remove
33473355
*
3348-
* Removes a payload from an MST topology if it was successfully assigned a start slot. Also updates
3349-
* the starting time slots of all other payloads which would have been shifted towards the start of
3350-
* the VC table as a result. After calling this, the driver should generate ACT and payload packets.
3356+
* Removes a payload along the virtual channel if it was successfully allocated.
3357+
* After calling this, the driver should set HW to generate ACT and then switch to new
3358+
* payload allocation state.
33513359
*/
3352-
void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr,
3353-
struct drm_dp_mst_topology_state *mst_state,
3354-
const struct drm_dp_mst_atomic_payload *old_payload,
3355-
struct drm_dp_mst_atomic_payload *new_payload)
3360+
void drm_dp_remove_payload_part1(struct drm_dp_mst_topology_mgr *mgr,
3361+
struct drm_dp_mst_topology_state *mst_state,
3362+
struct drm_dp_mst_atomic_payload *payload)
33563363
{
3357-
struct drm_dp_mst_atomic_payload *pos;
3364+
/* Remove remote payload allocation */
33583365
bool send_remove = false;
33593366

3360-
/* We failed to make the payload, so nothing to do */
3361-
if (new_payload->vc_start_slot == -1)
3362-
return;
3363-
33643367
mutex_lock(&mgr->lock);
3365-
send_remove = drm_dp_mst_port_downstream_of_branch(new_payload->port, mgr->mst_primary);
3368+
send_remove = drm_dp_mst_port_downstream_of_branch(payload->port, mgr->mst_primary);
33663369
mutex_unlock(&mgr->lock);
33673370

33683371
if (send_remove)
3369-
drm_dp_destroy_payload_step1(mgr, mst_state, new_payload);
3372+
drm_dp_destroy_payload_at_remote_and_dfp(mgr, mst_state, payload);
33703373
else
33713374
drm_dbg_kms(mgr->dev, "Payload for VCPI %d not in topology, not sending remove\n",
3372-
new_payload->vcpi);
3375+
payload->vcpi);
3376+
3377+
payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_LOCAL;
3378+
}
3379+
EXPORT_SYMBOL(drm_dp_remove_payload_part1);
33733380

3381+
/**
3382+
* drm_dp_remove_payload_part2() - Remove an MST payload locally
3383+
* @mgr: Manager to use.
3384+
* @mst_state: The MST atomic state
3385+
* @old_payload: The payload with its old state
3386+
* @new_payload: The payload with its latest state
3387+
*
3388+
* Updates the starting time slots of all other payloads which would have been shifted towards
3389+
* the start of the payload ID table as a result of removing a payload. Driver should call this
3390+
* function whenever it removes a payload in its HW. It's independent to the result of payload
3391+
* allocation/deallocation at branch devices along the virtual channel.
3392+
*/
3393+
void drm_dp_remove_payload_part2(struct drm_dp_mst_topology_mgr *mgr,
3394+
struct drm_dp_mst_topology_state *mst_state,
3395+
const struct drm_dp_mst_atomic_payload *old_payload,
3396+
struct drm_dp_mst_atomic_payload *new_payload)
3397+
{
3398+
struct drm_dp_mst_atomic_payload *pos;
3399+
3400+
/* Remove local payload allocation */
33743401
list_for_each_entry(pos, &mst_state->payloads, next) {
33753402
if (pos != new_payload && pos->vc_start_slot > new_payload->vc_start_slot)
33763403
pos->vc_start_slot -= old_payload->time_slots;
@@ -3382,9 +3409,10 @@ void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr,
33823409

33833410
if (new_payload->delete)
33843411
drm_dp_mst_put_port_malloc(new_payload->port);
3385-
}
3386-
EXPORT_SYMBOL(drm_dp_remove_payload);
33873412

3413+
new_payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_NONE;
3414+
}
3415+
EXPORT_SYMBOL(drm_dp_remove_payload_part2);
33883416
/**
33893417
* drm_dp_add_payload_part2() - Execute payload update part 2
33903418
* @mgr: Manager to use.
@@ -3403,17 +3431,19 @@ int drm_dp_add_payload_part2(struct drm_dp_mst_topology_mgr *mgr,
34033431
int ret = 0;
34043432

34053433
/* Skip failed payloads */
3406-
if (payload->vc_start_slot == -1) {
3407-
drm_dbg_kms(mgr->dev, "Part 1 of payload creation for %s failed, skipping part 2\n",
3434+
if (payload->payload_allocation_status != DRM_DP_MST_PAYLOAD_ALLOCATION_DFP) {
3435+
drm_dbg_kms(state->dev, "Part 1 of payload creation for %s failed, skipping part 2\n",
34083436
payload->port->connector->name);
34093437
return -EIO;
34103438
}
34113439

3412-
ret = drm_dp_create_payload_step2(mgr, payload);
3413-
if (ret < 0) {
3440+
/* Allocate payload to remote end */
3441+
ret = drm_dp_create_payload_to_remote(mgr, payload);
3442+
if (ret < 0)
34143443
drm_err(mgr->dev, "Step 2 of creating MST payload for %p failed: %d\n",
34153444
payload->port, ret);
3416-
}
3445+
else
3446+
payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_REMOTE;
34173447

34183448
return ret;
34193449
}
@@ -4324,6 +4354,7 @@ int drm_dp_atomic_find_time_slots(struct drm_atomic_state *state,
43244354
drm_dp_mst_get_port_malloc(port);
43254355
payload->port = port;
43264356
payload->vc_start_slot = -1;
4357+
payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_NONE;
43274358
list_add(&payload->next, &topology_state->payloads);
43284359
}
43294360
payload->time_slots = req_slots;
@@ -4493,7 +4524,7 @@ void drm_dp_mst_atomic_wait_for_dependencies(struct drm_atomic_state *state)
44934524
}
44944525

44954526
/* Now that previous state is committed, it's safe to copy over the start slot
4496-
* assignments
4527+
* and allocation status assignments
44974528
*/
44984529
list_for_each_entry(old_payload, &old_mst_state->payloads, next) {
44994530
if (old_payload->delete)
@@ -4502,6 +4533,8 @@ void drm_dp_mst_atomic_wait_for_dependencies(struct drm_atomic_state *state)
45024533
new_payload = drm_atomic_get_mst_payload_state(new_mst_state,
45034534
old_payload->port);
45044535
new_payload->vc_start_slot = old_payload->vc_start_slot;
4536+
new_payload->payload_allocation_status =
4537+
old_payload->payload_allocation_status;
45054538
}
45064539
}
45074540
}
@@ -4818,6 +4851,13 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
48184851
struct drm_dp_mst_atomic_payload *payload;
48194852
int i, ret;
48204853

4854+
static const char *const status[] = {
4855+
"None",
4856+
"Local",
4857+
"DFP",
4858+
"Remote",
4859+
};
4860+
48214861
mutex_lock(&mgr->lock);
48224862
if (mgr->mst_primary)
48234863
drm_dp_mst_dump_mstb(m, mgr->mst_primary);
@@ -4834,7 +4874,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
48344874
seq_printf(m, "payload_mask: %x, max_payloads: %d, start_slot: %u, pbn_div: %d\n",
48354875
state->payload_mask, mgr->max_payloads, state->start_slot, state->pbn_div);
48364876

4837-
seq_printf(m, "\n| idx | port | vcpi | slots | pbn | dsc | sink name |\n");
4877+
seq_printf(m, "\n| idx | port | vcpi | slots | pbn | dsc | status | sink name |\n");
48384878
for (i = 0; i < mgr->max_payloads; i++) {
48394879
list_for_each_entry(payload, &state->payloads, next) {
48404880
char name[14];
@@ -4843,14 +4883,15 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
48434883
continue;
48444884

48454885
fetch_monitor_name(mgr, payload->port, name, sizeof(name));
4846-
seq_printf(m, " %5d %6d %6d %02d - %02d %5d %5s %19s\n",
4886+
seq_printf(m, " %5d %6d %6d %02d - %02d %5d %5s %8s %19s\n",
48474887
i,
48484888
payload->port->port_num,
48494889
payload->vcpi,
48504890
payload->vc_start_slot,
48514891
payload->vc_start_slot + payload->time_slots - 1,
48524892
payload->pbn,
48534893
payload->dsc_enabled ? "Y" : "N",
4894+
status[payload->payload_allocation_status],
48544895
(*name != 0) ? name : "Unknown");
48554896
}
48564897
}

0 commit comments

Comments
 (0)