Merge tag 'topic/core-stuff-2014-11-05' of git://anongit.freedesktop.org/drm-intel...
[platform/kernel/linux-rpi.git] / drivers / gpu / drm / drm_dp_mst_topology.c
index 094af1d..dc98b8f 100644 (file)
@@ -682,7 +682,7 @@ static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_n
 static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr,
                                        struct drm_dp_vcpi *vcpi)
 {
-       int ret;
+       int ret, vcpi_ret;
 
        mutex_lock(&mgr->payload_lock);
        ret = find_first_zero_bit(&mgr->payload_mask, mgr->max_payloads + 1);
@@ -692,8 +692,16 @@ static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr,
                goto out_unlock;
        }
 
+       vcpi_ret = find_first_zero_bit(&mgr->vcpi_mask, mgr->max_payloads + 1);
+       if (vcpi_ret > mgr->max_payloads) {
+               ret = -EINVAL;
+               DRM_DEBUG_KMS("out of vcpi ids %d\n", ret);
+               goto out_unlock;
+       }
+
        set_bit(ret, &mgr->payload_mask);
-       vcpi->vcpi = ret;
+       set_bit(vcpi_ret, &mgr->vcpi_mask);
+       vcpi->vcpi = vcpi_ret + 1;
        mgr->proposed_vcpis[ret - 1] = vcpi;
 out_unlock:
        mutex_unlock(&mgr->payload_lock);
@@ -701,15 +709,23 @@ out_unlock:
 }
 
 static void drm_dp_mst_put_payload_id(struct drm_dp_mst_topology_mgr *mgr,
-                                     int id)
+                                     int vcpi)
 {
-       if (id == 0)
+       int i;
+       if (vcpi == 0)
                return;
 
        mutex_lock(&mgr->payload_lock);
-       DRM_DEBUG_KMS("putting payload %d\n", id);
-       clear_bit(id, &mgr->payload_mask);
-       mgr->proposed_vcpis[id - 1] = NULL;
+       DRM_DEBUG_KMS("putting payload %d\n", vcpi);
+       clear_bit(vcpi - 1, &mgr->vcpi_mask);
+
+       for (i = 0; i < mgr->max_payloads; i++) {
+               if (mgr->proposed_vcpis[i])
+                       if (mgr->proposed_vcpis[i]->vcpi == vcpi) {
+                               mgr->proposed_vcpis[i] = NULL;
+                               clear_bit(i + 1, &mgr->payload_mask);
+                       }
+       }
        mutex_unlock(&mgr->payload_lock);
 }
 
@@ -1564,7 +1580,7 @@ static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr,
        }
 
        drm_dp_dpcd_write_payload(mgr, id, payload);
-       payload->payload_state = 0;
+       payload->payload_state = DP_PAYLOAD_DELETE_LOCAL;
        return 0;
 }
 
@@ -1591,7 +1607,7 @@ static int drm_dp_destroy_payload_step2(struct drm_dp_mst_topology_mgr *mgr,
  */
 int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
 {
-       int i;
+       int i, j;
        int cur_slots = 1;
        struct drm_dp_payload req_payload;
        struct drm_dp_mst_port *port;
@@ -1608,26 +1624,46 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
                        port = NULL;
                        req_payload.num_slots = 0;
                }
+
+               if (mgr->payloads[i].start_slot != req_payload.start_slot) {
+                       mgr->payloads[i].start_slot = req_payload.start_slot;
+               }
                /* work out what is required to happen with this payload */
-               if (mgr->payloads[i].start_slot != req_payload.start_slot ||
-                   mgr->payloads[i].num_slots != req_payload.num_slots) {
+               if (mgr->payloads[i].num_slots != req_payload.num_slots) {
 
                        /* need to push an update for this payload */
                        if (req_payload.num_slots) {
-                               drm_dp_create_payload_step1(mgr, i + 1, &req_payload);
+                               drm_dp_create_payload_step1(mgr, mgr->proposed_vcpis[i]->vcpi, &req_payload);
                                mgr->payloads[i].num_slots = req_payload.num_slots;
                        } else if (mgr->payloads[i].num_slots) {
                                mgr->payloads[i].num_slots = 0;
-                               drm_dp_destroy_payload_step1(mgr, port, i + 1, &mgr->payloads[i]);
+                               drm_dp_destroy_payload_step1(mgr, port, port->vcpi.vcpi, &mgr->payloads[i]);
                                req_payload.payload_state = mgr->payloads[i].payload_state;
-                       } else
-                               req_payload.payload_state = 0;
-
-                       mgr->payloads[i].start_slot = req_payload.start_slot;
+                               mgr->payloads[i].start_slot = 0;
+                       }
                        mgr->payloads[i].payload_state = req_payload.payload_state;
                }
                cur_slots += req_payload.num_slots;
        }
+
+       for (i = 0; i < mgr->max_payloads; i++) {
+               if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) {
+                       DRM_DEBUG_KMS("removing payload %d\n", i);
+                       for (j = i; j < mgr->max_payloads - 1; j++) {
+                               memcpy(&mgr->payloads[j], &mgr->payloads[j + 1], sizeof(struct drm_dp_payload));
+                               mgr->proposed_vcpis[j] = mgr->proposed_vcpis[j + 1];
+                               if (mgr->proposed_vcpis[j] && mgr->proposed_vcpis[j]->num_slots) {
+                                       set_bit(j + 1, &mgr->payload_mask);
+                               } else {
+                                       clear_bit(j + 1, &mgr->payload_mask);
+                               }
+                       }
+                       memset(&mgr->payloads[mgr->max_payloads - 1], 0, sizeof(struct drm_dp_payload));
+                       mgr->proposed_vcpis[mgr->max_payloads - 1] = NULL;
+                       clear_bit(mgr->max_payloads, &mgr->payload_mask);
+
+               }
+       }
        mutex_unlock(&mgr->payload_lock);
 
        return 0;
@@ -1658,9 +1694,9 @@ int drm_dp_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr)
 
                DRM_DEBUG_KMS("payload %d %d\n", i, mgr->payloads[i].payload_state);
                if (mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL) {
-                       ret = drm_dp_create_payload_step2(mgr, port, i + 1, &mgr->payloads[i]);
+                       ret = drm_dp_create_payload_step2(mgr, port, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]);
                } else if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) {
-                       ret = drm_dp_destroy_payload_step2(mgr, i + 1, &mgr->payloads[i]);
+                       ret = drm_dp_destroy_payload_step2(mgr, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]);
                }
                if (ret) {
                        mutex_unlock(&mgr->payload_lock);
@@ -1862,6 +1898,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
                memset(mgr->payloads, 0, mgr->max_payloads * sizeof(struct drm_dp_payload));
                mgr->payload_mask = 0;
                set_bit(0, &mgr->payload_mask);
+               mgr->vcpi_mask = 0;
        }
 
 out_unlock:
@@ -2476,7 +2513,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
        mutex_unlock(&mgr->lock);
 
        mutex_lock(&mgr->payload_lock);
-       seq_printf(m, "vcpi: %lx\n", mgr->payload_mask);
+       seq_printf(m, "vcpi: %lx %lx\n", mgr->payload_mask, mgr->vcpi_mask);
 
        for (i = 0; i < mgr->max_payloads; i++) {
                if (mgr->proposed_vcpis[i]) {