768 lines
19 KiB
C
Executable File
768 lines
19 KiB
C
Executable File
/**
|
|
NVT info for the platform related tools
|
|
This file will provide the boot stage record the timestamp function
|
|
@file nvt-info.c
|
|
@ingroup
|
|
@note
|
|
Copyright Novatek Microelectronics Corp. 2019. 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 version 2 as
|
|
published by the Free Software Foundation.
|
|
*/
|
|
#include <linux/string.h>
|
|
#include <linux/printk.h>
|
|
#include <linux/init.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/gfp.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/memblock.h>
|
|
#include <generated/nvtversion.h>
|
|
|
|
#include <plat/hardware.h>
|
|
#include <mach/nvt-io.h>
|
|
#include <mach/nvt-info.h>
|
|
#include <mach/fmem.h>
|
|
#include <asm/outercache.h>
|
|
|
|
#include <linux/of_device.h>
|
|
#include <linux/of_platform.h>
|
|
#ifdef CONFIG_NVTTMR010_TIMER
|
|
#include <plat-na51068/nvt_jiffies.h>
|
|
#endif
|
|
|
|
#define NVT_BOOTTS_MAX_LEN 32
|
|
#define NVT_BOOTTS_NAME_MAX_LEN 16
|
|
#define NVT_BOOTTS_UBOOT_RESV_CNT 2
|
|
#define LOADER_TIME_OFFSET 0
|
|
|
|
#define NVT_TIMER_TM0_CNT 0x108
|
|
#define TM0_LIST_ONLY
|
|
|
|
struct bootts {
|
|
u32 time;
|
|
char name[NVT_BOOTTS_NAME_MAX_LEN];
|
|
int column;
|
|
s32 diff_time; //diff time to the same name
|
|
};
|
|
|
|
static struct bootts g_bootts[NVT_BOOTTS_MAX_LEN] = {0};
|
|
static int g_index = NVT_BOOTTS_UBOOT_RESV_CNT;
|
|
struct proc_dir_entry *nvt_info_dir_root = NULL;
|
|
EXPORT_SYMBOL(nvt_info_dir_root);
|
|
|
|
static DEFINE_SPINLOCK(test_l2_lock);
|
|
|
|
static unsigned long nvt_get_time(void)
|
|
{
|
|
#ifdef CONFIG_NVTTMR010_TIMER
|
|
return get_nvt_jiffies();
|
|
#else
|
|
return nvt_readl(NVT_TIMER_BASE_VIRT + NVT_TIMER_TM0_CNT);
|
|
#endif
|
|
}
|
|
|
|
//NOTE: the earliest "ker" tag is set in nvt_ivot_map_io(),
|
|
// which is located at linux-kernel/arch/arm/mach-nvt-ivot/io.c
|
|
void nvt_bootts_add_ts(char *name)
|
|
{
|
|
unsigned char name_len = strlen(name);
|
|
|
|
if (name_len > (NVT_BOOTTS_NAME_MAX_LEN - 1) || g_index >= NVT_BOOTTS_MAX_LEN) {
|
|
pr_err("\n%s %s fail\n", __func__, name);
|
|
return;
|
|
}
|
|
|
|
if (name != NULL)
|
|
strncpy(g_bootts[g_index].name, name, name_len);
|
|
|
|
g_bootts[g_index].time = nvt_get_time();
|
|
g_index++;
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(nvt_bootts_add_ts);
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
/* Support for /proc/nvt_info/bootts */
|
|
/* /proc/nvt_info/tm0 */
|
|
/* /proc/nvt_info/memperf */
|
|
|
|
static void add_uboot_time(void)
|
|
{
|
|
char *pstr = NULL;
|
|
char *psep = NULL;
|
|
char symbol;
|
|
unsigned long uboot_ts = 0;
|
|
int bootts_idx = 0;
|
|
|
|
pstr = strstr(saved_command_line, "bootts=");
|
|
if (pstr) {
|
|
pstr += strlen("bootts=");
|
|
}
|
|
while (pstr) {
|
|
psep = strpbrk(pstr, ", "); //find ',' or ' ', or '\0'
|
|
if (NULL == psep) {
|
|
break;
|
|
}
|
|
|
|
symbol = *psep;
|
|
*psep = '\0';
|
|
uboot_ts = 0;
|
|
kstrtoul(pstr, 10, &uboot_ts);
|
|
*psep = symbol;
|
|
|
|
if (bootts_idx < NVT_BOOTTS_UBOOT_RESV_CNT) {
|
|
strncpy(g_bootts[bootts_idx].name, "uboot", sizeof(g_bootts[bootts_idx].name)-1);
|
|
g_bootts[bootts_idx].time = uboot_ts;
|
|
bootts_idx++;
|
|
}
|
|
|
|
if (' ' == symbol) {
|
|
break;
|
|
}
|
|
|
|
pstr = psep + 1;
|
|
}
|
|
}
|
|
|
|
#ifndef TM0_LIST_ONLY
|
|
static void bootts_dump_linux_tm0(struct seq_file *m)
|
|
{
|
|
int i;
|
|
|
|
add_uboot_time();
|
|
|
|
seq_puts(m, "Name\t\tDiff(us)\tTM0\n");
|
|
for (i = 0; i < g_index; i++) {
|
|
seq_printf(m, "%-8.8s\t%-8.8u\t%-8.8u\n",
|
|
g_bootts[i].name,
|
|
(i-1 < 0) ? (g_bootts[i].time - 0) :
|
|
(g_bootts[i].time - g_bootts[i-1].time),
|
|
g_bootts[i].time
|
|
);
|
|
}
|
|
seq_printf(m, "%-8.8s\t%-8.8u\t\n",
|
|
"Total",
|
|
(g_bootts[g_index - 1].time - g_bootts[0].time)
|
|
);
|
|
}
|
|
#else //TM0_LIST_ONLY
|
|
static void bootts_dump_linux(struct seq_file *m)
|
|
{
|
|
int item_idx, item_idx2;
|
|
int column_cur, column_max;
|
|
int row_idx;
|
|
int max_diff_time;
|
|
|
|
if (g_index < 1) {
|
|
seq_printf(m, "no data");
|
|
return;
|
|
}
|
|
|
|
add_uboot_time();
|
|
|
|
//reset the column to recount the newest column
|
|
for (item_idx = 0; item_idx < g_index; item_idx++) {
|
|
g_bootts[item_idx].column = 0;
|
|
}
|
|
|
|
//setup the column of each item
|
|
column_cur = 0;
|
|
for (item_idx = 0; item_idx < g_index; item_idx++) {
|
|
if (0 != g_bootts[item_idx].column) {
|
|
continue;
|
|
}
|
|
column_cur++;
|
|
g_bootts[item_idx].column = column_cur;
|
|
for (item_idx2 = item_idx; item_idx2 < g_index; item_idx2++) {
|
|
if (!strcmp(g_bootts[item_idx2].name, g_bootts[item_idx].name)) {
|
|
g_bootts[item_idx2].column = column_cur;
|
|
g_bootts[item_idx2].diff_time = g_bootts[item_idx2].time - g_bootts[item_idx].time;
|
|
}
|
|
}
|
|
}
|
|
column_max = column_cur;
|
|
|
|
#if 0 //for debug
|
|
printk("g_index %d, column_max %d\r\n", g_index, column_max);
|
|
for (item_idx = 0; item_idx < g_index; item_idx++) {
|
|
printk("item[%d], column %d, %u, %s, %d\r\n",
|
|
item_idx,
|
|
g_bootts[item_idx].column,
|
|
g_bootts[item_idx].time,
|
|
g_bootts[item_idx].name,
|
|
g_bootts[item_idx].diff_time);
|
|
}
|
|
#endif
|
|
|
|
//print column name
|
|
seq_printf(m, "Name");
|
|
for (column_cur = 1; column_cur <= column_max; column_cur++) {
|
|
for (item_idx = 0; item_idx < g_index; item_idx++) {
|
|
if (column_cur == g_bootts[item_idx].column) {
|
|
seq_printf(m, "%12s", g_bootts[item_idx].name);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
seq_printf(m, "\n");
|
|
|
|
//print item data by column
|
|
for (row_idx = 0; row_idx < g_index; row_idx++) {
|
|
seq_printf(m, "[%02d]", row_idx);
|
|
for (column_cur = 1; column_cur <= column_max; column_cur++) {
|
|
if (column_cur == g_bootts[row_idx].column) {
|
|
seq_printf(m, "%12u", g_bootts[row_idx].time + LOADER_TIME_OFFSET);
|
|
} else {
|
|
seq_printf(m, "%12c", '-');
|
|
}
|
|
}
|
|
seq_printf(m, "\n");
|
|
}
|
|
|
|
//print diff time
|
|
seq_puts(m, "-----------------------------------------------\n");
|
|
seq_printf(m, "Diff");
|
|
for (column_cur = 1; column_cur <= column_max; column_cur++) {
|
|
max_diff_time = 0;
|
|
for (item_idx = 0; item_idx < g_index; item_idx++) {
|
|
if (g_bootts[item_idx].column == column_cur &&
|
|
g_bootts[item_idx].diff_time > max_diff_time) {
|
|
max_diff_time = g_bootts[item_idx].diff_time;
|
|
}
|
|
}
|
|
seq_printf(m, "%12d", max_diff_time);
|
|
}
|
|
seq_printf(m, "\n");
|
|
}
|
|
#endif //TM0_LIST_ONLY
|
|
|
|
static int nvt_bootts_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_puts(m, "============== Boot time results ==============\n");
|
|
/* seq_printf(m, "TM0 initial value: %llu\n", g_bootts.time[0]); */
|
|
#ifndef TM0_LIST_ONLY
|
|
bootts_dump_linux_tm0(m);
|
|
#else
|
|
bootts_dump_linux(m);
|
|
#endif
|
|
seq_puts(m, "================================================\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int nvt_bootts_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, nvt_bootts_proc_show, NULL);
|
|
}
|
|
|
|
static ssize_t nvt_bootts_write(struct file *file, const char __user *buffer,
|
|
size_t count, loff_t *pos)
|
|
{
|
|
char *buf = (char *) __get_free_page(GFP_USER);
|
|
int res = 0;
|
|
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
|
|
res = -EINVAL;
|
|
if (count >= NVT_BOOTTS_NAME_MAX_LEN)
|
|
goto out;
|
|
|
|
res = -EFAULT;
|
|
if (copy_from_user(buf, buffer, count))
|
|
goto out;
|
|
|
|
buf[count-1] = '\0';
|
|
|
|
nvt_bootts_add_ts(buf);
|
|
res = count;
|
|
out:
|
|
free_page((unsigned long)buf);
|
|
return res;
|
|
}
|
|
static const struct file_operations nvt_bootts_fops = {
|
|
.open = nvt_bootts_open,
|
|
.read = seq_read,
|
|
.write = nvt_bootts_write,
|
|
};
|
|
|
|
static int nvt_timer_tm0_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_printf(m, "%lu\n", nvt_get_time());
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nvt_timer_tm0_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, nvt_timer_tm0_proc_show, NULL);
|
|
}
|
|
|
|
static const struct file_operations nvt_timer_tm0_fops = {
|
|
.open = nvt_timer_tm0_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
};
|
|
|
|
static unsigned long nvt_test_memcpy_perf(struct seq_file *m, size_t bufsize, unsigned long iters)
|
|
{
|
|
unsigned int i = 0;
|
|
char *ptr_buf1 = NULL;
|
|
char *ptr_buf2 = NULL;
|
|
unsigned long time_before = 0;
|
|
unsigned long time_after = 0;
|
|
|
|
ptr_buf1 = (char*)kzalloc(bufsize, GFP_KERNEL);
|
|
ptr_buf2 = (char*)kzalloc(bufsize, GFP_KERNEL);
|
|
|
|
time_before = nvt_get_time();
|
|
for (i = 0; i < iters; ++i) {
|
|
memcpy(ptr_buf1, ptr_buf2, bufsize);
|
|
}
|
|
time_after = nvt_get_time();
|
|
kfree(ptr_buf1);
|
|
kfree(ptr_buf2);
|
|
return ((bufsize * iters) / (time_after - time_before));
|
|
}
|
|
|
|
static unsigned long nvt_test_memset_perf(struct seq_file *m, size_t bufsize, unsigned long iters)
|
|
{
|
|
unsigned int i = 0;
|
|
char *ptr_buf1 = NULL;
|
|
unsigned long time_before = 0;
|
|
unsigned long time_after = 0;
|
|
|
|
ptr_buf1 = (char*)kzalloc(bufsize, GFP_KERNEL);
|
|
|
|
time_before = nvt_get_time();
|
|
for (i = 0; i < iters; ++i) {
|
|
memset(ptr_buf1, i, bufsize);
|
|
}
|
|
time_after = nvt_get_time();
|
|
kfree(ptr_buf1);
|
|
return ((bufsize * iters) / (time_after - time_before));
|
|
}
|
|
|
|
static unsigned long nvt_test_memcmp_perf(struct seq_file *m, size_t bufsize, unsigned long iters)
|
|
{
|
|
unsigned int i = 0;
|
|
char *ptr_buf1 = NULL;
|
|
char *ptr_buf2 = NULL;
|
|
unsigned long time_before = 0;
|
|
unsigned long time_after = 0;
|
|
int ret = 0;
|
|
|
|
ptr_buf1 = (char*)kzalloc(bufsize, GFP_KERNEL);
|
|
ptr_buf2 = (char*)kzalloc(bufsize, GFP_KERNEL);
|
|
memset(ptr_buf1, 0x55aa55aa, bufsize);
|
|
memset(ptr_buf2, 0x55aa55aa, bufsize);
|
|
|
|
time_before = nvt_get_time();
|
|
for (i = 0; i < iters; ++i) {
|
|
ret = memcmp(ptr_buf1, ptr_buf2, bufsize);
|
|
if (ret != 0)
|
|
break;
|
|
}
|
|
time_after = nvt_get_time();
|
|
if (ret == 0)
|
|
seq_printf(m, "\tCompare result: Same\n");
|
|
else
|
|
seq_printf(m, "\tCompare result: Different\n");
|
|
|
|
kfree(ptr_buf1);
|
|
kfree(ptr_buf2);
|
|
return ((bufsize * iters) / (time_after - time_before));
|
|
}
|
|
|
|
static int nvt_test_L2_cache(struct seq_file *m, size_t size)
|
|
{
|
|
void __iomem *mem_base_cache, *mem_base_noncache;
|
|
phys_addr_t phy_base_cache, phy_base_nocache;
|
|
unsigned long time_before = 0;
|
|
unsigned long time_after = 0;
|
|
unsigned long flags;
|
|
struct device_node *node;
|
|
struct property *prop;
|
|
unsigned int array[2] = {0};
|
|
int length;
|
|
|
|
node = of_find_node_by_name(NULL, "hdal-memory");
|
|
if (node == NULL) {
|
|
pr_err("Failed to get hdal-memory device node\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
node = of_find_node_by_name(node, "media");
|
|
if (node == NULL) {
|
|
pr_err("Failed to get hdal-memory/media device node\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
prop = of_find_property(node, "reg", &length);
|
|
if (!prop) {
|
|
pr_err("Failed to get hdal-memory/media/reg device node\n");
|
|
}
|
|
|
|
of_property_read_u32_array(node, "reg", (u32 *)&array[0], 2);
|
|
|
|
mem_base_cache = ioremap_cache(array[0], size);
|
|
mem_base_noncache = ioremap_nocache(array[0], size);
|
|
|
|
phy_base_cache = fmem_lookup_pa((unsigned int)mem_base_cache);
|
|
phy_base_nocache = fmem_lookup_pa((unsigned int)mem_base_noncache);
|
|
|
|
seq_printf(m, "Starting to test L2 cache\n");
|
|
seq_printf(m, "\tCACHE: phys: 0x%08x virt: 0x%px\n", phy_base_cache, mem_base_cache);
|
|
seq_printf(m, "\tNon-CACHE: phys: 0x%08x virt: 0x%px\n", phy_base_nocache, mem_base_noncache);
|
|
|
|
#ifdef CONFIG_OUTER_CACHE
|
|
time_before = nvt_get_time();
|
|
spin_lock_irqsave(&test_l2_lock, flags);
|
|
outer_flush_all();
|
|
spin_unlock_irqrestore(&test_l2_lock, flags);
|
|
time_after = nvt_get_time();
|
|
seq_printf(m, "\tFlush all time (10M): %lu (us)\n", time_after - time_before);
|
|
time_before = nvt_get_time();
|
|
outer_flush_range(phy_base_cache, phy_base_cache + (SZ_1M * 10));
|
|
time_after = nvt_get_time();
|
|
seq_printf(m, "\tflush range time (10M): %lu (us)\n", (time_after - time_before));
|
|
time_before = nvt_get_time();
|
|
outer_clean_range(phy_base_cache, phy_base_cache + (SZ_1M * 10));
|
|
time_after = nvt_get_time();
|
|
seq_printf(m, "\tClean range time (10M): %lu (us)\n", (time_after - time_before));
|
|
time_before = nvt_get_time();
|
|
outer_inv_range(phy_base_cache, phy_base_cache + (SZ_1M * 10));
|
|
time_after = nvt_get_time();
|
|
seq_printf(m, "\tInv range time (10M): %lu (us)\n", (time_after - time_before));
|
|
#endif
|
|
|
|
iounmap(mem_base_cache);
|
|
iounmap(mem_base_noncache);
|
|
return 0;
|
|
}
|
|
|
|
static int nvt_memperf_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_puts(m, "Memory performance testing results\n");
|
|
seq_printf(m, "\tmemcpy: %lu MB/Sec.\n", nvt_test_memcpy_perf(m, 2000000, 1000));
|
|
seq_printf(m, "\tmemset: %lu MB/Sec.\n", nvt_test_memset_perf(m, 2000000, 1000));
|
|
seq_printf(m, "\tmemcmp: %lu MB/Sec.\n", nvt_test_memcmp_perf(m, 2000000, 1000));
|
|
nvt_test_L2_cache(m, SZ_1M * 10);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nvt_memperf_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, nvt_memperf_proc_show, NULL);
|
|
}
|
|
|
|
static const struct file_operations nvt_memperf_fops = {
|
|
.open = nvt_memperf_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
};
|
|
|
|
static ssize_t nvt_memhotplug_write(struct file *file, const char __user *buffer,
|
|
size_t count, loff_t *pos)
|
|
{
|
|
char *buf = (char *) __get_free_page(GFP_USER);
|
|
char* const delim = "@";
|
|
char *token = NULL;
|
|
unsigned long mem_address = 0;
|
|
unsigned long mem_size = 0;
|
|
int res = 0;
|
|
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
|
|
res = -EFAULT;
|
|
if (copy_from_user(buf, buffer, count))
|
|
goto out;
|
|
|
|
res = -EFAULT;
|
|
while ((token = strsep(&buf, delim)) != NULL) {
|
|
if (mem_size == 0) {
|
|
if (kstrtoul(token, 16, &mem_size) < 0)
|
|
goto out;
|
|
} else {
|
|
if (kstrtoul(token, 16, &mem_address) < 0)
|
|
goto out;
|
|
break;
|
|
}
|
|
}
|
|
|
|
res = memblock_add(mem_address, mem_size);
|
|
if (res != 0) {
|
|
pr_info("Got failures during add memory region 0x%08lx@0x%08lx\n", mem_size, mem_address);
|
|
res = -1;
|
|
} else {
|
|
pr_info("Add memory region 0x%08lx@0x%08lx\n", mem_size, mem_address);
|
|
res = count;
|
|
}
|
|
|
|
out:
|
|
free_page((unsigned long)buf);
|
|
return res;
|
|
}
|
|
|
|
static int nvt_memhotplug_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_puts(m, "Memory hotplug usage\n");
|
|
seq_puts(m, "\tAdd memory region:\n");
|
|
seq_puts(m, "\t$ echo Phys_size@Phys_addr > /proc/nvt_info/memhotplug\n");
|
|
seq_puts(m, "\tPrint memory region:\n");
|
|
seq_puts(m, "\t$ cat /sys/kernel/debug/memblock/memory\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nvt_memhotplug_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, nvt_memhotplug_proc_show, NULL);
|
|
}
|
|
|
|
static const struct file_operations nvt_memhotplug_fops = {
|
|
.open = nvt_memhotplug_open,
|
|
.read = seq_read,
|
|
.write = nvt_memhotplug_write,
|
|
};
|
|
|
|
static int nvt_version_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_printf(m, "Version: %s \n", NVT_UTS_RELEASE);
|
|
return 0;
|
|
}
|
|
|
|
static int nvt_version_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, nvt_version_show, NULL);
|
|
}
|
|
|
|
static const struct file_operations nvt_version_fops = {
|
|
.open = nvt_version_open,
|
|
.read = seq_read,
|
|
};
|
|
|
|
|
|
static int nvt_boot_source_show(struct seq_file *m, void *v)
|
|
{
|
|
char *path = "/nvt_info";
|
|
struct device_node *dt_node;
|
|
const u32 *property;
|
|
int len=0;
|
|
|
|
dt_node = of_find_node_by_path(path);
|
|
if (!dt_node) {
|
|
seq_printf(m, "error Failed to find device-tree node: %s\n", path);
|
|
return -ENODEV;
|
|
}
|
|
|
|
property = of_get_property(dt_node, "EMBMEM", &len);
|
|
// seq_printf(m, "(I) len=%d\n", len);
|
|
seq_printf(m, "%s\n", (char *)property);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nvt_boot_source_open(struct inode *inode, struct file *file){
|
|
return single_open(file, nvt_boot_source_show, NULL);
|
|
};
|
|
|
|
static const struct file_operations nvt_boot_source_fops = {
|
|
.open = nvt_boot_source_open,
|
|
.read = seq_read,
|
|
};
|
|
|
|
static int nvt_hdal_mtd_num_show(struct seq_file *m, void *v){
|
|
char path[64] = {0};
|
|
struct device_node *dt_node = NULL;
|
|
struct device_node *child = NULL;
|
|
char id_name[4]={0};
|
|
int i=0;
|
|
const u32 *property;
|
|
int len=0;
|
|
int check_rootfs1=0;
|
|
|
|
sprintf(path,"/nand@%x", NVT_NAND_BASE_PHYS);
|
|
dt_node = of_find_node_by_path(path);
|
|
if (!dt_node) {
|
|
seq_printf(m, "error Failed to find device-tree node: %s\n", path);
|
|
return 0;
|
|
}
|
|
|
|
dt_node = of_get_child_by_name(dt_node, "nvtpack");
|
|
|
|
if(dt_node == NULL){
|
|
seq_printf(m, "nvtpack node not found\n");
|
|
return 0;
|
|
}
|
|
dt_node = of_get_child_by_name(dt_node, "index");
|
|
if(dt_node == NULL){
|
|
seq_printf(m, "index node not found\n");
|
|
return 0;
|
|
}
|
|
|
|
while(1){
|
|
sprintf(id_name,"id%d",i);
|
|
child = of_get_child_by_name(dt_node, id_name);
|
|
if(child == NULL){
|
|
//seq_printf(m, "%s node not found\n",id_name);
|
|
break;
|
|
}
|
|
property = of_get_property(child, "partition_name", &len);
|
|
// seq_printf(m, "(I) len=%d\n", len);
|
|
//seq_printf(m, "%s\n", (char *)property);
|
|
if(strcmp((char *)property,"rootfs1") == 0){ // rootfs1 is user partition
|
|
check_rootfs1=1;
|
|
break;
|
|
}
|
|
//check user partition, now user partition name
|
|
//seq_printf(m, "find %s \n",id_name);
|
|
i++;
|
|
}
|
|
if(check_rootfs1 == 1){
|
|
seq_printf(m,"%d\n",i);
|
|
}
|
|
else{
|
|
seq_printf(m,"can not find rootfs1 (user partition),can not support mount user partition\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int nvt_hdal_mtd_num_open(struct inode *inode, struct file *file){
|
|
|
|
return single_open(file, nvt_hdal_mtd_num_show, NULL);
|
|
|
|
}
|
|
|
|
static const struct file_operations nvt_hdal_mtd_num_fops = {
|
|
|
|
.open = nvt_hdal_mtd_num_open,
|
|
.read = seq_read,
|
|
};
|
|
#endif
|
|
|
|
#ifdef CONFIG_NVT_STACK_CHECK
|
|
|
|
extern unsigned long stack_warn;
|
|
extern int remaining_min;
|
|
extern unsigned long remaining_stack;
|
|
|
|
static ssize_t nvt_stack_write(struct file *file, const char __user *buffer,
|
|
size_t count, loff_t *pos)
|
|
{
|
|
char *buf = (char *) __get_free_page(GFP_USER);
|
|
int res = -EINVAL;
|
|
|
|
if (!buf) {
|
|
pr_err("get free page fail\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (count < 1) {
|
|
pr_err("count < 1\n");
|
|
goto out;
|
|
}
|
|
|
|
if (copy_from_user(buf, buffer, count)) {
|
|
pr_err("copy_from_user fail\n");
|
|
goto out;
|
|
}
|
|
|
|
buf[count-1] = '\0';
|
|
|
|
if (kstrtoul(buf, 10, &stack_warn) < 0) {
|
|
pr_err("kstrtoul fail\n");
|
|
goto out;
|
|
}
|
|
|
|
if ((stack_warn <= 0) || (stack_warn > THREAD_SIZE)) {
|
|
pr_err("\nCommand error, value = 0x%lx\n", stack_warn);
|
|
goto out;
|
|
}
|
|
pr_info("\nNew stack check value = %ld\n", stack_warn);
|
|
remaining_min = THREAD_SIZE;
|
|
|
|
res = count;
|
|
out:
|
|
free_page((unsigned long)buf);
|
|
return res;
|
|
}
|
|
|
|
static int nvt_stack_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_puts(m, "====== Stack Detect ======\n");
|
|
seq_printf(m, "current stack usage %ld\n", THREAD_SIZE - remaining_stack);
|
|
seq_printf(m, "total stack size %ld, reserve %ld\n", THREAD_SIZE, stack_warn);
|
|
seq_printf(m, "Max stack usage %ld\n", THREAD_SIZE - remaining_min);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nvt_stack_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, nvt_stack_proc_show, NULL);
|
|
}
|
|
|
|
static const struct file_operations nvt_stack_fops = {
|
|
.open = nvt_stack_open,
|
|
.read = seq_read,
|
|
.write = nvt_stack_write,
|
|
};
|
|
#endif
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
static int __init nvt_bootts_proc_init(void)
|
|
{
|
|
struct proc_dir_entry *entry = NULL;
|
|
|
|
nvt_info_dir_root = proc_mkdir("nvt_info", NULL);
|
|
if (!nvt_info_dir_root)
|
|
return -ENOMEM;
|
|
|
|
entry = proc_create("bootts", 0664, nvt_info_dir_root, &nvt_bootts_fops);
|
|
if (!entry)
|
|
return -ENOMEM;
|
|
|
|
entry = proc_create("tm0", 0664, nvt_info_dir_root, &nvt_timer_tm0_fops);
|
|
if (!entry)
|
|
return -ENOMEM;
|
|
|
|
entry = proc_create("memperf", 0664, nvt_info_dir_root, &nvt_memperf_fops);
|
|
if (!entry)
|
|
return -ENOMEM;
|
|
|
|
entry = proc_create("memhotplug", 0664, nvt_info_dir_root, &nvt_memhotplug_fops);
|
|
if (!entry)
|
|
return -ENOMEM;
|
|
|
|
entry = proc_create("version", 0664, nvt_info_dir_root, &nvt_version_fops);
|
|
if (!entry)
|
|
return -ENOMEM;
|
|
|
|
entry = proc_create("boot_source", 0664, nvt_info_dir_root,&nvt_boot_source_fops);
|
|
if (!entry)
|
|
return -ENOMEM;
|
|
|
|
entry = proc_create("hdal_part_num", 0664, nvt_info_dir_root,&nvt_hdal_mtd_num_fops);
|
|
if (!entry)
|
|
return -ENOMEM;
|
|
|
|
#ifdef CONFIG_NVT_STACK_CHECK
|
|
entry = proc_create("stack", 0664, nvt_info_dir_root,&nvt_stack_fops);
|
|
if (!entry)
|
|
return -ENOMEM;
|
|
#endif
|
|
|
|
pr_info("NVTBOOTTS: %s initial success\n", __func__);
|
|
|
|
return 0;
|
|
}
|
|
|
|
core_initcall(nvt_bootts_proc_init);
|
|
#endif
|