Merge "msm: cvp: CVP DSP driver restructure for Lahaina"

This commit is contained in:
qctecmdr 2020-01-15 13:50:29 -08:00 • committed by Gerrit - the friendly Code Review server
commit 3db6466154
6 changed files with 390 additions and 568 deletions

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/debugfs.h>
@ -26,7 +26,6 @@
#include "msm_cvp_clocks.h"
#include "msm_cvp_dsp.h"
#define BASE_DEVICE_NUMBER 32
#define CLASS_NAME "cvp"
#define DRIVER_NAME "cvp"
@ -34,18 +33,15 @@ struct msm_cvp_drv *cvp_driver;
static int cvp_open(struct inode *inode, struct file *filp)
{
int rc;
struct msm_cvp_core *core = container_of(inode->i_cdev,
struct msm_cvp_core, cdev);
struct msm_cvp_inst *inst;
dprintk(CVP_DBG, "%s: Enter\n", __func__);
rc = cvp_dsp_device_init();
inst = msm_cvp_open(core->id, MSM_CVP_USER);
if (!inst || rc) {
dprintk(CVP_ERR,
"Failed to create cvp instance rc=%d\n", rc);
if (!inst) {
dprintk(CVP_ERR, "Failed to create cvp instance\n");
return -ENOMEM;
}
filp->private_data = inst;
@ -551,8 +547,7 @@ static int __init msm_cvp_init(void)
{
int rc = 0;
cvp_driver = kzalloc(sizeof(*cvp_driver),
GFP_KERNEL);
cvp_driver = kzalloc(sizeof(*cvp_driver), GFP_KERNEL);
if (!cvp_driver) {
dprintk(CVP_ERR,
"Failed to allocate memroy for msm_cvp_drv\n");
@ -582,6 +577,10 @@ static int __init msm_cvp_init(void)
cvp_driver->frame_buf_cache = KMEM_CACHE(msm_cvp_frame_buf, 0);
cvp_driver->internal_buf_cache = KMEM_CACHE(msm_cvp_internal_buffer, 0);
rc = cvp_dsp_device_init();
if (rc)
dprintk(CVP_WARN, "Failed to initialize DSP driver\n");
return rc;
}

View file

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#ifndef __H_CVP_CORE_HFI_H__
@ -201,11 +201,6 @@ struct iris_resources {
struct msm_cvp_fw fw;
};
enum dsp_flag {
DSP_INIT = BIT(0),
DSP_SUSPEND = BIT(1),
};
enum iris_hfi_state {
IRIS_STATE_DEINIT = 1,
IRIS_STATE_INIT,
@ -229,7 +224,6 @@ struct iris_hfi_vpu_ops {
};
struct iris_hfi_device {
struct list_head list;
struct list_head sess_head;
u32 version;
u32 intr_status;
@ -250,7 +244,6 @@ struct iris_hfi_device {
struct cvp_mem_addr mem_addr;
struct cvp_iface_q_info iface_queues[CVP_IFACEQ_NUMQ];
struct cvp_iface_q_info dsp_iface_queues[CVP_IFACEQ_NUMQ];
u32 dsp_flags;
struct cvp_hal_data *cvp_hal_data;
struct workqueue_struct *cvp_workq;
struct workqueue_struct *iris_pm_workq;
@ -267,7 +260,6 @@ struct iris_hfi_device {
unsigned int skip_pc_count;
struct msm_cvp_capability *sys_init_capabilities;
struct iris_hfi_vpu_ops *vpu_ops;
struct delayed_work dsp_init_work;
};
void cvp_iris_hfi_delete_device(void *device);

View file

@ -264,7 +264,6 @@ const int cvp_max_packets = 32;
static void iris_hfi_pm_handler(struct work_struct *work);
static DECLARE_DELAYED_WORK(iris_hfi_pm_work, iris_hfi_pm_handler);
static void dsp_init_work_handler(struct work_struct *work);
static inline int __resume(struct iris_hfi_device *device);
static inline int __suspend(struct iris_hfi_device *device);
static int __disable_regulators(struct iris_hfi_device *device);
@ -420,41 +419,6 @@ static void __dump_packet(u8 *packet, enum cvp_msg_prio log_level)
}
}
static int __dsp_send_hfi_queue(struct iris_hfi_device *device)
{
int rc;
if (msm_cvp_dsp_disable) {
dprintk(CVP_WARN, "%s: DSP support is disabled\n", __func__);
return 0;
}
if (!device->dsp_iface_q_table.mem_data.dma_handle) {
dprintk(CVP_ERR, "%s: invalid dsm_handle\n", __func__);
return -EINVAL;
}
if (device->dsp_flags & DSP_INIT) {
dprintk(CVP_DBG, "%s: dsp already inited\n", __func__);
return 0;
}
dprintk(CVP_DBG, "%s: hfi queue %#llx size %d\n",
__func__, device->dsp_iface_q_table.mem_data.dma_handle,
device->dsp_iface_q_table.mem_data.size);
rc = cvp_dsp_send_cmd_hfi_queue(
(phys_addr_t *)device->dsp_iface_q_table.mem_data.dma_handle,
device->dsp_iface_q_table.mem_data.size, device);
if (rc) {
dprintk(CVP_ERR, "%s: dsp hfi queue init failed\n", __func__);
return rc;
}
device->dsp_flags |= DSP_INIT;
dprintk(CVP_DBG, "%s: dsp inited\n", __func__);
return rc;
}
static int __dsp_suspend(struct iris_hfi_device *device, bool force, u32 flags)
{
int rc;
@ -463,12 +427,6 @@ static int __dsp_suspend(struct iris_hfi_device *device, bool force, u32 flags)
if (msm_cvp_dsp_disable)
return 0;
if (!(device->dsp_flags & DSP_INIT))
return 0;
if (device->dsp_flags & DSP_SUSPEND)
return 0;
list_for_each_entry(temp, &device->sess_head, list) {
/* if forceful suspend, don't check session pause info */
if (force)
@ -491,7 +449,6 @@ static int __dsp_suspend(struct iris_hfi_device *device, bool force, u32 flags)
return -EINVAL;
}
device->dsp_flags |= DSP_SUSPEND;
dprintk(CVP_DBG, "%s: dsp suspended\n", __func__);
return 0;
}
@ -503,11 +460,6 @@ static int __dsp_resume(struct iris_hfi_device *device, u32 flags)
if (msm_cvp_dsp_disable)
return 0;
if (!(device->dsp_flags & DSP_SUSPEND)) {
dprintk(CVP_DBG, "%s: dsp not suspended\n", __func__);
return 0;
}
dprintk(CVP_DBG, "%s: resume dsp\n", __func__);
rc = cvp_dsp_resume(flags);
if (rc) {
@ -517,7 +469,6 @@ static int __dsp_resume(struct iris_hfi_device *device, u32 flags)
return rc;
}
device->dsp_flags &= ~DSP_SUSPEND;
dprintk(CVP_DBG, "%s: dsp resumed\n", __func__);
return rc;
}
@ -529,13 +480,6 @@ static int __dsp_shutdown(struct iris_hfi_device *device, u32 flags)
if (msm_cvp_dsp_disable)
return 0;
cvp_dsp_set_cvp_ssr();
if (!(device->dsp_flags & DSP_INIT)) {
dprintk(CVP_WARN, "%s: dsp not inited\n", __func__);
return 0;
}
dprintk(CVP_DBG, "%s: shutdown dsp\n", __func__);
rc = cvp_dsp_shutdown(flags);
if (rc) {
@ -545,7 +489,6 @@ static int __dsp_shutdown(struct iris_hfi_device *device, u32 flags)
WARN_ON(1);
}
device->dsp_flags &= ~DSP_INIT;
dprintk(CVP_DBG, "%s: dsp shutdown successful\n", __func__);
return rc;
}
@ -1992,43 +1935,6 @@ static int __sys_set_power_control(struct iris_hfi_device *device,
return 0;
}
static void dsp_init_work_handler(struct work_struct *work)
{
int rc = 0;
static int retry_count;
struct iris_hfi_device *device;
if (!work) {
dprintk(CVP_ERR, "%s: NULL device\n", __func__);
return;
}
device = container_of(work, struct iris_hfi_device, dsp_init_work.work);
if (!device) {
dprintk(CVP_ERR, "%s: NULL device\n", __func__);
return;
}
dprintk(CVP_PROF, "Entering %s\n", __func__);
mutex_lock(&device->lock);
rc = __dsp_send_hfi_queue(device);
mutex_unlock(&device->lock);
if (rc) {
if (retry_count > MAX_DSP_INIT_ATTEMPTS) {
dprintk(CVP_ERR, "%s: max trials exceeded\n", __func__);
return;
}
dprintk(CVP_PROF, "%s: Attempt to init DSP %d\n",
__func__, retry_count);
schedule_delayed_work(&device->dsp_init_work,
msecs_to_jiffies(CVP_MAX_WAIT_TIME));
++retry_count;
}
}
static int iris_hfi_core_init(void *device)
{
int rc = 0;
@ -2115,13 +2021,12 @@ static int iris_hfi_core_init(void *device)
pm_qos_add_request(&dev->qos, PM_QOS_CPU_DMA_LATENCY,
dev->res->pm_qos_latency_us);
rc = __dsp_send_hfi_queue(device);
if (rc)
schedule_delayed_work(&dev->dsp_init_work,
msecs_to_jiffies(CVP_MAX_WAIT_TIME));
mutex_unlock(&dev->lock);
cvp_dsp_send_hfi_queue();
dprintk(CVP_DBG, "Core inited successfully\n");
mutex_unlock(&dev->lock);
return 0;
err_core_init:
__set_state(dev, IRIS_STATE_DEINIT);
@ -4574,8 +4479,6 @@ static struct iris_hfi_device *__add_device(u32 device_id,
mutex_init(&hdevice->lock);
INIT_LIST_HEAD(&hdevice->sess_head);
INIT_DELAYED_WORK(&hdevice->dsp_init_work, dsp_init_work_handler);
return hdevice;
err_cleanup:

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
#include <linux/rpmsg.h>
@ -8,405 +8,284 @@
#include <linux/of_fdt.h>
#include <soc/qcom/secure_buffer.h>
#include "msm_cvp_dsp.h"
#define VMID_CDSP_Q6 (30)
#define SRC_VM_NUM 1
#define DEST_VM_NUM 2
#define CVP_DSP_SEND_HFI_CMD_QUEUE 0
#define CVP_DSP_SUSPEND 1
#define CVP_DSP_RESUME 2
#define CVP_DSP_SHUTDOWN 3
#define CVP_DSP_REGISTER_BUFFER 4
#define CVP_DSP_DEREGISTER_BUFFER 5
#define STATUS_INIT 0
#define STATUS_DEINIT 1
#define STATUS_OK 2
#define STATUS_SSR 3
#define CVP_DSP_MAX_RESERVED 5
struct cvp_dsp_cmd_msg {
uint32_t cmd_msg_type;
int32_t ret_val;
uint64_t msg_ptr;
uint32_t msg_ptr_len;
uint32_t buff_fd_iova;
uint32_t buff_index;
uint32_t buff_size;
uint32_t session_id;
int32_t ddr_type;
uint32_t buff_fd;
uint32_t buff_offset;
uint32_t buff_fd_size;
uint32_t reserved1;
uint32_t reserved2;
};
struct cvp_dsp_rsp_msg {
uint32_t cmd_msg_type;
int32_t ret_val;
uint32_t reserved[CVP_DSP_MAX_RESERVED];
};
struct cvp_dsp_rsp_context {
struct completion work;
};
#include "msm_cvp_internal.h"
struct cvp_dsp_apps {
struct mutex lock;
struct rpmsg_device *chan;
struct mutex smd_mutex;
struct mutex reg_buffer_mutex;
struct mutex dereg_buffer_mutex;
int rpmsg_register;
uint32_t cdsp_state;
uint32_t cvp_shutdown;
struct completion reg_buffer_work;
struct completion dereg_buffer_work;
struct completion shutdown_work;
struct completion cmdqueue_send_work;
struct work_struct ssr_work;
struct iris_hfi_device *device;
uint32_t state;
bool hyp_assigned;
uint64_t addr;
uint32_t size;
struct completion completions[CVP_DSP_MAX_CMD];
};
static struct cvp_dsp_apps gfa_cv;
static int hlosVM[HLOS_VM_NUM] = {VMID_HLOS};
static int dspVM[DSP_VM_NUM] = {VMID_HLOS, VMID_CDSP_Q6};
static int dspVMperm[DSP_VM_NUM] = { PERM_READ | PERM_WRITE | PERM_EXEC,
PERM_READ | PERM_WRITE | PERM_EXEC };
static int hlosVMperm[HLOS_VM_NUM] = { PERM_READ | PERM_WRITE | PERM_EXEC };
static struct cvp_dsp_cmd_msg cmd_msg;
static struct cvp_dsp_rsp_msg cmd_msg_rsp;
static int cvp_dsp_send_cmd(void *msg, uint32_t len)
static int cvp_dsp_send_cmd(struct cvp_dsp_cmd_msg *cmd, uint32_t len)
{
int rc = 0;
struct cvp_dsp_apps *me = &gfa_cv;
int err = 0;
dprintk(CVP_DBG, "%s: cmd = %d\n", __func__, cmd->type);
if (IS_ERR_OR_NULL(me->chan)) {
dprintk(CVP_ERR, "%s: DSP GLink is not ready\n", __func__);
err = -EINVAL;
goto bail;
rc = -EINVAL;
goto exit;
}
rc = rpmsg_send(me->chan->ept, cmd, len);
if (rc) {
dprintk(CVP_ERR, "%s: DSP rpmsg_send failed rc=%d\n",
__func__, rc);
goto exit;
}
err = rpmsg_send(me->chan->ept, msg, len);
bail:
return err;
exit:
return rc;
}
void msm_cvp_cdsp_ssr_handler(struct work_struct *work)
static int cvp_dsp_send_cmd_sync(struct cvp_dsp_cmd_msg *cmd, uint32_t len)
{
struct cvp_dsp_apps *me;
uint64_t msg_ptr;
uint32_t msg_ptr_len;
int err;
int rc = 0;
struct cvp_dsp_apps *me = &gfa_cv;
me = container_of(work, struct cvp_dsp_apps, ssr_work);
if (!me) {
dprintk(CVP_ERR, "%s: Invalid params\n", __func__);
return;
dprintk(CVP_DBG, "%s: cmd = %d\n", __func__, cmd->type);
rc = cvp_dsp_send_cmd(cmd, len);
if (rc) {
dprintk(CVP_ERR, "%s: cvp_dsp_send_cmd failed rc=%d\n",
__func__, rc);
goto exit;
}
msg_ptr = cmd_msg.msg_ptr;
msg_ptr_len = cmd_msg.msg_ptr_len;
if (!wait_for_completion_timeout(&me->completions[cmd->type],
msecs_to_jiffies(CVP_DSP_RESPONSE_TIMEOUT))) {
dprintk(CVP_ERR, "%s cmd %d timeout\n", __func__, cmd->type);
rc = -ETIMEDOUT;
goto exit;
}
err = cvp_dsp_send_cmd_hfi_queue((phys_addr_t *)msg_ptr,
msg_ptr_len,
(void *)NULL);
if (err) {
exit:
return rc;
}
static int cvp_dsp_send_cmd_hfi_queue(phys_addr_t *phys_addr,
uint32_t size_in_bytes)
{
int rc = 0;
struct cvp_dsp_cmd_msg cmd;
cmd.type = CVP_DSP_SEND_HFI_QUEUE;
cmd.msg_ptr = (uint64_t)phys_addr;
cmd.msg_ptr_len = size_in_bytes;
cmd.ddr_type = of_fdt_get_ddrtype();
if (cmd.ddr_type < 0) {
dprintk(CVP_ERR,
"%s: Failed to send HFI Queue address. err=%d\n",
__func__, err);
return;
"%s: Incorrect DDR type value %d\n",
__func__, cmd.ddr_type);
return -EINVAL;
}
if (me->device) {
mutex_lock(&me->device->lock);
me->device->dsp_flags |= DSP_INIT;
mutex_unlock(&me->device->lock);
dprintk(CVP_DBG,
"%s: address of buffer, PA=0x%pK size_buff=%d ddr_type=%d\n",
__func__, phys_addr, size_in_bytes, cmd.ddr_type);
rc = cvp_dsp_send_cmd_sync(&cmd, sizeof(struct cvp_dsp_cmd_msg));
if (rc) {
dprintk(CVP_ERR,
"%s: cvp_dsp_send_cmd failed rc = %d\n",
__func__, rc);
goto exit;
}
dprintk(CVP_DBG, "%s: dsp recover from SSR successfully\n", __func__);
exit:
return rc;
}
static int cvp_hyp_assign_to_dsp(uint64_t addr, uint32_t size)
{
int rc = 0;
struct cvp_dsp_apps *me = &gfa_cv;
if (!me->hyp_assigned) {
rc = hyp_assign_phys(addr, size, hlosVM, HLOS_VM_NUM, dspVM,
dspVMperm, DSP_VM_NUM);
if (rc) {
dprintk(CVP_ERR, "%s failed. rc=%d\n", __func__, rc);
return rc;
}
me->addr = addr;
me->size = size;
me->hyp_assigned = true;
}
return rc;
}
static int cvp_hyp_assign_from_dsp(void)
{
int rc = 0;
struct cvp_dsp_apps *me = &gfa_cv;
if (me->hyp_assigned) {
rc = hyp_assign_phys(me->addr, me->size, dspVM, DSP_VM_NUM,
hlosVM, hlosVMperm, HLOS_VM_NUM);
if (rc) {
dprintk(CVP_ERR, "%s failed. rc=%d\n", __func__, rc);
return rc;
}
me->addr = 0;
me->size = 0;
me->hyp_assigned = false;
}
return rc;
}
static int cvp_dsp_rpmsg_probe(struct rpmsg_device *rpdev)
{
int err = 0;
struct cvp_dsp_apps *me = &gfa_cv;
uint32_t cdsp_state, cvp_shutdown;
uint64_t msg_ptr;
uint32_t msg_ptr_len;
int srcVM[DEST_VM_NUM] = {VMID_HLOS, VMID_CDSP_Q6};
int destVM[SRC_VM_NUM] = {VMID_HLOS};
int destVMperm[SRC_VM_NUM] = { PERM_READ | PERM_WRITE | PERM_EXEC };
if (strcmp(rpdev->dev.parent->of_node->name, "cdsp")) {
dprintk(CVP_ERR,
"%s: Failed to probe rpmsg device.Node name:%s\n",
__func__, rpdev->dev.parent->of_node->name);
err = -EINVAL;
goto bail;
return -EINVAL;
}
mutex_lock(&me->smd_mutex);
mutex_lock(&me->lock);
me->chan = rpdev;
cdsp_state = me->cdsp_state;
cvp_shutdown = me->cvp_shutdown;
msg_ptr = cmd_msg.msg_ptr;
msg_ptr_len = cmd_msg.msg_ptr_len;
mutex_unlock(&me->smd_mutex);
me->state = DSP_PROBED;
mutex_unlock(&me->lock);
if (cdsp_state == STATUS_SSR && cvp_shutdown == STATUS_OK) {
err = hyp_assign_phys((uint64_t)msg_ptr,
msg_ptr_len, srcVM, DEST_VM_NUM, destVM,
destVMperm, SRC_VM_NUM);
if (err) {
dprintk(CVP_ERR,
"%s: Failed to hyp_assign. err=%d\n",
__func__, err);
return err;
}
schedule_work(&me->ssr_work);
mutex_lock(&me->smd_mutex);
cdsp_state = me->cdsp_state;
mutex_unlock(&me->smd_mutex);
}
cvp_dsp_send_hfi_queue();
dprintk(CVP_INFO,
"%s: Successfully probed. cdsp_state=%d cvp_shutdown=%d\n",
__func__, cdsp_state, cvp_shutdown);
bail:
return err;
return 0;
}
static void cvp_dsp_rpmsg_remove(struct rpmsg_device *rpdev)
{
struct cvp_dsp_apps *me = &gfa_cv;
cancel_work_sync(&me->ssr_work);
mutex_lock(&me->smd_mutex);
dprintk(CVP_WARN, "%s: CDSP SSR triggered\n", __func__);
mutex_lock(&me->lock);
cvp_hyp_assign_from_dsp();
me->chan = NULL;
me->cdsp_state = STATUS_SSR;
if (me->device) {
mutex_lock(&me->device->lock);
me->device->dsp_flags &= ~DSP_INIT;
mutex_unlock(&me->device->lock);
}
mutex_unlock(&me->smd_mutex);
dprintk(CVP_INFO,
"%s: CDSP SSR triggered\n", __func__);
me->state = DSP_UNINIT;
mutex_unlock(&me->lock);
/* kernel driver needs clean all dsp sessions */
}
static int cvp_dsp_rpmsg_callback(struct rpmsg_device *rpdev,
void *data, int len, void *priv, u32 addr)
{
struct cvp_dsp_rsp_msg *dsp_response =
(struct cvp_dsp_rsp_msg *)data;
struct cvp_dsp_rsp_msg *rsp = (struct cvp_dsp_rsp_msg *)data;
struct cvp_dsp_apps *me = &gfa_cv;
dprintk(CVP_DBG,
"%s: cmd_msg_type=0x%x dsp_response->ret_val =0x%x\n"
, __func__, dsp_response->cmd_msg_type, dsp_response->ret_val);
switch (dsp_response->cmd_msg_type) {
case CVP_DSP_REGISTER_BUFFER:
complete(&me->reg_buffer_work);
break;
case CVP_DSP_DEREGISTER_BUFFER:
complete(&me->dereg_buffer_work);
break;
case CVP_DSP_SHUTDOWN:
complete(&me->shutdown_work);
break;
case CVP_DSP_SUSPEND:
break;
case CVP_DSP_RESUME:
break;
case CVP_DSP_SEND_HFI_CMD_QUEUE:
complete(&me->cmdqueue_send_work);
break;
default:
dprintk(CVP_ERR,
"%s: Invalid cmd_msg_type received from dsp: %d\n",
__func__, dsp_response->cmd_msg_type);
break;
dprintk(CVP_DBG, "%s: type = 0x%x ret = 0x%x\n",
__func__, rsp->type, rsp->ret);
if (rsp->type >= CVP_DSP_MAX_CMD) {
dprintk(CVP_ERR, "%s: Invalid type: %d\n", __func__, rsp->type);
return 0;
}
complete(&me->completions[rsp->type]);
return 0;
}
int cvp_dsp_send_cmd_hfi_queue(phys_addr_t *phys_addr,
uint32_t size_in_bytes,
struct iris_hfi_device *device)
{
int err, timeout;
struct msm_cvp_core *core;
struct cvp_dsp_cmd_msg local_cmd_msg;
struct cvp_dsp_apps *me = &gfa_cv;
int srcVM[SRC_VM_NUM] = {VMID_HLOS};
int destVM[DEST_VM_NUM] = {VMID_HLOS, VMID_CDSP_Q6};
int destVMperm[DEST_VM_NUM] = { PERM_READ | PERM_WRITE | PERM_EXEC,
PERM_READ | PERM_WRITE | PERM_EXEC };
local_cmd_msg.cmd_msg_type = CVP_DSP_SEND_HFI_CMD_QUEUE;
local_cmd_msg.msg_ptr = (uint64_t)phys_addr;
local_cmd_msg.msg_ptr_len = size_in_bytes;
local_cmd_msg.ddr_type = of_fdt_get_ddrtype();
if (local_cmd_msg.ddr_type < 0) {
dprintk(CVP_ERR,
"%s: Incorrect DDR type value %d\n",
__func__, local_cmd_msg.ddr_type);
err = -EINVAL;
goto exit;
}
mutex_lock(&me->smd_mutex);
cmd_msg.msg_ptr = (uint64_t)phys_addr;
cmd_msg.msg_ptr_len = (size_in_bytes);
me->device = device;
mutex_unlock(&me->smd_mutex);
dprintk(CVP_DBG,
"%s: address of buffer, PA=0x%pK size_buff=%d ddr_type=%d\n",
__func__, phys_addr, size_in_bytes, local_cmd_msg.ddr_type);
err = hyp_assign_phys((uint64_t)local_cmd_msg.msg_ptr,
local_cmd_msg.msg_ptr_len, srcVM, SRC_VM_NUM, destVM,
destVMperm, DEST_VM_NUM);
if (err) {
dprintk(CVP_ERR,
"%s: Failed in hyp_assign. err=%d\n",
__func__, err);
goto exit;
}
err = cvp_dsp_send_cmd
(&local_cmd_msg, sizeof(struct cvp_dsp_cmd_msg));
if (err) {
dprintk(CVP_ERR,
"%s: cvp_dsp_send_cmd faidmesgled with err=%d\n",
__func__, err);
goto exit;
}
core = list_first_entry(&cvp_driver->cores,
struct msm_cvp_core, list);
timeout = msecs_to_jiffies(
core->resources.msm_cvp_dsp_rsp_timeout);
if (!wait_for_completion_timeout(&me->cmdqueue_send_work, timeout)) {
dprintk(CVP_ERR, "failed to send cmdqueue\n");
err = -ETIMEDOUT;
goto exit;
}
mutex_lock(&me->smd_mutex);
me->cvp_shutdown = STATUS_OK;
me->cdsp_state = STATUS_OK;
mutex_unlock(&me->smd_mutex);
exit:
return err;
}
int cvp_dsp_suspend(uint32_t session_flag)
{
int err = 0;
struct cvp_dsp_cmd_msg local_cmd_msg;
int rc = 0;
struct cvp_dsp_cmd_msg cmd;
struct cvp_dsp_apps *me = &gfa_cv;
uint32_t cdsp_state;
mutex_lock(&me->smd_mutex);
cdsp_state = me->cdsp_state;
mutex_unlock(&me->smd_mutex);
cmd.type = CVP_DSP_SUSPEND;
if (cdsp_state == STATUS_SSR)
return 0;
mutex_lock(&me->lock);
if (me->state != DSP_READY)
goto exit;
local_cmd_msg.cmd_msg_type = CVP_DSP_SUSPEND;
err = cvp_dsp_send_cmd
(&local_cmd_msg, sizeof(struct cvp_dsp_cmd_msg));
if (err != 0)
/* Use cvp_dsp_send_cmd_sync after dsp driver is ready */
rc = cvp_dsp_send_cmd(&cmd, sizeof(struct cvp_dsp_cmd_msg));
if (rc) {
dprintk(CVP_ERR,
"%s: cvp_dsp_send_cmd failed with err=%d\n",
__func__, err);
"%s: cvp_dsp_send_cmd failed rc = %d\n",
__func__, rc);
me->state = DSP_UNINIT;
goto exit;
}
return err;
me->state = DSP_SUSPEND;
exit:
mutex_unlock(&me->lock);
return rc;
}
int cvp_dsp_resume(uint32_t session_flag)
{
int err;
struct cvp_dsp_cmd_msg local_cmd_msg;
int rc = 0;
struct cvp_dsp_cmd_msg cmd;
struct cvp_dsp_apps *me = &gfa_cv;
uint32_t cdsp_state;
mutex_lock(&me->smd_mutex);
cdsp_state = me->cdsp_state;
mutex_unlock(&me->smd_mutex);
cmd.type = CVP_DSP_RESUME;
if (cdsp_state == STATUS_SSR)
return 0;
mutex_lock(&me->lock);
if (me->state != DSP_SUSPEND)
goto exit;
local_cmd_msg.cmd_msg_type = CVP_DSP_RESUME;
err = cvp_dsp_send_cmd
(&local_cmd_msg, sizeof(struct cvp_dsp_cmd_msg));
if (err != 0)
/* Use cvp_dsp_send_cmd_sync after dsp driver is ready */
rc = cvp_dsp_send_cmd(&cmd, sizeof(struct cvp_dsp_cmd_msg));
if (rc) {
dprintk(CVP_ERR,
"%s: cvp_dsp_send_cmd failed with err=%d\n",
__func__, err);
"%s: cvp_dsp_send_cmd failed rc = %d\n",
__func__, rc);
me->state = DSP_UNINIT;
goto exit;
}
return err;
}
me->state = DSP_READY;
void cvp_dsp_set_cvp_ssr(void)
{
struct cvp_dsp_apps *me = &gfa_cv;
mutex_lock(&me->smd_mutex);
me->cvp_shutdown = STATUS_SSR;
mutex_unlock(&me->smd_mutex);
exit:
mutex_unlock(&me->lock);
return rc;
}
int cvp_dsp_shutdown(uint32_t session_flag)
{
struct msm_cvp_core *core;
struct cvp_dsp_apps *me = &gfa_cv;
int err, local_cmd_msg_rsp, timeout;
struct cvp_dsp_cmd_msg local_cmd_msg;
int srcVM[DEST_VM_NUM] = {VMID_HLOS, VMID_CDSP_Q6};
int destVM[SRC_VM_NUM] = {VMID_HLOS};
int destVMperm[SRC_VM_NUM] = { PERM_READ | PERM_WRITE | PERM_EXEC };
int rc = 0;
struct cvp_dsp_cmd_msg cmd;
local_cmd_msg.cmd_msg_type = CVP_DSP_SHUTDOWN;
err = cvp_dsp_send_cmd
(&local_cmd_msg, sizeof(struct cvp_dsp_cmd_msg));
if (err != 0)
cmd.type = CVP_DSP_SHUTDOWN;
mutex_lock(&me->lock);
if (me->state == DSP_INVALID)
goto exit;
me->state = DSP_UNINIT;
rc = cvp_dsp_send_cmd_sync(&cmd, sizeof(struct cvp_dsp_cmd_msg));
if (rc) {
dprintk(CVP_ERR,
"%s: cvp_dsp_send_cmd failed with err=%d\n",
__func__, err);
core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list);
timeout = msecs_to_jiffies(core->resources.msm_cvp_dsp_rsp_timeout);
err = wait_for_completion_timeout(&me->shutdown_work, timeout);
if (!err) {
dprintk(CVP_ERR, "failed to shutdown dsp\n");
return -ETIMEDOUT;
"%s: cvp_dsp_send_cmd failed with rc = %d\n",
__func__, rc);
goto exit;
}
mutex_lock(&me->smd_mutex);
local_cmd_msg.msg_ptr = cmd_msg.msg_ptr;
local_cmd_msg.msg_ptr_len = cmd_msg.msg_ptr_len;
mutex_unlock(&me->smd_mutex);
local_cmd_msg_rsp = cmd_msg_rsp.ret_val;
if (local_cmd_msg_rsp == 0) {
err = hyp_assign_phys((uint64_t)local_cmd_msg.msg_ptr,
local_cmd_msg.msg_ptr_len, srcVM, DEST_VM_NUM,
destVM, destVMperm, SRC_VM_NUM);
if (err) {
dprintk(CVP_ERR,
"%s: Failed to hyp_assign. err=%d\n",
__func__, err);
return err;
}
} else {
dprintk(CVP_ERR,
"%s: Skipping hyp_assign as CDSP sent invalid response=%d\n",
__func__, local_cmd_msg_rsp);
}
rc = cvp_hyp_assign_from_dsp();
return err;
exit:
mutex_unlock(&me->lock);
return rc;
}
int cvp_dsp_register_buffer(uint32_t session_id, uint32_t buff_fd,
@ -414,47 +293,37 @@ int cvp_dsp_register_buffer(uint32_t session_id, uint32_t buff_fd,
uint32_t buff_offset, uint32_t buff_index,
uint32_t buff_fd_iova)
{
struct cvp_dsp_cmd_msg local_cmd_msg;
int err;
struct cvp_dsp_cmd_msg cmd;
int rc;
struct cvp_dsp_apps *me = &gfa_cv;
local_cmd_msg.cmd_msg_type = CVP_DSP_REGISTER_BUFFER;
local_cmd_msg.session_id = session_id;
local_cmd_msg.buff_fd = buff_fd;
local_cmd_msg.buff_fd_size = buff_fd_size;
local_cmd_msg.buff_size = buff_size;
local_cmd_msg.buff_offset = buff_offset;
local_cmd_msg.buff_index = buff_index;
local_cmd_msg.buff_fd_iova = buff_fd_iova;
cmd.type = CVP_DSP_REGISTER_BUFFER;
cmd.session_id = session_id;
cmd.buff_fd = buff_fd;
cmd.buff_fd_size = buff_fd_size;
cmd.buff_size = buff_size;
cmd.buff_offset = buff_offset;
cmd.buff_index = buff_index;
cmd.buff_fd_iova = buff_fd_iova;
dprintk(CVP_DBG,
"%s: cmd_msg_type=0x%x, buff_fd_iova=0x%x buff_index=0x%x\n",
__func__, local_cmd_msg.cmd_msg_type, buff_fd_iova,
local_cmd_msg.buff_index);
dprintk(CVP_DBG,
"%s: buff_size=0x%x session_id=0x%x\n",
__func__, local_cmd_msg.buff_size, local_cmd_msg.session_id);
"%s: type=0x%x, buff_fd_iova=0x%x buff_index=0x%x\n",
__func__, cmd.type, buff_fd_iova,
cmd.buff_index);
dprintk(CVP_DBG, "%s: buff_size=0x%x session_id=0x%x\n",
__func__, cmd.buff_size, cmd.session_id);
mutex_lock(&me->reg_buffer_mutex);
err = cvp_dsp_send_cmd
(&local_cmd_msg, sizeof(struct cvp_dsp_cmd_msg));
if (err != 0) {
dprintk(CVP_ERR,
"%s: cvp_dsp_send_cmd failed with err=%d\n",
__func__, err);
mutex_unlock(&me->reg_buffer_mutex);
return err;
mutex_lock(&me->lock);
rc = cvp_dsp_send_cmd_sync(&cmd, sizeof(struct cvp_dsp_cmd_msg));
if (rc) {
dprintk(CVP_ERR, "%s send failed rc = %d\n", __func__, rc);
me->state = DSP_UNINIT;
goto exit;
}
dprintk(CVP_DBG,
"%s: calling wait_for_completion work=%pK\n",
__func__, &me->reg_buffer_work);
wait_for_completion(&me->reg_buffer_work);
mutex_unlock(&me->reg_buffer_mutex);
dprintk(CVP_DBG,
"%s: done calling wait_for_completion\n", __func__);
return err;
exit:
mutex_unlock(&me->lock);
return rc;
}
int cvp_dsp_deregister_buffer(uint32_t session_id, uint32_t buff_fd,
@ -462,47 +331,37 @@ int cvp_dsp_deregister_buffer(uint32_t session_id, uint32_t buff_fd,
uint32_t buff_offset, uint32_t buff_index,
uint32_t buff_fd_iova)
{
struct cvp_dsp_cmd_msg local_cmd_msg;
int err;
struct cvp_dsp_cmd_msg cmd;
int rc;
struct cvp_dsp_apps *me = &gfa_cv;
local_cmd_msg.cmd_msg_type = CVP_DSP_DEREGISTER_BUFFER;
local_cmd_msg.session_id = session_id;
local_cmd_msg.buff_fd = buff_fd;
local_cmd_msg.buff_fd_size = buff_fd_size;
local_cmd_msg.buff_size = buff_size;
local_cmd_msg.buff_offset = buff_offset;
local_cmd_msg.buff_index = buff_index;
local_cmd_msg.buff_fd_iova = buff_fd_iova;
cmd.type = CVP_DSP_DEREGISTER_BUFFER;
cmd.session_id = session_id;
cmd.buff_fd = buff_fd;
cmd.buff_fd_size = buff_fd_size;
cmd.buff_size = buff_size;
cmd.buff_offset = buff_offset;
cmd.buff_index = buff_index;
cmd.buff_fd_iova = buff_fd_iova;
dprintk(CVP_DBG,
"%s: cmd_msg_type=0x%x, buff_fd_iova=0x%x buff_index=0x%x\n",
__func__, local_cmd_msg.cmd_msg_type, buff_fd_iova,
local_cmd_msg.buff_index);
dprintk(CVP_DBG,
"%s: buff_size=0x%x session_id=0x%x\n",
__func__, local_cmd_msg.buff_size, local_cmd_msg.session_id);
"%s: type=0x%x, buff_fd_iova=0x%x buff_index=0x%x\n",
__func__, cmd.type, buff_fd_iova,
cmd.buff_index);
dprintk(CVP_DBG, "%s: buff_size=0x%x session_id=0x%x\n",
__func__, cmd.buff_size, cmd.session_id);
mutex_lock(&me->dereg_buffer_mutex);
err = cvp_dsp_send_cmd
(&local_cmd_msg, sizeof(struct cvp_dsp_cmd_msg));
if (err != 0) {
dprintk(CVP_ERR,
"%s: cvp_dsp_send_cmd failed with err=%d\n",
__func__, err);
mutex_unlock(&me->dereg_buffer_mutex);
return err;
mutex_lock(&me->lock);
rc = cvp_dsp_send_cmd_sync(&cmd, sizeof(struct cvp_dsp_cmd_msg));
if (rc) {
dprintk(CVP_ERR, "%s send failed rc = %d\n", __func__, rc);
me->state = DSP_UNINIT;
goto exit;
}
dprintk(CVP_DBG,
"%s: calling wait_for_completion work=%pK\n",
__func__, &me->dereg_buffer_work);
wait_for_completion(&me->dereg_buffer_work);
dprintk(CVP_DBG,
"%s: done calling wait_for_completion\n", __func__);
mutex_unlock(&me->dereg_buffer_mutex);
return err;
exit:
mutex_unlock(&me->lock);
return rc;
}
static const struct rpmsg_device_id cvp_dsp_rpmsg_match[] = {
@ -520,48 +379,102 @@ static struct rpmsg_driver cvp_dsp_rpmsg_client = {
},
};
void cvp_dsp_send_hfi_queue(void)
{
struct msm_cvp_core *core;
struct iris_hfi_device *device;
struct cvp_dsp_apps *me = &gfa_cv;
uint64_t addr;
uint32_t size;
int rc;
core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list);
if (core)
device = core->device->hfi_device_data;
else
return;
if (!device) {
dprintk(CVP_ERR, "%s: NULL device\n", __func__);
return;
}
dprintk(CVP_DBG, "Entering %s\n", __func__);
mutex_lock(&device->lock);
mutex_lock(&me->lock);
addr = (uint64_t)device->dsp_iface_q_table.mem_data.dma_handle;
size = device->dsp_iface_q_table.mem_data.size;
if (!addr || !size) {
dprintk(CVP_DBG, "%s: HFI queue is not ready\n", __func__);
goto exit;
}
if (me->state != DSP_PROBED)
goto exit;
rc = cvp_hyp_assign_to_dsp(addr, size);
if (rc) {
dprintk(CVP_ERR, "%s: cvp_hyp_assign_to_dsp. rc=%d\n",
__func__, rc);
goto exit;
}
rc = cvp_dsp_send_cmd_hfi_queue((phys_addr_t *)addr, size);
if (rc) {
dprintk(CVP_WARN, "%s: Send HFI Queue failed rc = %d\n",
__func__, rc);
rc = cvp_hyp_assign_from_dsp();
goto exit;
}
dprintk(CVP_DBG, "%s: dsp initialized\n", __func__);
me->state = DSP_READY;
exit:
mutex_unlock(&me->lock);
mutex_unlock(&device->lock);
}
int cvp_dsp_device_init(void)
{
struct cvp_dsp_apps *me = &gfa_cv;
int err;
int rc;
int i;
if (me->cdsp_state == STATUS_DEINIT) {
mutex_init(&me->smd_mutex);
mutex_init(&me->reg_buffer_mutex);
mutex_init(&me->dereg_buffer_mutex);
init_completion(&me->shutdown_work);
init_completion(&me->reg_buffer_work);
init_completion(&me->dereg_buffer_work);
init_completion(&me->cmdqueue_send_work);
me->cvp_shutdown = STATUS_INIT;
me->cdsp_state = STATUS_INIT;
INIT_WORK(&me->ssr_work, msm_cvp_cdsp_ssr_handler);
err = register_rpmsg_driver(&cvp_dsp_rpmsg_client);
if (err) {
dprintk(CVP_ERR,
"%s : register_rpmsg failed with err %d\n",
__func__, err);
goto register_bail;
}
me->rpmsg_register = 1;
mutex_init(&me->lock);
me->state = DSP_INVALID;
me->hyp_assigned = false;
for (i = 0; i < CVP_DSP_MAX_CMD; i++)
init_completion(&me->completions[i]);
rc = register_rpmsg_driver(&cvp_dsp_rpmsg_client);
if (rc) {
dprintk(CVP_ERR,
"%s : register_rpmsg_driver failed rc = %d\n",
__func__, rc);
goto register_bail;
}
me->state = DSP_UNINIT;
return 0;
register_bail:
me->cvp_shutdown = STATUS_DEINIT;
me->cdsp_state = STATUS_DEINIT;
return err;
return rc;
}
void cvp_dsp_device_exit(void)
{
struct cvp_dsp_apps *me = &gfa_cv;
me->cvp_shutdown = STATUS_DEINIT;
me->cdsp_state = STATUS_DEINIT;
mutex_destroy(&me->smd_mutex);
mutex_destroy(&me->reg_buffer_mutex);
mutex_destroy(&me->dereg_buffer_mutex);
if (me->rpmsg_register == 1)
unregister_rpmsg_driver(&cvp_dsp_rpmsg_client);
mutex_lock(&me->lock);
me->state = DSP_INVALID;
mutex_unlock(&me->lock);
mutex_destroy(&me->lock);
unregister_rpmsg_driver(&cvp_dsp_rpmsg_client);
}

View file

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#ifndef MSM_CVP_DSP_H
@ -13,18 +13,48 @@
#define CVP_APPS_DSP_GLINK_GUID "cvp-glink-apps-dsp"
#define CVP_APPS_DSP_SMD_GUID "cvp-smd-apps-dsp"
/*
* API for CVP driver to send physical address to dsp driver
* @param phys_addr
* Physical address of command message queue
* that needs to be mapped to CDSP.
* It should be allocated from CMA adsp_mem region.
*
* @param size_in_bytes
* Size in bytes of command message queue
*/
int cvp_dsp_send_cmd_hfi_queue(phys_addr_t *phys_addr,
uint32_t size_in_bytes, struct iris_hfi_device *device);
#define VMID_CDSP_Q6 (30)
#define HLOS_VM_NUM 1
#define DSP_VM_NUM 2
#define CVP_DSP_MAX_RESERVED 5
#define CVP_DSP_RESPONSE_TIMEOUT 1000
int cvp_dsp_device_init(void);
void cvp_dsp_device_exit(void);
void cvp_dsp_send_hfi_queue(void);
enum DSP_COMMAND {
CVP_DSP_SEND_HFI_QUEUE = 0,
CVP_DSP_SUSPEND = 1,
CVP_DSP_RESUME = 2,
CVP_DSP_SHUTDOWN = 3,
CVP_DSP_REGISTER_BUFFER = 4,
CVP_DSP_DEREGISTER_BUFFER = 5,
CVP_DSP_MAX_CMD
};
struct cvp_dsp_cmd_msg {
uint32_t type;
int32_t ret;
uint64_t msg_ptr;
uint32_t msg_ptr_len;
uint32_t buff_fd_iova;
uint32_t buff_index;
uint32_t buff_size;
uint32_t session_id;
int32_t ddr_type;
uint32_t buff_fd;
uint32_t buff_offset;
uint32_t buff_fd_size;
uint32_t reserved1;
uint32_t reserved2;
};
struct cvp_dsp_rsp_msg {
uint32_t type;
int32_t ret;
uint32_t reserved[CVP_DSP_MAX_RESERVED];
};
/*
* API for CVP driver to suspend CVP session during
@ -53,13 +83,6 @@ int cvp_dsp_resume(uint32_t session_flag);
*/
int cvp_dsp_shutdown(uint32_t session_flag);
/*
* API for CVP driver to set CVP status during
* cvp subsystem error.
*
*/
void cvp_dsp_set_cvp_ssr(void);
/*
* API to register iova buffer address with CDSP
*
@ -92,15 +115,5 @@ int cvp_dsp_deregister_buffer(uint32_t session_id, uint32_t buff_fd,
uint32_t buff_offset, uint32_t buff_index,
uint32_t buff_fd_iova);
/*
* API to initialize CPU and DSP driver interface
*/
int cvp_dsp_device_init(void);
/*
* API to deinitilized CPU and DSP driver interface
*/
void cvp_dsp_device_exit(void);
#endif // MSM_CVP_DSP_H

View file

@ -44,10 +44,6 @@
#define SYS_MSG_INDEX(__msg) (__msg - SYS_MSG_START)
#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START)
#define call_core_op(c, op, args...) \
(((c) && (c)->core_ops && (c)->core_ops->op) ? \
((c)->core_ops->op(args)) : 0)
#define ARP_BUF_SIZE 0x100000
#define CVP_RT_PRIO_THRESHOLD 1
@ -76,6 +72,14 @@ enum instance_state {
MSM_CVP_CORE_INVALID
};
enum dsp_state {
DSP_INVALID,
DSP_UNINIT,
DSP_PROBED,
DSP_READY,
DSP_SUSPEND,
};
struct msm_cvp_list {
struct list_head list;
struct mutex lock;
@ -314,9 +318,7 @@ struct msm_cvp_core {
bool smmu_fault_handled;
u32 last_fault_addr;
bool trigger_ssr;
unsigned long min_freq;
unsigned long curr_freq;
struct msm_cvp_core_ops *core_ops;
atomic64_t kernel_trans_id;
};