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

Commit aa656834 authored by Praneeth Paladugu's avatar Praneeth Paladugu Committed by Gerrit - the friendly Code Review server
Browse files

msm: vidc: cancel power collapse before venus command



Currently power collapse thread is canceled once the command is
written into interface queues. Venus may pick up this command and
starts working. When driver queries for PC_PREP, Venus immediately
returned without canceling current tasks. This makes driver to do
PC while Venus is still working. This results in unknown behavior.
So driver needs to make sure that it cancels the PC thread before
any command to Venus. If PC thread already scheduled, cmdq write
will wait till PC finishes and do power on before giving interrupt
to Venus.

Change-Id: I7e2af9b2aea6240b52857b920f2ce0c60b2040c3
Signed-off-by: default avatarPraneeth Paladugu <ppaladug@codeaurora.org>
Signed-off-by: default avatarAshray Kulkarni <ashrayk@codeaurora.org>
parent 700e0c78
Loading
Loading
Loading
Loading
+39 −50
Original line number Diff line number Diff line
@@ -1080,6 +1080,21 @@ static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device,
		dprintk(VIDC_ERR, "Invalid Params");
		return -EINVAL;
	}

	if (device->res->sw_power_collapsible) {
		dprintk(VIDC_DBG,
			"Cancel and queue delayed work from %s\n",
			__func__);
		cancel_delayed_work_sync(&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");
		}
	}

	mutex_lock(&device->write_lock);
	result = venus_hfi_iface_cmdq_write_nolock(device, pkt);
	mutex_unlock(&device->write_lock);
@@ -1605,6 +1620,13 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device)
		return 0;

	dprintk(VIDC_DBG, "Resuming from power collapse\n");

	rc = __alloc_ocmem(device);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to allocate OCMEM");
		return -EINVAL;
	}

	rc = venus_hfi_vote_buses(device, device->bus_load.vote_data,
			device->bus_load.vote_data_count);
	if (rc) {
@@ -1675,27 +1697,10 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device)
		goto err_reset_core;
	}

	/*
	 * set the flag here to skip venus_hfi_power_on() which is
	 * being called again via __alloc_set_ocmem() if ocmem is enabled
	 */
	device->power_enabled = true;

	/*
	 * write_lock is already acquired at this point, so to avoid
	 * recursive lock in cmdq_write function, call nolock version
	 * of alloc_ocmem
	 */
	WARN_ON(!mutex_is_locked(&device->write_lock));
	rc = __alloc_set_ocmem(device, false);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to allocate OCMEM");
		goto err_alloc_ocmem;
	}

	dprintk(VIDC_INFO, "Resumed from power collapse\n");
	return rc;
err_alloc_ocmem:
err_reset_core:
	venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
err_set_video_state:
@@ -1811,18 +1816,6 @@ static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device,
				device, VIDC_CPU_IC_SOFTINT,
				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);

		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");
			}
		}
		result = 0;
	} else {
		dprintk(VIDC_ERR, "venus_hfi_iface_cmdq_write:queue_full\n");
@@ -3102,9 +3095,13 @@ static int venus_hfi_core_pc_prep(void *device)
		dprintk(VIDC_ERR, "Failed to create sys pc prep pkt\n");
		goto err_create_pkt;
	}

	if (venus_hfi_iface_cmdq_write(dev, &pkt))
	/* Calling write_nolock() with write_lock instead of write()
	*  because write() will cancel and rescheduling power collapse.
	*/
	mutex_lock(&dev->write_lock);
	if (venus_hfi_iface_cmdq_write_nolock(dev, &pkt))
		rc = -ENOTEMPTY;
	mutex_unlock(&dev->write_lock);

err_create_pkt:
	return rc;
@@ -3144,6 +3141,7 @@ static void venus_hfi_pm_hndlr(struct work_struct *work)
		dprintk(VIDC_ERR, "%s: NULL device\n", __func__);
		return;
	}

	if (!device->power_enabled) {
		dprintk(VIDC_DBG, "%s: Power already disabled\n",
				__func__);
@@ -3164,22 +3162,9 @@ static void venus_hfi_pm_hndlr(struct work_struct *work)

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

	mutex_lock(&device->resource_lock);
	rc = __unset_free_ocmem(device);
	mutex_unlock(&device->resource_lock);
	if (rc) {
		dprintk(VIDC_ERR,
			"Failed to unset and free OCMEM for PC, rc : %d\n", rc);
		return;
	}

	rc = venus_hfi_prepare_pc(device);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to prepare for PC, rc : %d\n", rc);
		rc = __alloc_set_ocmem(device, true);
		if (rc)
			dprintk(VIDC_WARN,
				"Failed to re-allocate OCMEM. Performance will be impacted\n");
		return;
	}

@@ -3212,6 +3197,13 @@ static void venus_hfi_pm_hndlr(struct work_struct *work)
		goto err_power_off;
	}

	mutex_lock(&device->resource_lock);
	rc = __free_ocmem(device);
	mutex_unlock(&device->resource_lock);
	if (rc)
		dprintk(VIDC_ERR,
			"Failed to free OCMEM for PC, rc : %d\n", rc);

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

@@ -3234,10 +3226,6 @@ skip_power_off:
		device->last_packet_type, ctrl_status);

	mutex_unlock(&device->write_lock);
	rc = __alloc_set_ocmem(device, true);
	if (rc)
		dprintk(VIDC_WARN,
			"Failed to re-allocate OCMEM. Performance will be impacted\n");
	return;
}

@@ -3400,7 +3388,8 @@ static void venus_hfi_core_work_handler(struct work_struct *work)
		return;
	}
	if (device->res->sw_power_collapsible) {
		dprintk(VIDC_DBG, "Cancel and queue delayed work again.\n");
		dprintk(VIDC_DBG, "Cancel and queue delayed work from %s\n",
			__func__);
		cancel_delayed_work(&venus_hfi_pm_work);
		if (!queue_delayed_work(device->venus_pm_workq,
			&venus_hfi_pm_work,