Revert "drm/dp_mst: Remove single tx msg restriction."
[linux-2.6-microblaze.git] / drivers / gpu / drm / drm_dp_mst_topology.c
index ed0fea2..d2c1979 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/seq_file.h>
+#include <linux/iopoll.h>
 
 #if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS)
 #include <linux/stacktrace.h>
@@ -687,55 +688,53 @@ static void drm_dp_encode_sideband_reply(struct drm_dp_sideband_msg_reply_body *
        raw->cur_len = idx;
 }
 
-/* this adds a chunk of msg to the builder to get the final msg */
-static bool drm_dp_sideband_msg_build(struct drm_dp_sideband_msg_rx *msg,
-                                     u8 *replybuf, u8 replybuflen, bool hdr)
+static int drm_dp_sideband_msg_set_header(struct drm_dp_sideband_msg_rx *msg,
+                                         struct drm_dp_sideband_msg_hdr *hdr,
+                                         u8 hdrlen)
 {
-       int ret;
-       u8 crc4;
+       /*
+        * ignore out-of-order messages or messages that are part of a
+        * failed transaction
+        */
+       if (!hdr->somt && !msg->have_somt)
+               return false;
 
-       if (hdr) {
-               u8 hdrlen;
-               struct drm_dp_sideband_msg_hdr recv_hdr;
-               ret = drm_dp_decode_sideband_msg_hdr(&recv_hdr, replybuf, replybuflen, &hdrlen);
-               if (ret == false) {
-                       print_hex_dump(KERN_DEBUG, "failed hdr", DUMP_PREFIX_NONE, 16, 1, replybuf, replybuflen, false);
-                       return false;
-               }
+       /* get length contained in this portion */
+       msg->curchunk_idx = 0;
+       msg->curchunk_len = hdr->msg_len;
+       msg->curchunk_hdrlen = hdrlen;
 
-               /*
-                * ignore out-of-order messages or messages that are part of a
-                * failed transaction
-                */
-               if (!recv_hdr.somt && !msg->have_somt)
-                       return false;
+       /* we have already gotten an somt - don't bother parsing */
+       if (hdr->somt && msg->have_somt)
+               return false;
 
-               /* get length contained in this portion */
-               msg->curchunk_len = recv_hdr.msg_len;
-               msg->curchunk_hdrlen = hdrlen;
+       if (hdr->somt) {
+               memcpy(&msg->initial_hdr, hdr,
+                      sizeof(struct drm_dp_sideband_msg_hdr));
+               msg->have_somt = true;
+       }
+       if (hdr->eomt)
+               msg->have_eomt = true;
 
-               /* we have already gotten an somt - don't bother parsing */
-               if (recv_hdr.somt && msg->have_somt)
-                       return false;
+       return true;
+}
 
-               if (recv_hdr.somt) {
-                       memcpy(&msg->initial_hdr, &recv_hdr, sizeof(struct drm_dp_sideband_msg_hdr));
-                       msg->have_somt = true;
-               }
-               if (recv_hdr.eomt)
-                       msg->have_eomt = true;
+/* this adds a chunk of msg to the builder to get the final msg */
+static bool drm_dp_sideband_append_payload(struct drm_dp_sideband_msg_rx *msg,
+                                          u8 *replybuf, u8 replybuflen)
+{
+       u8 crc4;
 
-               /* copy the bytes for the remainder of this header chunk */
-               msg->curchunk_idx = min(msg->curchunk_len, (u8)(replybuflen - hdrlen));
-               memcpy(&msg->chunk[0], replybuf + hdrlen, msg->curchunk_idx);
-       } else {
-               memcpy(&msg->chunk[msg->curchunk_idx], replybuf, replybuflen);
-               msg->curchunk_idx += replybuflen;
-       }
+       memcpy(&msg->chunk[msg->curchunk_idx], replybuf, replybuflen);
+       msg->curchunk_idx += replybuflen;
 
        if (msg->curchunk_idx >= msg->curchunk_len) {
                /* do CRC */
                crc4 = drm_dp_msg_data_crc4(msg->chunk, msg->curchunk_len - 1);
+               if (crc4 != msg->chunk[msg->curchunk_len - 1])
+                       print_hex_dump(KERN_DEBUG, "wrong crc",
+                                      DUMP_PREFIX_NONE, 16, 1,
+                                      msg->chunk,  msg->curchunk_len, false);
                /* copy chunk into bigger msg */
                memcpy(&msg->msg[msg->curlen], msg->chunk, msg->curchunk_len - 1);
                msg->curlen += msg->curchunk_len - 1;
@@ -1035,7 +1034,8 @@ static bool drm_dp_sideband_parse_req(struct drm_dp_sideband_msg_rx *raw,
        }
 }
 
-static int build_dpcd_write(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 offset, u8 num_bytes, u8 *bytes)
+static void build_dpcd_write(struct drm_dp_sideband_msg_tx *msg,
+                            u8 port_num, u32 offset, u8 num_bytes, u8 *bytes)
 {
        struct drm_dp_sideband_msg_req_body req;
 
@@ -1045,29 +1045,26 @@ static int build_dpcd_write(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32
        req.u.dpcd_write.num_bytes = num_bytes;
        req.u.dpcd_write.bytes = bytes;
        drm_dp_encode_sideband_req(&req, msg);
-
-       return 0;
 }
 
-static int build_link_address(struct drm_dp_sideband_msg_tx *msg)
+static void build_link_address(struct drm_dp_sideband_msg_tx *msg)
 {
        struct drm_dp_sideband_msg_req_body req;
 
        req.req_type = DP_LINK_ADDRESS;
        drm_dp_encode_sideband_req(&req, msg);
-       return 0;
 }
 
-static int build_clear_payload_id_table(struct drm_dp_sideband_msg_tx *msg)
+static void build_clear_payload_id_table(struct drm_dp_sideband_msg_tx *msg)
 {
        struct drm_dp_sideband_msg_req_body req;
 
        req.req_type = DP_CLEAR_PAYLOAD_ID_TABLE;
        drm_dp_encode_sideband_req(&req, msg);
-       return 0;
 }
 
-static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg, int port_num)
+static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg,
+                                    int port_num)
 {
        struct drm_dp_sideband_msg_req_body req;
 
@@ -1078,10 +1075,11 @@ static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg, int por
        return 0;
 }
 
