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

Commit a03d5b19 authored by Vikash Garodia's avatar Vikash Garodia
Browse files

msm: vidc: Free OCMEM during power collapse



To disable OCMEM clock during power collapse, video driver
has to free up the allocated OCMEM. This memory will be
re-allocated before bringing venus core out of reset.

CRs-Fixed: 604629
Change-Id: I88f7e771b21046d9817feb17b06b3739f128c434
Signed-off-by: default avatarVikash Garodia <vgarodia@codeaurora.org>
parent 01951513
Loading
Loading
Loading
Loading
+312 −191
Original line number Diff line number Diff line
@@ -866,6 +866,210 @@ static int venus_hfi_unvote_buses(void *dev)
	return rc;
}

static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device,
					void *pkt);

static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device,
					void *pkt)
{
	int result = -EPERM;
	if (!device || !pkt) {
		dprintk(VIDC_ERR, "Invalid Params");
		return -EINVAL;
	}
	mutex_lock(&device->write_lock);
	mutex_lock(&device->clk_pwr_lock);
	result = venus_hfi_iface_cmdq_write_nolock(device, pkt);
	mutex_unlock(&device->clk_pwr_lock);
	mutex_unlock(&device->write_lock);
	return result;
}

static int venus_hfi_core_set_resource(void *device,
		struct vidc_resource_hdr *resource_hdr, void *resource_value,
		bool locked)
{
	struct hfi_cmd_sys_set_resource_packet *pkt;
	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
	int rc = 0;
	struct venus_hfi_device *dev;

	if (!device || !resource_hdr || !resource_value) {
		dprintk(VIDC_ERR, "set_res: Invalid Params\n");
		return -EINVAL;
	} else {
		dev = device;
	}

	pkt = (struct hfi_cmd_sys_set_resource_packet *) packet;

	rc = create_pkt_set_cmd_sys_resource(pkt, resource_hdr,
						resource_value);
	if (rc) {
		dprintk(VIDC_ERR, "set_res: failed to create packet\n");
		goto err_create_pkt;
	}
	rc = locked ? venus_hfi_iface_cmdq_write(dev, pkt) :
			venus_hfi_iface_cmdq_write_nolock(dev, pkt);
	if (rc)
		rc = -ENOTEMPTY;

err_create_pkt:
	return rc;
}

static int venus_hfi_core_release_resource(void *device,
			struct vidc_resource_hdr *resource_hdr)
{
	struct hfi_cmd_sys_release_resource_packet pkt;
	int rc = 0;
	struct venus_hfi_device *dev;

	if (!device || !resource_hdr) {
		dprintk(VIDC_ERR, "Inv-Params in rel_res\n");
		return -EINVAL;
	} else {
		dev = device;
	}

	rc = create_pkt_cmd_sys_release_resource(&pkt, resource_hdr);
	if (rc) {
		dprintk(VIDC_ERR, "release_res: failed to create packet\n");
		goto err_create_pkt;
	}

	if (venus_hfi_iface_cmdq_write(dev, &pkt))
		rc = -ENOTEMPTY;

err_create_pkt:
	return rc;
}

static int venus_hfi_set_ocmem(void *dev, struct ocmem_buf *ocmem, bool locked)
{
	struct vidc_resource_hdr rhdr;
	struct venus_hfi_device *device = dev;
	int rc = 0;
	if (!device || !ocmem) {
		dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n",
			device, ocmem);
		return -EINVAL;
	}
	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
	/*
	 * This handle is just used as a cookie and not(cannot be)
	 * accessed by fw
	 */
	rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem;
	rhdr.size = ocmem->len;
	rc = venus_hfi_core_set_resource(device, &rhdr, ocmem, locked);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
		goto ocmem_set_failed;
	}
	dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n",
		ocmem->addr, ocmem->len);
ocmem_set_failed:
	return rc;
}

static int venus_hfi_unset_ocmem(void *dev)
{
	struct vidc_resource_hdr rhdr;
	struct venus_hfi_device *device = dev;
	int rc = 0;

	if (!device) {
		dprintk(VIDC_ERR, "%s Invalid params, device:%p\n",
			__func__, device);
		rc = -EINVAL;
		goto ocmem_unset_failed;
	}
	if (!device->resources.ocmem.buf) {
		dprintk(VIDC_INFO, "%s Trying to free OCMEM which is not set\n",
			__func__);
		rc = -EINVAL;
		goto ocmem_unset_failed;
	}
	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
	/*
	 * This handle is just used as a cookie and not(cannot be)
	 * accessed by fw
	 */
	rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem;
	rc = venus_hfi_core_release_resource(device, &rhdr);
	if (rc)
		dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n");
ocmem_unset_failed:
	return rc;
}

