diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 0e409414f44d..1c2523e2f92e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -10,7 +10,7 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 4 -#define DRIVER_PATCHLEVEL 1 +#define DRIVER_PATCHLEVEL 2 /* * 1.1.1: @@ -37,6 +37,8 @@ * - implemented limited ABI16/NVIF interop * 1.4.1: * - add variable page sizes and compression for Turing+ + * 1.4.2: + * - tell userspace LPTE/SPTE races are fixed. */ #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c index 44daeec0aa6d..19a7407cf702 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c @@ -242,14 +242,17 @@ nvkm_vmm_unref_sptes(struct nvkm_vmm_iter *it, struct nvkm_vmm_pt *pgt, if (pgt->pte[pteb].s.sparse) { TRA(it, "LPTE %05x: U -> S %d PTEs", pteb, ptes); pair->func->sparse(vmm, pgt->pt[0], pteb, ptes); - } else - if (pair->func->invalid) { - /* If the MMU supports it, restore the LPTE to the - * INVALID state to tell the MMU there is no point - * trying to fetch the corresponding SPTEs. - */ - TRA(it, "LPTE %05x: U -> I %d PTEs", pteb, ptes); - pair->func->invalid(vmm, pgt->pt[0], pteb, ptes); + } else if (!pgt->pte[pteb].s.lpte_valid) { + if (pair->func->invalid) { + /* If the MMU supports it, restore the LPTE to the + * INVALID state to tell the MMU there is no point + * trying to fetch the corresponding SPTEs. + */ + TRA(it, "LPTE %05x: U -> I %d PTEs", pteb, ptes); + pair->func->invalid(vmm, pgt->pt[0], pteb, ptes); + } + } else { + TRA(it, "LPTE %05x: V %d PTEs", pteb, ptes); } } } @@ -280,6 +283,15 @@ nvkm_vmm_unref_ptes(struct nvkm_vmm_iter *it, bool pfn, u32 ptei, u32 ptes) if (desc->type == SPT && (pgt->refs[0] || pgt->refs[1])) nvkm_vmm_unref_sptes(it, pgt, desc, ptei, ptes); + if (desc->type == LPT && (pgt->refs[0] || pgt->refs[1])) { + for (u32 lpti = ptei; ptes; lpti++) { + pgt->pte[lpti].s.lptes--; + if (pgt->pte[lpti].s.lptes == 0) + pgt->pte[lpti].s.lpte_valid = false; + ptes--; + } + } + /* PT no longer needed? Destroy it. */ if (!pgt->refs[type]) { it->lvl++; @@ -332,10 +344,12 @@ nvkm_vmm_ref_sptes(struct nvkm_vmm_iter *it, struct nvkm_vmm_pt *pgt, * Determine how many LPTEs need to transition state. */ pgt->pte[ptei].s.spte_valid = true; + pgt->pte[ptei].s.lpte_valid = false; for (ptes = 1, ptei++; ptei < lpti; ptes++, ptei++) { if (pgt->pte[ptei].s.spte_valid) break; pgt->pte[ptei].s.spte_valid = true; + pgt->pte[ptei].s.lpte_valid = false; } if (pgt->pte[pteb].s.sparse) { @@ -374,6 +388,15 @@ nvkm_vmm_ref_ptes(struct nvkm_vmm_iter *it, bool pfn, u32 ptei, u32 ptes) if (desc->type == SPT) nvkm_vmm_ref_sptes(it, pgt, desc, ptei, ptes); + if (desc->type == LPT) { + for (u32 lpti = ptei; ptes; lpti++) { + pgt->pte[lpti].s.spte_valid = false; + pgt->pte[lpti].s.lpte_valid = true; + pgt->pte[lpti].s.lptes++; + ptes--; + } + } + return true; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h index a8b08126e8dc..4ec0a3a21169 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h @@ -9,7 +9,8 @@ union nvkm_pte_tracker { struct { u32 sparse:1; u32 spte_valid:1; - u32 padding:14; + u32 lpte_valid:1; + u32 lptes:13; u32 sptes:16; } s; };