/*
- * app.c
+ * run_app.c
*
* ADSP OS App management
*
- * Copyright (C) 2014 NVIDIA Corporation. All rights reserved.
+ * Copyright (C) 2014-2015 NVIDIA Corporation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
#define ADSP_OS_LOAD_TIMEOUT 5000 /* 5000 ms */
#define APP_FRAME_WAIT_TIMEOUT 5000 /* 5000 ms */
-#define OS_LOAD_COMPLETE 0x01
-#define LOAD_APP 0x03
-#define APP_LOAD_RET_STATUS 0x04
-#define APP_INIT 0x05
-#define APP_INIT_STATUS 0x06
-#define APP_START 0x07
-#define APP_START_STATUS 0x08
-#define APP_DEINIT 0x09
-#define APP_DEINIT_STATUS 0x0A
-#define APP_COMPLETE 0x0B
-#define APP_UNLOAD 0x0C
-#define APP_UNLOAD_STATUS 0x0D
+/*ADSP message pool structure */
+union app_loader_msgq {
+ msgq_t msgq;
+ struct {
+ int32_t header[MSGQ_HEADER_WSIZE];
+ int32_t queue[MSGQ_MAX_QUEUE_WSIZE];
+ };
+};
+
+struct adsp_app_shared_msg_pool {
+ union app_loader_msgq app_loader_send_message;
+ union app_loader_msgq app_loader_recv_message;
+} __packed;
+
+/* ADSP app loader message queue */
+struct run_app_instance_data {
+ uint32_t adsp_mod_ptr;
+ uint64_t host_ref;
+ uint32_t adsp_ref;
+ uint32_t dram_data_ptr;
+ uint32_t dram_shared_ptr;
+ uint32_t dram_shared_wc_ptr;
+ uint32_t aram_ptr;
+ uint32_t aram_flag;
+ uint32_t aram_x_ptr;
+ uint32_t aram_x_flag;
+ struct app_mem_size mem_size;
+ nvadsp_app_args_t app_args;
+ uint32_t stack_size;
+ uint32_t message;
+} __packed;
+
+struct app_loader_data {
+ int32_t header[MSGQ_MESSAGE_HEADER_WSIZE];
+ struct run_app_instance_data app_init;
+} __packed;
+
+#pragma pack(4)
+union app_loader_message {
+ msgq_message_t msgq_msg;
+ struct app_loader_data data;
+};
+struct app_complete_status_data {
+ int32_t header[MSGQ_MESSAGE_HEADER_WSIZE];
+ uint64_t host_ref;
+ uint32_t adsp_ref;
+ int32_t status;
+ uint32_t message;
+} __packed;
+
+#pragma pack(4)
+union app_complete_status_message {
+ msgq_message_t msgq_msg;
+ struct app_complete_status_data data;
+};
+
+/*
+ * structure to hold the list of app binaries loaded and
+ * its associated instances.
+*/
struct nvadsp_app_service {
char name[NVADSP_NAME_SZ];
- char file[NVADSP_NAME_SZ];
struct list_head node;
int instance;
- spinlock_t lock;
+ struct mutex lock;
struct list_head app_head;
const uint32_t token;
const struct app_mem_size *mem_size;
struct adsp_module *mod;
};
+/* nvadsp app loader private structure */
struct nvadsp_app_priv_struct {
struct platform_device *pdev;
+ struct completion os_load_complete;
+ struct nvadsp_mbox mbox;
+ struct list_head service_list;
+ struct mutex service_lock_list;
};
static struct nvadsp_app_priv_struct priv;
-static struct nvadsp_mbox mbox;
-static struct list_head service_list;
-#if RECORD_STATS
-static u64 ns_time_native_load_complete;
-#endif
-
-static DECLARE_COMPLETION(os_load);
-static DECLARE_COMPLETION(load_app_status);
-static DECLARE_COMPLETION(app_init_status);
-static DECLARE_COMPLETION(app_start_status);
-static DECLARE_COMPLETION(app_deinit_status);
-static DECLARE_COMPLETION(app_unload_status);
-
-static DEFINE_MUTEX(load_app_mutex);
-static DEFINE_MUTEX(app_init_mutex);
-static DEFINE_MUTEX(app_start_mutex);
-static DEFINE_MUTEX(app_deinit_mutex);
-static DEFINE_MUTEX(app_unload_mutex);
-
-/* app states need to be changed atomically */
-static DEFINE_SPINLOCK(state_lock);
-
-static DEFINE_MUTEX(service_lock_list);
-
-static struct shared_mem_struct *shared;
-
-static inline void print_load_stats(const char *appfile,
- struct app_load_stats *stats, struct device *dev)
-{
-#if RECORD_STATS
- dev_info(dev, "%s total load time %lld us\n",
- appfile, stats->ns_time_load / 1000);
- dev_info(dev, "%s parse load time %lld us\n",
- appfile, stats->ns_time_service_parse / 1000);
- dev_info(dev, "%s module load time %lld us\n",
- appfile, stats->ns_time_module_load / 1000);
- dev_info(dev, "\t request firmware %lld us\n",
- stats->ns_time_req_firmware / 1000);
- dev_info(dev, "\t layout and allocate %lld us\n",
- stats->ns_time_layout / 1000);
- dev_info(dev, "%s native load time %lld us\n",
- appfile, stats->ns_time_native_load / 1000);
- dev_info(dev, "\t load mbox_send time %lld us\n",
- stats->ns_time_load_mbox_send_time / 1000);
- dev_info(dev, "\t load native wait time %lld us\n",
- stats->ns_time_load_wait_time / 1000);
- dev_info(dev, "\t\t load native load complete %lld us\n",
- stats->ns_time_native_load_complete / 1000);
- dev_info(dev, "\t\t\t adsp map %llu us\n",
- stats->ns_time_adsp_map);
- dev_info(dev, "\t\t\t adsp app load %llu us\n",
- stats->ns_time_adsp_app_load);
- dev_info(dev, "\t\t\t adsp app load send ack %llu us\n",
- stats->ns_time_adsp_send_status);
- dev_info(dev, "\t\t\t latency in receiveing the mbox on adsp %llu\n",
- stats->adsp_receive_timestamp - stats->host_send_timestamp);
- dev_info(dev, "\t\t\t latency in receiveing the mbox on host %llu\n",
- stats->host_receive_timestamp - stats->adsp_receive_timestamp);
- dev_info(dev, "%s timestamp before send %llu\n",
- appfile, stats->host_send_timestamp);
- dev_info(dev, "%s timestamp on adsp receive %llu\n",
- appfile, stats->adsp_receive_timestamp);
- dev_info(dev, "%s timestamp on adsp receive %llu\n",
- appfile, stats->host_receive_timestamp);
-#endif
-}
-
-static inline void print_init_stats(const char *appfile,
- struct app_init_stats *stats, struct device *dev)
-{
-#if RECORD_STATS
- dev_info(dev, "%s app takes %lld us to init\n",
- appfile, stats->ns_time_app_init / 1000);
- dev_info(dev, "\t app instance allocation %lld us\n",
- stats->ns_time_app_alloc / 1000);
- dev_info(dev, "\t app instance memory allocation %lld us\n",
- stats->ns_time_instance_memory / 1000);
- dev_info(dev, "\t app instance native init call %lld us\n",
- stats->ns_time_native_call / 1000);
- dev_info(dev, "\t\t app init call on adsp %llu us\n",
- stats->ns_time_adsp_app_init);
- dev_info(dev, "\t\t\t app instance map on adsp %llu us\n",
- stats->ns_time_adsp_mem_instance_map);
- dev_info(dev, "\t\t\t app actual init call on adsp %llu us\n",
- stats->ns_time_adsp_init_call);
- dev_info(dev, "\t\t app send init status ack %llu us\n",
- stats->ns_time_adsp_send_status);
-#endif
-}
-
-static inline void print_start_stats(const char *appfile,
- struct app_start_stats *stats, struct device *dev)
-{
-#if RECORD_STATS
- dev_info(dev, "%s app takes %lld us to start\n",
- appfile, stats->ns_time_app_start / 1000);
- dev_info(dev, "\t app instance native init call %lld us\n",
- stats->ns_time_native_call / 1000);
- dev_info(dev, "\t\t app start call on adsp %llu us\n",
- stats->ns_time_adsp_app_start);
- dev_info(dev, "\t\t\t app thread creation %llu us\n",
- stats->ns_time_app_thread_creation);
- dev_info(dev, "\t\t\t app thread detach %llu us\n",
- stats->ns_time_app_thread_detach);
- dev_info(dev, "\t\t\t app threaad resume %llu us\n",
- stats->ns_time_app_thread_resume);
- dev_info(dev, "\t\t app send start status ack %llu us\n",
- stats->ns_time_adsp_send_status);
-#endif
-}
-
-
-static inline int wait_for_app_frame_timeout(struct completion *complete)
-{
- unsigned long timeout = msecs_to_jiffies(APP_FRAME_WAIT_TIMEOUT);
- return wait_for_completion_interruptible_timeout(complete, timeout);
-}
-
-static void app_complete_notifier(struct work_struct *work)
-{
- nvadsp_app_info_t *app = container_of(work,
- struct nvadsp_app_info, complete_work);
-
- app->complete_status_notifier(app, ADSP_APP_COMPLETE_STATUS,
- app->return_status);
-}
-
-static void notify_update_nvadsp_app_complete(struct app_complete_data *data)
+static struct nvadsp_app_service *get_loaded_service(const char *appfile)
{
- nvadsp_app_info_t *app = (nvadsp_app_info_t *)data->host_ref;
- int *state;
- unsigned long flags;
-
- app->return_status = data->app_status;
-
- /* notify adsp can process next data */
- data->copy_complete = 0;
-
- /* set the app instance as initialized to be reused or deinit */
- state = (int *)&app->state;
- spin_lock_irqsave(&state_lock, flags);
- *state = NVADSP_APP_STATE_INITIALIZED;
- spin_unlock_irqrestore(&state_lock, flags);
- /*
- * schedule the work if there is notifier call back and adsp app
- * instance has started
- */
- if (app->complete_status_notifier)
- schedule_work(&app->complete_work);
-
- /* notify app instance has completed */
- complete_all(&app->wait_for_app_complete);
-}
-
-static status_t nvadsp_app_receive_handler(uint32_t data, void *hdata)
-{
- struct nvadsp_app_priv_struct *priv = hdata;
- struct device *dev = &priv->pdev->dev;
- struct app_load_data *load;
-
- load = &shared->app_load;
- RECORD_TIMESTAMP(load->receive_timestamp);
- switch (data) {
- case OS_LOAD_COMPLETE:
- dev_dbg(dev, "in OS_LOAD_COMPLETE\n");
- complete(&os_load);
- break;
-
- case APP_LOAD_RET_STATUS:
- dev_dbg(dev, "in APP_LOAD_RET_STATUS\n");
- RECORD_STAT(ns_time_native_load_complete);
- complete(&load_app_status);
- break;
-
- case APP_UNLOAD_STATUS:
- dev_dbg(dev, "in APP_LOAD_RET_STATUS\n");
- complete(&app_unload_status);
- break;
-
- case APP_INIT_STATUS:
- dev_dbg(dev, "in APP_INIT_STATUS\n");
- complete(&app_init_status);
- break;
-
- case APP_DEINIT_STATUS:
- dev_dbg(dev, "in APP_DEINIT_STATUS\n");
- complete(&app_deinit_status);
- break;
-
- case APP_START_STATUS:
- dev_dbg(dev, "in APP_START_STATUS\n");
- complete(&app_start_status);
- break;
-
- case APP_COMPLETE:
- dev_dbg(dev, "in APP_COMPLETE\n");
- notify_update_nvadsp_app_complete(&shared->app_complete);
- break;
+ struct device *dev = &priv.pdev->dev;
+ struct nvadsp_app_service *ser;
- default:
- dev_err(dev, "received wrong data\n");
+ list_for_each_entry(ser, &priv.service_list, node) {
+ if (!strcmp(appfile, ser->name)) {
+ dev_dbg(dev, "module %s already loaded\n", appfile);
+ return ser;
+ }
}
- return 0;
+ dev_dbg(dev, "module %s will be loaded\n", appfile);
+ return NULL;
}
-int wait_for_adsp_os_load_complete(void)
+static nvadsp_app_handle_t app_load(const char *appfile)
{
struct device *dev = &priv.pdev->dev;
- unsigned long timeout;
- int ret;
-
- timeout = msecs_to_jiffies(ADSP_OS_LOAD_TIMEOUT);
- ret = wait_for_completion_timeout(&os_load, timeout);
- if (!ret) {
- dev_err(dev, "ADSP OS loading timed out\n");
- ret = -ETIMEDOUT;
- } else
- ret = 0;
-
- return ret;
-}
-static inline void native_adsp_app_start_stats(struct app_start_stats *stats,
- struct app_start_data *data)
-{
- EQUATE_STAT(stats->ns_time_adsp_app_start, data->app_start_time);
- EQUATE_STAT(stats->ns_time_app_thread_creation,
- data->app_thread_creation_time);
- EQUATE_STAT(stats->ns_time_app_thread_detach,
- data->app_thread_detach_time);
- EQUATE_STAT(stats->ns_time_app_thread_resume,
- data->app_thread_resume_time);
- EQUATE_STAT(stats->ns_time_adsp_send_status,
- data->adsp_send_status_time);
- EQUATE_STAT(stats->adsp_receive_timestamp, data->timestamp);
-}
-
-static int native_adsp_app_start(nvadsp_app_info_t *app,
- struct app_start_stats *stats)
-{
- struct app_start_data *data = &shared->app_start;
- int32_t status = -EINVAL;
+ struct nvadsp_app_service *ser;
+ struct app_load_stats stats;
- data->ptr = app->token;
- data->stack_size = app->stack_size;
+ mutex_lock(&priv.service_lock_list);
+ ser = get_loaded_service(appfile);
+ if (!ser) {
+ dev_dbg(dev, "loading app %s\n", appfile);
- nvadsp_mbox_send(&mbox, APP_START, NVADSP_MBOX_SMSG, true, 100);
- status = (wait_for_app_frame_timeout(&app_start_status) <= 0)
- ? status : data->status;
- native_adsp_app_start_stats(stats, data);
- memset(data, 0, sizeof(struct app_start_data));
+ ser = devm_kzalloc(dev, sizeof(*ser), GFP_KERNEL);
+ if (!ser)
+ goto err;
+ strncpy(ser->name, appfile, NVADSP_NAME_SZ);
- return status;
-}
+ /*load the module in to memory */
+ ser->mod = load_adsp_module(appfile, appfile, dev, &stats);
+ if (IS_ERR_OR_NULL(ser->mod))
+ goto err_free_service;
+ ser->mem_size = &ser->mod->mem_size;
-static struct nvadsp_app_service
-*get_loaded_service(const char *appname)
-{
- struct device *dev = &priv.pdev->dev;
- struct nvadsp_app_service *ser;
+ mutex_init(&ser->lock);
+ INIT_LIST_HEAD(&ser->app_head);
- mutex_lock(&service_lock_list);
- list_for_each_entry(ser, &service_list, node) {
- if (!strcmp(appname, ser->name)) {
- dev_dbg(dev, "module %s already loaded\n", appname);
- mutex_unlock(&service_lock_list);
- return ser;
- }
+ /* add the app instance service to the list */
+ list_add_tail(&ser->node, &priv.service_list);
+ dev_dbg(dev, "loaded app %s\n", ser->name);
}
- mutex_unlock(&service_lock_list);
- dev_dbg(dev, "module %s can be loaded\n", appname);
- return NULL;
-}
-
-static inline void native_adsp_load_stats(struct app_load_stats *stats,
- struct app_load_data *data)
-{
- EQUATE_STAT(stats->ns_time_native_load_complete,
- ns_time_native_load_complete);
- EQUATE_STAT(stats->ns_time_adsp_map, data->map_time);
- EQUATE_STAT(stats->ns_time_adsp_app_load, data->app_load_time);
- EQUATE_STAT(stats->ns_time_adsp_send_status,
- data->adsp_send_status_time);
- EQUATE_STAT(stats->adsp_receive_timestamp, data->timestamp);
- EQUATE_STAT(stats->host_receive_timestamp, data->receive_timestamp);
- EQUATE_STAT(ns_time_native_load_complete, 0);
-}
+ mutex_unlock(&priv.service_lock_list);
-static uint32_t native_adsp_load_app(struct nvadsp_app_service *ser,
- struct app_load_stats *stats)
-{
- uint32_t status = 0;
- struct app_load_data *data = &shared->app_load;
+ return ser;
- memcpy(&data->mem_size, ser->mem_size,
- sizeof(struct app_mem_size));
-#if !CONFIG_USE_STATIC_APP_LOAD
- data->adsp_mod_ptr = ser->mod->adsp_module_ptr;
- data->adsp_mod_size = ser->mod->size;
-#else
- strncpy(data->service_name, ser->name, NVADSP_NAME_SZ);
-#endif
-
- RECORD_TIMESTAMP(stats->host_send_timestamp);
- RECORD_STAT(stats->ns_time_load_mbox_send_time);
- nvadsp_mbox_send(&mbox, LOAD_APP, NVADSP_MBOX_SMSG, true, 100);
- RECORD_STAT(stats->ns_time_load_mbox_send_time);
-
- RECORD_STAT(stats->ns_time_load_wait_time);
- RECORD_STAT(ns_time_native_load_complete);
- status = (wait_for_app_frame_timeout(&load_app_status) <= 0)
- ? status : data->ser;
- RECORD_STAT(stats->ns_time_load_wait_time);
- native_adsp_load_stats(stats, data);
- memset(data, 0, sizeof(struct app_load_data));
-
- return status;
+err_free_service:
+ devm_kfree(dev, ser);
+err:
+ mutex_unlock(&priv.service_lock_list);
+ return NULL;
}
-void update_nvadsp_app_shared_ptr(void *ptr)
-{
- shared = (struct shared_mem_struct *)ptr;
-}
-nvadsp_app_handle_t
-nvadsp_app_load(const char *appname, const char *appfile)
+nvadsp_app_handle_t nvadsp_app_load(const char *appname, const char *appfile)
{
- struct nvadsp_app_service *ser = NULL;
- struct app_load_stats stats = { };
struct nvadsp_drv_data *drv_data;
- struct adsp_module *mod;
- struct device *dev;
- uint32_t *token;
- if (!priv.pdev) {
+ if (IS_ERR_OR_NULL(priv.pdev)) {
pr_err("ADSP Driver is not initialized\n");
- goto end;
+ return NULL;
}
drv_data = platform_get_drvdata(priv.pdev);
- dev = &priv.pdev->dev;
if (!drv_data->adsp_os_running)
- goto end;
+ return NULL;
+ return app_load(appfile);
+}
+EXPORT_SYMBOL(nvadsp_app_load);
- RECORD_STAT(stats.ns_time_load);
- RECORD_STAT(stats.ns_time_service_parse);
- ser = get_loaded_service(appname);
- RECORD_STAT(stats.ns_time_service_parse);
- if (!ser) {
- dev_dbg(dev, "loading app %s\n", appname);
+static void free_instance_memory(nvadsp_app_info_t *app,
+ const struct app_mem_size *sz)
+{
+ adsp_app_mem_t *mem = &app->mem;
+ adsp_app_iova_mem_t *iova_mem = &app->iova_mem;
- RECORD_STAT(stats.ns_time_module_load);
- mod = load_adsp_module(appname, appfile, dev, &stats);
- if (IS_ERR_OR_NULL(mod))
- goto end;
- RECORD_STAT(stats.ns_time_module_load);
-
- ser = kzalloc(sizeof(struct nvadsp_app_service), GFP_KERNEL);
- strncpy(ser->name, appname, NVADSP_NAME_SZ);
- strncpy(ser->file, appfile, NVADSP_NAME_SZ);
- ser->mod = mod;
-
- ser->mem_size = &mod->mem_size;
- token = (void *)&ser->token;
- RECORD_STAT(stats.ns_time_native_load);
- mutex_lock(&load_app_mutex);
- *token = native_adsp_load_app(ser, &stats);
- mutex_unlock(&load_app_mutex);
- RECORD_STAT(stats.ns_time_native_load);
- if (!ser->token) {
- dev_err(dev, "unable to load app %s\n", appname);
- goto err;
- }
- spin_lock_init(&ser->lock);
- INIT_LIST_HEAD(&ser->app_head);
+ if (mem->dram) {
+ nvadsp_free_coherent(sz->dram, mem->dram, iova_mem->dram);
+ mem->dram = NULL;
+ iova_mem->dram = 0;
+ }
- /* add the app instance service to the list */
- mutex_lock(&service_lock_list);
- list_add_tail(&ser->node, &service_list);
- mutex_unlock(&service_lock_list);
+ if (mem->shared) {
+ nvadsp_free_coherent(sz->dram_shared, mem->shared,
+ iova_mem->shared);
+ mem->shared = NULL;
+ iova_mem->shared = 0;
+ }
- dev_dbg(dev, "loaded app %s\n", ser->name);
+ if (mem->shared_wc) {
+ nvadsp_free_coherent(sz->dram_shared_wc, mem->shared_wc,
+ iova_mem->shared_wc);
+ mem->shared_wc = NULL;
+ iova_mem->shared_wc = 0;
+ }
+
+ if (mem->aram_flag)
+ aram_release(mem->aram);
+ else if (mem->aram)
+ nvadsp_free_coherent(sz->aram, mem->aram, iova_mem->aram);
+ mem->aram = NULL;
+ iova_mem->aram = 0;
+ mem->aram_flag = 0;
+
+ if (mem->aram_x_flag) {
+ aram_release(mem->aram_x);
+ mem->aram_x = NULL;
+ iova_mem->aram_x = 0;
+ mem->aram_flag = 0;
}
- RECORD_STAT(stats.ns_time_load);
- print_load_stats(appfile, &stats, dev);
-end:
- return ser;
-err:
- kfree(ser);
- return NULL;
}
-EXPORT_SYMBOL(nvadsp_app_load);
-static int
-create_instance_memory(nvadsp_app_info_t *app, const struct app_mem_size *sz)
+static int create_instance_memory(nvadsp_app_info_t *app,
+ const struct app_mem_size *sz)
{
+ adsp_app_iova_mem_t *iova_mem = &app->iova_mem;
struct device *dev = &priv.pdev->dev;
adsp_app_mem_t *mem = &app->mem;
- adsp_app_iova_mem_t *iova_mem = &app->iova_mem;
- dma_addr_t da;
- void *aram_handle;
char name[NVADSP_NAME_SZ];
+ void *aram_handle;
+ dma_addr_t da;
snprintf(name, NVADSP_NAME_SZ, "%s:%d", app->name, app->instance_id);
if (sz->dram) {
mem->dram = nvadsp_alloc_coherent(sz->dram, &da, GFP_KERNEL);
+ iova_mem->dram = (uint32_t)da;
if (!mem->dram) {
- dev_err(dev,
- "cannot allocate dram memory for app %s instance\n",
- name);
+ dev_err(dev, "app %s dram alloc failed\n",
+ name);
goto end;
}
- iova_mem->dram = (uint32_t)da;
- dev_dbg(dev, "%s :: mem.dram %p 0x%x\n",
- name, mem->dram, iova_mem->dram);
+ dev_dbg(dev, "%s :: mem.dram %p 0x%x\n", name,
+ mem->dram, iova_mem->dram);
}
if (sz->dram_shared) {
mem->shared = nvadsp_alloc_coherent(sz->dram_shared,
- &da, GFP_KERNEL);
+ &da, GFP_KERNEL);
if (!mem->shared) {
- dev_err(dev,
- "cannot allocate dram shared for app %s instance\n",
- name);
- goto free_dram;
+ dev_err(dev, "app %s shared dram alloc failed\n",
+ name);
+ goto end;
}
iova_mem->shared = (uint32_t)da;
- dev_dbg(dev, "%s :: mem.shared %p 0x%x\n",
- name, mem->shared, iova_mem->shared);
+ dev_dbg(dev, "%s :: mem.shared %p 0x%x\n", name,
+ mem->shared, iova_mem->shared);
}
if (sz->dram_shared_wc) {
- mem->shared_wc = nvadsp_alloc_coherent(
- sz->dram_shared_wc, &da, GFP_KERNEL);
+ mem->shared_wc = nvadsp_alloc_coherent(sz->dram_shared_wc,
+ &da, GFP_KERNEL);
if (!mem->shared_wc) {
- dev_err(dev,
- "cannot allocate dram shared for app %s instance\n",
- name);
- goto free_dram_shared;
+ dev_err(dev, "app %s shared dram wc alloc failed\n",
+ name);
+ goto end;
}
iova_mem->shared_wc = (uint32_t)da;
- dev_dbg(dev, "%s: :: mem.shared_wc %p 0x%x\n",
- name, mem->shared_wc, iova_mem->shared_wc);
+ dev_dbg(dev, "%s :: mem.shared_wc %p 0x%x\n", name,
+ mem->shared_wc, iova_mem->shared_wc);
}
if (sz->aram) {
iova_mem->aram_flag = mem->aram_flag = 1;
dev_dbg(dev, "%s aram %x\n", name, iova_mem->aram);
} else {
- dev_info(dev,
- "No ARAM memory avialable ! allocating from DRAM for app %s instance\n",
- name);
+ dev_dbg(dev, "app %s no ARAM memory ! using DRAM\n",
+ name);
mem->aram = nvadsp_alloc_coherent(sz->aram,
&da, GFP_KERNEL);
if (!mem->aram) {
+ iova_mem->aram_flag = mem->aram_flag = 0;
dev_err(dev,
- "cannot allocate aram memory from dram for app %s instance\n",
- name);
- goto free_dram_shared_wc;
+ "app %s aram memory alloc failed\n",
+ name);
+ goto end;
}
iova_mem->aram = (uint32_t)da;
- iova_mem->aram_flag = mem->aram_flag = 0;
- dev_dbg(dev, "mem.aram %p 0x%x\n",
- mem->aram, iova_mem->aram);
+ dev_dbg(dev, "%s :: mem.aram %p 0x%x\n", name,
+ mem->aram, iova_mem->aram);
}
}
} else {
iova_mem->aram_x = 0;
iova_mem->aram_x_flag = mem->aram_x_flag = 0;
- dev_err(dev,
- "unable to allocate exclusive memory for app instance %s\n",
- name);
+ dev_err(dev, "app %s aram x memory alloc failed\n",
+ name);
}
}
return 0;
-free_dram_shared_wc:
- if (sz->dram_shared_wc)
- nvadsp_free_coherent(sz->dram_shared_wc, mem->shared_wc,
- iova_mem->shared_wc);
-free_dram_shared:
- if (sz->dram_shared)
- nvadsp_free_coherent(sz->dram_shared, mem->shared,
- iova_mem->shared);
-free_dram:
- if (sz->dram)
- nvadsp_free_coherent(sz->dram, mem->dram, iova_mem->dram);
end:
+ free_instance_memory(app, sz);
return -ENOMEM;
}
-static void free_instance_memory(nvadsp_app_info_t *app,
- const struct app_mem_size *sz)
-{
- adsp_app_mem_t *mem = &app->mem;
- adsp_app_iova_mem_t *iova_mem = &app->iova_mem;
-
- if (sz->dram)
- nvadsp_free_coherent(sz->dram, mem->dram, iova_mem->dram);
-
- if (sz->dram_shared)
- nvadsp_free_coherent(sz->dram_shared, mem->shared,
- iova_mem->shared);
- if (sz->dram_shared_wc)
- nvadsp_free_coherent(sz->dram_shared_wc, mem->shared_wc,
- iova_mem->shared_wc);
- if (sz->aram) {
- if (mem->aram_flag)
- aram_release(mem->aram);
- else
- nvadsp_free_coherent(sz->aram,
- mem->aram, iova_mem->aram);
- }
-
- if (sz->aram_x && mem->aram_x_flag)
- aram_release(mem->aram_x);
-
-}
-
-static inline void native_adsp_init_stats(struct app_init_stats *stats,
- struct app_init_data *data)
+static void fill_app_instance_data(nvadsp_app_info_t *app,
+ struct nvadsp_app_service *ser, nvadsp_app_args_t *app_args,
+ struct run_app_instance_data *data, uint32_t stack_sz)
{
- EQUATE_STAT(stats->ns_time_adsp_app_init, data->app_init_time);
- EQUATE_STAT(stats->ns_time_adsp_mem_instance_map,
- data->app_mem_instance_map);
- EQUATE_STAT(stats->ns_time_adsp_init_call, data->app_init_call);
- EQUATE_STAT(stats->ns_time_adsp_send_status,
- data->adsp_send_status_time);
- EQUATE_STAT(stats->adsp_receive_timestamp, data->timestamp);
-}
-
-static uint32_t
-native_adsp_app_init(nvadsp_app_info_t *app,
- const struct nvadsp_app_service *ser, nvadsp_app_args_t *app_args,
- struct app_init_stats *stats)
-{
- uint32_t token = 0;
- struct app_init_data *data = &shared->app_init;
adsp_app_iova_mem_t *iova_mem = &app->iova_mem;
+ data->adsp_mod_ptr = ser->mod->adsp_module_ptr;
/* copy the iova address to adsp so that adsp can access the memory */
data->dram_data_ptr = iova_mem->dram;
data->dram_shared_ptr = iova_mem->shared;
if (app_args)
memcpy(&data->app_args, app_args, sizeof(nvadsp_app_args_t));
- /*
- * app on adsp needs to know the service from which it should instance
- */
- data->ser = ser->token;
/*
* app on adsp holds the reference of host app instance to communicate
* back when completed. This way we do not need to iterate through the
*/
data->host_ref = (uint64_t)app;
- /* call the adsp app init function on ADSP */
- nvadsp_mbox_send(&mbox, APP_INIT, NVADSP_MBOX_SMSG, true, 100);
- /* store the app instance structure if successful */
- token = (wait_for_app_frame_timeout(&app_init_status) <= 0)
- ? token : data->app_token;
- native_adsp_init_stats(stats, data);
- /* clear shared app init data structure */
- memset(data, 0, sizeof(struct app_init_data));
- return token;
+ /* copy instance mem_size */
+ memcpy(&data->mem_size, ser->mem_size, sizeof(struct app_mem_size));
}
-nvadsp_app_info_t *nvadsp_app_init(nvadsp_app_handle_t handle,
- nvadsp_app_args_t *app_args)
+static nvadsp_app_info_t *create_app_instance(nvadsp_app_handle_t handle,
+ nvadsp_app_args_t *app_args, struct run_app_instance_data *data,
+ app_complete_status_notifier notifier, uint32_t stack_size)
{
struct nvadsp_app_service *ser = (void *)handle;
- struct app_init_stats stats = { };
- struct nvadsp_drv_data *drv_data;
+ struct device *dev = &priv.pdev->dev;
nvadsp_app_info_t *app;
- unsigned long flags;
- struct device *dev;
- uint32_t *token;
int *state;
int *id;
- if (!priv.pdev) {
- pr_err("ADSP Driver is not initialized\n");
- goto err_value;
- }
-
- drv_data = platform_get_drvdata(priv.pdev);
- dev = &priv.pdev->dev;
-
- if (!drv_data->adsp_os_running)
- goto err_value;
-
- if (IS_ERR_OR_NULL(handle))
- goto err_value;
-
- RECORD_STAT(stats.ns_time_app_init);
- EQUATE_STAT(stats.ns_time_app_alloc, stats.ns_time_app_init);
- app = kzalloc(sizeof(nvadsp_app_info_t), GFP_KERNEL);
+ app = kzalloc(sizeof(*app), GFP_KERNEL);
if (unlikely(!app)) {
dev_err(dev, "cannot allocate memory for app %s instance\n",
ser->name);
goto err_value;
}
- RECORD_STAT(stats.ns_time_app_alloc);
-
/* set the instance name with the app name */
app->name = ser->name;
/* associate a unique id */
id = (int *)&app->instance_id;
*id = ser->generated_instance_id++;
+ /*
+ * hold the pointer to the service, to dereference later during deinit
+ */
+ app->handle = ser;
/* create the instance memory required by the app instance */
- RECORD_STAT(stats.ns_time_instance_memory);
if (create_instance_memory(app, ser->mem_size)) {
dev_err(dev, "instance creation failed for app %s:%d\n",
app->name, app->instance_id);
goto free_app;
}
- RECORD_STAT(stats.ns_time_instance_memory);
-
- /* token holds the app instance pointer created on adsp */
- token = (void *)&app->token;
- RECORD_STAT(stats.ns_time_native_call);
- mutex_lock(&app_init_mutex);
- *token = native_adsp_app_init(app, ser, app_args, &stats);
- mutex_unlock(&app_init_mutex);
- RECORD_STAT(stats.ns_time_native_call);
-
- if (!app->token) {
- dev_err(dev, "app failed to initilize %s\n", app->name);
- goto free_instance_memory;
- }
- /*
- * hold the pointer to the service, to dereference later during deinit
- */
- app->handle = ser;
-
- /*
- * Initilize the complete work which returns the return value after
- * execution
- */
- INIT_WORK(&app->complete_work, app_complete_notifier);
+ /* assign the stack that is needed by the app */
+ data->stack_size = stack_size;
/* set the state to INITIALIZED. No need to do it in a spin lock */
state = (int *)&app->state;
*state = NVADSP_APP_STATE_INITIALIZED;
/* increment instance count and add the app instance to service list */
- spin_lock_irqsave(&ser->lock, flags);
+ mutex_lock(&ser->lock);
list_add_tail(&app->node, &ser->app_head);
ser->instance++;
- spin_unlock_irqrestore(&ser->lock, flags);
+ mutex_unlock(&ser->lock);
+
+ fill_app_instance_data(app, ser, app_args, data, stack_size);
+
+ init_completion(&app->wait_for_app_start);
+ init_completion(&app->wait_for_app_complete);
+ set_app_complete_notifier(app, notifier);
dev_dbg(dev, "app %s instance %d initilized\n",
app->name, app->instance_id);
dev_dbg(dev, "app %s has %d instances\n", ser->name, ser->instance);
+ goto end;
- RECORD_STAT(stats.ns_time_app_init);
- print_init_stats(ser->file, &stats, dev);
- return app;
-
-free_instance_memory:
- free_instance_memory(app, ser->mem_size);
free_app:
kfree(app);
err_value:
app = ERR_PTR(-ENOMEM);
+end:
return app;
}
+
+nvadsp_app_info_t __must_check *nvadsp_app_init(nvadsp_app_handle_t handle,
+ nvadsp_app_args_t *args)
+{
+ struct adsp_app_shared_msg_pool *msg_pool;
+ union app_loader_message *message;
+ struct nvadsp_drv_data *drv_data;
+ struct app_loader_data *data;
+ nvadsp_app_info_t *app;
+ msgq_t *msgq_send;
+ int *state;
+
+ if (IS_ERR_OR_NULL(priv.pdev)) {
+ pr_err("ADSP Driver is not initialized\n");
+ goto err;
+ }
+
+ drv_data = platform_get_drvdata(priv.pdev);
+
+ if (!drv_data->adsp_os_running)
+ goto err;
+
+ message = kzalloc(sizeof(*message), GFP_KERNEL);
+ if (!message)
+ goto err;
+
+ msg_pool = drv_data->shared_adsp_os_data;
+ msgq_send = &msg_pool->app_loader_send_message.msgq;
+ data = &message->data;
+
+ app = create_app_instance(handle, args, &data->app_init, NULL, 0);
+ if (IS_ERR_OR_NULL(app)) {
+ kfree(message);
+ goto err;
+ }
+ app->priv = data;
+ data->app_init.message = ADSP_APP_INIT;
+
+ message->msgq_msg.size = MSGQ_MSG_PAYLOAD_WSIZE(*message);
+ msgq_queue_message(msgq_send, &message->msgq_msg);
+
+ if (app->return_status) {
+ state = (int *)&app->state;
+ *state = NVADSP_APP_STATE_STARTED;
+ }
+
+ nvadsp_mbox_send(&priv.mbox, 0, NVADSP_MBOX_SMSG, false, 0);
+
+ wait_for_completion(&app->wait_for_app_start);
+ init_completion(&app->wait_for_app_start);
+ return app;
+err:
+ return ERR_PTR(-ENOMEM);
+}
EXPORT_SYMBOL(nvadsp_app_init);
-static int native_adsp_app_deinit(nvadsp_app_info_t *app)
+static void start_app_on_adsp(nvadsp_app_info_t *app,
+ union app_loader_message *message, bool block)
{
- struct app_deinit_data *data = &shared->app_deinit;
- int32_t status = -EINVAL;
-
- data->ptr = app->token;
- nvadsp_mbox_send(&mbox, APP_DEINIT, NVADSP_MBOX_SMSG, true, 100);
- status = (wait_for_app_frame_timeout(&app_deinit_status) <= 0)
- ? status : data->status;
- memset(data, 0, sizeof(struct app_deinit_data));
- return status;
+ struct adsp_app_shared_msg_pool *msg_pool;
+ struct nvadsp_drv_data *drv_data;
+ msgq_t *msgq_send;
+ int *state;
+
+ drv_data = platform_get_drvdata(priv.pdev);
+ msg_pool = drv_data->shared_adsp_os_data;
+ msgq_send = &msg_pool->app_loader_send_message.msgq;
+
+ message->msgq_msg.size = MSGQ_MSG_PAYLOAD_WSIZE(*message);
+ msgq_queue_message(msgq_send, &message->msgq_msg);
+
+ state = (int *)&app->state;
+ *state = NVADSP_APP_STATE_STARTED;
+
+ nvadsp_mbox_send(&priv.mbox, 0, NVADSP_MBOX_SMSG, false, 0);
+
+ if (block) {
+ wait_for_completion(&app->wait_for_app_start);
+ if (app->return_status) {
+ pr_info("app instance failed to start\n");
+ state = (int *)&app->state;
+ *state = NVADSP_APP_STATE_INITIALIZED;
+ }
+ }
}
-int nvadsp_app_deinit(nvadsp_app_info_t *app)
+int nvadsp_app_start(nvadsp_app_info_t *app)
{
+ union app_loader_message *message = app->priv;
+ struct app_loader_data *data = &message->data;
struct nvadsp_drv_data *drv_data;
- unsigned long flags;
+
+ if (IS_ERR_OR_NULL(app))
+ return -EINVAL;
+
+ if (IS_ERR_OR_NULL(priv.pdev)) {
+ pr_err("ADSP Driver is not initialized\n");
+ goto err;
+ }
+
+ drv_data = platform_get_drvdata(priv.pdev);
+
+ if (!drv_data->adsp_os_running)
+ goto err;
+
+ data->app_init.message = ADSP_APP_START;
+ data->app_init.adsp_ref = app->token;
+ data->app_init.stack_size = app->stack_size;
+ start_app_on_adsp(app, app->priv, true);
+err:
+ return (app->state == NVADSP_APP_STATE_STARTED) ? 0 : -EINVAL;
+}
+EXPORT_SYMBOL(nvadsp_app_start);
+
+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, bool block)
+{
+ union app_loader_message message = {};
+ nvadsp_app_handle_t service_handle;
+ struct nvadsp_drv_data *drv_data;
+ nvadsp_app_info_t *info = NULL;
+ struct app_loader_data *data;
struct device *dev;
- int ret = -EINVAL;
- int *state;
- if (!priv.pdev) {
+ if (IS_ERR_OR_NULL(priv.pdev)) {
pr_err("ADSP Driver is not initialized\n");
+ info = ERR_PTR(-EINVAL);
goto end;
}
if (!drv_data->adsp_os_running)
goto end;
- if (IS_ERR_OR_NULL(app))
+ if (IS_ERR_OR_NULL(appfile))
goto end;
- state = (int *)&app->state;
- /* check and update state of app atomically */
- spin_lock_irqsave(&state_lock, flags);
- if (*state == NVADSP_APP_STATE_INITIALIZED) {
- *state = NVADSP_APP_STATE_UNKNOWN;
- spin_unlock_irqrestore(&state_lock, flags);
-
- /* free the adsp instance from app side */
- mutex_lock(&app_deinit_mutex);
- ret = native_adsp_app_deinit(app);
- mutex_unlock(&app_deinit_mutex);
-
- if (likely(!ret)) {
- struct nvadsp_app_service *ser =
- (struct nvadsp_app_service *)app->handle;
- dev_dbg(dev, "%s:freeing app %s:%d\n",
- __func__, app->name, app->instance_id);
-
- /* update the service app instance manager atomically */
- spin_lock_irqsave(&ser->lock, flags);
- ser->instance--;
- list_del(&app->node);
- dev_dbg(dev, "%s: the app %s has instance %d\n",
- __func__, ser->name, ser->instance);
- spin_unlock_irqrestore(&ser->lock, flags);
-
- /* free instance memory */
- free_instance_memory(app, ser->mem_size);
- kfree(app);
- } else {
- /*
- * this should not happen, This means there is something
- * wrong.
- */
- WARN(1, "invalid states maintained on ADSP and HOST for app %s:%d",
- app->name, app->instance_id);
- spin_lock_irqsave(&state_lock, flags);
- *state = NVADSP_APP_STATE_INITIALIZED;
- spin_unlock_irqrestore(&state_lock, flags);
- }
- } else {
- spin_unlock_irqrestore(&state_lock, flags);
+ data = &message.data;
+ service_handle = app_load(appfile);
+ if (!service_handle) {
+ dev_err(dev, "unable to load the app %s\n", appfile);
+ goto end;
+ }
+
+ info = create_app_instance(service_handle, app_args,
+ &data->app_init, notifier, stack_sz);
+ if (IS_ERR_OR_NULL(info)) {
+ dev_err(dev, "unable to create instance for app %s\n", appfile);
+ goto end;
}
+ data->app_init.message = RUN_ADSP_APP;
+
+ start_app_on_adsp(info, &message, block);
end:
- return ret;
+ return info;
+}
+EXPORT_SYMBOL(nvadsp_run_app);
+
+static void delete_app_instance(nvadsp_app_info_t *app)
+{
+ struct nvadsp_app_service *ser =
+ (struct nvadsp_app_service *)app->handle;
+ struct device *dev = &priv.pdev->dev;
+
+ dev_dbg(dev, "%s:freeing app %s:%d\n",
+ __func__, app->name, app->instance_id);
+
+ /* update the service app instance manager atomically */
+ mutex_lock(&ser->lock);
+ ser->instance--;
+ list_del(&app->node);
+ mutex_unlock(&ser->lock);
+
+ /* free instance memory */
+ free_instance_memory(app, ser->mem_size);
+ kfree(app->priv);
+ kfree(app);
+}
+
+void nvadsp_exit_app(nvadsp_app_info_t *app, bool terminate)
+{
+ int *state;
+
+ if (IS_ERR_OR_NULL(priv.pdev)) {
+ pr_err("ADSP Driver is not initialized\n");
+ return;
+ }
+
+ if (IS_ERR_OR_NULL(app))
+ return;
+
+ /* TODO: add termination if possible to kill thread on adsp */
+ wait_for_completion(&app->wait_for_app_complete);
+ state = (int *)&app->state;
+ *state = NVADSP_APP_STATE_INITIALIZED;
+ delete_app_instance(app);
+}
+EXPORT_SYMBOL(nvadsp_exit_app);
+
+int nvadsp_app_deinit(nvadsp_app_info_t *app)
+{
+ nvadsp_exit_app(app, false);
+ return 0;
}
EXPORT_SYMBOL(nvadsp_app_deinit);
-static int native_adsp_app_unload(struct nvadsp_app_service *ser)
+int nvadsp_app_stop(nvadsp_app_info_t *app)
{
- struct app_unload_data *data = &shared->app_unload;
- int32_t status = -EINVAL;
-
- data->ser = ser->token;
- nvadsp_mbox_send(&mbox, APP_UNLOAD, NVADSP_MBOX_SMSG, true, 100);
- status = (wait_for_app_frame_timeout(&app_unload_status) <= 0)
- ? status : data->status;
- memset(data, 0, sizeof(struct app_deinit_data));
- return status;
+ return -ENOENT;
}
+EXPORT_SYMBOL(nvadsp_app_stop);
void nvadsp_app_unload(nvadsp_app_handle_t handle)
{
struct nvadsp_drv_data *drv_data;
struct nvadsp_app_service *ser;
struct device *dev;
- int ret;
if (!priv.pdev) {
pr_err("ADSP Driver is not initialized\n");
if (IS_ERR_OR_NULL(handle))
return;
+ mutex_lock(&priv.service_lock_list);
ser = (struct nvadsp_app_service *)handle;
if (ser->instance) {
dev_err(dev, "cannot unload app %s, has instances %d\n",
return;
}
- mutex_lock(&service_lock_list);
list_del(&ser->node);
- mutex_unlock(&service_lock_list);
-
- mutex_lock(&app_unload_mutex);
- ret = native_adsp_app_unload(ser);
- mutex_unlock(&app_unload_mutex);
-
- if (ret)
- WARN(1, "%s:invalid counts maintained %s", __func__, ser->name);
-
unload_adsp_module(ser->mod);
- kfree(ser);
+ devm_kfree(dev, ser);
+ mutex_unlock(&priv.service_lock_list);
}
EXPORT_SYMBOL(nvadsp_app_unload);
-int nvadsp_app_start(nvadsp_app_info_t *app)
+static status_t nvadsp_app_receive_handler(uint32_t msg, void *hdata)
{
- struct app_start_stats stats = { };
+ union app_complete_status_message message = { };
+ struct adsp_app_shared_msg_pool *msg_pool;
+ struct app_complete_status_data *data;
struct nvadsp_drv_data *drv_data;
- struct nvadsp_app_service *ser;
- unsigned long flags;
+ struct platform_device *pdev;
+ nvadsp_app_info_t *app;
struct device *dev;
- int ret = -EINVAL;
- int *state;
+ msgq_t *msgq_recv;
+ uint32_t *token;
- if (!priv.pdev) {
- pr_err("ADSP Driver is not initialized\n");
- goto end;
+ pdev = hdata;
+ dev = &pdev->dev;
+ drv_data = platform_get_drvdata(pdev);
+ msg_pool = drv_data->shared_adsp_os_data;
+ msgq_recv = &msg_pool->app_loader_recv_message.msgq;
+ data = &message.data;
+
+ message.msgq_msg.size = MSGQ_MSG_PAYLOAD_WSIZE(*data);
+ if (msgq_dequeue_message(msgq_recv, &message.msgq_msg)) {
+ dev_err(dev, "unable to dequeue app status message\n");
+ return 0;
}
- drv_data = platform_get_drvdata(priv.pdev);
- dev = &priv.pdev->dev;
+ if (unlikely(data->message == OS_LOAD_COMPLETE)) {
+ complete(&priv.os_load_complete);
+ return 0;
+ }
- if (!drv_data->adsp_os_running)
- goto end;
+ app = (nvadsp_app_info_t *)data->host_ref;
+ app->return_status = data->status;
+ app->status_msg = data->message;
+ token = (uint32_t *)&app->token;
+ *token = data->adsp_ref;
- if (IS_ERR_OR_NULL(app))
- goto end;
+ if (app->complete_status_notifier) {
+ app->complete_status_notifier(app,
+ app->status_msg, app->return_status);
+ }
- ser = (void *)app->handle;
- state = (int *)&app->state;
+ switch (data->message) {
+ case ADSP_APP_START_STATUS:
+ complete_all(&app->wait_for_app_start);
+ break;
+ case ADSP_APP_COMPLETE_STATUS:
+ complete_all(&app->wait_for_app_complete);
+ break;
+ }
- /*
- * possiblity is that after deinit start is called ! need to check app
- * pointer
- */
- spin_lock_irqsave(&state_lock, flags);
- if (IS_ERR_OR_NULL(app)) {
- dev_err(dev, "unable to start app instance %s:%d\n",
- app->name, app->instance_id);
- spin_unlock_irqrestore(&state_lock, flags);
- } else if (*state == NVADSP_APP_STATE_INITIALIZED) {
- *state = NVADSP_APP_STATE_STARTED;
- spin_unlock_irqrestore(&state_lock, flags);
+ return 0;
+}
- /* initilize the complete structure */
- init_completion(&app->wait_for_app_complete);
+int wait_for_adsp_os_load_complete(void)
+{
+ struct device *dev = &priv.pdev->dev;
+ unsigned long timeout;
+ int ret;
- /* start the app from adsp side by creating a thread */
- RECORD_STAT(stats.ns_time_native_call);
- mutex_lock(&app_start_mutex);
- ret = native_adsp_app_start(app, &stats);
- mutex_unlock(&app_start_mutex);
- RECORD_STAT(stats.ns_time_native_call);
+ timeout = msecs_to_jiffies(ADSP_OS_LOAD_TIMEOUT);
+ ret = wait_for_completion_timeout(&priv.os_load_complete, timeout);
+ if (!ret) {
+ dev_err(dev, "ADSP OS loading timed out\n");
+ ret = -ETIMEDOUT;
+ } else
+ ret = 0;
- if (ret) {
- dev_err(dev,
- "Unable to start app instance adsp thread %s:%d\n",
- app->name, app->instance_id);
- spin_lock_irqsave(&state_lock, flags);
- *state = NVADSP_APP_STATE_INITIALIZED;
- spin_unlock_irqrestore(&state_lock, flags);
- goto end;
- }
- } else {
- spin_unlock_irqrestore(&state_lock, flags);
- }
- print_start_stats(ser->file, &stats, dev);
-end:
return ret;
}
-EXPORT_SYMBOL(nvadsp_app_start);
-
-int nvadsp_app_stop(nvadsp_app_info_t *app)
-{
- return -ENOENT;
-}
int nvadsp_app_module_probe(struct platform_device *pdev)
{
int ret;
uint16_t mbox_id = APP_LOADER_MBOX_ID;
+ struct device *dev = &pdev->dev;
- dev_info(&pdev->dev, "%s\n", __func__);
+ dev_info(dev, "%s\n", __func__);
- ret = nvadsp_mbox_open(&mbox, &mbox_id, "app_service",
- nvadsp_app_receive_handler, &priv);
+ ret = nvadsp_mbox_open(&priv.mbox, &mbox_id,
+ "app_service", nvadsp_app_receive_handler, pdev);
if (ret) {
- dev_err(&pdev->dev, "unable to open mailbox\n");
+ dev_err(dev, "unable to open mailbox\n");
goto end;
}
priv.pdev = pdev;
- INIT_LIST_HEAD(&service_list);
+ INIT_LIST_HEAD(&priv.service_list);
+ init_completion(&priv.os_load_complete);
+ mutex_init(&priv.service_lock_list);
end:
return ret;
}
+++ /dev/null
-/*
- * run_app.c
- *
- * ADSP OS App management
- *
- * Copyright (C) 2014 NVIDIA Corporation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/tegra_nvadsp.h>
-#include <linux/dma-mapping.h>
-#include <linux/completion.h>
-#include <linux/workqueue.h>
-#include <linux/firmware.h>
-#include <linux/dma-buf.h>
-#include <linux/slab.h>
-#include <linux/elf.h>
-
-#include "aram_manager.h"
-#include "os.h"
-#include "dev.h"
-
-#define APP_LOADER_MBOX_ID 10
-
-#define APP_START 0x07
-
-struct nvadsp_app_service {
- char name[NVADSP_NAME_SZ];
- struct list_head node;
- int instance;
- spinlock_t lock;
- struct list_head app_head;
- const uint32_t token;
- const struct app_mem_size *mem_size;
- int generated_instance_id;
- struct adsp_module *mod;
-};
-
-static struct nvadsp_drv_data *drv_data;
-static struct device *dev;
-
-struct nvadsp_app_priv_struct {
- struct platform_device *pdev;
-};
-
-struct run_app_instance_data {
- uint32_t adsp_mod_ptr;
- uint64_t host_ref;
- uint32_t dram_data_ptr;
- uint32_t dram_shared_ptr;
- uint32_t dram_shared_wc_ptr;
- uint32_t aram_ptr;
- uint32_t aram_flag;
- uint32_t aram_x_ptr;
- uint32_t aram_x_flag;
- struct app_mem_size mem_size;
- nvadsp_app_args_t app_args;
- uint32_t stack_size;
-} __packed;
-
-struct app_loader_data {
- int32_t header[MSGQ_MESSAGE_HEADER_WSIZE];
- struct run_app_instance_data app_init;
-} __packed;
-
-#pragma pack(4)
-union app_loader_message {
- msgq_message_t msgq_msg;
- struct app_loader_data data;
-};
-
-struct app_complete_status_data {
- int32_t header[MSGQ_MESSAGE_HEADER_WSIZE];
- uint64_t host_ref;
- int32_t status;
-} __packed;
-
-#pragma pack(4)
-union app_complete_status_message {
- msgq_message_t msgq_msg;
- struct app_complete_status_data data;
-};
-
-static struct nvadsp_app_priv_struct priv;
-static struct nvadsp_mbox mbox;
-static struct list_head service_list;
-
-static DEFINE_MUTEX(service_lock_list);
-
-static struct nvadsp_app_service *get_loaded_service(const char *appfile)
-{
- struct device *dev = &priv.pdev->dev;
- struct nvadsp_app_service *ser;
-
- list_for_each_entry(ser, &service_list, node) {
- if (!strcmp(appfile, ser->name)) {
- dev_dbg(dev, "module %s already loaded\n", appfile);
- return ser;
- }
- }
- dev_dbg(dev, "module %s will be loaded\n", appfile);
- return NULL;
-}
-
-static nvadsp_app_handle_t app_load(const char *appfile)
-{
- struct device *dev = &priv.pdev->dev;
- struct nvadsp_app_service *ser;
- struct app_load_stats stats;
-
- mutex_lock(&service_lock_list);
- ser = get_loaded_service(appfile);
- if (!ser) {
- dev_dbg(dev, "loading app %s\n", appfile);
-
- ser = devm_kzalloc(dev, sizeof(*ser), GFP_KERNEL);
- if (!ser)
- goto err;
- strncpy(ser->name, appfile, NVADSP_NAME_SZ);
-
- /*load the module in to memory */
- ser->mod = load_adsp_module(appfile, appfile, dev, &stats);
- if (IS_ERR_OR_NULL(ser->mod))
- goto err_free_service;
- ser->mem_size = &ser->mod->mem_size;
-
- spin_lock_init(&ser->lock);
- INIT_LIST_HEAD(&ser->app_head);
-
- /* add the app instance service to the list */
- list_add_tail(&ser->node, &service_list);
- dev_dbg(dev, "loaded app %s\n", ser->name);
- }
- mutex_unlock(&service_lock_list);
-
- return ser;
-
-err_free_service:
- devm_kfree(dev, ser);
-err:
- mutex_unlock(&service_lock_list);
- return NULL;
-}
-
-static void free_instance_memory(nvadsp_app_info_t *app,
- const struct app_mem_size *sz)
-{
- adsp_app_mem_t *mem = &app->mem;
- adsp_app_iova_mem_t *iova_mem = &app->iova_mem;
-
- if (mem->dram) {
- nvadsp_free_coherent(sz->dram, mem->dram, iova_mem->dram);
- mem->dram = NULL;
- iova_mem->dram = 0;
- }
-
- if (mem->shared) {
- nvadsp_free_coherent(sz->dram_shared, mem->shared,
- iova_mem->shared);
- mem->shared = NULL;
- iova_mem->shared = 0;
- }
-
- if (mem->shared_wc) {
- nvadsp_free_coherent(sz->dram_shared_wc, mem->shared_wc,
- iova_mem->shared_wc);
- mem->shared_wc = NULL;
- iova_mem->shared_wc = 0;
- }
-
- if (mem->aram_flag)
- aram_release(mem->aram);
- else if (mem->aram)
- nvadsp_free_coherent(sz->aram, mem->aram, iova_mem->aram);
- mem->aram = NULL;
- iova_mem->aram = 0;
- mem->aram_flag = 0;
-
- if (mem->aram_x_flag) {
- aram_release(mem->aram_x);
- mem->aram_x = NULL;
- iova_mem->aram_x = 0;
- mem->aram_flag = 0;
- }
-
-}
-
-static int create_instance_memory(nvadsp_app_info_t *app,
- const struct app_mem_size *sz)
-{
- adsp_app_iova_mem_t *iova_mem = &app->iova_mem;
- struct device *dev = &priv.pdev->dev;
- adsp_app_mem_t *mem = &app->mem;
- char name[NVADSP_NAME_SZ];
- void *aram_handle;
- dma_addr_t da;
-
- snprintf(name, NVADSP_NAME_SZ, "%s:%d", app->name, app->instance_id);
-
- if (sz->dram) {
- mem->dram = nvadsp_alloc_coherent(sz->dram, &da, GFP_KERNEL);
- iova_mem->dram = (uint32_t)da;
- if (!mem->dram) {
- dev_err(dev, "app %s dram alloc failed\n",
- name);
- goto end;
- }
- dev_dbg(dev, "%s :: mem.dram %p 0x%x\n", name,
- mem->dram, iova_mem->dram);
- }
-
- if (sz->dram_shared) {
- mem->shared = nvadsp_alloc_coherent(sz->dram_shared,
- &da, GFP_KERNEL);
- if (!mem->shared) {
- dev_err(dev, "app %s shared dram alloc failed\n",
- name);
- goto end;
- }
- iova_mem->shared = (uint32_t)da;
- dev_dbg(dev, "%s :: mem.shared %p 0x%x\n", name,
- mem->shared, iova_mem->shared);
- }
-
- if (sz->dram_shared_wc) {
- mem->shared_wc = nvadsp_alloc_coherent(sz->dram_shared_wc,
- &da, GFP_KERNEL);
- if (!mem->shared_wc) {
- dev_err(dev, "app %s shared dram wc alloc failed\n",
- name);
- goto end;
- }
- iova_mem->shared_wc = (uint32_t)da;
- dev_dbg(dev, "%s :: mem.shared_wc %p 0x%x\n", name,
- mem->shared_wc, iova_mem->shared_wc);
- }
-
- if (sz->aram) {
- aram_handle = aram_request(name, sz->aram);
- if (!IS_ERR_OR_NULL(aram_handle)) {
- iova_mem->aram = aram_get_address(aram_handle);
- mem->aram = aram_handle;
- iova_mem->aram_flag = mem->aram_flag = 1;
- dev_dbg(dev, "%s aram %x\n", name, iova_mem->aram);
- } else {
- dev_dbg(dev, "app %s no ARAM memory ! using DRAM\n",
- name);
- mem->aram = nvadsp_alloc_coherent(sz->aram,
- &da, GFP_KERNEL);
- if (!mem->aram) {
- iova_mem->aram_flag = mem->aram_flag = 0;
- dev_err(dev,
- "app %s aram memory alloc failed\n",
- name);
- goto end;
- }
- iova_mem->aram = (uint32_t)da;
- dev_dbg(dev, "%s :: mem.aram %p 0x%x\n", name,
- mem->aram, iova_mem->aram);
- }
- }
-
- if (sz->aram_x) {
- aram_handle = aram_request(name, sz->aram);
- if (!IS_ERR_OR_NULL(aram_handle)) {
- iova_mem->aram_x = aram_get_address(aram_handle);
- mem->aram_x = aram_handle;
- iova_mem->aram_x_flag = mem->aram_x_flag = 1;
- dev_dbg(dev, "aram_x %x\n", iova_mem->aram_x);
- } else {
- iova_mem->aram_x = 0;
- iova_mem->aram_x_flag = mem->aram_x_flag = 0;
- dev_err(dev, "app %s aram x memory alloc failed\n",
- name);
- }
- }
- return 0;
-
-end:
- free_instance_memory(app, sz);
- return -ENOMEM;
-}
-
-static void fill_app_instance_data(nvadsp_app_info_t *app,
- struct nvadsp_app_service *ser, nvadsp_app_args_t *app_args,
- struct run_app_instance_data *data, uint32_t stack_sz)
-{
- adsp_app_iova_mem_t *iova_mem = &app->iova_mem;
-
- data->adsp_mod_ptr = ser->mod->adsp_module_ptr;
- /* copy the iova address to adsp so that adsp can access the memory */
- data->dram_data_ptr = iova_mem->dram;
- data->dram_shared_ptr = iova_mem->shared;
- data->dram_shared_wc_ptr = iova_mem->shared_wc;
- data->aram_ptr = iova_mem->aram;
- data->aram_flag = iova_mem->aram_flag;
- data->aram_x_ptr = iova_mem->aram_x;
- data->aram_x_flag = iova_mem->aram_x_flag;
-
- if (app_args)
- memcpy(&data->app_args, app_args, sizeof(nvadsp_app_args_t));
- /*
- * app on adsp holds the reference of host app instance to communicate
- * back when completed. This way we do not need to iterate through the
- * list to find the instance.
- */
- data->host_ref = (uint64_t)app;
-
- /* copy instance 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,
- nvadsp_app_args_t *app_args, struct run_app_instance_data *data,
- app_complete_status_notifier notifier, uint32_t stack_size)
-{
- struct nvadsp_app_service *ser = (void *)handle;
- struct device *dev = &priv.pdev->dev;
- nvadsp_app_info_t *app;
- unsigned long flags;
- int *state;
- int *id;
-
- app = kzalloc(sizeof(*app), GFP_KERNEL);
- if (unlikely(!app)) {
- dev_err(dev, "cannot allocate memory for app %s instance\n",
- ser->name);
- goto err_value;
- }
- /* set the instance name with the app name */
- app->name = ser->name;
- /* associate a unique id */
- id = (int *)&app->instance_id;
- *id = ser->generated_instance_id++;
- /*
- * hold the pointer to the service, to dereference later during deinit
- */
- app->handle = ser;
-
- /* create the instance memory required by the app instance */
- if (create_instance_memory(app, ser->mem_size)) {
- dev_err(dev, "instance creation failed for app %s:%d\n",
- app->name, app->instance_id);
- goto free_app;
- }
-
- /* assign the stack that is needed by the app */
- data->stack_size = stack_size;
-
- /* set the state to INITIALIZED. No need to do it in a spin lock */
- state = (int *)&app->state;
- *state = NVADSP_APP_STATE_INITIALIZED;
-
- /* increment instance count and add the app instance to service list */
- spin_lock_irqsave(&ser->lock, flags);
- list_add_tail(&app->node, &ser->app_head);
- ser->instance++;
- spin_unlock_irqrestore(&ser->lock, flags);
-
- fill_app_instance_data(app, ser, app_args, data, stack_size);
-
- init_completion(&app->wait_for_app_start);
- init_completion(&app->wait_for_app_complete);
- set_app_complete_notifier(app, notifier);
-
- dev_dbg(dev, "app %s instance %d initilized\n",
- app->name, app->instance_id);
- dev_dbg(dev, "app %s has %d instances\n", ser->name, ser->instance);
- goto end;
-
-free_app:
- kfree(app);
-err_value:
- app = ERR_PTR(-ENOMEM);
-end:
- return app;
-}
-
-static void start_app_on_adsp(nvadsp_app_info_t *app,
- union app_loader_message *message, bool block)
-{
- struct shared_mem_struct *shared_struct = drv_data->shared_adsp_os_data;
- msgq_t *msgq_send = &shared_struct->app_loader_send_message.msgq;
- int *state;
-
- message->msgq_msg.size = MSGQ_MSG_PAYLOAD_WSIZE(*message);
- msgq_queue_message(msgq_send, &message->msgq_msg);
-
- if (app->return_status) {
- state = (int *)&app->state;
- *state = NVADSP_APP_STATE_STARTED;
- }
-
- nvadsp_mbox_send(&mbox, APP_START, NVADSP_MBOX_SMSG, false, 0);
-
- if (block) {
- wait_for_completion(&app->wait_for_app_start);
- if (app->return_status) {
- state = (int *)&app->state;
- *state = NVADSP_APP_STATE_INITIALIZED;
- }
- }
-}
-
-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, bool block)
-{
- union app_loader_message message = {};
- nvadsp_app_handle_t service_handle;
- struct nvadsp_drv_data *drv_data;
- nvadsp_app_info_t *info = NULL;
- struct app_loader_data *data;
- struct device *dev;
-
- if (IS_ERR_OR_NULL(priv.pdev)) {
- pr_err("ADSP Driver is not initialized\n");
- info = ERR_PTR(-EINVAL);
- goto end;
- }
-
- drv_data = platform_get_drvdata(priv.pdev);
- dev = &priv.pdev->dev;
-
- if (!drv_data->adsp_os_running)
- goto end;
-
- if (IS_ERR_OR_NULL(appfile))
- goto end;
-
- data = &message.data;
- service_handle = app_load(appfile);
- if (!service_handle) {
- dev_err(dev, "unable to load the app %s\n", appfile);
- goto end;
- }
-
- info = create_app_instance(service_handle, app_args,
- &data->app_init, notifier, stack_sz);
- if (IS_ERR_OR_NULL(info)) {
- dev_err(dev, "unable to create instance for app %s\n", appfile);
- goto end;
- }
-
- start_app_on_adsp(info, &message, block);
-end:
- return info;
-}
-EXPORT_SYMBOL(nvadsp_run_app);
-
-static void delete_app_instance(nvadsp_app_info_t *app)
-{
- struct nvadsp_app_service *ser =
- (struct nvadsp_app_service *)app->handle;
- struct device *dev = &priv.pdev->dev;
- unsigned long flags;
-
- dev_dbg(dev, "%s:freeing app %s:%d\n",
- __func__, app->name, app->instance_id);
-
- /* update the service app instance manager atomically */
- spin_lock_irqsave(&ser->lock, flags);
- ser->instance--;
- list_del(&app->node);
- spin_unlock_irqrestore(&ser->lock, flags);
-
- /* free instance memory */
- free_instance_memory(app, ser->mem_size);
- kfree(app);
-}
-
-void nvadsp_exit_app(nvadsp_app_info_t *app, bool terminate)
-{
- int *state;
-
- if (IS_ERR_OR_NULL(priv.pdev)) {
- pr_err("ADSP Driver is not initialized\n");
- return;
- }
-
- if (IS_ERR_OR_NULL(app))
- return;
-
- /* TODO: add termination if possible to kill thread on adsp */
- wait_for_completion(&app->wait_for_app_complete);
- state = (int *)&app->state;
- *state = NVADSP_APP_STATE_INITIALIZED;
- delete_app_instance(app);
-}
-EXPORT_SYMBOL(nvadsp_exit_app);
-
-static status_t nvadsp_app_receive_handler(uint32_t msg, void *hdata)
-{
- union app_complete_status_message message = { };
- struct shared_mem_struct *shared_adsp_struct;
- struct app_complete_status_data *data;
- struct nvadsp_drv_data *drv_data;
- struct platform_device *pdev;
- nvadsp_app_info_t *app;
- struct device *dev;
- msgq_t *msgq_recv;
-
- pdev = hdata;
- dev = &pdev->dev;
- drv_data = platform_get_drvdata(pdev);
- shared_adsp_struct = drv_data->shared_adsp_os_data;
- msgq_recv = &shared_adsp_struct->app_loader_recv_message.msgq;
- data = &message.data;
-
- message.msgq_msg.size = MSGQ_MSG_PAYLOAD_WSIZE(*data);
- if (msgq_dequeue_message(msgq_recv, &message.msgq_msg)) {
- dev_err(dev, "unable to dequeue app status message\n");
- return 0;
- }
- app = (nvadsp_app_info_t *)data->host_ref;
- app->return_status = data->status;
- app->status_msg = msg;
-
- if (app->complete_status_notifier) {
- app->complete_status_notifier(app,
- app->status_msg, app->return_status);
- }
-
- switch (msg) {
- case ADSP_APP_START_STATUS:
- complete_all(&app->wait_for_app_start);
- break;
- case ADSP_APP_COMPLETE_STATUS:
- complete_all(&app->wait_for_app_complete);
- break;
- }
-
- return 0;
-}
-
-int nvadsp_run_app_module_probe(struct platform_device *pdev)
-{
- int ret;
- uint16_t mbox_id = APP_LOADER_MBOX_ID;
-
- dev_info(&pdev->dev, "%s\n", __func__);
-
- dev = &pdev->dev;
- ret = nvadsp_mbox_open(&mbox, &mbox_id,
- "app_service", nvadsp_app_receive_handler, pdev);
- if (ret) {
- dev_err(dev, "unable to open mailbox\n");
- goto end;
- }
- priv.pdev = pdev;
- INIT_LIST_HEAD(&service_list);
- drv_data = platform_get_drvdata(pdev);
-end:
- return ret;
-}