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

Commit 220b8c97 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: vidc: Refactor power collapse"

parents 944f111f 87090592
Loading
Loading
Loading
Loading
+0 −14
Original line number Diff line number Diff line
@@ -1533,17 +1533,6 @@ static int hfi_process_sys_property_info(u32 device_id,

}

static int hfi_process_sys_pc_prep_done(u32 device_id,
		struct vidc_hal_msg_pkt_hdr *msg_hdr,
		struct msm_vidc_cb_info *info)
{
	*info = (struct msm_vidc_cb_info) {
		.response_type =  HAL_SYS_PC_PREP_DONE,
	};

	return 0;
}

static int hfi_process_ignore(u32 device_id,
		struct vidc_hal_msg_pkt_hdr *msg_hdr,
		struct msm_vidc_cb_info *info)
@@ -1620,9 +1609,6 @@ int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr,
	case HFI_MSG_SYS_SESSION_ABORT_DONE:
		pkt_func = (pkt_func_def)hfi_process_session_abort_done;
		break;
	case HFI_MSG_SYS_PC_PREP_DONE:
		pkt_func = (pkt_func_def)hfi_process_sys_pc_prep_done;
		break;
	case HFI_MSG_SESSION_SYNC_DONE:
		pkt_func = (pkt_func_def)hfi_process_ignore;
		break;
+66 −101
Original line number Diff line number Diff line
@@ -925,7 +925,6 @@ err_create_pkt:
	return rc;
}

static DECLARE_COMPLETION(pc_prep_done);
static DECLARE_COMPLETION(release_resources_done);

static int __alloc_imem(struct venus_hfi_device *device, unsigned long size)
@@ -1431,8 +1430,6 @@ static int __iface_cmdq_write_relaxed(struct venus_hfi_device *device,
		}

		if (device->res->sw_power_collapsible) {
			dprintk(VIDC_DBG,
				"Cancel and queue delayed work again\n");
			cancel_delayed_work(&venus_hfi_pm_work);
			if (!queue_delayed_work(device->venus_pm_workq,
				&venus_hfi_pm_work,
@@ -3005,8 +3002,6 @@ static int __prepare_pc(struct venus_hfi_device *device)
	int rc = 0;
	struct hfi_cmd_sys_pc_prep_packet pkt;

	init_completion(&pc_prep_done);

	rc = call_hfi_pkt_op(device, sys_pc_prep, &pkt);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to create sys pc prep pkt\n");
@@ -3015,27 +3010,8 @@ static int __prepare_pc(struct venus_hfi_device *device)

	if (__iface_cmdq_write(device, &pkt))
		rc = -ENOTEMPTY;
	if (rc) {
	if (rc)
		dprintk(VIDC_ERR, "Failed to prepare venus for power off");
		goto err_pc_prep;
	}

	WARN_ON(!mutex_is_locked(&device->lock));
	mutex_unlock(&device->lock);
	rc = wait_for_completion_timeout(&pc_prep_done,
			msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
	mutex_lock(&device->lock);
	if (!rc) {
		dprintk(VIDC_ERR,
				"Wait interrupted or timeout for PC_PREP_DONE: %d\n",
				rc);
		__flush_debug_queue(device, NULL);
		BUG_ON(msm_vidc_debug_timeout);
		rc = -EIO;
		goto err_pc_prep;
	}

	rc = 0;
err_pc_prep:
	return rc;
}
@@ -3043,9 +3019,9 @@ err_pc_prep:
static void venus_hfi_pm_handler(struct work_struct *work)
{
	int rc = 0;
	u32 ctrl_status = 0;
	u32 wfi_status = 0, idle_status = 0, pc_ready = 0;
	int count = 0;
	const int max_tries = 10;
	const int max_tries = 5;
	struct venus_hfi_device *device = list_first_entry(
			&hal_ctxt.dev_head, struct venus_hfi_device, list);
	if (!device) {
@@ -3053,6 +3029,16 @@ static void venus_hfi_pm_handler(struct work_struct *work)
		return;
	}

	/*
	 * It is ok to check this variable outside the lock since
	 * it is being updated in this context only
	 */
	if (device->skip_pc_count >= VIDC_MAX_PC_SKIP_COUNT) {
		dprintk(VIDC_WARN, "Failed to PC for %d times\n",
				device->skip_pc_count);
		__process_fatal_error(device);
		return;
	}
	mutex_lock(&device->lock);
	if (!device->power_enabled) {
		dprintk(VIDC_DBG, "%s: Power already disabled\n",
@@ -3066,74 +3052,63 @@ static void venus_hfi_pm_handler(struct work_struct *work)
				"Core is in bad state, Skipping power collapse\n");
		goto skip_power_off;
	}

	dprintk(VIDC_DBG, "Prepare for power collapse\n");

	rc = __prepare_pc(device);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to prepare for PC %d\n", rc);
		mutex_unlock(&device->lock);
		/*
		 * __process_fatal_error invokes msm_vidc layer callback
		 * function. Hence avoid holding the device->lock over the
		 * callback function.
		 */
		__process_fatal_error(device);
		return;
	}

	if (device->last_packet_type != HFI_CMD_SYS_PC_PREP) {
		dprintk(VIDC_WARN,
			"Skip PC. Reason: Last packet queued(%#x) is not PC_PREP\n",
			device->last_packet_type);
	pc_ready = __read_register(device, VIDC_CPU_CS_SCIACMDARG0) &
		VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY;
	if (!pc_ready) {
		wfi_status = __read_register(device,
				VIDC_WRAPPER_CPU_STATUS);
		idle_status = __read_register(device,
				VIDC_CPU_CS_SCIACMDARG0);
		if (!(wfi_status & BIT(0)) ||
				!(idle_status & BIT(30))) {
			dprintk(VIDC_WARN, "Skipping PC\n");
			goto skip_power_off;
		}

	if (__get_q_size(device, VIDC_IFACEQ_MSGQ_IDX) ||
		__get_q_size(device, VIDC_IFACEQ_CMDQ_IDX)) {
		dprintk(VIDC_WARN,
			"Skip PC. Reason: Cmd/Msg queue not empty\n");
		rc = __prepare_pc(device);
		if (rc) {
			dprintk(VIDC_WARN, "Failed PC %d\n", rc);
			goto skip_power_off;
		}

	while (!(ctrl_status & BIT(0)) && count < max_tries) {
		ctrl_status = __read_register(device, VIDC_WRAPPER_CPU_STATUS);
		while (count < max_tries) {
			wfi_status = __read_register(device,
					VIDC_WRAPPER_CPU_STATUS);
			pc_ready = __read_register(device,
					VIDC_CPU_CS_SCIACMDARG0);
			if ((wfi_status & BIT(0)) && (pc_ready &
				VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY))
				break;
			usleep_range(1000, 1500);
			count++;
		}

	if (!(ctrl_status & BIT(0))) {
		dprintk(VIDC_WARN,
			"Skip PC. Reason: Core is not in WFI state (%#x)\n",
			ctrl_status);
		if (count == max_tries) {
			dprintk(VIDC_ERR,
					"Skip PC. Core is not in right state (%#x, %#x)\n",
					wfi_status, pc_ready);
			goto skip_power_off;
		}
	}

	rc = __suspend(device);
	if (rc) {
	if (rc)
		dprintk(VIDC_ERR, "Failed venus power off\n");
		goto err_power_off;
	}

	/* Cancel pending delayed works if any */
	cancel_delayed_work(&venus_hfi_pm_work);
	device->skip_pc_count = 0;

	mutex_unlock(&device->lock);
	return;

err_power_off:
skip_power_off:

	/*
	* When power collapse is escaped, driver no need to inform Venus.
	* Venus is self-sufficient to come out of the power collapse at
	* any stage. Driver can skip power collapse and continue with
	* normal execution.
	*/

	/* Cancel pending delayed works if any */
	cancel_delayed_work(&venus_hfi_pm_work);

	device->skip_pc_count++;
	dprintk(VIDC_WARN, "Skip PC(%d, %#x, %#x, %#x)\n",
		device->skip_pc_count, wfi_status, idle_status, pc_ready);
	queue_delayed_work(device->venus_pm_workq,
			&venus_hfi_pm_work,
			msecs_to_jiffies(msm_vidc_pwr_collapse_delay));
exit:
	mutex_unlock(&device->lock);
	return;
@@ -3226,6 +3201,7 @@ static int __response_handler(struct venus_hfi_device *device)
	struct msm_vidc_cb_info *packets;
	int packet_count = 0;
	u8 *raw_packet = NULL;
	bool requeue_pm_work = true;

	if (!device || device->state != VENUS_STATE_INIT)
		return 0;
@@ -3291,16 +3267,6 @@ static int __response_handler(struct venus_hfi_device *device)
				dprintk(VIDC_WARN,
				"Failed to set IMEM. Performance will be impacted\n");
			break;
		case HAL_SYS_PC_PREP_DONE:
			dprintk(VIDC_DBG, "Received SYS_PC_PREP_DONE\n");
			complete(&pc_prep_done);
			/*
			 * PC_PREP_DONE should be the last packet during
			 * power collapse, so decrement the packet count
			 * to not process this pkt in callback
			 */
			--packet_count;
			break;
		case HAL_SESSION_LOAD_RESOURCE_DONE:
			/*
			 * Work around for H/W bug, need to re-program these
@@ -3382,6 +3348,15 @@ static int __response_handler(struct venus_hfi_device *device)
		}
	}

	if (requeue_pm_work && device->res->sw_power_collapsible) {
		cancel_delayed_work(&venus_hfi_pm_work);
		if (!queue_delayed_work(device->venus_pm_workq,
			&venus_hfi_pm_work,
			msecs_to_jiffies(msm_vidc_pwr_collapse_delay))) {
			dprintk(VIDC_ERR, "PM work already scheduled\n");
		}
	}

exit:
	__flush_debug_queue(device, raw_packet);

@@ -3415,16 +3390,6 @@ static void venus_hfi_core_work_handler(struct work_struct *work)
		goto err_no_work;
	}

	if (device->res->sw_power_collapsible) {
		dprintk(VIDC_DBG, "Cancel and queue delayed work again.\n");
		cancel_delayed_work(&venus_hfi_pm_work);
		if (!queue_delayed_work(device->venus_pm_workq,
			&venus_hfi_pm_work,
			msecs_to_jiffies(msm_vidc_pwr_collapse_delay))) {
			dprintk(VIDC_DBG, "PM work already scheduled\n");
		}
	}

	__core_clear_interrupt(device);
	num_responses = __response_handler(device);

+2 −1
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@
#define VIDC_IFACEQ_DFLT_QHDR				0x01010000

#define VIDC_MAX_NAME_LENGTH 64

#define VIDC_MAX_PC_SKIP_COUNT 4
struct hfi_queue_table_header {
	u32 qtbl_version;
	u32 qtbl_size;
@@ -249,6 +249,7 @@ struct venus_hfi_device {
	enum hfi_packetization_type packetization_type;
	struct msm_vidc_cb_info *response_pkt;
	struct pm_qos_request qos;
	unsigned int skip_pc_count;
};

void venus_hfi_delete_device(void *device);