-static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_num,
-                                 u8 vcpi, uint16_t pbn,
-                                 u8 number_sdp_streams,
-                                 u8 *sdp_stream_sink)
+static void build_allocate_payload(struct drm_dp_sideband_msg_tx *msg,
+                                  int port_num,
+                                  u8 vcpi, uint16_t pbn,
+                                  u8 number_sdp_streams,
+                                  u8 *sdp_stream_sink)
 {
        struct drm_dp_sideband_msg_req_body req;
        memset(&req, 0, sizeof(req));
@@ -1094,11 +1092,10 @@ static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_n
                   number_sdp_streams);
        drm_dp_encode_sideband_req(&req, msg);
        msg->path_msg = true;
-       return 0;
 }
 
-static int build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg,
-                                 int port_num, bool power_up)
+static void build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg,
+                                  int port_num, bool power_up)
 {
        struct drm_dp_sideband_msg_req_body req;
 
@@ -1110,7 +1107,6 @@ static int build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg,
        req.u.port_num.port_number = port_num;
        drm_dp_encode_sideband_req(&req, msg);
        msg->path_msg = true;
-       return 0;
 }
 
 static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr,
@@ -2061,7 +2057,7 @@ ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux,
  * sideband messaging as drm_dp_dpcd_write() does for local
  * devices via actual AUX CH.
  *
- * Return: 0 on success, negative error code on failure.
+ * Return: number of bytes written on success, negative error code on failure.
  */
 ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
                              unsigned int offset, void *buffer, size_t size)
@@ -2073,29 +2069,27 @@ ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
                                      offset, size, buffer);
 }
 
-static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid)
+static int drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid)
 {
-       int ret;
+       int ret = 0;
 
        memcpy(mstb->guid, guid, 16);
 
        if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) {
                if (mstb->port_parent) {
-                       ret = drm_dp_send_dpcd_write(
-                                       mstb->mgr,
-                                       mstb->port_parent,
-                                       DP_GUID,
-                                       16,
-                                       mstb->guid);
+                       ret = drm_dp_send_dpcd_write(mstb->mgr,
+                                                    mstb->port_parent,
+                                                    DP_GUID, 16, mstb->guid);
                } else {
-
-                       ret = drm_dp_dpcd_write(
-                                       mstb->mgr->aux,
-                                       DP_GUID,
-                                       mstb->guid,
-                                       16);
+                       ret = drm_dp_dpcd_write(mstb->mgr->aux,
+                                               DP_GUID, mstb->guid, 16);
                }
        }
