tegra: nvadsp: Include adsp usage functionality

Adds functionality to calculate adsp cpu usage
Inits, loads, starts and resume adsp_lpthread app

Bug 1727014

Change-Id: Icaf7a1ba9e91bff19d7fbc894bfdd0f884971d6c
Signed-off-by: Hariharan Sivaraman <hariharans@nvidia.com>
Reviewed-on: http://git-master/r/1134173
(cherry picked from commit 256bd7180cefa523a9e480be315fbf47b9c8de4f)
Signed-off-by: Hariharan Sivaraman <hariharans@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1564162
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Ajay Nandakumar M <anandakumarm@nvidia.com>
Reviewed-by: Nitin Pai <npai@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Hariharan Sivaraman
2016-04-28 16:17:26 +05:30
committed by Laxman Dewangan
parent 12dc199ff3
commit b3a66c2476
6 changed files with 405 additions and 1 deletions

View File

@@ -53,6 +53,17 @@ config TEGRA_ADSP_FILEIO
If unsure, say N
config TEGRA_ADSP_LPTHREAD
bool "Enable ADSP usage calc by lpthread"
depends on DEBUG_FS
default n
help
Enable calculation of ADSP usage by running a low priority
thread in background whenever OS is not suspended. Can be
enable or disabled by echo to adsp_usage file.
If unsure, say N
config TEGRA_EMC_APE_DFS
bool "Enable emc dfs due to APE"
default n

View File

@@ -33,3 +33,8 @@ endif
ifeq ($(CONFIG_TEGRA_ADSP_FILEIO),y)
nvadsp-objs += adspff.o
endif
ifeq ($(CONFIG_TEGRA_ADSP_LPTHREAD),y)
nvadsp-objs += adsp_lpthread.o
nvadsp-objs += adsp_lpthread_proc.o
endif

View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/fs.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/tegra_nvadsp.h>
#include "dev.h"
/* #define VERBOSE_OUTPUT_LPTHREAD */
struct adsp_lpthread_shared_state_t {
uint16_t mbox_id;
};
enum adsp_lpthread_mbx_cmd {
adsp_lpthread_cmd_resume = 0,
adsp_lpthread_cmd_pause,
adsp_lpthread_cmd_close,
};
static struct nvadsp_mbox mbox;
static struct adsp_lpthread_shared_state_t *adsp_lpthread;
int adsp_lpthread_init(bool is_adsp_suspended)
{
nvadsp_app_handle_t handle;
nvadsp_app_info_t *app_info;
int ret;
#ifdef VERBOSE_OUTPUT_LPTHREAD
pr_info("ADSP_LPTHREAD_INIT(): %d\n", (int)is_adsp_suspended);
#endif
handle = nvadsp_app_load("adsp_lpthread", "adsp_lpthread.elf");
if (!handle)
return -1;
app_info = nvadsp_app_init(handle, NULL);
if (!app_info) {
pr_info("unable to init app adsp_lpthread\n");
return -2;
}
ret = nvadsp_app_start(app_info);
if (ret) {
pr_info("unable to start app adsp_lpthread\n");
return -3;
}
adsp_lpthread = (struct adsp_lpthread_shared_state_t *)app_info->mem.shared;
ret = nvadsp_mbox_open(&mbox, &adsp_lpthread->mbox_id, "adsp_lpthread", NULL, NULL);
if (ret) {
pr_info("Failed to open mbox %d", adsp_lpthread->mbox_id);
return -4;
}
/* Start timer is adsp is not in suspended state */
if (!is_adsp_suspended) {
#ifdef VERBOSE_OUTPUT_LPTHREAD
pr_info("Attempting resume() from init()\n");
#endif
ret = adsp_lpthread_resume();
return ret;
}
return 0;
}
int adsp_lpthread_resume(void)
{
int ret;
#ifdef VERBOSE_OUTPUT_LPTHREAD
pr_info("ADSP_LPTHREAD_RESUME()\n");
#endif
ret = nvadsp_mbox_send(&mbox, adsp_lpthread_cmd_resume, NVADSP_MBOX_SMSG, 0, 0);
if (ret)
pr_info("nvadsp_mbox_send() in adsp_lpthread_resume() failed: %d, ret = %d\n", adsp_lpthread->mbox_id, ret);
return ret;
}
int adsp_lpthread_pause(void)
{
int ret;
#ifdef VERBOSE_OUTPUT_LPTHREAD
pr_info("ADSP_LPTHREAD_PAUSE()\n");
#endif
ret = nvadsp_mbox_send(&mbox, adsp_lpthread_cmd_pause, NVADSP_MBOX_SMSG, 0, 0);
if (ret)
pr_info("nvadsp_mbox_send() in adsp_lpthread_pause() failed: %d, ret = %d\n", adsp_lpthread->mbox_id, ret);
return ret;
}
int adsp_lpthread_exit(void)
{
int ret;
#ifdef VERBOSE_OUTPUT_LPTHREAD
pr_info("ADSP_LPTHREAD_EXIT()\n");
#endif
ret = nvadsp_mbox_send(&mbox, adsp_lpthread_cmd_close, NVADSP_MBOX_SMSG, 0, 0);
if (ret)
pr_info("nvadsp_mbox_send() in adsp_lpthread_exit() failed: %d, ret = %d\n", adsp_lpthread->mbox_id, ret);
nvadsp_mbox_close(&mbox);
return ret;
}

