summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
authorYong Ding <yongding@codeaurora.org>2018-07-31 14:16:16 +0800
committerYong Ding <yongding@codeaurora.org>2018-07-31 14:16:16 +0800
commit4faca7cde511cfb74ea9fe55cde7933bcd751987 (patch)
tree23cfba6c520250f6297ccb2ee8d283b3aaa4bc73 /drivers/soc
parent7adc4e13a4895e7f66b0cfe15d1f0dc60c847de0 (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/Makefile3
-rw-r--r--drivers/soc/qcom/hab/hab.c9
-rw-r--r--drivers/soc/qcom/hab/hab.h16
-rw-r--r--drivers/soc/qcom/hab/hab_mem_linux.c19
-rw-r--r--drivers/soc/qcom/hab/hab_mimex.c7
-rw-r--r--drivers/soc/qcom/hab/hab_qvm.h2
-rw-r--r--drivers/soc/qcom/hab/hab_stat.c167
-rw-r--r--drivers/soc/qcom/hab/hab_vchan.c49
-rw-r--r--drivers/soc/qcom/hab/khab_test.c124
-rw-r--r--drivers/soc/qcom/hab/qvm_comm.c13
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) {