Browse Source

disp: msm: dp: synchronize debug and aux common buffer handling

DP debug module is run by external script for automation testing.
DP aux and debug modules operate on shared buffers. In some race
conditions, aux and debug module can go out of sync resulting in
automation failures. Lock the buffers to make sure there are no
race conditions.

Change-Id: If0ae370c22cf035f3177666bd714221d6b3cd56e
Signed-off-by: Ajay Singh Parmar <[email protected]>
Ajay Singh Parmar 6 years ago
parent
commit
4ca56193c5
3 changed files with 40 additions and 46 deletions
  1. 21 21
      msm/dp/dp_aux.c
  2. 2 0
      msm/dp/dp_aux.h
  3. 17 25
      msm/dp/dp_debug.c

+ 21 - 21
msm/dp/dp_aux.c

@@ -495,35 +495,33 @@ static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux,
 	}
 
 	if (aux->native) {
+		mutex_lock(aux->dp_aux.access_lock);
 		aux->dp_aux.reg = msg->address;
 		aux->dp_aux.read = aux->read;
 		aux->dp_aux.size = msg->size;
 
-		reinit_completion(&aux->comp);
+		if (!aux->read)
+			memcpy(aux->dpcd + msg->address,
+				msg->buffer, msg->size);
 
-		if (aux->read) {
-			timeout = wait_for_completion_timeout(&aux->comp, HZ);
-			if (!timeout) {
-				DP_ERR("read timeout: 0x%x\n", msg->address);
-				atomic_set(&aux->aborted, 1);
-				ret = -ETIMEDOUT;
-				goto end;
-			}
+		reinit_completion(&aux->comp);
+		mutex_unlock(aux->dp_aux.access_lock);
+
+		timeout = wait_for_completion_timeout(&aux->comp, HZ * 2);
+		if (!timeout) {
+			DP_ERR("%s timeout: 0x%x\n",
+				aux->read ? "read" : "write",
+				msg->address);
+			atomic_set(&aux->aborted, 1);
+			ret = -ETIMEDOUT;
+			goto end;
+		}
 
+		mutex_lock(aux->dp_aux.access_lock);
+		if (aux->read)
 			memcpy(msg->buffer, aux->dpcd + msg->address,
 				msg->size);
-		} else {
-			memcpy(aux->dpcd + msg->address, msg->buffer,
-				msg->size);
-
-			timeout = wait_for_completion_timeout(&aux->comp, HZ);
-			if (!timeout) {
-				DP_ERR("write timeout: 0x%x\n", msg->address);
-				atomic_set(&aux->aborted, 1);
-				ret = -ETIMEDOUT;
-				goto end;
-			}
-		}
+		mutex_unlock(aux->dp_aux.access_lock);
 
 		aux->aux_error_num = DP_AUX_ERR_NONE;
 	} else {
@@ -725,6 +723,8 @@ static void dp_aux_dpcd_updated(struct dp_aux *dp_aux)
 
 	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
 
+	/* make sure wait has started */
+	usleep_range(20, 30);
 	complete(&aux->comp);
 }
 

+ 2 - 0
msm/dp/dp_aux.h

@@ -40,6 +40,8 @@ struct dp_aux {
 
 	bool read;
 
+	struct mutex *access_lock;
+
 	struct drm_dp_aux *drm_aux;
 	int (*drm_aux_register)(struct dp_aux *aux);
 	void (*drm_aux_deregister)(struct dp_aux *aux);

+ 17 - 25
msm/dp/dp_debug.c

@@ -178,7 +178,6 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
 	ssize_t rc = count;
 	char offset_ch[5];
 	u32 offset, data_len;
-	u32 extended_capability_bytes = 0;
 	const u32 dp_receiver_cap_size = 16;
 
 	if (!debug)
@@ -252,25 +251,9 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
 bail:
 	kfree(buf);
 
-	/*
-	 * If extension bit is set then increase the length
-	 * of user input to account for the extra bytes
-	 */
-	if (dpcd && (dpcd_buf_index > DP_RECEIVER_CAP_SIZE) &&
-			(dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
-			 DP_EXT_REC_CAP_FIELD))
-		extended_capability_bytes = 4;
-
-	/*
-	 * Reset panel's dpcd in case of any failure. Also, set the
-	 * panel's dpcd only if a full dpcd is provided with offset as 0.
-	 */
-	if (!dpcd || (!offset &&
-			(data_len == (dp_receiver_cap_size +
-			extended_capability_bytes))) ||
-			(offset == 0xffff)) {
+	if (!dpcd || (size / char_to_nib) >= dp_receiver_cap_size ||
+	    offset == 0xffff) {
 		debug->panel->set_dpcd(debug->panel, dpcd);
-
 		/*
 		 * print dpcd status as this code is executed
 		 * only while running in debug mode which is manually
@@ -280,10 +263,11 @@ bail:
 			DP_INFO("[%s]\n", "CLEAR");
 		else
 			DP_INFO("[%s]\n", "SET");
-	} else
-		debug->aux->dpcd_updated(debug->aux);
+	}
 
 	mutex_unlock(&debug->lock);
+
+	debug->aux->dpcd_updated(debug->aux);
 	return rc;
 }
 
@@ -295,16 +279,18 @@ static ssize_t dp_debug_read_dpcd(struct file *file,
 	int const buf_size = SZ_4K;
 	u32 offset = 0;
 	u32 len = 0;
+	bool notify = false;
 
 	if (!debug || !debug->aux || !debug->dpcd)
 		return -ENODEV;
 
+	mutex_lock(&debug->lock);
 	if (*ppos)
-		return 0;
+		goto end;
 
 	buf = kzalloc(buf_size, GFP_KERNEL);
 	if (!buf)
-		return -ENOMEM;
+		goto end;
 
 	len += snprintf(buf, buf_size, "0x%x", debug->aux->reg);
 
@@ -318,8 +304,7 @@ static ssize_t dp_debug_read_dpcd(struct file *file,
 				debug->dpcd[debug->aux->reg + offset++]);
 		}
 
-		if (debug->dp_debug.sim_mode && debug->aux->dpcd_updated)
-			debug->aux->dpcd_updated(debug->aux);
+		notify = true;
 	}
 
 	len = min_t(size_t, count, len);
@@ -327,6 +312,12 @@ static ssize_t dp_debug_read_dpcd(struct file *file,
 		*ppos += len;
 
 	kfree(buf);
+end:
+	mutex_unlock(&debug->lock);
+
+	if (notify)
+		debug->aux->dpcd_updated(debug->aux);
+
 	return len;
 }
 
@@ -2274,6 +2265,7 @@ struct dp_debug *dp_debug_get(struct dp_debug_in *in)
 		goto error;
 	}
 
+	debug->aux->access_lock = &debug->lock;
 	dp_debug->get_edid = dp_debug_get_edid;
 	dp_debug->abort = dp_debug_abort;