View File

@@ -0,0 +1,232 @@
/*
* Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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/kernel.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/debugfs.h>
#include <linux/platform_device.h>
#include <linux/irqchip/tegra-agic.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
#include "dev.h"
#define RW_MODE (S_IWUSR | S_IRUGO)
/* #define VERBOSE_OUTPUT_LPTHREAD */
struct adsp_lpthread {
bool lpthread_initialized;
bool adsp_os_suspended;
bool lpthread_to_be_paused;
bool lpthread_to_be_resumed;
bool lpthread_to_be_closed;
bool lpthread_init_and_closed;
};
static struct adsp_lpthread lpthread_obj;
static struct adsp_lpthread *lpthread;
static int adsp_usage_set(void *data, u64 val)
{
int ret = 0;
switch (val) {
case 1:
if (lpthread->adsp_os_suspended && !lpthread->lpthread_initialized) {
if (lpthread->lpthread_init_and_closed) {
lpthread->lpthread_init_and_closed = false;
lpthread->lpthread_initialized = true;
lpthread->lpthread_to_be_resumed = true;
pr_info("App already initialized\n");
break;
}
#ifdef VERBOSE_OUTPUT_LPTHREAD
pr_info("Starting os\n");
#endif
if (nvadsp_os_start()) {
pr_info("Unable to restart os\n");
break;
}
ret = adsp_lpthread_init(true);
lpthread->lpthread_initialized = true;
#ifdef VERBOSE_OUTPUT_LPTHREAD
pr_info("Initialized lpthread. Suspending OS\n");
#endif
if (nvadsp_os_suspend()) {
pr_info("Unable to restart os\n");
break;
}
lpthread->lpthread_to_be_resumed = true;
} else if (!lpthread->lpthread_initialized) {
if (lpthread->lpthread_init_and_closed) {
lpthread->lpthread_init_and_closed = false;
lpthread->lpthread_initialized = true;
lpthread->lpthread_to_be_resumed = true;
pr_info("App already initialized\n");
break;
}
ret = adsp_lpthread_init(lpthread->adsp_os_suspended);
lpthread->lpthread_initialized = true;
} else if (lpthread->adsp_os_suspended) {
#ifdef VERBOSE_OUTPUT_LPTHREAD
pr_info("App to be resumed\n");
#endif
lpthread->lpthread_to_be_resumed = true;
lpthread->lpthread_to_be_paused = false;
ret = 0;
} else {
ret = adsp_lpthread_resume();
}
break;
case 2:
if (lpthread->adsp_os_suspended && lpthread->lpthread_initialized) {
#ifdef VERBOSE_OUTPUT_LPTHREAD
pr_info("App to be paused\n");
#endif
lpthread->lpthread_to_be_resumed = false;
lpthread->lpthread_to_be_paused = true;
ret = 0;
} else if (lpthread->lpthread_initialized) {
ret = adsp_lpthread_pause();
} else {
pr_info("App not initialized. echo 1 > adsp_usage to init\n");
ret = 0;
}
break;
case 0:
if (lpthread->adsp_os_suspended && lpthread->lpthread_initialized) {
#ifdef VERBOSE_OUTPUT_LPTHREAD
pr_info("App to be closed\n");
#endif
lpthread->lpthread_to_be_closed = true;
lpthread->lpthread_init_and_closed = true;
lpthread->lpthread_initialized = false;
lpthread->lpthread_to_be_resumed = false;
ret = 0;
} else if (lpthread->lpthread_initialized) {
ret = adsp_lpthread_exit();
lpthread->lpthread_initialized = false;
} else {
pr_info("App not initialized. echo 1 > adsp_usage to init\n");
ret = 0;
}
break;
default:
pr_info("Invalid input\n");
pr_info("echo 1 > adsp_usage to init/resume\n");
pr_info("echo 2 > adsp_usage to pause\n");
pr_info("echo 0 > adsp_usage to stop\n");
ret = 0;
}
return ret;
}
static int adsp_usage_get(void *data, u64 *val)
{
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adsp_usage_fops, adsp_usage_get, adsp_usage_set, "%llu\n");
static int lpthread_debugfs_init(struct nvadsp_drv_data *drv)
{
int ret = -ENOMEM;
struct dentry *d, *dir;
if (!drv->adsp_debugfs_root)
return ret;
dir = debugfs_create_dir("adsp_lpthread", drv->adsp_debugfs_root);
if (!dir)
return ret;
d = debugfs_create_file(
"adsp_usage", RW_MODE, dir, NULL, &adsp_usage_fops);
if (!d)
return ret;
return 0;
}
int adsp_lpthread_debugfs_init(struct platform_device *pdev)
{
struct nvadsp_drv_data *drv = platform_get_drvdata(pdev);
int ret = -EINVAL;
lpthread = &lpthread_obj;
ret = lpthread_debugfs_init(drv);
if (!ret)
pr_info(" lpthread_debugfs_init() ret = %d\n", ret);
drv->lpthread_initialized = true;
lpthread->adsp_os_suspended = false;
return 0;
}
int adsp_lpthread_debugfs_exit(struct platform_device *pdev)
{
status_t ret = 0;
struct nvadsp_drv_data *drv = platform_get_drvdata(pdev);
if (!drv->lpthread_initialized)
ret = -EINVAL;
drv->lpthread_initialized = false;
return ret;
}
int adsp_lpthread_debugfs_set_suspend(bool is_suspended)
{
lpthread->adsp_os_suspended = is_suspended;
#ifdef VERBOSE_OUTPUT_LPTHREAD
pr_info("ADSP_OS_SUSPENDED = %d\n", (int)is_suspended);
#endif
return 0;
}
int adsp_lpthread_debugfs_callback(void)
{
int ret = 0;
if (lpthread->lpthread_initialized) {
if (lpthread->lpthread_to_be_resumed) {
lpthread->lpthread_to_be_resumed = false;
ret = adsp_lpthread_resume();
} else if (lpthread->lpthread_to_be_paused) {
lpthread->lpthread_to_be_paused = false;
ret = adsp_lpthread_pause();
}
return ret;
}
if (lpthread->lpthread_to_be_closed) {
lpthread->lpthread_to_be_closed = false;
lpthread->lpthread_init_and_closed = false;
ret = adsp_lpthread_exit();
return ret;
}
#ifdef VERBOSE_OUTPUT_LPTHREAD
pr_info("to_be_paused = %d\n", (int)lpthread->lpthread_to_be_paused);
pr_info("to_be_resumed = %d\n", (int)lpthread->lpthread_to_be_resumed);
pr_info("to_be_closed = %d\n", (int)lpthread->lpthread_to_be_closed);
pr_info("init_and_closed = %d\n", (int)lpthread->lpthread_init_and_closed);
pr_info("initialized = %d\n", (int)lpthread->lpthread_initialized);
#endif
return ret;
}

