diff options
Diffstat (limited to 'drivers/gpu/nvgpu/gv11b')
-rw-r--r-- | drivers/gpu/nvgpu/gv11b/mm_gv11b.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gv11b/mm_gv11b.c b/drivers/gpu/nvgpu/gv11b/mm_gv11b.c index f4fc4db4..9430f576 100644 --- a/drivers/gpu/nvgpu/gv11b/mm_gv11b.c +++ b/drivers/gpu/nvgpu/gv11b/mm_gv11b.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | #include <nvgpu/hw/gv11b/hw_fb_gv11b.h> | 31 | #include <nvgpu/hw/gv11b/hw_fb_gv11b.h> |
32 | #include <nvgpu/hw/gv11b/hw_gmmu_gv11b.h> | 32 | #include <nvgpu/hw/gv11b/hw_gmmu_gv11b.h> |
33 | #include <nvgpu/hw/gv11b/hw_bus_gv11b.h> | ||
33 | 34 | ||
34 | #define NVGPU_L3_ALLOC_BIT 36 | 35 | #define NVGPU_L3_ALLOC_BIT 36 |
35 | 36 | ||
@@ -268,6 +269,56 @@ u64 gv11b_gpu_phys_addr(struct gk20a *g, | |||
268 | return phys; | 269 | return phys; |
269 | } | 270 | } |
270 | 271 | ||
272 | static int gv11b_init_bar2_mm_hw_setup(struct gk20a *g) | ||
273 | { | ||
274 | struct mm_gk20a *mm = &g->mm; | ||
275 | struct nvgpu_mem *inst_block = &mm->bar2.inst_block; | ||
276 | u64 inst_pa = gk20a_mm_inst_block_addr(g, inst_block); | ||
277 | u32 reg_val; | ||
278 | struct nvgpu_timeout timeout; | ||
279 | u32 delay = GR_IDLE_CHECK_DEFAULT; | ||
280 | |||
281 | nvgpu_log_fn(g, " "); | ||
282 | |||
283 | g->ops.fb.set_mmu_page_size(g); | ||
284 | |||
285 | inst_pa = (u32)(inst_pa >> bus_bar2_block_ptr_shift_v()); | ||
286 | nvgpu_log_info(g, "bar2 inst block ptr: 0x%08x", (u32)inst_pa); | ||
287 | |||
288 | gk20a_writel(g, bus_bar2_block_r(), | ||
289 | nvgpu_aperture_mask(g, inst_block, | ||
290 | bus_bar2_block_target_sys_mem_ncoh_f(), | ||
291 | bus_bar2_block_target_vid_mem_f()) | | ||
292 | bus_bar2_block_mode_virtual_f() | | ||
293 | bus_bar2_block_ptr_f(inst_pa)); | ||
294 | |||
295 | /* This is needed as BAR1 support is removed and there is no way | ||
296 | * to know if gpu successfully accessed memory. | ||
297 | * To avoid deadlocks and non-deterministic virtual address translation | ||
298 | * behavior, after writing BAR2_BLOCK to bind BAR2 to a virtual address | ||
299 | * space, SW must ensure that the bind has completed prior to issuing | ||
300 | * any further BAR2 requests by polling for both | ||
301 | * BUS_BIND_STATUS_BAR2_PENDING to return to EMPTY and | ||
302 | * BUS_BIND_STATUS_BAR2_OUTSTANDING to return to FALSE | ||
303 | */ | ||
304 | nvgpu_timeout_init(g, &timeout, gk20a_get_gr_idle_timeout(g), | ||
305 | NVGPU_TIMER_CPU_TIMER); | ||
306 | nvgpu_log_info(g, "check bar2 bind status"); | ||
307 | do { | ||
308 | reg_val = gk20a_readl(g, bus_bind_status_r()); | ||
309 | |||
310 | if (!((reg_val & bus_bind_status_bar2_pending_busy_f()) || | ||
311 | (reg_val & bus_bind_status_bar2_outstanding_true_f()))) | ||
312 | return 0; | ||
313 | |||
314 | nvgpu_usleep_range(delay, delay * 2); | ||
315 | delay = min_t(u32, delay << 1, GR_IDLE_CHECK_MAX); | ||
316 | } while (!nvgpu_timeout_expired_msg(&timeout, "bar2 bind timedout")); | ||
317 | |||
318 | nvgpu_err(g, "bar2 bind failed. gpu unable to access memory"); | ||
319 | return -EBUSY; | ||
320 | } | ||
321 | |||
271 | void gv11b_init_mm(struct gpu_ops *gops) | 322 | void gv11b_init_mm(struct gpu_ops *gops) |
272 | { | 323 | { |
273 | gp10b_init_mm(gops); | 324 | gp10b_init_mm(gops); |
@@ -280,4 +331,5 @@ void gv11b_init_mm(struct gpu_ops *gops) | |||
280 | gops->mm.fault_info_mem_destroy = | 331 | gops->mm.fault_info_mem_destroy = |
281 | gv11b_mm_fault_info_mem_destroy; | 332 | gv11b_mm_fault_info_mem_destroy; |
282 | gops->mm.remove_bar2_vm = gv11b_mm_remove_bar2_vm; | 333 | gops->mm.remove_bar2_vm = gv11b_mm_remove_bar2_vm; |
334 | gops->mm.init_bar2_mm_hw_setup = gv11b_init_bar2_mm_hw_setup; | ||
283 | } | 335 | } |