xref: /openbmc/linux/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
18e39abffSBen Skeggs /*
28e39abffSBen Skeggs  * Copyright 2017 Red Hat Inc.
38e39abffSBen Skeggs  *
48e39abffSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
58e39abffSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
68e39abffSBen Skeggs  * to deal in the Software without restriction, including without limitation
78e39abffSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88e39abffSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
98e39abffSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
108e39abffSBen Skeggs  *
118e39abffSBen Skeggs  * The above copyright notice and this permission notice shall be included in
128e39abffSBen Skeggs  * all copies or substantial portions of the Software.
138e39abffSBen Skeggs  *
148e39abffSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
158e39abffSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
168e39abffSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
178e39abffSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
188e39abffSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
198e39abffSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
208e39abffSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
218e39abffSBen Skeggs  */
228e39abffSBen Skeggs #include "vmm.h"
238e39abffSBen Skeggs 
2471871aa6SBen Skeggs #include <core/client.h>
25f9400afbSBen Skeggs #include <subdev/fb.h>
26f9400afbSBen Skeggs #include <subdev/ltc.h>
2771871aa6SBen Skeggs #include <subdev/timer.h>
2871871aa6SBen Skeggs #include <engine/gr.h>
29f9400afbSBen Skeggs 
30f9400afbSBen Skeggs #include <nvif/ifc00d.h>
31f9400afbSBen Skeggs #include <nvif/unpack.h>
32f9400afbSBen Skeggs 
33a5ff307fSBen Skeggs static void
gp100_vmm_pfn_unmap(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes)34a5ff307fSBen Skeggs gp100_vmm_pfn_unmap(struct nvkm_vmm *vmm,
35a5ff307fSBen Skeggs 		    struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes)
36a5ff307fSBen Skeggs {
37a5ff307fSBen Skeggs 	struct device *dev = vmm->mmu->subdev.device->dev;
38a5ff307fSBen Skeggs 	dma_addr_t addr;
39a5ff307fSBen Skeggs 
40a5ff307fSBen Skeggs 	nvkm_kmap(pt->memory);
41a5ff307fSBen Skeggs 	while (ptes--) {
42a5ff307fSBen Skeggs 		u32 datalo = nvkm_ro32(pt->memory, pt->base + ptei * 8 + 0);
43a5ff307fSBen Skeggs 		u32 datahi = nvkm_ro32(pt->memory, pt->base + ptei * 8 + 4);
44a5ff307fSBen Skeggs 		u64 data   = (u64)datahi << 32 | datalo;
45a5ff307fSBen Skeggs 		if ((data & (3ULL << 1)) != 0) {
46a5ff307fSBen Skeggs 			addr = (data >> 8) << 12;
47a5ff307fSBen Skeggs 			dma_unmap_page(dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
48a5ff307fSBen Skeggs 		}
49a5ff307fSBen Skeggs 		ptei++;
50a5ff307fSBen Skeggs 	}
51a5ff307fSBen Skeggs 	nvkm_done(pt->memory);
52a5ff307fSBen Skeggs }
53a5ff307fSBen Skeggs 
54a5ff307fSBen Skeggs static bool
gp100_vmm_pfn_clear(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes)55a5ff307fSBen Skeggs gp100_vmm_pfn_clear(struct nvkm_vmm *vmm,
56a5ff307fSBen Skeggs 		    struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes)
57a5ff307fSBen Skeggs {
58a5ff307fSBen Skeggs 	bool dma = false;
59a5ff307fSBen Skeggs 	nvkm_kmap(pt->memory);
60a5ff307fSBen Skeggs 	while (ptes--) {
61a5ff307fSBen Skeggs 		u32 datalo = nvkm_ro32(pt->memory, pt->base + ptei * 8 + 0);
62a5ff307fSBen Skeggs 		u32 datahi = nvkm_ro32(pt->memory, pt->base + ptei * 8 + 4);
63a5ff307fSBen Skeggs 		u64 data   = (u64)datahi << 32 | datalo;
64a5ff307fSBen Skeggs 		if ((data & BIT_ULL(0)) && (data & (3ULL << 1)) != 0) {
65a5ff307fSBen Skeggs 			VMM_WO064(pt, vmm, ptei * 8, data & ~BIT_ULL(0));
66a5ff307fSBen Skeggs 			dma = true;
67a5ff307fSBen Skeggs 		}
68a5ff307fSBen Skeggs 		ptei++;
69a5ff307fSBen Skeggs 	}
70a5ff307fSBen Skeggs 	nvkm_done(pt->memory);
71a5ff307fSBen Skeggs 	return dma;
72a5ff307fSBen Skeggs }
73a5ff307fSBen Skeggs 
74a5ff307fSBen Skeggs static void
gp100_vmm_pgt_pfn(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes,struct nvkm_vmm_map * map)75a5ff307fSBen Skeggs gp100_vmm_pgt_pfn(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
76a5ff307fSBen Skeggs 		  u32 ptei, u32 ptes, struct nvkm_vmm_map *map)
77a5ff307fSBen Skeggs {
78a5ff307fSBen Skeggs 	struct device *dev = vmm->mmu->subdev.device->dev;
79a5ff307fSBen Skeggs 	dma_addr_t addr;
80a5ff307fSBen Skeggs 
81a5ff307fSBen Skeggs 	nvkm_kmap(pt->memory);
821a77decdSRalph Campbell 	for (; ptes; ptes--, map->pfn++) {
83a5ff307fSBen Skeggs 		u64 data = 0;
841a77decdSRalph Campbell 
851a77decdSRalph Campbell 		if (!(*map->pfn & NVKM_VMM_PFN_V))
861a77decdSRalph Campbell 			continue;
871a77decdSRalph Campbell 
88a5ff307fSBen Skeggs 		if (!(*map->pfn & NVKM_VMM_PFN_W))
89a5ff307fSBen Skeggs 			data |= BIT_ULL(6); /* RO. */
90a5ff307fSBen Skeggs 
918f187163SAlistair Popple 		if (!(*map->pfn & NVKM_VMM_PFN_A))
928f187163SAlistair Popple 			data |= BIT_ULL(7); /* Atomic disable. */
938f187163SAlistair Popple 
94a5ff307fSBen Skeggs 		if (!(*map->pfn & NVKM_VMM_PFN_VRAM)) {
95a5ff307fSBen Skeggs 			addr = *map->pfn >> NVKM_VMM_PFN_ADDR_SHIFT;
96a5ff307fSBen Skeggs 			addr = dma_map_page(dev, pfn_to_page(addr), 0,
97a5ff307fSBen Skeggs 					    PAGE_SIZE, DMA_BIDIRECTIONAL);
98a5ff307fSBen Skeggs 			if (!WARN_ON(dma_mapping_error(dev, addr))) {
99a5ff307fSBen Skeggs 				data |= addr >> 4;
100a5ff307fSBen Skeggs 				data |= 2ULL << 1; /* SYSTEM_COHERENT_MEMORY. */
101a5ff307fSBen Skeggs 				data |= BIT_ULL(3); /* VOL. */
102a5ff307fSBen Skeggs 				data |= BIT_ULL(0); /* VALID. */
103a5ff307fSBen Skeggs 			}
104a5ff307fSBen Skeggs 		} else {
105a5ff307fSBen Skeggs 			data |= (*map->pfn & NVKM_VMM_PFN_ADDR) >> 4;
106a5ff307fSBen Skeggs 			data |= BIT_ULL(0); /* VALID. */
107a5ff307fSBen Skeggs 		}
108a5ff307fSBen Skeggs 
109a5ff307fSBen Skeggs 		VMM_WO064(pt, vmm, ptei++ * 8, data);
110a5ff307fSBen Skeggs 	}
111a5ff307fSBen Skeggs 	nvkm_done(pt->memory);
112a5ff307fSBen Skeggs }
113a5ff307fSBen Skeggs 
114f9400afbSBen Skeggs static inline void
gp100_vmm_pgt_pte(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes,struct nvkm_vmm_map * map,u64 addr)115f9400afbSBen Skeggs gp100_vmm_pgt_pte(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
116f9400afbSBen Skeggs 		  u32 ptei, u32 ptes, struct nvkm_vmm_map *map, u64 addr)
117f9400afbSBen Skeggs {
118f9400afbSBen Skeggs 	u64 data = (addr >> 4) | map->type;
119f9400afbSBen Skeggs 
120f9400afbSBen Skeggs 	map->type += ptes * map->ctag;
121f9400afbSBen Skeggs 
122f9400afbSBen Skeggs 	while (ptes--) {
123f9400afbSBen Skeggs 		VMM_WO064(pt, vmm, ptei++ * 8, data);
124f9400afbSBen Skeggs 		data += map->next;
125f9400afbSBen Skeggs 	}
126f9400afbSBen Skeggs }
127f9400afbSBen Skeggs 
128f9400afbSBen Skeggs static void
gp100_vmm_pgt_sgl(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes,struct nvkm_vmm_map * map)129f9400afbSBen Skeggs gp100_vmm_pgt_sgl(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
130f9400afbSBen Skeggs 		  u32 ptei, u32 ptes, struct nvkm_vmm_map *map)
131f9400afbSBen Skeggs {
132f9400afbSBen Skeggs 	VMM_MAP_ITER_SGL(vmm, pt, ptei, ptes, map, gp100_vmm_pgt_pte);
133f9400afbSBen Skeggs }
134f9400afbSBen Skeggs 
135f9400afbSBen Skeggs static void
gp100_vmm_pgt_dma(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes,struct nvkm_vmm_map * map)136f9400afbSBen Skeggs gp100_vmm_pgt_dma(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
137f9400afbSBen Skeggs 		  u32 ptei, u32 ptes, struct nvkm_vmm_map *map)
138f9400afbSBen Skeggs {
139f9400afbSBen Skeggs 	if (map->page->shift == PAGE_SHIFT) {
140f9400afbSBen Skeggs 		VMM_SPAM(vmm, "DMAA %08x %08x PTE(s)", ptei, ptes);
141f9400afbSBen Skeggs 		nvkm_kmap(pt->memory);
142f9400afbSBen Skeggs 		while (ptes--) {
143f9400afbSBen Skeggs 			const u64 data = (*map->dma++ >> 4) | map->type;
144f9400afbSBen Skeggs 			VMM_WO064(pt, vmm, ptei++ * 8, data);
145f9400afbSBen Skeggs 			map->type += map->ctag;
146f9400afbSBen Skeggs 		}
147f9400afbSBen Skeggs 		nvkm_done(pt->memory);
148f9400afbSBen Skeggs 		return;
149f9400afbSBen Skeggs 	}
150f9400afbSBen Skeggs 
151f9400afbSBen Skeggs 	VMM_MAP_ITER_DMA(vmm, pt, ptei, ptes, map, gp100_vmm_pgt_pte);
152f9400afbSBen Skeggs }
153f9400afbSBen Skeggs 
154f9400afbSBen Skeggs static void
gp100_vmm_pgt_mem(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes,struct nvkm_vmm_map * map)155f9400afbSBen Skeggs gp100_vmm_pgt_mem(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
156f9400afbSBen Skeggs 		  u32 ptei, u32 ptes, struct nvkm_vmm_map *map)
157f9400afbSBen Skeggs {
158f9400afbSBen Skeggs 	VMM_MAP_ITER_MEM(vmm, pt, ptei, ptes, map, gp100_vmm_pgt_pte);
159f9400afbSBen Skeggs }
160f9400afbSBen Skeggs 
161f9400afbSBen Skeggs static void
gp100_vmm_pgt_sparse(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes)162f9400afbSBen Skeggs gp100_vmm_pgt_sparse(struct nvkm_vmm *vmm,
163f9400afbSBen Skeggs 		     struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes)
164f9400afbSBen Skeggs {
165f9400afbSBen Skeggs 	/* VALID_FALSE + VOL tells the MMU to treat the PTE as sparse. */
166f9400afbSBen Skeggs 	VMM_FO064(pt, vmm, ptei * 8, BIT_ULL(3) /* VOL. */, ptes);
167f9400afbSBen Skeggs }
168f9400afbSBen Skeggs 
1698e39abffSBen Skeggs static const struct nvkm_vmm_desc_func
1708e39abffSBen Skeggs gp100_vmm_desc_spt = {
171f9400afbSBen Skeggs 	.unmap = gf100_vmm_pgt_unmap,
172f9400afbSBen Skeggs 	.sparse = gp100_vmm_pgt_sparse,
173f9400afbSBen Skeggs 	.mem = gp100_vmm_pgt_mem,
174f9400afbSBen Skeggs 	.dma = gp100_vmm_pgt_dma,
175f9400afbSBen Skeggs 	.sgl = gp100_vmm_pgt_sgl,
176a5ff307fSBen Skeggs 	.pfn = gp100_vmm_pgt_pfn,
177a5ff307fSBen Skeggs 	.pfn_clear = gp100_vmm_pfn_clear,
178a5ff307fSBen Skeggs 	.pfn_unmap = gp100_vmm_pfn_unmap,
1798e39abffSBen Skeggs };
1808e39abffSBen Skeggs 
181f9400afbSBen Skeggs static void
gp100_vmm_lpt_invalid(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes)182f9400afbSBen Skeggs gp100_vmm_lpt_invalid(struct nvkm_vmm *vmm,
183f9400afbSBen Skeggs 		      struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes)
184f9400afbSBen Skeggs {
185f9400afbSBen Skeggs 	/* VALID_FALSE + PRIV tells the MMU to ignore corresponding SPTEs. */
186f9400afbSBen Skeggs 	VMM_FO064(pt, vmm, ptei * 8, BIT_ULL(5) /* PRIV. */, ptes);
187f9400afbSBen Skeggs }
188f9400afbSBen Skeggs 
1898e39abffSBen Skeggs static const struct nvkm_vmm_desc_func
1908e39abffSBen Skeggs gp100_vmm_desc_lpt = {
191f9400afbSBen Skeggs 	.invalid = gp100_vmm_lpt_invalid,
192f9400afbSBen Skeggs 	.unmap = gf100_vmm_pgt_unmap,
193f9400afbSBen Skeggs 	.sparse = gp100_vmm_pgt_sparse,
194f9400afbSBen Skeggs 	.mem = gp100_vmm_pgt_mem,
1958e39abffSBen Skeggs };
1968e39abffSBen Skeggs 
197f9400afbSBen Skeggs static inline void
gp100_vmm_pd0_pte(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes,struct nvkm_vmm_map * map,u64 addr)198f9400afbSBen Skeggs gp100_vmm_pd0_pte(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
199f9400afbSBen Skeggs 		  u32 ptei, u32 ptes, struct nvkm_vmm_map *map, u64 addr)
200f9400afbSBen Skeggs {
201f9400afbSBen Skeggs 	u64 data = (addr >> 4) | map->type;
202f9400afbSBen Skeggs 
203f9400afbSBen Skeggs 	map->type += ptes * map->ctag;
204f9400afbSBen Skeggs 
205f9400afbSBen Skeggs 	while (ptes--) {
206f9400afbSBen Skeggs 		VMM_WO128(pt, vmm, ptei++ * 0x10, data, 0ULL);
207f9400afbSBen Skeggs 		data += map->next;
208f9400afbSBen Skeggs 	}
209f9400afbSBen Skeggs }
210f9400afbSBen Skeggs 
211f9400afbSBen Skeggs static void
gp100_vmm_pd0_mem(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes,struct nvkm_vmm_map * map)212f9400afbSBen Skeggs gp100_vmm_pd0_mem(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
213f9400afbSBen Skeggs 		  u32 ptei, u32 ptes, struct nvkm_vmm_map *map)
214f9400afbSBen Skeggs {
215f9400afbSBen Skeggs 	VMM_MAP_ITER_MEM(vmm, pt, ptei, ptes, map, gp100_vmm_pd0_pte);
216f9400afbSBen Skeggs }
217f9400afbSBen Skeggs 
218f9400afbSBen Skeggs static inline bool
gp100_vmm_pde(struct nvkm_mmu_pt * pt,u64 * data)219f9400afbSBen Skeggs gp100_vmm_pde(struct nvkm_mmu_pt *pt, u64 *data)
220f9400afbSBen Skeggs {
221f9400afbSBen Skeggs 	switch (nvkm_memory_target(pt->memory)) {
222f9400afbSBen Skeggs 	case NVKM_MEM_TARGET_VRAM: *data |= 1ULL << 1; break;
223f9400afbSBen Skeggs 	case NVKM_MEM_TARGET_HOST: *data |= 2ULL << 1;
224f9400afbSBen Skeggs 		*data |= BIT_ULL(3); /* VOL. */
225f9400afbSBen Skeggs 		break;
226f9400afbSBen Skeggs 	case NVKM_MEM_TARGET_NCOH: *data |= 3ULL << 1; break;
227f9400afbSBen Skeggs 	default:
228f9400afbSBen Skeggs 		WARN_ON(1);
229f9400afbSBen Skeggs 		return false;
230f9400afbSBen Skeggs 	}
231f9400afbSBen Skeggs 	*data |= pt->addr >> 4;
232f9400afbSBen Skeggs 	return true;
233f9400afbSBen Skeggs }
234f9400afbSBen Skeggs 
235f9400afbSBen Skeggs static void
gp100_vmm_pd0_pde(struct nvkm_vmm * vmm,struct nvkm_vmm_pt * pgd,u32 pdei)236f9400afbSBen Skeggs gp100_vmm_pd0_pde(struct nvkm_vmm *vmm, struct nvkm_vmm_pt *pgd, u32 pdei)
237f9400afbSBen Skeggs {
238f9400afbSBen Skeggs 	struct nvkm_vmm_pt *pgt = pgd->pde[pdei];
239f9400afbSBen Skeggs 	struct nvkm_mmu_pt *pd = pgd->pt[0];
240f9400afbSBen Skeggs 	u64 data[2] = {};
241f9400afbSBen Skeggs 
242f9400afbSBen Skeggs 	if (pgt->pt[0] && !gp100_vmm_pde(pgt->pt[0], &data[0]))
243f9400afbSBen Skeggs 		return;
244f9400afbSBen Skeggs 	if (pgt->pt[1] && !gp100_vmm_pde(pgt->pt[1], &data[1]))
245f9400afbSBen Skeggs 		return;
246f9400afbSBen Skeggs 
247f9400afbSBen Skeggs 	nvkm_kmap(pd->memory);
248f9400afbSBen Skeggs 	VMM_WO128(pd, vmm, pdei * 0x10, data[0], data[1]);
249f9400afbSBen Skeggs 	nvkm_done(pd->memory);
250f9400afbSBen Skeggs }
251f9400afbSBen Skeggs 
252f9400afbSBen Skeggs static void
gp100_vmm_pd0_sparse(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 pdei,u32 pdes)253f9400afbSBen Skeggs gp100_vmm_pd0_sparse(struct nvkm_vmm *vmm,
254f9400afbSBen Skeggs 		     struct nvkm_mmu_pt *pt, u32 pdei, u32 pdes)
255f9400afbSBen Skeggs {
256f9400afbSBen Skeggs 	/* VALID_FALSE + VOL_BIG tells the MMU to treat the PDE as sparse. */
257f9400afbSBen Skeggs 	VMM_FO128(pt, vmm, pdei * 0x10, BIT_ULL(3) /* VOL_BIG. */, 0ULL, pdes);
258f9400afbSBen Skeggs }
259f9400afbSBen Skeggs 
260f9400afbSBen Skeggs static void
gp100_vmm_pd0_unmap(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 pdei,u32 pdes)261f9400afbSBen Skeggs gp100_vmm_pd0_unmap(struct nvkm_vmm *vmm,
262f9400afbSBen Skeggs 		    struct nvkm_mmu_pt *pt, u32 pdei, u32 pdes)
263f9400afbSBen Skeggs {
264f9400afbSBen Skeggs 	VMM_FO128(pt, vmm, pdei * 0x10, 0ULL, 0ULL, pdes);
265f9400afbSBen Skeggs }
266f9400afbSBen Skeggs 
2674725c6b8SRalph Campbell static void
gp100_vmm_pd0_pfn_unmap(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes)2684725c6b8SRalph Campbell gp100_vmm_pd0_pfn_unmap(struct nvkm_vmm *vmm,
2694725c6b8SRalph Campbell 			struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes)
2704725c6b8SRalph Campbell {
2714725c6b8SRalph Campbell 	struct device *dev = vmm->mmu->subdev.device->dev;
2724725c6b8SRalph Campbell 	dma_addr_t addr;
2734725c6b8SRalph Campbell 
2744725c6b8SRalph Campbell 	nvkm_kmap(pt->memory);
2754725c6b8SRalph Campbell 	while (ptes--) {
2764725c6b8SRalph Campbell 		u32 datalo = nvkm_ro32(pt->memory, pt->base + ptei * 16 + 0);
2774725c6b8SRalph Campbell 		u32 datahi = nvkm_ro32(pt->memory, pt->base + ptei * 16 + 4);
2784725c6b8SRalph Campbell 		u64 data   = (u64)datahi << 32 | datalo;
2794725c6b8SRalph Campbell 
2804725c6b8SRalph Campbell 		if ((data & (3ULL << 1)) != 0) {
2814725c6b8SRalph Campbell 			addr = (data >> 8) << 12;
2824725c6b8SRalph Campbell 			dma_unmap_page(dev, addr, 1UL << 21, DMA_BIDIRECTIONAL);
2834725c6b8SRalph Campbell 		}
2844725c6b8SRalph Campbell 		ptei++;
2854725c6b8SRalph Campbell 	}
2864725c6b8SRalph Campbell 	nvkm_done(pt->memory);
2874725c6b8SRalph Campbell }
2884725c6b8SRalph Campbell 
2894725c6b8SRalph Campbell static bool
gp100_vmm_pd0_pfn_clear(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes)2904725c6b8SRalph Campbell gp100_vmm_pd0_pfn_clear(struct nvkm_vmm *vmm,
2914725c6b8SRalph Campbell 			struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes)
2924725c6b8SRalph Campbell {
2934725c6b8SRalph Campbell 	bool dma = false;
2944725c6b8SRalph Campbell 
2954725c6b8SRalph Campbell 	nvkm_kmap(pt->memory);
2964725c6b8SRalph Campbell 	while (ptes--) {
2974725c6b8SRalph Campbell 		u32 datalo = nvkm_ro32(pt->memory, pt->base + ptei * 16 + 0);
2984725c6b8SRalph Campbell 		u32 datahi = nvkm_ro32(pt->memory, pt->base + ptei * 16 + 4);
2994725c6b8SRalph Campbell 		u64 data   = (u64)datahi << 32 | datalo;
3004725c6b8SRalph Campbell 
3014725c6b8SRalph Campbell 		if ((data & BIT_ULL(0)) && (data & (3ULL << 1)) != 0) {
3024725c6b8SRalph Campbell 			VMM_WO064(pt, vmm, ptei * 16, data & ~BIT_ULL(0));
3034725c6b8SRalph Campbell 			dma = true;
3044725c6b8SRalph Campbell 		}
3054725c6b8SRalph Campbell 		ptei++;
3064725c6b8SRalph Campbell 	}
3074725c6b8SRalph Campbell 	nvkm_done(pt->memory);
3084725c6b8SRalph Campbell 	return dma;
3094725c6b8SRalph Campbell }
3104725c6b8SRalph Campbell 
3114725c6b8SRalph Campbell static void
gp100_vmm_pd0_pfn(struct nvkm_vmm * vmm,struct nvkm_mmu_pt * pt,u32 ptei,u32 ptes,struct nvkm_vmm_map * map)3124725c6b8SRalph Campbell gp100_vmm_pd0_pfn(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
3134725c6b8SRalph Campbell 		  u32 ptei, u32 ptes, struct nvkm_vmm_map *map)
3144725c6b8SRalph Campbell {
3154725c6b8SRalph Campbell 	struct device *dev = vmm->mmu->subdev.device->dev;
3164725c6b8SRalph Campbell 	dma_addr_t addr;
3174725c6b8SRalph Campbell 
3184725c6b8SRalph Campbell 	nvkm_kmap(pt->memory);
3191a77decdSRalph Campbell 	for (; ptes; ptes--, map->pfn++) {
3204725c6b8SRalph Campbell 		u64 data = 0;
3214725c6b8SRalph Campbell 
3221a77decdSRalph Campbell 		if (!(*map->pfn & NVKM_VMM_PFN_V))
3231a77decdSRalph Campbell 			continue;
3241a77decdSRalph Campbell 
3254725c6b8SRalph Campbell 		if (!(*map->pfn & NVKM_VMM_PFN_W))
3264725c6b8SRalph Campbell 			data |= BIT_ULL(6); /* RO. */
3274725c6b8SRalph Campbell 
3288f187163SAlistair Popple 		if (!(*map->pfn & NVKM_VMM_PFN_A))
3298f187163SAlistair Popple 			data |= BIT_ULL(7); /* Atomic disable. */
3308f187163SAlistair Popple 
3314725c6b8SRalph Campbell 		if (!(*map->pfn & NVKM_VMM_PFN_VRAM)) {
3324725c6b8SRalph Campbell 			addr = *map->pfn >> NVKM_VMM_PFN_ADDR_SHIFT;
3334725c6b8SRalph Campbell 			addr = dma_map_page(dev, pfn_to_page(addr), 0,
3344725c6b8SRalph Campbell 					    1UL << 21, DMA_BIDIRECTIONAL);
3354725c6b8SRalph Campbell 			if (!WARN_ON(dma_mapping_error(dev, addr))) {
3364725c6b8SRalph Campbell 				data |= addr >> 4;
3374725c6b8SRalph Campbell 				data |= 2ULL << 1; /* SYSTEM_COHERENT_MEMORY. */
3384725c6b8SRalph Campbell 				data |= BIT_ULL(3); /* VOL. */
3394725c6b8SRalph Campbell 				data |= BIT_ULL(0); /* VALID. */
3404725c6b8SRalph Campbell 			}
3414725c6b8SRalph Campbell 		} else {
3424725c6b8SRalph Campbell 			data |= (*map->pfn & NVKM_VMM_PFN_ADDR) >> 4;
3434725c6b8SRalph Campbell 			data |= BIT_ULL(0); /* VALID. */
3444725c6b8SRalph Campbell 		}
3454725c6b8SRalph Campbell 
3464725c6b8SRalph Campbell 		VMM_WO064(pt, vmm, ptei++ * 16, data);
3474725c6b8SRalph Campbell 	}
3484725c6b8SRalph Campbell 	nvkm_done(pt->memory);
3494725c6b8SRalph Campbell }
3504725c6b8SRalph Campbell 
3518e39abffSBen Skeggs static const struct nvkm_vmm_desc_func
3528e39abffSBen Skeggs gp100_vmm_desc_pd0 = {
353f9400afbSBen Skeggs 	.unmap = gp100_vmm_pd0_unmap,
354f9400afbSBen Skeggs 	.sparse = gp100_vmm_pd0_sparse,
355f9400afbSBen Skeggs 	.pde = gp100_vmm_pd0_pde,
356f9400afbSBen Skeggs 	.mem = gp100_vmm_pd0_mem,
3574725c6b8SRalph Campbell 	.pfn = gp100_vmm_pd0_pfn,
3584725c6b8SRalph Campbell 	.pfn_clear = gp100_vmm_pd0_pfn_clear,
3594725c6b8SRalph Campbell 	.pfn_unmap = gp100_vmm_pd0_pfn_unmap,
3608e39abffSBen Skeggs };
3618e39abffSBen Skeggs 
362f9400afbSBen Skeggs static void
gp100_vmm_pd1_pde(struct nvkm_vmm * vmm,struct nvkm_vmm_pt * pgd,u32 pdei)363f9400afbSBen Skeggs gp100_vmm_pd1_pde(struct nvkm_vmm *vmm, struct nvkm_vmm_pt *pgd, u32 pdei)
364f9400afbSBen Skeggs {
365f9400afbSBen Skeggs 	struct nvkm_vmm_pt *pgt = pgd->pde[pdei];
366f9400afbSBen Skeggs 	struct nvkm_mmu_pt *pd = pgd->pt[0];
367f9400afbSBen Skeggs 	u64 data = 0;
368f9400afbSBen Skeggs 
369f9400afbSBen Skeggs 	if (!gp100_vmm_pde(pgt->pt[0], &data))
370f9400afbSBen Skeggs 		return;
371f9400afbSBen Skeggs 
372f9400afbSBen Skeggs 	nvkm_kmap(pd->memory);
373f9400afbSBen Skeggs 	VMM_WO064(pd, vmm, pdei * 8, data);
374f9400afbSBen Skeggs 	nvkm_done(pd->memory);
375f9400afbSBen Skeggs }
376f9400afbSBen Skeggs 
3778e39abffSBen Skeggs static const struct nvkm_vmm_desc_func
3788e39abffSBen Skeggs gp100_vmm_desc_pd1 = {
379f9400afbSBen Skeggs 	.unmap = gf100_vmm_pgt_unmap,
380f9400afbSBen Skeggs 	.sparse = gp100_vmm_pgt_sparse,
381f9400afbSBen Skeggs 	.pde = gp100_vmm_pd1_pde,
3828e39abffSBen Skeggs };
3838e39abffSBen Skeggs 
3848e39abffSBen Skeggs const struct nvkm_vmm_desc
3858e39abffSBen Skeggs gp100_vmm_desc_16[] = {
3868e39abffSBen Skeggs 	{ LPT, 5,  8, 0x0100, &gp100_vmm_desc_lpt },
3878e39abffSBen Skeggs 	{ PGD, 8, 16, 0x1000, &gp100_vmm_desc_pd0 },
3888e39abffSBen Skeggs 	{ PGD, 9,  8, 0x1000, &gp100_vmm_desc_pd1 },
3898e39abffSBen Skeggs 	{ PGD, 9,  8, 0x1000, &gp100_vmm_desc_pd1 },
3908e39abffSBen Skeggs 	{ PGD, 2,  8, 0x1000, &gp100_vmm_desc_pd1 },
3918e39abffSBen Skeggs 	{}
3928e39abffSBen Skeggs };
3938e39abffSBen Skeggs 
3948e39abffSBen Skeggs const struct nvkm_vmm_desc
3958e39abffSBen Skeggs gp100_vmm_desc_12[] = {
3968e39abffSBen Skeggs 	{ SPT, 9,  8, 0x1000, &gp100_vmm_desc_spt },
3978e39abffSBen Skeggs 	{ PGD, 8, 16, 0x1000, &gp100_vmm_desc_pd0 },
3988e39abffSBen Skeggs 	{ PGD, 9,  8, 0x1000, &gp100_vmm_desc_pd1 },
3998e39abffSBen Skeggs 	{ PGD, 9,  8, 0x1000, &gp100_vmm_desc_pd1 },
4008e39abffSBen Skeggs 	{ PGD, 2,  8, 0x1000, &gp100_vmm_desc_pd1 },
4018e39abffSBen Skeggs 	{}
4028e39abffSBen Skeggs };
4038e39abffSBen Skeggs 
4048e39abffSBen Skeggs int
gp100_vmm_valid(struct nvkm_vmm * vmm,void * argv,u32 argc,struct nvkm_vmm_map * map)405f9400afbSBen Skeggs gp100_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
406f9400afbSBen Skeggs 		struct nvkm_vmm_map *map)
407f9400afbSBen Skeggs {
408f9400afbSBen Skeggs 	const enum nvkm_memory_target target = nvkm_memory_target(map->memory);
409f9400afbSBen Skeggs 	const struct nvkm_vmm_page *page = map->page;
410f9400afbSBen Skeggs 	union {
411f9400afbSBen Skeggs 		struct gp100_vmm_map_vn vn;
412f9400afbSBen Skeggs 		struct gp100_vmm_map_v0 v0;
413f9400afbSBen Skeggs 	} *args = argv;
414f9400afbSBen Skeggs 	struct nvkm_device *device = vmm->mmu->subdev.device;
415f9400afbSBen Skeggs 	struct nvkm_memory *memory = map->memory;
416176ada03SJames Jones 	u8  kind, kind_inv, priv, ro, vol;
417f9400afbSBen Skeggs 	int kindn, aper, ret = -ENOSYS;
418f9400afbSBen Skeggs 	const u8 *kindm;
419f9400afbSBen Skeggs 
420f9400afbSBen Skeggs 	map->next = (1ULL << page->shift) >> 4;
421f9400afbSBen Skeggs 	map->type = 0;
422f9400afbSBen Skeggs 
423f9400afbSBen Skeggs 	if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
424f9400afbSBen Skeggs 		vol  = !!args->v0.vol;
425f9400afbSBen Skeggs 		ro   = !!args->v0.ro;
426f9400afbSBen Skeggs 		priv = !!args->v0.priv;
427f9400afbSBen Skeggs 		kind =   args->v0.kind;
428f9400afbSBen Skeggs 	} else
429f9400afbSBen Skeggs 	if (!(ret = nvif_unvers(ret, &argv, &argc, args->vn))) {
430f9400afbSBen Skeggs 		vol  = target == NVKM_MEM_TARGET_HOST;
431f9400afbSBen Skeggs 		ro   = 0;
432f9400afbSBen Skeggs 		priv = 0;
433f9400afbSBen Skeggs 		kind = 0x00;
434f9400afbSBen Skeggs 	} else {
435f9400afbSBen Skeggs 		VMM_DEBUG(vmm, "args");
436f9400afbSBen Skeggs 		return ret;
437f9400afbSBen Skeggs 	}
438f9400afbSBen Skeggs 
439f9400afbSBen Skeggs 	aper = vmm->func->aper(target);
440f9400afbSBen Skeggs 	if (WARN_ON(aper < 0))
441f9400afbSBen Skeggs 		return aper;
442f9400afbSBen Skeggs 
443176ada03SJames Jones 	kindm = vmm->mmu->func->kind(vmm->mmu, &kindn, &kind_inv);
444176ada03SJames Jones 	if (kind >= kindn || kindm[kind] == kind_inv) {
445f9400afbSBen Skeggs 		VMM_DEBUG(vmm, "kind %02x", kind);
446f9400afbSBen Skeggs 		return -EINVAL;
447f9400afbSBen Skeggs 	}
448f9400afbSBen Skeggs 
449f9400afbSBen Skeggs 	if (kindm[kind] != kind) {
450f9400afbSBen Skeggs 		u64 tags = nvkm_memory_size(memory) >> 16;
451f9400afbSBen Skeggs 		if (aper != 0 || !(page->type & NVKM_VMM_PAGE_COMP)) {
452f9400afbSBen Skeggs 			VMM_DEBUG(vmm, "comp %d %02x", aper, page->type);
453f9400afbSBen Skeggs 			return -EINVAL;
454f9400afbSBen Skeggs 		}
455f9400afbSBen Skeggs 
456*6b252cf4SDanilo Krummrich 		if (!map->no_comp) {
457f9400afbSBen Skeggs 			ret = nvkm_memory_tags_get(memory, device, tags,
458f9400afbSBen Skeggs 						   nvkm_ltc_tags_clear,
459f9400afbSBen Skeggs 						   &map->tags);
460f9400afbSBen Skeggs 			if (ret) {
461f9400afbSBen Skeggs 				VMM_DEBUG(vmm, "comp %d", ret);
462f9400afbSBen Skeggs 				return ret;
463f9400afbSBen Skeggs 			}
464*6b252cf4SDanilo Krummrich 		}
465f9400afbSBen Skeggs 
466*6b252cf4SDanilo Krummrich 		if (!map->no_comp && map->tags->mn) {
467f9400afbSBen Skeggs 			tags = map->tags->mn->offset + (map->offset >> 16);
468f9400afbSBen Skeggs 			map->ctag |= ((1ULL << page->shift) >> 16) << 36;
469f9400afbSBen Skeggs 			map->type |= tags << 36;
470f9400afbSBen Skeggs 			map->next |= map->ctag;
471f9400afbSBen Skeggs 		} else {
472f9400afbSBen Skeggs 			kind = kindm[kind];
473f9400afbSBen Skeggs 		}
474f9400afbSBen Skeggs 	}
475f9400afbSBen Skeggs 
476f9400afbSBen Skeggs 	map->type |= BIT(0);
477f9400afbSBen Skeggs 	map->type |= (u64)aper << 1;
478f9400afbSBen Skeggs 	map->type |= (u64) vol << 3;
479f9400afbSBen Skeggs 	map->type |= (u64)priv << 5;
480f9400afbSBen Skeggs 	map->type |= (u64)  ro << 6;
481f9400afbSBen Skeggs 	map->type |= (u64)kind << 56;
482f9400afbSBen Skeggs 	return 0;
483f9400afbSBen Skeggs }
484f9400afbSBen Skeggs 
48571871aa6SBen Skeggs static int
gp100_vmm_fault_cancel(struct nvkm_vmm * vmm,void * argv,u32 argc)48671871aa6SBen Skeggs gp100_vmm_fault_cancel(struct nvkm_vmm *vmm, void *argv, u32 argc)
48771871aa6SBen Skeggs {
48871871aa6SBen Skeggs 	struct nvkm_device *device = vmm->mmu->subdev.device;
48971871aa6SBen Skeggs 	union {
49071871aa6SBen Skeggs 		struct gp100_vmm_fault_cancel_v0 v0;
49171871aa6SBen Skeggs 	} *args = argv;
49271871aa6SBen Skeggs 	int ret = -ENOSYS;
493381ba6a6SKarol Herbst 	u32 aper;
49471871aa6SBen Skeggs 
49571871aa6SBen Skeggs 	if ((ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false)))
49671871aa6SBen Skeggs 		return ret;
49771871aa6SBen Skeggs 
49871871aa6SBen Skeggs 	/* Translate MaxwellFaultBufferA instance pointer to the same
49971871aa6SBen Skeggs 	 * format as the NV_GR_FECS_CURRENT_CTX register.
50071871aa6SBen Skeggs 	 */
50171871aa6SBen Skeggs 	aper = (args->v0.inst >> 8) & 3;
50271871aa6SBen Skeggs 	args->v0.inst >>= 12;
50371871aa6SBen Skeggs 	args->v0.inst |= aper << 28;
50471871aa6SBen Skeggs 	args->v0.inst |= 0x80000000;
50571871aa6SBen Skeggs 
50671871aa6SBen Skeggs 	if (!WARN_ON(nvkm_gr_ctxsw_pause(device))) {
507404046cfSLuo penghao 		if (nvkm_gr_ctxsw_inst(device) == args->v0.inst) {
50871871aa6SBen Skeggs 			gf100_vmm_invalidate(vmm, 0x0000001b
50971871aa6SBen Skeggs 					     /* CANCEL_TARGETED. */ |
51071871aa6SBen Skeggs 					     (args->v0.hub    << 20) |
51171871aa6SBen Skeggs 					     (args->v0.gpc    << 15) |
51271871aa6SBen Skeggs 					     (args->v0.client << 9));
51371871aa6SBen Skeggs 		}
51471871aa6SBen Skeggs 		WARN_ON(nvkm_gr_ctxsw_resume(device));
51571871aa6SBen Skeggs 	}
51671871aa6SBen Skeggs 
51771871aa6SBen Skeggs 	return 0;
51871871aa6SBen Skeggs }
51971871aa6SBen Skeggs 
52071871aa6SBen Skeggs static int
gp100_vmm_fault_replay(struct nvkm_vmm * vmm,void * argv,u32 argc)52171871aa6SBen Skeggs gp100_vmm_fault_replay(struct nvkm_vmm *vmm, void *argv, u32 argc)
52271871aa6SBen Skeggs {
52371871aa6SBen Skeggs 	union {
52471871aa6SBen Skeggs 		struct gp100_vmm_fault_replay_vn vn;
52571871aa6SBen Skeggs 	} *args = argv;
52671871aa6SBen Skeggs 	int ret = -ENOSYS;
52771871aa6SBen Skeggs 
52871871aa6SBen Skeggs 	if (!(ret = nvif_unvers(ret, &argv, &argc, args->vn))) {
52971871aa6SBen Skeggs 		gf100_vmm_invalidate(vmm, 0x0000000b); /* REPLAY_GLOBAL. */
53071871aa6SBen Skeggs 	}
53171871aa6SBen Skeggs 
53271871aa6SBen Skeggs 	return ret;
53371871aa6SBen Skeggs }
53471871aa6SBen Skeggs 
53571871aa6SBen Skeggs int
gp100_vmm_mthd(struct nvkm_vmm * vmm,struct nvkm_client * client,u32 mthd,void * argv,u32 argc)53671871aa6SBen Skeggs gp100_vmm_mthd(struct nvkm_vmm *vmm,
53771871aa6SBen Skeggs 	       struct nvkm_client *client, u32 mthd, void *argv, u32 argc)
53871871aa6SBen Skeggs {
53971871aa6SBen Skeggs 	switch (mthd) {
54071871aa6SBen Skeggs 	case GP100_VMM_VN_FAULT_REPLAY:
54171871aa6SBen Skeggs 		return gp100_vmm_fault_replay(vmm, argv, argc);
54271871aa6SBen Skeggs 	case GP100_VMM_VN_FAULT_CANCEL:
54371871aa6SBen Skeggs 		return gp100_vmm_fault_cancel(vmm, argv, argc);
54471871aa6SBen Skeggs 	default:
54571871aa6SBen Skeggs 		break;
54671871aa6SBen Skeggs 	}
54771871aa6SBen Skeggs 	return -EINVAL;
54871871aa6SBen Skeggs }
54971871aa6SBen Skeggs 
550f9400afbSBen Skeggs void
gp100_vmm_invalidate_pdb(struct nvkm_vmm * vmm,u64 addr)551d389fd4fSBen Skeggs gp100_vmm_invalidate_pdb(struct nvkm_vmm *vmm, u64 addr)
552d389fd4fSBen Skeggs {
553d389fd4fSBen Skeggs 	struct nvkm_device *device = vmm->mmu->subdev.device;
554d389fd4fSBen Skeggs 	nvkm_wr32(device, 0x100cb8, lower_32_bits(addr));
555d389fd4fSBen Skeggs 	nvkm_wr32(device, 0x100cec, upper_32_bits(addr));
556d389fd4fSBen Skeggs }
557d389fd4fSBen Skeggs 
558d389fd4fSBen Skeggs void
gp100_vmm_flush(struct nvkm_vmm * vmm,int depth)559f9400afbSBen Skeggs gp100_vmm_flush(struct nvkm_vmm *vmm, int depth)
560f9400afbSBen Skeggs {
561874c1b56SBen Skeggs 	u32 type = (5 /* CACHE_LEVEL_UP_TO_PDE3 */ - depth) << 24;
562874c1b56SBen Skeggs 	if (atomic_read(&vmm->engref[NVKM_SUBDEV_BAR]))
563874c1b56SBen Skeggs 		type |= 0x00000004; /* HUB_ONLY */
564874c1b56SBen Skeggs 	type |= 0x00000001; /* PAGE_ALL */
565874c1b56SBen Skeggs 	gf100_vmm_invalidate(vmm, type);
566f9400afbSBen Skeggs }
567f9400afbSBen Skeggs 
568f9400afbSBen Skeggs int
gp100_vmm_join(struct nvkm_vmm * vmm,struct nvkm_memory * inst)5698e39abffSBen Skeggs gp100_vmm_join(struct nvkm_vmm *vmm, struct nvkm_memory *inst)
5708e39abffSBen Skeggs {
571ab2ee9ffSBen Skeggs 	u64 base = BIT_ULL(10) /* VER2 */ | BIT_ULL(11) /* 64KiB */;
572ab2ee9ffSBen Skeggs 	if (vmm->replay) {
573ab2ee9ffSBen Skeggs 		base |= BIT_ULL(4); /* FAULT_REPLAY_TEX */
574ab2ee9ffSBen Skeggs 		base |= BIT_ULL(5); /* FAULT_REPLAY_GCC */
575ab2ee9ffSBen Skeggs 	}
5768e39abffSBen Skeggs 	return gf100_vmm_join_(vmm, inst, base);
5778e39abffSBen Skeggs }
5788e39abffSBen Skeggs 
5798e39abffSBen Skeggs static const struct nvkm_vmm_func
5808e39abffSBen Skeggs gp100_vmm = {
5818e39abffSBen Skeggs 	.join = gp100_vmm_join,
5828e39abffSBen Skeggs 	.part = gf100_vmm_part,
583f9400afbSBen Skeggs 	.aper = gf100_vmm_aper,
584f9400afbSBen Skeggs 	.valid = gp100_vmm_valid,
585f9400afbSBen Skeggs 	.flush = gp100_vmm_flush,
58671871aa6SBen Skeggs 	.mthd = gp100_vmm_mthd,
587d389fd4fSBen Skeggs 	.invalidate_pdb = gp100_vmm_invalidate_pdb,
5888e39abffSBen Skeggs 	.page = {
5898e39abffSBen Skeggs 		{ 47, &gp100_vmm_desc_16[4], NVKM_VMM_PAGE_Sxxx },
5908e39abffSBen Skeggs 		{ 38, &gp100_vmm_desc_16[3], NVKM_VMM_PAGE_Sxxx },
5918e39abffSBen Skeggs 		{ 29, &gp100_vmm_desc_16[2], NVKM_VMM_PAGE_Sxxx },
5928e39abffSBen Skeggs 		{ 21, &gp100_vmm_desc_16[1], NVKM_VMM_PAGE_SVxC },
5938e39abffSBen Skeggs 		{ 16, &gp100_vmm_desc_16[0], NVKM_VMM_PAGE_SVxC },
5948e39abffSBen Skeggs 		{ 12, &gp100_vmm_desc_12[0], NVKM_VMM_PAGE_SVHx },
5958e39abffSBen Skeggs 		{}
5968e39abffSBen Skeggs 	}
5978e39abffSBen Skeggs };
5988e39abffSBen Skeggs 
5998e39abffSBen Skeggs int
gp100_vmm_new_(const struct nvkm_vmm_func * func,struct nvkm_mmu * mmu,bool managed,u64 addr,u64 size,void * argv,u32 argc,struct lock_class_key * key,const char * name,struct nvkm_vmm ** pvmm)600ab2ee9ffSBen Skeggs gp100_vmm_new_(const struct nvkm_vmm_func *func,
601ab2ee9ffSBen Skeggs 	       struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
602ab2ee9ffSBen Skeggs 	       void *argv, u32 argc, struct lock_class_key *key,
603ab2ee9ffSBen Skeggs 	       const char *name, struct nvkm_vmm **pvmm)
604ab2ee9ffSBen Skeggs {
605ab2ee9ffSBen Skeggs 	union {
606ab2ee9ffSBen Skeggs 		struct gp100_vmm_vn vn;
607ab2ee9ffSBen Skeggs 		struct gp100_vmm_v0 v0;
608ab2ee9ffSBen Skeggs 	} *args = argv;
609ab2ee9ffSBen Skeggs 	int ret = -ENOSYS;
610ab2ee9ffSBen Skeggs 	bool replay;
611ab2ee9ffSBen Skeggs 
612ab2ee9ffSBen Skeggs 	if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
613ab2ee9ffSBen Skeggs 		replay = args->v0.fault_replay != 0;
614ab2ee9ffSBen Skeggs 	} else
615ab2ee9ffSBen Skeggs 	if (!(ret = nvif_unvers(ret, &argv, &argc, args->vn))) {
616ab2ee9ffSBen Skeggs 		replay = false;
617ab2ee9ffSBen Skeggs 	} else
618ab2ee9ffSBen Skeggs 		return ret;
619ab2ee9ffSBen Skeggs 
620ab2ee9ffSBen Skeggs 	ret = nvkm_vmm_new_(func, mmu, 0, managed, addr, size, key, name, pvmm);
621ab2ee9ffSBen Skeggs 	if (ret)
622ab2ee9ffSBen Skeggs 		return ret;
623ab2ee9ffSBen Skeggs 
624ab2ee9ffSBen Skeggs 	(*pvmm)->replay = replay;
625ab2ee9ffSBen Skeggs 	return 0;
626ab2ee9ffSBen Skeggs }
627ab2ee9ffSBen Skeggs 
628ab2ee9ffSBen Skeggs int
gp100_vmm_new(struct nvkm_mmu * mmu,bool managed,u64 addr,u64 size,void * argv,u32 argc,struct lock_class_key * key,const char * name,struct nvkm_vmm ** pvmm)6292606f291SBen Skeggs gp100_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
6302606f291SBen Skeggs 	      void *argv, u32 argc, struct lock_class_key *key,
6312606f291SBen Skeggs 	      const char *name, struct nvkm_vmm **pvmm)
6328e39abffSBen Skeggs {
633ab2ee9ffSBen Skeggs 	return gp100_vmm_new_(&gp100_vmm, mmu, managed, addr, size,
6348e39abffSBen Skeggs 			      argv, argc, key, name, pvmm);
6358e39abffSBen Skeggs }
636