Skip to content

Commit d19512f

Browse files
committed
nouveau/vmm: start tracking if the LPT PTE is valid. (v6)
When NVK enabled large pages userspace tests were seeing fault reports at a valid address. There was a case where an address moving from 64k page to 4k pages could expose a race between unmapping the 4k page, mapping the 64k page and unref the 4k pages. Unref 4k pages would cause the dual-page table handling to always set the LPTE entry to SPARSE or INVALID, but if we'd mapped a valid LPTE in the meantime, it would get trashed. Keep track of when a valid LPTE has been referenced, and don't reset in that case. This adds an lpte valid tracker and lpte reference count. Whenever an lpte is referenced, it gets made valid and the ref count increases, whenever it gets unreference the refcount is tracked. Link: https://gitlab.freedesktop.org/mesa/mesa/-/issues/14610 Reviewed-by: Mary Guillemard <[email protected]> Tested-by: Mary Guillemard <[email protected]> Tested-by: Mel Henning <[email protected]> Signed-off-by: Dave Airlie <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 9dc983a commit d19512f

3 files changed

Lines changed: 36 additions & 10 deletions

File tree

drivers/gpu/drm/nouveau/nouveau_drv.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
#define DRIVER_MAJOR 1
1212
#define DRIVER_MINOR 4
13-
#define DRIVER_PATCHLEVEL 1
13+
#define DRIVER_PATCHLEVEL 2
1414

1515
/*
1616
* 1.1.1:
@@ -37,6 +37,8 @@
3737
* - implemented limited ABI16/NVIF interop
3838
* 1.4.1:
3939
* - add variable page sizes and compression for Turing+
40+
* 1.4.2:
41+
* - tell userspace LPTE/SPTE races are fixed.
4042
*/
4143

4244
#include <linux/notifier.h>

drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,17 @@ nvkm_vmm_unref_sptes(struct nvkm_vmm_iter *it, struct nvkm_vmm_pt *pgt,
242242
if (pgt->pte[pteb].s.sparse) {
243243
TRA(it, "LPTE %05x: U -> S %d PTEs", pteb, ptes);
244244
pair->func->sparse(vmm, pgt->pt[0], pteb, ptes);
245-
} else
246-
if (pair->func->invalid) {
247-
/* If the MMU supports it, restore the LPTE to the
248-
* INVALID state to tell the MMU there is no point
249-
* trying to fetch the corresponding SPTEs.
250-
*/
251-
TRA(it, "LPTE %05x: U -> I %d PTEs", pteb, ptes);
252-
pair->func->invalid(vmm, pgt->pt[0], pteb, ptes);
245+
} else if (!pgt->pte[pteb].s.lpte_valid) {
246+
if (pair->func->invalid) {
247+
/* If the MMU supports it, restore the LPTE to the
248+
* INVALID state to tell the MMU there is no point
249+
* trying to fetch the corresponding SPTEs.
250+
*/
251+
TRA(it, "LPTE %05x: U -> I %d PTEs", pteb, ptes);
252+
pair->func->invalid(vmm, pgt->pt[0], pteb, ptes);
253+
}
254+
} else {
255+
TRA(it, "LPTE %05x: V %d PTEs", pteb, ptes);
253256
}
254257
}
255258
}
@@ -280,6 +283,15 @@ nvkm_vmm_unref_ptes(struct nvkm_vmm_iter *it, bool pfn, u32 ptei, u32 ptes)
280283
if (desc->type == SPT && (pgt->refs[0] || pgt->refs[1]))
281284
nvkm_vmm_unref_sptes(it, pgt, desc, ptei, ptes);
282285

286+
if (desc->type == LPT && (pgt->refs[0] || pgt->refs[1])) {
287+
for (u32 lpti = ptei; ptes; lpti++) {
288+
pgt->pte[lpti].s.lptes--;
289+
if (pgt->pte[lpti].s.lptes == 0)
290+
pgt->pte[lpti].s.lpte_valid = false;
291+
ptes--;
292+
}
293+
}
294+
283295
/* PT no longer needed? Destroy it. */
284296
if (!pgt->refs[type]) {
285297
it->lvl++;
@@ -332,10 +344,12 @@ nvkm_vmm_ref_sptes(struct nvkm_vmm_iter *it, struct nvkm_vmm_pt *pgt,
332344
* Determine how many LPTEs need to transition state.
333345
*/
334346
pgt->pte[ptei].s.spte_valid = true;
347+
pgt->pte[ptei].s.lpte_valid = false;
335348
for (ptes = 1, ptei++; ptei < lpti; ptes++, ptei++) {
336349
if (pgt->pte[ptei].s.spte_valid)
337350
break;
338351
pgt->pte[ptei].s.spte_valid = true;
352+
pgt->pte[ptei].s.lpte_valid = false;
339353
}
340354

341355
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)
374388
if (desc->type == SPT)
375389
nvkm_vmm_ref_sptes(it, pgt, desc, ptei, ptes);
376390

391+
if (desc->type == LPT) {
392+
for (u32 lpti = ptei; ptes; lpti++) {
393+
pgt->pte[lpti].s.spte_valid = false;
394+
pgt->pte[lpti].s.lpte_valid = true;
395+
pgt->pte[lpti].s.lptes++;
396+
ptes--;
397+
}
398+
}
399+
377400
return true;
378401
}
379402

drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ union nvkm_pte_tracker {
99
struct {
1010
u32 sparse:1;
1111
u32 spte_valid:1;
12-
u32 padding:14;
12+
u32 lpte_valid:1;
13+
u32 lptes:13;
1314
u32 sptes:16;
1415
} s;
1516
};

0 commit comments

Comments
 (0)