Forráskód Böngészése

msm: camera: cdm: handle dead lock scenario

This change handles a race condition in which cdm workqueue is
scheduled on one of the cores and cdm flush is executing on
another core. We come across a dead lock between fifo_lock and
hw_mutex lock.

CRs-Fixed: 3049531
Change-Id: Ie0b8982a7e55218fc5655f8e3d08a952fd852ed7
Signed-off-by: Vikram Sharma <[email protected]>
Vikram Sharma 3 éve
szülő
commit
0f54afd904

+ 0 - 5
drivers/cam_cdm/cam_cdm_core_common.c

@@ -180,12 +180,10 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw,
 			(struct cam_cdm_bl_cb_request_entry *)data;
 
 		client_idx = CAM_CDM_GET_CLIENT_IDX(node->client_hdl);
-		mutex_lock(&cdm_hw->hw_mutex);
 		client = core->clients[client_idx];
 		if ((!client) || (client->handle != node->client_hdl)) {
 			CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client,
 				node->client_hdl);
-			mutex_unlock(&cdm_hw->hw_mutex);
 			return;
 		}
 		cam_cdm_get_client_refcount(client);
@@ -204,7 +202,6 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw,
 		}
 		mutex_unlock(&client->lock);
 		cam_cdm_put_client_refcount(client);
-		mutex_unlock(&cdm_hw->hw_mutex);
 		return;
 	} else if (status == CAM_CDM_CB_STATUS_HW_RESET_DONE ||
 			status == CAM_CDM_CB_STATUS_HW_FLUSH ||
@@ -242,7 +239,6 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw,
 
 	for (i = 0; i < CAM_PER_CDM_MAX_REGISTERED_CLIENTS; i++) {
 		if (core->clients[i] != NULL) {
-			mutex_lock(&cdm_hw->hw_mutex);
 			client = core->clients[i];
 			cam_cdm_get_client_refcount(client);
 			mutex_lock(&client->lock);
@@ -265,7 +261,6 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw,
 			}
 			mutex_unlock(&client->lock);
 			cam_cdm_put_client_refcount(client);
-			mutex_unlock(&cdm_hw->hw_mutex);
 		}
 	}
 }

+ 6 - 1
drivers/cam_cdm/cam_cdm_hw_core.c

@@ -1234,6 +1234,7 @@ static void cam_hw_cdm_work(struct work_struct *work)
 			return;
 		}
 
+		mutex_lock(&cdm_hw->hw_mutex);
 		mutex_lock(&core->bl_fifo[fifo_idx].fifo_lock);
 
 		if (atomic_read(&core->bl_fifo[fifo_idx].work_record))
@@ -1247,6 +1248,7 @@ static void cam_hw_cdm_work(struct work_struct *work)
 				core->arbitration);
 			mutex_unlock(&core->bl_fifo[fifo_idx]
 					.fifo_lock);
+			mutex_unlock(&cdm_hw->hw_mutex);
 			return;
 		}
 
@@ -1285,6 +1287,7 @@ static void cam_hw_cdm_work(struct work_struct *work)
 		}
 		mutex_unlock(&core->bl_fifo[payload->fifo_idx]
 			.fifo_lock);
+		mutex_unlock(&cdm_hw->hw_mutex);
 	}
 
 	if (payload->irq_status &
@@ -1398,9 +1401,9 @@ handle_cdm_pf:
 				cdm_hw->soc_info.index);
 		for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++)
 			mutex_unlock(&core->bl_fifo[i].fifo_lock);
-		mutex_unlock(&cdm_hw->hw_mutex);
 		cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_PAGEFAULT,
 			(void *)pf_info->iova);
+		mutex_unlock(&cdm_hw->hw_mutex);
 		clear_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status);
 	} else {
 		CAM_ERR(CAM_CDM, "Invalid token");
@@ -1805,9 +1808,11 @@ int cam_hw_cdm_handle_error_info(
 
 	if (node != NULL) {
 		if (node->request_type == CAM_HW_CDM_BL_CB_CLIENT) {
+			mutex_lock(&cdm_hw->hw_mutex);
 			cam_cdm_notify_clients(cdm_hw,
 					CAM_CDM_CB_STATUS_HW_ERROR,
 					(void *)node);
+			mutex_unlock(&cdm_hw->hw_mutex);
 		} else if (node->request_type == CAM_HW_CDM_BL_CB_INTERNAL) {
 			CAM_ERR(CAM_CDM, "Invalid node=%pK %d", node,
 					node->request_type);