]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/gpu/drm/drm_dp_mst_topology.c
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma
[linux.git] / drivers / gpu / drm / drm_dp_mst_topology.c
index bfd237c15e76e8cfe9f3c78ffd555f42390a7d5e..ae5f068955628248fe027f3e88df8ce84ce07de7 100644 (file)
@@ -330,6 +330,13 @@ static bool drm_dp_sideband_msg_build(struct drm_dp_sideband_msg_rx *msg,
                        return false;
                }
 
+               /*
+                * ignore out-of-order messages or messages that are part of a
+                * failed transaction
+                */
+               if (!recv_hdr.somt && !msg->have_somt)
+                       return false;
+
                /* get length contained in this portion */
                msg->curchunk_len = recv_hdr.msg_len;
                msg->curchunk_hdrlen = hdrlen;
@@ -2164,7 +2171,7 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr)
 }
 EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume);
 
-static void drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
+static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
 {
        int len;
        u8 replyblock[32];
@@ -2179,12 +2186,12 @@ static void drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
                               replyblock, len);
        if (ret != len) {
                DRM_DEBUG_KMS("failed to read DPCD down rep %d %d\n", len, ret);
-               return;
+               return false;
        }
        ret = drm_dp_sideband_msg_build(msg, replyblock, len, true);
        if (!ret) {
                DRM_DEBUG_KMS("sideband msg build failed %d\n", replyblock[0]);
-               return;
+               return false;
        }
        replylen = msg->curchunk_len + msg->curchunk_hdrlen;
 
@@ -2196,21 +2203,32 @@ static void drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
                ret = drm_dp_dpcd_read(mgr->aux, basereg + curreply,
                                    replyblock, len);
                if (ret != len) {
-                       DRM_DEBUG_KMS("failed to read a chunk\n");
+                       DRM_DEBUG_KMS("failed to read a chunk (len %d, ret %d)\n",
+                                     len, ret);
+                       return false;
                }
+
                ret = drm_dp_sideband_msg_build(msg, replyblock, len, false);
-               if (ret == false)
+               if (!ret) {
                        DRM_DEBUG_KMS("failed to build sideband msg\n");
+                       return false;
+               }
+
                curreply += len;
                replylen -= len;
        }
+       return true;
 }
 
 static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
 {
        int ret = 0;
 
-       drm_dp_get_one_sb_msg(mgr, false);
+       if (!drm_dp_get_one_sb_msg(mgr, false)) {
+               memset(&mgr->down_rep_recv, 0,
+                      sizeof(struct drm_dp_sideband_msg_rx));
+               return 0;
+       }
 
        if (mgr->down_rep_recv.have_eomt) {
                struct drm_dp_sideband_msg_tx *txmsg;
@@ -2266,7 +2284,12 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
 static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
 {
        int ret = 0;
-       drm_dp_get_one_sb_msg(mgr, true);
+
+       if (!drm_dp_get_one_sb_msg(mgr, true)) {
+               memset(&mgr->up_req_recv, 0,
+                      sizeof(struct drm_dp_sideband_msg_rx));
+               return 0;
+       }
 
        if (mgr->up_req_recv.have_eomt) {
                struct drm_dp_sideband_msg_req_body msg;
@@ -2318,7 +2341,9 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
                        DRM_DEBUG_KMS("Got RSN: pn: %d avail_pbn %d\n", msg.u.resource_stat.port_number, msg.u.resource_stat.available_pbn);
                }
 
-               drm_dp_put_mst_branch_device(mstb);
+               if (mstb)
+                       drm_dp_put_mst_branch_device(mstb);
+
                memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
        }
        return ret;