View File

@@ -76,7 +76,6 @@ enum adsp_unit_fpga_reset {
ADSP_UNIT_FPGA_RESET_END,
};
#define AMISC_REGS 0x2000
#define AMISC_ADSP_L2_REGFILEBASE 0x10
@@ -201,6 +200,10 @@ struct nvadsp_drv_data {
bool adspff_init;
#endif
#ifdef CONFIG_TEGRA_ADSP_LPTHREAD
bool lpthread_initialized;
#endif
wait_queue_head_t adsp_health_waitq;
bool adsp_crashed;
@@ -271,4 +274,16 @@ static inline int __init nvadsp_reset_init(struct platform_device *pdev)
return -EINVAL;
}
#ifdef CONFIG_TEGRA_ADSP_LPTHREAD
int adsp_lpthread_init(bool is_adsp_suspended);
int adsp_lpthread_resume(void);
int adsp_lpthread_pause(void);
int adsp_lpthread_exit(void);
int adsp_lpthread_debugfs_init(struct platform_device *pdev);
int adsp_lpthread_debugfs_exit(struct platform_device *pdev);
int adsp_lpthread_debugfs_set_suspend(bool is_suspended);
int adsp_lpthread_debugfs_callback(void);
#endif
#endif /* __TEGRA_NVADSP_DEV_H */

View File

@@ -1489,10 +1489,27 @@ int nvadsp_os_start(void)
drv_data->adspff_init = true;
}
#endif
#ifdef CONFIG_TEGRA_ADSP_LPTHREAD
if (drv_data->adsp_os_suspended == false) {
ret = adsp_lpthread_debugfs_init(priv.pdev);
if (ret)
dev_err(dev, "adsp_lpthread_debugfs_init() failed with ret = %d\n", ret);
else
dev_err(dev, "adsp_lpthread_debugfs_init() success with ret = %d\n", ret);
}
#endif
drv_data->adsp_os_suspended = false;
#ifdef CONFIG_DEBUG_FS
wake_up(&priv.logger.wait_queue);
#endif
#ifdef CONFIG_TEGRA_ADSP_LPTHREAD
adsp_lpthread_debugfs_set_suspend(drv_data->adsp_os_suspended);
adsp_lpthread_debugfs_callback();
#endif
unlock:
mutex_unlock(&priv.os_run_lock);
end:
@@ -1540,6 +1557,10 @@ static int __nvadsp_os_suspend(void)
drv_data->adsp_os_suspended = true;
#ifdef CONFIG_TEGRA_ADSP_LPTHREAD
adsp_lpthread_debugfs_set_suspend(drv_data->adsp_os_suspended);
#endif
nvadsp_assert_adsp(drv_data);
out: