Skip to content

Commit dfda0df

Browse files
committed
drm/mst: rework payload table allocation to conform better.
The old code has problems with the Dell MST monitors due to some assumptions I made that weren't true. I initially thought the Virtual Channel Payload IDs had to be in the DPCD table in ascending order, however it appears that assumption is bogus. The old code also assumed it was possible to insert a member into the table and it would move other members up, like it does when you remove table entries, however reality has shown this isn't true. So the new code allocates VCPIs separate from entries in the payload tracking table, and when we remove an entry from the DPCD table, I shuffle the tracking payload entries around in the struct. This appears to make VT switch more robust (still not perfect) with an MST enabled Dell monitor. Signed-off-by: Dave Airlie <[email protected]>
1 parent 1e99cfa commit dfda0df

File tree

2 files changed

+59
-20
lines changed

2 files changed

+59
-20
lines changed

drivers/gpu/drm/drm_dp_mst_topology.c

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_n
682682
static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr,
683683
struct drm_dp_vcpi *vcpi)
684684
{
685-
int ret;
685+
int ret, vcpi_ret;
686686

687687
mutex_lock(&mgr->payload_lock);
688688
ret = find_first_zero_bit(&mgr->payload_mask, mgr->max_payloads + 1);
@@ -692,24 +692,40 @@ static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr,
692692
goto out_unlock;
693693
}
694694

695+
vcpi_ret = find_first_zero_bit(&mgr->vcpi_mask, mgr->max_payloads + 1);
696+
if (vcpi_ret > mgr->max_payloads) {
697+
ret = -EINVAL;
698+
DRM_DEBUG_KMS("out of vcpi ids %d\n", ret);
699+
goto out_unlock;
700+
}
701+
695702
set_bit(ret, &mgr->payload_mask);
696-
vcpi->vcpi = ret;
703+
set_bit(vcpi_ret, &mgr->vcpi_mask);
704+
vcpi->vcpi = vcpi_ret + 1;
697705
mgr->proposed_vcpis[ret - 1] = vcpi;
698706
out_unlock:
699707
mutex_unlock(&mgr->payload_lock);
700708
return ret;
701709
}
702710

703711
static void drm_dp_mst_put_payload_id(struct drm_dp_mst_topology_mgr *mgr,
704-
int id)
712+
int vcpi)
705713
{
706-
if (id == 0)
714+
int i;
715+
if (vcpi == 0)
707716
return;
708717

709718
mutex_lock(&mgr->payload_lock);
710-
DRM_DEBUG_KMS("putting payload %d\n", id);
711-
clear_bit(id, &mgr->payload_mask);
712-
mgr->proposed_vcpis[id - 1] = NULL;
719+
DRM_DEBUG_KMS("putting payload %d\n", vcpi);
720+
clear_bit(vcpi - 1, &mgr->vcpi_mask);
721+
722+
for (i = 0; i < mgr->max_payloads; i++) {
723+
if (mgr->proposed_vcpis[i])
724+
if (mgr->proposed_vcpis[i]->vcpi == vcpi) {
725+
mgr->proposed_vcpis[i] = NULL;
726+
clear_bit(i + 1, &mgr->payload_mask);
727+
}
728+
}
713729
mutex_unlock(&mgr->payload_lock);
714730
}
715731

@@ -1563,7 +1579,7 @@ static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr,
15631579
}
15641580

15651581
drm_dp_dpcd_write_payload(mgr, id, payload);
1566-
payload->payload_state = 0;
1582+
payload->payload_state = DP_PAYLOAD_DELETE_LOCAL;
15671583
return 0;
15681584
}
15691585

