History

Merge tag 'topic/mst-bw-check-fixes-for-airlied-2020-03-12-2' of git://anongit.freedesktop.org/drm/drm-misc into drm-fixes

UAPI Changes: None Cross-subsystem Changes: None Core Changes: Fixed regressions introduced by commit cd82d82cbc04 ("drm/dp_mst: Add branch bandwidth validation to MST atomic check"), which would cause us to: * Calculate the available bandwidth on an MST topology incorrectly, and as a result reject most display configurations that would try to enable more then one sink on a topology * Occasionally expose MST connectors to userspace before finishing probing their PBN capabilities, resulting in us rejecting display configurations because we assumed briefly that no bandwidth was available Driver Changes: None

Dave Airlie committed 6 years ago

Commit 16b78f02 parents f31d83f 047d4cd2 files · +128 −60Browse files

Showing the changes to drivers/gpu (1 of 2 files). Show all

Unified · Split

drivers/gpu/drm/drm_dp_mst_topology.c+126−58
@@ -1935,7 +1935,7 @@ static u8 drm_dp_calculate_rad(struct drm_dp_mst_port *port, · 1934 unmodified lines
19351935 return parent_lct + 1;
19361936 }
19371937
1938−static bool drm_dp_mst_is_dp_mst_end_device(u8 pdt, bool mcs)
1938+static bool drm_dp_mst_is_end_device(u8 pdt, bool mcs)
19391939 {
19401940 switch (pdt) {
19411941 case DP_PEER_DEVICE_DP_LEGACY_CONV:
@@ -1965,13 +1965,13 @@ drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt, · 23 unmodified lines
19651965
19661966 /* Teardown the old pdt, if there is one */
19671967 if (port->pdt != DP_PEER_DEVICE_NONE) {
1968− if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
1968+ if (drm_dp_mst_is_end_device(port->pdt, port->mcs)) {
19691969 /*
19701970 * If the new PDT would also have an i2c bus,
19711971 * don't bother with reregistering it
19721972 */
19731973 if (new_pdt != DP_PEER_DEVICE_NONE &&
1974− drm_dp_mst_is_dp_mst_end_device(new_pdt, new_mcs)) {
1974+ drm_dp_mst_is_end_device(new_pdt, new_mcs)) {
19751975 port->pdt = new_pdt;
19761976 port->mcs = new_mcs;
19771977 return 0;
@@ -1991,7 +1991,7 @@ drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt, · 13 unmodified lines
19911991 port->mcs = new_mcs;
19921992
19931993 if (port->pdt != DP_PEER_DEVICE_NONE) {
1994− if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
1994+ if (drm_dp_mst_is_end_device(port->pdt, port->mcs)) {
19951995 /* add i2c over sideband */
19961996 ret = drm_dp_mst_register_i2c_bus(&port->aux);
19971997 } else {
@@ -2172,7 +2172,7 @@ drm_dp_mst_port_add_connector(struct drm_dp_mst_branch *mstb, · 174 unmodified lines
21722172 }
21732173
21742174 if (port->pdt != DP_PEER_DEVICE_NONE &&
2175− drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
2175+ drm_dp_mst_is_end_device(port->pdt, port->mcs)) {
21762176 port->cached_edid = drm_get_edid(port->connector,
21772177 &port->aux.ddc);
21782178 drm_connector_set_tile_property(port->connector);
@@ -2302,14 +2302,18 @@ drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb, · 123 unmodified lines
23022302 mutex_unlock(&mgr->lock);
23032303 }
23042304
2305− if (old_ddps != port->ddps) {
2306− if (port->ddps) {
2307− if (!port->input) {
2308− drm_dp_send_enum_path_resources(mgr, mstb,
2309− port);
2310− }
2305+ /*
2306+ * Reprobe PBN caps on both hotplug, and when re-probing the link
2307+ * for our parent mstb
2308+ */
2309+ if (old_ddps != port->ddps || !created) {
2310+ if (port->ddps && !port->input) {
2311+ ret = drm_dp_send_enum_path_resources(mgr, mstb,
2312+ port);
2313+ if (ret == 1)
2314+ changed = true;
23112315 } else {
2312− port->available_pbn = 0;
2316+ port->full_pbn = 0;
23132317 }
23142318 }
23152319
@@ -2401,11 +2405,10 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch *mstb, · 85 unmodified lines
24012405 port->ddps = conn_stat->displayport_device_plug_status;
24022406
24032407 if (old_ddps != port->ddps) {
2404− if (port->ddps) {
2405− dowork = true;
2406− } else {
2407− port->available_pbn = 0;
2408− }
2408+ if (port->ddps && !port->input)
2409+ drm_dp_send_enum_path_resources(mgr, mstb, port);
2410+ else
2411+ port->full_pbn = 0;
24092412 }
24102413
24112414 new_pdt = port->input ? DP_PEER_DEVICE_NONE : conn_stat->peer_device_type;
@@ -2556,13 +2559,6 @@ static int drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *mg · 144 unmodified lines
25562559 if (port->input || !port->ddps)
25572560 continue;
25582561
2559− if (!port->available_pbn) {
2560− drm_modeset_lock(&mgr->base.lock, NULL);
2561− drm_dp_send_enum_path_resources(mgr, mstb, port);
2562− drm_modeset_unlock(&mgr->base.lock);
2563− changed = true;
2564− }
2565−
25662562 if (port->mstb)
25672563 mstb_child = drm_dp_mst_topology_get_mstb_validated(
25682564 mgr, port->mstb);
@@ -2990,6 +2986,7 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, · 421 unmodified lines
29902986
29912987 ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
29922988 if (ret > 0) {
2989+ ret = 0;
29932990 path_res = &txmsg->reply.u.path_resources;
29942991
29952992 if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
@@ -3002,14 +2999,22 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, · 6 unmodified lines
30022999 path_res->port_number,
30033000 path_res->full_payload_bw_number,
30043001 path_res->avail_payload_bw_number);
3005− port->available_pbn =
3006− path_res->avail_payload_bw_number;
3002+
3003+ /*
3004+ * If something changed, make sure we send a
3005+ * hotplug
3006+ */
3007+ if (port->full_pbn != path_res->full_payload_bw_number ||
3008+ port->fec_capable != path_res->fec_capable)
3009+ ret = 1;
3010+
3011+ port->full_pbn = path_res->full_payload_bw_number;
30073012 port->fec_capable = path_res->fec_capable;
30083013 }
30093014 }
30103015
30113016 kfree(txmsg);
3012− return 0;
3017+ return ret;
30133018 }
30143019
30153020 static struct drm_dp_mst_port *drm_dp_get_last_connected_port_to_mstb(struct drm_dp_mst_branch *mstb)
@@ -3596,13 +3601,9 @@ drm_dp_mst_topology_mgr_invalidate_mstb(struct drm_dp_mst_branch *mstb) · 580 unmodified lines
35963601 /* The link address will need to be re-sent on resume */
35973602 mstb->link_address_sent = false;
35983603
3599− list_for_each_entry(port, &mstb->ports, next) {
3600− /* The PBN for each port will also need to be re-probed */
3601− port->available_pbn = 0;
3602−
3604+ list_for_each_entry(port, &mstb->ports, next)
36033605 if (port->mstb)
36043606 drm_dp_mst_topology_mgr_invalidate_mstb(port->mstb);
3605− }
36063607 }
36073608
36083609 /**
@@ -4829,41 +4830,102 @@ static bool drm_dp_mst_port_downstream_of_branch(struct drm_dp_mst_port *port, · 1220 unmodified lines
48294830 return false;
48304831 }
48314832
4832−static inline
4833−int drm_dp_mst_atomic_check_bw_limit(struct drm_dp_mst_branch *branch,
4834− struct drm_dp_mst_topology_state *mst_state)
4833+static int
4834+drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port,
4835+ struct drm_dp_mst_topology_state *state);
4836+
4837+static int
4838+drm_dp_mst_atomic_check_mstb_bw_limit(struct drm_dp_mst_branch *mstb,
4839+ struct drm_dp_mst_topology_state *state)
48354840 {
4836− struct drm_dp_mst_port *port;
48374841 struct drm_dp_vcpi_allocation *vcpi;
4838− int pbn_limit = 0, pbn_used = 0;
4842+ struct drm_dp_mst_port *port;
4843+ int pbn_used = 0, ret;
4844+ bool found = false;
48394845
4840− list_for_each_entry(port, &branch->ports, next) {
4841− if (port->mstb)
4842− if (drm_dp_mst_atomic_check_bw_limit(port->mstb, mst_state))
4843− return -ENOSPC;
4846+ /* Check that we have at least one port in our state that's downstream
4847+ * of this branch, otherwise we can skip this branch
4848+ */
4849+ list_for_each_entry(vcpi, &state->vcpis, next) {
4850+ if (!vcpi->pbn ||
4851+ !drm_dp_mst_port_downstream_of_branch(vcpi->port, mstb))
4852+ continue;
48444853
4845− if (port->available_pbn > 0)
4846− pbn_limit = port->available_pbn;
4854+ found = true;
4855+ break;
48474856 }
4848− DRM_DEBUG_ATOMIC("[MST BRANCH:%p] branch has %d PBN available\n",
4849− branch, pbn_limit);
4857+ if (!found)
4858+ return 0;
48504859
4851− list_for_each_entry(vcpi, &mst_state->vcpis, next) {
4852− if (!vcpi->pbn)
4853− continue;
4860+ if (mstb->port_parent)
4861+ DRM_DEBUG_ATOMIC("[MSTB:%p] [MST PORT:%p] Checking bandwidth limits on [MSTB:%p]\n",
4862+ mstb->port_parent->parent, mstb->port_parent,
4863+ mstb);
4864+ else
4865+ DRM_DEBUG_ATOMIC("[MSTB:%p] Checking bandwidth limits\n",
4866+ mstb);
4867+
4868+ list_for_each_entry(port, &mstb->ports, next) {
4869+ ret = drm_dp_mst_atomic_check_port_bw_limit(port, state);
4870+ if (ret < 0)
4871+ return ret;
48544872
4855− if (drm_dp_mst_port_downstream_of_branch(vcpi->port, branch))
4856− pbn_used += vcpi->pbn;
4873+ pbn_used += ret;
48574874 }
4858− DRM_DEBUG_ATOMIC("[MST BRANCH:%p] branch used %d PBN\n",
4859− branch, pbn_used);
48604875
4861− if (pbn_used > pbn_limit) {
4862− DRM_DEBUG_ATOMIC("[MST BRANCH:%p] No available bandwidth\n",
4863− branch);
4876+ return pbn_used;
4877+}
4878+
4879+static int
4880+drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port,
4881+ struct drm_dp_mst_topology_state *state)
4882+{
4883+ struct drm_dp_vcpi_allocation *vcpi;
4884+ int pbn_used = 0;
4885+
4886+ if (port->pdt == DP_PEER_DEVICE_NONE)
4887+ return 0;
4888+
4889+ if (drm_dp_mst_is_end_device(port->pdt, port->mcs)) {
4890+ bool found = false;
4891+
4892+ list_for_each_entry(vcpi, &state->vcpis, next) {
4893+ if (vcpi->port != port)
4894+ continue;
4895+ if (!vcpi->pbn)
4896+ return 0;
4897+
4898+ found = true;
4899+ break;
4900+ }
4901+ if (!found)
4902+ return 0;
4903+
4904+ /* This should never happen, as it means we tried to
4905+ * set a mode before querying the full_pbn
4906+ */
4907+ if (WARN_ON(!port->full_pbn))
4908+ return -EINVAL;
4909+
4910+ pbn_used = vcpi->pbn;
4911+ } else {
4912+ pbn_used = drm_dp_mst_atomic_check_mstb_bw_limit(port->mstb,
4913+ state);
4914+ if (pbn_used <= 0)
4915+ return pbn_used;
4916+ }
4917+
4918+ if (pbn_used > port->full_pbn) {
4919+ DRM_DEBUG_ATOMIC("[MSTB:%p] [MST PORT:%p] required PBN of %d exceeds port limit of %d\n",
4920+ port->parent, port, pbn_used,
4921+ port->full_pbn);
48644922 return -ENOSPC;
48654923 }
4866− return 0;
4924+
4925+ DRM_DEBUG_ATOMIC("[MSTB:%p] [MST PORT:%p] uses %d out of %d PBN\n",
4926+ port->parent, port, pbn_used, port->full_pbn);
4927+
4928+ return pbn_used;
48674929 }
48684930
48694931 static inline int
@@ -5061,9 +5123,15 @@ int drm_dp_mst_atomic_check(struct drm_atomic_state *state) · 191 unmodified lines
50615123 ret = drm_dp_mst_atomic_check_vcpi_alloc_limit(mgr, mst_state);
50625124 if (ret)
50635125 break;
5064− ret = drm_dp_mst_atomic_check_bw_limit(mgr->mst_primary, mst_state);
5065− if (ret)
5126+
5127+ mutex_lock(&mgr->lock);
5128+ ret = drm_dp_mst_atomic_check_mstb_bw_limit(mgr->mst_primary,
5129+ mst_state);
5130+ mutex_unlock(&mgr->lock);
5131+ if (ret < 0)
50665132 break;
5133+ else
5134+ ret = 0;
50675135 }
50685136
50695137 return ret;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t