+
+       if (ret < 16 && ret > 0)
+               return -EPROTO;
+
+       return ret == 16 ? 0 : ret;
 }
 
 static void build_mst_prop_path(const struct drm_dp_mst_branch *mstb,
@@ -2178,7 +2172,7 @@ drm_dp_mst_port_add_connector(struct drm_dp_mst_branch *mstb,
                drm_connector_set_tile_property(port->connector);
        }
 
-       mgr->cbs->register_connector(port->connector);
+       drm_connector_register(port->connector);
        return;
 
 error:
@@ -2641,7 +2635,8 @@ static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
        return false;
 }
 
-static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 offset, u8 num_bytes)
+static void build_dpcd_read(struct drm_dp_sideband_msg_tx *msg,
+                           u8 port_num, u32 offset, u8 num_bytes)
 {
        struct drm_dp_sideband_msg_req_body req;
 
@@ -2650,8 +2645,6 @@ static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32
        req.u.dpcd_read.dpcd_address = offset;
        req.u.dpcd_read.num_bytes = num_bytes;
        drm_dp_encode_sideband_req(&req, msg);
-
-       return 0;
 }
 
 static int drm_dp_send_sideband_msg(struct drm_dp_mst_topology_mgr *mgr,
@@ -2877,7 +2870,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
        struct drm_dp_sideband_msg_tx *txmsg;
        struct drm_dp_link_address_ack_reply *reply;
        struct drm_dp_mst_port *port, *tmp;
-       int i, len, ret, port_mask = 0;
+       int i, ret, port_mask = 0;
        bool changed = false;
 
        txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
@@ -2885,7 +2878,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
                return -ENOMEM;
 
        txmsg->dst = mstb;
-       len = build_link_address(txmsg);
+       build_link_address(txmsg);
 
        mstb->link_address_sent = true;
        drm_dp_queue_down_tx(mgr, txmsg);
@@ -2906,7 +2899,15 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
        DRM_DEBUG_KMS("link address reply: %d\n", reply->nports);
        drm_dp_dump_link_address(reply);
 
-       drm_dp_check_mstb_guid(mstb, reply->guid);
+       ret = drm_dp_check_mstb_guid(mstb, reply->guid);
+       if (ret) {
+               char buf[64];
+
+               drm_dp_mst_rad_to_str(mstb->rad, mstb->lct, buf, sizeof(buf));
+               DRM_ERROR("GUID check on %s failed: %d\n",
+                         buf, ret);
+               goto out;
+       }
 
        for (i = 0; i < reply->nports; i++) {
                port_mask |= BIT(reply->ports[i].port_number);
@@ -2947,14 +2948,14 @@ void drm_dp_send_clear_payload_id_table(struct drm_dp_mst_topology_mgr *mgr,
                                        struct drm_dp_mst_branch *mstb)
 {
        struct drm_dp_sideband_msg_tx *txmsg;
-       int len, ret;
+       int ret;
 
        txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
        if (!txmsg)
                return;
 
        txmsg->dst = mstb;
-       len = build_clear_payload_id_table(txmsg);
+       build_clear_payload_id_table(txmsg);
 
        drm_dp_queue_down_tx(mgr, txmsg);
 
@@ -2972,7 +2973,6 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
 {
        struct drm_dp_enum_path_resources_ack_reply *path_res;
        struct drm_dp_sideband_msg_tx *txmsg;
-       int len;
        int ret;
 
        txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
@@ -2980,7 +2980,7 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
                return -ENOMEM;
 
        txmsg->dst = mstb;
-       len = build_enum_path_resources(txmsg, port->port_num);
+       build_enum_path_resources(txmsg, port->port_num);
 
        drm_dp_queue_down_tx(mgr, txmsg);
 
@@ -3073,7 +3073,7 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
 {
        struct drm_dp_sideband_msg_tx *txmsg;
        struct drm_dp_mst_branch *mstb;
-       int len, ret, port_num;
+       int ret, port_num;
        u8 sinks[DRM_DP_MAX_SDP_STREAMS];
        int i;
 
@@ -3098,9 +3098,9 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
                sinks[i] = i;
 
        txmsg->dst = mstb;
-       len = build_allocate_payload(txmsg, port_num,
-                                    id,
-                                    pbn, port->num_sdp_streams, sinks);
+       build_allocate_payload(txmsg, port_num,
+                              id,
+                              pbn, port->num_sdp_streams, sinks);
 
        drm_dp_queue_down_tx(mgr, txmsg);
 
@@ -3129,7 +3129,7 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr,
                                 struct drm_dp_mst_port *port, bool power_up)
 {
        struct drm_dp_sideband_msg_tx *txmsg;
-       int len, ret;
+       int ret;
 
        port = drm_dp_mst_topology_get_port_validated(mgr, port);
        if (!port)
@@ -3142,7 +3142,7 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr,
        }
 
        txmsg->dst = port->parent;
-       len = build_power_updown_phy(txmsg, port->port_num, power_up);
+       build_power_updown_phy(txmsg, port->port_num, power_up);
        drm_dp_queue_down_tx(mgr, txmsg);
 
        ret = drm_dp_mst_wait_tx_reply(port->parent, txmsg);
@@ -3364,7 +3364,6 @@ static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr,
                                 struct drm_dp_mst_port *port,
                                 int offset, int size, u8 *bytes)
 {
-       int len;
        int ret = 0;
        struct drm_dp_sideband_msg_tx *txmsg;
        struct drm_dp_mst_branch *mstb;
@@ -3379,7 +3378,7 @@ static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr,
                goto fail_put;
        }
 
-       len = build_dpcd_read(txmsg, port->port_num, offset, size);
+       build_dpcd_read(txmsg, port->port_num, offset, size);
        txmsg->dst = port->parent;
 
        drm_dp_queue_down_tx(mgr, txmsg);
@@ -3417,7 +3416,6 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
                                  struct drm_dp_mst_port *port,
                                  int offset, int size, u8 *bytes)
 {
-       int len;
        int ret;
        struct drm_dp_sideband_msg_tx *txmsg;
        struct drm_dp_mst_branch *mstb;
@@ -3432,18 +3430,15 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
                goto fail_put;
        }
 
-       len = build_dpcd_write(txmsg, port->port_num, offset, size, bytes);
+       build_dpcd_write(txmsg, port->port_num, offset, size, bytes);
        txmsg->dst = mstb;
 
        drm_dp_queue_down_tx(mgr, txmsg);
 
        ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
-       if (ret > 0) {
-               if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK)
-                       ret = -EIO;
-               else
-                       ret = 0;
-       }
+       if (ret > 0 && txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK)
+               ret = -EIO;
+
        kfree(txmsg);
 fail_put:
        drm_dp_mst_topology_put_mstb(mstb);
@@ -3504,9 +3499,9 @@ static int drm_dp_get_vc_payload_bw(u8 dp_link_bw, u8  dp_link_count)
 int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool mst_state)
 {
        int ret = 0;
-       int i = 0;
        struct drm_dp_mst_branch *mstb = NULL;
 
+       mutex_lock(&mgr->payload_lock);
        mutex_lock(&mgr->lock);
        if (mst_state == mgr->mst_state)
                goto out_unlock;
@@ -3514,6 +3509,8 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
        mgr->mst_state = mst_state;
        /* set the device into MST mode */
        if (mst_state) {
+               struct drm_dp_payload reset_pay;
+
                WARN_ON(mgr->mst_primary);
 
                /* get dpcd info */
@@ -3543,17 +3540,15 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
                drm_dp_mst_topology_get_mstb(mgr->mst_primary);
 
                ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
-                                                        DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC);
-               if (ret < 0) {
+                                        DP_MST_EN |
+                                        DP_UP_REQ_EN |
+                                        DP_UPSTREAM_IS_SRC);
+               if (ret < 0)
                        goto out_unlock;
-               }
 