@@ -1590,7 +1606,7 @@ static int drm_dp_destroy_payload_step2(struct drm_dp_mst_topology_mgr *mgr,
15901606
*/
15911607
int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
15921608
{
1593-
int i;
1609+
int i, j;
15941610
int cur_slots = 1;
15951611
struct drm_dp_payload req_payload;
15961612
struct drm_dp_mst_port *port;
@@ -1607,26 +1623,46 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
16071623
port = NULL;
16081624
req_payload.num_slots = 0;
16091625
}
1626+
1627+
if (mgr->payloads[i].start_slot != req_payload.start_slot) {
1628+
mgr->payloads[i].start_slot = req_payload.start_slot;
1629+
}
16101630
/* work out what is required to happen with this payload */
1611-
if (mgr->payloads[i].start_slot != req_payload.start_slot ||
1612-
mgr->payloads[i].num_slots != req_payload.num_slots) {
1631+
if (mgr->payloads[i].num_slots != req_payload.num_slots) {
16131632

16141633
/* need to push an update for this payload */
16151634
if (req_payload.num_slots) {
1616-
drm_dp_create_payload_step1(mgr, i + 1, &req_payload);
1635+
drm_dp_create_payload_step1(mgr, mgr->proposed_vcpis[i]->vcpi, &req_payload);
16171636
mgr->payloads[i].num_slots = req_payload.num_slots;
16181637
} else if (mgr->payloads[i].num_slots) {
16191638
mgr->payloads[i].num_slots = 0;
1620-
drm_dp_destroy_payload_step1(mgr, port, i + 1, &mgr->payloads[i]);
1639+
drm_dp_destroy_payload_step1(mgr, port, port->vcpi.vcpi, &mgr->payloads[i]);
16211640
req_payload.payload_state = mgr->payloads[i].payload_state;
1622-
} else
1623-
req_payload.payload_state = 0;
1624-
1625-
mgr->payloads[i].start_slot = req_payload.start_slot;
1641+
mgr->payloads[i].start_slot = 0;
1642+
}
16261643
mgr->payloads[i].payload_state = req_payload.payload_state;
16271644
}
16281645
cur_slots += req_payload.num_slots;
16291646
}
1647+
1648+
for (i = 0; i < mgr->max_payloads; i++) {
1649+
if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) {
1650+
DRM_DEBUG_KMS("removing payload %d\n", i);
1651+
for (j = i; j < mgr->max_payloads - 1; j++) {
1652+
memcpy(&mgr->payloads[j], &mgr->payloads[j + 1], sizeof(struct drm_dp_payload));
1653+
mgr->proposed_vcpis[j] = mgr->proposed_vcpis[j + 1];
1654+
if (mgr->proposed_vcpis[j] && mgr->proposed_vcpis[j]->num_slots) {
1655+
set_bit(j + 1, &mgr->payload_mask);
1656+
} else {
1657+
clear_bit(j + 1, &mgr->payload_mask);
1658+
}
1659+
}
1660+
memset(&mgr->payloads[mgr->max_payloads - 1], 0, sizeof(struct drm_dp_payload));
1661+
mgr->proposed_vcpis[mgr->max_payloads - 1] = NULL;
1662+
clear_bit(mgr->max_payloads, &mgr->payload_mask);
1663+
1664+
}
1665+
}
16301666
mutex_unlock(&mgr->payload_lock);
16311667

16321668
return 0;
@@ -1657,9 +1693,9 @@ int drm_dp_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr)
16571693

16581694
DRM_DEBUG_KMS("payload %d %d\n", i, mgr->payloads[i].payload_state);
16591695
if (mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL) {
1660-
ret = drm_dp_create_payload_step2(mgr, port, i + 1, &mgr->payloads[i]);
1696+
ret = drm_dp_create_payload_step2(mgr, port, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]);
16611697
} else if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) {
1662-
ret = drm_dp_destroy_payload_step2(mgr, i + 1, &mgr->payloads[i]);
1698+
ret = drm_dp_destroy_payload_step2(mgr, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]);
16631699
}
16641700
if (ret) {
16651701
mutex_unlock(&mgr->payload_lock);
@@ -1861,6 +1897,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
18611897
memset(mgr->payloads, 0, mgr->max_payloads * sizeof(struct drm_dp_payload));
18621898
mgr->payload_mask = 0;
18631899
set_bit(0, &mgr->payload_mask);
1900+
mgr->vcpi_mask = 0;
18641901
}
18651902

18661903
out_unlock:
@@ -2475,7 +2512,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
24752512
mutex_unlock(&mgr->lock);
24762513

24772514
mutex_lock(&mgr->payload_lock);
2478-
seq_printf(m, "vcpi: %lx\n", mgr->payload_mask);
2515+
seq_printf(m, "vcpi: %lx %lx\n", mgr->payload_mask, mgr->vcpi_mask);
24792516

24802517
for (i = 0; i < mgr->max_payloads; i++) {
24812518
if (mgr->proposed_vcpis[i]) {

include/drm/drm_dp_mst_helper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ struct drm_dp_payload {
388388
int payload_state;
389389
int start_slot;
390390
int num_slots;
391+
int vcpi;
391392
};
392393

393394
/**
@@ -454,6 +455,7 @@ struct drm_dp_mst_topology_mgr {
454455
struct drm_dp_vcpi **proposed_vcpis;
455456
struct drm_dp_payload *payloads;
456457
unsigned long payload_mask;
458+
unsigned long vcpi_mask;
457459

458460
wait_queue_head_t tx_waitq;
459461
struct work_struct work;

0 commit comments

Comments
 (0)