static int __alloc_ocmem(void *dev, unsigned long size, bool locked)
{
	int rc = 0;
	struct ocmem_buf *ocmem_buffer;
	struct venus_hfi_device *device = dev;

	if (!device || !size) {
		dprintk(VIDC_ERR, "%s Invalid param, core: %p, size: %lu\n",
			__func__, device, size);
		return -EINVAL;
	}
	ocmem_buffer = device->resources.ocmem.buf;
	if (!ocmem_buffer ||
		ocmem_buffer->len < size) {
		ocmem_buffer = ocmem_allocate(OCMEM_VIDEO, size);
		if (IS_ERR_OR_NULL(ocmem_buffer)) {
			dprintk(VIDC_ERR,
				"ocmem_allocate_nb failed: %lu\n",
				(unsigned long) ocmem_buffer);
			rc = -ENOMEM;
			goto ocmem_alloc_failed;
		}
		device->resources.ocmem.buf = ocmem_buffer;
		rc = venus_hfi_set_ocmem(device, ocmem_buffer, locked);
		if (rc) {
			dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
			goto ocmem_set_failed;
		}
	} else
		dprintk(VIDC_DBG,
			"OCMEM is enough. reqd: %lu, available: %lu\n",
			size, ocmem_buffer->len);

	return rc;
ocmem_set_failed:
	ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf);
	device->resources.ocmem.buf = NULL;
ocmem_alloc_failed:
	return rc;
}

static int venus_hfi_alloc_ocmem(void *dev, unsigned long size)
{
	return __alloc_ocmem(dev, size, true);
}

static int venus_hfi_free_ocmem(void *dev)
{
	struct venus_hfi_device *device = dev;
	int rc = 0;

	if (!device) {
		dprintk(VIDC_ERR, "%s invalid device handle %p\n",
			__func__, device);
		return -EINVAL;
	}

	if (device->resources.ocmem.buf) {
		rc = ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf);
		if (rc)
			dprintk(VIDC_ERR, "Failed to free ocmem\n");
		device->resources.ocmem.buf = NULL;
	}
	return rc;
}

static inline int venus_hfi_tzbsp_set_video_state(enum tzbsp_video_state state)
{
	struct tzbsp_video_set_state_req cmd = {0};
@@ -929,7 +1133,6 @@ static unsigned long venus_hfi_get_clock_rate(struct clock_info *clock,
	return ret;
}

/*Calling function is responsible to acquire device->clk_pwr_lock*/
static inline int venus_hfi_clk_enable(struct venus_hfi_device *device)
{
	int rc = 0;
@@ -940,6 +1143,8 @@ static inline int venus_hfi_clk_enable(struct venus_hfi_device *device)
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return -EINVAL;
	}
	WARN(!mutex_is_locked(&device->clk_pwr_lock),
				"Clock/power lock must be acquired");
	if (device->clocks_enabled) {
		dprintk(VIDC_DBG, "Clocks already enabled\n");
		return 0;
@@ -977,7 +1182,6 @@ fail_clk_enable:
	return rc;
}

/*Calling function is responsible to acquire device->clk_pwr_lock*/
static inline void venus_hfi_clk_disable(struct venus_hfi_device *device)
{
	struct clock_info *cl;
@@ -986,6 +1190,8 @@ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device)
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return;
	}
	WARN(!mutex_is_locked(&device->clk_pwr_lock),
			"Clock/power lock must be acquired");
	if (!device->clocks_enabled) {
		dprintk(VIDC_DBG, "Clocks already disabled\n");
		return;
@@ -1016,6 +1222,7 @@ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device)
}

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