-               {
-                       struct drm_dp_payload reset_pay;
-                       reset_pay.start_slot = 0;
-                       reset_pay.num_slots = 0x3f;
-                       drm_dp_dpcd_write_payload(mgr, 0, &reset_pay);
-               }
+               reset_pay.start_slot = 0;
+               reset_pay.num_slots = 0x3f;
+               drm_dp_dpcd_write_payload(mgr, 0, &reset_pay);
 
                queue_work(system_long_wq, &mgr->work);
 
@@ -3565,27 +3560,19 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
                /* this can fail if the device is gone */
                drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0);
                ret = 0;
-               mutex_lock(&mgr->payload_lock);
-               memset(mgr->payloads, 0, mgr->max_payloads * sizeof(struct drm_dp_payload));
+               memset(mgr->payloads, 0,
+                      mgr->max_payloads * sizeof(mgr->payloads[0]));
+               memset(mgr->proposed_vcpis, 0,
+                      mgr->max_payloads * sizeof(mgr->proposed_vcpis[0]));
                mgr->payload_mask = 0;
                set_bit(0, &mgr->payload_mask);
-               for (i = 0; i < mgr->max_payloads; i++) {
-                       struct drm_dp_vcpi *vcpi = mgr->proposed_vcpis[i];
-
-                       if (vcpi) {
-                               vcpi->vcpi = 0;
-                               vcpi->num_slots = 0;
-                       }
-                       mgr->proposed_vcpis[i] = NULL;
-               }
                mgr->vcpi_mask = 0;
