summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2026-06-15 14:47:37 +1000
committerDave Airlie <airlied@redhat.com>2026-07-10 14:19:23 +1000
commit6763a0aea6d658d69b9215ab9151d7bd4c1c314b (patch)
tree9435a47f28856113e7cba078fb91aec961db5785
parent695255c57ff18171190cd374cd5fb7c1539e9842 (diff)
nouveau/vmm: fix another SPT/LPT racedrm-fixes-2026-07-10
We've had an unknown Turing issue for a while with page faults since large pages and compression. I've got a patch series that syncs all our L2 handling with ogkm and it made this fault happen more. After writing a bunch of debugging patches, I spotted an invalid LPT entry where there should have been a valid one. A 64K MAP succeeds on a range, but a subsequent SPT put drops SPT refs across multiple ranges, We shouldn't assume all ranges where SPTEs go away will have the same sparse/invalid/valid state, just iterate over each instead and do the right thing. Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie <airlied@redhat.com> Fixes: d19512f5abb1 ("nouveau/vmm: start tracking if the LPT PTE is valid. (v6)") Link: https://patch.msgid.link/20260615044737.3419585-1-airlied@gmail.com [ Properly format commit message. - Danilo ] Signed-off-by: Danilo Krummrich <dakr@kernel.org> (cherry picked from commit d008141ed4ce924167a03d46fbce9ad1fe4efa29) Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c31
1 files changed, 14 insertions, 17 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
index 107bdb642f22..190c082b12c8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
@@ -231,29 +231,26 @@ nvkm_vmm_unref_sptes(struct nvkm_vmm_iter *it, struct nvkm_vmm_pt *pgt,
* covered by a number of LPTEs, the LPTEs once again take
* control over their address range.
*
- * Determine how many LPTEs need to transition state.
+ * Transition each LPTE individually as each may have a
+ * different target state (sparse, invalid, or valid).
*/
- pgt->pte[ptei].s.spte_valid = false;
- for (ptes = 1, ptei++; ptei < lpti; ptes++, ptei++) {
+ for (ptei++; ptei < lpti; ptei++) {
if (pgt->pte[ptei].s.sptes)
break;
- pgt->pte[ptei].s.spte_valid = false;
}
- 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 (!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);
+ while (pteb < ptei) {
+ pgt->pte[pteb].s.spte_valid = false;
+ if (pgt->pte[pteb].s.sparse) {
+ TRA(it, "LPTE %05x: U -> S", pteb);
+ pair->func->sparse(vmm, pgt->pt[0], pteb, 1);
+ } else if (!pgt->pte[pteb].s.lpte_valid) {
+ if (pair->func->invalid) {
+ TRA(it, "LPTE %05x: U -> I", pteb);
+ pair->func->invalid(vmm, pgt->pt[0], pteb, 1);
+ }
}
- } else {
- TRA(it, "LPTE %05x: V %d PTEs", pteb, ptes);
+ pteb++;
}
}
}