static int venus_hfi_halt_axi(struct venus_hfi_device *device)
{
@@ -1154,9 +1361,21 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device)
		goto err_reset_core;
	}

	/*
	 * 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_ocmem(device, device->res->ocmem_size, false);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to allocate OCMEM");
		goto err_alloc_ocmem;
	}
	device->power_enabled = 1;
	dprintk(VIDC_INFO, "resuming 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:
@@ -1254,18 +1473,19 @@ static int venus_hfi_scale_clocks(void *dev, int load)
	return rc;
}

static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device,
static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device,
					void *pkt)
{
	u32 rx_req_is_set = 0;
	struct vidc_iface_q_info *q_info;
	int result = -EPERM;

	if (!device || !pkt) {
		dprintk(VIDC_ERR, "Invalid Params\n");
		return -EINVAL;
	}

	mutex_lock(&device->write_lock);
	WARN(!mutex_is_locked(&device->write_lock),
			"Cmd queue write lock must be acquired");
	q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
	if (!q_info) {
		dprintk(VIDC_ERR, "cannot write to shared Q's\n");
@@ -1273,18 +1493,17 @@ static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device,
	}
	venus_hfi_sim_modify_cmd_packet((u8 *)pkt, device);
	if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
		mutex_lock(&device->clk_pwr_lock);
		WARN(!mutex_is_locked(&device->clk_pwr_lock),
					"Clock/power lock must be acquired");
		result = venus_hfi_clk_gating_off(device);
		if (result) {
			dprintk(VIDC_ERR, "%s : Clock enable failed\n",
					__func__);
			mutex_unlock(&device->clk_pwr_lock);
			goto err_q_write;
		}
		result = venus_hfi_scale_clocks(device, device->clk_load);
		if (result) {
			dprintk(VIDC_ERR, "Clock scaling failed\n");
			mutex_unlock(&device->clk_pwr_lock);
			goto err_q_write;
		}
		if (rx_req_is_set)
@@ -1293,13 +1512,11 @@ static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device,
				VIDC_CPU_IC_SOFTINT,
				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
		result = 0;
		mutex_unlock(&device->clk_pwr_lock);
	} else {
		dprintk(VIDC_ERR, "venus_hfi_iface_cmdq_write:queue_full\n");
	}
err_q_write:
err_q_null:
	mutex_unlock(&device->write_lock);
	return result;
}

@@ -1972,63 +2189,6 @@ err_clk_gating_off:
	mutex_unlock(&device->write_lock);
}

static int venus_hfi_core_set_resource(void *device,
		struct vidc_resource_hdr *resource_hdr, void *resource_value)
{
	struct hfi_cmd_sys_set_resource_packet *pkt;
	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
	int rc = 0;
	struct venus_hfi_device *dev;

	if (!device || !resource_hdr || !resource_value) {
		dprintk(VIDC_ERR, "set_res: Invalid Params\n");
		return -EINVAL;
	} else {
		dev = device;
	}

	pkt = (struct hfi_cmd_sys_set_resource_packet *) packet;

	rc = create_pkt_set_cmd_sys_resource(pkt, resource_hdr,
						resource_value);
	if (rc) {
		dprintk(VIDC_ERR, "set_res: failed to create packet\n");
		goto err_create_pkt;
	}
	if (venus_hfi_iface_cmdq_write(dev, pkt))
		rc = -ENOTEMPTY;

err_create_pkt:
	return rc;
}

static int venus_hfi_core_release_resource(void *device,
			struct vidc_resource_hdr *resource_hdr)
{
	struct hfi_cmd_sys_release_resource_packet pkt;
	int rc = 0;
	struct venus_hfi_device *dev;

	if (!device || !resource_hdr) {
		dprintk(VIDC_ERR, "Inv-Params in rel_res\n");
		return -EINVAL;
	} else {
		dev = device;
	}

	rc = create_pkt_cmd_sys_release_resource(&pkt, resource_hdr);
	if (rc) {
		dprintk(VIDC_ERR, "release_res: failed to create packet\n");
		goto err_create_pkt;
	}

	if (venus_hfi_iface_cmdq_write(dev, &pkt))
		rc = -ENOTEMPTY;

err_create_pkt:
	return rc;
}

static int venus_hfi_core_ping(void *device)
{
	struct hfi_cmd_sys_ping_packet pkt;
@@ -2633,6 +2793,67 @@ err_create_pkt:
	return rc;
}

static int venus_hfi_unset_free_ocmem(struct venus_hfi_device *device)
{
	int rc = 0;

	if (!device) {
		dprintk(VIDC_ERR, "Invalid param: %p\n", device);
		return -EINVAL;
	}

	init_completion(&release_resources_done);
	rc = venus_hfi_unset_ocmem(device);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to unset OCMEM during PC %d\n", rc);
		goto ocmem_unset_failed;
	}
	rc = wait_for_completion_timeout(&release_resources_done,
			msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
	if (!rc) {
		dprintk(VIDC_ERR,
				"Wait interrupted or timeout for RELEASE_RESOURCES: %d\n",
				rc);
		rc = -EIO;
		goto release_resources_failed;
	}

	rc = venus_hfi_free_ocmem(device);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to free OCMEM during PC\n");
		goto ocmem_free_failed;
	}
	return rc;

ocmem_free_failed:
	venus_hfi_alloc_ocmem(device, device->res->ocmem_size);
release_resources_failed:
ocmem_unset_failed:
	return rc;
}

static int venus_hfi_prepare_pc(struct venus_hfi_device *device)
{
	int rc = 0;
	init_completion(&pc_prep_done);
	rc = venus_hfi_core_pc_prep(device);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to prepare venus for power off");
		goto err_pc_prep;
	}
	rc = wait_for_completion_timeout(&pc_prep_done,
			msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
	if (!rc) {
		dprintk(VIDC_ERR,
				"Wait interrupted or timeout for PC_PREP_DONE: %d\n",
				rc);
		rc = -EIO;
		goto err_pc_prep;
	}
	rc = 0;
err_pc_prep:
	return rc;
}

static void venus_hfi_pm_hndlr(struct work_struct *work)
{
@@ -2647,17 +2868,19 @@ static void venus_hfi_pm_hndlr(struct work_struct *work)
		goto clks_enabled;
	}
	mutex_unlock(&device->clk_pwr_lock);
	init_completion(&pc_prep_done);
	rc = venus_hfi_core_pc_prep(device);

	rc = venus_hfi_unset_free_ocmem(device);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to prepare venus for power off\n");
		dprintk(VIDC_ERR,
				"Failed to unset and free OCMEM for PC %d\n",
				rc);
		return;
	}
	rc = wait_for_completion_timeout(&pc_prep_done,
			msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
	if (!rc) {
		dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n",
			__func__, rc);

	rc = venus_hfi_prepare_pc(device);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to prepare for PC %d\n", rc);
		venus_hfi_alloc_ocmem(device, device->res->ocmem_size);
		return;
	}

@@ -2761,9 +2984,14 @@ static void venus_hfi_response_handler(struct venus_hfi_device *device)
				device->device_id,
				(struct vidc_hal_msg_pkt_hdr *) packet,
				&device->sess_head, &device->session_lock);
			if (rc == HFI_MSG_EVENT_NOTIFY)
			if (rc == HFI_MSG_EVENT_NOTIFY) {
				venus_hfi_process_msg_event_notify(
					device, (void *)packet);
			} else if (rc == HFI_MSG_SYS_RELEASE_RESOURCE) {
				dprintk(VIDC_DBG,
					"Received HFI_MSG_SYS_RELEASE_RESOURCE\n");
				complete(&release_resources_done);
			}
		}
		while (!venus_hfi_iface_dbgq_read(device, packet)) {
			struct hfi_msg_sys_coverage_packet *pkt =
@@ -2784,10 +3012,13 @@ static void venus_hfi_response_handler(struct venus_hfi_device *device)
				dprintk(VIDC_FW, "%s", pkt->rg_msg_data);
			}
		}
		if (rc == HFI_MSG_SYS_IDLE) {
			dprintk(VIDC_DBG, "Received HFI_MSG_SYS_IDLE\n");
		switch (rc) {
		case HFI_MSG_SYS_IDLE:
			dprintk(VIDC_DBG,
					"Received HFI_MSG_SYS_IDLE\n");
			rc = venus_hfi_try_clk_gating(device);
		} else if (rc == HFI_MSG_SYS_PC_PREP_DONE) {
			break;
		case HFI_MSG_SYS_PC_PREP_DONE:
			dprintk(VIDC_DBG,
					"Received HFI_MSG_SYS_PC_PREP_DONE\n");
			rc = venus_hfi_try_clk_gating(device);
@@ -2795,6 +3026,7 @@ static void venus_hfi_response_handler(struct venus_hfi_device *device)
				dprintk(VIDC_ERR,
					"Failed clk gating after PC_PREP_DONE\n");
			complete(&pc_prep_done);
			break;
		}
	} else {
		dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT\n");
@@ -3153,61 +3385,6 @@ err_init_bus:
	return rc;
}

static int venus_hfi_set_ocmem(void *dev, struct ocmem_buf *ocmem)
{
	struct vidc_resource_hdr rhdr;
	struct venus_hfi_device *device = dev;
	int rc = 0;
	if (!device || !ocmem) {
		dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n",
			device, ocmem);
		return -EINVAL;
	}
	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
	/* This handle is just used as a cookie and not(cannot be)
	 * accessed by fw */
	rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem;
	rhdr.size = ocmem->len;
	rc = venus_hfi_core_set_resource(device, &rhdr, ocmem);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
		goto ocmem_set_failed;
	}
	dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n",
		ocmem->addr, ocmem->len);