-               mutex_unlock(&mgr->payload_lock);
-
                mgr->payload_id_table_cleared = false;
        }
 
 out_unlock:
        mutex_unlock(&mgr->lock);
+       mutex_unlock(&mgr->payload_lock);
        if (mstb)
                drm_dp_mst_topology_put_mstb(mstb);
        return ret;
@@ -3682,7 +3669,12 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr,
                DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n");
                goto out_fail;
        }
-       drm_dp_check_mstb_guid(mgr->mst_primary, guid);
+
+       ret = drm_dp_check_mstb_guid(mgr->mst_primary, guid);
+       if (ret) {
+               DRM_DEBUG_KMS("check mstb failed - undocked during suspend?\n");
+               goto out_fail;
+       }
 
        /*
         * For the final step of resuming the topology, we need to bring the
@@ -3705,32 +3697,67 @@ out_fail:
 }
 EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume);
 
-static bool 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,
+                                 struct drm_dp_mst_branch **mstb, int *seqno)
 {
        int len;
        u8 replyblock[32];
-       int replylen, origlen, curreply;
+       int replylen, curreply;
        int ret;
+       u8 hdrlen;
+       struct drm_dp_sideband_msg_hdr hdr;
        struct drm_dp_sideband_msg_rx *msg;
-       int basereg = up ? DP_SIDEBAND_MSG_UP_REQ_BASE : DP_SIDEBAND_MSG_DOWN_REP_BASE;
-       msg = up ? &mgr->up_req_recv : &mgr->down_rep_recv;
+       int basereg = up ? DP_SIDEBAND_MSG_UP_REQ_BASE :
+                          DP_SIDEBAND_MSG_DOWN_REP_BASE;
+
+       if (!up)
+               *mstb = NULL;
+       *seqno = -1;
 
        len = min(mgr->max_dpcd_transaction_bytes, 16);
-       ret = drm_dp_dpcd_read(mgr->aux, basereg,
-                              replyblock, len);
+       ret = drm_dp_dpcd_read(mgr->aux, basereg, replyblock, len);
        if (ret != len) {
                DRM_DEBUG_KMS("failed to read DPCD down rep %d %d\n", len, ret);
                return false;
        }
-       ret = drm_dp_sideband_msg_build(msg, replyblock, len, true);
+
+       ret = drm_dp_decode_sideband_msg_hdr(&hdr, replyblock, len, &hdrlen);
+       if (ret == false) {
+               print_hex_dump(KERN_DEBUG, "failed hdr", DUMP_PREFIX_NONE, 16,
+                              1, replyblock, len, false);
+               DRM_DEBUG_KMS("ERROR: failed header\n");
+               return false;
+       }
+
+       *seqno = hdr.seqno;
+
+       if (up) {
+               msg = &mgr->up_req_recv;
+       } else {
+               /* Caller is responsible for giving back this reference */
+               *mstb = drm_dp_get_mst_branch_device(mgr, hdr.lct, hdr.rad);
+               if (!*mstb) {
+                       DRM_DEBUG_KMS("Got MST reply from unknown device %d\n",
+                                     hdr.lct);
+                       return false;
+               }
+               msg = &(*mstb)->down_rep_recv[hdr.seqno];
+       }
+
+       if (!drm_dp_sideband_msg_set_header(msg, &hdr, hdrlen)) {
+               DRM_DEBUG_KMS("sideband msg set header failed %d\n",
+                             replyblock[0]);
+               return false;
+       }
+
+       replylen = min(msg->curchunk_len, (u8)(len - hdrlen));
+       ret = drm_dp_sideband_append_payload(msg, replyblock + hdrlen, replylen);
        if (!ret) {
                DRM_DEBUG_KMS("sideband msg build failed %d\n", replyblock[0]);
                return false;
        }
