summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/mm/mm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/common/mm/mm.c')
-rw-r--r--drivers/gpu/nvgpu/common/mm/mm.c450
1 files changed, 450 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/mm/mm.c b/drivers/gpu/nvgpu/common/mm/mm.c
new file mode 100644
index 00000000..db87c4c4
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/mm/mm.c
@@ -0,0 +1,450 @@
1/*
2 * Permission is hereby granted, free of charge, to any person obtaining a
3 * copy of this software and associated documentation files (the "Software"),
4 * to deal in the Software without restriction, including without limitation
5 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
6 * and/or sell copies of the Software, and to permit persons to whom the
7 * Software is furnished to do so, subject to the following conditions:
8 *
9 * The above copyright notice and this permission notice shall be included in
10 * all copies or substantial portions of the Software.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
15 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18 * DEALINGS IN THE SOFTWARE.
19 */
20
21#include <nvgpu/mm.h>
22#include <nvgpu/vm.h>
23#include <nvgpu/dma.h>
24#include <nvgpu/vm_area.h>
25#include <nvgpu/gmmu.h>
26#include <nvgpu/vidmem.h>
27#include <nvgpu/semaphore.h>
28#include <nvgpu/pramin.h>
29#include <nvgpu/enabled.h>
30
31#include "gk20a/gk20a.h"
32
33/*
34 * Attempt to find a reserved memory area to determine PTE size for the passed
35 * mapping. If no reserved area can be found use small pages.
36 */
37enum gmmu_pgsz_gk20a __get_pte_size_fixed_map(struct vm_gk20a *vm,
38 u64 base, u64 size)
39{
40 struct nvgpu_vm_area *vm_area;
41
42 vm_area = nvgpu_vm_area_find(vm, base);
43 if (!vm_area)
44 return gmmu_page_size_small;
45
46 return vm_area->pgsz_idx;
47}
48
49/*
50 * This is for when the address space does not support unified address spaces.
51 */
52static enum gmmu_pgsz_gk20a __get_pte_size_split_addr(struct vm_gk20a *vm,
53 u64 base, u64 size)
54{
55 if (!base) {
56 if (size >= vm->gmmu_page_sizes[gmmu_page_size_big])
57 return gmmu_page_size_big;
58 return gmmu_page_size_small;
59 } else {
60 if (base < __nv_gmmu_va_small_page_limit())
61 return gmmu_page_size_small;
62 else
63 return gmmu_page_size_big;
64 }
65}
66
67/*
68 * This determines the PTE size for a given alloc. Used by both the GVA space
69 * allocator and the mm core code so that agreement can be reached on how to
70 * map allocations.
71 *
72 * The page size of a buffer is this:
73 *
74 * o If the VM doesn't support large pages then obviously small pages
75 * must be used.
76 * o If the base address is non-zero (fixed address map):
77 * - Attempt to find a reserved memory area and use the page size
78 * based on that.
79 * - If no reserved page size is available, default to small pages.
80 * o If the base is zero:
81 * - If the size is larger than or equal to the big page size, use big
82 * pages.
83 * - Otherwise use small pages.
84 */
85enum gmmu_pgsz_gk20a __get_pte_size(struct vm_gk20a *vm, u64 base, u64 size)
86{
87 struct gk20a *g = gk20a_from_vm(vm);
88
89 if (!vm->big_pages)
90 return gmmu_page_size_small;
91
92 if (!nvgpu_is_enabled(g, NVGPU_MM_UNIFY_ADDRESS_SPACES))
93 return __get_pte_size_split_addr(vm, base, size);
94
95 if (base)
96 return __get_pte_size_fixed_map(vm, base, size);
97
98 if (size >= vm->gmmu_page_sizes[gmmu_page_size_big])
99 return gmmu_page_size_big;
100 return gmmu_page_size_small;
101}
102
103int nvgpu_mm_suspend(struct gk20a *g)
104{
105 nvgpu_log_info(g, "MM suspend running...");
106
107 nvgpu_vidmem_thread_pause_sync(&g->mm);
108
109 g->ops.mm.cbc_clean(g);
110 g->ops.mm.l2_flush(g, false);
111
112 nvgpu_log_info(g, "MM suspend done!");
113
114 return 0;
115}
116
117u64 nvgpu_inst_block_addr(struct gk20a *g, struct nvgpu_mem *inst_block)
118{
119 if (g->mm.has_physical_mode)
120 return nvgpu_mem_get_phys_addr(g, inst_block);
121 else
122 return nvgpu_mem_get_addr(g, inst_block);
123}
124
125void nvgpu_free_inst_block(struct gk20a *g, struct nvgpu_mem *inst_block)
126{
127 if (nvgpu_mem_is_valid(inst_block))
128 nvgpu_dma_free(g, inst_block);
129}
130
131static int nvgpu_alloc_sysmem_flush(struct gk20a *g)
132{
133 return nvgpu_dma_alloc_sys(g, SZ_4K, &g->mm.sysmem_flush);
134}
135
136static void nvgpu_remove_mm_ce_support(struct mm_gk20a *mm)
137{
138 struct gk20a *g = gk20a_from_mm(mm);
139
140 if (mm->vidmem.ce_ctx_id != (u32)~0)
141 gk20a_ce_delete_context_priv(g, mm->vidmem.ce_ctx_id);
142
143 mm->vidmem.ce_ctx_id = (u32)~0;
144
145 nvgpu_vm_put(mm->ce.vm);
146}
147
148static void nvgpu_remove_mm_support(struct mm_gk20a *mm)
149{
150 struct gk20a *g = gk20a_from_mm(mm);
151
152 if (g->ops.mm.fault_info_mem_destroy)
153 g->ops.mm.fault_info_mem_destroy(g);
154
155 if (g->ops.mm.remove_bar2_vm)
156 g->ops.mm.remove_bar2_vm(g);
157
158 if (g->ops.mm.is_bar1_supported(g)) {
159 nvgpu_free_inst_block(g, &mm->bar1.inst_block);
160 nvgpu_vm_put(mm->bar1.vm);
161 }
162
163 nvgpu_free_inst_block(g, &mm->pmu.inst_block);
164 nvgpu_free_inst_block(g, &mm->hwpm.inst_block);
165 nvgpu_vm_put(mm->pmu.vm);
166 nvgpu_vm_put(mm->cde.vm);
167
168 nvgpu_semaphore_sea_destroy(g);
169 nvgpu_vidmem_destroy(g);
170 nvgpu_pd_cache_fini(g);
171}
172
173/* pmu vm, share channel_vm interfaces */
174static int nvgpu_init_system_vm(struct mm_gk20a *mm)
175{
176 int err;
177 struct gk20a *g = gk20a_from_mm(mm);
178 struct nvgpu_mem *inst_block = &mm->pmu.inst_block;
179 u32 big_page_size = g->ops.mm.get_default_big_page_size();
180 u32 low_hole, aperture_size;
181
182 /*
183 * No user region - so we will pass that as zero sized.
184 */
185 low_hole = SZ_4K * 16;
186 aperture_size = GK20A_PMU_VA_SIZE * 2;
187
188 mm->pmu.aperture_size = GK20A_PMU_VA_SIZE;
189 nvgpu_log_info(g, "pmu vm size = 0x%x", mm->pmu.aperture_size);
190
191 mm->pmu.vm = nvgpu_vm_init(g, big_page_size,
192 low_hole,
193 aperture_size - low_hole,
194 aperture_size,
195 true,
196 false,
197 "system");
198 if (!mm->pmu.vm)
199 return -ENOMEM;
200
201 err = g->ops.mm.alloc_inst_block(g, inst_block);
202 if (err)
203 goto clean_up_vm;
204 g->ops.mm.init_inst_block(inst_block, mm->pmu.vm, big_page_size);
205
206 return 0;
207
208clean_up_vm:
209 nvgpu_vm_put(mm->pmu.vm);
210 return err;
211}
212
213static int nvgpu_init_hwpm(struct mm_gk20a *mm)
214{
215 int err;
216 struct gk20a *g = gk20a_from_mm(mm);
217 struct nvgpu_mem *inst_block = &mm->hwpm.inst_block;
218
219 err = g->ops.mm.alloc_inst_block(g, inst_block);
220 if (err)
221 return err;
222 g->ops.mm.init_inst_block(inst_block, mm->pmu.vm, 0);
223
224 return 0;
225}
226
227static int nvgpu_init_cde_vm(struct mm_gk20a *mm)
228{
229 struct gk20a *g = gk20a_from_mm(mm);
230 u32 big_page_size = g->ops.mm.get_default_big_page_size();
231
232 mm->cde.vm = nvgpu_vm_init(g, big_page_size,
233 big_page_size << 10,
234 NV_MM_DEFAULT_KERNEL_SIZE,
235 NV_MM_DEFAULT_KERNEL_SIZE + NV_MM_DEFAULT_USER_SIZE,
236 false, false, "cde");
237 if (!mm->cde.vm)
238 return -ENOMEM;
239 return 0;
240}
241
242static int nvgpu_init_ce_vm(struct mm_gk20a *mm)
243{
244 struct gk20a *g = gk20a_from_mm(mm);
245 u32 big_page_size = g->ops.mm.get_default_big_page_size();
246
247 mm->ce.vm = nvgpu_vm_init(g, big_page_size,
248 big_page_size << 10,
249 NV_MM_DEFAULT_KERNEL_SIZE,
250 NV_MM_DEFAULT_KERNEL_SIZE + NV_MM_DEFAULT_USER_SIZE,
251 false, false, "ce");
252 if (!mm->ce.vm)
253 return -ENOMEM;
254 return 0;
255}
256
257void nvgpu_init_mm_ce_context(struct gk20a *g)
258{
259#if defined(CONFIG_GK20A_VIDMEM)
260 if (g->mm.vidmem.size && (g->mm.vidmem.ce_ctx_id == (u32)~0)) {
261 g->mm.vidmem.ce_ctx_id =
262 gk20a_ce_create_context(g,
263 gk20a_fifo_get_fast_ce_runlist_id(g),
264 -1,
265 -1);
266
267 if (g->mm.vidmem.ce_ctx_id == (u32)~0)
268 nvgpu_err(g,
269 "Failed to allocate CE context for vidmem page clearing support");
270 }
271#endif
272}
273
274static int nvgpu_init_mm_reset_enable_hw(struct gk20a *g)
275{
276 if (g->ops.fb.reset)
277 g->ops.fb.reset(g);
278
279 if (g->ops.clock_gating.slcg_fb_load_gating_prod)
280 g->ops.clock_gating.slcg_fb_load_gating_prod(g,
281 g->slcg_enabled);
282 if (g->ops.clock_gating.slcg_ltc_load_gating_prod)
283 g->ops.clock_gating.slcg_ltc_load_gating_prod(g,
284 g->slcg_enabled);
285 if (g->ops.clock_gating.blcg_fb_load_gating_prod)
286 g->ops.clock_gating.blcg_fb_load_gating_prod(g,
287 g->blcg_enabled);
288 if (g->ops.clock_gating.blcg_ltc_load_gating_prod)
289 g->ops.clock_gating.blcg_ltc_load_gating_prod(g,
290 g->blcg_enabled);
291
292 if (g->ops.fb.init_fs_state)
293 g->ops.fb.init_fs_state(g);
294
295 return 0;
296}
297
298static int nvgpu_init_bar1_vm(struct mm_gk20a *mm)
299{
300 int err;
301 struct gk20a *g = gk20a_from_mm(mm);
302 struct nvgpu_mem *inst_block = &mm->bar1.inst_block;
303 u32 big_page_size = g->ops.mm.get_default_big_page_size();
304
305 mm->bar1.aperture_size = bar1_aperture_size_mb_gk20a() << 20;
306 nvgpu_log_info(g, "bar1 vm size = 0x%x", mm->bar1.aperture_size);
307 mm->bar1.vm = nvgpu_vm_init(g,
308 big_page_size,
309 SZ_4K,
310 mm->bar1.aperture_size - SZ_4K,
311 mm->bar1.aperture_size,
312 true, false,
313 "bar1");
314 if (!mm->bar1.vm)
315 return -ENOMEM;
316
317 err = g->ops.mm.alloc_inst_block(g, inst_block);
318 if (err)
319 goto clean_up_vm;
320 g->ops.mm.init_inst_block(inst_block, mm->bar1.vm, big_page_size);
321
322 return 0;
323
324clean_up_vm:
325 nvgpu_vm_put(mm->bar1.vm);
326 return err;
327}
328
329static int nvgpu_init_mm_setup_sw(struct gk20a *g)
330{
331 struct mm_gk20a *mm = &g->mm;
332 int err;
333
334 if (mm->sw_ready) {
335 nvgpu_log_info(g, "skip init");
336 return 0;
337 }
338
339 mm->g = g;
340 nvgpu_mutex_init(&mm->l2_op_lock);
341
342 /*TBD: make channel vm size configurable */
343 mm->channel.user_size = NV_MM_DEFAULT_USER_SIZE -
344 NV_MM_DEFAULT_KERNEL_SIZE;
345 mm->channel.kernel_size = NV_MM_DEFAULT_KERNEL_SIZE;
346
347 nvgpu_log_info(g, "channel vm size: user %dMB kernel %dMB",
348 (int)(mm->channel.user_size >> 20),
349 (int)(mm->channel.kernel_size >> 20));
350
351 nvgpu_init_pramin(mm);
352
353 mm->vidmem.ce_ctx_id = (u32)~0;
354
355 err = nvgpu_vidmem_init(mm);
356 if (err)
357 return err;
358
359 /*
360 * this requires fixed allocations in vidmem which must be
361 * allocated before all other buffers
362 */
363 if (g->ops.pmu.alloc_blob_space
364 && !nvgpu_is_enabled(g, NVGPU_MM_UNIFIED_MEMORY)) {
365 err = g->ops.pmu.alloc_blob_space(g, 0, &g->acr.ucode_blob);
366 if (err)
367 return err;
368 }
369
370 err = nvgpu_alloc_sysmem_flush(g);
371 if (err)
372 return err;
373
374 if (g->ops.mm.is_bar1_supported(g)) {
375 err = nvgpu_init_bar1_vm(mm);
376 if (err)
377 return err;
378 }
379 if (g->ops.mm.init_bar2_vm) {
380 err = g->ops.mm.init_bar2_vm(g);
381 if (err)
382 return err;
383 }
384 err = nvgpu_init_system_vm(mm);
385 if (err)
386 return err;
387
388 err = nvgpu_init_hwpm(mm);
389 if (err)
390 return err;
391
392 err = nvgpu_init_cde_vm(mm);
393 if (err)
394 return err;
395
396 err = nvgpu_init_ce_vm(mm);
397 if (err)
398 return err;
399
400 mm->remove_support = nvgpu_remove_mm_support;
401 mm->remove_ce_support = nvgpu_remove_mm_ce_support;
402
403 mm->sw_ready = true;
404
405 return 0;
406}
407
408int nvgpu_init_mm_support(struct gk20a *g)
409{
410 u32 err;
411
412 err = nvgpu_init_mm_reset_enable_hw(g);
413 if (err)
414 return err;
415
416 err = nvgpu_init_mm_setup_sw(g);
417 if (err)
418 return err;
419
420 if (g->ops.mm.init_mm_setup_hw)
421 err = g->ops.mm.init_mm_setup_hw(g);
422
423 return err;
424}
425
426u32 nvgpu_mm_get_default_big_page_size(struct gk20a *g)
427{
428 u32 big_page_size;
429
430 big_page_size = g->ops.mm.get_default_big_page_size();
431
432 if (g->mm.disable_bigpage)
433 big_page_size = 0;
434
435 return big_page_size;
436}
437
438u32 nvgpu_mm_get_available_big_page_sizes(struct gk20a *g)
439{
440 u32 available_big_page_sizes = 0;
441
442 if (!g->mm.disable_bigpage) {
443 available_big_page_sizes =
444 g->ops.mm.get_default_big_page_size();
445 if (g->ops.mm.get_big_page_sizes)
446 available_big_page_sizes |= g->ops.mm.get_big_page_sizes();
447 }
448
449 return available_big_page_sizes;
450}