mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 09:12:24 +03:00
gpu: nvgpu: Fix TLB invalidate race
TLB invalidate can have a race if several contexts use the same address space. One thread starting an invalidate allows another thread to submit before invalidate is completed. Bug 1502332 Change-Id: I074ec493eac3b153c5f23d796a1dee1d8db24855 Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/407578 Reviewed-by: Riham Haidar <rhaidar@nvidia.com> Tested-by: Riham Haidar <rhaidar@nvidia.com>
This commit is contained in:
committed by
Dan Willemsen
parent
4ac110cb8a
commit
c8a5d3f908
@@ -1575,13 +1575,6 @@ static int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
|
|||||||
incr_cmd->gp_put = c->gpfifo.put;
|
incr_cmd->gp_put = c->gpfifo.put;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invalidate tlb if it's dirty... */
|
|
||||||
/* TBD: this should be done in the cmd stream, not with PRIs. */
|
|
||||||
/* We don't know what context is currently running... */
|
|
||||||
/* Note also: there can be more than one context associated with the */
|
|
||||||
/* address space (vm). */
|
|
||||||
gk20a_mm_tlb_invalidate(c->vm);
|
|
||||||
|
|
||||||
trace_gk20a_channel_submitted_gpfifo(c->g->dev->name,
|
trace_gk20a_channel_submitted_gpfifo(c->g->dev->name,
|
||||||
c->hw_chid,
|
c->hw_chid,
|
||||||
num_entries,
|
num_entries,
|
||||||
|
|||||||
@@ -298,7 +298,6 @@ int gk20a_init_mm_setup_sw(struct gk20a *g)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mm->g = g;
|
mm->g = g;
|
||||||
mutex_init(&mm->tlb_lock);
|
|
||||||
mutex_init(&mm->l2_op_lock);
|
mutex_init(&mm->l2_op_lock);
|
||||||
mm->big_page_size = gmmu_page_sizes[gmmu_page_size_big];
|
mm->big_page_size = gmmu_page_sizes[gmmu_page_size_big];
|
||||||
mm->compression_page_size = gmmu_page_sizes[gmmu_page_size_big];
|
mm->compression_page_size = gmmu_page_sizes[gmmu_page_size_big];
|
||||||
@@ -2892,11 +2891,11 @@ int gk20a_vm_find_buffer(struct vm_gk20a *vm, u64 gpu_va,
|
|||||||
|
|
||||||
void gk20a_mm_tlb_invalidate(struct vm_gk20a *vm)
|
void gk20a_mm_tlb_invalidate(struct vm_gk20a *vm)
|
||||||
{
|
{
|
||||||
struct mm_gk20a *mm = vm->mm;
|
|
||||||
struct gk20a *g = gk20a_from_vm(vm);
|
struct gk20a *g = gk20a_from_vm(vm);
|
||||||
u32 addr_lo = u64_lo32(gk20a_mm_iova_addr(vm->pdes.sgt->sgl) >> 12);
|
u32 addr_lo = u64_lo32(gk20a_mm_iova_addr(vm->pdes.sgt->sgl) >> 12);
|
||||||
u32 data;
|
u32 data;
|
||||||
s32 retry = 200;
|
s32 retry = 200;
|
||||||
|
static DEFINE_MUTEX(tlb_lock);
|
||||||
|
|
||||||
gk20a_dbg_fn("");
|
gk20a_dbg_fn("");
|
||||||
|
|
||||||
@@ -2915,10 +2914,8 @@ void gk20a_mm_tlb_invalidate(struct vm_gk20a *vm)
|
|||||||
mutex_unlock(&vm->update_gmmu_lock);
|
mutex_unlock(&vm->update_gmmu_lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vm->tlb_dirty = false;
|
|
||||||
mutex_unlock(&vm->update_gmmu_lock);
|
|
||||||
|
|
||||||
mutex_lock(&mm->tlb_lock);
|
mutex_lock(&tlb_lock);
|
||||||
do {
|
do {
|
||||||
data = gk20a_readl(g, fb_mmu_ctrl_r());
|
data = gk20a_readl(g, fb_mmu_ctrl_r());
|
||||||
if (fb_mmu_ctrl_pri_fifo_space_v(data) != 0)
|
if (fb_mmu_ctrl_pri_fifo_space_v(data) != 0)
|
||||||
@@ -2927,17 +2924,17 @@ void gk20a_mm_tlb_invalidate(struct vm_gk20a *vm)
|
|||||||
retry--;
|
retry--;
|
||||||
} while (retry >= 0 || !tegra_platform_is_silicon());
|
} while (retry >= 0 || !tegra_platform_is_silicon());
|
||||||
|
|
||||||
if (retry < 0)
|
if (retry < 0) {
|
||||||
gk20a_warn(dev_from_gk20a(g),
|
gk20a_warn(dev_from_gk20a(g),
|
||||||
"wait mmu fifo space too many retries");
|
"wait mmu fifo space too many retries");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
gk20a_writel(g, fb_mmu_invalidate_pdb_r(),
|
gk20a_writel(g, fb_mmu_invalidate_pdb_r(),
|
||||||
fb_mmu_invalidate_pdb_addr_f(addr_lo) |
|
fb_mmu_invalidate_pdb_addr_f(addr_lo) |
|
||||||
fb_mmu_invalidate_pdb_aperture_vid_mem_f());
|
fb_mmu_invalidate_pdb_aperture_vid_mem_f());
|
||||||
|
|
||||||
/* this is a sledgehammer, it would seem */
|
|
||||||
gk20a_writel(g, fb_mmu_invalidate_r(),
|
gk20a_writel(g, fb_mmu_invalidate_r(),
|
||||||
fb_mmu_invalidate_all_pdb_true_f() |
|
|
||||||
fb_mmu_invalidate_all_va_true_f() |
|
fb_mmu_invalidate_all_va_true_f() |
|
||||||
fb_mmu_invalidate_trigger_true_f());
|
fb_mmu_invalidate_trigger_true_f());
|
||||||
|
|
||||||
@@ -2954,7 +2951,10 @@ void gk20a_mm_tlb_invalidate(struct vm_gk20a *vm)
|
|||||||
gk20a_warn(dev_from_gk20a(g),
|
gk20a_warn(dev_from_gk20a(g),
|
||||||
"mmu invalidate too many retries");
|
"mmu invalidate too many retries");
|
||||||
|
|
||||||
mutex_unlock(&mm->tlb_lock);
|
out:
|
||||||
|
mutex_unlock(&tlb_lock);
|
||||||
|
vm->tlb_dirty = false;
|
||||||
|
mutex_unlock(&vm->update_gmmu_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gk20a_mm_suspend(struct gk20a *g)
|
int gk20a_mm_suspend(struct gk20a *g)
|
||||||
|
|||||||
@@ -322,7 +322,6 @@ struct mm_gk20a {
|
|||||||
struct inst_desc inst_block;
|
struct inst_desc inst_block;
|
||||||
} pmu;
|
} pmu;
|
||||||
|
|
||||||
struct mutex tlb_lock;
|
|
||||||
struct mutex l2_op_lock;
|
struct mutex l2_op_lock;
|
||||||
|
|
||||||
void (*remove_support)(struct mm_gk20a *mm);
|
void (*remove_support)(struct mm_gk20a *mm);
|
||||||
|
|||||||
Reference in New Issue
Block a user