diff options
Diffstat (limited to 'drivers/gpu/nvgpu/common/mm/gmmu.c')
-rw-r--r-- | drivers/gpu/nvgpu/common/mm/gmmu.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/mm/gmmu.c b/drivers/gpu/nvgpu/common/mm/gmmu.c index 748e9f45..a04e501f 100644 --- a/drivers/gpu/nvgpu/common/mm/gmmu.c +++ b/drivers/gpu/nvgpu/common/mm/gmmu.c | |||
@@ -36,6 +36,9 @@ | |||
36 | 36 | ||
37 | #include "gk20a/mm_gk20a.h" | 37 | #include "gk20a/mm_gk20a.h" |
38 | 38 | ||
39 | // XXX: Shouldn't really be here! Needed for __nvgpu_update_paddr() | ||
40 | #include <nvgpu/hw/gp10b/hw_gmmu_gp10b.h> | ||
41 | |||
39 | #define __gmmu_dbg(g, attrs, fmt, args...) \ | 42 | #define __gmmu_dbg(g, attrs, fmt, args...) \ |
40 | do { \ | 43 | do { \ |
41 | if (attrs->debug) { \ | 44 | if (attrs->debug) { \ |
@@ -938,3 +941,54 @@ int __nvgpu_set_pte(struct gk20a *g, struct vm_gk20a *vm, u64 vaddr, u32 *pte) | |||
938 | 941 | ||
939 | return 0; | 942 | return 0; |
940 | } | 943 | } |
944 | |||
945 | u64 pgsz_enum_to_bytes(int sz) { | ||
946 | if (sz == GMMU_PAGE_SIZE_SMALL) | ||
947 | return SZ_4K; | ||
948 | else | ||
949 | return SZ_64K; // Dangerous! Big pages may also be 128k. Should check ram_in_big_page_size... registers. | ||
950 | } | ||
951 | |||
952 | // Caller is responsible for TLB/L2 flushing so that this can be called | ||
953 | // repeatedly with low overhead. | ||
954 | int __nvgpu_update_paddr(struct gk20a *g, struct vm_gk20a *vm, u64 vaddr, u64 paddr) | ||
955 | { | ||
956 | struct nvgpu_gmmu_pd *pd; | ||
957 | u32 pd_idx, pd_offs; | ||
958 | int err; | ||
959 | u32 pte[2]; // Safe for at least gv11b | ||
960 | struct nvgpu_gmmu_attrs attrs = { | ||
961 | .pgsz = 0, | ||
962 | }; | ||
963 | // u32 pte_orig[2]; | ||
964 | |||
965 | // Get existing pte entry and location | ||
966 | err = __nvgpu_locate_pte(g, vm, &vm->pdb, | ||
967 | vaddr, 0, &attrs, | ||
968 | pte, &pd, &pd_idx, &pd_offs); | ||
969 | if (unlikely(err)) { | ||
970 | printk(KERN_ERR "nvgpu: Unable to find PTE for vaddr %llx in __nvgpu_update_paddr()\n", vaddr); | ||
971 | return err; | ||
972 | } | ||
973 | // TODO: Verify that the PTE is actually in SYSMEM | ||
974 | // pte_orig[0] = pte[0]; | ||
975 | // pte_orig[1] = pte[1]; | ||
976 | |||
977 | // Following logic is borrowed from __update_pte() for gp10b+ | ||
978 | // TODO: Make this work for gk20a-gp10b! | ||
979 | // Zero-out the address field | ||
980 | pte[0] &= ~gmmu_new_pte_address_sys_f(~0 >> gmmu_new_pte_address_shift_v()); | ||
981 | pte[1] &= ~(~0U >> (24 + gmmu_new_pte_address_shift_v())); | ||
982 | // Write new address (upper and lower bits) | ||
983 | pte[0] |= gmmu_new_pte_address_sys_f(paddr >> gmmu_new_pte_address_shift_v()); | ||
984 | pte[1] |= paddr >> (24 + gmmu_new_pte_address_shift_v()); | ||
985 | // Commit to the page tables | ||
986 | pd_write(g, pd, pd_offs, pte[0]); | ||
987 | pd_write(g, pd, pd_offs + 1, pte[1]); | ||
988 | nvgpu_wmb(); // XXX: Is this needed? | ||
989 | // printk(KERN_INFO "nvgpu: Mapped vaddr %llx @ paddr %llx. %lluKb pg. [%08x, %08x]\n", vaddr, paddr, pgsz_enum_to_bytes(attrs.pgsz)/1024, pte[1], pte[0]); | ||
990 | // if (pte_orig[0] != pte[0] || pte_orig[1] != pte[1]) { | ||
991 | // printk(KERN_INFO "nvgpu: Updated PTE entry from {%x,%x} to {%x, %x}\n", pte_orig[0], pte_orig[1], pte[0], pte[1]); | ||
992 | // } | ||
993 | return pgsz_enum_to_bytes(attrs.pgsz); | ||
994 | } | ||