summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/linux/vgpu/gp10b/vgpu_mm_gp10b.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/vgpu/gp10b/vgpu_mm_gp10b.c')
-rw-r--r--drivers/gpu/nvgpu/common/linux/vgpu/gp10b/vgpu_mm_gp10b.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/vgpu/gp10b/vgpu_mm_gp10b.c b/drivers/gpu/nvgpu/common/linux/vgpu/gp10b/vgpu_mm_gp10b.c
new file mode 100644
index 00000000..9eb140a3
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/vgpu/gp10b/vgpu_mm_gp10b.c
@@ -0,0 +1,197 @@
1/*
2 * Virtualized GPU Memory Management
3 *
4 * Copyright (c) 2015-2017, 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 <uapi/linux/nvgpu.h>
20
21#include "common/linux/vgpu/vgpu.h"
22#include "vgpu_mm_gp10b.h"
23#include "gk20a/mm_gk20a.h"
24
25#include <nvgpu/bug.h>
26
27int vgpu_gp10b_init_mm_setup_hw(struct gk20a *g)
28{
29 g->mm.bypass_smmu = true;
30 g->mm.disable_bigpage = true;
31 return 0;
32}
33
34static inline int add_mem_desc(struct tegra_vgpu_mem_desc *mem_desc,
35 u64 addr, u64 size, size_t *oob_size)
36{
37 if (*oob_size < sizeof(*mem_desc))
38 return -ENOMEM;
39
40 mem_desc->addr = addr;
41 mem_desc->length = size;
42 *oob_size -= sizeof(*mem_desc);
43 return 0;
44}
45
46u64 vgpu_gp10b_locked_gmmu_map(struct vm_gk20a *vm,
47 u64 map_offset,
48 struct nvgpu_sgt *sgt,
49 u64 buffer_offset,
50 u64 size,
51 int pgsz_idx,
52 u8 kind_v,
53 u32 ctag_offset,
54 u32 flags,
55 int rw_flag,
56 bool clear_ctags,
57 bool sparse,
58 bool priv,
59 struct vm_gk20a_mapping_batch *batch,
60 enum nvgpu_aperture aperture)
61{
62 int err = 0;
63 struct gk20a *g = gk20a_from_vm(vm);
64 struct tegra_vgpu_cmd_msg msg;
65 struct tegra_vgpu_as_map_ex_params *p = &msg.params.as_map_ex;
66 struct tegra_vgpu_mem_desc *mem_desc;
67 u32 page_size = vm->gmmu_page_sizes[pgsz_idx];
68 u64 buffer_size = PAGE_ALIGN(size);
69 u64 space_to_skip = buffer_offset;
70 u32 mem_desc_count = 0, i;
71 void *handle = NULL;
72 size_t oob_size;
73 u8 prot;
74 void *sgl;
75
76 gk20a_dbg_fn("");
77
78 /* FIXME: add support for sparse mappings */
79
80 if (WARN_ON(!sgt) || WARN_ON(!g->mm.bypass_smmu))
81 return 0;
82
83 if (space_to_skip & (page_size - 1))
84 return 0;
85
86 memset(&msg, 0, sizeof(msg));
87
88 /* Allocate (or validate when map_offset != 0) the virtual address. */
89 if (!map_offset) {
90 map_offset = __nvgpu_vm_alloc_va(vm, size, pgsz_idx);
91 if (!map_offset) {
92 nvgpu_err(g, "failed to allocate va space");
93 err = -ENOMEM;
94 goto fail;
95 }
96 }
97
98 handle = tegra_gr_comm_oob_get_ptr(TEGRA_GR_COMM_CTX_CLIENT,
99 tegra_gr_comm_get_server_vmid(),
100 TEGRA_VGPU_QUEUE_CMD,
101 (void **)&mem_desc, &oob_size);
102 if (!handle) {
103 err = -EINVAL;
104 goto fail;
105 }
106 sgl = sgt->sgl;
107 while (sgl) {
108 u64 phys_addr;
109 u64 chunk_length;
110
111 /*
112 * Cut out sgl ents for space_to_skip.
113 */
114 if (space_to_skip &&
115 space_to_skip >= nvgpu_sgt_get_length(sgt, sgl)) {
116 space_to_skip -= nvgpu_sgt_get_length(sgt, sgl);
117 sgl = nvgpu_sgt_get_next(sgt, sgl);
118 continue;
119 }
120
121 phys_addr = nvgpu_sgt_get_phys(sgt, sgl) + space_to_skip;
122 chunk_length = min(size,
123 nvgpu_sgt_get_length(sgt, sgl) - space_to_skip);
124
125 if (add_mem_desc(&mem_desc[mem_desc_count++], phys_addr,
126 chunk_length, &oob_size)) {
127 err = -ENOMEM;
128 goto fail;
129 }
130
131 space_to_skip = 0;
132 size -= chunk_length;
133 sgl = nvgpu_sgt_get_next(sgt, sgl);
134
135 if (size == 0)
136 break;
137 }
138
139 if (rw_flag == gk20a_mem_flag_read_only)
140 prot = TEGRA_VGPU_MAP_PROT_READ_ONLY;
141 else if (rw_flag == gk20a_mem_flag_write_only)
142 prot = TEGRA_VGPU_MAP_PROT_WRITE_ONLY;
143 else
144 prot = TEGRA_VGPU_MAP_PROT_NONE;
145
146 if (pgsz_idx == gmmu_page_size_kernel) {
147 if (page_size == vm->gmmu_page_sizes[gmmu_page_size_small]) {
148 pgsz_idx = gmmu_page_size_small;
149 } else if (page_size ==
150 vm->gmmu_page_sizes[gmmu_page_size_big]) {
151 pgsz_idx = gmmu_page_size_big;
152 } else {
153 nvgpu_err(g, "invalid kernel page size %d",
154 page_size);
155 goto fail;
156 }
157 }
158
159 msg.cmd = TEGRA_VGPU_CMD_AS_MAP_EX;
160 msg.handle = vgpu_get_handle(g);
161 p->handle = vm->handle;
162 p->gpu_va = map_offset;
163 p->size = buffer_size;
164 p->mem_desc_count = mem_desc_count;
165 p->pgsz_idx = pgsz_idx;
166 p->iova = 0;
167 p->kind = kind_v;
168 p->cacheable = (flags & NVGPU_AS_MAP_BUFFER_FLAGS_CACHEABLE) ? 1 : 0;
169 p->prot = prot;
170 p->ctag_offset = ctag_offset;
171 p->clear_ctags = clear_ctags;
172 err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg));
173 if (err || msg.ret)
174 goto fail;
175
176 /* TLB invalidate handled on server side */
177
178 tegra_gr_comm_oob_put_ptr(handle);
179 return map_offset;
180fail:
181 if (handle)
182 tegra_gr_comm_oob_put_ptr(handle);
183 nvgpu_err(g, "Failed: err=%d, msg.ret=%d", err, msg.ret);
184 nvgpu_err(g,
185 " Map: %-5s GPU virt %#-12llx +%#-9llx "
186 "phys offset: %#-4llx; pgsz: %3dkb perm=%-2s | "
187 "kind=%#02x APT=%-6s",
188 vm->name, map_offset, buffer_size, buffer_offset,
189 vm->gmmu_page_sizes[pgsz_idx] >> 10,
190 nvgpu_gmmu_perm_str(rw_flag),
191 kind_v, "SYSMEM");
192 for (i = 0; i < mem_desc_count; i++)
193 nvgpu_err(g, " > 0x%010llx + 0x%llx",
194 mem_desc[i].addr, mem_desc[i].length);
195
196 return 0;
197}