-       replylen = msg->curchunk_len + msg->curchunk_hdrlen;
 
-       origlen = replylen;
-       replylen -= len;
+       replylen = msg->curchunk_len + msg->curchunk_hdrlen - len;
        curreply = len;
        while (replylen > 0) {
                len = min3(replylen, mgr->max_dpcd_transaction_bytes, 16);
@@ -3742,7 +3769,7 @@ static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
                        return false;
                }
 
-               ret = drm_dp_sideband_msg_build(msg, replyblock, len, false);
+               ret = drm_dp_sideband_append_payload(msg, replyblock, len);
                if (!ret) {
                        DRM_DEBUG_KMS("failed to build sideband msg\n");
                        return false;
@@ -3757,53 +3784,51 @@ static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
 static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
 {
        struct drm_dp_sideband_msg_tx *txmsg;
-       struct drm_dp_mst_branch *mstb;
-       struct drm_dp_sideband_msg_hdr *hdr = &mgr->down_rep_recv.initial_hdr;
-       int slot = -1;
+       struct drm_dp_mst_branch *mstb = NULL;
+       struct drm_dp_sideband_msg_rx *msg = NULL;
+       int seqno = -1;
 
-       if (!drm_dp_get_one_sb_msg(mgr, false))
-               goto clear_down_rep_recv;
+       if (!drm_dp_get_one_sb_msg(mgr, false, &mstb, &seqno))
+               goto out_clear_reply;
 
-       if (!mgr->down_rep_recv.have_eomt)
-               return 0;
+       msg = &mstb->down_rep_recv[seqno];
 
-       mstb = drm_dp_get_mst_branch_device(mgr, hdr->lct, hdr->rad);
-       if (!mstb) {
-               DRM_DEBUG_KMS("Got MST reply from unknown device %d\n",
-                             hdr->lct);
-               goto clear_down_rep_recv;
-       }
+       /* Multi-packet message transmission, don't clear the reply */
+       if (!msg->have_eomt)
+               goto out;
 
        /* find the message */
-       slot = hdr->seqno;
        mutex_lock(&mgr->qlock);
-       txmsg = mstb->tx_slots[slot];
+       txmsg = mstb->tx_slots[seqno];
        /* remove from slots */
        mutex_unlock(&mgr->qlock);
 
        if (!txmsg) {
+               struct drm_dp_sideband_msg_hdr *hdr;
+               hdr = &msg->initial_hdr;
                DRM_DEBUG_KMS("Got MST reply with no msg %p %d %d %02x %02x\n",
                              mstb, hdr->seqno, hdr->lct, hdr->rad[0],
-                             mgr->down_rep_recv.msg[0]);
-               goto no_msg;
+                             msg->msg[0]);
+               goto out_clear_reply;
        }
 
-       drm_dp_sideband_parse_reply(&mgr->down_rep_recv, &txmsg->reply);
+       drm_dp_sideband_parse_reply(msg, &txmsg->reply);
 
-       if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK)
+       if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
                DRM_DEBUG_KMS("Got NAK reply: req 0x%02x (%s), reason 0x%02x (%s), nak data 0x%02x\n",
                              txmsg->reply.req_type,
                              drm_dp_mst_req_type_str(txmsg->reply.req_type),
                              txmsg->reply.u.nak.reason,
                              drm_dp_mst_nak_reason_str(txmsg->reply.u.nak.reason),
                              txmsg->reply.u.nak.nak_data);
+       }
 
