diff options
author | Yong Ding <yongding@codeaurora.org> | 2018-07-31 14:16:16 +0800 |
---|---|---|
committer | Yong Ding <yongding@codeaurora.org> | 2018-07-31 14:16:16 +0800 |
commit | 4faca7cde511cfb74ea9fe55cde7933bcd751987 (patch) | |
tree | 23cfba6c520250f6297ccb2ee8d283b3aaa4bc73 /drivers/soc | |
parent | 7adc4e13a4895e7f66b0cfe15d1f0dc60c847de0 (diff) |
soc: qcom: hab: add hab statistics support
This allows user to read back hab runtime information.
Change-Id: Id266dd17b9c9d38f0e93aa600510ae1c6b12cca5
Signed-off-by: Yong Ding <yongding@codeaurora.org>
Diffstat (limited to 'drivers/soc')
-rw-r--r-- | drivers/soc/qcom/hab/Makefile | 3 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/hab.c | 9 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/hab.h | 16 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/hab_mem_linux.c | 19 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/hab_mimex.c | 7 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/hab_qvm.h | 2 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/hab_stat.c | 167 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/hab_vchan.c | 49 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/khab_test.c | 124 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/qvm_comm.c | 13 |
10 files changed, 387 insertions, 22 deletions
diff --git a/drivers/soc/qcom/hab/Makefile b/drivers/soc/qcom/hab/Makefile index 945ae52de196..9dbe77bfc23d 100644 --- a/drivers/soc/qcom/hab/Makefile +++ b/drivers/soc/qcom/hab/Makefile @@ -9,7 +9,8 @@ msm_hab-objs = \ hab_mem_linux.o \ hab_pipe.o \ hab_parser.o \ - khab_test.o + khab_test.o \ + hab_stat.o ifdef CONFIG_GHS_VMM msm_hab_hyp-objs = \ diff --git a/drivers/soc/qcom/hab/hab.c b/drivers/soc/qcom/hab/hab.c index ef249bcba68c..b4ce657edae0 100644 --- a/drivers/soc/qcom/hab/hab.c +++ b/drivers/soc/qcom/hab/hab.c @@ -21,7 +21,7 @@ .openlock = __SPIN_LOCK_UNLOCKED(&hab_devices[__num__].openlock)\ } -static const char hab_info_str[] = "Change: 16239527 Revision: #65"; +static const char hab_info_str[] = "Change: 16764735 Revision: #76"; /* * The following has to match habmm definitions, order does not matter if @@ -283,7 +283,7 @@ struct virtual_channel *frontend_open(struct uhab_context *ctx, pr_err("vchan alloc failed\n"); ret = -ENOMEM; goto err; - } else + } /* Send Init sequence */ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT, pchan, @@ -667,6 +667,7 @@ int hab_vchan_open(struct uhab_context *ctx, } } else { pr_err("failed to find device, mmid %d\n", mmid); + return -ENODEV; } } @@ -1368,6 +1369,9 @@ static int __init hab_init(void) } else set_dma_ops(hab_driver.dev, &hab_dma_ops); } + + hab_stat_init(&hab_driver); + return result; err: @@ -1387,6 +1391,7 @@ static void __exit hab_exit(void) dev_t dev; hab_hypervisor_unregister(); + hab_stat_deinit(&hab_driver); hab_ctx_put(hab_driver.kctx); dev = MKDEV(MAJOR(hab_driver.major), 0); device_destroy(hab_driver.class, dev); diff --git a/drivers/soc/qcom/hab/hab.h b/drivers/soc/qcom/hab/hab.h index d1aa88e3978e..f381303f3ca8 100644 --- a/drivers/soc/qcom/hab/hab.h +++ b/drivers/soc/qcom/hab/hab.h @@ -43,6 +43,8 @@ #include <linux/dma-mapping.h> #include <linux/jiffies.h> #include <linux/reboot.h> +#include <linux/kobject.h> +#include <linux/sysfs.h> enum hab_payload_type { HAB_PAYLOAD_TYPE_MSG = 0x0, @@ -338,6 +340,8 @@ struct hab_driver { int b_loopback; void *hyp_priv; /* hypervisor plug-in storage */ + + void *hab_vmm_handle; }; struct virtual_channel { @@ -412,6 +416,7 @@ int hab_vchan_recv(struct uhab_context *ctx, void hab_vchan_stop(struct virtual_channel *vchan); void hab_vchans_stop(struct physical_channel *pchan); void hab_vchan_stop_notify(struct virtual_channel *vchan); +void hab_vchans_empty_wait(int vmid); int hab_mem_export(struct uhab_context *ctx, struct hab_export *param, int kernel); @@ -456,7 +461,7 @@ int habmm_imp_hyp_unmap(void *imp_ctx, struct export_desc *exp, int kernel); int habmem_imp_hyp_mmap(struct file *flip, struct vm_area_struct *vma); - +int habmm_imp_hyp_map_check(void *imp_ctx, struct export_desc *exp); void hab_msg_free(struct hab_message *message); int hab_msg_dequeue(struct virtual_channel *vchan, @@ -563,6 +568,15 @@ int hab_open_cancel_notify(struct hab_open_request *request); int hab_open_receive_cancel(struct physical_channel *pchan, size_t sizebytes); +int hab_stat_init(struct hab_driver *drv); +int hab_stat_deinit(struct hab_driver *drv); +int hab_stat_show_vchan(struct hab_driver *drv, char *buf, int sz); +int hab_stat_show_ctx(struct hab_driver *drv, char *buf, int sz); +int hab_stat_show_expimp(struct hab_driver *drv, int pid, char *buf, int sz); + +int hab_stat_init_sub(struct hab_driver *drv); +int hab_stat_deinit_sub(struct hab_driver *drv); + /* Global singleton HAB instance */ extern struct hab_driver hab_driver; diff --git a/drivers/soc/qcom/hab/hab_mem_linux.c b/drivers/soc/qcom/hab/hab_mem_linux.c index e9e42554cbe2..da41536205a5 100644 --- a/drivers/soc/qcom/hab/hab_mem_linux.c +++ b/drivers/soc/qcom/hab/hab_mem_linux.c @@ -751,3 +751,22 @@ int habmem_imp_hyp_mmap(struct file *filp, struct vm_area_struct *vma) return 0; } + +int habmm_imp_hyp_map_check(void *imp_ctx, struct export_desc *exp) +{ + struct importer_context *priv = imp_ctx; + struct pages_list *pglist; + int found = 0; + + read_lock(&priv->implist_lock); + list_for_each_entry(pglist, &priv->imp_list, list) { + if (pglist->export_id == exp->export_id && + pglist->vcid == exp->vcid_remote) { + found = 1; + break; + } + } + read_unlock(&priv->implist_lock); + + return found; +} diff --git a/drivers/soc/qcom/hab/hab_mimex.c b/drivers/soc/qcom/hab/hab_mimex.c index 3e9046381b12..23087680c690 100644 --- a/drivers/soc/qcom/hab/hab_mimex.c +++ b/drivers/soc/qcom/hab/hab_mimex.c @@ -104,8 +104,8 @@ static struct export_desc *habmem_add_export(struct virtual_channel *vchan, exp->vchan = vchan; exp->vcid_local = vchan->id; exp->vcid_remote = vchan->otherend_id; - exp->domid_local = -1; /* dom id, provided on the importer */ - exp->domid_remote = vchan->pchan->dom_id; + exp->domid_local = vchan->pchan->vmid_local; + exp->domid_remote = vchan->pchan->vmid_remote; exp->ctx = vchan->ctx; exp->pchan = vchan->pchan; @@ -124,7 +124,8 @@ void habmem_remove_export(struct export_desc *exp) struct uhab_context *ctx; if (!exp || !exp->ctx || !exp->pchan) { - pr_err("failed to find valid info in exp %pK\n", exp); + pr_err("failed to find valid info in exp %pK ctx %pK pchan %pK\n", + exp, exp->ctx, exp->pchan); return; } diff --git a/drivers/soc/qcom/hab/hab_qvm.h b/drivers/soc/qcom/hab/hab_qvm.h index fe7cb0bbda0a..6ff699c6f2ec 100644 --- a/drivers/soc/qcom/hab/hab_qvm.h +++ b/drivers/soc/qcom/hab/hab_qvm.h @@ -49,5 +49,5 @@ struct qvm_channel { void *qnx_hyp_rx_dispatch(void *data); void hab_pipe_reset(struct physical_channel *pchan); - +void habhyp_notify(void *commdev); #endif /* __HAB_QNX_H */ diff --git a/drivers/soc/qcom/hab/hab_stat.c b/drivers/soc/qcom/hab/hab_stat.c new file mode 100644 index 000000000000..f0a4207bc871 --- /dev/null +++ b/drivers/soc/qcom/hab/hab_stat.c @@ -0,0 +1,167 @@ +/* Copyright (c) 2018, The Linux Foundation. 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 and + * only version 2 as published by the Free Software Foundation. + * + * 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 "hab.h" +#include "hab_grantable.h" + +#define MAX_LINE_SIZE 128 + +int hab_stat_init(struct hab_driver *driver) +{ + return hab_stat_init_sub(driver); +} + +int hab_stat_deinit(struct hab_driver *driver) +{ + return hab_stat_deinit_sub(driver); +} + +/* + * If all goes well the return value is the formated print and concatenated + * original dest string. + */ +static int hab_stat_buffer_print(char *dest, + int dest_size, const char *fmt, ...) +{ + va_list args; + char line[MAX_LINE_SIZE]; + int ret; + + va_start(args, fmt); + ret = vsnprintf(line, sizeof(line), fmt, args); + va_end(args); + if (ret > 0) + ret = strlcat(dest, line, dest_size); + return ret; +} + +int hab_stat_show_vchan(struct hab_driver *driver, + char *buf, int size) +{ + int i, ret = 0; + + ret = strlcpy(buf, "", size); + for (i = 0; i < driver->ndevices; i++) { + struct hab_device *dev = &driver->devp[i]; + struct physical_channel *pchan; + struct virtual_channel *vc; + + spin_lock_bh(&dev->pchan_lock); + list_for_each_entry(pchan, &dev->pchannels, node) { + if (!pchan->vcnt) + continue; + + ret = hab_stat_buffer_print(buf, size, + "mmid %s role %d local %d remote %d vcnt %d:\n", + pchan->name, pchan->is_be, pchan->vmid_local, + pchan->vmid_remote, pchan->vcnt); + + read_lock(&pchan->vchans_lock); + list_for_each_entry(vc, &pchan->vchannels, pnode) { + ret = hab_stat_buffer_print(buf, size, + "%08X ", vc->id); + } + ret = hab_stat_buffer_print(buf, size, "\n"); + read_unlock(&pchan->vchans_lock); + } + spin_unlock_bh(&dev->pchan_lock); + } + + return ret; +} + +int hab_stat_show_ctx(struct hab_driver *driver, + char *buf, int size) +{ + int ret = 0; + struct uhab_context *ctx; + + ret = strlcpy(buf, "", size); + + spin_lock_bh(&hab_driver.drvlock); + ret = hab_stat_buffer_print(buf, size, + "Total contexts %d\n", + driver->ctx_cnt); + list_for_each_entry(ctx, &hab_driver.uctx_list, node) { + ret = hab_stat_buffer_print(buf, size, + "ctx %d K %d close %d vc %d exp %d imp %d open %d\n", + ctx->owner, ctx->kernel, ctx->closing, + ctx->vcnt, ctx->export_total, + ctx->import_total, ctx->pending_cnt); + } + spin_unlock_bh(&hab_driver.drvlock); + + return ret; +} + +static int get_pft_tbl_total_size(struct compressed_pfns *pfn_table) +{ + int i, total_size = 0; + + for (i = 0; i < pfn_table->nregions; i++) + total_size += pfn_table->region[i].size * PAGE_SIZE; + + return total_size; +} + +static int print_ctx_total_expimp(struct uhab_context *ctx, + char *buf, int size) +{ + struct compressed_pfns *pfn_table; + int exp_total = 0, imp_total = 0; + int exp_cnt = 0, imp_cnt = 0; + struct export_desc *exp; + + read_lock(&ctx->exp_lock); + list_for_each_entry(exp, &ctx->exp_whse, node) { + pfn_table = (struct compressed_pfns *)exp->payload; + exp_total += get_pft_tbl_total_size(pfn_table); + exp_cnt++; + } + read_unlock(&ctx->exp_lock); + + spin_lock_bh(&ctx->imp_lock); + list_for_each_entry(exp, &ctx->imp_whse, node) { + if (habmm_imp_hyp_map_check(ctx->import_ctx, exp)) { + pfn_table = (struct compressed_pfns *)exp->payload; + imp_total += get_pft_tbl_total_size(pfn_table); + imp_cnt++; + } + } + spin_unlock_bh(&ctx->imp_lock); + + if (exp_cnt || exp_total || imp_cnt || imp_total) + return hab_stat_buffer_print(buf, size, + "ctx %d exp %d size %d imp %d size %d\n", + ctx->owner, exp_cnt, exp_total, + imp_cnt, imp_total); + else + return 0; +} + +int hab_stat_show_expimp(struct hab_driver *driver, + int pid, char *buf, int size) +{ + struct uhab_context *ctx; + int ret; + + ret = strlcpy(buf, "", size); + + spin_lock_bh(&hab_driver.drvlock); + list_for_each_entry(ctx, &hab_driver.uctx_list, node) { + if (pid == ctx->owner) + ret = print_ctx_total_expimp(ctx, buf, size); + } + spin_unlock_bh(&hab_driver.drvlock); + + return ret; +} diff --git a/drivers/soc/qcom/hab/hab_vchan.c b/drivers/soc/qcom/hab/hab_vchan.c index d127bcca19f8..e7b46df3f97e 100644 --- a/drivers/soc/qcom/hab/hab_vchan.c +++ b/drivers/soc/qcom/hab/hab_vchan.c @@ -194,6 +194,55 @@ void hab_vchan_stop_notify(struct virtual_channel *vchan) hab_vchan_stop(vchan); } +static int hab_vchans_per_pchan_empty(struct physical_channel *pchan) +{ + int empty; + + read_lock(&pchan->vchans_lock); + empty = list_empty(&pchan->vchannels); + read_unlock(&pchan->vchans_lock); + + return empty; +} + +static int hab_vchans_empty(int vmid) +{ + int i, empty = 1; + struct physical_channel *pchan; + struct hab_device *hab_dev; + + for (i = 0; i < hab_driver.ndevices; i++) { + hab_dev = &hab_driver.devp[i]; + + spin_lock_bh(&hab_dev->pchan_lock); + list_for_each_entry(pchan, &hab_dev->pchannels, node) { + if (pchan->vmid_remote == vmid) { + if (!hab_vchans_per_pchan_empty(pchan)) { + empty = 0; + spin_unlock_bh(&hab_dev->pchan_lock); + break; + } + } + } + spin_unlock_bh(&hab_dev->pchan_lock); + } + + return empty; +} + +/* + * block until all vchans of a given GVM are explicitly closed + * with habmm_socket_close() by hab clients themselves + */ +void hab_vchans_empty_wait(int vmid) +{ + pr_info("waiting for GVM%d's sockets closure\n", vmid); + + while (!hab_vchans_empty(vmid)) + schedule(); + + pr_info("all of GVM%d's sockets are closed\n", vmid); +} int hab_vchan_find_domid(struct virtual_channel *vchan) { diff --git a/drivers/soc/qcom/hab/khab_test.c b/drivers/soc/qcom/hab/khab_test.c index 7d6df8861421..bb04815ad35e 100644 --- a/drivers/soc/qcom/hab/khab_test.c +++ b/drivers/soc/qcom/hab/khab_test.c @@ -11,13 +11,12 @@ * */ #include "hab.h" -#include "khab_test.h" -#include "hab_pipe.h" -#ifdef CONFIG_MSM_GVM_QUIN -#include "hab_qvm.h" -#endif +#if !defined CONFIG_GHS_VMM && defined(CONFIG_MSM_GVM_QUIN) #include <asm/cacheflush.h> #include <linux/list.h> +#include "hab_pipe.h" +#include "hab_qvm.h" +#include "khab_test.h" static char g_perf_test_result[256]; @@ -32,10 +31,8 @@ enum hab_perf_test_type { static int hab_shmm_throughput_test(void) { struct hab_device *habDev; -#ifdef CONFIG_MSM_GVM_QUIN struct qvm_channel *dev; -#endif - struct hab_shared_buf *sh_buf = NULL; + struct hab_shared_buf *sh_buf; struct physical_channel *pchan; struct timeval tv1, tv2; int i, counter; @@ -56,7 +53,6 @@ static int hab_shmm_throughput_test(void) pchan = list_first_entry(&(habDev->pchannels), struct physical_channel, node); -#ifdef CONFIG_MSM_GVM_QUIN dev = pchan->hyp_data; if (!dev) { ret = -EPERM; @@ -64,7 +60,6 @@ static int hab_shmm_throughput_test(void) } sh_buf = dev->pipe_ep->tx_info.sh_buf; -#endif /* pChannel is of 128k, we use 64k to test */ size = 0x10000; @@ -268,3 +263,112 @@ static int get_hab_perf_result(char *buffer, struct kernel_param *kp) return strlcpy(buffer, g_perf_test_result, strlen(g_perf_test_result)+1); } +#endif + +static struct kobject *hab_kobject; + +static int vchan_stat; +static int context_stat; +static int pid_stat; + +static ssize_t vchan_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return hab_stat_show_vchan(&hab_driver, buf, PAGE_SIZE); +} + +static ssize_t vchan_store(struct kobject *kobj, struct kobj_attribute *attr, + char *buf, size_t count) +{ + int ret; + + ret = sscanf(buf, "%du", &vchan_stat); + if (ret < 1) { + pr_err("failed to read anything from input %d", ret); + return 0; + } else + return vchan_stat; +} + +static ssize_t ctx_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return hab_stat_show_ctx(&hab_driver, buf, PAGE_SIZE); +} + +static ssize_t ctx_store(struct kobject *kobj, struct kobj_attribute *attr, + char *buf, size_t count) +{ + int ret; + + ret = sscanf(buf, "%du", &context_stat); + if (ret < 1) { + pr_err("failed to read anything from input %d", ret); + return 0; + } else + return context_stat; +} + +static ssize_t expimp_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return hab_stat_show_expimp(&hab_driver, pid_stat, buf, PAGE_SIZE); +} + +static ssize_t expimp_store(struct kobject *kobj, struct kobj_attribute *attr, + char *buf, size_t count) +{ + int ret; + + ret = sscanf(buf, "%du", &pid_stat); + if (ret < 1) { + pr_err("failed to read anything from input %d", ret); + return 0; + } else + return pid_stat; +} + +static struct kobj_attribute vchan_attribute = __ATTR(vchan_stat, 0660, + vchan_show, + vchan_store); + +static struct kobj_attribute ctx_attribute = __ATTR(context_stat, 0660, + ctx_show, + ctx_store); + +static struct kobj_attribute expimp_attribute = __ATTR(pid_stat, 0660, + expimp_show, + expimp_store); + +int hab_stat_init_sub(struct hab_driver *driver) +{ + int result; + + hab_kobject = kobject_create_and_add("hab", kernel_kobj); + if (!hab_kobject) + return -ENOMEM; + + result = sysfs_create_file(hab_kobject, &vchan_attribute.attr); + if (result) + pr_debug("cannot add vchan in /sys/kernel/hab %d\n", result); + + result = sysfs_create_file(hab_kobject, &ctx_attribute.attr); + if (result) + pr_debug("cannot add ctx in /sys/kernel/hab %d\n", result); + + result = sysfs_create_file(hab_kobject, &expimp_attribute.attr); + if (result) + pr_debug("cannot add expimp in /sys/kernel/hab %d\n", result); + + return result; +} + +int hab_stat_deinit_sub(struct hab_driver *driver) +{ + sysfs_remove_file(hab_kobject, &vchan_attribute.attr); + sysfs_remove_file(hab_kobject, &ctx_attribute.attr); + sysfs_remove_file(hab_kobject, &expimp_attribute.attr); + kobject_put(hab_kobject); + + return 0; +} diff --git a/drivers/soc/qcom/hab/qvm_comm.c b/drivers/soc/qcom/hab/qvm_comm.c index 04381232b26a..cce24d72c28e 100644 --- a/drivers/soc/qcom/hab/qvm_comm.c +++ b/drivers/soc/qcom/hab/qvm_comm.c @@ -13,7 +13,7 @@ #include "hab.h" #include "hab_qvm.h" -static inline void habhyp_notify(void *commdev) +inline void habhyp_notify(void *commdev) { struct qvm_channel *dev = (struct qvm_channel *)commdev; @@ -70,9 +70,14 @@ int physical_channel_send(struct physical_channel *pchan, struct habmm_xing_vm_stat *pstat = (struct habmm_xing_vm_stat *)payload; - do_gettimeofday(&tv); - pstat->tx_sec = tv.tv_sec; - pstat->tx_usec = tv.tv_usec; + if (pstat) { + do_gettimeofday(&tv); + pstat->tx_sec = tv.tv_sec; + pstat->tx_usec = tv.tv_usec; + } else { + spin_unlock_bh(&dev->io_lock); + return -EINVAL; + } } if (sizebytes) { |