nvadsp: Add multi-instance support

ADSP host driver is enhanced to be multi-instance
capable and reentrant:
 - Trailing unique identifier string in compatible DT property, like
    "adsp", "adsp1" or "aon", is used to identify the driver instances
 - Each probed driver instance is inserted into a global list, from
    which the handle can be fetched using 'nvadsp_get_handle' API
    (passing the above unique identifier as argument)
 - Above unique identifier is also used as name for the DBFS
    directory (containing files like adsp_console, adsp_logger, etc.)
 - 'nvadsp_get_handle' is the only exported API; all other APIs are
    accessible via function pointers within 'struct nvadsp_handle'
 - APIs above maintain one-is-to-one correspondence with all
    legacy APIs, with the addition of a new argument
    'struct nvadsp_handle *' at the beginning
 - Legacy APIs continue to be supported, but they are hardwired to
    work only if the kernel probes just one driver instance
 - All driver files are cleaned up to not use any global state
    variables (necessary for reentrancy)

Bug 3682950

Change-Id: Id5db49e861b2f81716ae8352b36b406654da2bbd
Signed-off-by: Viswanath L <viswanathl@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3092701
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
Reviewed-by: Dara Ramesh <dramesh@nvidia.com>
This commit is contained in:
Viswanath L
2024-03-08 21:07:39 +00:00
committed by mobile promotions
parent 9458d6b97f
commit e2a1904d46
17 changed files with 1332 additions and 862 deletions

View File

@@ -9,7 +9,7 @@ obj-m := nvadsp.o
nvadsp-objs += dev.o os.o app.o app_loader_linker.o\ nvadsp-objs += dev.o os.o app.o app_loader_linker.o\
amc.o nvadsp_shared_sema.o \ amc.o nvadsp_shared_sema.o \
hwmailbox.o mailbox.o msgq.o \ hwmailbox.o mailbox.o msgq.o \
mem_manager.o aram_manager.o dram_app_mem_manager.o \ mem_manager.o aram_manager.o \
acast.o adsp_console_dbfs.o acast.o adsp_console_dbfs.o
# T234/T239/T194/T186 # T234/T239/T194/T186

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/** /**
* Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2014-2024, NVIDIA CORPORATION. All rights reserved.
*/ */
#include <linux/module.h> #include <linux/module.h>
@@ -25,15 +25,9 @@
#define USE_RUN_APP_API #define USE_RUN_APP_API
static int open_cnt;
#define ADSP_APP_CTX_MAX 32
static uint64_t adsp_app_ctx_vals[ADSP_APP_CTX_MAX];
#define ACCESS_OK(addr, size) access_ok(addr, size) #define ACCESS_OK(addr, size) access_ok(addr, size)
static int adsp_app_ctx_add(uint64_t ctx) static int adsp_app_ctx_add(struct nvadsp_cnsl *console, uint64_t ctx)
{ {
int i; int i;
@@ -41,15 +35,15 @@ static int adsp_app_ctx_add(uint64_t ctx)
return -EINVAL; return -EINVAL;
for (i = 0; i < ADSP_APP_CTX_MAX; i++) { for (i = 0; i < ADSP_APP_CTX_MAX; i++) {
if (adsp_app_ctx_vals[i] == 0) { if (console->adsp_app_ctx_vals[i] == 0) {
adsp_app_ctx_vals[i] = ctx; console->adsp_app_ctx_vals[i] = ctx;
return 0; return 0;
} }
} }
return -EINVAL; return -EINVAL;
} }
static int adsp_app_ctx_check(uint64_t ctx) static int adsp_app_ctx_check(struct nvadsp_cnsl *console, uint64_t ctx)
{ {
int i; int i;
@@ -57,20 +51,20 @@ static int adsp_app_ctx_check(uint64_t ctx)
return -EINVAL; return -EINVAL;
for (i = 0; i < ADSP_APP_CTX_MAX; i++) { for (i = 0; i < ADSP_APP_CTX_MAX; i++) {
if (adsp_app_ctx_vals[i] == ctx) if (console->adsp_app_ctx_vals[i] == ctx)
return 0; return 0;
} }
return -EINVAL; return -EINVAL;
} }
static void adsp_app_ctx_remove(uint64_t ctx) static void adsp_app_ctx_remove(struct nvadsp_cnsl *console, uint64_t ctx)
{ {
int i; int i;
for (i = 0; i < ADSP_APP_CTX_MAX; i++) { for (i = 0; i < ADSP_APP_CTX_MAX; i++) {
if (adsp_app_ctx_vals[i] == ctx) { if (console->adsp_app_ctx_vals[i] == ctx) {
adsp_app_ctx_vals[i] = 0; console->adsp_app_ctx_vals[i] = 0;
return; return;
} }
} }
@@ -85,21 +79,23 @@ static int adsp_consol_open(struct inode *i, struct file *f)
struct device *dev = console->dev; struct device *dev = console->dev;
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev);
struct nvadsp_handle *nvadsp_handle = &drv_data->nvadsp_handle;
if (open_cnt) if (console->open_cnt)
return -EBUSY; return -EBUSY;
open_cnt++; console->open_cnt++;
ret = 0; ret = 0;
f->private_data = console; f->private_data = console;
if (!drv_data->adsp_os_running) if (!drv_data->adsp_os_running)
goto exit_open; goto exit_open;
ret = nvadsp_mbox_open(&console->shl_snd_mbox, &snd_mbox_id, ret = nvadsp_handle->mbox_open(nvadsp_handle,
&console->shl_snd_mbox, &snd_mbox_id,
"adsp_send_cnsl", NULL, NULL); "adsp_send_cnsl", NULL, NULL);
if (!ret) if (!ret)
goto exit_open; goto exit_open;
pr_err("adsp_consol: Failed to init adsp_consol send mailbox"); pr_err("adsp_consol: Failed to init adsp_consol send mailbox");
memset(&console->shl_snd_mbox, 0, sizeof(struct nvadsp_mbox)); memset(&console->shl_snd_mbox, 0, sizeof(struct nvadsp_mbox));
open_cnt--; console->open_cnt--;
exit_open: exit_open:
return ret; return ret;
} }
@@ -111,11 +107,12 @@ static int adsp_consol_close(struct inode *i, struct file *f)
struct device *dev = console->dev; struct device *dev = console->dev;
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev);
struct nvadsp_handle *nvadsp_handle = &drv_data->nvadsp_handle;
open_cnt--; console->open_cnt--;
if (!drv_data->adsp_os_running || (0 == mbox->id)) if (!drv_data->adsp_os_running || (0 == mbox->id))
goto exit_close; goto exit_close;
ret = nvadsp_mbox_close(mbox); ret = nvadsp_handle->mbox_close(nvadsp_handle, mbox);
if (ret) if (ret)
pr_err("adsp_consol: Failed to close adsp_consol send mailbox)"); pr_err("adsp_consol: Failed to close adsp_consol send mailbox)");
memset(mbox, 0, sizeof(struct nvadsp_mbox)); memset(mbox, 0, sizeof(struct nvadsp_mbox));
@@ -138,6 +135,7 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
struct device *dev = console->dev; struct device *dev = console->dev;
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev);
struct nvadsp_handle *nvadsp_handle = &drv_data->nvadsp_handle;
void __user *uarg = (void __user *)arg; void __user *uarg = (void __user *)arg;
if (_IOC_TYPE(cmd) != NV_ADSP_CONSOLE_MAGIC) if (_IOC_TYPE(cmd) != NV_ADSP_CONSOLE_MAGIC)
@@ -164,17 +162,17 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
break; break;
mbxid = 30; mbxid = 30;
mbox = &console->shl_snd_mbox; mbox = &console->shl_snd_mbox;
ret = nvadsp_os_load(); ret = nvadsp_handle->os_load(nvadsp_handle);
if (ret) { if (ret) {
dev_info(dev, "adsp_consol: Load OS Failed."); dev_info(dev, "adsp_consol: Load OS Failed.");
break; break;
} }
ret = nvadsp_os_start(); ret = nvadsp_handle->os_start(nvadsp_handle);
if (ret) { if (ret) {
dev_info(dev, "adsp_consol: Start OS Failed."); dev_info(dev, "adsp_consol: Start OS Failed.");
break; break;
} }
ret = nvadsp_mbox_open(mbox, &mbxid, ret = nvadsp_handle->mbox_open(nvadsp_handle, mbox, &mbxid,
"adsp_send_cnsl", NULL, NULL); "adsp_send_cnsl", NULL, NULL);
if (!ret) if (!ret)
break; break;
@@ -182,19 +180,19 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
memset(mbox, 0, sizeof(struct nvadsp_mbox)); memset(mbox, 0, sizeof(struct nvadsp_mbox));
break; break;
case _IOC_NR(ADSP_CNSL_SUSPEND): case _IOC_NR(ADSP_CNSL_SUSPEND):
ret = nvadsp_os_suspend(); ret = nvadsp_handle->os_suspend(nvadsp_handle);
if (ret) if (ret)
dev_info(dev, "adsp_consol: OS Suspend Failed."); dev_info(dev, "adsp_consol: OS Suspend Failed.");
break; break;
case _IOC_NR(ADSP_CNSL_STOP): case _IOC_NR(ADSP_CNSL_STOP):
nvadsp_os_stop(); nvadsp_handle->os_stop(nvadsp_handle);
break; break;
case _IOC_NR(ADSP_CNSL_RESUME): case _IOC_NR(ADSP_CNSL_RESUME):
if (!drv_data->adsp_os_suspended) { if (!drv_data->adsp_os_suspended) {
dev_info(dev, "adsp_consol: OS is not suspended to perform resume."); dev_info(dev, "adsp_consol: OS is not suspended to perform resume.");
break; break;
} }
ret = nvadsp_os_start(); ret = nvadsp_handle->os_start(nvadsp_handle);
if (ret) if (ret)
dev_info(dev, "adsp_consol: OS Resume Failed."); dev_info(dev, "adsp_consol: OS Resume Failed.");
break; break;
@@ -212,7 +210,8 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
app_args.app_name[NVADSP_NAME_SZ_MAX] = '\0'; app_args.app_name[NVADSP_NAME_SZ_MAX] = '\0';
#ifdef USE_RUN_APP_API #ifdef USE_RUN_APP_API
app_args.ctx2 = (uint64_t)nvadsp_run_app(NULL, app_args.ctx2 = (uint64_t)nvadsp_handle->run_app(
nvadsp_handle, NULL,
app_args.app_name, app_args.app_name,
(nvadsp_app_args_t *)&app_args.args[0], (nvadsp_app_args_t *)&app_args.args[0],
NULL, 0, app_args.core_id, true); NULL, 0, app_args.core_id, true);
@@ -221,13 +220,14 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
app_args.app_name); app_args.app_name);
return -EINVAL; return -EINVAL;
} }
if (adsp_app_ctx_add(app_args.ctx2)) { if (adsp_app_ctx_add(console, app_args.ctx2)) {
dev_info(dev, "adsp_consol: unable to add %s ctx\n", dev_info(dev, "adsp_consol: unable to add %s ctx\n",
app_args.app_name); app_args.app_name);
return -EINVAL; return -EINVAL;
} }
#else #else
app_args.ctx1 = (uint64_t)nvadsp_app_load(app_args.app_path, app_args.ctx1 = (uint64_t)nvadsp_handle->app_load(
nvadsp_handle, app_args.app_path,
app_args.app_name); app_args.app_name);
if (!app_args.ctx1) { if (!app_args.ctx1) {
dev_info(dev, dev_info(dev,
@@ -235,28 +235,28 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
app_args.app_name); app_args.app_name);
return -EINVAL; return -EINVAL;
} }
if (adsp_app_ctx_add(app_args.ctx1)) { if (adsp_app_ctx_add(console, app_args.ctx1)) {
dev_info(dev, "adsp_consol: unable to add %s ctx\n", dev_info(dev, "adsp_consol: unable to add %s ctx\n",
app_args.app_name); app_args.app_name);
return -EINVAL; return -EINVAL;
} }
dev_info(dev, "adsp_consol: calling nvadsp_app_init\n"); dev_info(dev, "adsp_consol: calling nvadsp_app_init\n");
app_args.ctx2 = app_args.ctx2 = (uint64_t)nvadsp_handle->app_init(
(uint64_t)nvadsp_app_init((void *)app_args.ctx1, NULL); nvadsp_handle, (void *)app_args.ctx1, NULL);
if (!app_args.ctx2) { if (!app_args.ctx2) {
dev_info(dev, dev_info(dev,
"adsp_consol: unable to initilize the app\n"); "adsp_consol: unable to initilize the app\n");
return -EINVAL; return -EINVAL;
} }
if (adsp_app_ctx_add(app_args.ctx2)) { if (adsp_app_ctx_add(console, app_args.ctx2)) {
dev_info(dev, "adsp_consol: unable to add %s ctx\n", dev_info(dev, "adsp_consol: unable to add %s ctx\n",
app_args.app_name); app_args.app_name);
return -EINVAL; return -EINVAL;
} }
dev_info(dev, "adsp_consol: calling nvadsp_app_start\n"); dev_info(dev, "adsp_consol: calling nvadsp_app_start\n");
ret = nvadsp_app_start((void *)app_args.ctx2); ret = nvadsp_handle->app_start(nvadsp_handle, (void *)app_args.ctx2);
if (ret) { if (ret) {
dev_info(dev, "adsp_consol: unable to start the app\n"); dev_info(dev, "adsp_consol: unable to start the app\n");
break; break;
@@ -281,7 +281,7 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
ret = -EACCES; ret = -EACCES;
break; break;
} }
if (adsp_app_ctx_check(app_args.ctx2)) { if (adsp_app_ctx_check(console, app_args.ctx2)) {
dev_info(dev, "adsp_consol: unable to check %s ctx\n", dev_info(dev, "adsp_consol: unable to check %s ctx\n",
app_args.app_name); app_args.app_name);
return -EINVAL; return -EINVAL;
@@ -290,28 +290,32 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
app_args.ctx1 = (uint64_t) app_args.ctx1 = (uint64_t)
((nvadsp_app_info_t *)app_args.ctx2)->handle; ((nvadsp_app_info_t *)app_args.ctx2)->handle;
nvadsp_exit_app((nvadsp_app_info_t *)app_args.ctx2, false); nvadsp_handle->exit_app(nvadsp_handle,
nvadsp_app_unload((const void *)app_args.ctx1); (nvadsp_app_info_t *)app_args.ctx2, false);
nvadsp_handle->app_unload(nvadsp_handle,
(const void *)app_args.ctx1);
adsp_app_ctx_remove(app_args.ctx2); adsp_app_ctx_remove(console, app_args.ctx2);
#else #else
if ((!app_args.ctx2) || (!app_args.ctx1)) { if ((!app_args.ctx2) || (!app_args.ctx1)) {
ret = -EACCES; ret = -EACCES;
break; break;
} }
if (adsp_app_ctx_check(app_args.ctx2) || if (adsp_app_ctx_check(console, app_args.ctx2) ||
adsp_app_ctx_check(app_args.ctx1)) { adsp_app_ctx_check(console, app_args.ctx1)) {
dev_info(dev, "adsp_consol: unable to check %s ctx\n", dev_info(dev, "adsp_consol: unable to check %s ctx\n",
app_args.app_name); app_args.app_name);
return -EINVAL; return -EINVAL;
} }
nvadsp_app_deinit((void *)app_args.ctx2); nvadsp_handle->app_deinit(nvadsp_handle,
nvadsp_app_unload((void *)app_args.ctx1); (void *)app_args.ctx2);
nvadsp_handle->nvadsp_app_unload(nvadsp_handle,
(void *)app_args.ctx1);
adsp_app_ctx_remove(app_args.ctx2); adsp_app_ctx_remove(console, app_args.ctx2);
adsp_app_ctx_remove(app_args.ctx1); adsp_app_ctx_remove(console, app_args.ctx1);
#endif #endif
break; break;
@@ -325,7 +329,7 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
ret = -EACCES; ret = -EACCES;
break; break;
} }
if (adsp_app_ctx_check(ctx2)) { if (adsp_app_ctx_check(console, ctx2)) {
dev_info(dev, "adsp_consol: unable to check ctx\n"); dev_info(dev, "adsp_consol: unable to check ctx\n");
return -EINVAL; return -EINVAL;
} }
@@ -338,7 +342,8 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
mbxid = *mid; mbxid = *mid;
} }
ret = nvadsp_mbox_open(&console->app_mbox, &mbxid, ret = nvadsp_handle->mbox_open(nvadsp_handle,
&console->app_mbox, &mbxid,
"app_mbox", NULL, NULL); "app_mbox", NULL, NULL);
if (ret) { if (ret) {
pr_err("adsp_consol: Failed to open app mailbox"); pr_err("adsp_consol: Failed to open app mailbox");
@@ -347,9 +352,10 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
break; break;
case _IOC_NR(ADSP_CNSL_CLOSE_MBX): case _IOC_NR(ADSP_CNSL_CLOSE_MBX):
mbox = &console->app_mbox; mbox = &console->app_mbox;
while (!nvadsp_mbox_recv(mbox, &data, 0, 0)) while (!nvadsp_handle->mbox_recv(nvadsp_handle,
mbox, &data, 0, 0))
; ;
ret = nvadsp_mbox_close(mbox); ret = nvadsp_handle->mbox_close(nvadsp_handle, mbox);
if (ret) if (ret)
break; break;
memset(mbox, 0, sizeof(struct nvadsp_mbox)); memset(mbox, 0, sizeof(struct nvadsp_mbox));
@@ -363,13 +369,15 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
ret = -EACCES; ret = -EACCES;
break; break;
} }
ret = nvadsp_mbox_send(&console->app_mbox, data, ret = nvadsp_handle->mbox_send(nvadsp_handle,
&console->app_mbox, data,
NVADSP_MBOX_SMSG, 0, 0); NVADSP_MBOX_SMSG, 0, 0);
break; break;
case _IOC_NR(ADSP_CNSL_GET_MBX): case _IOC_NR(ADSP_CNSL_GET_MBX):
if (!ACCESS_OK(uarg, sizeof(uint32_t))) if (!ACCESS_OK(uarg, sizeof(uint32_t)))
return -EACCES; return -EACCES;
ret = nvadsp_mbox_recv(&console->app_mbox, &data, 0, 0); ret = nvadsp_handle->mbox_recv(nvadsp_handle,
&console->app_mbox, &data, 0, 0);
if (ret) if (ret)
break; break;
ret = copy_to_user(uarg, &data, ret = copy_to_user(uarg, &data,
@@ -385,7 +393,8 @@ adsp_consol_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
ret = -EACCES; ret = -EACCES;
break; break;
} }
return nvadsp_mbox_send(&console->shl_snd_mbox, data, return nvadsp_handle->mbox_send(nvadsp_handle,
&console->shl_snd_mbox, data,
NVADSP_MBOX_SMSG, 0, 0); NVADSP_MBOX_SMSG, 0, 0);
break; break;
default: default:

View File

@@ -1,15 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/** /**
* Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2014-2024, NVIDIA CORPORATION. All rights reserved.
*/ */
#ifndef ADSP_CNSL_DBFS_H #ifndef ADSP_CNSL_DBFS_H
#define ADSP_CNSL_DBFS_H #define ADSP_CNSL_DBFS_H
#define ADSP_APP_CTX_MAX 32
struct nvadsp_cnsl { struct nvadsp_cnsl {
struct device *dev; struct device *dev;
struct nvadsp_mbox shl_snd_mbox; struct nvadsp_mbox shl_snd_mbox;
struct nvadsp_mbox app_mbox; struct nvadsp_mbox app_mbox;
int open_cnt;
uint64_t adsp_app_ctx_vals[ADSP_APP_CTX_MAX];
}; };
int int

View File

@@ -10,19 +10,17 @@
#include "dev.h" #include "dev.h"
#include "amc.h" #include "amc.h"
static struct platform_device *nvadsp_pdev; static inline u32 amc_readl(struct nvadsp_drv_data *drv, u32 reg)
static struct nvadsp_drv_data *nvadsp_drv_data;
static inline u32 amc_readl(u32 reg)
{ {
return readl(nvadsp_drv_data->base_regs[AMC] + reg); return readl(drv->base_regs[AMC] + reg);
} }
static inline void amc_writel(u32 val, u32 reg) static inline void amc_writel(struct nvadsp_drv_data *drv, u32 val, u32 reg)
{ {
writel(val, nvadsp_drv_data->base_regs[AMC] + reg); writel(val, drv->base_regs[AMC] + reg);
} }
#ifdef CONFIG_AMC_SAVE_RESTORE
static void wmemcpy_to_aram(u32 to_aram, const u32 *from_mem, size_t wlen) static void wmemcpy_to_aram(u32 to_aram, const u32 *from_mem, size_t wlen)
{ {
u32 base, offset; u32 base, offset;
@@ -116,20 +114,23 @@ int nvadsp_amc_restore(struct platform_device *pdev)
return 0; return 0;
} }
#endif /* CONFIG_AMC_SAVE_RESTORE */
static irqreturn_t nvadsp_amc_error_int_handler(int irq, void *devid) static irqreturn_t nvadsp_amc_error_int_handler(int irq, void *devid)
{ {
struct platform_device *pdev = devid;
struct nvadsp_drv_data *drv = platform_get_drvdata(pdev);
u32 val, addr, status, intr = 0; u32 val, addr, status, intr = 0;
status = amc_readl(AMC_INT_STATUS); status = amc_readl(drv, AMC_INT_STATUS);
addr = amc_readl(AMC_ERROR_ADDR); addr = amc_readl(drv, AMC_ERROR_ADDR);
if (status & AMC_INT_STATUS_ARAM) { if (status & AMC_INT_STATUS_ARAM) {
/* /*
* Ignore addresses lesser than AMC_ERROR_ADDR_IGNORE (4k) * Ignore addresses lesser than AMC_ERROR_ADDR_IGNORE (4k)
* as those are spurious ones due a hardware issue. * as those are spurious ones due a hardware issue.
*/ */
if (!(nvadsp_drv_data->chip_data->amc_err_war) || if (!(drv->chip_data->amc_err_war) ||
(addr > AMC_ERROR_ADDR_IGNORE)) (addr > AMC_ERROR_ADDR_IGNORE))
pr_info("nvadsp: invalid ARAM access. address: 0x%x\n", pr_info("nvadsp: invalid ARAM access. address: 0x%x\n",
addr); addr);
@@ -143,9 +144,9 @@ static irqreturn_t nvadsp_amc_error_int_handler(int irq, void *devid)
intr |= AMC_INT_INVALID_REG_ACCESS; intr |= AMC_INT_INVALID_REG_ACCESS;
} }
val = amc_readl(AMC_INT_CLR); val = amc_readl(drv, AMC_INT_CLR);
val |= intr; val |= intr;
amc_writel(val, AMC_INT_CLR); amc_writel(drv, val, AMC_INT_CLR);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@@ -154,13 +155,10 @@ void nvadsp_free_amc_interrupts(struct platform_device *pdev)
{ {
struct nvadsp_drv_data *drv = platform_get_drvdata(pdev); struct nvadsp_drv_data *drv = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *node;
if (drv->chip_data->amc_not_avlbl) if (drv->chip_data->amc_not_avlbl)
return; return;
node = dev->of_node;
if (!is_tegra_hypervisor_mode()) if (!is_tegra_hypervisor_mode())
devm_free_irq(dev, drv->agic_irqs[AMC_ERR_VIRQ], pdev); devm_free_irq(dev, drv->agic_irqs[AMC_ERR_VIRQ], pdev);
} }
@@ -169,16 +167,11 @@ int nvadsp_setup_amc_interrupts(struct platform_device *pdev)
{ {
struct nvadsp_drv_data *drv = platform_get_drvdata(pdev); struct nvadsp_drv_data *drv = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *node;
int ret = 0; int ret = 0;
if (drv->chip_data->amc_not_avlbl) if (drv->chip_data->amc_not_avlbl)
return ret; return ret;
node = dev->of_node;
nvadsp_pdev = pdev;
nvadsp_drv_data = drv;
if (!is_tegra_hypervisor_mode()) if (!is_tegra_hypervisor_mode())
ret = devm_request_irq(dev, drv->agic_irqs[AMC_ERR_VIRQ], ret = devm_request_irq(dev, drv->agic_irqs[AMC_ERR_VIRQ],
nvadsp_amc_error_int_handler, 0, nvadsp_amc_error_int_handler, 0,

View File

@@ -50,9 +50,8 @@ struct nvadsp_app_priv_struct {
#endif #endif
}; };
static struct nvadsp_app_priv_struct priv; static void delete_app_instance(struct nvadsp_app_priv_struct *,
nvadsp_app_info_t *);
static void delete_app_instance(nvadsp_app_info_t *);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
static int dump_binary_in_2bytes_app_file_node(struct seq_file *s, void *data) static int dump_binary_in_2bytes_app_file_node(struct seq_file *s, void *data)
@@ -219,17 +218,18 @@ ADSP_APP_FILE_OPERATION(dram_shared_wc);
ADSP_APP_FILE_OPERATION(aram); ADSP_APP_FILE_OPERATION(aram);
ADSP_APP_FILE_OPERATION(aram_exclusive); ADSP_APP_FILE_OPERATION(aram_exclusive);
static int create_adsp_app_debugfs(struct nvadsp_app_service *ser) static int create_adsp_app_debugfs(struct nvadsp_app_priv_struct *priv,
struct nvadsp_app_service *ser)
{ {
struct app_mem_size *mem_size = (struct app_mem_size *)ser->mem_size; struct app_mem_size *mem_size = (struct app_mem_size *)ser->mem_size;
struct device *dev = &priv.pdev->dev; struct device *dev = &priv->pdev->dev;
struct dentry *instance_mem_sizes; struct dentry *instance_mem_sizes;
struct dentry *root; struct dentry *root;
int ret = 0; int ret = 0;
root = debugfs_create_dir(ser->name, root = debugfs_create_dir(ser->name,
priv.adsp_app_debugfs_root); priv->adsp_app_debugfs_root);
if (IS_ERR_OR_NULL(root)) { if (IS_ERR_OR_NULL(root)) {
ret = -EINVAL; ret = -EINVAL;
goto err_out; goto err_out;
@@ -256,19 +256,27 @@ err_out:
return ret; return ret;
} }
static int __init adsp_app_debug_init(struct dentry *root) static int __init adsp_app_debug_init(struct nvadsp_app_priv_struct *priv,
struct dentry *root)
{ {
priv.adsp_app_debugfs_root = debugfs_create_dir("adsp_apps", root); priv->adsp_app_debugfs_root = debugfs_create_dir("adsp_apps", root);
return IS_ERR_OR_NULL(priv.adsp_app_debugfs_root) ? -ENOMEM : 0; return IS_ERR_OR_NULL(priv->adsp_app_debugfs_root) ? -ENOMEM : 0;
} }
#endif /* CONFIG_DEBUG_FS */ #endif /* CONFIG_DEBUG_FS */
static struct nvadsp_app_service *get_loaded_service(const char *appfile) static void _nvadsp_set_app_complete_cb(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *info, app_complete_status_notifier notifier)
{ {
struct device *dev = &priv.pdev->dev; info->complete_status_notifier = notifier;
}
static struct nvadsp_app_service *get_loaded_service(
struct nvadsp_app_priv_struct *priv, const char *appfile)
{
struct device *dev = &priv->pdev->dev;
struct nvadsp_app_service *ser; struct nvadsp_app_service *ser;
list_for_each_entry(ser, &priv.service_list, node) { list_for_each_entry(ser, &priv->service_list, node) {
if (!strcmp(appfile, ser->name)) { if (!strcmp(appfile, ser->name)) {
dev_dbg(dev, "module %s already loaded\n", appfile); dev_dbg(dev, "module %s already loaded\n", appfile);
return ser; return ser;
@@ -287,18 +295,18 @@ static inline void extract_appname(char *appname, const char *appfile)
appname[len] = '\0'; appname[len] = '\0';
} }
static nvadsp_app_handle_t app_load(const char *appfile, static nvadsp_app_handle_t app_load(struct nvadsp_app_priv_struct *priv,
struct adsp_shared_app *shared_app, bool dynamic) const char *appfile, struct adsp_shared_app *shared_app, bool dynamic)
{ {
struct nvadsp_drv_data *drv_data; struct nvadsp_drv_data *drv_data;
struct device *dev = &priv.pdev->dev; struct device *dev = &priv->pdev->dev;
char appname[NVADSP_NAME_SZ] = { }; char appname[NVADSP_NAME_SZ] = { };
struct nvadsp_app_service *ser; struct nvadsp_app_service *ser;
drv_data = platform_get_drvdata(priv.pdev); drv_data = platform_get_drvdata(priv->pdev);
extract_appname(appname, appfile); extract_appname(appname, appfile);
mutex_lock(&priv.service_lock_list); mutex_lock(&priv->service_lock_list);
ser = get_loaded_service(appname); ser = get_loaded_service(priv, appname);
if (!ser) { if (!ser) {
/* dynamic loading is disabled when running in secure mode */ /* dynamic loading is disabled when running in secure mode */
@@ -329,78 +337,85 @@ static nvadsp_app_handle_t app_load(const char *appfile,
INIT_LIST_HEAD(&ser->app_head); INIT_LIST_HEAD(&ser->app_head);
/* add the app instance service to the list */ /* add the app instance service to the list */
list_add_tail(&ser->node, &priv.service_list); list_add_tail(&ser->node, &priv->service_list);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
create_adsp_app_debugfs(ser); create_adsp_app_debugfs(priv, ser);
#endif #endif
dev_dbg(dev, "loaded app %s\n", ser->name); dev_dbg(dev, "loaded app %s\n", ser->name);
} }
mutex_unlock(&priv.service_lock_list); mutex_unlock(&priv->service_lock_list);
return ser; return ser;
err_free_service: err_free_service:
devm_kfree(dev, ser); devm_kfree(dev, ser);
err: err:
mutex_unlock(&priv.service_lock_list); mutex_unlock(&priv->service_lock_list);
return NULL; return NULL;
} }
static nvadsp_app_handle_t _nvadsp_app_load(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_handle_t nvadsp_app_load(const char *appname, const char *appfile) const char *appname, const char *appfile)
{ {
struct nvadsp_drv_data *drv_data; struct nvadsp_drv_data *drv_data =
(struct nvadsp_drv_data *)nvadsp_handle;
if (IS_ERR_OR_NULL(priv.pdev)) { if (!drv_data || !drv_data->pdev || !drv_data->app_priv) {
pr_err("ADSP Driver is not initialized\n"); pr_err("ADSP Driver is not initialized\n");
return NULL; return NULL;
} }
drv_data = platform_get_drvdata(priv.pdev);
if (!drv_data->adsp_os_running) if (!drv_data->adsp_os_running)
return NULL; return NULL;
return app_load(appfile, NULL, true); return app_load(drv_data->app_priv, appfile, NULL, true);
} }
EXPORT_SYMBOL(nvadsp_app_load);
static void free_instance_memory(nvadsp_app_info_t *app, static void free_instance_memory(struct nvadsp_app_priv_struct *priv,
const struct app_mem_size *sz) nvadsp_app_info_t *app, const struct app_mem_size *sz)
{ {
adsp_app_mem_t *mem = &app->mem; adsp_app_mem_t *mem = &app->mem;
adsp_app_iova_mem_t *iova_mem = &app->iova_mem; adsp_app_iova_mem_t *iova_mem = &app->iova_mem;
struct nvadsp_drv_data *drv_data;
struct nvadsp_handle *nvadsp_handle;
drv_data = platform_get_drvdata(priv->pdev);
nvadsp_handle = &drv_data->nvadsp_handle;
if (mem->dram) { if (mem->dram) {
nvadsp_free_coherent(sz->dram, mem->dram, iova_mem->dram); nvadsp_handle->free_coherent(nvadsp_handle,
sz->dram, mem->dram, iova_mem->dram);
mem->dram = NULL; mem->dram = NULL;
iova_mem->dram = 0; iova_mem->dram = 0;
} }
if (mem->shared) { if (mem->shared) {
nvadsp_free_coherent(sz->dram_shared, mem->shared, nvadsp_handle->free_coherent(nvadsp_handle,
sz->dram_shared, mem->shared,
iova_mem->shared); iova_mem->shared);
mem->shared = NULL; mem->shared = NULL;
iova_mem->shared = 0; iova_mem->shared = 0;
} }
if (mem->shared_wc) { if (mem->shared_wc) {
nvadsp_free_coherent(sz->dram_shared_wc, mem->shared_wc, nvadsp_handle->free_coherent(nvadsp_handle,
sz->dram_shared_wc, mem->shared_wc,
iova_mem->shared_wc); iova_mem->shared_wc);
mem->shared_wc = NULL; mem->shared_wc = NULL;
iova_mem->shared_wc = 0; iova_mem->shared_wc = 0;
} }
if (mem->aram_flag) if (mem->aram_flag)
nvadsp_aram_release(mem->aram); nvadsp_aram_release(drv_data->aram_handle, mem->aram);
else if (mem->aram) else if (mem->aram)
nvadsp_free_coherent(sz->aram, mem->aram, iova_mem->aram); nvadsp_handle->free_coherent(nvadsp_handle,
sz->aram, mem->aram, iova_mem->aram);
mem->aram = NULL; mem->aram = NULL;
iova_mem->aram = 0; iova_mem->aram = 0;
mem->aram_flag = 0; mem->aram_flag = 0;
if (mem->aram_x_flag) { if (mem->aram_x_flag) {
nvadsp_aram_release(mem->aram_x); nvadsp_aram_release(drv_data->aram_handle, mem->aram_x);
mem->aram_x = NULL; mem->aram_x = NULL;
iova_mem->aram_x = 0; iova_mem->aram_x = 0;
mem->aram_flag = 0; mem->aram_flag = 0;
@@ -408,12 +423,14 @@ static void free_instance_memory(nvadsp_app_info_t *app,
} }
static int create_instance_memory(nvadsp_app_info_t *app, static int create_instance_memory(struct nvadsp_app_priv_struct *priv,
const struct app_mem_size *sz) nvadsp_app_info_t *app, const struct app_mem_size *sz)
{ {
adsp_app_iova_mem_t *iova_mem = &app->iova_mem; adsp_app_iova_mem_t *iova_mem = &app->iova_mem;
struct device *dev = &priv.pdev->dev; struct device *dev = &priv->pdev->dev;
adsp_app_mem_t *mem = &app->mem; adsp_app_mem_t *mem = &app->mem;
struct nvadsp_drv_data *drv_data;
struct nvadsp_handle *nvadsp_handle;
char name[NVADSP_NAME_SZ]; char name[NVADSP_NAME_SZ];
void *aram_handle; void *aram_handle;
dma_addr_t da; dma_addr_t da;
@@ -425,8 +442,12 @@ static int create_instance_memory(nvadsp_app_info_t *app,
return -EINVAL; return -EINVAL;
} }
drv_data = platform_get_drvdata(priv->pdev);
nvadsp_handle = &drv_data->nvadsp_handle;
if (sz->dram) { if (sz->dram) {
mem->dram = nvadsp_alloc_coherent(sz->dram, &da, GFP_KERNEL); mem->dram = nvadsp_handle->alloc_coherent(nvadsp_handle,
sz->dram, &da, GFP_KERNEL);
iova_mem->dram = (uint32_t)da; iova_mem->dram = (uint32_t)da;
if (!mem->dram) { if (!mem->dram) {
dev_err(dev, "app %s dram alloc failed\n", dev_err(dev, "app %s dram alloc failed\n",
@@ -438,8 +459,8 @@ static int create_instance_memory(nvadsp_app_info_t *app,
} }
if (sz->dram_shared) { if (sz->dram_shared) {
mem->shared = nvadsp_alloc_coherent(sz->dram_shared, mem->shared = nvadsp_handle->alloc_coherent(nvadsp_handle,
&da, GFP_KERNEL); sz->dram_shared, &da, GFP_KERNEL);
if (!mem->shared) { if (!mem->shared) {
dev_err(dev, "app %s shared dram alloc failed\n", dev_err(dev, "app %s shared dram alloc failed\n",
name); name);
@@ -451,8 +472,8 @@ static int create_instance_memory(nvadsp_app_info_t *app,
} }
if (sz->dram_shared_wc) { if (sz->dram_shared_wc) {
mem->shared_wc = nvadsp_alloc_coherent(sz->dram_shared_wc, mem->shared_wc = nvadsp_handle->alloc_coherent(nvadsp_handle,
&da, GFP_KERNEL); sz->dram_shared_wc, &da, GFP_KERNEL);
if (!mem->shared_wc) { if (!mem->shared_wc) {
dev_err(dev, "app %s shared dram wc alloc failed\n", dev_err(dev, "app %s shared dram wc alloc failed\n",
name); name);
@@ -464,7 +485,8 @@ static int create_instance_memory(nvadsp_app_info_t *app,
} }
if (sz->aram) { if (sz->aram) {
aram_handle = nvadsp_aram_request(name, sz->aram); aram_handle = nvadsp_aram_request(drv_data->aram_handle,
name, sz->aram);
if (!IS_ERR_OR_NULL(aram_handle)) { if (!IS_ERR_OR_NULL(aram_handle)) {
iova_mem->aram = nvadsp_aram_get_address(aram_handle); iova_mem->aram = nvadsp_aram_get_address(aram_handle);
mem->aram = aram_handle; mem->aram = aram_handle;
@@ -473,7 +495,8 @@ static int create_instance_memory(nvadsp_app_info_t *app,
} else { } else {
dev_dbg(dev, "app %s no ARAM memory ! using DRAM\n", dev_dbg(dev, "app %s no ARAM memory ! using DRAM\n",
name); name);
mem->aram = nvadsp_alloc_coherent(sz->aram, mem->aram = nvadsp_handle->alloc_coherent(
nvadsp_handle, sz->aram,
&da, GFP_KERNEL); &da, GFP_KERNEL);
if (!mem->aram) { if (!mem->aram) {
iova_mem->aram_flag = mem->aram_flag = 0; iova_mem->aram_flag = mem->aram_flag = 0;
@@ -489,7 +512,8 @@ static int create_instance_memory(nvadsp_app_info_t *app,
} }
if (sz->aram_x) { if (sz->aram_x) {
aram_handle = nvadsp_aram_request(name, sz->aram); aram_handle = nvadsp_aram_request(drv_data->aram_handle,
name, sz->aram);
if (!IS_ERR_OR_NULL(aram_handle)) { if (!IS_ERR_OR_NULL(aram_handle)) {
iova_mem->aram_x = nvadsp_aram_get_address(aram_handle); iova_mem->aram_x = nvadsp_aram_get_address(aram_handle);
mem->aram_x = aram_handle; mem->aram_x = aram_handle;
@@ -505,7 +529,7 @@ static int create_instance_memory(nvadsp_app_info_t *app,
return 0; return 0;
end: end:
free_instance_memory(app, sz); free_instance_memory(priv, app, sz);
return -ENOMEM; return -ENOMEM;
} }
@@ -538,14 +562,17 @@ static void fill_app_instance_data(nvadsp_app_info_t *app,
memcpy(&data->mem_size, ser->mem_size, sizeof(struct app_mem_size)); memcpy(&data->mem_size, ser->mem_size, sizeof(struct app_mem_size));
} }
static nvadsp_app_info_t *create_app_instance(nvadsp_app_handle_t handle, static nvadsp_app_info_t *create_app_instance(
struct nvadsp_app_priv_struct *priv, nvadsp_app_handle_t handle,
nvadsp_app_args_t *app_args, struct run_app_instance_data *data, nvadsp_app_args_t *app_args, struct run_app_instance_data *data,
app_complete_status_notifier notifier, uint32_t stack_size, app_complete_status_notifier notifier, uint32_t stack_size,
uint32_t core_id) uint32_t core_id)
{ {
struct nvadsp_app_service *ser = (void *)handle; struct nvadsp_app_service *ser = (void *)handle;
struct device *dev = &priv.pdev->dev; struct device *dev = &priv->pdev->dev;
nvadsp_app_info_t *app; nvadsp_app_info_t *app;
struct nvadsp_drv_data *drv_data;
struct nvadsp_handle *nvadsp_handle;
int *state; int *state;
int *id; int *id;
@@ -565,8 +592,11 @@ static nvadsp_app_info_t *create_app_instance(nvadsp_app_handle_t handle,
*/ */
app->handle = ser; app->handle = ser;
drv_data = platform_get_drvdata(priv->pdev);
nvadsp_handle = &drv_data->nvadsp_handle;
/* create the instance memory required by the app instance */ /* create the instance memory required by the app instance */
if (create_instance_memory(app, ser->mem_size)) { if (create_instance_memory(priv, app, ser->mem_size)) {
dev_err(dev, "instance creation failed for app %s:%d\n", dev_err(dev, "instance creation failed for app %s:%d\n",
app->name, app->instance_id); app->name, app->instance_id);
goto free_app; goto free_app;
@@ -591,7 +621,7 @@ static nvadsp_app_info_t *create_app_instance(nvadsp_app_handle_t handle,
init_completion(&app->wait_for_app_start); init_completion(&app->wait_for_app_start);
init_completion(&app->wait_for_app_complete); init_completion(&app->wait_for_app_complete);
set_app_complete_notifier(app, notifier); _nvadsp_set_app_complete_cb(nvadsp_handle, app, notifier);
dev_dbg(dev, "app %s instance %d initilized\n", dev_dbg(dev, "app %s instance %d initilized\n",
app->name, app->instance_id); app->name, app->instance_id);
@@ -606,25 +636,27 @@ end:
return app; return app;
} }
nvadsp_app_info_t __must_check *nvadsp_app_init(nvadsp_app_handle_t handle, static nvadsp_app_info_t *_nvadsp_app_init(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_args_t *args) nvadsp_app_handle_t handle, nvadsp_app_args_t *args)
{ {
struct nvadsp_app_shared_msg_pool *msg_pool; struct nvadsp_app_shared_msg_pool *msg_pool;
struct nvadsp_shared_mem *shared_mem; struct nvadsp_shared_mem *shared_mem;
union app_loader_message *message; union app_loader_message *message;
struct nvadsp_drv_data *drv_data; struct nvadsp_drv_data *drv_data =
(struct nvadsp_drv_data *)nvadsp_handle;
struct nvadsp_app_priv_struct *priv;
struct app_loader_data *data; struct app_loader_data *data;
nvadsp_app_info_t *app; nvadsp_app_info_t *app;
msgq_t *msgq_send; msgq_t *msgq_send;
int *state; int *state;
unsigned long flags, ret = 0; unsigned long flags, ret = 0;
if (IS_ERR_OR_NULL(priv.pdev)) { if (!drv_data || !drv_data->pdev || !drv_data->app_priv) {
pr_err("ADSP Driver is not initialized\n"); pr_err("ADSP Driver is not initialized\n");
goto err; goto err;
} }
drv_data = platform_get_drvdata(priv.pdev); priv = drv_data->app_priv;
if (!drv_data->adsp_os_running) { if (!drv_data->adsp_os_running) {
pr_err("ADSP is not running\n"); pr_err("ADSP is not running\n");
@@ -648,7 +680,8 @@ nvadsp_app_info_t __must_check *nvadsp_app_init(nvadsp_app_handle_t handle,
data = &message->data; data = &message->data;
/* Pinning app to core 0 by default */ /* Pinning app to core 0 by default */
app = create_app_instance(handle, args, &data->app_init, NULL, 0, 0); app = create_app_instance(drv_data->app_priv, handle,
args, &data->app_init, NULL, 0, 0);
if (IS_ERR_OR_NULL(app)) { if (IS_ERR_OR_NULL(app)) {
pr_err("Failed to create APP instance\n"); pr_err("Failed to create APP instance\n");
kfree(message); kfree(message);
@@ -668,12 +701,13 @@ nvadsp_app_info_t __must_check *nvadsp_app_init(nvadsp_app_handle_t handle,
*state = NVADSP_APP_STATE_STARTED; *state = NVADSP_APP_STATE_STARTED;
} }
nvadsp_mbox_send(&priv.mbox, 0, NVADSP_MBOX_SMSG, false, 0); nvadsp_handle->mbox_send(nvadsp_handle, &priv->mbox,
0, NVADSP_MBOX_SMSG, false, 0);
ret = wait_for_completion_timeout(&app->wait_for_app_start, ret = wait_for_completion_timeout(&app->wait_for_app_start,
msecs_to_jiffies(ADSP_APP_INIT_TIMEOUT)); msecs_to_jiffies(ADSP_APP_INIT_TIMEOUT));
if (!ret) { if (!ret) {
delete_app_instance(app); delete_app_instance(drv_data->app_priv, app);
return NULL; return NULL;
} }
init_completion(&app->wait_for_app_start); init_completion(&app->wait_for_app_start);
@@ -681,20 +715,23 @@ nvadsp_app_info_t __must_check *nvadsp_app_init(nvadsp_app_handle_t handle,
err: err:
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
EXPORT_SYMBOL(nvadsp_app_init);
static int start_app_on_adsp(nvadsp_app_info_t *app, static int start_app_on_adsp(struct nvadsp_app_priv_struct *priv,
nvadsp_app_info_t *app,
union app_loader_message *message, bool block) union app_loader_message *message, bool block)
{ {
struct nvadsp_app_shared_msg_pool *msg_pool; struct nvadsp_app_shared_msg_pool *msg_pool;
struct device *dev = &priv.pdev->dev; struct device *dev = &priv->pdev->dev;
struct nvadsp_shared_mem *shared_mem; struct nvadsp_shared_mem *shared_mem;
struct nvadsp_drv_data *drv_data;
msgq_t *msgq_send; msgq_t *msgq_send;
struct nvadsp_drv_data *drv_data;
struct nvadsp_handle *nvadsp_handle;
int *state; int *state;
unsigned long flags; unsigned long flags;
drv_data = platform_get_drvdata(priv.pdev); drv_data = platform_get_drvdata(priv->pdev);
nvadsp_handle = &drv_data->nvadsp_handle;
shared_mem = drv_data->shared_adsp_os_data; shared_mem = drv_data->shared_adsp_os_data;
msg_pool = &shared_mem->app_shared_msg_pool; msg_pool = &shared_mem->app_shared_msg_pool;
msgq_send = &msg_pool->app_loader_send_message.msgq; msgq_send = &msg_pool->app_loader_send_message.msgq;
@@ -708,7 +745,8 @@ static int start_app_on_adsp(nvadsp_app_info_t *app,
state = (int *)&app->state; state = (int *)&app->state;
*state = NVADSP_APP_STATE_STARTED; *state = NVADSP_APP_STATE_STARTED;
nvadsp_mbox_send(&priv.mbox, 0, NVADSP_MBOX_SMSG, false, 0); nvadsp_handle->mbox_send(nvadsp_handle, &priv->mbox,
0, NVADSP_MBOX_SMSG, false, 0);
if (block) { if (block) {
wait_for_completion(&app->wait_for_app_start); wait_for_completion(&app->wait_for_app_start);
@@ -723,56 +761,58 @@ static int start_app_on_adsp(nvadsp_app_info_t *app,
return app->return_status; return app->return_status;
} }
int nvadsp_app_start(nvadsp_app_info_t *app) static int _nvadsp_app_start(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *app)
{ {
union app_loader_message *message = app->priv; union app_loader_message *message = app->priv;
struct app_loader_data *data = &message->data; struct app_loader_data *data = &message->data;
struct nvadsp_drv_data *drv_data; struct nvadsp_drv_data *drv_data =
(struct nvadsp_drv_data *)nvadsp_handle;
int ret = -EINVAL; int ret = -EINVAL;
if (IS_ERR_OR_NULL(app)) if (IS_ERR_OR_NULL(app))
return -EINVAL; return -EINVAL;
if (IS_ERR_OR_NULL(priv.pdev)) { if (!drv_data || !drv_data->pdev || !drv_data->app_priv) {
pr_err("ADSP Driver is not initialized\n"); pr_err("ADSP Driver is not initialized\n");
goto err; goto err;
} }
drv_data = platform_get_drvdata(priv.pdev);
if (!drv_data->adsp_os_running) if (!drv_data->adsp_os_running)
goto err; goto err;
data->app_init.message = ADSP_APP_START; data->app_init.message = ADSP_APP_START;
data->app_init.adsp_ref = app->token; data->app_init.adsp_ref = app->token;
data->app_init.stack_size = app->stack_size; data->app_init.stack_size = app->stack_size;
ret = start_app_on_adsp(app, app->priv, true); ret = start_app_on_adsp(drv_data->app_priv, app, app->priv, true);
err: err:
return ret; return ret;
} }
EXPORT_SYMBOL(nvadsp_app_start);
nvadsp_app_info_t *nvadsp_run_app(nvadsp_os_handle_t os_handle, static nvadsp_app_info_t *_nvadsp_run_app(struct nvadsp_handle *nvadsp_handle,
nvadsp_os_handle_t os_handle,
const char *appfile, nvadsp_app_args_t *app_args, const char *appfile, nvadsp_app_args_t *app_args,
app_complete_status_notifier notifier, uint32_t stack_sz, app_complete_status_notifier notifier, uint32_t stack_sz,
uint32_t core_id, bool block) uint32_t core_id, bool block)
{ {
union app_loader_message message = {}; union app_loader_message message = {};
nvadsp_app_handle_t service_handle; nvadsp_app_handle_t service_handle;
struct nvadsp_drv_data *drv_data; struct nvadsp_drv_data *drv_data =
(struct nvadsp_drv_data *)nvadsp_handle;
struct nvadsp_app_priv_struct *priv;
nvadsp_app_info_t *info = NULL; nvadsp_app_info_t *info = NULL;
struct app_loader_data *data; struct app_loader_data *data;
struct device *dev; struct device *dev;
int ret; int ret;
if (IS_ERR_OR_NULL(priv.pdev)) { if (!drv_data || !drv_data->pdev || !drv_data->app_priv) {
pr_err("ADSP Driver is not initialized\n"); pr_err("ADSP Driver is not initialized\n");
info = ERR_PTR(-EINVAL); info = ERR_PTR(-EINVAL);
goto end; goto end;
} }
drv_data = platform_get_drvdata(priv.pdev); priv = drv_data->app_priv;
dev = &priv.pdev->dev; dev = &priv->pdev->dev;
if (!drv_data->adsp_os_running) if (!drv_data->adsp_os_running)
goto end; goto end;
@@ -781,13 +821,13 @@ nvadsp_app_info_t *nvadsp_run_app(nvadsp_os_handle_t os_handle,
goto end; goto end;
data = &message.data; data = &message.data;
service_handle = app_load(appfile, NULL, true); service_handle = app_load(priv, appfile, NULL, true);
if (!service_handle) { if (!service_handle) {
dev_err(dev, "unable to load the app %s\n", appfile); dev_err(dev, "unable to load the app %s\n", appfile);
goto end; goto end;
} }
info = create_app_instance(service_handle, app_args, info = create_app_instance(priv, service_handle, app_args,
&data->app_init, notifier, stack_sz, core_id); &data->app_init, notifier, stack_sz, core_id);
if (IS_ERR_OR_NULL(info)) { if (IS_ERR_OR_NULL(info)) {
dev_err(dev, "unable to create instance for app %s\n", appfile); dev_err(dev, "unable to create instance for app %s\n", appfile);
@@ -795,21 +835,21 @@ nvadsp_app_info_t *nvadsp_run_app(nvadsp_os_handle_t os_handle,
} }
data->app_init.message = RUN_ADSP_APP; data->app_init.message = RUN_ADSP_APP;
ret = start_app_on_adsp(info, &message, block); ret = start_app_on_adsp(priv, info, &message, block);
if (ret) { if (ret) {
delete_app_instance(info); delete_app_instance(priv, info);
info = NULL; info = NULL;
} }
end: end:
return info; return info;
} }
EXPORT_SYMBOL(nvadsp_run_app);
static void delete_app_instance(nvadsp_app_info_t *app) static void delete_app_instance(struct nvadsp_app_priv_struct *priv,
nvadsp_app_info_t *app)
{ {
struct nvadsp_app_service *ser = struct nvadsp_app_service *ser =
(struct nvadsp_app_service *)app->handle; (struct nvadsp_app_service *)app->handle;
struct device *dev = &priv.pdev->dev; struct device *dev = &priv->pdev->dev;
dev_dbg(dev, "%s:freeing app %s:%d\n", dev_dbg(dev, "%s:freeing app %s:%d\n",
__func__, app->name, app->instance_id); __func__, app->name, app->instance_id);
@@ -821,16 +861,19 @@ static void delete_app_instance(nvadsp_app_info_t *app)
mutex_unlock(&ser->lock); mutex_unlock(&ser->lock);
/* free instance memory */ /* free instance memory */
free_instance_memory(app, ser->mem_size); free_instance_memory(priv, app, ser->mem_size);
kfree(app->priv); kfree(app->priv);
kfree(app); kfree(app);
} }
void nvadsp_exit_app(nvadsp_app_info_t *app, bool terminate) static void _nvadsp_exit_app(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *app, bool terminate)
{ {
struct nvadsp_drv_data *drv_data =
(struct nvadsp_drv_data *)nvadsp_handle;
int *state; int *state;
if (IS_ERR_OR_NULL(priv.pdev)) { if (!drv_data || !drv_data->pdev || !drv_data->app_priv) {
pr_err("ADSP Driver is not initialized\n"); pr_err("ADSP Driver is not initialized\n");
return; return;
} }
@@ -844,36 +887,38 @@ void nvadsp_exit_app(nvadsp_app_info_t *app, bool terminate)
state = (int *)&app->state; state = (int *)&app->state;
*state = NVADSP_APP_STATE_INITIALIZED; *state = NVADSP_APP_STATE_INITIALIZED;
} }
delete_app_instance(app); delete_app_instance(drv_data->app_priv, app);
} }
EXPORT_SYMBOL(nvadsp_exit_app);
int nvadsp_app_deinit(nvadsp_app_info_t *app) static int _nvadsp_app_deinit(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *app)
{ {
nvadsp_exit_app(app, false); _nvadsp_exit_app(nvadsp_handle, app, false);
return 0; return 0;
} }
EXPORT_SYMBOL(nvadsp_app_deinit);
int nvadsp_app_stop(nvadsp_app_info_t *app) static int _nvadsp_app_stop(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *app)
{ {
return -ENOENT; return -ENOENT;
} }
EXPORT_SYMBOL(nvadsp_app_stop);
void nvadsp_app_unload(nvadsp_app_handle_t handle) static void _nvadsp_app_unload(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_handle_t handle)
{ {
struct nvadsp_drv_data *drv_data; struct nvadsp_drv_data *drv_data =
(struct nvadsp_drv_data *)nvadsp_handle;
struct nvadsp_app_priv_struct *priv;
struct nvadsp_app_service *ser; struct nvadsp_app_service *ser;
struct device *dev; struct device *dev;
if (!priv.pdev) { if (!drv_data || !drv_data->pdev || !drv_data->app_priv) {
pr_err("ADSP Driver is not initialized\n"); pr_err("ADSP Driver is not initialized\n");
return; return;
} }
drv_data = platform_get_drvdata(priv.pdev); priv = drv_data->app_priv;
dev = &priv.pdev->dev; dev = &priv->pdev->dev;
if (!drv_data->adsp_os_running) if (!drv_data->adsp_os_running)
return; return;
@@ -886,7 +931,7 @@ void nvadsp_app_unload(nvadsp_app_handle_t handle)
return; return;
#ifdef CONFIG_ADSP_DYNAMIC_APP #ifdef CONFIG_ADSP_DYNAMIC_APP
mutex_lock(&priv.service_lock_list); mutex_lock(&priv->service_lock_list);
if (ser->instance) { if (ser->instance) {
dev_err(dev, "cannot unload app %s, has instances %d\n", dev_err(dev, "cannot unload app %s, has instances %d\n",
ser->name, ser->instance); ser->name, ser->instance);
@@ -899,10 +944,9 @@ void nvadsp_app_unload(nvadsp_app_handle_t handle)
#endif #endif
unload_adsp_module(ser->mod); unload_adsp_module(ser->mod);
devm_kfree(dev, ser); devm_kfree(dev, ser);
mutex_unlock(&priv.service_lock_list); mutex_unlock(&priv->service_lock_list);
#endif // CONFIG_ADSP_DYNAMIC_APP #endif // CONFIG_ADSP_DYNAMIC_APP
} }
EXPORT_SYMBOL(nvadsp_app_unload);
static status_t nvadsp_app_receive_handler(uint32_t msg, void *hdata) static status_t nvadsp_app_receive_handler(uint32_t msg, void *hdata)
{ {
@@ -954,19 +998,13 @@ static status_t nvadsp_app_receive_handler(uint32_t msg, void *hdata)
return 0; return 0;
} }
int load_adsp_static_apps(void) int load_adsp_static_apps(struct nvadsp_drv_data *drv_data)
{ {
struct nvadsp_app_shared_msg_pool *msg_pool; struct nvadsp_app_shared_msg_pool *msg_pool;
struct nvadsp_shared_mem *shared_mem; struct nvadsp_shared_mem *shared_mem;
struct nvadsp_drv_data *drv_data; struct device *dev = &drv_data->pdev->dev;
struct platform_device *pdev;
struct device *dev;
msgq_t *msgq_recv; msgq_t *msgq_recv;
pdev = priv.pdev;
dev = &pdev->dev;
drv_data = platform_get_drvdata(pdev);
shared_mem = drv_data->shared_adsp_os_data; shared_mem = drv_data->shared_adsp_os_data;
if (!shared_mem) if (!shared_mem)
return 0; return 0;
@@ -993,37 +1031,88 @@ int load_adsp_static_apps(void)
/* Skip Start on boot apps */ /* Skip Start on boot apps */
if (shared_app->flags & ADSP_APP_FLAG_START_ON_BOOT) if (shared_app->flags & ADSP_APP_FLAG_START_ON_BOOT)
continue; continue;
app_load(name, shared_app, false); app_load(drv_data->app_priv, name, shared_app, false);
} }
return 0; return 0;
} }
static void _nvadsp_wait_for_app_complete(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *info)
{
/*
* wait_for_complete must be called only after app has started
*/
if (info->state == NVADSP_APP_STATE_STARTED)
wait_for_completion(&info->wait_for_app_complete);
}
static long _nvadsp_wait_for_app_complete_timeout(
struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *info, unsigned long timeout)
{
int ret = -EINVAL;
/*
* wait_for_complete must be called only after app has started
*/
if (info->state == NVADSP_APP_STATE_STARTED)
ret = wait_for_completion_interruptible_timeout(
&info->wait_for_app_complete, timeout);
return ret;
}
int __init nvadsp_app_module_probe(struct platform_device *pdev) int __init nvadsp_app_module_probe(struct platform_device *pdev)
{ {
#ifdef CONFIG_DEBUG_FS
struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev);
#endif struct nvadsp_handle *nvadsp_handle = &drv_data->nvadsp_handle;
uint16_t mbox_id = APP_LOADER_MBOX_ID; uint16_t mbox_id = APP_LOADER_MBOX_ID;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct nvadsp_app_priv_struct *priv;
int ret; int ret;
dev_info(dev, "%s\n", __func__); dev_info(dev, "%s\n", __func__);
ret = nvadsp_mbox_open(&priv.mbox, &mbox_id, priv = devm_kzalloc(dev,
sizeof(struct nvadsp_app_priv_struct), GFP_KERNEL);
if (!priv) {
dev_err(dev, "Failed to allocate app_priv\n");
ret = -ENOMEM;
goto end;
}
drv_data->app_priv = priv;
ret = nvadsp_handle->mbox_open(nvadsp_handle, &priv->mbox, &mbox_id,
"app_service", nvadsp_app_receive_handler, pdev); "app_service", nvadsp_app_receive_handler, pdev);
if (ret) { if (ret) {
dev_err(dev, "unable to open mailbox\n"); dev_err(dev, "unable to open mailbox\n");
goto end; goto end;
} }
priv.pdev = pdev; priv->pdev = pdev;
INIT_LIST_HEAD(&priv.service_list); INIT_LIST_HEAD(&priv->service_list);
init_completion(&priv.os_load_complete); init_completion(&priv->os_load_complete);
mutex_init(&priv.service_lock_list); mutex_init(&priv->service_lock_list);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
if (adsp_app_debug_init(drv_data->adsp_debugfs_root)) if (adsp_app_debug_init(priv, drv_data->adsp_debugfs_root))
dev_err(&pdev->dev, "unable to create adsp apps debugfs\n"); dev_err(dev, "unable to create adsp apps debugfs\n");
#endif #endif
end: end:
if (ret == 0) {
nvadsp_handle->app_load = _nvadsp_app_load;
nvadsp_handle->app_init = _nvadsp_app_init;
nvadsp_handle->app_start = _nvadsp_app_start;
nvadsp_handle->run_app = _nvadsp_run_app;
nvadsp_handle->app_stop = _nvadsp_app_stop;
nvadsp_handle->app_deinit = _nvadsp_app_deinit;
nvadsp_handle->exit_app = _nvadsp_exit_app;
nvadsp_handle->app_unload = _nvadsp_app_unload;
nvadsp_handle->set_app_complete_cb =
_nvadsp_set_app_complete_cb;
nvadsp_handle->wait_for_app_complete =
_nvadsp_wait_for_app_complete;
nvadsp_handle->wait_for_app_complete_timeout =
_nvadsp_wait_for_app_complete_timeout;
}
return ret; return ret;
} }

View File

@@ -3,7 +3,6 @@
#include <linux/device.h> #include <linux/device.h>
#include "os.h" #include "os.h"
#include "dram_app_mem_manager.h"
#include "adsp_shared_struct.h" #include "adsp_shared_struct.h"
#ifdef CONFIG_ADSP_DYNAMIC_APP #ifdef CONFIG_ADSP_DYNAMIC_APP
@@ -17,6 +16,7 @@
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <asm/hwcap.h> #include <asm/hwcap.h>
#include "dram_app_mem_manager.h"
#ifdef CONFIG_DEBUG_SET_MODULE_RONX #ifdef CONFIG_DEBUG_SET_MODULE_RONX
# define debug_align(X) ALIGN(X, PAGE_SIZE) # define debug_align(X) ALIGN(X, PAGE_SIZE)

View File

@@ -10,22 +10,17 @@
#include "aram_manager.h" #include "aram_manager.h"
static void *aram_handle; void nvadsp_aram_print(void *aram_handle)
static LIST_HEAD(aram_alloc_list);
static LIST_HEAD(aram_free_list);
void nvadsp_aram_print(void)
{ {
mem_print(aram_handle); mem_print(aram_handle);
} }
void *nvadsp_aram_request(const char *name, size_t size) void *nvadsp_aram_request(void *aram_handle, const char *name, size_t size)
{ {
return mem_request(aram_handle, name, size); return mem_request(aram_handle, name, size);
} }
bool nvadsp_aram_release(void *handle) bool nvadsp_aram_release(void *aram_handle, void *handle)
{ {
return mem_release(aram_handle, handle); return mem_release(aram_handle, handle);
} }
@@ -35,11 +30,11 @@ unsigned long nvadsp_aram_get_address(void *handle)
return mem_get_address(handle); return mem_get_address(handle);
} }
static struct dentry *aram_dump_debugfs_file;
static int nvadsp_aram_dump(struct seq_file *s, void *data) static int nvadsp_aram_dump(struct seq_file *s, void *data)
{ {
mem_dump(aram_handle, s); struct nvadsp_drv_data *drv_data = data;
mem_dump(drv_data->aram_handle, s);
return 0; return 0;
} }
@@ -55,29 +50,31 @@ static const struct file_operations aram_dump_fops = {
.release = single_release, .release = single_release,
}; };
int nvadsp_aram_init(unsigned long addr, unsigned long size) int nvadsp_aram_init(struct nvadsp_drv_data *drv_data,
unsigned long addr, unsigned long size)
{ {
aram_handle = create_mem_manager("ARAM", addr, size); drv_data->aram_handle = create_mem_manager("ARAM", addr, size);
if (IS_ERR(aram_handle)) { if (IS_ERR(drv_data->aram_handle)) {
pr_err("ERROR: failed to create aram memory_manager"); pr_err("ERROR: failed to create aram memory_manager");
return PTR_ERR(aram_handle); return PTR_ERR(drv_data->aram_handle);
} }
if (debugfs_initialized()) { if (debugfs_initialized()) {
aram_dump_debugfs_file = debugfs_create_file("aram_dump", drv_data->aram_dump_debugfs_file = debugfs_create_file("aram_dump",
S_IRUSR, NULL, NULL, &aram_dump_fops); S_IRUSR, drv_data->adsp_debugfs_root,
if (!aram_dump_debugfs_file) { drv_data, &aram_dump_fops);
if (!drv_data->aram_dump_debugfs_file) {
pr_err("ERROR: failed to create aram_dump debugfs"); pr_err("ERROR: failed to create aram_dump debugfs");
destroy_mem_manager(aram_handle); destroy_mem_manager(drv_data->aram_handle);
return -ENOMEM; return -ENOMEM;
} }
} }
return 0; return 0;
} }
void nvadsp_aram_exit(void) void nvadsp_aram_exit(struct nvadsp_drv_data *drv_data)
{ {
debugfs_remove(aram_dump_debugfs_file); debugfs_remove(drv_data->aram_dump_debugfs_file);
destroy_mem_manager(aram_handle); destroy_mem_manager(drv_data->aram_handle);
} }

View File

@@ -1,13 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/** /**
* Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2014-2024, NVIDIA CORPORATION. All rights reserved.
*/ */
#ifndef __TEGRA_NVADSP_ARAM_MANAGER_H #ifndef __TEGRA_NVADSP_ARAM_MANAGER_H
#define __TEGRA_NVADSP_ARAM_MANAGER_H #define __TEGRA_NVADSP_ARAM_MANAGER_H
#include "mem_manager.h" #include "mem_manager.h"
#include "dev.h"
int nvadsp_aram_init(struct nvadsp_drv_data *drv_data,
unsigned long addr, unsigned long size);
void nvadsp_aram_exit(struct nvadsp_drv_data *drv_data);
int nvadsp_aram_init(unsigned long addr, unsigned long size);
void nvadsp_aram_exit(void);
#endif /* __TEGRA_NVADSP_ARAM_MANAGER_H */ #endif /* __TEGRA_NVADSP_ARAM_MANAGER_H */

View File

@@ -3,7 +3,6 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/of.h> #include <linux/of.h>
@@ -13,6 +12,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/tegra_nvadsp.h> #include <linux/tegra_nvadsp.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/slab.h>
#include <soc/tegra/fuse-helper.h> #include <soc/tegra/fuse-helper.h>
#include <soc/tegra/virt/hv-ivc.h> #include <soc/tegra/virt/hv-ivc.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
@@ -21,6 +21,7 @@
#include <asm/arch_timer.h> #include <asm/arch_timer.h>
#include "dev.h" #include "dev.h"
#include "hwmailbox.h"
#include "os.h" #include "os.h"
#include "amc.h" #include "amc.h"
#include "ape_actmon.h" #include "ape_actmon.h"
@@ -28,12 +29,69 @@
#include "dev-t18x.h" #include "dev-t18x.h"
static struct nvadsp_drv_data *nvadsp_drv_data; #define MAX_DEV_STR_LEN (20)
struct nvadsp_handle_node {
char dev_str[MAX_DEV_STR_LEN];
struct nvadsp_handle *nvadsp_handle;
struct list_head list;
};
/* Global list of driver instance handles */
static LIST_HEAD(nvadsp_handle_list);
static DEFINE_MUTEX(nvadsp_handle_mutex);
/**
* nvadsp_get_handle: Fetch driver instance using unique identfier
*
* @dev_str : Unique identifier string for the driver instance
* (trailing unique identifer in compatible DT property,
* e.g. "adsp", "adsp1", etc.)
*
* Return : Driver instance handle on success, else NULL
*/
struct nvadsp_handle *nvadsp_get_handle(const char *dev_str)
{
struct nvadsp_handle_node *handle_node;
struct nvadsp_handle *nvadsp_handle = NULL;
uint32_t num_devs = 0;
mutex_lock(&nvadsp_handle_mutex);
if (list_empty(&nvadsp_handle_list))
goto out;
list_for_each_entry(handle_node, &nvadsp_handle_list, list) {
num_devs++;
if (!strcmp(dev_str, handle_node->dev_str)) {
nvadsp_handle = handle_node->nvadsp_handle;
goto out;
}
}
if ((num_devs == 1) && !strcmp(dev_str, "")) {
handle_node = list_first_entry(
&nvadsp_handle_list,
struct nvadsp_handle_node, list);
nvadsp_handle = handle_node->nvadsp_handle;
}
out:
mutex_unlock(&nvadsp_handle_mutex);
if (!nvadsp_handle)
pr_err("Unable to find device %s in list\n", dev_str);
return nvadsp_handle;
}
EXPORT_SYMBOL(nvadsp_get_handle);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
static int __init adsp_debug_init(struct nvadsp_drv_data *drv_data) static int __init adsp_debug_init(struct nvadsp_drv_data *drv_data,
const char *dev_str)
{ {
drv_data->adsp_debugfs_root = debugfs_create_dir("tegra_ape", NULL); drv_data->adsp_debugfs_root = debugfs_create_dir(dev_str, NULL);
if (!drv_data->adsp_debugfs_root) if (!drv_data->adsp_debugfs_root)
return -ENOMEM; return -ENOMEM;
return 0; return 0;
@@ -107,7 +165,6 @@ uint64_t nvadsp_get_timestamp_counter(void)
{ {
return __arch_counter_get_cntvct_stable(); return __arch_counter_get_cntvct_stable();
} }
EXPORT_SYMBOL(nvadsp_get_timestamp_counter);
int nvadsp_set_bw(struct nvadsp_drv_data *drv_data, u32 efreq) int nvadsp_set_bw(struct nvadsp_drv_data *drv_data, u32 efreq)
{ {
@@ -343,13 +400,45 @@ static int __init nvadsp_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *res = NULL; struct resource *res = NULL;
void __iomem *base = NULL; void __iomem *base = NULL;
uint32_t aram_addr; uint32_t aram_addr, aram_size;
uint32_t aram_size; int irq_iter, iter, irq_num;
int irq_iter, iter; const char *compat, *dev_str;
int irq_num; struct nvadsp_handle_node *handle_node;
int ret = 0; int ret = 0;
dev_info(dev, "in probe()...\n"); mutex_lock(&nvadsp_handle_mutex);
ret = of_property_read_string(dev->of_node, "compatible", &compat);
if (ret)
goto out;
/**
* Trailing part of compatible string after the
* last '-' is taken as unique device string
*/
dev_str = strrchr(compat, '-');
if (strlen(dev_str) < 2) {
dev_err(dev, "Unable to extract device string\n");
ret = -EINVAL;
goto out;
}
dev_str += 1;
if (strlen(dev_str) >= MAX_DEV_STR_LEN) {
dev_err(dev, "Device string %s out of bound\n", dev_str);
ret = -EINVAL;
goto out;
}
list_for_each_entry(handle_node, &nvadsp_handle_list, list) {
if (!strcmp(dev_str, handle_node->dev_str)) {
dev_err(dev, "Device %s already probed\n", dev_str);
ret = -EEXIST;
goto out;
}
}
dev_info(dev, "in probe()...%s\n", dev_str);
drv_data = devm_kzalloc(dev, sizeof(*drv_data), drv_data = devm_kzalloc(dev, sizeof(*drv_data),
GFP_KERNEL); GFP_KERNEL);
@@ -376,9 +465,9 @@ static int __init nvadsp_probe(struct platform_device *pdev)
#endif #endif
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
if (adsp_debug_init(drv_data)) if (adsp_debug_init(drv_data, dev_str))
dev_err(dev, dev_err(dev,
"unable to create tegra_ape debug fs directory\n"); "unable to create %s debug fs directory\n", dev_str);
#endif #endif
drv_data->base_regs = drv_data->base_regs =
@@ -408,7 +497,8 @@ static int __init nvadsp_probe(struct platform_device *pdev)
goto out; goto out;
} }
drv_data->base_regs[iter] = base; drv_data->base_regs[iter] = base;
nvadsp_add_load_mappings(res->start, (void __force *)base, nvadsp_add_load_mappings(drv_data,
res->start, (void __force *)base,
resource_size(res)); resource_size(res));
} }
@@ -425,8 +515,6 @@ static int __init nvadsp_probe(struct platform_device *pdev)
drv_data->agic_irqs[irq_iter] = irq_num; drv_data->agic_irqs[irq_iter] = irq_num;
} }
nvadsp_drv_data = drv_data;
#ifdef CONFIG_PM #ifdef CONFIG_PM
pm_runtime_enable(dev); pm_runtime_enable(dev);
@@ -465,7 +553,7 @@ static int __init nvadsp_probe(struct platform_device *pdev)
aram_addr = drv_data->adsp_mem[ARAM_ALIAS_0_ADDR]; aram_addr = drv_data->adsp_mem[ARAM_ALIAS_0_ADDR];
aram_size = drv_data->adsp_mem[ARAM_ALIAS_0_SIZE]; aram_size = drv_data->adsp_mem[ARAM_ALIAS_0_SIZE];
if (aram_size) { if (aram_size) {
ret = nvadsp_aram_init(aram_addr, aram_size); ret = nvadsp_aram_init(drv_data, aram_addr, aram_size);
if (ret) if (ret)
dev_err(dev, "Failed to init aram\n"); dev_err(dev, "Failed to init aram\n");
} }
@@ -478,6 +566,20 @@ static int __init nvadsp_probe(struct platform_device *pdev)
goto err; goto err;
} }
handle_node = kzalloc(sizeof(struct nvadsp_handle_node),
GFP_KERNEL);
if (!handle_node) {
dev_err(dev, "Failed to allocate node mem for %s\n", dev_str);
ret = -ENOMEM;
goto err;
}
/* Add probed device into list of handles */
strcpy(handle_node->dev_str, dev_str);
handle_node->nvadsp_handle = (struct nvadsp_handle *)drv_data;
INIT_LIST_HEAD(&handle_node->list);
list_add_tail(&handle_node->list, &nvadsp_handle_list);
err: err:
#ifdef CONFIG_PM #ifdef CONFIG_PM
ret = pm_runtime_put_sync(dev); ret = pm_runtime_put_sync(dev);
@@ -485,6 +587,8 @@ err:
dev_err(dev, "pm_runtime_put_sync failed\n"); dev_err(dev, "pm_runtime_put_sync failed\n");
#endif #endif
out: out:
mutex_unlock(&nvadsp_handle_mutex);
return ret; return ret;
} }
@@ -492,11 +596,12 @@ static int nvadsp_remove(struct platform_device *pdev)
{ {
struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev);
uint32_t aram_size = drv_data->adsp_mem[ARAM_ALIAS_0_SIZE]; uint32_t aram_size = drv_data->adsp_mem[ARAM_ALIAS_0_SIZE];
struct nvadsp_handle_node *handle_node;
nvadsp_bw_unregister(drv_data); nvadsp_bw_unregister(drv_data);
if (aram_size) if (aram_size)
nvadsp_aram_exit(); nvadsp_aram_exit(drv_data);
#ifdef CONFIG_PM #ifdef CONFIG_PM
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
@@ -505,6 +610,18 @@ static int nvadsp_remove(struct platform_device *pdev)
nvadsp_runtime_suspend(&pdev->dev); nvadsp_runtime_suspend(&pdev->dev);
#endif #endif
mutex_lock(&nvadsp_handle_mutex);
list_for_each_entry(handle_node, &nvadsp_handle_list, list) {
if (handle_node->nvadsp_handle ==
(struct nvadsp_handle *)drv_data) {
list_del(&handle_node->list);
kfree(handle_node);
}
}
mutex_unlock(&nvadsp_handle_mutex);
return 0; return 0;
} }

View File

@@ -16,7 +16,6 @@
#endif #endif
#include <linux/interconnect.h> #include <linux/interconnect.h>
#include "hwmailbox.h"
#include "amc.h" #include "amc.h"
/* /*
@@ -119,6 +118,9 @@ struct nvadsp_hwmb {
u32 empty_int_ie; u32 empty_int_ie;
}; };
/* Max SW mailboxes */
#define NVADSP_MAILBOX_MAX 1024
/* Max no. of entries in "nvidia,cluster_mem" */ /* Max no. of entries in "nvidia,cluster_mem" */
#define MAX_CLUSTER_MEM 3 #define MAX_CLUSTER_MEM 3
@@ -163,14 +165,33 @@ struct nvadsp_chipdata {
size_t num_regs; size_t num_regs;
}; };
/* Maximum number of LOAD MAPPINGS supported */
#define NM_LOAD_MAPPINGS 20
struct nvadsp_mappings {
phys_addr_t da;
void *va;
int len;
};
struct nvadsp_drv_data { struct nvadsp_drv_data {
/**
* API handle exposed to caller
* MUST BE THE FIRST FIELD IN THIS STRUCTURE
*/
struct nvadsp_handle nvadsp_handle;
void __iomem **base_regs; void __iomem **base_regs;
void __iomem **base_regs_saved; void __iomem **base_regs_saved;
struct platform_device *pdev; struct platform_device *pdev;
struct hwmbox_queue hwmbox_send_queue;
struct nvadsp_mbox **mboxes; /* Memories allocated by subsidiary modules */
unsigned long *mbox_ids; void *hwmbox_send_queue; /* struct hwmbox_queue */
void *os_priv; /* struct nvadsp_os_data */
void *app_priv; /* struct nvadsp_app_priv_struct */
struct nvadsp_mbox *mboxes[NVADSP_MAILBOX_MAX];
unsigned long mbox_ids[BITS_TO_LONGS(NVADSP_MAILBOX_MAX)];
spinlock_t mbox_lock; spinlock_t mbox_lock;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
@@ -259,6 +280,13 @@ struct nvadsp_drv_data {
/* "nvidia,dram_map" */ /* "nvidia,dram_map" */
struct nvadsp_reg_map dram_map[MAX_DRAM_MAP]; struct nvadsp_reg_map dram_map[MAX_DRAM_MAP];
struct nvadsp_mappings adsp_map[NM_LOAD_MAPPINGS];
int map_idx;
/* ARAM manager */
void *aram_handle;
struct dentry *aram_dump_debugfs_file;
}; };
#define ADSP_CONFIG 0x04 #define ADSP_CONFIG 0x04

View File

@@ -9,63 +9,50 @@
#include <linux/tegra_nvadsp.h> #include <linux/tegra_nvadsp.h>
#include "dev.h" #include "dev.h"
#include "hwmailbox.h"
static struct platform_device *nvadsp_pdev;
static struct nvadsp_drv_data *nvadsp_drv_data;
/* Initialized to false by default */
static bool is_hwmbox_busy;
#ifdef CONFIG_MBOX_ACK_HANDLER
static int hwmbox_last_msg;
#endif
/* /*
* Mailbox 0 is for receiving messages * Mailbox 0 is for receiving messages
* from ADSP i.e. CPU <-- ADSP. * from ADSP i.e. CPU <-- ADSP.
*/ */
#define INT_RECV_HWMBOX INT_AMISC_MBOX_FULL0 static inline u32 recv_hwmbox(struct nvadsp_drv_data *drv)
static inline u32 recv_hwmbox(void)
{ {
return nvadsp_drv_data->chip_data->hwmb.hwmbox0_reg; return drv->chip_data->hwmb.hwmbox0_reg;
} }
/* /*
* Mailbox 1 is for sending messages * Mailbox 1 is for sending messages
* to ADSP i.e. CPU --> ADSP * to ADSP i.e. CPU --> ADSP
*/ */
#define INT_SEND_HWMBOX INT_AMISC_MBOX_EMPTY1 static inline u32 send_hwmbox(struct nvadsp_drv_data *drv)
static inline u32 send_hwmbox(void)
{ {
return nvadsp_drv_data->chip_data->hwmb.hwmbox1_reg; return drv->chip_data->hwmb.hwmbox1_reg;
}
static u32 hwmb_reg_idx(struct nvadsp_drv_data *drv)
{
return drv->chip_data->hwmb.reg_idx;
}
u32 hwmbox_readl(struct nvadsp_drv_data *drv, u32 reg)
{
return readl(drv->base_regs[hwmb_reg_idx(drv)] + reg);
}
void hwmbox_writel(struct nvadsp_drv_data *drv, u32 val, u32 reg)
{
writel(val, drv->base_regs[hwmb_reg_idx(drv)] + reg);
} }
u32 hwmb_reg_idx(void) #define PRINT_HWMBOX(d, x) \
pr_err("%s: 0x%x\n", #x, hwmbox_readl(d, x))
void dump_mailbox_regs(struct nvadsp_drv_data *drv)
{ {
return nvadsp_drv_data->chip_data->hwmb.reg_idx; pr_err("dumping hwmailbox registers ...\n");
} PRINT_HWMBOX(drv, recv_hwmbox(drv));
PRINT_HWMBOX(drv, send_hwmbox(drv));
u32 hwmbox_readl(u32 reg)
{
return readl(nvadsp_drv_data->base_regs[hwmb_reg_idx()] + reg);
}
void hwmbox_writel(u32 val, u32 reg)
{
writel(val, nvadsp_drv_data->base_regs[hwmb_reg_idx()] + reg);
}
#define PRINT_HWMBOX(x) \
dev_info(&nvadsp_pdev->dev, "%s: 0x%x\n", #x, hwmbox_readl(x))
void dump_mailbox_regs(void)
{
dev_info(&nvadsp_pdev->dev, "dumping hwmailbox registers ...\n");
PRINT_HWMBOX(recv_hwmbox());
PRINT_HWMBOX(send_hwmbox());
} }
static void hwmboxq_init(struct hwmbox_queue *queue) static void hwmboxq_init(struct hwmbox_queue *queue)
@@ -75,6 +62,8 @@ static void hwmboxq_init(struct hwmbox_queue *queue)
queue->count = 0; queue->count = 0;
init_completion(&queue->comp); init_completion(&queue->comp);
spin_lock_init(&queue->lock); spin_lock_init(&queue->lock);
queue->is_hwmbox_busy = false;
queue->hwmbox_last_msg = 0;
} }
/* Must be called with queue lock held in non-interrupt context */ /* Must be called with queue lock held in non-interrupt context */
@@ -116,10 +105,12 @@ static status_t hwmboxq_enqueue(struct hwmbox_queue *queue,
return ret; return ret;
} }
status_t nvadsp_hwmbox_send_data(uint16_t mid, uint32_t data, uint32_t flags) status_t nvadsp_hwmbox_send_data(struct nvadsp_drv_data *drv,
uint16_t mid, uint32_t data, uint32_t flags)
{ {
spinlock_t *lock = &nvadsp_drv_data->hwmbox_send_queue.lock; struct hwmbox_queue *hwmbox_send_queue = drv->hwmbox_send_queue;
u32 empty_int_ie = nvadsp_drv_data->chip_data->hwmb.empty_int_ie; spinlock_t *lock = &hwmbox_send_queue->lock;
u32 empty_int_ie = drv->chip_data->hwmb.empty_int_ie;
unsigned long lockflags; unsigned long lockflags;
int ret = 0; int ret = 0;
@@ -132,19 +123,18 @@ status_t nvadsp_hwmbox_send_data(uint16_t mid, uint32_t data, uint32_t flags)
spin_lock_irqsave(lock, lockflags); spin_lock_irqsave(lock, lockflags);
if (!is_hwmbox_busy) { if (!hwmbox_send_queue->is_hwmbox_busy) {
is_hwmbox_busy = true; hwmbox_send_queue->is_hwmbox_busy = true;
pr_debug("nvadsp_mbox_send: empty mailbox. write to mailbox.\n"); pr_debug("nvadsp_mbox_send: empty mailbox. write to mailbox.\n");
#ifdef CONFIG_MBOX_ACK_HANDLER hwmbox_send_queue->hwmbox_last_msg = data;
hwmbox_last_msg = data; hwmbox_writel(drv, data, send_hwmbox(drv));
#endif if (empty_int_ie) {
hwmbox_writel(data, send_hwmbox()); hwmbox_writel(drv, INT_ENABLE,
if (empty_int_ie) send_hwmbox(drv) + empty_int_ie);
hwmbox_writel(INT_ENABLE, send_hwmbox() + empty_int_ie); }
} else { } else {
pr_debug("nvadsp_mbox_send: enqueue data\n"); pr_debug("nvadsp_mbox_send: enqueue data\n");
ret = hwmboxq_enqueue(&nvadsp_drv_data->hwmbox_send_queue, ret = hwmboxq_enqueue(hwmbox_send_queue, data);
data);
} }
spin_unlock_irqrestore(lock, lockflags); spin_unlock_irqrestore(lock, lockflags);
return ret; return ret;
@@ -162,7 +152,7 @@ static status_t hwmboxq_dequeue(struct hwmbox_queue *queue,
} }
if (is_hwmboxq_full(queue)) if (is_hwmboxq_full(queue))
complete_all(&nvadsp_drv_data->hwmbox_send_queue.comp); complete_all(&queue->comp);
*data = queue->array[queue->head]; *data = queue->array[queue->head];
queue->head = (queue->head + 1) & HWMBOX_QUEUE_SIZE_MASK; queue->head = (queue->head + 1) & HWMBOX_QUEUE_SIZE_MASK;
@@ -174,26 +164,30 @@ static status_t hwmboxq_dequeue(struct hwmbox_queue *queue,
static irqreturn_t hwmbox_send_empty_int_handler(int irq, void *devid) static irqreturn_t hwmbox_send_empty_int_handler(int irq, void *devid)
{ {
spinlock_t *lock = &nvadsp_drv_data->hwmbox_send_queue.lock; struct platform_device *pdev = devid;
struct device *dev = &nvadsp_pdev->dev; struct device *dev = &pdev->dev;
u32 empty_int_ie = nvadsp_drv_data->chip_data->hwmb.empty_int_ie; struct nvadsp_drv_data *drv = platform_get_drvdata(pdev);
struct hwmbox_queue *hwmbox_send_queue = drv->hwmbox_send_queue;
spinlock_t *lock = &hwmbox_send_queue->lock;
u32 empty_int_ie = drv->chip_data->hwmb.empty_int_ie;
unsigned long lockflags; unsigned long lockflags;
uint32_t data; uint32_t data, hwmbox_last_msg;
uint16_t last_mboxid;
struct nvadsp_mbox *mbox;
int ret; int ret;
if (!is_hwmbox_busy) if (!hwmbox_send_queue->is_hwmbox_busy)
return IRQ_HANDLED; return IRQ_HANDLED;
spin_lock_irqsave(lock, lockflags); spin_lock_irqsave(lock, lockflags);
data = hwmbox_readl(send_hwmbox()); data = hwmbox_readl(drv, send_hwmbox(drv));
if (data != PREPARE_HWMBOX_EMPTY_MSG()) if (data != PREPARE_HWMBOX_EMPTY_MSG())
dev_err(dev, "last mailbox sent failed with 0x%x\n", data); dev_err(dev, "last mailbox sent failed with 0x%x\n", data);
#ifdef CONFIG_MBOX_ACK_HANDLER hwmbox_last_msg = hwmbox_send_queue->hwmbox_last_msg;
{ last_mboxid = HWMBOX_SMSG_MID(hwmbox_last_msg);
uint16_t last_mboxid = HWMBOX_SMSG_MID(hwmbox_last_msg); mbox = drv->mboxes[last_mboxid];
struct nvadsp_mbox *mbox = nvadsp_drv_data->mboxes[last_mboxid];
if (mbox) { if (mbox) {
nvadsp_mbox_handler_t ack_handler = mbox->ack_handler; nvadsp_mbox_handler_t ack_handler = mbox->ack_handler;
@@ -204,21 +198,17 @@ static irqreturn_t hwmbox_send_empty_int_handler(int irq, void *devid)
ack_handler(msg, mbox->hdata); ack_handler(msg, mbox->hdata);
} }
} }
}
#endif ret = hwmboxq_dequeue(hwmbox_send_queue, &data);
ret = hwmboxq_dequeue(&nvadsp_drv_data->hwmbox_send_queue,
&data);
if (ret == 0) { if (ret == 0) {
#ifdef CONFIG_MBOX_ACK_HANDLER hwmbox_send_queue->hwmbox_last_msg = data;
hwmbox_last_msg = data; hwmbox_writel(drv, data, send_hwmbox(drv));
#endif
hwmbox_writel(data, send_hwmbox());
dev_dbg(dev, "Writing 0x%x to SEND_HWMBOX\n", data); dev_dbg(dev, "Writing 0x%x to SEND_HWMBOX\n", data);
} else { } else {
is_hwmbox_busy = false; hwmbox_send_queue->is_hwmbox_busy = false;
if (empty_int_ie) if (empty_int_ie)
hwmbox_writel(INT_DISABLE, hwmbox_writel(drv, INT_DISABLE,
send_hwmbox() + empty_int_ie); send_hwmbox(drv) + empty_int_ie);
} }
spin_unlock_irqrestore(lock, lockflags); spin_unlock_irqrestore(lock, lockflags);
@@ -227,18 +217,21 @@ static irqreturn_t hwmbox_send_empty_int_handler(int irq, void *devid)
static irqreturn_t hwmbox_recv_full_int_handler(int irq, void *devid) static irqreturn_t hwmbox_recv_full_int_handler(int irq, void *devid)
{ {
struct platform_device *pdev = devid;
struct device *dev = &pdev->dev;
struct nvadsp_drv_data *drv = platform_get_drvdata(pdev);
uint32_t data; uint32_t data;
int ret; int ret;
data = hwmbox_readl(recv_hwmbox()); data = hwmbox_readl(drv, recv_hwmbox(drv));
hwmbox_writel(PREPARE_HWMBOX_EMPTY_MSG(), recv_hwmbox()); hwmbox_writel(drv, PREPARE_HWMBOX_EMPTY_MSG(), recv_hwmbox(drv));
if (IS_HWMBOX_MSG_SMSG(data)) { if (IS_HWMBOX_MSG_SMSG(data)) {
uint16_t mboxid = HWMBOX_SMSG_MID(data); uint16_t mboxid = HWMBOX_SMSG_MID(data);
struct nvadsp_mbox *mbox = nvadsp_drv_data->mboxes[mboxid]; struct nvadsp_mbox *mbox = drv->mboxes[mboxid];
if (!mbox) { if (!mbox) {
dev_info(&nvadsp_pdev->dev, dev_info(dev,
"Failed to get mbox for mboxid: %u\n", "Failed to get mbox for mboxid: %u\n",
mboxid); mboxid);
goto out; goto out;
@@ -250,7 +243,7 @@ static irqreturn_t hwmbox_recv_full_int_handler(int irq, void *devid)
ret = nvadsp_mboxq_enqueue(&mbox->recv_queue, ret = nvadsp_mboxq_enqueue(&mbox->recv_queue,
HWMBOX_SMSG_MSG(data)); HWMBOX_SMSG_MSG(data));
if (ret) { if (ret) {
dev_info(&nvadsp_pdev->dev, dev_info(dev,
"Failed to deliver msg 0x%x to" "Failed to deliver msg 0x%x to"
" mbox id %u\n", " mbox id %u\n",
HWMBOX_SMSG_MSG(data), mboxid); HWMBOX_SMSG_MSG(data), mboxid);
@@ -266,7 +259,6 @@ static irqreturn_t hwmbox_recv_full_int_handler(int irq, void *devid)
void nvadsp_free_hwmbox_interrupts(struct platform_device *pdev) void nvadsp_free_hwmbox_interrupts(struct platform_device *pdev)
{ {
struct nvadsp_drv_data *drv = platform_get_drvdata(pdev); struct nvadsp_drv_data *drv = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
int recv_virq, send_virq; int recv_virq, send_virq;
@@ -301,8 +293,8 @@ int nvadsp_setup_hwmbox_interrupts(struct platform_device *pdev)
goto err; goto err;
if (empty_int_ie) if (empty_int_ie)
hwmbox_writel(INT_DISABLE, hwmbox_writel(drv, INT_DISABLE,
send_hwmbox() + empty_int_ie); send_hwmbox(drv) + empty_int_ie);
ret = devm_request_irq(dev, send_virq, hwmbox_send_empty_int_handler, ret = devm_request_irq(dev, send_virq, hwmbox_send_empty_int_handler,
IRQF_TRIGGER_RISING, IRQF_TRIGGER_RISING,
"hwmbox1_send_empty", pdev); "hwmbox1_send_empty", pdev);
@@ -320,12 +312,19 @@ int nvadsp_setup_hwmbox_interrupts(struct platform_device *pdev)
int __init nvadsp_hwmbox_init(struct platform_device *pdev) int __init nvadsp_hwmbox_init(struct platform_device *pdev)
{ {
struct nvadsp_drv_data *drv = platform_get_drvdata(pdev); struct nvadsp_drv_data *drv = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
int ret = 0; int ret = 0;
nvadsp_pdev = pdev; drv->hwmbox_send_queue = devm_kzalloc(dev,
nvadsp_drv_data = drv; sizeof(struct hwmbox_queue), GFP_KERNEL);
if (!drv->hwmbox_send_queue) {
dev_err(dev, "Failed to allocate hwmbox_send_queue\n");
ret = -ENOMEM;
goto exit;
}
hwmboxq_init(&drv->hwmbox_send_queue); hwmboxq_init(drv->hwmbox_send_queue);
exit:
return ret; return ret;
} }

View File

@@ -95,15 +95,17 @@ struct hwmbox_queue {
uint16_t count; uint16_t count;
struct completion comp; struct completion comp;
spinlock_t lock; spinlock_t lock;
bool is_hwmbox_busy;
uint32_t hwmbox_last_msg;
}; };
u32 hwmb_reg_idx(void); u32 hwmbox_readl(struct nvadsp_drv_data *, u32 reg);
u32 hwmbox_readl(u32 reg); void hwmbox_writel(struct nvadsp_drv_data *, u32 val, u32 reg);
void hwmbox_writel(u32 val, u32 reg); status_t nvadsp_hwmbox_send_data(struct nvadsp_drv_data *,
int nvadsp_hwmbox_init(struct platform_device *); uint16_t, uint32_t, uint32_t);
status_t nvadsp_hwmbox_send_data(uint16_t, uint32_t, uint32_t); void dump_mailbox_regs(struct nvadsp_drv_data *);
void dump_mailbox_regs(void);
int nvadsp_hwmbox_init(struct platform_device *);
int nvadsp_setup_hwmbox_interrupts(struct platform_device *pdev); int nvadsp_setup_hwmbox_interrupts(struct platform_device *pdev);
void nvadsp_free_hwmbox_interrupts(struct platform_device *pdev); void nvadsp_free_hwmbox_interrupts(struct platform_device *pdev);

View File

@@ -1,19 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/** /**
* Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2014-2024, NVIDIA CORPORATION. All rights reserved.
*/ */
#include "dev.h" #include "dev.h"
#include "hwmailbox.h"
#include <linux/nospec.h> #include <linux/nospec.h>
#include <asm/barrier.h> #include <asm/barrier.h>
#define NVADSP_MAILBOX_START 512 #define NVADSP_MAILBOX_START 512
#define NVADSP_MAILBOX_MAX 1024
#define NVADSP_MAILBOX_OS_MAX 16
static struct nvadsp_mbox *nvadsp_mboxes[NVADSP_MAILBOX_MAX];
static DECLARE_BITMAP(nvadsp_mbox_ids, NVADSP_MAILBOX_MAX);
static struct nvadsp_drv_data *nvadsp_drv_data;
static inline bool is_mboxq_empty(struct nvadsp_mbox_queue *queue) static inline bool is_mboxq_empty(struct nvadsp_mbox_queue *queue)
{ {
@@ -123,7 +118,8 @@ static void mboxq_dump(struct nvadsp_mbox_queue *queue)
spin_unlock_irqrestore(&queue->lock, flags); spin_unlock_irqrestore(&queue->lock, flags);
} }
static uint16_t nvadsp_mbox_alloc_mboxid(void) static uint16_t nvadsp_mbox_alloc_mboxid(
struct nvadsp_drv_data *nvadsp_drv_data)
{ {
unsigned long start = NVADSP_MAILBOX_START; unsigned long start = NVADSP_MAILBOX_START;
unsigned int nr = 1; unsigned int nr = 1;
@@ -138,20 +134,31 @@ static uint16_t nvadsp_mbox_alloc_mboxid(void)
return mid; return mid;
} }
static status_t nvadsp_mbox_free_mboxid(uint16_t mid) static status_t nvadsp_mbox_free_mboxid(
struct nvadsp_drv_data *nvadsp_drv_data, uint16_t mid)
{ {
bitmap_clear(nvadsp_drv_data->mbox_ids, mid, 1); bitmap_clear(nvadsp_drv_data->mbox_ids, mid, 1);
return 0; return 0;
} }
status_t nvadsp_mbox_open(struct nvadsp_mbox *mbox, uint16_t *mid, static void _nvadsp_mbox_set_ack_handler(struct nvadsp_handle *nvadsp_handle,
const char *name, nvadsp_mbox_handler_t handler, struct nvadsp_mbox *mbox,
void *hdata) nvadsp_mbox_handler_t handler)
{ {
mbox->ack_handler = handler;
}
static status_t _nvadsp_mbox_open(struct nvadsp_handle *nvadsp_handle,
struct nvadsp_mbox *mbox,
uint16_t *mid, const char *name,
nvadsp_mbox_handler_t handler, void *hdata)
{
struct nvadsp_drv_data *nvadsp_drv_data =
(struct nvadsp_drv_data *)nvadsp_handle;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
if (!nvadsp_drv_data) { if (!nvadsp_drv_data || !nvadsp_drv_data->pdev) {
ret = -ENOSYS; ret = -ENOSYS;
goto err; goto err;
} }
@@ -164,7 +171,7 @@ status_t nvadsp_mbox_open(struct nvadsp_mbox *mbox, uint16_t *mid,
} }
if (*mid == 0) { if (*mid == 0) {
mbox->id = nvadsp_mbox_alloc_mboxid(); mbox->id = nvadsp_mbox_alloc_mboxid(nvadsp_drv_data);
if (mbox->id >= NVADSP_MAILBOX_MAX) { if (mbox->id >= NVADSP_MAILBOX_MAX) {
ret = -ENOMEM; ret = -ENOMEM;
mbox->id = 0; mbox->id = 0;
@@ -201,14 +208,18 @@ status_t nvadsp_mbox_open(struct nvadsp_mbox *mbox, uint16_t *mid,
err: err:
return ret; return ret;
} }
EXPORT_SYMBOL(nvadsp_mbox_open);
status_t nvadsp_mbox_send(struct nvadsp_mbox *mbox, uint32_t data, static status_t _nvadsp_mbox_send(struct nvadsp_handle *nvadsp_handle,
struct nvadsp_mbox *mbox, uint32_t data,
uint32_t flags, bool block, unsigned int timeout) uint32_t flags, bool block, unsigned int timeout)
{ {
struct nvadsp_drv_data *nvadsp_drv_data =
(struct nvadsp_drv_data *)nvadsp_handle;
struct hwmbox_queue *hwmbox_send_queue;
int ret = 0; int ret = 0;
if (!nvadsp_drv_data) { if (!nvadsp_drv_data || !nvadsp_drv_data->pdev ||
!nvadsp_drv_data->hwmbox_send_queue) {
pr_err("ADSP drv_data is NULL\n"); pr_err("ADSP drv_data is NULL\n");
ret = -ENOSYS; ret = -ENOSYS;
goto out; goto out;
@@ -220,15 +231,17 @@ status_t nvadsp_mbox_send(struct nvadsp_mbox *mbox, uint32_t data,
goto out; goto out;
} }
hwmbox_send_queue = nvadsp_drv_data->hwmbox_send_queue;
retry: retry:
ret = nvadsp_hwmbox_send_data(mbox->id, data, flags); ret = nvadsp_hwmbox_send_data(nvadsp_drv_data, mbox->id, data, flags);
if (!ret) if (!ret)
goto out; goto out;
if (ret == -EBUSY) { if (ret == -EBUSY) {
if (block) { if (block) {
ret = wait_for_completion_timeout( ret = wait_for_completion_timeout(
&nvadsp_drv_data->hwmbox_send_queue.comp, &hwmbox_send_queue->comp,
msecs_to_jiffies(timeout)); msecs_to_jiffies(timeout));
if (ret) { if (ret) {
pr_warn("ADSP HWMBOX send retry\n"); pr_warn("ADSP HWMBOX send retry\n");
@@ -250,14 +263,16 @@ status_t nvadsp_mbox_send(struct nvadsp_mbox *mbox, uint32_t data,
out: out:
return ret; return ret;
} }
EXPORT_SYMBOL(nvadsp_mbox_send);
status_t nvadsp_mbox_recv(struct nvadsp_mbox *mbox, uint32_t *data, bool block, static status_t _nvadsp_mbox_recv(struct nvadsp_handle *nvadsp_handle,
unsigned int timeout) struct nvadsp_mbox *mbox, uint32_t *data,
bool block, unsigned int timeout)
{ {
struct nvadsp_drv_data *nvadsp_drv_data =
(struct nvadsp_drv_data *)nvadsp_handle;
int ret = 0; int ret = 0;
if (!nvadsp_drv_data) { if (!nvadsp_drv_data || !nvadsp_drv_data->pdev) {
ret = -ENOSYS; ret = -ENOSYS;
goto out; goto out;
} }
@@ -294,14 +309,16 @@ status_t nvadsp_mbox_recv(struct nvadsp_mbox *mbox, uint32_t *data, bool block,
out: out:
return ret; return ret;
} }
EXPORT_SYMBOL(nvadsp_mbox_recv);
status_t nvadsp_mbox_close(struct nvadsp_mbox *mbox) static status_t _nvadsp_mbox_close(struct nvadsp_handle *nvadsp_handle,
struct nvadsp_mbox *mbox)
{ {
struct nvadsp_drv_data *nvadsp_drv_data =
(struct nvadsp_drv_data *)nvadsp_handle;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
if (!nvadsp_drv_data) { if (!nvadsp_drv_data || !nvadsp_drv_data->pdev) {
ret = -ENOSYS; ret = -ENOSYS;
goto err; goto err;
} }
@@ -318,7 +335,7 @@ status_t nvadsp_mbox_close(struct nvadsp_mbox *mbox)
goto out; goto out;
} }
nvadsp_mbox_free_mboxid(mbox->id); nvadsp_mbox_free_mboxid(nvadsp_drv_data, mbox->id);
mboxq_destroy(&mbox->recv_queue); mboxq_destroy(&mbox->recv_queue);
nvadsp_drv_data->mboxes[mbox->id] = NULL; nvadsp_drv_data->mboxes[mbox->id] = NULL;
out: out:
@@ -326,18 +343,22 @@ status_t nvadsp_mbox_close(struct nvadsp_mbox *mbox)
err: err:
return ret; return ret;
} }
EXPORT_SYMBOL(nvadsp_mbox_close);
status_t __init nvadsp_mbox_init(struct platform_device *pdev) status_t __init nvadsp_mbox_init(struct platform_device *pdev)
{ {
struct nvadsp_drv_data *drv = platform_get_drvdata(pdev); struct nvadsp_drv_data *drv = platform_get_drvdata(pdev);
struct nvadsp_handle *nvadsp_handle = &drv->nvadsp_handle;
drv->mboxes = nvadsp_mboxes; memset(drv->mboxes, 0, sizeof(drv->mboxes));
drv->mbox_ids = nvadsp_mbox_ids; memset(drv->mbox_ids, 0, sizeof(drv->mbox_ids));
spin_lock_init(&drv->mbox_lock); spin_lock_init(&drv->mbox_lock);
nvadsp_drv_data = drv; nvadsp_handle->mbox_open = _nvadsp_mbox_open;
nvadsp_handle->mbox_close = _nvadsp_mbox_close;
nvadsp_handle->mbox_send = _nvadsp_mbox_send;
nvadsp_handle->mbox_recv = _nvadsp_mbox_recv;
nvadsp_handle->mbox_set_ack_handler = _nvadsp_mbox_set_ack_handler;
return 0; return 0;
} }

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/** /**
* Copyright (c) 2015-2023, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2015-2024, NVIDIA CORPORATION. All rights reserved.
*/ */
#include <linux/version.h> #include <linux/version.h>
@@ -11,6 +11,7 @@
#include <linux/tegra-hsp.h> #include <linux/tegra-hsp.h>
#include "dev.h" #include "dev.h"
#include "hwmailbox.h"
#include "os.h" #include "os.h"
#include "dev-t18x.h" #include "dev-t18x.h"
@@ -78,10 +79,12 @@ int nvadsp_os_t18x_init(struct platform_device *pdev)
val = val | (adma_ch_page << ADSP_CONFIG_DMA_PAGE_SHIFT); val = val | (adma_ch_page << ADSP_CONFIG_DMA_PAGE_SHIFT);
/* Write to HWMBOX5 */ /* Write to HWMBOX5 */
hwmbox_writel(val, drv_data->chip_data->adsp_os_config_hwmbox); hwmbox_writel(drv_data, val,
drv_data->chip_data->adsp_os_config_hwmbox);
/* Clear HWMBOX0 for ADSP Guest reset handling */ /* Clear HWMBOX0 for ADSP Guest reset handling */
hwmbox_writel(0, drv_data->chip_data->hwmb.hwmbox0_reg); hwmbox_writel(drv_data, 0,
drv_data->chip_data->hwmb.hwmbox0_reg);
return 0; return 0;
} }

View File

File diff suppressed because it is too large Load Diff

View File

@@ -168,11 +168,12 @@ static inline int nvadsp_os_init(struct platform_device *pdev)
int nvadsp_os_probe(struct platform_device *); int nvadsp_os_probe(struct platform_device *);
int nvadsp_app_module_probe(struct platform_device *); int nvadsp_app_module_probe(struct platform_device *);
void *nvadsp_da_to_va_mappings(u64 da, int len); void *nvadsp_da_to_va_mappings(struct nvadsp_drv_data *, u64 da, int len);
int nvadsp_add_load_mappings(phys_addr_t pa, void *mapping, int len); int nvadsp_add_load_mappings(struct nvadsp_drv_data *,
phys_addr_t pa, void *mapping, int len);
struct elf32_shdr *nvadsp_get_section(const struct firmware *, char *); struct elf32_shdr *nvadsp_get_section(const struct firmware *, char *);
struct global_sym_info *find_global_symbol(const char *); struct global_sym_info *find_global_symbol(struct nvadsp_drv_data *,
void update_nvadsp_app_shared_ptr(void *); const char *);
struct adsp_module *load_adsp_dynamic_module(const char *, const char *, struct adsp_module *load_adsp_dynamic_module(const char *, const char *,
struct device *); struct device *);
@@ -180,7 +181,6 @@ struct adsp_module *load_adsp_static_module(const char *,
struct adsp_shared_app *, struct device *); struct adsp_shared_app *, struct device *);
void unload_adsp_module(struct adsp_module *); void unload_adsp_module(struct adsp_module *);
int allocate_memory_from_adsp(void **, unsigned int); int load_adsp_static_apps(struct nvadsp_drv_data *);
bool is_adsp_dram_addr(u64);
int load_adsp_static_apps(void);
#endif /* __TEGRA_NVADSP_OS_H */ #endif /* __TEGRA_NVADSP_OS_H */

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/** /**
* Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2014-2024, NVIDIA CORPORATION. All rights reserved.
*/ */
#ifndef __LINUX_TEGRA_NVADSP_H #ifndef __LINUX_TEGRA_NVADSP_H
@@ -16,11 +16,6 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/completion.h> #include <linux/completion.h>
struct nvadsp_platform_data {
phys_addr_t co_pa;
unsigned long co_size;
};
typedef int status_t; typedef int status_t;
/* /*
@@ -83,32 +78,13 @@ struct nvadsp_mbox {
char name[NVADSP_MBOX_NAME_MAX_STR]; char name[NVADSP_MBOX_NAME_MAX_STR];
struct nvadsp_mbox_queue recv_queue; struct nvadsp_mbox_queue recv_queue;
nvadsp_mbox_handler_t handler; nvadsp_mbox_handler_t handler;
#ifdef CONFIG_MBOX_ACK_HANDLER
nvadsp_mbox_handler_t ack_handler; nvadsp_mbox_handler_t ack_handler;
#endif
void *hdata; void *hdata;
}; };
#define NVADSP_MBOX_SMSG 0x1 #define NVADSP_MBOX_SMSG 0x1
#define NVADSP_MBOX_LMSG 0x2 #define NVADSP_MBOX_LMSG 0x2
status_t nvadsp_mbox_open(struct nvadsp_mbox *mbox, uint16_t *mid,
const char *name, nvadsp_mbox_handler_t handler,
void *hdata);
status_t nvadsp_mbox_send(struct nvadsp_mbox *mbox, uint32_t data,
uint32_t flags, bool block, unsigned int timeout);
status_t nvadsp_mbox_recv(struct nvadsp_mbox *mbox, uint32_t *data, bool block,
unsigned int timeout);
status_t nvadsp_mbox_close(struct nvadsp_mbox *mbox);
#ifdef CONFIG_MBOX_ACK_HANDLER
static inline void register_ack_handler(struct nvadsp_mbox *mbox,
nvadsp_mbox_handler_t handler)
{
mbox->ack_handler = handler;
}
#endif
/* /*
* Circular Message Queue * Circular Message Queue
*/ */
@@ -142,54 +118,12 @@ int32_t msgq_queue_message(msgq_t *msgq, const msgq_message_t *message);
int32_t msgq_dequeue_message(msgq_t *msgq, msgq_message_t *message); int32_t msgq_dequeue_message(msgq_t *msgq, msgq_message_t *message);
#define msgq_discard_message(msgq) msgq_dequeue_message(msgq, NULL) #define msgq_discard_message(msgq) msgq_dequeue_message(msgq, NULL)
/*
* DRAM Sharing
*/
typedef dma_addr_t nvadsp_iova_addr_t;
typedef enum dma_data_direction nvadsp_data_direction_t;
nvadsp_iova_addr_t
nvadsp_dram_map_single(struct device *nvadsp_dev,
void *cpu_addr, size_t size,
nvadsp_data_direction_t direction);
void
nvadsp_dram_unmap_single(struct device *nvadsp_dev,
nvadsp_iova_addr_t iova_addr, size_t size,
nvadsp_data_direction_t direction);
nvadsp_iova_addr_t
nvadsp_dram_map_page(struct device *nvadsp_dev,
struct page *page, unsigned long offset, size_t size,
nvadsp_data_direction_t direction);
void
nvadsp_dram_unmap_page(struct device *nvadsp_dev,
nvadsp_iova_addr_t iova_addr, size_t size,
nvadsp_data_direction_t direction);
void
nvadsp_dram_sync_single_for_cpu(struct device *nvadsp_dev,
nvadsp_iova_addr_t iova_addr, size_t size,
nvadsp_data_direction_t direction);
void
nvadsp_dram_sync_single_for_device(struct device *nvadsp_dev,
nvadsp_iova_addr_t iova_addr, size_t size,
nvadsp_data_direction_t direction);
/* /*
* ADSP OS * ADSP OS
*/ */
typedef const void *nvadsp_os_handle_t; typedef const void *nvadsp_os_handle_t;
void nvadsp_adsp_init(void);
int __must_check nvadsp_os_load(void);
int __must_check nvadsp_os_start(void);
void nvadsp_os_stop(void);
int __must_check nvadsp_os_suspend(void);
void dump_adsp_sys(void);
void nvadsp_get_os_version(char *, int);
int adsp_usage_set(unsigned int val);
unsigned int adsp_usage_get(void);
/* /*
* ADSP TSC * ADSP TSC
*/ */
@@ -287,71 +221,6 @@ typedef struct nvadsp_app_info {
void *priv; void *priv;
} nvadsp_app_info_t; } nvadsp_app_info_t;
nvadsp_app_handle_t __must_check nvadsp_app_load(const char *, const char *);
nvadsp_app_info_t __must_check *nvadsp_app_init(nvadsp_app_handle_t,
nvadsp_app_args_t *);
void nvadsp_app_unload(nvadsp_app_handle_t);
int __must_check nvadsp_app_start(nvadsp_app_info_t *);
int nvadsp_app_stop(nvadsp_app_info_t *);
int nvadsp_app_deinit(nvadsp_app_info_t *);
void *nvadsp_alloc_coherent(size_t, dma_addr_t *, gfp_t);
void nvadsp_free_coherent(size_t, void *, dma_addr_t);
nvadsp_app_info_t __must_check *nvadsp_run_app(nvadsp_os_handle_t, const char *,
nvadsp_app_args_t *, app_complete_status_notifier,
uint32_t, uint32_t, bool);
void nvadsp_exit_app(nvadsp_app_info_t *app, bool terminate);
static inline void
set_app_complete_notifier(
nvadsp_app_info_t *info, app_complete_status_notifier notifier)
{
info->complete_status_notifier = notifier;
}
static inline void wait_for_nvadsp_app_complete(nvadsp_app_info_t *info)
{
/*
* wait_for_complete must be called only after app has started
*/
if (info->state == NVADSP_APP_STATE_STARTED)
wait_for_completion(&info->wait_for_app_complete);
}
/**
* wait_for_nvadsp_app_complete_timeout:
* @info: pointer to nvadsp_app_info_t
* @timeout: timeout value in jiffies
*
* This waits for either a completion of a specific app to be signaled or for a
* specified timeout to expire. It is interruptible. The timeout is in jiffies.
*
* The return value is -ERESTARTSYS if interrupted, 0 if timed out,
* positive (at least 1, or number of jiffies left till timeout) if completed.
*/
static inline long wait_for_nvadsp_app_complete_timeout(nvadsp_app_info_t *info,
unsigned long timeout)
{
int ret = -EINVAL;
/*
* wait_for_complete must be called only after app has started
*/
if (info->state == NVADSP_APP_STATE_STARTED)
ret = wait_for_completion_interruptible_timeout(
&info->wait_for_app_complete, timeout);
return ret;
}
/*
* set adma reg dump callback function pointer
* @cb_adma_regdump: function pointer for callback
*
* This api is exported and can be accessed by adsp audio driver,
* which during adsp init, calls this api to set the callback
* function pointer
*/
void nvadsp_set_adma_dump_reg(void (*cb_adma_regdump)(void));
#ifdef CONFIG_TEGRA_ADSP_DFS #ifdef CONFIG_TEGRA_ADSP_DFS
/* /*
* Override adsp freq and reinit actmon counters * Override adsp freq and reinit actmon counters
@@ -384,10 +253,284 @@ static inline void adsp_update_dfs(bool enable)
} }
#endif #endif
void *nvadsp_aram_request(const char *name, size_t size); void *nvadsp_aram_request(void *aram_handle, const char *name, size_t size);
bool nvadsp_aram_release(void *handle); bool nvadsp_aram_release(void *aram_handle, void *handle);
unsigned long nvadsp_aram_get_address(void *handle); unsigned long nvadsp_aram_get_address(void *handle);
void nvadsp_aram_print(void); void nvadsp_aram_print(void *aram_handle);
int adsp_usage_set(unsigned int val);
unsigned int adsp_usage_get(void);
/* Multi-instance capable interface - START */
/**
* nvadsp_get_handle: Fetch driver instance using unique identfier
*
* @dev_str : Unique identifier string for the driver instance
* (trailing unique identifer in compatible DT property,
* e.g. "adsp", "adsp1", etc.)
*
* Return : Driver instance handle on success, else NULL
*/
struct nvadsp_handle *nvadsp_get_handle(const char *dev_str);
/**
* struct nvadsp_handle:
* - Function interfaces exposed on the driver handle
* - First argument to each API is the handle
* returned from nvadsp_get_handle()
*/
struct nvadsp_handle {
/* Mailbox interfaces */
status_t (*mbox_open)(struct nvadsp_handle *nvadsp_handle,
struct nvadsp_mbox *mbox,
uint16_t *mid, const char *name,
nvadsp_mbox_handler_t handler, void *hdata);
status_t (*mbox_close)(struct nvadsp_handle *nvadsp_handle,
struct nvadsp_mbox *mbox);
status_t (*mbox_send)(struct nvadsp_handle *nvadsp_handle,
struct nvadsp_mbox *mbox, uint32_t data,
uint32_t flags, bool block, unsigned int timeout);
status_t (*mbox_recv)(struct nvadsp_handle *nvadsp_handle,
struct nvadsp_mbox *mbox, uint32_t *data,
bool block, unsigned int timeout);
void (*mbox_set_ack_handler)(struct nvadsp_handle *nvadsp_handle,
struct nvadsp_mbox *mbox,
nvadsp_mbox_handler_t handler);
/* OS interfaces */
void (*get_os_version)(struct nvadsp_handle *nvadsp_handle,
char *buf, int buf_size);
int (*os_load)(struct nvadsp_handle *nvadsp_handle);
int (*os_start)(struct nvadsp_handle *nvadsp_handle);
int (*os_suspend)(struct nvadsp_handle *nvadsp_handle);
void (*os_stop)(struct nvadsp_handle *nvadsp_handle);
/* Debug interfaces */
void (*set_adma_dump_reg)(struct nvadsp_handle *nvadsp_handle,
void (*cb_adma_regdump)(void));
void (*dump_adsp_sys)(struct nvadsp_handle *nvadsp_handle);
/* Memory interfaces */
void *(*alloc_coherent)(struct nvadsp_handle *nvadsp_handle,
size_t size, dma_addr_t *da, gfp_t flags);
void (*free_coherent)(struct nvadsp_handle *nvadsp_handle,
size_t size, void *va, dma_addr_t da);
/* App interfaces */
nvadsp_app_handle_t (*app_load)(struct nvadsp_handle *nvadsp_handle,
const char *appname, const char *appfile);
nvadsp_app_info_t *(*app_init)(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_handle_t handle, nvadsp_app_args_t *args);
int (*app_start)(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *app);
nvadsp_app_info_t *(*run_app)(struct nvadsp_handle *nvadsp_handle,
nvadsp_os_handle_t os_handle,
const char *appfile, nvadsp_app_args_t *app_args,
app_complete_status_notifier notifier, uint32_t stack_sz,
uint32_t core_id, bool block);
int (*app_stop)(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *app);
int (*app_deinit)(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *app);
void (*exit_app)(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *app, bool terminate);
void (*app_unload)(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_handle_t handle);
void (*set_app_complete_cb)(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *info, app_complete_status_notifier notifier);
void (*wait_for_app_complete)(struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *info);
long (*wait_for_app_complete_timeout)(
struct nvadsp_handle *nvadsp_handle,
nvadsp_app_info_t *info, unsigned long timeout);
};
/* Multi-instance capable interface - END */
/* Legacy interface - START (works if only one driver instance is probed) */
static inline status_t nvadsp_mbox_open(struct nvadsp_mbox *mbox,
uint16_t *mid, const char *name,
nvadsp_mbox_handler_t handler, void *hdata)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->mbox_open(h, mbox, mid, name, handler, hdata);
}
static inline status_t nvadsp_mbox_close(struct nvadsp_mbox *mbox)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->mbox_close(h, mbox);
}
static inline status_t nvadsp_mbox_send(struct nvadsp_mbox *mbox,
uint32_t data, uint32_t flags,
bool block, unsigned int timeout)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->mbox_send(h, mbox, data, flags, block, timeout);
}
static inline status_t nvadsp_mbox_recv(struct nvadsp_mbox *mbox,
uint32_t *data, bool block,
unsigned int timeout)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->mbox_recv(h, mbox, data, block, timeout);
}
static inline void register_ack_handler(struct nvadsp_mbox *mbox,
nvadsp_mbox_handler_t handler)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->mbox_set_ack_handler(h, mbox, handler);
}
static inline void nvadsp_get_os_version(char *buf, int buf_size)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->get_os_version(h, buf, buf_size);
}
static inline int nvadsp_os_load(void)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->os_load(h);
}
static inline int nvadsp_os_start(void)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->os_start(h);
}
static inline int nvadsp_os_suspend(void)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->os_suspend(h);
}
static inline void nvadsp_os_stop(void)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->os_stop(h);
}
static inline void nvadsp_set_adma_dump_reg(void (*cb_adma_regdump)(void))
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->set_adma_dump_reg(h, cb_adma_regdump);
}
static inline void dump_adsp_sys(void)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->dump_adsp_sys(h);
}
static inline void *nvadsp_alloc_coherent(
size_t size, dma_addr_t *da, gfp_t flags)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->alloc_coherent(h, size, da, flags);
}
static inline void nvadsp_free_coherent(size_t size, void *va, dma_addr_t da)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->free_coherent(h, size, va, da);
}
static inline nvadsp_app_handle_t nvadsp_app_load(
const char *appname, const char *appfile)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->app_load(h, appname, appfile);
}
static inline nvadsp_app_info_t *nvadsp_app_init(
nvadsp_app_handle_t handle, nvadsp_app_args_t *args)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->app_init(h, handle, args);
}
static inline int nvadsp_app_start(nvadsp_app_info_t *app)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->app_start(h, app);
}
static inline nvadsp_app_info_t *nvadsp_run_app(
nvadsp_os_handle_t os_handle, const char *appfile,
nvadsp_app_args_t *app_args, app_complete_status_notifier notifier,
uint32_t stack_sz, uint32_t core_id, bool block)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->run_app(h, os_handle, appfile, app_args,
notifier, stack_sz, core_id, block);
}
static inline int nvadsp_app_stop(nvadsp_app_info_t *app)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->app_stop(h, app);
}
static inline int nvadsp_app_deinit(nvadsp_app_info_t *app)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->app_deinit(h, app);
}
static inline void nvadsp_exit_app(nvadsp_app_info_t *app, bool terminate)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->exit_app(h, app, terminate);
}
static inline void nvadsp_app_unload(nvadsp_app_handle_t handle)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->app_unload(h, handle);
}
static inline void set_app_complete_notifier(
nvadsp_app_info_t *info,
app_complete_status_notifier notifier)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->set_app_complete_cb(h, info, notifier);
}
static inline void wait_for_nvadsp_app_complete(nvadsp_app_info_t *info)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->wait_for_app_complete(h, info);
}
/**
* wait_for_nvadsp_app_complete_timeout:
* @info: pointer to nvadsp_app_info_t
* @timeout: timeout value in jiffies
*
* This waits for either a completion of a specific app to be signaled or for a
* specified timeout to expire. It is interruptible. The timeout is in jiffies.
*
* The return value is -ERESTARTSYS if interrupted, 0 if timed out,
* positive (at least 1, or number of jiffies left till timeout) if completed.
*/
static inline long wait_for_nvadsp_app_complete_timeout(
nvadsp_app_info_t *info, unsigned long timeout)
{
struct nvadsp_handle *h = nvadsp_get_handle("");
return h->wait_for_app_complete_timeout(h, info, timeout);
}
/* Legacy interface - END */
#endif /* __LINUX_TEGRA_NVADSP_H */ #endif /* __LINUX_TEGRA_NVADSP_H */