-       memset(&mgr->down_rep_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
+       memset(msg, 0, sizeof(struct drm_dp_sideband_msg_rx));
        drm_dp_mst_topology_put_mstb(mstb);
 
        mutex_lock(&mgr->qlock);
        txmsg->state = DRM_DP_SIDEBAND_TX_RX;
-       mstb->tx_slots[slot] = NULL;
+       mstb->tx_slots[seqno] = NULL;
        mgr->is_waiting_for_dwn_reply = false;
        mutex_unlock(&mgr->qlock);
 
@@ -3811,13 +3836,15 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
 
        return 0;
 
-no_msg:
-       drm_dp_mst_topology_put_mstb(mstb);
-clear_down_rep_recv:
+out_clear_reply:
        mutex_lock(&mgr->qlock);
        mgr->is_waiting_for_dwn_reply = false;
        mutex_unlock(&mgr->qlock);
-       memset(&mgr->down_rep_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
+       if (msg)
+               memset(msg, 0, sizeof(struct drm_dp_sideband_msg_rx));
+out:
+       if (mstb)
+               drm_dp_mst_topology_put_mstb(mstb);
 
        return 0;
 }
@@ -3893,11 +3920,10 @@ static void drm_dp_mst_up_req_work(struct work_struct *work)
 
 static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
 {
-       struct drm_dp_sideband_msg_hdr *hdr = &mgr->up_req_recv.initial_hdr;
        struct drm_dp_pending_up_req *up_req;
-       bool seqno;
+       int seqno;
 
-       if (!drm_dp_get_one_sb_msg(mgr, true))
+       if (!drm_dp_get_one_sb_msg(mgr, true, NULL, &seqno))
                goto out;
 
        if (!mgr->up_req_recv.have_eomt)
@@ -3910,7 +3936,6 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
        }
        INIT_LIST_HEAD(&up_req->next);
 
-       seqno = hdr->seqno;
        drm_dp_sideband_parse_req(&mgr->up_req_recv, &up_req->msg);
 
        if (up_req->msg.req_type != DP_CONNECTION_STATUS_NOTIFY &&
@@ -3944,7 +3969,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
                              res_stat->available_pbn);
        }
 
-       up_req->hdr = *hdr;
+       up_req->hdr = mgr->up_req_recv.initial_hdr;
        mutex_lock(&mgr->up_req_lock);
        list_add_tail(&up_req->next, &mgr->up_req_list);
        mutex_unlock(&mgr->up_req_lock);
@@ -4049,27 +4074,6 @@ out:
 }
 EXPORT_SYMBOL(drm_dp_mst_detect_port);
 
-/**
- * drm_dp_mst_port_has_audio() - Check whether port has audio capability or not
- * @mgr: manager for this port
- * @port: unverified pointer to a port.
- *
- * This returns whether the port supports audio or not.
- */
-bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr,
-                                       struct drm_dp_mst_port *port)
-{
-       bool ret = false;
-
-       port = drm_dp_mst_topology_get_port_validated(mgr, port);
-       if (!port)
-               return ret;
-       ret = port->has_audio;
-       drm_dp_mst_topology_put_port(port);
-       return ret;
-}
-EXPORT_SYMBOL(drm_dp_mst_port_has_audio);
-
 /**
  * drm_dp_mst_get_edid() - get EDID for an MST port
  * @connector: toplevel connector to get EDID for
@@ -4446,42 +4450,58 @@ fail:
        return ret;
 }
 
+static int do_get_act_status(struct drm_dp_aux *aux)
+{
+       int ret;
+       u8 status;
+
+       ret = drm_dp_dpcd_readb(aux, DP_PAYLOAD_TABLE_UPDATE_STATUS, &status);
+       if (ret < 0)
+               return ret;
+
+       return status;
+}
 
 /**
- * drm_dp_check_act_status() - Check ACT handled status.
+ * drm_dp_check_act_status() - Polls for ACT handled status.
  * @mgr: manager to use
  *
- * Check the payload status bits in the DPCD for ACT handled completion.
+ * Tries waiting for the MST hub to finish updating it's payload table by
+ * polling for the ACT handled bit for up to 3 seconds (yes-some hubs really
+ * take that long).
+ *
+ * Returns:
+ * 0 if the ACT was handled in time, negative error code on failure.
  */
 int drm_dp_check_act_status(struct drm_dp_mst_topology_mgr *mgr)
 {
-       u8 status;
-       int ret;
-       int count = 0;
-
-       do {
-               ret = drm_dp_dpcd_readb(mgr->aux, DP_PAYLOAD_TABLE_UPDATE_STATUS, &status);
-
-               if (ret < 0) {
-                       DRM_DEBUG_KMS("failed to read payload table status %d\n", ret);
-                       goto fail;
-               }
-
-               if (status & DP_PAYLOAD_ACT_HANDLED)
-                       break;
-               count++;
-               udelay(100);
-
-       } while (count < 30);
-
-       if (!(status & DP_PAYLOAD_ACT_HANDLED)) {
-               DRM_DEBUG_KMS("failed to get ACT bit %d after %d retries\n", status, count);
-               ret = -EINVAL;
-               goto fail;
+       /*
+        * There doesn't seem to be any recommended retry count or timeout in
+        * the MST specification. Since some hubs have been observed to take
+        * over 1 second to update their payload allocations under certain
+        * conditions, we use a rather large timeout value.
+        */
+       const int timeout_ms = 3000;
+       int ret, status;
+
+       ret = readx_poll_timeout(do_get_act_status, mgr->aux, status,
+                                status & DP_PAYLOAD_ACT_HANDLED || status < 0,
+                                200, timeout_ms * USEC_PER_MSEC);
+       if (ret < 0 && status >= 0) {
+               DRM_ERROR("Failed to get ACT after %dms, last status: %02x\n",
+                         timeout_ms, status);
+               return -EINVAL;
+       } else if (status < 0) {
+               /*
+                * Failure here isn't unexpected - the hub may have
+                * just been unplugged
+                */
+               DRM_DEBUG_KMS("Failed to read payload table status: %d\n",
+                             status);
+               return status;
        }
+
        return 0;
-fail:
-       return ret;
 }
 EXPORT_SYMBOL(drm_dp_check_act_status);
 
@@ -4625,15 +4645,34 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
                int ret;
 
                ret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, buf, DP_RECEIVER_CAP_SIZE);
