Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <airlied@redhat.com>

+59 -20
+57 -20
drivers/gpu/drm/drm_dp_mst_topology.c
··· 682 682 static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr, 683 683 struct drm_dp_vcpi *vcpi) 684 684 { 685 - int ret; 685 + int ret, vcpi_ret; 686 686 687 687 mutex_lock(&mgr->payload_lock); 688 688 ret = find_first_zero_bit(&mgr->payload_mask, mgr->max_payloads + 1); ··· 692 692 goto out_unlock; 693 693 } 694 694 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 + 695 702 set_bit(ret, &mgr->payload_mask); 696 - vcpi->vcpi = ret; 703 + set_bit(vcpi_ret, &mgr->vcpi_mask); 704 + vcpi->vcpi = vcpi_ret + 1; 697 705 mgr->proposed_vcpis[ret - 1] = vcpi; 698 706 out_unlock: 699 707 mutex_unlock(&mgr->payload_lock); ··· 709 701 } 710 702 711 703 static void drm_dp_mst_put_payload_id(struct drm_dp_mst_topology_mgr *mgr, 712 - int id) 704 + int vcpi) 713 705 { 714 - if (id == 0) 706 + int i; 707 + if (vcpi == 0) 715 708 return; 716 709 717 710 mutex_lock(&mgr->payload_lock); 718 - DRM_DEBUG_KMS("putting payload %d\n", id); 719 - clear_bit(id, &mgr->payload_mask); 720 - mgr->proposed_vcpis[id - 1] = NULL; 711 + DRM_DEBUG_KMS("putting payload %d\n", vcpi); 712 + clear_bit(vcpi - 1, &mgr->vcpi_mask); 713 + 714 + for (i = 0; i < mgr->max_payloads; i++) { 715 + if (mgr->proposed_vcpis[i]) 716 + if (mgr->proposed_vcpis[i]->vcpi == vcpi) { 717 + mgr->proposed_vcpis[i] = NULL; 718 + clear_bit(i + 1, &mgr->payload_mask); 719 + } 720 + } 721 721 mutex_unlock(&mgr->payload_lock); 722 722 } 723 723 ··· 1579 1563 } 1580 1564 1581 1565 drm_dp_dpcd_write_payload(mgr, id, payload); 1582 - payload->payload_state = 0; 1566 + payload->payload_state = DP_PAYLOAD_DELETE_LOCAL; 1583 1567 return 0; 1584 1568 } 1585 1569 ··· 1606 1590 */ 1607 1591 int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) 1608 1592 { 1609 - int i; 1593 + int i, j; 1610 1594 int cur_slots = 1; 1611 1595 struct drm_dp_payload req_payload; 1612 1596 struct drm_dp_mst_port *port; ··· 1623 1607 port = NULL; 1624 1608 req_payload.num_slots = 0; 1625 1609 } 1610 + 1611 + if (mgr->payloads[i].start_slot != req_payload.start_slot) { 1612 + mgr->payloads[i].start_slot = req_payload.start_slot; 1613 + } 1626 1614 /* work out what is required to happen with this payload */ 1627 - if (mgr->payloads[i].start_slot != req_payload.start_slot || 1628 - mgr->payloads[i].num_slots != req_payload.num_slots) { 1615 + if (mgr->payloads[i].num_slots != req_payload.num_slots) { 1629 1616 1630 1617 /* need to push an update for this payload */ 1631 1618 if (req_payload.num_slots) { 1632 - drm_dp_create_payload_step1(mgr, i + 1, &req_payload); 1619 + drm_dp_create_payload_step1(mgr, mgr->proposed_vcpis[i]->vcpi, &req_payload); 1633 1620 mgr->payloads[i].num_slots = req_payload.num_slots; 1634 1621 } else if (mgr->payloads[i].num_slots) { 1635 1622 mgr->payloads[i].num_slots = 0; 1636 - drm_dp_destroy_payload_step1(mgr, port, i + 1, &mgr->payloads[i]); 1623 + drm_dp_destroy_payload_step1(mgr, port, port->vcpi.vcpi, &mgr->payloads[i]); 1637 1624 req_payload.payload_state = mgr->payloads[i].payload_state; 1638 - } else 1639 - req_payload.payload_state = 0; 1640 - 1641 - mgr->payloads[i].start_slot = req_payload.start_slot; 1625 + mgr->payloads[i].start_slot = 0; 1626 + } 1642 1627 mgr->payloads[i].payload_state = req_payload.payload_state; 1643 1628 } 1644 1629 cur_slots += req_payload.num_slots; 1630 + } 1631 + 1632 + for (i = 0; i < mgr->max_payloads; i++) { 1633 + if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) { 1634 + DRM_DEBUG_KMS("removing payload %d\n", i); 1635 + for (j = i; j < mgr->max_payloads - 1; j++) { 1636 + memcpy(&mgr->payloads[j], &mgr->payloads[j + 1], sizeof(struct drm_dp_payload)); 1637 + mgr->proposed_vcpis[j] = mgr->proposed_vcpis[j + 1]; 1638 + if (mgr->proposed_vcpis[j] && mgr->proposed_vcpis[j]->num_slots) { 1639 + set_bit(j + 1, &mgr->payload_mask); 1640 + } else { 1641 + clear_bit(j + 1, &mgr->payload_mask); 1642 + } 1643 + } 1644 + memset(&mgr->payloads[mgr->max_payloads - 1], 0, sizeof(struct drm_dp_payload)); 1645 + mgr->proposed_vcpis[mgr->max_payloads - 1] = NULL; 1646 + clear_bit(mgr->max_payloads, &mgr->payload_mask); 1647 + 1648 + } 1645 1649 } 1646 1650 mutex_unlock(&mgr->payload_lock); 1647 1651 ··· 1693 1657 1694 1658 DRM_DEBUG_KMS("payload %d %d\n", i, mgr->payloads[i].payload_state); 1695 1659 if (mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL) { 1696 - ret = drm_dp_create_payload_step2(mgr, port, i + 1, &mgr->payloads[i]); 1660 + ret = drm_dp_create_payload_step2(mgr, port, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]); 1697 1661 } else if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) { 1698 - ret = drm_dp_destroy_payload_step2(mgr, i + 1, &mgr->payloads[i]); 1662 + ret = drm_dp_destroy_payload_step2(mgr, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]); 1699 1663 } 1700 1664 if (ret) { 1701 1665 mutex_unlock(&mgr->payload_lock); ··· 1897 1861 memset(mgr->payloads, 0, mgr->max_payloads * sizeof(struct drm_dp_payload)); 1898 1862 mgr->payload_mask = 0; 1899 1863 set_bit(0, &mgr->payload_mask); 1864 + mgr->vcpi_mask = 0; 1900 1865 } 1901 1866 1902 1867 out_unlock: ··· 2512 2475 mutex_unlock(&mgr->lock); 2513 2476 2514 2477 mutex_lock(&mgr->payload_lock); 2515 - seq_printf(m, "vcpi: %lx\n", mgr->payload_mask); 2478 + seq_printf(m, "vcpi: %lx %lx\n", mgr->payload_mask, mgr->vcpi_mask); 2516 2479 2517 2480 for (i = 0; i < mgr->max_payloads; i++) { 2518 2481 if (mgr->proposed_vcpis[i]) {
+2
include/drm/drm_dp_mst_helper.h
··· 388 388 int payload_state; 389 389 int start_slot; 390 390 int num_slots; 391 + int vcpi; 391 392 }; 392 393 393 394 /** ··· 455 454 struct drm_dp_vcpi **proposed_vcpis; 456 455 struct drm_dp_payload *payloads; 457 456 unsigned long payload_mask; 457 + unsigned long vcpi_mask; 458 458 459 459 wait_queue_head_t tx_waitq; 460 460 struct work_struct work;