OSDN Git Service

soc: qcom: hab: add hab statistics support
authorYong Ding <yongding@codeaurora.org>
Tue, 31 Jul 2018 06:16:16 +0000 (14:16 +0800)
committerYong Ding <yongding@codeaurora.org>
Tue, 31 Jul 2018 06:16:16 +0000 (14:16 +0800)
This allows user to read back hab runtime information.

Change-Id: Id266dd17b9c9d38f0e93aa600510ae1c6b12cca5
Signed-off-by: Yong Ding <yongding@codeaurora.org>
drivers/soc/qcom/hab/Makefile
drivers/soc/qcom/hab/hab.c
drivers/soc/qcom/hab/hab.h
drivers/soc/qcom/hab/hab_mem_linux.c
drivers/soc/qcom/hab/hab_mimex.c
drivers/soc/qcom/hab/hab_qvm.h
drivers/soc/qcom/hab/hab_stat.c [new file with mode: 0644]
drivers/soc/qcom/hab/hab_vchan.c
drivers/soc/qcom/hab/khab_test.c
drivers/soc/qcom/hab/qvm_comm.c

index 945ae52..9dbe77b 100644 (file)
@@ -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 = \
index ef249bc..b4ce657 100644 (file)
@@ -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);
index d1aa88e..f381303 100644 (file)
@@ -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;
 
index e9e4255..da41536 100644 (file)
@@ -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;
+}
index 3e90463..2308768 100644 (file)
@@ -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;
        }
 
index fe7cb0b..6ff699c 100644 (file)
@@ -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 (file)
index 0000000..f0a4207
--- /dev/null
@@ -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;
+}
index d127bcc..e7b46df 100644 (file)
@@ -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)
 {
index 7d6df88..bb04815 100644 (file)
  *
  */
 #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;
+}
index 0438123..cce24d7 100644 (file)
@@ -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) {