]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
platform: tegra: nvadsp: app unload
authorAjay Nandakumar <anandakumarm@nvidia.com>
Sun, 3 Aug 2014 18:41:44 +0000 (00:11 +0530)
committerNitin Kumbhar <nkumbhar@nvidia.com>
Thu, 7 Aug 2014 09:39:17 +0000 (02:39 -0700)
Adding the ability to unload an app, when there are no
instances of the app running. This frees the memory where
the app has been loaded.

Bug 200009729

Change-Id: I1eb2de04a258b8ba32eab304919fa23e8350d497
Signed-off-by: Ajay Nandakumar <anandakumarm@nvidia.com>
Reviewed-on: http://git-master/r/450683
Reviewed-by: Nitin Kumbhar <nkumbhar@nvidia.com>
Tested-by: Nitin Kumbhar <nkumbhar@nvidia.com>
drivers/platform/tegra/nvadsp/app.c
drivers/platform/tegra/nvadsp/app_loader_linker.c
drivers/platform/tegra/nvadsp/os.h

index 6dfe424cd0c3a29ba8635221a6525d22e339476e..00d32666be22b09c2e6754718463981e6038ed7c 100644 (file)
@@ -41,6 +41,8 @@
 #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];
@@ -100,12 +102,18 @@ struct app_complete_data {
        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;
@@ -118,15 +126,19 @@ DECLARE_COMPLETION(load_app_status);
 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)
@@ -177,6 +189,11 @@ static void nvadsp_app_receive_thread(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);
@@ -231,13 +248,16 @@ static struct nvadsp_app_service
        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;
 }
@@ -273,8 +293,8 @@ nvadsp_app_handle_t
 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);
@@ -301,7 +321,12 @@ nvadsp_app_load(const char *appname, const char *appfile)
                }
                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:
@@ -639,10 +664,46 @@ int nvadsp_app_deinit(nvadsp_app_info_t *app)
 }
 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)
 {
index 63ebae109dedaa86bc6402a2f728161c094d3712..b2b0173ec39611876edc37da863ea8a7a27b7eba 100644 (file)
@@ -493,16 +493,15 @@ end:
 
 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,
@@ -690,6 +689,7 @@ static struct adsp_module *setup_load_info(struct load_info *info)
        if (info->index.sym == 0) {
                dev_warn(dev, "%s: module has no symbols (stripped?)\n",
                                                                mod->name);
+               kfree(mod);
                return ERR_PTR(-ENOEXEC);
        }
 
@@ -758,8 +758,11 @@ static struct adsp_module *layout_and_allocate(struct load_info *info)
 
        /* 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;
 }
@@ -910,6 +913,7 @@ struct adsp_module
        if (ret) {
                dev_err(dev,
                        "Unable to simplify symbols error value %d\n", ret);
+               unload_adsp_module(mod);
                return ERR_PTR(ret);
        }
 
@@ -917,8 +921,17 @@ struct adsp_module
        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);
+}
index 33f5078e7a348348de1812f849de11de4efd9edd..15aeba4abeb1f243eb905c67c1f2e574a21cb1ba 100644 (file)
@@ -46,11 +46,12 @@ struct app_mem_size {
 };
 
 struct adsp_module {
-       const char *name;
-       void *module_ptr;
-       uint32_t adsp_module_ptr;
-       size_t size;
-       const struct app_mem_size mem_size;
+       const char                      *name;
+       void                            *handle;
+       void                            *module_ptr;
+       uint32_t                        adsp_module_ptr;
+       size_t                          size;
+       const struct app_mem_size       mem_size;
 };
 
 int nvadsp_os_probe(struct platform_device *);
@@ -60,8 +61,11 @@ void *get_mailbox_shared_region(void);
 struct elf32_shdr *nvadsp_get_section(const struct firmware *, char *);
 struct global_sym_info *find_global_symbol(const char *);
 void update_nvadsp_app_shared_ptr(void *);
+
 struct adsp_module
 *load_adsp_module(const char *, const char *, struct device *);
+void unload_adsp_module(struct adsp_module *);
+
 int allocate_memory_from_adsp(void **, unsigned int);
 bool is_adsp_dram_addr(u64);
 void wait_for_adsp_os_load_complete(void);