ocmem_set_failed:
	return rc;
}

static int venus_hfi_unset_ocmem(void *dev)
{
	struct vidc_resource_hdr rhdr;
	struct venus_hfi_device *device = dev;
	int rc = 0;

	if (!device) {
		dprintk(VIDC_ERR, "%s Invalid params, device:%p\n",
			__func__, device);
		rc = -EINVAL;
		goto ocmem_unset_failed;
	}
	if (!device->resources.ocmem.buf) {
		dprintk(VIDC_INFO, "%s Trying to free OCMEM which is not set\n",
			__func__);
		rc = -EINVAL;
		goto ocmem_unset_failed;
	}
	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
	/* This handle is just used as a cookie and not(cannot be)
	 * accessed by fw */
	rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem;
	rc = venus_hfi_core_release_resource(device, &rhdr);
	if (rc)
		dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n");
ocmem_unset_failed:
	return rc;
}

static int venus_hfi_ocmem_notify_handler(struct notifier_block *this,
		unsigned long event, void *data)
{
@@ -3227,7 +3404,7 @@ static int venus_hfi_ocmem_notify_handler(struct notifier_block *this,
			struct venus_resources, ocmem);
		device = container_of(resources,
			struct venus_hfi_device, resources);
		if (venus_hfi_set_ocmem(device, buff)) {
		if (venus_hfi_set_ocmem(device, buff, true)) {
			dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
			goto err_ocmem_notify;
		}
@@ -3253,62 +3430,6 @@ static void venus_hfi_ocmem_init(struct venus_hfi_device *device)
	}
}

static int venus_hfi_alloc_ocmem(void *dev, unsigned long size)
{
	int rc = 0;
	struct ocmem_buf *ocmem_buffer;
	struct venus_hfi_device *device = dev;

	if (!device || !size) {
		dprintk(VIDC_ERR, "%s Invalid param, core: %p, size: %lu\n",
			__func__, device, size);
		return -EINVAL;
	}
	ocmem_buffer = device->resources.ocmem.buf;
	if (!ocmem_buffer || ocmem_buffer->len < size) {
		ocmem_buffer = ocmem_allocate(OCMEM_VIDEO, size);
		if (IS_ERR_OR_NULL(ocmem_buffer)) {
			dprintk(VIDC_ERR,
				"ocmem_allocate_nb failed: %lu\n",
				(unsigned long) ocmem_buffer);
			rc = -ENOMEM;
			goto ocmem_set_failed;
		}
		device->resources.ocmem.buf = ocmem_buffer;
		rc = venus_hfi_set_ocmem(device, ocmem_buffer);
		if (rc) {
			dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
			goto ocmem_set_failed;
		}
	} else
		dprintk(VIDC_DBG,
			"OCMEM is enough. reqd: %lu, available: %lu\n",
			size, ocmem_buffer->len);

ocmem_set_failed:
	return rc;
}

static int venus_hfi_free_ocmem(void *dev)
{
	struct venus_hfi_device *device = dev;
	int rc = 0;

	if (!device) {
		dprintk(VIDC_ERR, "%s invalid device handle %p\n",
			__func__, device);
		return -EINVAL;
	}

	if (device->resources.ocmem.buf) {
		rc = ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf);
		if (rc)
			dprintk(VIDC_ERR, "Failed to free ocmem\n");
		device->resources.ocmem.buf = NULL;
	}
	return rc;
}

static void venus_hfi_deinit_ocmem(struct venus_hfi_device *device)
{
	if (device->resources.ocmem.handle)