aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-02-05 00:24:17 -0500
committerDave Airlie <airlied@redhat.com>2016-02-05 00:24:17 -0500
commit6739b3d7bc18a5373efd863b11831e8f515fffe1 (patch)
treeb08d818569141778000f5e93a47c5ed966751608
parentc745884b30f96348f83ce59caf6798d8085daa77 (diff)
parent91a25e463130c8e19bdb42f2d827836c7937992e (diff)
Merge branch 'drm-fixes-mst' of git://people.freedesktop.org/~airlied/linux into drm-fixes
displayport multistream fixes from AMD. * 'drm-fixes-mst' of git://people.freedesktop.org/~airlied/linux: drm/dp/mst: deallocate payload on port destruction drm/dp/mst: Reverse order of MST enable and clearing VC payload table. drm/dp/mst: move GUID storage from mgr, port to only mst branch drm/dp/mst: change MST detection scheme drm/dp/mst: Calculate MST PBN with 31.32 fixed point drm: Add drm_fixp_from_fraction and drm_fixp2int_ceil drm/mst: Add range check for max_payloads during init drm/mst: Don't ignore the MST PBN self-test result drm: fix missing reference counting decrease
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c279
-rw-r--r--include/drm/drm_dp_mst_helper.h25
-rw-r--r--include/drm/drm_fixed.h53
3 files changed, 243 insertions, 114 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 6ed90a2437e5..8ae13de272c4 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -803,6 +803,18 @@ static struct drm_dp_mst_branch *drm_dp_add_mst_branch_device(u8 lct, u8 *rad)
803 return mstb; 803 return mstb;
804} 804}
805 805
806static void drm_dp_free_mst_port(struct kref *kref);
807
808static void drm_dp_free_mst_branch_device(struct kref *kref)
809{
810 struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref);
811 if (mstb->port_parent) {
812 if (list_empty(&mstb->port_parent->next))
813 kref_put(&mstb->port_parent->kref, drm_dp_free_mst_port);
814 }
815 kfree(mstb);
816}
817
806static void drm_dp_destroy_mst_branch_device(struct kref *kref) 818static void drm_dp_destroy_mst_branch_device(struct kref *kref)
807{ 819{
808 struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); 820 struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref);
@@ -810,6 +822,15 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref)
810 bool wake_tx = false; 822 bool wake_tx = false;
811 823
812 /* 824 /*
825 * init kref again to be used by ports to remove mst branch when it is
826 * not needed anymore
827 */
828 kref_init(kref);
829
830 if (mstb->port_parent && list_empty(&mstb->port_parent->next))
831 kref_get(&mstb->port_parent->kref);
832
833 /*
813 * destroy all ports - don't need lock 834 * destroy all ports - don't need lock
814 * as there are no more references to the mst branch 835 * as there are no more references to the mst branch
815 * device at this point. 836 * device at this point.
@@ -835,7 +856,8 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref)
835 856
836 if (wake_tx) 857 if (wake_tx)
837 wake_up(&mstb->mgr->tx_waitq); 858 wake_up(&mstb->mgr->tx_waitq);
838 kfree(mstb); 859
860 kref_put(kref, drm_dp_free_mst_branch_device);
839} 861}
840 862
841static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb) 863static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb)
@@ -883,6 +905,7 @@ static void drm_dp_destroy_port(struct kref *kref)
883 * from an EDID retrieval */ 905 * from an EDID retrieval */
884 906
885 mutex_lock(&mgr->destroy_connector_lock); 907 mutex_lock(&mgr->destroy_connector_lock);
908 kref_get(&port->parent->kref);
886 list_add(&port->next, &mgr->destroy_connector_list); 909 list_add(&port->next, &mgr->destroy_connector_list);
887 mutex_unlock(&mgr->destroy_connector_lock); 910 mutex_unlock(&mgr->destroy_connector_lock);
888 schedule_work(&mgr->destroy_connector_work); 911 schedule_work(&mgr->destroy_connector_work);
@@ -1018,18 +1041,27 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port)
1018 return send_link; 1041 return send_link;
1019} 1042}
1020 1043
1021static void drm_dp_check_port_guid(struct drm_dp_mst_branch *mstb, 1044static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid)
1022 struct drm_dp_mst_port *port)
1023{ 1045{
1024 int ret; 1046 int ret;
1025 if (port->dpcd_rev >= 0x12) { 1047
1026 port->guid_valid = drm_dp_validate_guid(mstb->mgr, port->guid); 1048 memcpy(mstb->guid, guid, 16);
1027 if (!port->guid_valid) { 1049
1028 ret = drm_dp_send_dpcd_write(mstb->mgr, 1050 if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) {
1029 port, 1051 if (mstb->port_parent) {
1030 DP_GUID, 1052 ret = drm_dp_send_dpcd_write(
1031 16, port->guid); 1053 mstb->mgr,
1032 port->guid_valid = true; 1054 mstb->port_parent,
1055 DP_GUID,
1056 16,
1057 mstb->guid);
1058 } else {
1059
1060 ret = drm_dp_dpcd_write(
1061 mstb->mgr->aux,
1062 DP_GUID,
1063 mstb->guid,
1064 16);
1033 } 1065 }
1034 } 1066 }
1035} 1067}
@@ -1086,7 +1118,6 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
1086 port->dpcd_rev = port_msg->dpcd_revision; 1118 port->dpcd_rev = port_msg->dpcd_revision;
1087 port->num_sdp_streams = port_msg->num_sdp_streams; 1119 port->num_sdp_streams = port_msg->num_sdp_streams;
1088 port->num_sdp_stream_sinks = port_msg->num_sdp_stream_sinks; 1120 port->num_sdp_stream_sinks = port_msg->num_sdp_stream_sinks;
1089 memcpy(port->guid, port_msg->peer_guid, 16);
1090 1121
1091 /* manage mstb port lists with mgr lock - take a reference 1122 /* manage mstb port lists with mgr lock - take a reference
1092 for this list */ 1123 for this list */
@@ -1099,11 +1130,9 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
1099 1130
1100 if (old_ddps != port->ddps) { 1131 if (old_ddps != port->ddps) {
1101 if (port->ddps) { 1132 if (port->ddps) {
1102 drm_dp_check_port_guid(mstb, port);
1103 if (!port->input) 1133 if (!port->input)
1104 drm_dp_send_enum_path_resources(mstb->mgr, mstb, port); 1134 drm_dp_send_enum_path_resources(mstb->mgr, mstb, port);
1105 } else { 1135 } else {
1106 port->guid_valid = false;
1107 port->available_pbn = 0; 1136 port->available_pbn = 0;
1108 } 1137 }
1109 } 1138 }
@@ -1130,13 +1159,11 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
1130 drm_dp_put_port(port); 1159 drm_dp_put_port(port);
1131 goto out; 1160 goto out;
1132 } 1161 }
1133 if (port->port_num >= DP_MST_LOGICAL_PORT_0) { 1162
1134 port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); 1163 drm_mode_connector_set_tile_property(port->connector);
1135 drm_mode_connector_set_tile_property(port->connector); 1164
1136 }
1137 (*mstb->mgr->cbs->register_connector)(port->connector); 1165 (*mstb->mgr->cbs->register_connector)(port->connector);
1138 } 1166 }
1139
1140out: 1167out:
1141 /* put reference to this port */ 1168 /* put reference to this port */
1142 drm_dp_put_port(port); 1169 drm_dp_put_port(port);
@@ -1161,11 +1188,9 @@ static void drm_dp_update_port(struct drm_dp_mst_branch *mstb,
1161 port->ddps = conn_stat->displayport_device_plug_status; 1188 port->ddps = conn_stat->displayport_device_plug_status;
1162 1189
1163 if (old_ddps != port->ddps) { 1190 if (old_ddps != port->ddps) {
1191 dowork = true;
1164 if (port->ddps) { 1192 if (port->ddps) {
1165 drm_dp_check_port_guid(mstb, port);
1166 dowork = true;
1167 } else { 1193 } else {
1168 port->guid_valid = false;
1169 port->available_pbn = 0; 1194 port->available_pbn = 0;
1170 } 1195 }
1171 } 1196 }
@@ -1222,13 +1247,14 @@ static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
1222 struct drm_dp_mst_branch *found_mstb; 1247 struct drm_dp_mst_branch *found_mstb;
1223 struct drm_dp_mst_port *port; 1248 struct drm_dp_mst_port *port;
1224 1249
1250 if (memcmp(mstb->guid, guid, 16) == 0)
1251 return mstb;
1252
1253
1225 list_for_each_entry(port, &mstb->ports, next) { 1254 list_for_each_entry(port, &mstb->ports, next) {
1226 if (!port->mstb) 1255 if (!port->mstb)
1227 continue; 1256 continue;
1228 1257
1229 if (port->guid_valid && memcmp(port->guid, guid, 16) == 0)
1230 return port->mstb;
1231
1232 found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid); 1258 found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid);
1233 1259
1234 if (found_mstb) 1260 if (found_mstb)
@@ -1247,10 +1273,7 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device_by_guid(
1247 /* find the port by iterating down */ 1273 /* find the port by iterating down */
1248 mutex_lock(&mgr->lock); 1274 mutex_lock(&mgr->lock);
1249 1275
1250 if (mgr->guid_valid && memcmp(mgr->guid, guid, 16) == 0) 1276 mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid);
1251 mstb = mgr->mst_primary;
1252 else
1253 mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid);
1254 1277
1255 if (mstb) 1278 if (mstb)
1256 kref_get(&mstb->kref); 1279 kref_get(&mstb->kref);
@@ -1271,8 +1294,13 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m
1271 if (port->input) 1294 if (port->input)
1272 continue; 1295 continue;
1273 1296
1274 if (!port->ddps) 1297 if (!port->ddps) {
1298 if (port->cached_edid) {
1299 kfree(port->cached_edid);
1300 port->cached_edid = NULL;
1301 }
1275 continue; 1302 continue;
1303 }
1276 1304
1277 if (!port->available_pbn) 1305 if (!port->available_pbn)
1278 drm_dp_send_enum_path_resources(mgr, mstb, port); 1306 drm_dp_send_enum_path_resources(mgr, mstb, port);
@@ -1283,6 +1311,12 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m
1283 drm_dp_check_and_send_link_address(mgr, mstb_child); 1311 drm_dp_check_and_send_link_address(mgr, mstb_child);
1284 drm_dp_put_mst_branch_device(mstb_child); 1312 drm_dp_put_mst_branch_device(mstb_child);
1285 } 1313 }
1314 } else if (port->pdt == DP_PEER_DEVICE_SST_SINK ||
1315 port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV) {
1316 if (!port->cached_edid) {
1317 port->cached_edid =
1318 drm_get_edid(port->connector, &port->aux.ddc);
1319 }
1286 } 1320 }
1287 } 1321 }
1288} 1322}
@@ -1302,6 +1336,8 @@ static void drm_dp_mst_link_probe_work(struct work_struct *work)
1302 drm_dp_check_and_send_link_address(mgr, mstb); 1336 drm_dp_check_and_send_link_address(mgr, mstb);
1303 drm_dp_put_mst_branch_device(mstb); 1337 drm_dp_put_mst_branch_device(mstb);
1304 } 1338 }
1339
1340 (*mgr->cbs->hotplug)(mgr);
1305} 1341}
1306 1342
1307static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr, 1343static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
@@ -1555,10 +1591,12 @@ static void drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
1555 txmsg->reply.u.link_addr.ports[i].num_sdp_streams, 1591 txmsg->reply.u.link_addr.ports[i].num_sdp_streams,
1556 txmsg->reply.u.link_addr.ports[i].num_sdp_stream_sinks); 1592 txmsg->reply.u.link_addr.ports[i].num_sdp_stream_sinks);
1557 } 1593 }
1594
1595 drm_dp_check_mstb_guid(mstb, txmsg->reply.u.link_addr.guid);
1596
1558 for (i = 0; i < txmsg->reply.u.link_addr.nports; i++) { 1597 for (i = 0; i < txmsg->reply.u.link_addr.nports; i++) {
1559 drm_dp_add_port(mstb, mgr->dev, &txmsg->reply.u.link_addr.ports[i]); 1598 drm_dp_add_port(mstb, mgr->dev, &txmsg->reply.u.link_addr.ports[i]);
1560 } 1599 }
1561 (*mgr->cbs->hotplug)(mgr);
1562 } 1600 }
1563 } else { 1601 } else {
1564 mstb->link_address_sent = false; 1602 mstb->link_address_sent = false;
@@ -1602,6 +1640,37 @@ static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
1602 return 0; 1640 return 0;
1603} 1641}
1604 1642
1643static struct drm_dp_mst_port *drm_dp_get_last_connected_port_to_mstb(struct drm_dp_mst_branch *mstb)
1644{
1645 if (!mstb->port_parent)
1646 return NULL;
1647
1648 if (mstb->port_parent->mstb != mstb)
1649 return mstb->port_parent;
1650
1651 return drm_dp_get_last_connected_port_to_mstb(mstb->port_parent->parent);
1652}
1653
1654static struct drm_dp_mst_branch *drm_dp_get_last_connected_port_and_mstb(struct drm_dp_mst_topology_mgr *mgr,
1655 struct drm_dp_mst_branch *mstb,
1656 int *port_num)
1657{
1658 struct drm_dp_mst_branch *rmstb = NULL;
1659 struct drm_dp_mst_port *found_port;
1660 mutex_lock(&mgr->lock);
1661 if (mgr->mst_primary) {
1662 found_port = drm_dp_get_last_connected_port_to_mstb(mstb);
1663
1664 if (found_port) {
1665 rmstb = found_port->parent;
1666 kref_get(&rmstb->kref);
1667 *port_num = found_port->port_num;
1668 }
1669 }
1670 mutex_unlock(&mgr->lock);
1671 return rmstb;
1672}
1673
1605static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, 1674static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
1606 struct drm_dp_mst_port *port, 1675 struct drm_dp_mst_port *port,
1607 int id, 1676 int id,
@@ -1609,13 +1678,18 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
1609{ 1678{
1610 struct drm_dp_sideband_msg_tx *txmsg; 1679 struct drm_dp_sideband_msg_tx *txmsg;
1611 struct drm_dp_mst_branch *mstb; 1680 struct drm_dp_mst_branch *mstb;
1612 int len, ret; 1681 int len, ret, port_num;
1613 u8 sinks[DRM_DP_MAX_SDP_STREAMS]; 1682 u8 sinks[DRM_DP_MAX_SDP_STREAMS];
1614 int i; 1683 int i;
1615 1684
1685 port_num = port->port_num;
1616 mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); 1686 mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent);
1617 if (!mstb) 1687 if (!mstb) {
1618 return -EINVAL; 1688 mstb = drm_dp_get_last_connected_port_and_mstb(mgr, port->parent, &port_num);
1689
1690 if (!mstb)
1691 return -EINVAL;
1692 }
1619 1693
1620 txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); 1694 txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
1621 if (!txmsg) { 1695 if (!txmsg) {
@@ -1627,7 +1701,7 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
1627 sinks[i] = i; 1701 sinks[i] = i;
1628 1702
1629 txmsg->dst = mstb; 1703 txmsg->dst = mstb;
1630 len = build_allocate_payload(txmsg, port->port_num, 1704 len = build_allocate_payload(txmsg, port_num,
1631 id, 1705 id,
1632 pbn, port->num_sdp_streams, sinks); 1706 pbn, port->num_sdp_streams, sinks);
1633 1707
@@ -1983,31 +2057,17 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
1983 mgr->mst_primary = mstb; 2057 mgr->mst_primary = mstb;
1984 kref_get(&mgr->mst_primary->kref); 2058 kref_get(&mgr->mst_primary->kref);
1985 2059
1986 {
1987 struct drm_dp_payload reset_pay;
1988 reset_pay.start_slot = 0;
1989 reset_pay.num_slots = 0x3f;
1990 drm_dp_dpcd_write_payload(mgr, 0, &reset_pay);
1991 }
1992
1993 ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 2060 ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
1994 DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); 2061 DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC);
1995 if (ret < 0) { 2062 if (ret < 0) {
1996 goto out_unlock; 2063 goto out_unlock;
1997 } 2064 }
1998 2065
1999 2066 {
2000 /* sort out guid */ 2067 struct drm_dp_payload reset_pay;
2001 ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, mgr->guid, 16); 2068 reset_pay.start_slot = 0;
2002 if (ret != 16) { 2069 reset_pay.num_slots = 0x3f;
2003 DRM_DEBUG_KMS("failed to read DP GUID %d\n", ret); 2070 drm_dp_dpcd_write_payload(mgr, 0, &reset_pay);
2004 goto out_unlock;
2005 }
2006
2007 mgr->guid_valid = drm_dp_validate_guid(mgr, mgr->guid);
2008 if (!mgr->guid_valid) {
2009 ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, mgr->guid, 16);
2010 mgr->guid_valid = true;
2011 } 2071 }
2012 2072
2013 queue_work(system_long_wq, &mgr->work); 2073 queue_work(system_long_wq, &mgr->work);
@@ -2231,9 +2291,8 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
2231 } 2291 }
2232 2292
2233 drm_dp_update_port(mstb, &msg.u.conn_stat); 2293 drm_dp_update_port(mstb, &msg.u.conn_stat);
2234 DRM_DEBUG_KMS("Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", msg.u.conn_stat.port_number, msg.u.conn_stat.legacy_device_plug_status, msg.u.conn_stat.displayport_device_plug_status, msg.u.conn_stat.message_capability_status, msg.u.conn_stat.input_port, msg.u.conn_stat.peer_device_type);
2235 (*mgr->cbs->hotplug)(mgr);
2236 2294
2295 DRM_DEBUG_KMS("Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", msg.u.conn_stat.port_number, msg.u.conn_stat.legacy_device_plug_status, msg.u.conn_stat.displayport_device_plug_status, msg.u.conn_stat.message_capability_status, msg.u.conn_stat.input_port, msg.u.conn_stat.peer_device_type);
2237 } else if (msg.req_type == DP_RESOURCE_STATUS_NOTIFY) { 2296 } else if (msg.req_type == DP_RESOURCE_STATUS_NOTIFY) {
2238 drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false); 2297 drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false);
2239 if (!mstb) 2298 if (!mstb)
@@ -2320,10 +2379,6 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector
2320 2379
2321 case DP_PEER_DEVICE_SST_SINK: 2380 case DP_PEER_DEVICE_SST_SINK:
2322 status = connector_status_connected; 2381 status = connector_status_connected;
2323 /* for logical ports - cache the EDID */
2324 if (port->port_num >= 8 && !port->cached_edid) {
2325 port->cached_edid = drm_get_edid(connector, &port->aux.ddc);
2326 }
2327 break; 2382 break;
2328 case DP_PEER_DEVICE_DP_LEGACY_CONV: 2383 case DP_PEER_DEVICE_DP_LEGACY_CONV:
2329 if (port->ldps) 2384 if (port->ldps)
@@ -2378,10 +2433,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
2378 2433
2379 if (port->cached_edid) 2434 if (port->cached_edid)
2380 edid = drm_edid_duplicate(port->cached_edid); 2435 edid = drm_edid_duplicate(port->cached_edid);
2381 else { 2436
2382 edid = drm_get_edid(connector, &port->aux.ddc);
2383 drm_mode_connector_set_tile_property(connector);
2384 }
2385 port->has_audio = drm_detect_monitor_audio(edid); 2437 port->has_audio = drm_detect_monitor_audio(edid);
2386 drm_dp_put_port(port); 2438 drm_dp_put_port(port);
2387 return edid; 2439 return edid;
@@ -2446,6 +2498,7 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp
2446 DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", port->vcpi.vcpi, port->vcpi.pbn, pbn); 2498 DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", port->vcpi.vcpi, port->vcpi.pbn, pbn);
2447 if (pbn == port->vcpi.pbn) { 2499 if (pbn == port->vcpi.pbn) {
2448 *slots = port->vcpi.num_slots; 2500 *slots = port->vcpi.num_slots;
2501 drm_dp_put_port(port);
2449 return true; 2502 return true;
2450 } 2503 }
2451 } 2504 }
@@ -2605,32 +2658,31 @@ EXPORT_SYMBOL(drm_dp_check_act_status);
2605 */ 2658 */
2606int drm_dp_calc_pbn_mode(int clock, int bpp) 2659int drm_dp_calc_pbn_mode(int clock, int bpp)
2607{ 2660{
2608 fixed20_12 pix_bw; 2661 u64 kbps;
2609 fixed20_12 fbpp; 2662 s64 peak_kbps;
2610 fixed20_12 result; 2663 u32 numerator;
2611 fixed20_12 margin, tmp; 2664 u32 denominator;
2612 u32 res; 2665
2613 2666 kbps = clock * bpp;
2614 pix_bw.full = dfixed_const(clock); 2667
2615 fbpp.full = dfixed_const(bpp); 2668 /*
2616 tmp.full = dfixed_const(8); 2669 * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006
2617 fbpp.full = dfixed_div(fbpp, tmp); 2670 * The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on
2618 2671 * common multiplier to render an integer PBN for all link rate/lane
2619 result.full = dfixed_mul(pix_bw, fbpp); 2672 * counts combinations
2620 margin.full = dfixed_const(54); 2673 * calculate
2621 tmp.full = dfixed_const(64); 2674 * peak_kbps *= (1006/1000)
2622 margin.full = dfixed_div(margin, tmp); 2675 * peak_kbps *= (64/54)
2623 result.full = dfixed_div(result, margin); 2676 * peak_kbps *= 8 convert to bytes
2624 2677 */
2625 margin.full = dfixed_const(1006); 2678
2626 tmp.full = dfixed_const(1000); 2679 numerator = 64 * 1006;
2627 margin.full = dfixed_div(margin, tmp); 2680 denominator = 54 * 8 * 1000 * 1000;
2628 result.full = dfixed_mul(result, margin); 2681
2629 2682 kbps *= numerator;
2630 result.full = dfixed_div(result, tmp); 2683 peak_kbps = drm_fixp_from_fraction(kbps, denominator);
2631 result.full = dfixed_ceil(result); 2684
2632 res = dfixed_trunc(result); 2685 return drm_fixp2int_ceil(peak_kbps);
2633 return res;
2634} 2686}
2635EXPORT_SYMBOL(drm_dp_calc_pbn_mode); 2687EXPORT_SYMBOL(drm_dp_calc_pbn_mode);
2636 2688
@@ -2638,11 +2690,23 @@ static int test_calc_pbn_mode(void)
2638{ 2690{
2639 int ret; 2691 int ret;
2640 ret = drm_dp_calc_pbn_mode(154000, 30); 2692 ret = drm_dp_calc_pbn_mode(154000, 30);
2641 if (ret != 689) 2693 if (ret != 689) {
2694 DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n",
2695 154000, 30, 689, ret);
2642 return -EINVAL; 2696 return -EINVAL;
2697 }
2643 ret = drm_dp_calc_pbn_mode(234000, 30); 2698 ret = drm_dp_calc_pbn_mode(234000, 30);
2644 if (ret != 1047) 2699 if (ret != 1047) {
2700 DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n",
2701 234000, 30, 1047, ret);
2645 return -EINVAL; 2702 return -EINVAL;
2703 }
2704 ret = drm_dp_calc_pbn_mode(297000, 24);
2705 if (ret != 1063) {
2706 DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n",
2707 297000, 24, 1063, ret);
2708 return -EINVAL;
2709 }
2646 return 0; 2710 return 0;
2647} 2711}
2648 2712
@@ -2783,6 +2847,13 @@ static void drm_dp_tx_work(struct work_struct *work)
2783 mutex_unlock(&mgr->qlock); 2847 mutex_unlock(&mgr->qlock);
2784} 2848}
2785 2849
2850static void drm_dp_free_mst_port(struct kref *kref)
2851{
2852 struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref);
2853 kref_put(&port->parent->kref, drm_dp_free_mst_branch_device);
2854 kfree(port);
2855}
2856
2786static void drm_dp_destroy_connector_work(struct work_struct *work) 2857static void drm_dp_destroy_connector_work(struct work_struct *work)
2787{ 2858{
2788 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); 2859 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
@@ -2803,13 +2874,22 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
2803 list_del(&port->next); 2874 list_del(&port->next);
2804 mutex_unlock(&mgr->destroy_connector_lock); 2875 mutex_unlock(&mgr->destroy_connector_lock);
2805 2876
2877 kref_init(&port->kref);
2878 INIT_LIST_HEAD(&port->next);
2879
2806 mgr->cbs->destroy_connector(mgr, port->connector); 2880 mgr->cbs->destroy_connector(mgr, port->connector);
2807 2881
2808 drm_dp_port_teardown_pdt(port, port->pdt); 2882 drm_dp_port_teardown_pdt(port, port->pdt);
2809 2883
2810 if (!port->input && port->vcpi.vcpi > 0) 2884 if (!port->input && port->vcpi.vcpi > 0) {
2811 drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); 2885 if (mgr->mst_state) {
2812 kfree(port); 2886 drm_dp_mst_reset_vcpi_slots(mgr, port);
2887 drm_dp_update_payload_part1(mgr);
2888 drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
2889 }
2890 }
2891
2892 kref_put(&port->kref, drm_dp_free_mst_port);
2813 send_hotplug = true; 2893 send_hotplug = true;
2814 } 2894 }
2815 if (send_hotplug) 2895 if (send_hotplug)
@@ -2847,6 +2927,9 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
2847 mgr->max_dpcd_transaction_bytes = max_dpcd_transaction_bytes; 2927 mgr->max_dpcd_transaction_bytes = max_dpcd_transaction_bytes;
2848 mgr->max_payloads = max_payloads; 2928 mgr->max_payloads = max_payloads;
2849 mgr->conn_base_id = conn_base_id; 2929 mgr->conn_base_id = conn_base_id;
2930 if (max_payloads + 1 > sizeof(mgr->payload_mask) * 8 ||
2931 max_payloads + 1 > sizeof(mgr->vcpi_mask) * 8)
2932 return -EINVAL;
2850 mgr->payloads = kcalloc(max_payloads, sizeof(struct drm_dp_payload), GFP_KERNEL); 2933 mgr->payloads = kcalloc(max_payloads, sizeof(struct drm_dp_payload), GFP_KERNEL);
2851 if (!mgr->payloads) 2934 if (!mgr->payloads)
2852 return -ENOMEM; 2935 return -ENOMEM;
@@ -2854,7 +2937,9 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
2854 if (!mgr->proposed_vcpis) 2937 if (!mgr->proposed_vcpis)
2855 return -ENOMEM; 2938 return -ENOMEM;
2856 set_bit(0, &mgr->payload_mask); 2939 set_bit(0, &mgr->payload_mask);
2857 test_calc_pbn_mode(); 2940 if (test_calc_pbn_mode() < 0)
2941 DRM_ERROR("MST PBN self-test failed\n");
2942
2858 return 0; 2943 return 0;
2859} 2944}
2860EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init); 2945EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init);
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
index 24ab1787b771..fdb47051d549 100644
--- a/include/drm/drm_dp_mst_helper.h
+++ b/include/drm/drm_dp_mst_helper.h
@@ -44,8 +44,6 @@ struct drm_dp_vcpi {
44/** 44/**
45 * struct drm_dp_mst_port - MST port 45 * struct drm_dp_mst_port - MST port
46 * @kref: reference count for this port. 46 * @kref: reference count for this port.
47 * @guid_valid: for DP 1.2 devices if we have validated the GUID.
48 * @guid: guid for DP 1.2 device on this port.
49 * @port_num: port number 47 * @port_num: port number
50 * @input: if this port is an input port. 48 * @input: if this port is an input port.
51 * @mcs: message capability status - DP 1.2 spec. 49 * @mcs: message capability status - DP 1.2 spec.
@@ -70,10 +68,6 @@ struct drm_dp_vcpi {
70struct drm_dp_mst_port { 68struct drm_dp_mst_port {
71 struct kref kref; 69 struct kref kref;
72 70
73 /* if dpcd 1.2 device is on this port - its GUID info */
74 bool guid_valid;
75 u8 guid[16];
76
77 u8 port_num; 71 u8 port_num;
78 bool input; 72 bool input;
79 bool mcs; 73 bool mcs;
@@ -110,10 +104,12 @@ struct drm_dp_mst_port {
110 * @tx_slots: transmission slots for this device. 104 * @tx_slots: transmission slots for this device.
111 * @last_seqno: last sequence number used to talk to this. 105 * @last_seqno: last sequence number used to talk to this.
112 * @link_address_sent: if a link address message has been sent to this device yet. 106 * @link_address_sent: if a link address message has been sent to this device yet.
107 * @guid: guid for DP 1.2 branch device. port under this branch can be
108 * identified by port #.
113 * 109 *
114 * This structure represents an MST branch device, there is one 110 * This structure represents an MST branch device, there is one
115 * primary branch device at the root, along with any others connected 111 * primary branch device at the root, along with any other branches connected
116 * to downstream ports 112 * to downstream port of parent branches.
117 */ 113 */
118struct drm_dp_mst_branch { 114struct drm_dp_mst_branch {
119 struct kref kref; 115 struct kref kref;
@@ -132,6 +128,9 @@ struct drm_dp_mst_branch {
132 struct drm_dp_sideband_msg_tx *tx_slots[2]; 128 struct drm_dp_sideband_msg_tx *tx_slots[2];
133 int last_seqno; 129 int last_seqno;
134 bool link_address_sent; 130 bool link_address_sent;
131
132 /* global unique identifier to identify branch devices */
133 u8 guid[16];
135}; 134};
136 135
137 136
@@ -406,11 +405,9 @@ struct drm_dp_payload {
406 * @conn_base_id: DRM connector ID this mgr is connected to. 405 * @conn_base_id: DRM connector ID this mgr is connected to.
407 * @down_rep_recv: msg receiver state for down replies. 406 * @down_rep_recv: msg receiver state for down replies.
408 * @up_req_recv: msg receiver state for up requests. 407 * @up_req_recv: msg receiver state for up requests.
409 * @lock: protects mst state, primary, guid, dpcd. 408 * @lock: protects mst state, primary, dpcd.
410 * @mst_state: if this manager is enabled for an MST capable port. 409 * @mst_state: if this manager is enabled for an MST capable port.
411 * @mst_primary: pointer to the primary branch device. 410 * @mst_primary: pointer to the primary branch device.
412 * @guid_valid: GUID valid for the primary branch device.
413 * @guid: GUID for primary port.
414 * @dpcd: cache of DPCD for primary port. 411 * @dpcd: cache of DPCD for primary port.
415 * @pbn_div: PBN to slots divisor. 412 * @pbn_div: PBN to slots divisor.
416 * 413 *
@@ -432,13 +429,11 @@ struct drm_dp_mst_topology_mgr {
432 struct drm_dp_sideband_msg_rx up_req_recv; 429 struct drm_dp_sideband_msg_rx up_req_recv;
433 430
434 /* pointer to info about the initial MST device */ 431 /* pointer to info about the initial MST device */
435 struct mutex lock; /* protects mst_state + primary + guid + dpcd */ 432 struct mutex lock; /* protects mst_state + primary + dpcd */
436 433
437 bool mst_state; 434 bool mst_state;
438 struct drm_dp_mst_branch *mst_primary; 435 struct drm_dp_mst_branch *mst_primary;
439 /* primary MST device GUID */ 436
440 bool guid_valid;
441 u8 guid[16];
442 u8 dpcd[DP_RECEIVER_CAP_SIZE]; 437 u8 dpcd[DP_RECEIVER_CAP_SIZE];
443 u8 sink_count; 438 u8 sink_count;
444 int pbn_div; 439 int pbn_div;
diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h
index d639049a613d..553210c02ee0 100644
--- a/include/drm/drm_fixed.h
+++ b/include/drm/drm_fixed.h
@@ -73,18 +73,28 @@ static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B)
73#define DRM_FIXED_ONE (1ULL << DRM_FIXED_POINT) 73#define DRM_FIXED_ONE (1ULL << DRM_FIXED_POINT)
74#define DRM_FIXED_DECIMAL_MASK (DRM_FIXED_ONE - 1) 74#define DRM_FIXED_DECIMAL_MASK (DRM_FIXED_ONE - 1)
75#define DRM_FIXED_DIGITS_MASK (~DRM_FIXED_DECIMAL_MASK) 75#define DRM_FIXED_DIGITS_MASK (~DRM_FIXED_DECIMAL_MASK)
76#define DRM_FIXED_EPSILON 1LL
77#define DRM_FIXED_ALMOST_ONE (DRM_FIXED_ONE - DRM_FIXED_EPSILON)
76 78
77static inline s64 drm_int2fixp(int a) 79static inline s64 drm_int2fixp(int a)
78{ 80{
79 return ((s64)a) << DRM_FIXED_POINT; 81 return ((s64)a) << DRM_FIXED_POINT;
80} 82}
81 83
82static inline int drm_fixp2int(int64_t a) 84static inline int drm_fixp2int(s64 a)
83{ 85{
84 return ((s64)a) >> DRM_FIXED_POINT; 86 return ((s64)a) >> DRM_FIXED_POINT;
85} 87}
86 88
87static inline unsigned drm_fixp_msbset(int64_t a) 89static inline int drm_fixp2int_ceil(s64 a)
90{
91 if (a > 0)
92 return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE);
93 else
94 return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE);
95}
96
97static inline unsigned drm_fixp_msbset(s64 a)
88{ 98{
89 unsigned shift, sign = (a >> 63) & 1; 99 unsigned shift, sign = (a >> 63) & 1;
90 100
@@ -136,6 +146,45 @@ static inline s64 drm_fixp_div(s64 a, s64 b)
136 return result; 146 return result;
137} 147}
138 148
149static inline s64 drm_fixp_from_fraction(s64 a, s64 b)
150{
151 s64 res;
152 bool a_neg = a < 0;
153 bool b_neg = b < 0;
154 u64 a_abs = a_neg ? -a : a;
155 u64 b_abs = b_neg ? -b : b;
156 u64 rem;
157
158 /* determine integer part */
159 u64 res_abs = div64_u64_rem(a_abs, b_abs, &rem);
160
161 /* determine fractional part */
162 {
163 u32 i = DRM_FIXED_POINT;
164
165 do {
166 rem <<= 1;
167 res_abs <<= 1;
168 if (rem >= b_abs) {
169 res_abs |= 1;
170 rem -= b_abs;
171 }
172 } while (--i != 0);
173 }
174
175 /* round up LSB */
176 {
177 u64 summand = (rem << 1) >= b_abs;
178
179 res_abs += summand;
180 }
181
182 res = (s64) res_abs;
183 if (a_neg ^ b_neg)
184 res = -res;
185 return res;
186}
187
139static inline s64 drm_fixp_exp(s64 x) 188static inline s64 drm_fixp_exp(s64 x)
140{ 189{
141 s64 tolerance = div64_s64(DRM_FIXED_ONE, 1000000); 190 s64 tolerance = div64_s64(DRM_FIXED_ONE, 1000000);