.. | .. |
---|
21 | 21 | */ |
---|
22 | 22 | #include "vmm.h" |
---|
23 | 23 | |
---|
| 24 | +#include <core/client.h> |
---|
24 | 25 | #include <subdev/fb.h> |
---|
25 | 26 | #include <subdev/ltc.h> |
---|
| 27 | +#include <subdev/timer.h> |
---|
| 28 | +#include <engine/gr.h> |
---|
26 | 29 | |
---|
27 | 30 | #include <nvif/ifc00d.h> |
---|
28 | 31 | #include <nvif/unpack.h> |
---|
| 32 | + |
---|
| 33 | +static void |
---|
| 34 | +gp100_vmm_pfn_unmap(struct nvkm_vmm *vmm, |
---|
| 35 | + struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes) |
---|
| 36 | +{ |
---|
| 37 | + struct device *dev = vmm->mmu->subdev.device->dev; |
---|
| 38 | + dma_addr_t addr; |
---|
| 39 | + |
---|
| 40 | + nvkm_kmap(pt->memory); |
---|
| 41 | + while (ptes--) { |
---|
| 42 | + u32 datalo = nvkm_ro32(pt->memory, pt->base + ptei * 8 + 0); |
---|
| 43 | + u32 datahi = nvkm_ro32(pt->memory, pt->base + ptei * 8 + 4); |
---|
| 44 | + u64 data = (u64)datahi << 32 | datalo; |
---|
| 45 | + if ((data & (3ULL << 1)) != 0) { |
---|
| 46 | + addr = (data >> 8) << 12; |
---|
| 47 | + dma_unmap_page(dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL); |
---|
| 48 | + } |
---|
| 49 | + ptei++; |
---|
| 50 | + } |
---|
| 51 | + nvkm_done(pt->memory); |
---|
| 52 | +} |
---|
| 53 | + |
---|
| 54 | +static bool |
---|
| 55 | +gp100_vmm_pfn_clear(struct nvkm_vmm *vmm, |
---|
| 56 | + struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes) |
---|
| 57 | +{ |
---|
| 58 | + bool dma = false; |
---|
| 59 | + nvkm_kmap(pt->memory); |
---|
| 60 | + while (ptes--) { |
---|
| 61 | + u32 datalo = nvkm_ro32(pt->memory, pt->base + ptei * 8 + 0); |
---|
| 62 | + u32 datahi = nvkm_ro32(pt->memory, pt->base + ptei * 8 + 4); |
---|
| 63 | + u64 data = (u64)datahi << 32 | datalo; |
---|
| 64 | + if ((data & BIT_ULL(0)) && (data & (3ULL << 1)) != 0) { |
---|
| 65 | + VMM_WO064(pt, vmm, ptei * 8, data & ~BIT_ULL(0)); |
---|
| 66 | + dma = true; |
---|
| 67 | + } |
---|
| 68 | + ptei++; |
---|
| 69 | + } |
---|
| 70 | + nvkm_done(pt->memory); |
---|
| 71 | + return dma; |
---|
| 72 | +} |
---|
| 73 | + |
---|
| 74 | +static void |
---|
| 75 | +gp100_vmm_pgt_pfn(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt, |
---|
| 76 | + u32 ptei, u32 ptes, struct nvkm_vmm_map *map) |
---|
| 77 | +{ |
---|
| 78 | + struct device *dev = vmm->mmu->subdev.device->dev; |
---|
| 79 | + dma_addr_t addr; |
---|
| 80 | + |
---|
| 81 | + nvkm_kmap(pt->memory); |
---|
| 82 | + for (; ptes; ptes--, map->pfn++) { |
---|
| 83 | + u64 data = 0; |
---|
| 84 | + |
---|
| 85 | + if (!(*map->pfn & NVKM_VMM_PFN_V)) |
---|
| 86 | + continue; |
---|
| 87 | + |
---|
| 88 | + if (!(*map->pfn & NVKM_VMM_PFN_W)) |
---|
| 89 | + data |= BIT_ULL(6); /* RO. */ |
---|
| 90 | + |
---|
| 91 | + if (!(*map->pfn & NVKM_VMM_PFN_VRAM)) { |
---|
| 92 | + addr = *map->pfn >> NVKM_VMM_PFN_ADDR_SHIFT; |
---|
| 93 | + addr = dma_map_page(dev, pfn_to_page(addr), 0, |
---|
| 94 | + PAGE_SIZE, DMA_BIDIRECTIONAL); |
---|
| 95 | + if (!WARN_ON(dma_mapping_error(dev, addr))) { |
---|
| 96 | + data |= addr >> 4; |
---|
| 97 | + data |= 2ULL << 1; /* SYSTEM_COHERENT_MEMORY. */ |
---|
| 98 | + data |= BIT_ULL(3); /* VOL. */ |
---|
| 99 | + data |= BIT_ULL(0); /* VALID. */ |
---|
| 100 | + } |
---|
| 101 | + } else { |
---|
| 102 | + data |= (*map->pfn & NVKM_VMM_PFN_ADDR) >> 4; |
---|
| 103 | + data |= BIT_ULL(0); /* VALID. */ |
---|
| 104 | + } |
---|
| 105 | + |
---|
| 106 | + VMM_WO064(pt, vmm, ptei++ * 8, data); |
---|
| 107 | + } |
---|
| 108 | + nvkm_done(pt->memory); |
---|
| 109 | +} |
---|
29 | 110 | |
---|
30 | 111 | static inline void |
---|
31 | 112 | gp100_vmm_pgt_pte(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt, |
---|
.. | .. |
---|
89 | 170 | .mem = gp100_vmm_pgt_mem, |
---|
90 | 171 | .dma = gp100_vmm_pgt_dma, |
---|
91 | 172 | .sgl = gp100_vmm_pgt_sgl, |
---|
| 173 | + .pfn = gp100_vmm_pgt_pfn, |
---|
| 174 | + .pfn_clear = gp100_vmm_pfn_clear, |
---|
| 175 | + .pfn_unmap = gp100_vmm_pfn_unmap, |
---|
92 | 176 | }; |
---|
93 | 177 | |
---|
94 | 178 | static void |
---|
.. | .. |
---|
177 | 261 | VMM_FO128(pt, vmm, pdei * 0x10, 0ULL, 0ULL, pdes); |
---|
178 | 262 | } |
---|
179 | 263 | |
---|
| 264 | +static void |
---|
| 265 | +gp100_vmm_pd0_pfn_unmap(struct nvkm_vmm *vmm, |
---|
| 266 | + struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes) |
---|
| 267 | +{ |
---|
| 268 | + struct device *dev = vmm->mmu->subdev.device->dev; |
---|
| 269 | + dma_addr_t addr; |
---|
| 270 | + |
---|
| 271 | + nvkm_kmap(pt->memory); |
---|
| 272 | + while (ptes--) { |
---|
| 273 | + u32 datalo = nvkm_ro32(pt->memory, pt->base + ptei * 16 + 0); |
---|
| 274 | + u32 datahi = nvkm_ro32(pt->memory, pt->base + ptei * 16 + 4); |
---|
| 275 | + u64 data = (u64)datahi << 32 | datalo; |
---|
| 276 | + |
---|
| 277 | + if ((data & (3ULL << 1)) != 0) { |
---|
| 278 | + addr = (data >> 8) << 12; |
---|
| 279 | + dma_unmap_page(dev, addr, 1UL << 21, DMA_BIDIRECTIONAL); |
---|
| 280 | + } |
---|
| 281 | + ptei++; |
---|
| 282 | + } |
---|
| 283 | + nvkm_done(pt->memory); |
---|
| 284 | +} |
---|
| 285 | + |
---|
| 286 | +static bool |
---|
| 287 | +gp100_vmm_pd0_pfn_clear(struct nvkm_vmm *vmm, |
---|
| 288 | + struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes) |
---|
| 289 | +{ |
---|
| 290 | + bool dma = false; |
---|
| 291 | + |
---|
| 292 | + nvkm_kmap(pt->memory); |
---|
| 293 | + while (ptes--) { |
---|
| 294 | + u32 datalo = nvkm_ro32(pt->memory, pt->base + ptei * 16 + 0); |
---|
| 295 | + u32 datahi = nvkm_ro32(pt->memory, pt->base + ptei * 16 + 4); |
---|
| 296 | + u64 data = (u64)datahi << 32 | datalo; |
---|
| 297 | + |
---|
| 298 | + if ((data & BIT_ULL(0)) && (data & (3ULL << 1)) != 0) { |
---|
| 299 | + VMM_WO064(pt, vmm, ptei * 16, data & ~BIT_ULL(0)); |
---|
| 300 | + dma = true; |
---|
| 301 | + } |
---|
| 302 | + ptei++; |
---|
| 303 | + } |
---|
| 304 | + nvkm_done(pt->memory); |
---|
| 305 | + return dma; |
---|
| 306 | +} |
---|
| 307 | + |
---|
| 308 | +static void |
---|
| 309 | +gp100_vmm_pd0_pfn(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt, |
---|
| 310 | + u32 ptei, u32 ptes, struct nvkm_vmm_map *map) |
---|
| 311 | +{ |
---|
| 312 | + struct device *dev = vmm->mmu->subdev.device->dev; |
---|
| 313 | + dma_addr_t addr; |
---|
| 314 | + |
---|
| 315 | + nvkm_kmap(pt->memory); |
---|
| 316 | + for (; ptes; ptes--, map->pfn++) { |
---|
| 317 | + u64 data = 0; |
---|
| 318 | + |
---|
| 319 | + if (!(*map->pfn & NVKM_VMM_PFN_V)) |
---|
| 320 | + continue; |
---|
| 321 | + |
---|
| 322 | + if (!(*map->pfn & NVKM_VMM_PFN_W)) |
---|
| 323 | + data |= BIT_ULL(6); /* RO. */ |
---|
| 324 | + |
---|
| 325 | + if (!(*map->pfn & NVKM_VMM_PFN_VRAM)) { |
---|
| 326 | + addr = *map->pfn >> NVKM_VMM_PFN_ADDR_SHIFT; |
---|
| 327 | + addr = dma_map_page(dev, pfn_to_page(addr), 0, |
---|
| 328 | + 1UL << 21, DMA_BIDIRECTIONAL); |
---|
| 329 | + if (!WARN_ON(dma_mapping_error(dev, addr))) { |
---|
| 330 | + data |= addr >> 4; |
---|
| 331 | + data |= 2ULL << 1; /* SYSTEM_COHERENT_MEMORY. */ |
---|
| 332 | + data |= BIT_ULL(3); /* VOL. */ |
---|
| 333 | + data |= BIT_ULL(0); /* VALID. */ |
---|
| 334 | + } |
---|
| 335 | + } else { |
---|
| 336 | + data |= (*map->pfn & NVKM_VMM_PFN_ADDR) >> 4; |
---|
| 337 | + data |= BIT_ULL(0); /* VALID. */ |
---|
| 338 | + } |
---|
| 339 | + |
---|
| 340 | + VMM_WO064(pt, vmm, ptei++ * 16, data); |
---|
| 341 | + } |
---|
| 342 | + nvkm_done(pt->memory); |
---|
| 343 | +} |
---|
| 344 | + |
---|
180 | 345 | static const struct nvkm_vmm_desc_func |
---|
181 | 346 | gp100_vmm_desc_pd0 = { |
---|
182 | 347 | .unmap = gp100_vmm_pd0_unmap, |
---|
183 | 348 | .sparse = gp100_vmm_pd0_sparse, |
---|
184 | 349 | .pde = gp100_vmm_pd0_pde, |
---|
185 | 350 | .mem = gp100_vmm_pd0_mem, |
---|
| 351 | + .pfn = gp100_vmm_pd0_pfn, |
---|
| 352 | + .pfn_clear = gp100_vmm_pd0_pfn_clear, |
---|
| 353 | + .pfn_unmap = gp100_vmm_pd0_pfn_unmap, |
---|
186 | 354 | }; |
---|
187 | 355 | |
---|
188 | 356 | static void |
---|
.. | .. |
---|
239 | 407 | } *args = argv; |
---|
240 | 408 | struct nvkm_device *device = vmm->mmu->subdev.device; |
---|
241 | 409 | struct nvkm_memory *memory = map->memory; |
---|
242 | | - u8 kind, priv, ro, vol; |
---|
| 410 | + u8 kind, kind_inv, priv, ro, vol; |
---|
243 | 411 | int kindn, aper, ret = -ENOSYS; |
---|
244 | 412 | const u8 *kindm; |
---|
245 | 413 | |
---|
.. | .. |
---|
266 | 434 | if (WARN_ON(aper < 0)) |
---|
267 | 435 | return aper; |
---|
268 | 436 | |
---|
269 | | - kindm = vmm->mmu->func->kind(vmm->mmu, &kindn); |
---|
270 | | - if (kind >= kindn || kindm[kind] == 0xff) { |
---|
| 437 | + kindm = vmm->mmu->func->kind(vmm->mmu, &kindn, &kind_inv); |
---|
| 438 | + if (kind >= kindn || kindm[kind] == kind_inv) { |
---|
271 | 439 | VMM_DEBUG(vmm, "kind %02x", kind); |
---|
272 | 440 | return -EINVAL; |
---|
273 | 441 | } |
---|
.. | .. |
---|
306 | 474 | return 0; |
---|
307 | 475 | } |
---|
308 | 476 | |
---|
| 477 | +static int |
---|
| 478 | +gp100_vmm_fault_cancel(struct nvkm_vmm *vmm, void *argv, u32 argc) |
---|
| 479 | +{ |
---|
| 480 | + struct nvkm_device *device = vmm->mmu->subdev.device; |
---|
| 481 | + union { |
---|
| 482 | + struct gp100_vmm_fault_cancel_v0 v0; |
---|
| 483 | + } *args = argv; |
---|
| 484 | + int ret = -ENOSYS; |
---|
| 485 | + u32 inst, aper; |
---|
| 486 | + |
---|
| 487 | + if ((ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) |
---|
| 488 | + return ret; |
---|
| 489 | + |
---|
| 490 | + /* Translate MaxwellFaultBufferA instance pointer to the same |
---|
| 491 | + * format as the NV_GR_FECS_CURRENT_CTX register. |
---|
| 492 | + */ |
---|
| 493 | + aper = (args->v0.inst >> 8) & 3; |
---|
| 494 | + args->v0.inst >>= 12; |
---|
| 495 | + args->v0.inst |= aper << 28; |
---|
| 496 | + args->v0.inst |= 0x80000000; |
---|
| 497 | + |
---|
| 498 | + if (!WARN_ON(nvkm_gr_ctxsw_pause(device))) { |
---|
| 499 | + if ((inst = nvkm_gr_ctxsw_inst(device)) == args->v0.inst) { |
---|
| 500 | + gf100_vmm_invalidate(vmm, 0x0000001b |
---|
| 501 | + /* CANCEL_TARGETED. */ | |
---|
| 502 | + (args->v0.hub << 20) | |
---|
| 503 | + (args->v0.gpc << 15) | |
---|
| 504 | + (args->v0.client << 9)); |
---|
| 505 | + } |
---|
| 506 | + WARN_ON(nvkm_gr_ctxsw_resume(device)); |
---|
| 507 | + } |
---|
| 508 | + |
---|
| 509 | + return 0; |
---|
| 510 | +} |
---|
| 511 | + |
---|
| 512 | +static int |
---|
| 513 | +gp100_vmm_fault_replay(struct nvkm_vmm *vmm, void *argv, u32 argc) |
---|
| 514 | +{ |
---|
| 515 | + union { |
---|
| 516 | + struct gp100_vmm_fault_replay_vn vn; |
---|
| 517 | + } *args = argv; |
---|
| 518 | + int ret = -ENOSYS; |
---|
| 519 | + |
---|
| 520 | + if (!(ret = nvif_unvers(ret, &argv, &argc, args->vn))) { |
---|
| 521 | + gf100_vmm_invalidate(vmm, 0x0000000b); /* REPLAY_GLOBAL. */ |
---|
| 522 | + } |
---|
| 523 | + |
---|
| 524 | + return ret; |
---|
| 525 | +} |
---|
| 526 | + |
---|
| 527 | +int |
---|
| 528 | +gp100_vmm_mthd(struct nvkm_vmm *vmm, |
---|
| 529 | + struct nvkm_client *client, u32 mthd, void *argv, u32 argc) |
---|
| 530 | +{ |
---|
| 531 | + if (client->super) { |
---|
| 532 | + switch (mthd) { |
---|
| 533 | + case GP100_VMM_VN_FAULT_REPLAY: |
---|
| 534 | + return gp100_vmm_fault_replay(vmm, argv, argc); |
---|
| 535 | + case GP100_VMM_VN_FAULT_CANCEL: |
---|
| 536 | + return gp100_vmm_fault_cancel(vmm, argv, argc); |
---|
| 537 | + default: |
---|
| 538 | + break; |
---|
| 539 | + } |
---|
| 540 | + } |
---|
| 541 | + return -EINVAL; |
---|
| 542 | +} |
---|
| 543 | + |
---|
| 544 | +void |
---|
| 545 | +gp100_vmm_invalidate_pdb(struct nvkm_vmm *vmm, u64 addr) |
---|
| 546 | +{ |
---|
| 547 | + struct nvkm_device *device = vmm->mmu->subdev.device; |
---|
| 548 | + nvkm_wr32(device, 0x100cb8, lower_32_bits(addr)); |
---|
| 549 | + nvkm_wr32(device, 0x100cec, upper_32_bits(addr)); |
---|
| 550 | +} |
---|
| 551 | + |
---|
309 | 552 | void |
---|
310 | 553 | gp100_vmm_flush(struct nvkm_vmm *vmm, int depth) |
---|
311 | 554 | { |
---|
312 | | - gf100_vmm_flush_(vmm, 5 /* CACHE_LEVEL_UP_TO_PDE3 */ - depth); |
---|
| 555 | + u32 type = (5 /* CACHE_LEVEL_UP_TO_PDE3 */ - depth) << 24; |
---|
| 556 | + if (atomic_read(&vmm->engref[NVKM_SUBDEV_BAR])) |
---|
| 557 | + type |= 0x00000004; /* HUB_ONLY */ |
---|
| 558 | + type |= 0x00000001; /* PAGE_ALL */ |
---|
| 559 | + gf100_vmm_invalidate(vmm, type); |
---|
313 | 560 | } |
---|
314 | 561 | |
---|
315 | 562 | int |
---|
316 | 563 | gp100_vmm_join(struct nvkm_vmm *vmm, struct nvkm_memory *inst) |
---|
317 | 564 | { |
---|
318 | | - const u64 base = BIT_ULL(10) /* VER2 */ | BIT_ULL(11); /* 64KiB */ |
---|
| 565 | + u64 base = BIT_ULL(10) /* VER2 */ | BIT_ULL(11) /* 64KiB */; |
---|
| 566 | + if (vmm->replay) { |
---|
| 567 | + base |= BIT_ULL(4); /* FAULT_REPLAY_TEX */ |
---|
| 568 | + base |= BIT_ULL(5); /* FAULT_REPLAY_GCC */ |
---|
| 569 | + } |
---|
319 | 570 | return gf100_vmm_join_(vmm, inst, base); |
---|
320 | 571 | } |
---|
321 | 572 | |
---|
.. | .. |
---|
326 | 577 | .aper = gf100_vmm_aper, |
---|
327 | 578 | .valid = gp100_vmm_valid, |
---|
328 | 579 | .flush = gp100_vmm_flush, |
---|
| 580 | + .mthd = gp100_vmm_mthd, |
---|
| 581 | + .invalidate_pdb = gp100_vmm_invalidate_pdb, |
---|
329 | 582 | .page = { |
---|
330 | 583 | { 47, &gp100_vmm_desc_16[4], NVKM_VMM_PAGE_Sxxx }, |
---|
331 | 584 | { 38, &gp100_vmm_desc_16[3], NVKM_VMM_PAGE_Sxxx }, |
---|
.. | .. |
---|
338 | 591 | }; |
---|
339 | 592 | |
---|
340 | 593 | int |
---|
341 | | -gp100_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc, |
---|
342 | | - struct lock_class_key *key, const char *name, |
---|
343 | | - struct nvkm_vmm **pvmm) |
---|
| 594 | +gp100_vmm_new_(const struct nvkm_vmm_func *func, |
---|
| 595 | + struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size, |
---|
| 596 | + void *argv, u32 argc, struct lock_class_key *key, |
---|
| 597 | + const char *name, struct nvkm_vmm **pvmm) |
---|
344 | 598 | { |
---|
345 | | - return nv04_vmm_new_(&gp100_vmm, mmu, 0, addr, size, |
---|
346 | | - argv, argc, key, name, pvmm); |
---|
| 599 | + union { |
---|
| 600 | + struct gp100_vmm_vn vn; |
---|
| 601 | + struct gp100_vmm_v0 v0; |
---|
| 602 | + } *args = argv; |
---|
| 603 | + int ret = -ENOSYS; |
---|
| 604 | + bool replay; |
---|
| 605 | + |
---|
| 606 | + if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) { |
---|
| 607 | + replay = args->v0.fault_replay != 0; |
---|
| 608 | + } else |
---|
| 609 | + if (!(ret = nvif_unvers(ret, &argv, &argc, args->vn))) { |
---|
| 610 | + replay = false; |
---|
| 611 | + } else |
---|
| 612 | + return ret; |
---|
| 613 | + |
---|
| 614 | + ret = nvkm_vmm_new_(func, mmu, 0, managed, addr, size, key, name, pvmm); |
---|
| 615 | + if (ret) |
---|
| 616 | + return ret; |
---|
| 617 | + |
---|
| 618 | + (*pvmm)->replay = replay; |
---|
| 619 | + return 0; |
---|
| 620 | +} |
---|
| 621 | + |
---|
| 622 | +int |
---|
| 623 | +gp100_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size, |
---|
| 624 | + void *argv, u32 argc, struct lock_class_key *key, |
---|
| 625 | + const char *name, struct nvkm_vmm **pvmm) |
---|
| 626 | +{ |
---|
| 627 | + return gp100_vmm_new_(&gp100_vmm, mmu, managed, addr, size, |
---|
| 628 | + argv, argc, key, name, pvmm); |
---|
347 | 629 | } |
---|