#define APP_DEINIT 0x09
#define APP_DEINIT_STATUS 0x0A
#define APP_COMPLETE 0x0B
+#define APP_UNLOAD 0x0C
+#define APP_UNLOAD_STATUS 0x0D
struct nvadsp_app_service {
char name[NVADSP_NAME_SZ];
int32_t copy_complete;
} __packed;
+struct app_unload_data {
+ uint32_t ser;
+ int32_t status;
+} __packed;
+
struct shared_mem_struct {
- struct app_load_data app_load;
- struct app_init_data app_init;
- struct app_start_data app_start;
- struct app_deinit_data app_deinit;
- struct app_complete_data app_complete;
+ struct app_load_data app_load;
+ struct app_init_data app_init;
+ struct app_start_data app_start;
+ struct app_deinit_data app_deinit;
+ struct app_complete_data app_complete;
+ struct app_unload_data app_unload;
} __packed;
static struct nvadsp_app_priv_struct priv;
DECLARE_COMPLETION(app_init_status);
DECLARE_COMPLETION(app_start_status);
DECLARE_COMPLETION(app_deinit_status);
+DECLARE_COMPLETION(app_unload_status);
DEFINE_MUTEX(load_app_mutex);
DEFINE_MUTEX(app_init_mutex);
DEFINE_MUTEX(app_start_mutex);
DEFINE_MUTEX(app_deinit_mutex);
+DEFINE_MUTEX(app_unload_mutex);
/* app states need to be changed atomically */
static DEFINE_SPINLOCK(state_lock);
+static DEFINE_MUTEX(service_lock_list);
+
struct shared_mem_struct *shared;
static void app_complete_notifier(struct work_struct *work)
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);
struct device *dev = &priv.pdev->dev;
struct nvadsp_app_service *ser;
+ mutex_lock(&service_lock_list);
list_for_each_entry(ser, &service_list, node) {
if (!strcmp(appname, ser->name)) {
dev_info(dev, "module %s already loaded\n",
appname);
+ mutex_unlock(&service_lock_list);
return ser;
}
}
+ mutex_unlock(&service_lock_list);
dev_dbg(dev, "module %s can be loaded\n", appname);
return NULL;
}
nvadsp_app_load(const char *appname, const char *appfile)
{
struct device *dev = &priv.pdev->dev;
- struct adsp_module *mod;
struct nvadsp_app_service *ser;
+ struct adsp_module *mod;
uint32_t *token;
ser = get_loaded_service(appname);
}
spin_lock_init(&ser->lock);
INIT_LIST_HEAD(&ser->app_head);
+
+ /* 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);
+
dev_dbg(dev, "loaded app %s\n", ser->name);
}
end:
}
EXPORT_SYMBOL(nvadsp_app_deinit);
+static int native_adsp_app_unload(struct nvadsp_app_service *ser)
+{
+ struct app_unload_data *data = &shared->app_unload;
+ int32_t status;
+
+ data->ser = ser->token;
+ nvadsp_mbox_send(&mbox, APP_UNLOAD, NVADSP_MBOX_SMSG, true, 100);
+ wait_for_completion(&app_unload_status);
+ status = data->status;
+ memset(data, 0, sizeof(struct app_deinit_data));
+ return status;
+}
+
void nvadsp_app_unload(nvadsp_app_handle_t handle)
{
- return;
+ struct nvadsp_app_service *ser = (struct nvadsp_app_service *)handle;
+ struct device *dev = &priv.pdev->dev;
+ int ret;
+
+ if (ser->instance) {
+ dev_err(dev, "cannot unload app %s, has instances %d\n",
+ ser->name, ser->instance);
+ 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);
}
+EXPORT_SYMBOL(nvadsp_app_unload);
int nvadsp_app_start(nvadsp_app_info_t *app)
{
static int move_module(struct adsp_module *mod, struct load_info *info)
{
- int i;
struct device *dev = info->dev;
- void *handle;
+ int i;
- handle = dram_app_mem_request(info->name, mod->size);
- if (!handle) {
+ mod->handle = dram_app_mem_request(info->name, mod->size);
+ if (!mod->handle) {
dev_err(dev, "cannot allocate memory for app %s\n", info->name);
return -ENOMEM;
}
- mod->adsp_module_ptr = dram_app_mem_get_address(handle);
+ mod->adsp_module_ptr = dram_app_mem_get_address(mod->handle);
mod->module_ptr = nvadsp_da_to_va_mappings(mod->adsp_module_ptr,
mod->size);
dev_info(dev, "module %s Load address %p 0x%x\n", info->name,
if (info->index.sym == 0) {
dev_warn(dev, "%s: module has no symbols (stripped?)\n",
mod->name);
+ kfree(mod);
return ERR_PTR(-ENOEXEC);
}
/* Allocate and move to the final place */
err = move_module(mod, info);
- if (err)
+ if (err) {
+ /* TODO: need to handle error path more genericly */
+ kfree(mod);
return ERR_PTR(err);
+ }
return mod;
}
if (ret) {
dev_err(dev,
"Unable to simplify symbols error value %d\n", ret);
+ unload_adsp_module(mod);
return ERR_PTR(ret);
}
ret = apply_relocations(mod, &info);
if (ret) {
dev_err(dev, "relocation failed\n");
+ unload_adsp_module(mod);
return ERR_PTR(ret);
}
#endif
return mod;
}
+
+void unload_adsp_module(struct adsp_module *mod)
+{
+#if !CONFIG_USE_STATIC_APP_LOAD
+ dram_app_mem_release(mod->handle);
+#endif
+ kfree(mod);
+}