summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/virt/tegra/hvc_sysfs.c146
-rw-r--r--drivers/virt/tegra/ivc-cdev.c468
-rw-r--r--drivers/virt/tegra/tegra_hv.c785
-rw-r--r--drivers/virt/tegra/tegra_hv.h18
-rw-r--r--drivers/virt/tegra/userspace_ivc_mempool.c394
-rw-r--r--include/linux/nvhvivc_mempool_ioctl.h30
6 files changed, 1841 insertions, 0 deletions
diff --git a/drivers/virt/tegra/hvc_sysfs.c b/drivers/virt/tegra/hvc_sysfs.c
new file mode 100644
index 000000000..9d8e9074f
--- /dev/null
+++ b/drivers/virt/tegra/hvc_sysfs.c
@@ -0,0 +1,146 @@
1/*
2 * drivers/virt/tegra/hvc_sysfs.c
3 *
4 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 */
17
18#include <linux/errno.h>
19#include <soc/tegra/chip-id.h>
20#include <linux/kobject.h>
21#include <linux/sysfs.h>
22#include <linux/mm.h>
23#include <linux/bug.h>
24#include <linux/io.h>
25#include <soc/tegra/virt/syscalls.h>
26
27#define TEGRA_HV_ERR(...) pr_err("hvc_sysfs: " __VA_ARGS__)
28#define TEGRA_HV_INFO(...) pr_info("hvc_sysfs: " __VA_ARGS__)
29
30
31/*
32 * This file implements a hypervisor control driver that can be accessed
33 * from user-space via the sysfs interface. Currently, the only supported
34 * use case is retrieval of the HV trace log when it is available.
35 */
36
37struct hyp_shared_memory_info {
38 const char *node_name;
39 struct bin_attribute attr;
40 uint64_t ipa;
41 unsigned long size;
42};
43
44enum HYP_SHM_ID {
45 HYP_SHM_ID_LOG,
46 HYP_SHM_ID_PCT,
47
48 HYP_SHM_ID_NUM
49};
50
51static struct hyp_shared_memory_info hyp_shared_memory_attrs[HYP_SHM_ID_NUM];
52
53
54
55/* Map the HV trace buffer to the calling user process */
56static int hvc_sysfs_mmap(struct file *fp, struct kobject *ko,
57 struct bin_attribute *attr, struct vm_area_struct *vma)
58{
59 struct hyp_shared_memory_info *hyp_shm_info =
60 container_of(attr, struct hyp_shared_memory_info, attr);
61
62 if ((hyp_shm_info->ipa == 0) || (hyp_shm_info->size == 0))
63 return -EINVAL;
64
65
66 if ((vma->vm_end - vma->vm_start) != attr->size)
67 return -EINVAL;
68
69 return remap_pfn_range(
70 vma,
71 vma->vm_start,
72 hyp_shm_info->ipa >> PAGE_SHIFT,
73 hyp_shm_info->size,
74 vma->vm_page_prot);
75}
76
77/* Discover availability and placement of the HV trace buffer */
78static int hvc_create_sysfs(
79 struct kobject *kobj,
80 struct hyp_shared_memory_info *hyp_shm_info)
81{
82 sysfs_bin_attr_init((struct bin_attribute *)&hyp_shm_info->attr);
83
84 hyp_shm_info->attr.attr.name = hyp_shm_info->node_name;
85 hyp_shm_info->attr.attr.mode = S_IRUSR | S_IRGRP | S_IROTH;
86 hyp_shm_info->attr.mmap = hvc_sysfs_mmap;
87 hyp_shm_info->attr.size = (size_t)hyp_shm_info->size;
88
89 if ((hyp_shm_info->ipa == 0) || (hyp_shm_info->size == 0))
90 return -EINVAL;
91
92 return sysfs_create_bin_file(kobj, &hyp_shm_info->attr);
93}
94
95/* Set up all relevant hypervisor control nodes */
96static int __init hvc_sysfs_register(void)
97{
98 struct kobject *kobj;
99 int ret;
100 uint64_t ipa;
101 struct hyp_info_page *info;
102
103 if (is_tegra_hypervisor_mode() == false) {
104 TEGRA_HV_INFO("hypervisor is not present\n");
105 return -EPERM;
106 }
107
108 kobj = kobject_create_and_add("hvc", NULL);
109 if (kobj == NULL) {
110 TEGRA_HV_INFO("failed to add kobject\n");
111 return -ENOMEM;
112 }
113
114 if (hyp_read_hyp_info(&ipa) != 0)
115 return -EINVAL;
116
117 info = (struct hyp_info_page *)ioremap(ipa, sizeof(*info));
118 if (info == NULL)
119 return -EFAULT;
120
121 hyp_shared_memory_attrs[HYP_SHM_ID_LOG].ipa = info->log_ipa;
122 hyp_shared_memory_attrs[HYP_SHM_ID_LOG].size = (size_t)info->log_size;
123 hyp_shared_memory_attrs[HYP_SHM_ID_LOG].node_name = "log";
124
125 ret = hvc_create_sysfs(kobj, &hyp_shared_memory_attrs[HYP_SHM_ID_LOG]);
126 if (ret == 0)
127 TEGRA_HV_INFO("log is available\n");
128 else
129 TEGRA_HV_INFO("log is unavailable\n");
130
131 hyp_shared_memory_attrs[HYP_SHM_ID_PCT].ipa = info->pct_ipa;
132 hyp_shared_memory_attrs[HYP_SHM_ID_PCT].size = (size_t)info->pct_size;
133 hyp_shared_memory_attrs[HYP_SHM_ID_PCT].node_name = "pct";
134
135 ret = hvc_create_sysfs(kobj, &hyp_shared_memory_attrs[HYP_SHM_ID_PCT]);
136 if (ret == 0)
137 TEGRA_HV_INFO("pct is available\n");
138 else
139 TEGRA_HV_INFO("pct is unavailable\n");
140
141 iounmap(info);
142
143 return 0;
144}
145
146late_initcall(hvc_sysfs_register);
diff --git a/drivers/virt/tegra/ivc-cdev.c b/drivers/virt/tegra/ivc-cdev.c
new file mode 100644
index 000000000..f75a0474d
--- /dev/null
+++ b/drivers/virt/tegra/ivc-cdev.c
@@ -0,0 +1,468 @@
1/*
2 * IVC character device driver
3 *
4 * Copyright (C) 2014-2018, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 *
10 */
11
12#include <linux/tegra-ivc.h>
13#include <linux/tegra-ivc-instance.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/workqueue.h>
17#include <linux/cdev.h>
18#include <linux/poll.h>
19#include <linux/interrupt.h>
20#include <linux/device.h>
21#include <linux/slab.h>
22#include <linux/sched.h>
23
24#include "tegra_hv.h"
25
26#define ERR(...) pr_err("ivc: " __VA_ARGS__)
27#define DBG(...) pr_debug("ivc: " __VA_ARGS__)
28
29struct ivc_dev {
30 int minor;
31 dev_t dev;
32 struct cdev cdev;
33 struct device *device;
34 char name[32];
35
36 /* channel configuration */
37 struct tegra_hv_ivc_cookie *ivck;
38 const struct tegra_hv_queue_data *qd;
39
40 /* File mode */
41 wait_queue_head_t wq;
42 /*
43 * Lock for synchronizing access to the IVC channel between the threaded
44 * IRQ handler's notification processing and file ops.
45 */
46 struct mutex file_lock;
47};
48
49static dev_t ivc_dev;
50static const struct ivc_info_page *info;
51
52static irqreturn_t ivc_dev_handler(int irq, void *data)
53{
54 struct ivc_dev *ivc = data;
55
56 BUG_ON(!ivc->ivck);
57
58 mutex_lock(&ivc->file_lock);
59 tegra_ivc_channel_notified(tegra_hv_ivc_convert_co