diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 3dc8d6b..6b02a03 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -35,6 +35,10 @@ #include #include #include +#include +#include +#include +#include #define TTM_BO_VM_NUM_PREFAULT 16 @@ -69,6 +73,137 @@ static struct ttm_buffer_object *ttm_bo_vm_lookup_rb(struct ttm_bo_device *bdev, return best_bo; } +void print_pte(char *what, struct page *page, unsigned int pfn, unsigned long address) +{ + static const char * const level_name[] = + { "NONE", "4K", "2M", "1G", "NUM" }; + unsigned long addr = 0; + pte_t *pte = NULL; + pteval_t val = (pteval_t)0; + unsigned int level = 0; + unsigned offset; + unsigned long phys; + pgprotval_t prot; + char buf[80]; + char *str; + + str = buf; + // Figure out if the address is pagetable. + if (address == 0 && page) + addr = (u64)page_address(page); + + if (address && !page) + addr = address; + + if (address && page) { + addr = (u64)page_address(page); + if (address != addr) { + if (addr == 0) { + str += sprintf(str, "addr==0"); + addr = address; + } + } + } + if (!virt_addr_valid(addr)) + str += sprintf(str, "!addr"); + + if (pfn != 0 && page && pfn_valid(pfn)) { + if (pfn != page_to_pfn(page)) // Gosh!? + str += sprintf(str, "pfn!=pfn(%ld)", page_to_pfn(page)); + } + if (pfn != 0 && addr != 0 && pfn_valid(pfn)) { + if (pfn != virt_to_pfn(addr)) + str += sprintf(str,"pfn(addr)!=pfn"); + } + if (!pfn_valid(pfn)) + str += sprintf(str,"!pfn"); + + if (pfn_valid(pfn) && xen_initial_domain()) { + str += sprintf(str,"mfn:%ld->%lx", + pfn_to_mfn(pfn), + (unsigned long)mfn_to_virt(pfn_to_mfn(pfn))); + } + // Fixup, last attempt + if (!virt_addr_valid(addr) && pfn_valid(pfn)) { + str += sprintf(str,"(%lx)", addr); // old address. + addr = (u64)pfn_to_kaddr(pfn); + } + pte = lookup_address(addr, &level); + if (!pte) { + str += sprintf(str,"!pte(addr)"); + goto print; + } + offset = addr & ~PAGE_MASK; + + if (xen_domain()) { + phys = (pte_mfn(*pte) << PAGE_SHIFT) + offset; + val = pte_val_ma(*pte); + } else { + phys = (pte_pfn(*pte) << PAGE_SHIFT) + offset; + val = pte_val(*pte); + } + prot = pgprot_val(pte_pgprot(*pte)); + + if (!prot) + str += sprintf(str, "Not present."); + else { + if (prot & _PAGE_USER) + str += sprintf(str, "USR "); + else + str += sprintf(str, " "); + if (prot & _PAGE_RW) + str += sprintf(str, "RW "); + else + str += sprintf(str, "ro "); + if (prot & _PAGE_PWT) + str += sprintf(str, "PWT "); + else + str += sprintf(str, " "); + if (prot & _PAGE_PCD) + str += sprintf(str, "PCD "); + else + str += sprintf(str, " "); + + /* Bit 9 has a different meaning on level 3 vs 4 */ + if (level <= 3) { + if (prot & _PAGE_PSE) + str += sprintf(str, "PSE "); + else + str += sprintf(str, " "); + } else { + if (prot & _PAGE_PAT) + str += sprintf(str, "pat "); + else + str += sprintf(str, " "); + } + if (prot & _PAGE_GLOBAL) + str += sprintf(str, "GLB "); + else + str += sprintf(str, " "); + if (prot & _PAGE_NX) + str += sprintf(str, "NX "); + else + str += sprintf(str, "x "); +#ifdef _PAGE_IOMEM + if (prot & _PAGE_IOMEM) + str += sprintf(str, "IO "); + else + str += sprintf(str, " "); +#endif + if (prot & _PAGE_SPECIAL) + str += sprintf(str, "SP "); + } + +print: + printk(KERN_INFO "[%16s]PFN: 0x%lx PTE: 0x%lx (val:%lx): [%s] [%s]\n", + what, + (unsigned long)pfn, + (pte) ? (unsigned long)(pte->pte) : 0, + (unsigned long)val, + buf, + level_name[level]); +} + static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct ttm_buffer_object *bo = (struct ttm_buffer_object *) @@ -81,7 +216,7 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) unsigned long page_last; unsigned long pfn; struct ttm_tt *ttm = NULL; - struct page *page; + struct page *page = NULL; int ret; int i; bool is_iomem; @@ -186,7 +321,9 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) pfn = page_to_pfn(page); } + print_pte("BEFORE",page, pfn, address); ret = vm_insert_mixed(vma, address, pfn); + print_pte("AFTER",page, pfn, address); /* * Somebody beat us to this PTE or prefaulting to * an already populated PTE, or prefaulting error.