Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e30b6d7d authored by Harsh Shah's avatar Harsh Shah Committed by Karthik Anantha Ram
Browse files

msm: camera: crm: Unlink devices before clearing the link



There can be a potential deadlock - unlink waits on context
lock, context waits to finish config_dev, config_dev is waiting
for link lock to add request. By calling unlink outside the
lock will resolve this deadlock. It also solves the problem of
workq being freed before unlink in case there is no lock for
unlink.

Change-Id: Ia4e911fd32c6b32b368acf620b5ccbb84dd0cb85
Signed-off-by: default avatarHarsh Shah <harshs@codeaurora.org>
Signed-off-by: default avatarKarthik Anantha Ram <kartanan@codeaurora.org>
parent 0b3ab13b
Loading
Loading
Loading
Loading
+37 −77
Original line number Diff line number Diff line
@@ -60,52 +60,6 @@ static int __cam_req_mgr_setup_payload(struct cam_req_mgr_core_workq *workq)
	return rc;
}

/**
 * __cam_req_mgr_reset_req_tbl()
 *
 * @brief : Initialize req table data
 * @in_q  : request queue pointer
 *
 * @return: 0 for success, negative for failure
 *
 */
static int __cam_req_mgr_print_req_tbl(struct cam_req_mgr_req_data *req)
{
	int                           rc = 0;
	int32_t                       i = 0;
	struct cam_req_mgr_req_queue *in_q = req->in_q;
	struct cam_req_mgr_req_tbl   *req_tbl = req->l_tbl;

	if (!in_q || !req_tbl) {
		CAM_WARN(CAM_CRM, "NULL pointer %pK %pK", in_q, req_tbl);
		return -EINVAL;
	}
	CAM_DBG(CAM_CRM, "in_q %pK %pK %d", in_q, req_tbl, req_tbl->num_slots);
	mutex_lock(&req->lock);
	for (i = 0; i < in_q->num_slots; i++) {
		CAM_DBG(CAM_CRM, "IN_Q %d: idx %d, red_id %lld", i,
			in_q->slot[i].idx, CRM_GET_REQ_ID(in_q, i));
	}

	while (req_tbl != NULL) {
		for (i = 0; i < req_tbl->num_slots; i++) {
			CAM_DBG(CAM_CRM, "idx= %d, map= %x, state= %d",
				req_tbl->slot[i].idx,
				req_tbl->slot[i].req_ready_map,
				req_tbl->slot[i].state);
		}
		CAM_DBG(CAM_CRM,
			"TBL:id= %d, pd=%d cnt=%d mask=%x skip=%d num_slt= %d",
			req_tbl->id, req_tbl->pd, req_tbl->dev_count,
			req_tbl->dev_mask, req_tbl->skip_traverse,
			req_tbl->num_slots);
		req_tbl = req_tbl->next;
	}
	mutex_unlock(&req->lock);

	return rc;
}

/**
 * __cam_req_mgr_find_pd_tbl()
 *
@@ -1256,12 +1210,12 @@ static void __cam_req_mgr_destroy_subdev(
/**
 * __cam_req_mgr_destroy_link_info()
 *
 * @brief    : Cleans up the mem allocated while linking
 * @link     : pointer to link, mem associated with this link is freed
 * @brief    : Unlinks all devices on the link
 * @link     : pointer to link
 *
 * @return   : returns if unlink for any device was success or failure
 */
static int __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
static int __cam_req_mgr_disconnect_link(struct cam_req_mgr_core_link *link)
{
	int32_t                                 i = 0;
	struct cam_req_mgr_connected_device    *dev;
@@ -1276,7 +1230,9 @@ static int __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
	/* Using device ops unlink devices */
	for (i = 0; i < link->num_devs; i++) {
		dev = &link->l_dev[i];
		if (dev != NULL) {
		if (dev == NULL)
			continue;

		link_data.dev_hdl = dev->dev_hdl;
		if (dev->ops && dev->ops->link_setup) {
			rc = dev->ops->link_setup(&link_data);
@@ -1290,7 +1246,18 @@ static int __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
		dev->parent = NULL;
		dev->ops = NULL;
	}

	return rc;
}

/**
 * __cam_req_mgr_destroy_link_info()
 *
 * @brief    : Cleans up the mem allocated while linking
 * @link     : pointer to link, mem associated with this link is freed
 */
static void __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
{
	__cam_req_mgr_destroy_all_tbl(&link->req.l_tbl);
	__cam_req_mgr_reset_in_q(&link->req);
	link->req.num_tbl = 0;
@@ -1299,8 +1266,6 @@ static int __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
	link->pd_mask = 0;
	link->num_devs = 0;
	link->max_delay = 0;

	return rc;
}

/**
@@ -2320,27 +2285,24 @@ static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link)
{
	int rc;

	mutex_lock(&link->lock);
	spin_lock_bh(&link->link_state_spin_lock);
	link->state = CAM_CRM_LINK_STATE_IDLE;
	spin_unlock_bh(&link->link_state_spin_lock);

	rc = __cam_req_mgr_disconnect_link(link);
	if (rc)
		CAM_ERR(CAM_CORE,
			"Unlink for all devices was not successful");

	mutex_lock(&link->lock);
	/* Destroy timer of link */
	crm_timer_exit(&link->watchdog);
	spin_unlock_bh(&link->link_state_spin_lock);
	__cam_req_mgr_print_req_tbl(&link->req);

	/* Destroy workq payload data */
	kfree(link->workq->task.pool[0].payload);
	link->workq->task.pool[0].payload = NULL;

	/* Destroy workq of link */
	cam_req_mgr_workq_destroy(&link->workq);

	/* Cleanup request tables and unlink devices */
	rc = __cam_req_mgr_destroy_link_info(link);
	if (rc)
		CAM_ERR(CAM_CORE,
			"Unlink for all devices was not successful");
	__cam_req_mgr_destroy_link_info(link);

	/* Free memory holding data of linked devs */
	__cam_req_mgr_destroy_subdev(link->l_dev);
@@ -2378,7 +2340,6 @@ int cam_req_mgr_destroy_session(
		goto end;

	}
	mutex_lock(&cam_session->lock);
	if (cam_session->num_links) {
		CAM_DBG(CAM_CRM, "destroy session %x num_active_links %d",
			ses_info->session_hdl,
@@ -2396,7 +2357,6 @@ int cam_req_mgr_destroy_session(
		}
	}
	list_del(&cam_session->entry);
	mutex_unlock(&cam_session->lock);
	mutex_destroy(&cam_session->lock);
	kfree(cam_session);

+6 −1
Original line number Diff line number Diff line
@@ -262,8 +262,13 @@ void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **crm_workq)
			(*crm_workq)->job = NULL;
			WORKQ_RELEASE_LOCK(*crm_workq, flags);
			destroy_workqueue(job);
		} else
		} else {
			WORKQ_RELEASE_LOCK(*crm_workq, flags);
		}

		/* Destroy workq payload data */
		kfree((*crm_workq)->task.pool[0].payload);
		(*crm_workq)->task.pool[0].payload = NULL;
		kfree((*crm_workq)->task.pool);
		kfree(*crm_workq);
		*crm_workq = NULL;