diff options
| author | Joshua Bakita <bakitajoshua@gmail.com> | 2023-06-28 18:24:25 -0400 |
|---|---|---|
| committer | Joshua Bakita <bakitajoshua@gmail.com> | 2023-06-28 18:24:25 -0400 |
| commit | 01e6fac4d61fdd7fff5433942ec93fc2ea1e4df1 (patch) | |
| tree | 4ef34501728a087be24f4ba0af90f91486bf780b /include/os/linux/vgpu | |
| parent | 306a03d18b305e4e573be3b2931978fa10679eb9 (diff) | |
Include nvgpu headers
These are needed to build on NVIDIA's Jetson boards for the time
being. Only a couple structs are required, so it should be fairly
easy to remove this dependency at some point in the future.
Diffstat (limited to 'include/os/linux/vgpu')
| -rw-r--r-- | include/os/linux/vgpu/fecs_trace_vgpu.c | 225 | ||||
| -rw-r--r-- | include/os/linux/vgpu/gv11b/platform_gv11b_vgpu_tegra.c | 103 | ||||
| -rw-r--r-- | include/os/linux/vgpu/platform_vgpu_tegra.c | 97 | ||||
| -rw-r--r-- | include/os/linux/vgpu/platform_vgpu_tegra.h | 24 | ||||
| -rw-r--r-- | include/os/linux/vgpu/sysfs_vgpu.c | 143 | ||||
| -rw-r--r-- | include/os/linux/vgpu/vgpu_ivc.c | 77 | ||||
| -rw-r--r-- | include/os/linux/vgpu/vgpu_ivm.c | 53 | ||||
| -rw-r--r-- | include/os/linux/vgpu/vgpu_linux.c | 525 | ||||
| -rw-r--r-- | include/os/linux/vgpu/vgpu_linux.h | 68 |
9 files changed, 1315 insertions, 0 deletions
diff --git a/include/os/linux/vgpu/fecs_trace_vgpu.c b/include/os/linux/vgpu/fecs_trace_vgpu.c new file mode 100644 index 0000000..02a381e --- /dev/null +++ b/include/os/linux/vgpu/fecs_trace_vgpu.c | |||
| @@ -0,0 +1,225 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <uapi/linux/nvgpu.h> | ||
| 18 | |||
| 19 | #include <nvgpu/kmem.h> | ||
| 20 | #include <nvgpu/bug.h> | ||
| 21 | #include <nvgpu/enabled.h> | ||
| 22 | #include <nvgpu/ctxsw_trace.h> | ||
| 23 | #include <nvgpu/vgpu/vgpu_ivm.h> | ||
| 24 | #include <nvgpu/vgpu/tegra_vgpu.h> | ||
| 25 | #include <nvgpu/vgpu/vgpu.h> | ||
| 26 | #include <nvgpu/gk20a.h> | ||
| 27 | |||
| 28 | #include "os/linux/os_linux.h" | ||
| 29 | #include "gk20a/fecs_trace_gk20a.h" | ||
| 30 | #include "vgpu/fecs_trace_vgpu.h" | ||
| 31 | |||
| 32 | struct vgpu_fecs_trace { | ||
| 33 | struct tegra_hv_ivm_cookie *cookie; | ||
| 34 | struct nvgpu_ctxsw_ring_header *header; | ||
| 35 | struct nvgpu_gpu_ctxsw_trace_entry *entries; | ||
| 36 | int num_entries; | ||
| 37 | bool enabled; | ||
| 38 | void *buf; | ||
| 39 | }; | ||
| 40 | |||
| 41 | int vgpu_fecs_trace_init(struct gk20a *g) | ||
| 42 | { | ||
| 43 | struct device *dev = dev_from_gk20a(g); | ||
| 44 | struct device_node *np = dev->of_node; | ||
| 45 | struct of_phandle_args args; | ||
| 46 | struct vgpu_fecs_trace *vcst; | ||
| 47 | u32 mempool; | ||
| 48 | int err; | ||
| 49 | |||
| 50 | nvgpu_log_fn(g, " "); | ||
| 51 | |||
| 52 | vcst = nvgpu_kzalloc(g, sizeof(*vcst)); | ||
| 53 | if (!vcst) | ||
| 54 | return -ENOMEM; | ||
| 55 | |||
| 56 | err = of_parse_phandle_with_fixed_args(np, | ||
| 57 | "mempool-fecs-trace", 1, 0, &args); | ||
| 58 | if (err) { | ||
| 59 | nvgpu_info(g, "does not support fecs trace"); | ||
| 60 | goto fail; | ||
| 61 | } | ||
| 62 | __nvgpu_set_enabled(g, NVGPU_SUPPORT_FECS_CTXSW_TRACE, true); | ||
| 63 | |||
| 64 | mempool = args.args[0]; | ||
| 65 | vcst->cookie = vgpu_ivm_mempool_reserve(mempool); | ||
| 66 | if (IS_ERR(vcst->cookie)) { | ||
| 67 | nvgpu_info(g, | ||
| 68 | "mempool %u reserve failed", mempool); | ||
| 69 | vcst->cookie = NULL; | ||
| 70 | err = -EINVAL; | ||
| 71 | goto fail; | ||
| 72 | } | ||
| 73 | |||
| 74 | vcst->buf = ioremap_cache(vgpu_ivm_get_ipa(vcst->cookie), | ||
| 75 | vgpu_ivm_get_size(vcst->cookie)); | ||
| 76 | if (!vcst->buf) { | ||
| 77 | nvgpu_info(g, "ioremap_cache failed"); | ||
| 78 | err = -EINVAL; | ||
| 79 | goto fail; | ||
| 80 | } | ||
| 81 | vcst->header = vcst->buf; | ||
| 82 | vcst->num_entries = vcst->header->num_ents; | ||
| 83 | if (unlikely(vcst->header->ent_size != sizeof(*vcst->entries))) { | ||
| 84 | nvgpu_err(g, "entry size mismatch"); | ||
| 85 | goto fail; | ||
| 86 | } | ||
| 87 | vcst->entries = vcst->buf + sizeof(*vcst->header); | ||
| 88 | g->fecs_trace = (struct gk20a_fecs_trace *)vcst; | ||
| 89 | |||
| 90 | return 0; | ||
| 91 | fail: | ||
| 92 | iounmap(vcst->buf); | ||
| 93 | if (vcst->cookie) | ||
| 94 | vgpu_ivm_mempool_unreserve(vcst->cookie); | ||
| 95 | nvgpu_kfree(g, vcst); | ||
| 96 | return err; | ||
| 97 | } | ||
| 98 | |||
| 99 | int vgpu_fecs_trace_deinit(struct gk20a *g) | ||
| 100 | { | ||
| 101 | struct vgpu_fecs_trace *vcst = (struct vgpu_fecs_trace *)g->fecs_trace; | ||
| 102 | |||
| 103 | iounmap(vcst->buf); | ||
| 104 | vgpu_ivm_mempool_unreserve(vcst->cookie); | ||
| 105 | nvgpu_kfree(g, vcst); | ||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | int vgpu_fecs_trace_enable(struct gk20a *g) | ||
| 110 | { | ||
| 111 | struct vgpu_fecs_trace *vcst = (struct vgpu_fecs_trace *)g->fecs_trace; | ||
| 112 | struct tegra_vgpu_cmd_msg msg = { | ||
| 113 | .cmd = TEGRA_VGPU_CMD_FECS_TRACE_ENABLE, | ||
| 114 | .handle = vgpu_get_handle(g), | ||
| 115 | }; | ||
| 116 | int err; | ||
| 117 | |||
| 118 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); | ||
| 119 | err = err ? err : msg.ret; | ||
| 120 | WARN_ON(err); | ||
| 121 | vcst->enabled = !err; | ||
| 122 | return err; | ||
| 123 | } | ||
| 124 | |||
| 125 | int vgpu_fecs_trace_disable(struct gk20a *g) | ||
| 126 | { | ||
| 127 | struct vgpu_fecs_trace *vcst = (struct vgpu_fecs_trace *)g->fecs_trace; | ||
| 128 | struct tegra_vgpu_cmd_msg msg = { | ||
| 129 | .cmd = TEGRA_VGPU_CMD_FECS_TRACE_DISABLE, | ||
| 130 | .handle = vgpu_get_handle(g), | ||
| 131 | }; | ||
| 132 | int err; | ||
| 133 | |||
| 134 | vcst->enabled = false; | ||
| 135 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); | ||
| 136 | err = err ? err : msg.ret; | ||
| 137 | WARN_ON(err); | ||
| 138 | return err; | ||
| 139 | } | ||
| 140 | |||
| 141 | bool vgpu_fecs_trace_is_enabled(struct gk20a *g) | ||
| 142 | { | ||
| 143 | struct vgpu_fecs_trace *vcst = (struct vgpu_fecs_trace *)g->fecs_trace; | ||
| 144 | |||
| 145 | return (vcst && vcst->enabled); | ||
| 146 | } | ||
| 147 | |||
| 148 | int vgpu_fecs_trace_poll(struct gk20a *g) | ||
| 149 | { | ||
| 150 | struct tegra_vgpu_cmd_msg msg = { | ||
| 151 | .cmd = TEGRA_VGPU_CMD_FECS_TRACE_POLL, | ||
| 152 | .handle = vgpu_get_handle(g), | ||
| 153 | }; | ||
| 154 | int err; | ||
| 155 | |||
| 156 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); | ||
| 157 | err = err ? err : msg.ret; | ||
| 158 | WARN_ON(err); | ||
| 159 | return err; | ||
| 160 | } | ||
| 161 | |||
| 162 | int vgpu_alloc_user_buffer(struct gk20a *g, void **buf, size_t *size) | ||
| 163 | { | ||
| 164 | struct vgpu_fecs_trace *vcst = (struct vgpu_fecs_trace *)g->fecs_trace; | ||
| 165 | |||
| 166 | *buf = vcst->buf; | ||
| 167 | *size = vgpu_ivm_get_size(vcst->cookie); | ||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 171 | int vgpu_free_user_buffer(struct gk20a *g) | ||
| 172 | { | ||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | |||
| 176 | int vgpu_mmap_user_buffer(struct gk20a *g, struct vm_area_struct *vma) | ||
| 177 | { | ||
| 178 | struct vgpu_fecs_trace *vcst = (struct vgpu_fecs_trace *)g->fecs_trace; | ||
| 179 | unsigned long size = vgpu_ivm_get_size(vcst->cookie); | ||
| 180 | unsigned long vsize = vma->vm_end - vma->vm_start; | ||
| 181 | |||
| 182 | size = min(size, vsize); | ||
| 183 | size = round_up(size, PAGE_SIZE); | ||
| 184 | |||
| 185 | return remap_pfn_range(vma, vma->vm_start, | ||
| 186 | vgpu_ivm_get_ipa(vcst->cookie) >> PAGE_SHIFT, | ||
| 187 | size, | ||
| 188 | vma->vm_page_prot); | ||
| 189 | } | ||
| 190 | |||
| 191 | #ifdef CONFIG_GK20A_CTXSW_TRACE | ||
| 192 | int vgpu_fecs_trace_max_entries(struct gk20a *g, | ||
| 193 | struct nvgpu_gpu_ctxsw_trace_filter *filter) | ||
| 194 | { | ||
| 195 | struct vgpu_fecs_trace *vcst = (struct vgpu_fecs_trace *)g->fecs_trace; | ||
| 196 | |||
| 197 | return vcst->header->num_ents; | ||
| 198 | } | ||
| 199 | |||
| 200 | #if NVGPU_CTXSW_FILTER_SIZE != TEGRA_VGPU_FECS_TRACE_FILTER_SIZE | ||
| 201 | #error "FECS trace filter size mismatch!" | ||
| 202 | #endif | ||
| 203 | |||
| 204 | int vgpu_fecs_trace_set_filter(struct gk20a *g, | ||
| 205 | struct nvgpu_gpu_ctxsw_trace_filter *filter) | ||
| 206 | { | ||
| 207 | struct tegra_vgpu_cmd_msg msg = { | ||
| 208 | .cmd = TEGRA_VGPU_CMD_FECS_TRACE_SET_FILTER, | ||
| 209 | .handle = vgpu_get_handle(g), | ||
| 210 | }; | ||
| 211 | struct tegra_vgpu_fecs_trace_filter *p = &msg.params.fecs_trace_filter; | ||
| 212 | int err; | ||
| 213 | |||
| 214 | memcpy(&p->tag_bits, &filter->tag_bits, sizeof(p->tag_bits)); | ||
| 215 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); | ||
| 216 | err = err ? err : msg.ret; | ||
| 217 | WARN_ON(err); | ||
| 218 | return err; | ||
| 219 | } | ||
| 220 | |||
| 221 | void vgpu_fecs_trace_data_update(struct gk20a *g) | ||
| 222 | { | ||
| 223 | gk20a_ctxsw_trace_wake_up(g, 0); | ||
| 224 | } | ||
| 225 | #endif /* CONFIG_GK20A_CTXSW_TRACE */ | ||
diff --git a/include/os/linux/vgpu/gv11b/platform_gv11b_vgpu_tegra.c b/include/os/linux/vgpu/gv11b/platform_gv11b_vgpu_tegra.c new file mode 100644 index 0000000..0304bcc --- /dev/null +++ b/include/os/linux/vgpu/gv11b/platform_gv11b_vgpu_tegra.c | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/platform_device.h> | ||
| 18 | |||
| 19 | #include <nvgpu/nvhost.h> | ||
| 20 | #include <nvgpu/gk20a.h> | ||
| 21 | |||
| 22 | #include "vgpu/clk_vgpu.h" | ||
| 23 | #include "os/linux/platform_gk20a.h" | ||
| 24 | #include "os/linux/os_linux.h" | ||
| 25 | #include "os/linux/vgpu/vgpu_linux.h" | ||
| 26 | #include "os/linux/vgpu/platform_vgpu_tegra.h" | ||
| 27 | |||
| 28 | static int gv11b_vgpu_probe(struct device *dev) | ||
| 29 | { | ||
| 30 | struct platform_device *pdev = to_platform_device(dev); | ||
| 31 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
| 32 | struct resource *r; | ||
| 33 | void __iomem *regs; | ||
| 34 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(platform->g); | ||
| 35 | struct gk20a *g = platform->g; | ||
| 36 | int ret; | ||
| 37 | |||
| 38 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "usermode"); | ||
| 39 | if (!r) { | ||
| 40 | nvgpu_err(g, "failed to get usermode regs"); | ||
| 41 | return -ENXIO; | ||
| 42 | } | ||
| 43 | regs = devm_ioremap_resource(dev, r); | ||
| 44 | if (IS_ERR(regs)) { | ||
| 45 | nvgpu_err(g, "failed to map usermode regs"); | ||
| 46 | return PTR_ERR(regs); | ||
| 47 | } | ||
| 48 | l->usermode_regs = regs; | ||
| 49 | |||
| 50 | #ifdef CONFIG_TEGRA_GK20A_NVHOST | ||
| 51 | ret = nvgpu_get_nvhost_dev(g); | ||
| 52 | if (ret) { | ||
| 53 | l->usermode_regs = NULL; | ||
| 54 | return ret; | ||
| 55 | } | ||
| 56 | |||
| 57 | ret = nvgpu_nvhost_syncpt_unit_interface_get_aperture(g->nvhost_dev, | ||
| 58 | &g->syncpt_unit_base, | ||
| 59 | &g->syncpt_unit_size); | ||
| 60 | if (ret) { | ||
| 61 | nvgpu_err(g, "Failed to get syncpt interface"); | ||
| 62 | return -ENOSYS; | ||
| 63 | } | ||
| 64 | g->syncpt_size = nvgpu_nvhost_syncpt_unit_interface_get_byte_offset(1); | ||
| 65 | nvgpu_info(g, "syncpt_unit_base %llx syncpt_unit_size %zx size %x\n", | ||
| 66 | g->syncpt_unit_base, g->syncpt_unit_size, g->syncpt_size); | ||
| 67 | #endif | ||
| 68 | vgpu_init_clk_support(platform->g); | ||
| 69 | |||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | struct gk20a_platform gv11b_vgpu_tegra_platform = { | ||
| 74 | .has_syncpoints = true, | ||
| 75 | |||
| 76 | /* power management configuration */ | ||
| 77 | .can_railgate_init = false, | ||
| 78 | .can_elpg_init = false, | ||
| 79 | .enable_slcg = false, | ||
| 80 | .enable_blcg = false, | ||
| 81 | .enable_elcg = false, | ||
| 82 | .enable_elpg = false, | ||
| 83 | .enable_aelpg = false, | ||
| 84 | .can_slcg = false, | ||
| 85 | .can_blcg = false, | ||
| 86 | .can_elcg = false, | ||
| 87 | |||
| 88 | .ch_wdt_timeout_ms = 5000, | ||
| 89 | |||
| 90 | .probe = gv11b_vgpu_probe, | ||
| 91 | |||
| 92 | .clk_round_rate = vgpu_plat_clk_round_rate, | ||
| 93 | .get_clk_freqs = vgpu_plat_clk_get_freqs, | ||
| 94 | |||
| 95 | /* frequency scaling configuration */ | ||
| 96 | .devfreq_governor = "userspace", | ||
| 97 | |||
| 98 | .virtual_dev = true, | ||
| 99 | |||
| 100 | /* power management callbacks */ | ||
| 101 | .suspend = vgpu_tegra_suspend, | ||
| 102 | .resume = vgpu_tegra_resume, | ||
| 103 | }; | ||
diff --git a/include/os/linux/vgpu/platform_vgpu_tegra.c b/include/os/linux/vgpu/platform_vgpu_tegra.c new file mode 100644 index 0000000..948323e --- /dev/null +++ b/include/os/linux/vgpu/platform_vgpu_tegra.c | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | /* | ||
| 2 | * Tegra Virtualized GPU Platform Interface | ||
| 3 | * | ||
| 4 | * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <nvgpu/nvhost.h> | ||
| 20 | #include <nvgpu/gk20a.h> | ||
| 21 | |||
| 22 | #include "os/linux/platform_gk20a.h" | ||
| 23 | #include "vgpu/clk_vgpu.h" | ||
| 24 | #include "vgpu_linux.h" | ||
| 25 | |||
| 26 | static int gk20a_tegra_probe(struct device *dev) | ||
| 27 | { | ||
| 28 | #ifdef CONFIG_TEGRA_GK20A_NVHOST | ||
| 29 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
| 30 | int ret; | ||
| 31 | |||
| 32 | ret = nvgpu_get_nvhost_dev(platform->g); | ||
| 33 | if (ret) | ||
| 34 | return ret; | ||
| 35 | |||
| 36 | vgpu_init_clk_support(platform->g); | ||
| 37 | return 0; | ||
| 38 | #else | ||
| 39 | return 0; | ||
| 40 | #endif | ||
| 41 | } | ||
| 42 | |||
| 43 | long vgpu_plat_clk_round_rate(struct device *dev, unsigned long rate) | ||
| 44 | { | ||
| 45 | /* server will handle frequency rounding */ | ||
| 46 | return rate; | ||
| 47 | } | ||
| 48 | |||
| 49 | int vgpu_plat_clk_get_freqs(struct device *dev, unsigned long **freqs, | ||
| 50 | int *num_freqs) | ||
| 51 | { | ||
| 52 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
| 53 | struct gk20a *g = platform->g; | ||
| 54 | |||
| 55 | return vgpu_clk_get_freqs(g, freqs, num_freqs); | ||
| 56 | } | ||
| 57 | |||
| 58 | int vgpu_plat_clk_cap_rate(struct device *dev, unsigned long rate) | ||
| 59 | { | ||
| 60 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
| 61 | struct gk20a *g = platform->g; | ||
| 62 | |||
| 63 | return vgpu_clk_cap_rate(g, rate); | ||
| 64 | } | ||
| 65 | |||
| 66 | struct gk20a_platform vgpu_tegra_platform = { | ||
| 67 | .has_syncpoints = true, | ||
| 68 | .aggressive_sync_destroy_thresh = 64, | ||
| 69 | |||
| 70 | /* power management configuration */ | ||
| 71 | .can_railgate_init = false, | ||
| 72 | .can_elpg_init = false, | ||
| 73 | .enable_slcg = false, | ||
| 74 | .enable_blcg = false, | ||
| 75 | .enable_elcg = false, | ||
| 76 | .enable_elpg = false, | ||
| 77 | .enable_aelpg = false, | ||
| 78 | .can_slcg = false, | ||
| 79 | .can_blcg = false, | ||
| 80 | .can_elcg = false, | ||
| 81 | |||
| 82 | .ch_wdt_timeout_ms = 5000, | ||
| 83 | |||
| 84 | .probe = gk20a_tegra_probe, | ||
| 85 | |||
| 86 | .clk_round_rate = vgpu_plat_clk_round_rate, | ||
| 87 | .get_clk_freqs = vgpu_plat_clk_get_freqs, | ||
| 88 | |||
| 89 | /* frequency scaling configuration */ | ||
| 90 | .devfreq_governor = "userspace", | ||
| 91 | |||
| 92 | .virtual_dev = true, | ||
| 93 | |||
| 94 | /* power management callbacks */ | ||
| 95 | .suspend = vgpu_tegra_suspend, | ||
| 96 | .resume = vgpu_tegra_resume, | ||
| 97 | }; | ||
diff --git a/include/os/linux/vgpu/platform_vgpu_tegra.h b/include/os/linux/vgpu/platform_vgpu_tegra.h new file mode 100644 index 0000000..fef346d --- /dev/null +++ b/include/os/linux/vgpu/platform_vgpu_tegra.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef _VGPU_PLATFORM_H_ | ||
| 18 | #define _VGPU_PLATFORM_H_ | ||
| 19 | |||
| 20 | long vgpu_plat_clk_round_rate(struct device *dev, unsigned long rate); | ||
| 21 | int vgpu_plat_clk_get_freqs(struct device *dev, unsigned long **freqs, | ||
| 22 | int *num_freqs); | ||
| 23 | int vgpu_plat_clk_cap_rate(struct device *dev, unsigned long rate); | ||
| 24 | #endif | ||
diff --git a/include/os/linux/vgpu/sysfs_vgpu.c b/include/os/linux/vgpu/sysfs_vgpu.c new file mode 100644 index 0000000..ade5d82 --- /dev/null +++ b/include/os/linux/vgpu/sysfs_vgpu.c | |||
| @@ -0,0 +1,143 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/device.h> | ||
| 18 | #include <nvgpu/vgpu/vgpu.h> | ||
| 19 | |||
| 20 | #include "os/linux/platform_gk20a.h" | ||
| 21 | #include "os/linux/os_linux.h" | ||
| 22 | #include "vgpu/ecc_vgpu.h" | ||
| 23 | |||
| 24 | static ssize_t vgpu_load_show(struct device *dev, | ||
| 25 | struct device_attribute *attr, | ||
| 26 | char *buf) | ||
| 27 | { | ||
| 28 | struct gk20a *g = get_gk20a(dev); | ||
| 29 | struct tegra_vgpu_cmd_msg msg = {0}; | ||
| 30 | struct tegra_vgpu_gpu_load_params *p = &msg.params.gpu_load; | ||
| 31 | int err; | ||
| 32 | |||
| 33 | msg.cmd = TEGRA_VGPU_CMD_GET_GPU_LOAD; | ||
| 34 | msg.handle = vgpu_get_handle(g); | ||
| 35 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); | ||
| 36 | if (err) | ||
| 37 | return err; | ||
| 38 | |||
| 39 | return snprintf(buf, PAGE_SIZE, "%u\n", p->load); | ||
| 40 | } | ||
| 41 | static DEVICE_ATTR(load, S_IRUGO, vgpu_load_show, NULL); | ||
| 42 | |||
| 43 | static ssize_t vgpu_ecc_stat_show(struct device *dev, | ||
| 44 | struct device_attribute *attr, | ||
| 45 | char *buf) | ||
| 46 | { | ||
| 47 | struct gk20a *g = get_gk20a(dev); | ||
| 48 | struct tegra_vgpu_cmd_msg msg = {0}; | ||
| 49 | struct tegra_vgpu_ecc_counter_params *p = &msg.params.ecc_counter; | ||
| 50 | struct dev_ext_attribute *ext_attr = container_of(attr, | ||
| 51 | struct dev_ext_attribute, attr); | ||
| 52 | struct vgpu_ecc_stat *ecc_stat = ext_attr->var; | ||
| 53 | int err; | ||
| 54 | |||
| 55 | p->ecc_id = ecc_stat->ecc_id; | ||
| 56 | |||
| 57 | msg.cmd = TEGRA_VGPU_CMD_GET_ECC_COUNTER_VALUE; | ||
| 58 | msg.handle = vgpu_get_handle(g); | ||
| 59 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); | ||
| 60 | err = err ? err : msg.ret; | ||
| 61 | if (unlikely(err)) { | ||
| 62 | nvgpu_err(g, "ecc: cannot get ECC counter value: %d", err); | ||
| 63 | return err; | ||
| 64 | } | ||
| 65 | |||
| 66 | return snprintf(buf, PAGE_SIZE, "%u\n", p->value); | ||
| 67 | } | ||
| 68 | |||
| 69 | static int vgpu_create_ecc_sysfs(struct device *dev) | ||
| 70 | { | ||
| 71 | struct gk20a *g = get_gk20a(dev); | ||
| 72 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
| 73 | struct vgpu_priv_data *priv = vgpu_get_priv_data(g); | ||
| 74 | struct vgpu_ecc_stat *stats; | ||
| 75 | struct dev_ext_attribute *attrs; | ||
| 76 | int err, i, count; | ||
| 77 | |||
| 78 | err = vgpu_ecc_get_info(g); | ||
| 79 | if (unlikely(err)) { | ||
| 80 | nvgpu_err(g, "ecc: cannot get ECC info: %d", err); | ||
| 81 | return err; | ||
| 82 | } | ||
| 83 | |||
| 84 | stats = priv->ecc_stats; | ||
| 85 | count = priv->ecc_stats_count; | ||
| 86 | |||
| 87 | attrs = nvgpu_kzalloc(g, count * sizeof(*attrs)); | ||
| 88 | if (unlikely(!attrs)) { | ||
| 89 | nvgpu_err(g, "ecc: no memory"); | ||
| 90 | vgpu_ecc_remove_info(g); | ||
| 91 | return -ENOMEM; | ||
| 92 | } | ||
| 93 | |||
| 94 | for (i = 0; i < count; i++) { | ||
| 95 | sysfs_attr_init(&attrs[i].attr.attr); | ||
| 96 | attrs[i].attr.attr.name = stats[i].name; | ||
| 97 | attrs[i].attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(S_IRUGO); | ||
| 98 | attrs[i].attr.show = vgpu_ecc_stat_show; | ||
| 99 | attrs[i].attr.store = NULL; | ||
| 100 | attrs[i].var = &stats[i]; | ||
| 101 | |||
| 102 | err = device_create_file(dev, &attrs[i].attr); | ||
| 103 | if (unlikely(err)) { | ||
| 104 | nvgpu_warn(g, "ecc: cannot create file \"%s\": %d", | ||
| 105 | stats[i].name, err); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | l->ecc_attrs = attrs; | ||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | |||
| 113 | static void vgpu_remove_ecc_sysfs(struct device *dev) | ||
| 114 | { | ||
| 115 | struct gk20a *g = get_gk20a(dev); | ||
| 116 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
| 117 | struct vgpu_priv_data *priv = vgpu_get_priv_data(g); | ||
| 118 | int i; | ||
| 119 | |||
| 120 | if (l->ecc_attrs) { | ||
| 121 | for (i = 0; i < priv->ecc_stats_count; i++) | ||
| 122 | device_remove_file(dev, &l->ecc_attrs[i].attr); | ||
| 123 | |||
| 124 | nvgpu_kfree(g, l->ecc_attrs); | ||
| 125 | l->ecc_attrs = NULL; | ||
| 126 | } | ||
| 127 | |||
| 128 | vgpu_ecc_remove_info(g); | ||
| 129 | } | ||
| 130 | |||
| 131 | void vgpu_create_sysfs(struct device *dev) | ||
| 132 | { | ||
| 133 | if (device_create_file(dev, &dev_attr_load)) | ||
| 134 | dev_err(dev, "Failed to create vgpu sysfs attributes!\n"); | ||
| 135 | |||
| 136 | vgpu_create_ecc_sysfs(dev); | ||
| 137 | } | ||
| 138 | |||
| 139 | void vgpu_remove_sysfs(struct device *dev) | ||
| 140 | { | ||
| 141 | device_remove_file(dev, &dev_attr_load); | ||
| 142 | vgpu_remove_ecc_sysfs(dev); | ||
| 143 | } | ||
diff --git a/include/os/linux/vgpu/vgpu_ivc.c b/include/os/linux/vgpu/vgpu_ivc.c new file mode 100644 index 0000000..950f0d4 --- /dev/null +++ b/include/os/linux/vgpu/vgpu_ivc.c | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2018, NVIDIA Corporation. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <nvgpu/types.h> | ||
| 18 | #include <linux/tegra_gr_comm.h> | ||
| 19 | |||
| 20 | #include "os/linux/os_linux.h" | ||
| 21 | |||
| 22 | int vgpu_ivc_init(struct gk20a *g, u32 elems, | ||
| 23 | const size_t *queue_sizes, u32 queue_start, u32 num_queues) | ||
| 24 | { | ||
| 25 | struct platform_device *pdev = to_platform_device(dev_from_gk20a(g)); | ||
| 26 | |||
| 27 | return tegra_gr_comm_init(pdev, elems, queue_sizes, queue_start, | ||
| 28 | num_queues); | ||
| 29 | } | ||
| 30 | |||
| 31 | void vgpu_ivc_deinit(u32 queue_start, u32 num_queues) | ||
| 32 | { | ||
| 33 | tegra_gr_comm_deinit(queue_start, num_queues); | ||
| 34 | } | ||
| 35 | |||
| 36 | void vgpu_ivc_release(void *handle) | ||
| 37 | { | ||
| 38 | tegra_gr_comm_release(handle); | ||
| 39 | } | ||
| 40 | |||
| 41 | u32 vgpu_ivc_get_server_vmid(void) | ||
| 42 | { | ||
| 43 | return tegra_gr_comm_get_server_vmid(); | ||
| 44 | } | ||
| 45 | |||
| 46 | int vgpu_ivc_recv(u32 index, void **handle, void **data, | ||
| 47 | size_t *size, u32 *sender) | ||
| 48 | { | ||
| 49 | return tegra_gr_comm_recv(index, handle, data, size, sender); | ||
| 50 | } | ||
| 51 | |||
| 52 | int vgpu_ivc_send(u32 peer, u32 index, void *data, size_t size) | ||
| 53 | { | ||
| 54 | return tegra_gr_comm_send(peer, index, data, size); | ||
| 55 | } | ||
| 56 | |||
| 57 | int vgpu_ivc_sendrecv(u32 peer, u32 index, void **handle, | ||
| 58 | void **data, size_t *size) | ||
| 59 | { | ||
| 60 | return tegra_gr_comm_sendrecv(peer, index, handle, data, size); | ||
| 61 | } | ||
| 62 | |||
| 63 | u32 vgpu_ivc_get_peer_self(void) | ||
| 64 | { | ||
| 65 | return TEGRA_GR_COMM_ID_SELF; | ||
| 66 | } | ||
| 67 | |||
| 68 | void *vgpu_ivc_oob_get_ptr(u32 peer, u32 index, void **ptr, | ||
| 69 | size_t *size) | ||
| 70 | { | ||
| 71 | return tegra_gr_comm_oob_get_ptr(peer, index, ptr, size); | ||
| 72 | } | ||
| 73 | |||
| 74 | void vgpu_ivc_oob_put_ptr(void *handle) | ||
| 75 | { | ||
| 76 | tegra_gr_comm_oob_put_ptr(handle); | ||
| 77 | } | ||
diff --git a/include/os/linux/vgpu/vgpu_ivm.c b/include/os/linux/vgpu/vgpu_ivm.c new file mode 100644 index 0000000..bbd444d --- /dev/null +++ b/include/os/linux/vgpu/vgpu_ivm.c | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2018, NVIDIA Corporation. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <nvgpu/vgpu/vgpu_ivm.h> | ||
| 18 | |||
| 19 | #include <linux/tegra-ivc.h> | ||
| 20 | |||
| 21 | #include "os/linux/os_linux.h" | ||
| 22 | |||
| 23 | struct tegra_hv_ivm_cookie *vgpu_ivm_mempool_reserve(unsigned int id) | ||
| 24 | { | ||
| 25 | return tegra_hv_mempool_reserve(id); | ||
| 26 | } | ||
| 27 | |||
| 28 | int vgpu_ivm_mempool_unreserve(struct tegra_hv_ivm_cookie *cookie) | ||
| 29 | { | ||
| 30 | return tegra_hv_mempool_unreserve(cookie); | ||
| 31 | } | ||
| 32 | |||
| 33 | u64 vgpu_ivm_get_ipa(struct tegra_hv_ivm_cookie *cookie) | ||
| 34 | { | ||
| 35 | return cookie->ipa; | ||
| 36 | } | ||
| 37 | |||
| 38 | u64 vgpu_ivm_get_size(struct tegra_hv_ivm_cookie *cookie) | ||
| 39 | { | ||
| 40 | return cookie->size; | ||
| 41 | } | ||
| 42 | |||
| 43 | void *vgpu_ivm_mempool_map(struct tegra_hv_ivm_cookie *cookie) | ||
| 44 | { | ||
| 45 | return ioremap_cache(vgpu_ivm_get_ipa(cookie), | ||
| 46 | vgpu_ivm_get_size(cookie)); | ||
| 47 | } | ||
| 48 | |||
| 49 | void vgpu_ivm_mempool_unmap(struct tegra_hv_ivm_cookie *cookie, | ||
| 50 | void *addr) | ||
| 51 | { | ||
| 52 | iounmap(addr); | ||
| 53 | } | ||
diff --git a/include/os/linux/vgpu/vgpu_linux.c b/include/os/linux/vgpu/vgpu_linux.c new file mode 100644 index 0000000..80bcfff --- /dev/null +++ b/include/os/linux/vgpu/vgpu_linux.c | |||
| @@ -0,0 +1,525 @@ | |||
| 1 | /* | ||
| 2 | * Virtualized GPU for Linux | ||
| 3 | * | ||
| 4 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/mm.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <linux/dma-mapping.h> | ||
| 22 | #include <linux/pm_runtime.h> | ||
| 23 | #include <linux/pm_qos.h> | ||
| 24 | #include <linux/platform_device.h> | ||
| 25 | #include <soc/tegra/chip-id.h> | ||
| 26 | |||
| 27 | #include <nvgpu/kmem.h> | ||
| 28 | #include <nvgpu/bug.h> | ||
| 29 | #include <nvgpu/enabled.h> | ||
| 30 | #include <nvgpu/debug.h> | ||
| 31 | #include <nvgpu/soc.h> | ||
| 32 | #include <nvgpu/ctxsw_trace.h> | ||
| 33 | #include <nvgpu/defaults.h> | ||
| 34 | #include <nvgpu/ltc.h> | ||
| 35 | #include <nvgpu/channel.h> | ||
| 36 | #include <nvgpu/clk_arb.h> | ||
| 37 | |||
| 38 | #include "vgpu_linux.h" | ||
| 39 | #include "vgpu/fecs_trace_vgpu.h" | ||
| 40 | #include "vgpu/clk_vgpu.h" | ||
| 41 | #include "gk20a/regops_gk20a.h" | ||
| 42 | #include "gm20b/hal_gm20b.h" | ||
| 43 | |||
| 44 | #include "os/linux/module.h" | ||
| 45 | #include "os/linux/os_linux.h" | ||
| 46 | #include "os/linux/ioctl.h" | ||
| 47 | #include "os/linux/scale.h" | ||
| 48 | #include "os/linux/driver_common.h" | ||
| 49 | #include "os/linux/platform_gk20a.h" | ||
| 50 | #include "os/linux/vgpu/platform_vgpu_tegra.h" | ||
| 51 | |||
| 52 | struct vgpu_priv_data *vgpu_get_priv_data(struct gk20a *g) | ||
| 53 | { | ||
| 54 | struct gk20a_platform *plat = gk20a_get_platform(dev_from_gk20a(g)); | ||
| 55 | |||
| 56 | return (struct vgpu_priv_data *)plat->vgpu_priv; | ||
| 57 | } | ||
| 58 | |||
| 59 | static void vgpu_remove_support(struct gk20a *g) | ||
| 60 | { | ||
| 61 | vgpu_remove_support_common(g); | ||
| 62 | } | ||
| 63 | |||
| 64 | static void vgpu_init_vars(struct gk20a *g, struct gk20a_platform *platform) | ||
| 65 | { | ||
| 66 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
| 67 | struct vgpu_priv_data *priv = vgpu_get_priv_data(g); | ||
| 68 | |||
| 69 | nvgpu_mutex_init(&g->power_lock); | ||
| 70 | nvgpu_mutex_init(&g->ctxsw_disable_lock); | ||
| 71 | nvgpu_mutex_init(&g->clk_arb_enable_lock); | ||
| 72 | nvgpu_mutex_init(&g->cg_pg_lock); | ||
| 73 | |||
| 74 | nvgpu_mutex_init(&priv->vgpu_clk_get_freq_lock); | ||
| 75 | |||
| 76 | nvgpu_mutex_init(&l->ctrl.privs_lock); | ||
| 77 | nvgpu_init_list_node(&l->ctrl.privs); | ||
| 78 | |||
| 79 | l->regs_saved = l->regs; | ||
| 80 | l->bar1_saved = l->bar1; | ||
| 81 | |||
| 82 | nvgpu_atomic_set(&g->clk_arb_global_nr, 0); | ||
| 83 | |||
| 84 | g->aggressive_sync_destroy = platform->aggressive_sync_destroy; | ||
| 85 | g->aggressive_sync_destroy_thresh = platform->aggressive_sync_destroy_thresh; | ||
| 86 | __nvgpu_set_enabled(g, NVGPU_HAS_SYNCPOINTS, platform->has_syncpoints); | ||
| 87 | g->ptimer_src_freq = platform->ptimer_src_freq; | ||
| 88 | __nvgpu_set_enabled(g, NVGPU_CAN_RAILGATE, platform->can_railgate_init); | ||
| 89 | g->railgate_delay = platform->railgate_delay_init; | ||
| 90 | |||
| 91 | __nvgpu_set_enabled(g, NVGPU_MM_UNIFY_ADDRESS_SPACES, | ||
| 92 | platform->unify_address_spaces); | ||
| 93 | } | ||
| 94 | |||
| 95 | static int vgpu_init_support(struct platform_device *pdev) | ||
| 96 | { | ||
| 97 | struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 98 | struct gk20a *g = get_gk20a(&pdev->dev); | ||
| 99 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
| 100 | void __iomem *regs; | ||
| 101 | int err = 0; | ||
| 102 | |||
| 103 | if (!r) { | ||
| 104 | nvgpu_err(g, "failed to get gk20a bar1"); | ||
| 105 | err = -ENXIO; | ||
| 106 | goto fail; | ||
| 107 | } | ||
| 108 | |||
| 109 | if (r->name && !strcmp(r->name, "/vgpu")) { | ||
| 110 | regs = devm_ioremap_resource(&pdev->dev, r); | ||
| 111 | if (IS_ERR(regs)) { | ||
| 112 | nvgpu_err(g, "failed to remap gk20a bar1"); | ||
| 113 | err = PTR_ERR(regs); | ||
| 114 | goto fail; | ||
| 115 | } | ||
| 116 | l->bar1 = regs; | ||
| 117 | l->bar1_mem = r; | ||
| 118 | } | ||
| 119 | |||
| 120 | nvgpu_mutex_init(&g->dbg_sessions_lock); | ||
| 121 | nvgpu_mutex_init(&g->client_lock); | ||
| 122 | |||
| 123 | nvgpu_init_list_node(&g->profiler_objects); | ||
| 124 | |||
| 125 | g->dbg_regops_tmp_buf = nvgpu_kzalloc(g, SZ_4K); | ||
| 126 | if (!g->dbg_regops_tmp_buf) { | ||
| 127 | nvgpu_err(g, "couldn't allocate regops tmp buf"); | ||
| 128 | return -ENOMEM; | ||
| 129 | } | ||
| 130 | g->dbg_regops_tmp_buf_ops = | ||
| 131 | SZ_4K / sizeof(g->dbg_regops_tmp_buf[0]); | ||
| 132 | |||
| 133 | g->remove_support = vgpu_remove_support; | ||
| 134 | return 0; | ||
| 135 | |||
| 136 | fail: | ||
| 137 | vgpu_remove_support(g); | ||
| 138 | return err; | ||
| 139 | } | ||
| 140 | |||
| 141 | int vgpu_pm_prepare_poweroff(struct device *dev) | ||
| 142 | { | ||
| 143 | struct gk20a *g = get_gk20a(dev); | ||
| 144 | int ret = 0; | ||
| 145 | |||
| 146 | nvgpu_log_fn(g, " "); | ||
| 147 | |||
| 148 | nvgpu_mutex_acquire(&g->power_lock); | ||
| 149 | |||
| 150 | if (!g->power_on) | ||
| 151 | goto done; | ||
| 152 | |||
| 153 | if (g->ops.fifo.channel_suspend) | ||
| 154 | ret = g->ops.fifo.channel_suspend(g); | ||
| 155 | if (ret) | ||
| 156 | goto done; | ||
| 157 | |||
| 158 | g->power_on = false; | ||
| 159 | done: | ||
| 160 | nvgpu_mutex_release(&g->power_lock); | ||
| 161 | |||
| 162 | return ret; | ||
| 163 | } | ||
| 164 | |||
| 165 | int vgpu_pm_finalize_poweron(struct device *dev) | ||
| 166 | { | ||
| 167 | struct gk20a *g = get_gk20a(dev); | ||
| 168 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
| 169 | int err = 0; | ||
| 170 | |||
| 171 | nvgpu_log_fn(g, " "); | ||
| 172 | |||
| 173 | nvgpu_mutex_acquire(&g->power_lock); | ||
| 174 | |||
| 175 | if (g->power_on) | ||
| 176 | goto done; | ||
| 177 | |||
| 178 | g->power_on = true; | ||
| 179 | |||
| 180 | vgpu_detect_chip(g); | ||
| 181 | err = vgpu_init_hal(g); | ||
| 182 | if (err) | ||
| 183 | goto done; | ||
| 184 | |||
| 185 | if (g->ops.ltc.init_fs_state) | ||
| 186 | g->ops.ltc.init_fs_state(g); | ||
| 187 | |||
| 188 | err = nvgpu_init_ltc_support(g); | ||
| 189 | if (err) { | ||
| 190 | nvgpu_err(g, "failed to init ltc"); | ||
| 191 | goto done; | ||
| 192 | } | ||
| 193 | |||
| 194 | err = vgpu_init_mm_support(g); | ||
| 195 | if (err) { | ||
| 196 | nvgpu_err(g, "failed to init gk20a mm"); | ||
| 197 | goto done; | ||
| 198 | } | ||
| 199 | |||
| 200 | err = vgpu_init_fifo_support(g); | ||
| 201 | if (err) { | ||
| 202 | nvgpu_err(g, "failed to init gk20a fifo"); | ||
| 203 | goto done; | ||
| 204 | } | ||
| 205 | |||
| 206 | err = vgpu_init_gr_support(g); | ||
| 207 | if (err) { | ||
| 208 | nvgpu_err(g, "failed to init gk20a gr"); | ||
| 209 | goto done; | ||
| 210 | } | ||
| 211 | |||
| 212 | err = nvgpu_clk_arb_init_arbiter(g); | ||
| 213 | if (err) { | ||
| 214 | nvgpu_err(g, "failed to init clk arb"); | ||
| 215 | goto done; | ||
| 216 | } | ||
| 217 | |||
| 218 | err = g->ops.chip_init_gpu_characteristics(g); | ||
| 219 | if (err) { | ||
| 220 | nvgpu_err(g, "failed to init gk20a gpu characteristics"); | ||
| 221 | goto done; | ||
| 222 | } | ||
| 223 | |||
| 224 | err = nvgpu_finalize_poweron_linux(l); | ||
| 225 | if (err) | ||
| 226 | goto done; | ||
| 227 | |||
| 228 | #ifdef CONFIG_GK20A_CTXSW_TRACE | ||
| 229 | gk20a_ctxsw_trace_init(g); | ||
| 230 | #endif | ||
| 231 | gk20a_sched_ctrl_init(g); | ||
| 232 | gk20a_channel_resume(g); | ||
| 233 | |||
| 234 | g->sw_ready = true; | ||
| 235 | |||
| 236 | done: | ||
| 237 | if (err) | ||
| 238 | g->power_on = false; | ||
| 239 | |||
| 240 | nvgpu_mutex_release(&g->power_lock); | ||
| 241 | return err; | ||
| 242 | } | ||
| 243 | |||
| 244 | static int vgpu_qos_notify(struct notifier_block *nb, | ||
| 245 | unsigned long n, void *data) | ||
| 246 | { | ||
| 247 | struct gk20a_scale_profile *profile = | ||
| 248 | container_of(nb, struct gk20a_scale_profile, | ||
| 249 | qos_notify_block); | ||
| 250 | struct gk20a *g = get_gk20a(profile->dev); | ||
| 251 | u32 max_freq; | ||
| 252 | int err; | ||
| 253 | |||
| 254 | nvgpu_log_fn(g, " "); | ||
| 255 | |||
| 256 | max_freq = (u32)pm_qos_read_max_bound(PM_QOS_GPU_FREQ_BOUNDS); | ||
| 257 | err = vgpu_plat_clk_cap_rate(profile->dev, max_freq); | ||
| 258 | if (err) | ||
| 259 | nvgpu_err(g, "%s failed, err=%d", __func__, err); | ||
| 260 | |||
| 261 | return NOTIFY_OK; /* need notify call further */ | ||
| 262 | } | ||
| 263 | |||
| 264 | static int vgpu_pm_qos_init(struct device *dev) | ||
| 265 | { | ||
| 266 | struct gk20a *g = get_gk20a(dev); | ||
| 267 | struct gk20a_scale_profile *profile = g->scale_profile; | ||
| 268 | |||
| 269 | if (IS_ENABLED(CONFIG_GK20A_DEVFREQ)) { | ||
| 270 | if (!profile) | ||
| 271 | return -EINVAL; | ||
| 272 | } else { | ||
| 273 | profile = nvgpu_kzalloc(g, sizeof(*profile)); | ||
| 274 | if (!profile) | ||
| 275 | return -ENOMEM; | ||
| 276 | g->scale_profile = profile; | ||
| 277 | } | ||
| 278 | |||
| 279 | profile->dev = dev; | ||
| 280 | profile->qos_notify_block.notifier_call = vgpu_qos_notify; | ||
| 281 | pm_qos_add_max_notifier(PM_QOS_GPU_FREQ_BOUNDS, | ||
| 282 | &profile->qos_notify_block); | ||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | |||
| 286 | static void vgpu_pm_qos_remove(struct device *dev) | ||
| 287 | { | ||
| 288 | struct gk20a *g = get_gk20a(dev); | ||
| 289 | |||
| 290 | pm_qos_remove_max_notifier(PM_QOS_GPU_FREQ_BOUNDS, | ||
| 291 | &g->scale_profile->qos_notify_block); | ||
| 292 | nvgpu_kfree(g, g->scale_profile); | ||
| 293 | g->scale_profile = NULL; | ||
| 294 | } | ||
| 295 | |||
| 296 | static int vgpu_pm_init(struct device *dev) | ||
| 297 | { | ||
| 298 | struct gk20a *g = get_gk20a(dev); | ||
| 299 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
| 300 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
| 301 | unsigned long *freqs; | ||
| 302 | int num_freqs; | ||
| 303 | int err = 0; | ||
| 304 | |||
| 305 | nvgpu_log_fn(g, " "); | ||
| 306 | |||
| 307 | if (nvgpu_platform_is_simulation(g)) | ||
| 308 | return 0; | ||
| 309 | |||
| 310 | __pm_runtime_disable(dev, false); | ||
| 311 | |||
| 312 | if (IS_ENABLED(CONFIG_GK20A_DEVFREQ)) | ||
| 313 | gk20a_scale_init(dev); | ||
| 314 | |||
| 315 | if (l->devfreq) { | ||
| 316 | /* set min/max frequency based on frequency table */ | ||
| 317 | err = platform->get_clk_freqs(dev, &freqs, &num_freqs); | ||
| 318 | if (err) | ||
| 319 | return err; | ||
| 320 | |||
| 321 | if (num_freqs < 1) | ||
| 322 | return -EINVAL; | ||
| 323 | |||
| 324 | l->devfreq->min_freq = freqs[0]; | ||
| 325 | l->devfreq->max_freq = freqs[num_freqs - 1]; | ||
| 326 | } | ||
| 327 | |||
| 328 | err = vgpu_pm_qos_init(dev); | ||
| 329 | if (err) | ||
| 330 | return err; | ||
| 331 | |||
| 332 | return err; | ||
| 333 | } | ||
| 334 | |||
| 335 | int vgpu_probe(struct platform_device *pdev) | ||
| 336 | { | ||
| 337 | struct nvgpu_os_linux *l; | ||
| 338 | struct gk20a *gk20a; | ||
| 339 | int err; | ||
| 340 | struct device *dev = &pdev->dev; | ||
| 341 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
| 342 | struct vgpu_priv_data *priv; | ||
| 343 | |||
| 344 | if (!platform) { | ||
| 345 | dev_err(dev, "no platform data\n"); | ||
| 346 | return -ENODATA; | ||
| 347 | } | ||
| 348 | |||
| 349 | l = kzalloc(sizeof(*l), GFP_KERNEL); | ||
| 350 | if (!l) { | ||
| 351 | dev_err(dev, "couldn't allocate gk20a support"); | ||
| 352 | return -ENOMEM; | ||
| 353 | } | ||
| 354 | gk20a = &l->g; | ||
| 355 | |||
| 356 | nvgpu_log_fn(gk20a, " "); | ||
| 357 | |||
| 358 | nvgpu_init_gk20a(gk20a); | ||
| 359 | |||
| 360 | nvgpu_kmem_init(gk20a); | ||
| 361 | |||
| 362 | err = nvgpu_init_enabled_flags(gk20a); | ||
| 363 | if (err) { | ||
| 364 | kfree(gk20a); | ||
| 365 | return err; | ||
| 366 | } | ||
| 367 | |||
| 368 | l->dev = dev; | ||
| 369 | if (tegra_platform_is_vdk()) | ||
| 370 | __nvgpu_set_enabled(gk20a, NVGPU_IS_FMODEL, true); | ||
| 371 | |||
| 372 | gk20a->is_virtual = true; | ||
| 373 | |||
| 374 | priv = nvgpu_kzalloc(gk20a, sizeof(*priv)); | ||
| 375 | if (!priv) { | ||
| 376 | kfree(gk20a); | ||
| 377 | return -ENOMEM; | ||
| 378 | } | ||
| 379 | |||
| 380 | platform->g = gk20a; | ||
| 381 | platform->vgpu_priv = priv; | ||
| 382 | |||
| 383 | err = gk20a_user_init(dev, INTERFACE_NAME, &nvgpu_class); | ||
| 384 | if (err) | ||
| 385 | return err; | ||
| 386 | |||
| 387 | vgpu_init_support(pdev); | ||
| 388 | |||
| 389 | vgpu_init_vars(gk20a, platform); | ||
| 390 | |||
| 391 | init_rwsem(&l->busy_lock); | ||
| 392 | |||
| 393 | nvgpu_spinlock_init(&gk20a->mc_enable_lock); | ||
| 394 | |||
| 395 | gk20a->ch_wdt_timeout_ms = platform->ch_wdt_timeout_ms; | ||
| 396 | |||
| 397 | /* Initialize the platform interface. */ | ||
| 398 | err = platform->probe(dev); | ||
| 399 | if (err) { | ||
| 400 | if (err == -EPROBE_DEFER) | ||
| 401 | nvgpu_info(gk20a, "platform probe failed"); | ||
| 402 | else | ||
| 403 | nvgpu_err(gk20a, "platform probe failed"); | ||
| 404 | return err; | ||
| 405 | } | ||
| 406 | |||
| 407 | if (platform->late_probe) { | ||
| 408 | err = platform->late_probe(dev); | ||
| 409 | if (err) { | ||
| 410 | nvgpu_err(gk20a, "late probe failed"); | ||
| 411 | return err; | ||
| 412 | } | ||
| 413 | } | ||
| 414 | |||
| 415 | err = vgpu_comm_init(gk20a); | ||
| 416 | if (err) { | ||
| 417 | nvgpu_err(gk20a, "failed to init comm interface"); | ||
| 418 | return -ENOSYS; | ||
| 419 | } | ||
| 420 | |||
| 421 | priv->virt_handle = vgpu_connect(); | ||
| 422 | if (!priv->virt_handle) { | ||
| 423 | nvgpu_err(gk20a, "failed to connect to server node"); | ||
| 424 | vgpu_comm_deinit(); | ||
| 425 | return -ENOSYS; | ||
| 426 | } | ||
| 427 | |||
| 428 | err = vgpu_get_constants(gk20a); | ||
| 429 | if (err) { | ||
| 430 | vgpu_comm_deinit(); | ||
| 431 | return err; | ||
| 432 | } | ||
| 433 | |||
| 434 | err = vgpu_pm_init(dev); | ||
| 435 | if (err) { | ||
| 436 | nvgpu_err(gk20a, "pm init failed"); | ||
| 437 | return err; | ||
| 438 | } | ||
| 439 | |||
| 440 | err = nvgpu_thread_create(&priv->intr_handler, gk20a, | ||
| 441 | vgpu_intr_thread, "gk20a"); | ||
| 442 | if (err) | ||
| 443 | return err; | ||
| 444 | |||
| 445 | gk20a_debug_init(gk20a, "gpu.0"); | ||
| 446 | |||
| 447 | /* Set DMA parameters to allow larger sgt lists */ | ||
| 448 | dev->dma_parms = &l->dma_parms; | ||
| 449 | dma_set_max_seg_size(dev, UINT_MAX); | ||
| 450 | |||
| 451 | gk20a->gr_idle_timeout_default = NVGPU_DEFAULT_GR_IDLE_TIMEOUT; | ||
| 452 | gk20a->timeouts_disabled_by_user = false; | ||
| 453 | nvgpu_atomic_set(&gk20a->timeouts_disabled_refcount, 0); | ||
| 454 | |||
| 455 | vgpu_create_sysfs(dev); | ||
| 456 | gk20a_init_gr(gk20a); | ||
| 457 | |||
| 458 | nvgpu_log_info(gk20a, "total ram pages : %lu", totalram_pages); | ||
| 459 | gk20a->gr.max_comptag_mem = totalram_size_in_mb; | ||
| 460 | |||
| 461 | nvgpu_ref_init(&gk20a->refcount); | ||
| 462 | |||
| 463 | return 0; | ||
| 464 | } | ||
| 465 | |||
| 466 | int vgpu_remove(struct platform_device *pdev) | ||
| 467 | { | ||
| 468 | struct device *dev = &pdev->dev; | ||
| 469 | struct gk20a *g = get_gk20a(dev); | ||
| 470 | |||
| 471 | nvgpu_log_fn(g, " "); | ||
| 472 | |||
| 473 | vgpu_pm_qos_remove(dev); | ||
| 474 | if (g->remove_support) | ||
| 475 | g->remove_support(g); | ||
| 476 | |||
| 477 | vgpu_comm_deinit(); | ||
| 478 | gk20a_sched_ctrl_cleanup(g); | ||
| 479 | gk20a_user_deinit(dev, &nvgpu_class); | ||
| 480 | vgpu_remove_sysfs(dev); | ||
| 481 | gk20a_get_platform(dev)->g = NULL; | ||
| 482 | gk20a_put(g); | ||
| 483 | |||
| 484 | return 0; | ||
| 485 | } | ||
| 486 | |||
| 487 | bool vgpu_is_reduced_bar1(struct gk20a *g) | ||
| 488 | { | ||
| 489 | struct fifo_gk20a *f = &g->fifo; | ||
| 490 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
| 491 | |||
| 492 | return resource_size(l->bar1_mem) == (resource_size_t)f->userd.size; | ||
| 493 | } | ||
| 494 | |||
| 495 | int vgpu_tegra_suspend(struct device *dev) | ||
| 496 | { | ||
| 497 | struct tegra_vgpu_cmd_msg msg = {}; | ||
| 498 | struct gk20a *g = get_gk20a(dev); | ||
| 499 | int err = 0; | ||
| 500 | |||
| 501 | msg.cmd = TEGRA_VGPU_CMD_SUSPEND; | ||
| 502 | msg.handle = vgpu_get_handle(g); | ||
| 503 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); | ||
| 504 | err = err ? err : msg.ret; | ||
| 505 | if (err) | ||
| 506 | nvgpu_err(g, "vGPU suspend failed\n"); | ||
| 507 | |||
| 508 | return err; | ||
| 509 | } | ||
| 510 | |||
| 511 | int vgpu_tegra_resume(struct device *dev) | ||
| 512 | { | ||
| 513 | struct tegra_vgpu_cmd_msg msg = {}; | ||
| 514 | struct gk20a *g = get_gk20a(dev); | ||
| 515 | int err = 0; | ||
| 516 | |||
| 517 | msg.cmd = TEGRA_VGPU_CMD_RESUME; | ||
| 518 | msg.handle = vgpu_get_handle(g); | ||
| 519 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); | ||
| 520 | err = err ? err : msg.ret; | ||
| 521 | if (err) | ||
| 522 | nvgpu_err(g, "vGPU resume failed\n"); | ||
| 523 | |||
| 524 | return err; | ||
| 525 | } | ||
diff --git a/include/os/linux/vgpu/vgpu_linux.h b/include/os/linux/vgpu/vgpu_linux.h new file mode 100644 index 0000000..ff7d3a6 --- /dev/null +++ b/include/os/linux/vgpu/vgpu_linux.h | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* | ||
| 2 | * Virtualized GPU Linux Interfaces | ||
| 3 | * | ||
| 4 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef __VGPU_LINUX_H__ | ||
| 20 | #define __VGPU_LINUX_H__ | ||
| 21 | |||
| 22 | struct device; | ||
| 23 | struct platform_device; | ||
| 24 | |||
| 25 | #ifdef CONFIG_TEGRA_GR_VIRTUALIZATION | ||
| 26 | |||
| 27 | #include <nvgpu/vgpu/vgpu.h> | ||
| 28 | |||
| 29 | int vgpu_pm_prepare_poweroff(struct device *dev); | ||
| 30 | int vgpu_pm_finalize_poweron(struct device *dev); | ||
| 31 | int vgpu_probe(struct platform_device *dev); | ||
| 32 | int vgpu_remove(struct platform_device *dev); | ||
| 33 | |||
| 34 | void vgpu_create_sysfs(struct device *dev); | ||
| 35 | void vgpu_remove_sysfs(struct device *dev); | ||
| 36 | |||
| 37 | int vgpu_tegra_suspend(struct device *dev); | ||
| 38 | int vgpu_tegra_resume(struct device *dev); | ||
| 39 | #else | ||
| 40 | /* define placeholders for functions used outside of vgpu */ | ||
| 41 | |||
| 42 | static inline int vgpu_pm_prepare_poweroff(struct device *dev) | ||
| 43 | { | ||
| 44 | return -ENOSYS; | ||
| 45 | } | ||
| 46 | static inline int vgpu_pm_finalize_poweron(struct device *dev) | ||
| 47 | { | ||
| 48 | return -ENOSYS; | ||
| 49 | } | ||
| 50 | static inline int vgpu_probe(struct platform_device *dev) | ||
| 51 | { | ||
| 52 | return -ENOSYS; | ||
| 53 | } | ||
| 54 | static inline int vgpu_remove(struct platform_device *dev) | ||
| 55 | { | ||
| 56 | return -ENOSYS; | ||
| 57 | } | ||
| 58 | static inline int vgpu_tegra_suspend(struct device *dev) | ||
| 59 | { | ||
| 60 | return -ENOSYS; | ||
| 61 | } | ||
| 62 | static inline int vgpu_tegra_resume(struct device *dev) | ||
| 63 | { | ||
| 64 | return -ENOSYS; | ||
| 65 | } | ||
| 66 | #endif | ||
| 67 | |||
| 68 | #endif | ||