+               if (ret) {
+                       seq_printf(m, "dpcd read failed\n");
+                       goto out;
+               }
                seq_printf(m, "dpcd: %*ph\n", DP_RECEIVER_CAP_SIZE, buf);
+
                ret = drm_dp_dpcd_read(mgr->aux, DP_FAUX_CAP, buf, 2);
+               if (ret) {
+                       seq_printf(m, "faux/mst read failed\n");
+                       goto out;
+               }
                seq_printf(m, "faux/mst: %*ph\n", 2, buf);
+
                ret = drm_dp_dpcd_read(mgr->aux, DP_MSTM_CTRL, buf, 1);
+               if (ret) {
+                       seq_printf(m, "mst ctrl read failed\n");
+                       goto out;
+               }
                seq_printf(m, "mst ctrl: %*ph\n", 1, buf);
 
                /* dump the standard OUI branch header */
                ret = drm_dp_dpcd_read(mgr->aux, DP_BRANCH_OUI, buf, DP_BRANCH_OUI_HEADER_SIZE);
+               if (ret) {
+                       seq_printf(m, "branch oui read failed\n");
+                       goto out;
+               }
                seq_printf(m, "branch oui: %*phN devid: ", 3, buf);
+
                for (i = 0x3; i < 0x8 && buf[i]; i++)
                        seq_printf(m, "%c", buf[i]);
                seq_printf(m, " revision: hw: %x.%x sw: %x.%x\n",
@@ -4642,6 +4681,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
                        seq_printf(m, "payload table: %*ph\n", DP_PAYLOAD_TABLE_SIZE, buf);
        }
 
+out:
        mutex_unlock(&mgr->lock);
 
 }
@@ -4660,8 +4700,10 @@ static void drm_dp_tx_work(struct work_struct *work)
 static inline void
 drm_dp_delayed_destroy_port(struct drm_dp_mst_port *port)
 {
-       if (port->connector)
-               port->mgr->cbs->destroy_connector(port->mgr, port->connector);
+       if (port->connector) {
+               drm_connector_unregister(port->connector);
+               drm_connector_put(port->connector);
+       }
 
        drm_dp_port_set_pdt(port, DP_PEER_DEVICE_NONE, port->mcs);
        drm_dp_mst_put_port_malloc(port);
@@ -5529,7 +5571,8 @@ struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port)
        if (drm_dp_read_desc(port->mgr->aux, &desc, true))
                return NULL;
 
-       if (drm_dp_has_quirk(&desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) &&
+       if (drm_dp_has_quirk(&desc, 0,
+                            DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) &&
            port->mgr->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14 &&
            port->parent == port->mgr->mst_primary) {
                u8 downstreamport;