__pa(kernel_address) is invalid for vmap'd GTT kmap addresses. Record
page->user_pfn at setup (virt_to_page / vmalloc_to_pfn) and use it in
kfd_event_mmap() instead of __pa().

Change-Id: I61061ab280850afa776191c30ba90a475afab46d
Signed-off-by: "Sun, Yongqiang" <[email protected]>
---
 drivers/gpu/drm/amd/amdkfd/kfd_events.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c 
b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
index e9be798c0a2b..6e0beacca81e 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
@@ -21,8 +21,10 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <linux/mm.h>
 #include <linux/mm_types.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/types.h>
 #include <linux/sched/signal.h>
 #include <linux/sched/mm.h>
@@ -54,6 +56,7 @@ struct kfd_event_waiter {
 struct kfd_signal_page {
        uint64_t *kernel_address;
        uint64_t __user *user_address;
+       unsigned long user_pfn;
        bool need_to_free_pages;
 };
 
@@ -82,6 +85,7 @@ static struct kfd_signal_page *allocate_signal_page(struct 
kfd_process *p)
 
        page->kernel_address = backing_store;
        page->need_to_free_pages = true;
+       page->user_pfn = page_to_pfn(virt_to_page(backing_store));
        pr_debug("Allocated new event signal page at %p, for process %p\n",
                        page, p);
 
@@ -349,6 +353,11 @@ static int kfd_event_page_set(struct kfd_process *p, void 
*kernel_address,
               KFD_SIGNAL_EVENT_LIMIT * 8);
 
        page->kernel_address = kernel_address;
+       /* kmap for GTT is vmap-backed; do not use __pa() on kernel_address */
+       if (is_vmalloc_addr(kernel_address))
+               page->user_pfn = vmalloc_to_pfn(kernel_address);
+       else
+               page->user_pfn = page_to_pfn(virt_to_page(kernel_address));
 
        p->signal_page = page;
        p->signal_mapped_size = size;
@@ -1087,8 +1096,11 @@ int kfd_event_mmap(struct kfd_process *p, struct 
vm_area_struct *vma)
                return -EINVAL;
        }
 
-       pfn = __pa(page->kernel_address);
-       pfn >>= PAGE_SHIFT;
+       if (!page->user_pfn) {
+               pr_err("signal page has no recorded PFN\n");
+               return -EINVAL;
+       }
+       pfn = page->user_pfn;
 
        vm_flags_set(vma, VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE
                       | VM_DONTDUMP | VM_PFNMAP);
-- 
2.43.0

Reply via email to