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

Commit 0db96286 authored by Mangalaram ARCHANA's avatar Mangalaram ARCHANA Committed by Gerrit - the friendly Code Review server
Browse files

msm: camera: icp: Enqueue the abort cmd in workq



The request frame cmds are submitted to the FW in workq context.
The abort cmd as part of flush is triggered in user thread context.
This change will enqueue the abort as part of flush to FW in workq,
thereby ensuring that if there are any pending frames they are
submitted prior to the abort cmd.

Change-Id: Ia5686e79fff49d9a623845fe17c9b21a6c38580b
Signed-off-by: default avatarMangalaram ARCHANA <mangar@codeaurora.org>
parent 6dd66723
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -642,6 +642,7 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx)
			ctx->dev_name, ctx->ctx_id);

	flush_args.num_req_pending = 0;
	flush_args.last_flush_req = ctx->last_flush_req;
	while (true) {
		spin_lock(&ctx->lock);
		if (list_empty(&temp_list)) {
+3 −0
Original line number Diff line number Diff line
@@ -235,6 +235,8 @@ struct cam_hw_config_args {
 * @num_req_active:        Num request to flush, valid when flush type is REQ
 * @flush_req_active:      Request active pointers to flush
 * @flush_type:            The flush type
 * @last_flush_req:        last flush req_id notified to hw_mgr for the
 *                         given stream
 *
 */
struct cam_hw_flush_args {
@@ -244,6 +246,7 @@ struct cam_hw_flush_args {
	uint32_t                        num_req_active;
	void                           *flush_req_active[20];
	enum flush_type_t               flush_type;
	uint32_t                        last_flush_req;
};

/**
+133 −4
Original line number Diff line number Diff line
@@ -2672,11 +2672,93 @@ static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr)
		hw_mgr->a5_jtag_debug);
}

static int cam_icp_retry_wait_for_abort(
	struct cam_icp_hw_ctx_data *ctx_data)
{
	int retry_cnt = 1;
	unsigned long rem_jiffies;
	int timeout = 1000;

	CAM_WARN(CAM_ICP, "FW timeout in abort ctx: %u retry_left: %d",
		ctx_data->ctx_id, retry_cnt);
	while (retry_cnt > 0) {
		rem_jiffies = wait_for_completion_timeout(
			&ctx_data->wait_complete,
			msecs_to_jiffies((timeout)));
		if (!rem_jiffies) {
			retry_cnt--;
			if (retry_cnt > 0) {
				CAM_WARN(CAM_ICP,
					"FW timeout in abort ctx: %u retry_left: %u",
					ctx_data->ctx_id, retry_cnt);
				continue;
			}
		}

		if (retry_cnt > 0)
			return 0;
	}

	return -ETIMEDOUT;
}

static int cam_icp_mgr_abort_handle_wq(
	void *priv, void *data)
{
	int rc;
	size_t packet_size;
	struct hfi_cmd_work_data   *task_data = NULL;
	struct cam_icp_hw_ctx_data *ctx_data;
	struct hfi_cmd_ipebps_async *abort_cmd;

	if (!data || !priv) {
		CAM_ERR(CAM_ICP, "Invalid params %pK %pK", data, priv);
		return -EINVAL;
	}

	task_data = (struct hfi_cmd_work_data *)data;
	ctx_data =
		(struct cam_icp_hw_ctx_data *)task_data->data;
	packet_size =
		sizeof(struct hfi_cmd_ipebps_async) +
		sizeof(struct hfi_cmd_abort) -
		sizeof(((struct hfi_cmd_ipebps_async *)0)->payload.direct);
	abort_cmd = kzalloc(packet_size, GFP_KERNEL);
	CAM_DBG(CAM_ICP, "abort pkt size = %d", (int) packet_size);
	if (!abort_cmd) {
		rc = -ENOMEM;
		return rc;
	}

	abort_cmd->size = packet_size;
	abort_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT;
	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
		abort_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_ABORT;
	else
		abort_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_ABORT;

	abort_cmd->num_fw_handles = 1;
	abort_cmd->fw_handles[0] = ctx_data->fw_handle;
	abort_cmd->user_data1 = PTR_TO_U64(ctx_data);
	abort_cmd->user_data2 = (uint64_t)0x0;

	rc = hfi_write_cmd(abort_cmd);
	if (rc) {
		kfree(abort_cmd);
		return rc;
	}
	CAM_DBG(CAM_ICP, "fw_handle = %x ctx_data = %pK ctx_id %d",
		ctx_data->fw_handle, ctx_data, ctx_data->ctx_id);

	kfree(abort_cmd);
	return rc;
}

static int cam_icp_mgr_abort_handle(
	struct cam_icp_hw_ctx_data *ctx_data)
{
	int rc = 0;
	unsigned long rem_jiffies;
	unsigned long rem_jiffies = 0;
	size_t packet_size;
	int timeout = 1000;
	struct hfi_cmd_ipebps_async *abort_cmd;
@@ -2808,6 +2890,7 @@ static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id)

	hw_mgr->ctx_data[ctx_id].fw_handle = 0;
	hw_mgr->ctx_data[ctx_id].scratch_mem_size = 0;
	hw_mgr->ctx_data[ctx_id].last_flush_req = 0;
	for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
		clear_bit(i, hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
	kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
@@ -3415,6 +3498,10 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args)
			CAM_ERR(CAM_ICP, "Fail to send reconfig io cmd");
	}

	if (req_id <= ctx_data->last_flush_req)
		CAM_WARN(CAM_ICP,
			"Anomaly submitting flushed req %llu [last_flush %llu] in ctx %u",
			req_id, ctx_data->last_flush_req, ctx_data->ctx_id);
	rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args);
	if (rc)
		goto config_err;
@@ -4433,6 +4520,46 @@ static int cam_icp_mgr_flush_req(struct cam_icp_hw_ctx_data *ctx_data,
	return 0;
}

static int cam_icp_mgr_enqueue_abort(
	struct cam_icp_hw_ctx_data *ctx_data)
{
	int timeout = 1000, rc;
	unsigned long rem_jiffies = 0;
	struct hfi_cmd_work_data *task_data;
	struct crm_workq_task *task;

	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
	if (!task) {
		CAM_ERR(CAM_ICP, "no empty task");
		return -ENOMEM;
	}

	reinit_completion(&ctx_data->wait_complete);
	task_data = (struct hfi_cmd_work_data *)task->payload;
	task_data->data = (void *)ctx_data;
	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
	task->process_cb = cam_icp_mgr_abort_handle_wq;
	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
		CRM_TASK_PRIORITY_0);

	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
		msecs_to_jiffies((timeout)));
	if (!rem_jiffies) {
		rc = cam_icp_retry_wait_for_abort(ctx_data);
		if (rc) {
			CAM_ERR(CAM_ICP,
				"FW timeout/err in abort handle command ctx: %u",
				ctx_data->ctx_id);
			cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl);
			cam_hfi_queue_dump();
			return rc;
		}
	}

	CAM_DBG(CAM_ICP, "Abort after flush is success");
	return 0;
}

static int cam_icp_mgr_hw_dump(void *hw_priv, void *hw_dump_args)
{
	struct cam_hw_dump_args *dump_args = hw_dump_args;
@@ -4550,8 +4677,10 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args)
		return -EINVAL;
	}

	CAM_DBG(CAM_REQ, "ctx_id %d Flush type %d",
		ctx_data->ctx_id, flush_args->flush_type);
	ctx_data->last_flush_req = flush_args->last_flush_req;
	CAM_DBG(CAM_REQ, "ctx_id %d Flush type %d last_flush_req %u",
		ctx_data->ctx_id, flush_args->flush_type,
		ctx_data->last_flush_req);

	switch (flush_args->flush_type) {
	case CAM_FLUSH_TYPE_ALL:
@@ -4559,7 +4688,7 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args)
		if (!atomic_read(&hw_mgr->recovery)
			&& flush_args->num_req_active) {
			mutex_unlock(&hw_mgr->hw_mgr_mutex);
			cam_icp_mgr_abort_handle(ctx_data);
			cam_icp_mgr_enqueue_abort(ctx_data);
		} else {
			mutex_unlock(&hw_mgr->hw_mgr_mutex);
		}
+3 −1
Original line number Diff line number Diff line
/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -219,6 +219,7 @@ struct cam_ctx_clk_info {
 * @watch_dog: watchdog timer handle
 * @watch_dog_reset_counter: Counter for watch dog reset
 * @icp_dev_io_info: io config resource
 * @last_flush_req: last flush req for this ctx
 */
struct cam_icp_hw_ctx_data {
	void *context_priv;
@@ -239,6 +240,7 @@ struct cam_icp_hw_ctx_data {
	struct cam_req_mgr_timer *watch_dog;
	uint32_t watch_dog_reset_counter;
	struct cam_icp_acquire_dev_info icp_dev_io_info;
	uint64_t last_flush_req;
};

/**
+3 −2
Original line number Diff line number Diff line
/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -410,8 +410,9 @@ static uint32_t cam_smmu_find_closest_mapping(int idx, void *vaddr)
	if (closest_mapping) {
		buf_handle = GET_MEM_HANDLE(idx, closest_mapping->ion_fd);
		CAM_INFO(CAM_SMMU,
			"Closest map fd %d 0x%lx 0x%lx-0x%lx buf=%pK mem %0x",
			"Closest map fd %d 0x%lx %llu-%llu 0x%lx-0x%lx buf=%pK mem %0x",
			closest_mapping->ion_fd, current_addr,
			mapping->len, closest_mapping->len,
			(unsigned long)closest_mapping->paddr,
			(unsigned long)closest_mapping->paddr + mapping->len,
			closest_mapping->buf,