1ac49797cSLizhi Hou // SPDX-License-Identifier: GPL-2.0 2ac49797cSLizhi Hou /* 3ac49797cSLizhi Hou * Copyright (C) 2024, Advanced Micro Devices, Inc. 4ac49797cSLizhi Hou */ 5ac49797cSLizhi Hou 6ac49797cSLizhi Hou #include <drm/amdxdna_accel.h> 7ac49797cSLizhi Hou #include <drm/drm_cache.h> 8ac49797cSLizhi Hou #include <drm/drm_device.h> 9ac49797cSLizhi Hou #include <drm/drm_gem.h> 10ac49797cSLizhi Hou #include <drm/drm_gem_shmem_helper.h> 11aac24309SLizhi Hou #include <drm/gpu_scheduler.h> 12*e486147cSLizhi Hou #include <linux/dma-buf.h> 13*e486147cSLizhi Hou #include <linux/dma-direct.h> 14ac49797cSLizhi Hou #include <linux/iosys-map.h> 15*e486147cSLizhi Hou #include <linux/pagemap.h> 16ac49797cSLizhi Hou #include <linux/vmalloc.h> 17ac49797cSLizhi Hou 18ac49797cSLizhi Hou #include "amdxdna_ctx.h" 19ac49797cSLizhi Hou #include "amdxdna_gem.h" 20ac49797cSLizhi Hou #include "amdxdna_pci_drv.h" 21ac49797cSLizhi Hou 22ac49797cSLizhi Hou #define XDNA_MAX_CMD_BO_SIZE SZ_32K 23ac49797cSLizhi Hou 24*e486147cSLizhi Hou MODULE_IMPORT_NS("DMA_BUF"); 25*e486147cSLizhi Hou 26ac49797cSLizhi Hou static int 27ac49797cSLizhi Hou amdxdna_gem_insert_node_locked(struct amdxdna_gem_obj *abo, bool use_vmap) 28ac49797cSLizhi Hou { 29ac49797cSLizhi Hou struct amdxdna_client *client = abo->client; 30ac49797cSLizhi Hou struct amdxdna_dev *xdna = client->xdna; 31ac49797cSLizhi Hou struct amdxdna_mem *mem = &abo->mem; 32ac49797cSLizhi Hou u64 offset; 33ac49797cSLizhi Hou u32 align; 34ac49797cSLizhi Hou int ret; 35ac49797cSLizhi Hou 36ac49797cSLizhi Hou align = 1 << max(PAGE_SHIFT, xdna->dev_info->dev_mem_buf_shift); 37ac49797cSLizhi Hou ret = drm_mm_insert_node_generic(&abo->dev_heap->mm, &abo->mm_node, 38ac49797cSLizhi Hou mem->size, align, 39ac49797cSLizhi Hou 0, DRM_MM_INSERT_BEST); 40ac49797cSLizhi Hou if (ret) { 41ac49797cSLizhi Hou XDNA_ERR(xdna, "Failed to alloc dev bo memory, ret %d", ret); 42ac49797cSLizhi Hou return ret; 43ac49797cSLizhi Hou } 44ac49797cSLizhi Hou 45ac49797cSLizhi Hou mem->dev_addr = abo->mm_node.start; 46ac49797cSLizhi Hou offset = mem->dev_addr - abo->dev_heap->mem.dev_addr; 47ac49797cSLizhi Hou mem->userptr = abo->dev_heap->mem.userptr + offset; 48ac49797cSLizhi Hou mem->pages = &abo->dev_heap->base.pages[offset >> PAGE_SHIFT]; 49ac49797cSLizhi Hou mem->nr_pages = mem->size >> PAGE_SHIFT; 50ac49797cSLizhi Hou 51ac49797cSLizhi Hou if (use_vmap) { 52ac49797cSLizhi Hou mem->kva = vmap(mem->pages, mem->nr_pages, VM_MAP, PAGE_KERNEL); 53ac49797cSLizhi Hou if (!mem->kva) { 54ac49797cSLizhi Hou XDNA_ERR(xdna, "Failed to vmap"); 55ac49797cSLizhi Hou drm_mm_remove_node(&abo->mm_node); 56ac49797cSLizhi Hou return -EFAULT; 57ac49797cSLizhi Hou } 58ac49797cSLizhi Hou } 59ac49797cSLizhi Hou 60ac49797cSLizhi Hou return 0; 61ac49797cSLizhi Hou } 62ac49797cSLizhi Hou 63*e486147cSLizhi Hou static bool amdxdna_hmm_invalidate(struct mmu_interval_notifier *mni, 64*e486147cSLizhi Hou const struct mmu_notifier_range *range, 65*e486147cSLizhi Hou unsigned long cur_seq) 66*e486147cSLizhi Hou { 67*e486147cSLizhi Hou struct amdxdna_umap *mapp = container_of(mni, struct amdxdna_umap, notifier); 68*e486147cSLizhi Hou struct amdxdna_gem_obj *abo = mapp->abo; 69*e486147cSLizhi Hou struct amdxdna_dev *xdna; 70*e486147cSLizhi Hou 71*e486147cSLizhi Hou xdna = to_xdna_dev(to_gobj(abo)->dev); 72*e486147cSLizhi Hou XDNA_DBG(xdna, "Invalidating range 0x%lx, 0x%lx, type %d", 73*e486147cSLizhi Hou mapp->vma->vm_start, mapp->vma->vm_end, abo->type); 74*e486147cSLizhi Hou 75*e486147cSLizhi Hou if (!mmu_notifier_range_blockable(range)) 76*e486147cSLizhi Hou return false; 77*e486147cSLizhi Hou 78*e486147cSLizhi Hou down_write(&xdna->notifier_lock); 79*e486147cSLizhi Hou abo->mem.map_invalid = true; 80*e486147cSLizhi Hou mapp->invalid = true; 81*e486147cSLizhi Hou mmu_interval_set_seq(&mapp->notifier, cur_seq); 82*e486147cSLizhi Hou up_write(&xdna->notifier_lock); 83*e486147cSLizhi Hou 84*e486147cSLizhi Hou xdna->dev_info->ops->hmm_invalidate(abo, cur_seq); 85*e486147cSLizhi Hou 86*e486147cSLizhi Hou if (range->event == MMU_NOTIFY_UNMAP) { 87*e486147cSLizhi Hou down_write(&xdna->notifier_lock); 88*e486147cSLizhi Hou if (!mapp->unmapped) { 89*e486147cSLizhi Hou queue_work(xdna->notifier_wq, &mapp->hmm_unreg_work); 90*e486147cSLizhi Hou mapp->unmapped = true; 91*e486147cSLizhi Hou } 92*e486147cSLizhi Hou up_write(&xdna->notifier_lock); 93*e486147cSLizhi Hou } 94*e486147cSLizhi Hou 95*e486147cSLizhi Hou return true; 96*e486147cSLizhi Hou } 97*e486147cSLizhi Hou 98*e486147cSLizhi Hou static const struct mmu_interval_notifier_ops amdxdna_hmm_ops = { 99*e486147cSLizhi Hou .invalidate = amdxdna_hmm_invalidate, 100*e486147cSLizhi Hou }; 101*e486147cSLizhi Hou 102*e486147cSLizhi Hou static void amdxdna_hmm_unregister(struct amdxdna_gem_obj *abo, 103*e486147cSLizhi Hou struct vm_area_struct *vma) 104*e486147cSLizhi Hou { 105*e486147cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev); 106*e486147cSLizhi Hou struct amdxdna_umap *mapp; 107*e486147cSLizhi Hou 108*e486147cSLizhi Hou down_read(&xdna->notifier_lock); 109*e486147cSLizhi Hou list_for_each_entry(mapp, &abo->mem.umap_list, node) { 110*e486147cSLizhi Hou if (!vma || mapp->vma == vma) { 111*e486147cSLizhi Hou if (!mapp->unmapped) { 112*e486147cSLizhi Hou queue_work(xdna->notifier_wq, &mapp->hmm_unreg_work); 113*e486147cSLizhi Hou mapp->unmapped = true; 114*e486147cSLizhi Hou } 115*e486147cSLizhi Hou if (vma) 116*e486147cSLizhi Hou break; 117*e486147cSLizhi Hou } 118*e486147cSLizhi Hou } 119*e486147cSLizhi Hou up_read(&xdna->notifier_lock); 120*e486147cSLizhi Hou } 121*e486147cSLizhi Hou 122*e486147cSLizhi Hou static void amdxdna_umap_release(struct kref *ref) 123*e486147cSLizhi Hou { 124*e486147cSLizhi Hou struct amdxdna_umap *mapp = container_of(ref, struct amdxdna_umap, refcnt); 125*e486147cSLizhi Hou struct vm_area_struct *vma = mapp->vma; 126*e486147cSLizhi Hou struct amdxdna_dev *xdna; 127*e486147cSLizhi Hou 128*e486147cSLizhi Hou mmu_interval_notifier_remove(&mapp->notifier); 129*e486147cSLizhi Hou if (is_import_bo(mapp->abo) && vma->vm_file && vma->vm_file->f_mapping) 130*e486147cSLizhi Hou mapping_clear_unevictable(vma->vm_file->f_mapping); 131*e486147cSLizhi Hou 132*e486147cSLizhi Hou xdna = to_xdna_dev(to_gobj(mapp->abo)->dev); 133*e486147cSLizhi Hou down_write(&xdna->notifier_lock); 134*e486147cSLizhi Hou list_del(&mapp->node); 135*e486147cSLizhi Hou up_write(&xdna->notifier_lock); 136*e486147cSLizhi Hou 137*e486147cSLizhi Hou kvfree(mapp->range.hmm_pfns); 138*e486147cSLizhi Hou kfree(mapp); 139*e486147cSLizhi Hou } 140*e486147cSLizhi Hou 141*e486147cSLizhi Hou void amdxdna_umap_put(struct amdxdna_umap *mapp) 142*e486147cSLizhi Hou { 143*e486147cSLizhi Hou kref_put(&mapp->refcnt, amdxdna_umap_release); 144*e486147cSLizhi Hou } 145*e486147cSLizhi Hou 146*e486147cSLizhi Hou static void amdxdna_hmm_unreg_work(struct work_struct *work) 147*e486147cSLizhi Hou { 148*e486147cSLizhi Hou struct amdxdna_umap *mapp = container_of(work, struct amdxdna_umap, 149*e486147cSLizhi Hou hmm_unreg_work); 150*e486147cSLizhi Hou 151*e486147cSLizhi Hou amdxdna_umap_put(mapp); 152*e486147cSLizhi Hou } 153*e486147cSLizhi Hou 154*e486147cSLizhi Hou static int amdxdna_hmm_register(struct amdxdna_gem_obj *abo, 155*e486147cSLizhi Hou struct vm_area_struct *vma) 156*e486147cSLizhi Hou { 157*e486147cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev); 158*e486147cSLizhi Hou unsigned long len = vma->vm_end - vma->vm_start; 159*e486147cSLizhi Hou unsigned long addr = vma->vm_start; 160*e486147cSLizhi Hou struct amdxdna_umap *mapp; 161*e486147cSLizhi Hou u32 nr_pages; 162*e486147cSLizhi Hou int ret; 163*e486147cSLizhi Hou 164*e486147cSLizhi Hou if (!xdna->dev_info->ops->hmm_invalidate) 165*e486147cSLizhi Hou return 0; 166*e486147cSLizhi Hou 167*e486147cSLizhi Hou mapp = kzalloc(sizeof(*mapp), GFP_KERNEL); 168*e486147cSLizhi Hou if (!mapp) 169*e486147cSLizhi Hou return -ENOMEM; 170*e486147cSLizhi Hou 171*e486147cSLizhi Hou nr_pages = (PAGE_ALIGN(addr + len) - (addr & PAGE_MASK)) >> PAGE_SHIFT; 172*e486147cSLizhi Hou mapp->range.hmm_pfns = kvcalloc(nr_pages, sizeof(*mapp->range.hmm_pfns), 173*e486147cSLizhi Hou GFP_KERNEL); 174*e486147cSLizhi Hou if (!mapp->range.hmm_pfns) { 175*e486147cSLizhi Hou ret = -ENOMEM; 176*e486147cSLizhi Hou goto free_map; 177*e486147cSLizhi Hou } 178*e486147cSLizhi Hou 179*e486147cSLizhi Hou ret = mmu_interval_notifier_insert_locked(&mapp->notifier, 180*e486147cSLizhi Hou current->mm, 181*e486147cSLizhi Hou addr, 182*e486147cSLizhi Hou len, 183*e486147cSLizhi Hou &amdxdna_hmm_ops); 184*e486147cSLizhi Hou if (ret) { 185*e486147cSLizhi Hou XDNA_ERR(xdna, "Insert mmu notifier failed, ret %d", ret); 186*e486147cSLizhi Hou goto free_pfns; 187*e486147cSLizhi Hou } 188*e486147cSLizhi Hou 189*e486147cSLizhi Hou mapp->range.notifier = &mapp->notifier; 190*e486147cSLizhi Hou mapp->range.start = vma->vm_start; 191*e486147cSLizhi Hou mapp->range.end = vma->vm_end; 192*e486147cSLizhi Hou mapp->range.default_flags = HMM_PFN_REQ_FAULT; 193*e486147cSLizhi Hou mapp->vma = vma; 194*e486147cSLizhi Hou mapp->abo = abo; 195*e486147cSLizhi Hou kref_init(&mapp->refcnt); 196*e486147cSLizhi Hou 197*e486147cSLizhi Hou if (abo->mem.userptr == AMDXDNA_INVALID_ADDR) 198*e486147cSLizhi Hou abo->mem.userptr = addr; 199*e486147cSLizhi Hou INIT_WORK(&mapp->hmm_unreg_work, amdxdna_hmm_unreg_work); 200*e486147cSLizhi Hou if (is_import_bo(abo) && vma->vm_file && vma->vm_file->f_mapping) 201*e486147cSLizhi Hou mapping_set_unevictable(vma->vm_file->f_mapping); 202*e486147cSLizhi Hou 203*e486147cSLizhi Hou down_write(&xdna->notifier_lock); 204*e486147cSLizhi Hou list_add_tail(&mapp->node, &abo->mem.umap_list); 205*e486147cSLizhi Hou up_write(&xdna->notifier_lock); 206*e486147cSLizhi Hou 207*e486147cSLizhi Hou return 0; 208*e486147cSLizhi Hou 209*e486147cSLizhi Hou free_pfns: 210*e486147cSLizhi Hou kvfree(mapp->range.hmm_pfns); 211*e486147cSLizhi Hou free_map: 212*e486147cSLizhi Hou kfree(mapp); 213*e486147cSLizhi Hou return ret; 214*e486147cSLizhi Hou } 215*e486147cSLizhi Hou 216*e486147cSLizhi Hou static int amdxdna_insert_pages(struct amdxdna_gem_obj *abo, 217*e486147cSLizhi Hou struct vm_area_struct *vma) 218*e486147cSLizhi Hou { 219*e486147cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev); 220*e486147cSLizhi Hou unsigned long num_pages = vma_pages(vma); 221*e486147cSLizhi Hou unsigned long offset = 0; 222*e486147cSLizhi Hou int ret; 223*e486147cSLizhi Hou 224*e486147cSLizhi Hou if (!is_import_bo(abo)) { 225*e486147cSLizhi Hou ret = drm_gem_shmem_mmap(&abo->base, vma); 226*e486147cSLizhi Hou if (ret) { 227*e486147cSLizhi Hou XDNA_ERR(xdna, "Failed shmem mmap %d", ret); 228*e486147cSLizhi Hou return ret; 229*e486147cSLizhi Hou } 230*e486147cSLizhi Hou 231*e486147cSLizhi Hou /* The buffer is based on memory pages. Fix the flag. */ 232*e486147cSLizhi Hou vm_flags_mod(vma, VM_MIXEDMAP, VM_PFNMAP); 233*e486147cSLizhi Hou ret = vm_insert_pages(vma, vma->vm_start, abo->base.pages, 234*e486147cSLizhi Hou &num_pages); 235*e486147cSLizhi Hou if (ret) { 236*e486147cSLizhi Hou XDNA_ERR(xdna, "Failed insert pages %d", ret); 237*e486147cSLizhi Hou vma->vm_ops->close(vma); 238*e486147cSLizhi Hou return ret; 239*e486147cSLizhi Hou } 240*e486147cSLizhi Hou 241*e486147cSLizhi Hou return 0; 242*e486147cSLizhi Hou } 243*e486147cSLizhi Hou 244*e486147cSLizhi Hou vma->vm_private_data = NULL; 245*e486147cSLizhi Hou vma->vm_ops = NULL; 246*e486147cSLizhi Hou ret = dma_buf_mmap(to_gobj(abo)->dma_buf, vma, 0); 247*e486147cSLizhi Hou if (ret) { 248*e486147cSLizhi Hou XDNA_ERR(xdna, "Failed to mmap dma buf %d", ret); 249*e486147cSLizhi Hou return ret; 250*e486147cSLizhi Hou } 251*e486147cSLizhi Hou 252*e486147cSLizhi Hou do { 253*e486147cSLizhi Hou vm_fault_t fault_ret; 254*e486147cSLizhi Hou 255*e486147cSLizhi Hou fault_ret = handle_mm_fault(vma, vma->vm_start + offset, 256*e486147cSLizhi Hou FAULT_FLAG_WRITE, NULL); 257*e486147cSLizhi Hou if (fault_ret & VM_FAULT_ERROR) { 258*e486147cSLizhi Hou vma->vm_ops->close(vma); 259*e486147cSLizhi Hou XDNA_ERR(xdna, "Fault in page failed"); 260*e486147cSLizhi Hou return -EFAULT; 261*e486147cSLizhi Hou } 262*e486147cSLizhi Hou 263*e486147cSLizhi Hou offset += PAGE_SIZE; 264*e486147cSLizhi Hou } while (--num_pages); 265*e486147cSLizhi Hou 266*e486147cSLizhi Hou /* Drop the reference drm_gem_mmap_obj() acquired.*/ 267*e486147cSLizhi Hou drm_gem_object_put(to_gobj(abo)); 268*e486147cSLizhi Hou 269*e486147cSLizhi Hou return 0; 270*e486147cSLizhi Hou } 271*e486147cSLizhi Hou 272*e486147cSLizhi Hou static int amdxdna_gem_obj_mmap(struct drm_gem_object *gobj, 273*e486147cSLizhi Hou struct vm_area_struct *vma) 274*e486147cSLizhi Hou { 275*e486147cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev); 276*e486147cSLizhi Hou struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); 277*e486147cSLizhi Hou int ret; 278*e486147cSLizhi Hou 279*e486147cSLizhi Hou ret = amdxdna_hmm_register(abo, vma); 280*e486147cSLizhi Hou if (ret) 281*e486147cSLizhi Hou return ret; 282*e486147cSLizhi Hou 283*e486147cSLizhi Hou ret = amdxdna_insert_pages(abo, vma); 284*e486147cSLizhi Hou if (ret) { 285*e486147cSLizhi Hou XDNA_ERR(xdna, "Failed insert pages, ret %d", ret); 286*e486147cSLizhi Hou goto hmm_unreg; 287*e486147cSLizhi Hou } 288*e486147cSLizhi Hou 289*e486147cSLizhi Hou XDNA_DBG(xdna, "BO map_offset 0x%llx type %d userptr 0x%lx size 0x%lx", 290*e486147cSLizhi Hou drm_vma_node_offset_addr(&gobj->vma_node), abo->type, 291*e486147cSLizhi Hou vma->vm_start, gobj->size); 292*e486147cSLizhi Hou return 0; 293*e486147cSLizhi Hou 294*e486147cSLizhi Hou hmm_unreg: 295*e486147cSLizhi Hou amdxdna_hmm_unregister(abo, vma); 296*e486147cSLizhi Hou return ret; 297*e486147cSLizhi Hou } 298*e486147cSLizhi Hou 299*e486147cSLizhi Hou static int amdxdna_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) 300*e486147cSLizhi Hou { 301*e486147cSLizhi Hou struct drm_gem_object *gobj = dma_buf->priv; 302*e486147cSLizhi Hou struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); 303*e486147cSLizhi Hou unsigned long num_pages = vma_pages(vma); 304*e486147cSLizhi Hou int ret; 305*e486147cSLizhi Hou 306*e486147cSLizhi Hou vma->vm_ops = &drm_gem_shmem_vm_ops; 307*e486147cSLizhi Hou vma->vm_private_data = gobj; 308*e486147cSLizhi Hou 309*e486147cSLizhi Hou drm_gem_object_get(gobj); 310*e486147cSLizhi Hou ret = drm_gem_shmem_mmap(&abo->base, vma); 311*e486147cSLizhi Hou if (ret) 312*e486147cSLizhi Hou goto put_obj; 313*e486147cSLizhi Hou 314*e486147cSLizhi Hou /* The buffer is based on memory pages. Fix the flag. */ 315*e486147cSLizhi Hou vm_flags_mod(vma, VM_MIXEDMAP, VM_PFNMAP); 316*e486147cSLizhi Hou ret = vm_insert_pages(vma, vma->vm_start, abo->base.pages, 317*e486147cSLizhi Hou &num_pages); 318*e486147cSLizhi Hou if (ret) 319*e486147cSLizhi Hou goto close_vma; 320*e486147cSLizhi Hou 321*e486147cSLizhi Hou return 0; 322*e486147cSLizhi Hou 323*e486147cSLizhi Hou close_vma: 324*e486147cSLizhi Hou vma->vm_ops->close(vma); 325*e486147cSLizhi Hou put_obj: 326*e486147cSLizhi Hou drm_gem_object_put(gobj); 327*e486147cSLizhi Hou return ret; 328*e486147cSLizhi Hou } 329*e486147cSLizhi Hou 330*e486147cSLizhi Hou static const struct dma_buf_ops amdxdna_dmabuf_ops = { 331*e486147cSLizhi Hou .attach = drm_gem_map_attach, 332*e486147cSLizhi Hou .detach = drm_gem_map_detach, 333*e486147cSLizhi Hou .map_dma_buf = drm_gem_map_dma_buf, 334*e486147cSLizhi Hou .unmap_dma_buf = drm_gem_unmap_dma_buf, 335*e486147cSLizhi Hou .release = drm_gem_dmabuf_release, 336*e486147cSLizhi Hou .mmap = amdxdna_gem_dmabuf_mmap, 337*e486147cSLizhi Hou .vmap = drm_gem_dmabuf_vmap, 338*e486147cSLizhi Hou .vunmap = drm_gem_dmabuf_vunmap, 339*e486147cSLizhi Hou }; 340*e486147cSLizhi Hou 341*e486147cSLizhi Hou static struct dma_buf *amdxdna_gem_prime_export(struct drm_gem_object *gobj, int flags) 342*e486147cSLizhi Hou { 343*e486147cSLizhi Hou DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 344*e486147cSLizhi Hou 345*e486147cSLizhi Hou exp_info.ops = &amdxdna_dmabuf_ops; 346*e486147cSLizhi Hou exp_info.size = gobj->size; 347*e486147cSLizhi Hou exp_info.flags = flags; 348*e486147cSLizhi Hou exp_info.priv = gobj; 349*e486147cSLizhi Hou exp_info.resv = gobj->resv; 350*e486147cSLizhi Hou 351*e486147cSLizhi Hou return drm_gem_dmabuf_export(gobj->dev, &exp_info); 352*e486147cSLizhi Hou } 353*e486147cSLizhi Hou 354*e486147cSLizhi Hou static void amdxdna_imported_obj_free(struct amdxdna_gem_obj *abo) 355*e486147cSLizhi Hou { 356*e486147cSLizhi Hou dma_buf_unmap_attachment_unlocked(abo->attach, abo->base.sgt, DMA_BIDIRECTIONAL); 357*e486147cSLizhi Hou dma_buf_detach(abo->dma_buf, abo->attach); 358*e486147cSLizhi Hou dma_buf_put(abo->dma_buf); 359*e486147cSLizhi Hou drm_gem_object_release(to_gobj(abo)); 360*e486147cSLizhi Hou kfree(abo); 361*e486147cSLizhi Hou } 362*e486147cSLizhi Hou 363ac49797cSLizhi Hou static void amdxdna_gem_obj_free(struct drm_gem_object *gobj) 364ac49797cSLizhi Hou { 365ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev); 366ac49797cSLizhi Hou struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); 367ac49797cSLizhi Hou struct iosys_map map = IOSYS_MAP_INIT_VADDR(abo->mem.kva); 368ac49797cSLizhi Hou 369ac49797cSLizhi Hou XDNA_DBG(xdna, "BO type %d xdna_addr 0x%llx", abo->type, abo->mem.dev_addr); 370*e486147cSLizhi Hou 371*e486147cSLizhi Hou amdxdna_hmm_unregister(abo, NULL); 372*e486147cSLizhi Hou flush_workqueue(xdna->notifier_wq); 373*e486147cSLizhi Hou 374ac49797cSLizhi Hou if (abo->pinned) 375ac49797cSLizhi Hou amdxdna_gem_unpin(abo); 376ac49797cSLizhi Hou 377ac49797cSLizhi Hou if (abo->type == AMDXDNA_BO_DEV) { 378ac49797cSLizhi Hou mutex_lock(&abo->client->mm_lock); 379ac49797cSLizhi Hou drm_mm_remove_node(&abo->mm_node); 380ac49797cSLizhi Hou mutex_unlock(&abo->client->mm_lock); 381ac49797cSLizhi Hou 382ac49797cSLizhi Hou vunmap(abo->mem.kva); 383ac49797cSLizhi Hou drm_gem_object_put(to_gobj(abo->dev_heap)); 384ac49797cSLizhi Hou drm_gem_object_release(gobj); 385ac49797cSLizhi Hou mutex_destroy(&abo->lock); 386ac49797cSLizhi Hou kfree(abo); 387ac49797cSLizhi Hou return; 388ac49797cSLizhi Hou } 389ac49797cSLizhi Hou 390ac49797cSLizhi Hou if (abo->type == AMDXDNA_BO_DEV_HEAP) 391ac49797cSLizhi Hou drm_mm_takedown(&abo->mm); 392ac49797cSLizhi Hou 393a600794aSBoris Brezillon drm_gem_vunmap(gobj, &map); 394ac49797cSLizhi Hou mutex_destroy(&abo->lock); 395*e486147cSLizhi Hou 396*e486147cSLizhi Hou if (is_import_bo(abo)) { 397*e486147cSLizhi Hou amdxdna_imported_obj_free(abo); 398*e486147cSLizhi Hou return; 399*e486147cSLizhi Hou } 400*e486147cSLizhi Hou 401ac49797cSLizhi Hou drm_gem_shmem_free(&abo->base); 402ac49797cSLizhi Hou } 403ac49797cSLizhi Hou 404ac49797cSLizhi Hou static const struct drm_gem_object_funcs amdxdna_gem_dev_obj_funcs = { 405ac49797cSLizhi Hou .free = amdxdna_gem_obj_free, 406ac49797cSLizhi Hou }; 407ac49797cSLizhi Hou 408ac49797cSLizhi Hou static const struct drm_gem_object_funcs amdxdna_gem_shmem_funcs = { 409ac49797cSLizhi Hou .free = amdxdna_gem_obj_free, 410ac49797cSLizhi Hou .print_info = drm_gem_shmem_object_print_info, 411ac49797cSLizhi Hou .pin = drm_gem_shmem_object_pin, 412ac49797cSLizhi Hou .unpin = drm_gem_shmem_object_unpin, 413ac49797cSLizhi Hou .get_sg_table = drm_gem_shmem_object_get_sg_table, 414ac49797cSLizhi Hou .vmap = drm_gem_shmem_object_vmap, 415ac49797cSLizhi Hou .vunmap = drm_gem_shmem_object_vunmap, 416ac49797cSLizhi Hou .mmap = amdxdna_gem_obj_mmap, 417*e486147cSLizhi Hou .vm_ops = &drm_gem_shmem_vm_ops, 418*e486147cSLizhi Hou .export = amdxdna_gem_prime_export, 419ac49797cSLizhi Hou }; 420ac49797cSLizhi Hou 421ac49797cSLizhi Hou static struct amdxdna_gem_obj * 422ac49797cSLizhi Hou amdxdna_gem_create_obj(struct drm_device *dev, size_t size) 423ac49797cSLizhi Hou { 424ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 425ac49797cSLizhi Hou 426ac49797cSLizhi Hou abo = kzalloc(sizeof(*abo), GFP_KERNEL); 427ac49797cSLizhi Hou if (!abo) 428ac49797cSLizhi Hou return ERR_PTR(-ENOMEM); 429ac49797cSLizhi Hou 430ac49797cSLizhi Hou abo->pinned = false; 431ac49797cSLizhi Hou abo->assigned_hwctx = AMDXDNA_INVALID_CTX_HANDLE; 432ac49797cSLizhi Hou mutex_init(&abo->lock); 433ac49797cSLizhi Hou 434ac49797cSLizhi Hou abo->mem.userptr = AMDXDNA_INVALID_ADDR; 435ac49797cSLizhi Hou abo->mem.dev_addr = AMDXDNA_INVALID_ADDR; 436ac49797cSLizhi Hou abo->mem.size = size; 437*e486147cSLizhi Hou INIT_LIST_HEAD(&abo->mem.umap_list); 438ac49797cSLizhi Hou 439ac49797cSLizhi Hou return abo; 440ac49797cSLizhi Hou } 441ac49797cSLizhi Hou 442ac49797cSLizhi Hou /* For drm_driver->gem_create_object callback */ 443ac49797cSLizhi Hou struct drm_gem_object * 444ac49797cSLizhi Hou amdxdna_gem_create_object_cb(struct drm_device *dev, size_t size) 445ac49797cSLizhi Hou { 446ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 447ac49797cSLizhi Hou 448ac49797cSLizhi Hou abo = amdxdna_gem_create_obj(dev, size); 449ac49797cSLizhi Hou if (IS_ERR(abo)) 450ac49797cSLizhi Hou return ERR_CAST(abo); 451ac49797cSLizhi Hou 452ac49797cSLizhi Hou to_gobj(abo)->funcs = &amdxdna_gem_shmem_funcs; 453ac49797cSLizhi Hou 454ac49797cSLizhi Hou return to_gobj(abo); 455ac49797cSLizhi Hou } 456ac49797cSLizhi Hou 457*e486147cSLizhi Hou struct drm_gem_object * 458*e486147cSLizhi Hou amdxdna_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf) 459*e486147cSLizhi Hou { 460*e486147cSLizhi Hou struct dma_buf_attachment *attach; 461*e486147cSLizhi Hou struct amdxdna_gem_obj *abo; 462*e486147cSLizhi Hou struct drm_gem_object *gobj; 463*e486147cSLizhi Hou struct sg_table *sgt; 464*e486147cSLizhi Hou int ret; 465*e486147cSLizhi Hou 466*e486147cSLizhi Hou get_dma_buf(dma_buf); 467*e486147cSLizhi Hou 468*e486147cSLizhi Hou attach = dma_buf_attach(dma_buf, dev->dev); 469*e486147cSLizhi Hou if (IS_ERR(attach)) { 470*e486147cSLizhi Hou ret = PTR_ERR(attach); 471*e486147cSLizhi Hou goto put_buf; 472*e486147cSLizhi Hou } 473*e486147cSLizhi Hou 474*e486147cSLizhi Hou sgt = dma_buf_map_attachment_unlocked(attach, DMA_BIDIRECTIONAL); 475*e486147cSLizhi Hou if (IS_ERR(sgt)) { 476*e486147cSLizhi Hou ret = PTR_ERR(sgt); 477*e486147cSLizhi Hou goto fail_detach; 478*e486147cSLizhi Hou } 479*e486147cSLizhi Hou 480*e486147cSLizhi Hou gobj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt); 481*e486147cSLizhi Hou if (IS_ERR(gobj)) { 482*e486147cSLizhi Hou ret = PTR_ERR(gobj); 483*e486147cSLizhi Hou goto fail_unmap; 484*e486147cSLizhi Hou } 485*e486147cSLizhi Hou 486*e486147cSLizhi Hou abo = to_xdna_obj(gobj); 487*e486147cSLizhi Hou abo->attach = attach; 488*e486147cSLizhi Hou abo->dma_buf = dma_buf; 489*e486147cSLizhi Hou 490*e486147cSLizhi Hou return gobj; 491*e486147cSLizhi Hou 492*e486147cSLizhi Hou fail_unmap: 493*e486147cSLizhi Hou dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_BIDIRECTIONAL); 494*e486147cSLizhi Hou fail_detach: 495*e486147cSLizhi Hou dma_buf_detach(dma_buf, attach); 496*e486147cSLizhi Hou put_buf: 497*e486147cSLizhi Hou dma_buf_put(dma_buf); 498*e486147cSLizhi Hou 499*e486147cSLizhi Hou return ERR_PTR(ret); 500*e486147cSLizhi Hou } 501*e486147cSLizhi Hou 502ac49797cSLizhi Hou static struct amdxdna_gem_obj * 503ac49797cSLizhi Hou amdxdna_drm_alloc_shmem(struct drm_device *dev, 504ac49797cSLizhi Hou struct amdxdna_drm_create_bo *args, 505ac49797cSLizhi Hou struct drm_file *filp) 506ac49797cSLizhi Hou { 507ac49797cSLizhi Hou struct amdxdna_client *client = filp->driver_priv; 508ac49797cSLizhi Hou struct drm_gem_shmem_object *shmem; 509ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 510ac49797cSLizhi Hou 511ac49797cSLizhi Hou shmem = drm_gem_shmem_create(dev, args->size); 512ac49797cSLizhi Hou if (IS_ERR(shmem)) 513ac49797cSLizhi Hou return ERR_CAST(shmem); 514ac49797cSLizhi Hou 515ac49797cSLizhi Hou shmem->map_wc = false; 516ac49797cSLizhi Hou 517ac49797cSLizhi Hou abo = to_xdna_obj(&shmem->base); 518ac49797cSLizhi Hou abo->client = client; 519ac49797cSLizhi Hou abo->type = AMDXDNA_BO_SHMEM; 520ac49797cSLizhi Hou 521ac49797cSLizhi Hou return abo; 522ac49797cSLizhi Hou } 523ac49797cSLizhi Hou 524ac49797cSLizhi Hou static struct amdxdna_gem_obj * 525ac49797cSLizhi Hou amdxdna_drm_create_dev_heap(struct drm_device *dev, 526ac49797cSLizhi Hou struct amdxdna_drm_create_bo *args, 527ac49797cSLizhi Hou struct drm_file *filp) 528ac49797cSLizhi Hou { 529ac49797cSLizhi Hou struct amdxdna_client *client = filp->driver_priv; 530ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(dev); 531ac49797cSLizhi Hou struct drm_gem_shmem_object *shmem; 532ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 533ac49797cSLizhi Hou int ret; 534ac49797cSLizhi Hou 535ac49797cSLizhi Hou if (args->size > xdna->dev_info->dev_mem_size) { 536ac49797cSLizhi Hou XDNA_DBG(xdna, "Invalid dev heap size 0x%llx, limit 0x%lx", 537ac49797cSLizhi Hou args->size, xdna->dev_info->dev_mem_size); 538ac49797cSLizhi Hou return ERR_PTR(-EINVAL); 539ac49797cSLizhi Hou } 540ac49797cSLizhi Hou 541ac49797cSLizhi Hou mutex_lock(&client->mm_lock); 542ac49797cSLizhi Hou if (client->dev_heap) { 543ac49797cSLizhi Hou XDNA_DBG(client->xdna, "dev heap is already created"); 544ac49797cSLizhi Hou ret = -EBUSY; 545ac49797cSLizhi Hou goto mm_unlock; 546ac49797cSLizhi Hou } 547ac49797cSLizhi Hou 548ac49797cSLizhi Hou shmem = drm_gem_shmem_create(dev, args->size); 549ac49797cSLizhi Hou if (IS_ERR(shmem)) { 550ac49797cSLizhi Hou ret = PTR_ERR(shmem); 551ac49797cSLizhi Hou goto mm_unlock; 552ac49797cSLizhi Hou } 553ac49797cSLizhi Hou 554ac49797cSLizhi Hou shmem->map_wc = false; 555ac49797cSLizhi Hou abo = to_xdna_obj(&shmem->base); 556ac49797cSLizhi Hou 557ac49797cSLizhi Hou abo->type = AMDXDNA_BO_DEV_HEAP; 558ac49797cSLizhi Hou abo->client = client; 559ac49797cSLizhi Hou abo->mem.dev_addr = client->xdna->dev_info->dev_mem_base; 560ac49797cSLizhi Hou drm_mm_init(&abo->mm, abo->mem.dev_addr, abo->mem.size); 561ac49797cSLizhi Hou 562ac49797cSLizhi Hou client->dev_heap = abo; 563ac49797cSLizhi Hou drm_gem_object_get(to_gobj(abo)); 564ac49797cSLizhi Hou mutex_unlock(&client->mm_lock); 565ac49797cSLizhi Hou 566ac49797cSLizhi Hou return abo; 567ac49797cSLizhi Hou 568ac49797cSLizhi Hou mm_unlock: 569ac49797cSLizhi Hou mutex_unlock(&client->mm_lock); 570ac49797cSLizhi Hou return ERR_PTR(ret); 571ac49797cSLizhi Hou } 572ac49797cSLizhi Hou 573ac49797cSLizhi Hou struct amdxdna_gem_obj * 574ac49797cSLizhi Hou amdxdna_drm_alloc_dev_bo(struct drm_device *dev, 575ac49797cSLizhi Hou struct amdxdna_drm_create_bo *args, 576ac49797cSLizhi Hou struct drm_file *filp, bool use_vmap) 577ac49797cSLizhi Hou { 578ac49797cSLizhi Hou struct amdxdna_client *client = filp->driver_priv; 579ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(dev); 580ac49797cSLizhi Hou size_t aligned_sz = PAGE_ALIGN(args->size); 581ac49797cSLizhi Hou struct amdxdna_gem_obj *abo, *heap; 582ac49797cSLizhi Hou int ret; 583ac49797cSLizhi Hou 584ac49797cSLizhi Hou mutex_lock(&client->mm_lock); 585ac49797cSLizhi Hou heap = client->dev_heap; 586ac49797cSLizhi Hou if (!heap) { 587ac49797cSLizhi Hou ret = -EINVAL; 588ac49797cSLizhi Hou goto mm_unlock; 589ac49797cSLizhi Hou } 590ac49797cSLizhi Hou 591ac49797cSLizhi Hou if (heap->mem.userptr == AMDXDNA_INVALID_ADDR) { 592ac49797cSLizhi Hou XDNA_ERR(xdna, "Invalid dev heap userptr"); 593ac49797cSLizhi Hou ret = -EINVAL; 594ac49797cSLizhi Hou goto mm_unlock; 595ac49797cSLizhi Hou } 596ac49797cSLizhi Hou 597ac49797cSLizhi Hou if (args->size > heap->mem.size) { 598ac49797cSLizhi Hou XDNA_ERR(xdna, "Invalid dev bo size 0x%llx, limit 0x%lx", 599ac49797cSLizhi Hou args->size, heap->mem.size); 600ac49797cSLizhi Hou ret = -EINVAL; 601ac49797cSLizhi Hou goto mm_unlock; 602ac49797cSLizhi Hou } 603ac49797cSLizhi Hou 604ac49797cSLizhi Hou abo = amdxdna_gem_create_obj(&xdna->ddev, aligned_sz); 605ac49797cSLizhi Hou if (IS_ERR(abo)) { 606ac49797cSLizhi Hou ret = PTR_ERR(abo); 607ac49797cSLizhi Hou goto mm_unlock; 608ac49797cSLizhi Hou } 609ac49797cSLizhi Hou to_gobj(abo)->funcs = &amdxdna_gem_dev_obj_funcs; 610ac49797cSLizhi Hou abo->type = AMDXDNA_BO_DEV; 611ac49797cSLizhi Hou abo->client = client; 612ac49797cSLizhi Hou abo->dev_heap = heap; 613ac49797cSLizhi Hou ret = amdxdna_gem_insert_node_locked(abo, use_vmap); 614ac49797cSLizhi Hou if (ret) { 615ac49797cSLizhi Hou XDNA_ERR(xdna, "Failed to alloc dev bo memory, ret %d", ret); 616ac49797cSLizhi Hou goto mm_unlock; 617ac49797cSLizhi Hou } 618ac49797cSLizhi Hou 619ac49797cSLizhi Hou drm_gem_object_get(to_gobj(heap)); 620ac49797cSLizhi Hou drm_gem_private_object_init(&xdna->ddev, to_gobj(abo), aligned_sz); 621ac49797cSLizhi Hou 622ac49797cSLizhi Hou mutex_unlock(&client->mm_lock); 623ac49797cSLizhi Hou return abo; 624ac49797cSLizhi Hou 625ac49797cSLizhi Hou mm_unlock: 626ac49797cSLizhi Hou mutex_unlock(&client->mm_lock); 627ac49797cSLizhi Hou return ERR_PTR(ret); 628ac49797cSLizhi Hou } 629ac49797cSLizhi Hou 630ac49797cSLizhi Hou static struct amdxdna_gem_obj * 631ac49797cSLizhi Hou amdxdna_drm_create_cmd_bo(struct drm_device *dev, 632ac49797cSLizhi Hou struct amdxdna_drm_create_bo *args, 633ac49797cSLizhi Hou struct drm_file *filp) 634ac49797cSLizhi Hou { 635ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(dev); 636ac49797cSLizhi Hou struct drm_gem_shmem_object *shmem; 637ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 638ac49797cSLizhi Hou struct iosys_map map; 639ac49797cSLizhi Hou int ret; 640ac49797cSLizhi Hou 641ac49797cSLizhi Hou if (args->size > XDNA_MAX_CMD_BO_SIZE) { 642ac49797cSLizhi Hou XDNA_ERR(xdna, "Command bo size 0x%llx too large", args->size); 643ac49797cSLizhi Hou return ERR_PTR(-EINVAL); 644ac49797cSLizhi Hou } 645ac49797cSLizhi Hou 646ac49797cSLizhi Hou if (args->size < sizeof(struct amdxdna_cmd)) { 647ac49797cSLizhi Hou XDNA_DBG(xdna, "Command BO size 0x%llx too small", args->size); 648ac49797cSLizhi Hou return ERR_PTR(-EINVAL); 649ac49797cSLizhi Hou } 650ac49797cSLizhi Hou 651ac49797cSLizhi Hou shmem = drm_gem_shmem_create(dev, args->size); 652ac49797cSLizhi Hou if (IS_ERR(shmem)) 653ac49797cSLizhi Hou return ERR_CAST(shmem); 654ac49797cSLizhi Hou 655ac49797cSLizhi Hou shmem->map_wc = false; 656ac49797cSLizhi Hou abo = to_xdna_obj(&shmem->base); 657ac49797cSLizhi Hou 658ac49797cSLizhi Hou abo->type = AMDXDNA_BO_CMD; 659ac49797cSLizhi Hou abo->client = filp->driver_priv; 660ac49797cSLizhi Hou 661a600794aSBoris Brezillon ret = drm_gem_vmap(to_gobj(abo), &map); 662ac49797cSLizhi Hou if (ret) { 663ac49797cSLizhi Hou XDNA_ERR(xdna, "Vmap cmd bo failed, ret %d", ret); 664ac49797cSLizhi Hou goto release_obj; 665ac49797cSLizhi Hou } 666ac49797cSLizhi Hou abo->mem.kva = map.vaddr; 667ac49797cSLizhi Hou 668ac49797cSLizhi Hou return abo; 669ac49797cSLizhi Hou 670ac49797cSLizhi Hou release_obj: 671ac49797cSLizhi Hou drm_gem_shmem_free(shmem); 672ac49797cSLizhi Hou return ERR_PTR(ret); 673ac49797cSLizhi Hou } 674ac49797cSLizhi Hou 675ac49797cSLizhi Hou int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) 676ac49797cSLizhi Hou { 677ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(dev); 678ac49797cSLizhi Hou struct amdxdna_drm_create_bo *args = data; 679ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 680ac49797cSLizhi Hou int ret; 681ac49797cSLizhi Hou 682ac49797cSLizhi Hou if (args->flags || args->vaddr || !args->size) 683ac49797cSLizhi Hou return -EINVAL; 684ac49797cSLizhi Hou 685ac49797cSLizhi Hou XDNA_DBG(xdna, "BO arg type %d vaddr 0x%llx size 0x%llx flags 0x%llx", 686ac49797cSLizhi Hou args->type, args->vaddr, args->size, args->flags); 687ac49797cSLizhi Hou switch (args->type) { 688ac49797cSLizhi Hou case AMDXDNA_BO_SHMEM: 689ac49797cSLizhi Hou abo = amdxdna_drm_alloc_shmem(dev, args, filp); 690ac49797cSLizhi Hou break; 691ac49797cSLizhi Hou case AMDXDNA_BO_DEV_HEAP: 692ac49797cSLizhi Hou abo = amdxdna_drm_create_dev_heap(dev, args, filp); 693ac49797cSLizhi Hou break; 694ac49797cSLizhi Hou case AMDXDNA_BO_DEV: 695ac49797cSLizhi Hou abo = amdxdna_drm_alloc_dev_bo(dev, args, filp, false); 696ac49797cSLizhi Hou break; 697ac49797cSLizhi Hou case AMDXDNA_BO_CMD: 698ac49797cSLizhi Hou abo = amdxdna_drm_create_cmd_bo(dev, args, filp); 699ac49797cSLizhi Hou break; 700ac49797cSLizhi Hou default: 701ac49797cSLizhi Hou return -EINVAL; 702ac49797cSLizhi Hou } 703ac49797cSLizhi Hou if (IS_ERR(abo)) 704ac49797cSLizhi Hou return PTR_ERR(abo); 705ac49797cSLizhi Hou 706ac49797cSLizhi Hou /* ready to publish object to userspace */ 707ac49797cSLizhi Hou ret = drm_gem_handle_create(filp, to_gobj(abo), &args->handle); 708ac49797cSLizhi Hou if (ret) { 709ac49797cSLizhi Hou XDNA_ERR(xdna, "Create handle failed"); 710ac49797cSLizhi Hou goto put_obj; 711ac49797cSLizhi Hou } 712ac49797cSLizhi Hou 713ac49797cSLizhi Hou XDNA_DBG(xdna, "BO hdl %d type %d userptr 0x%llx xdna_addr 0x%llx size 0x%lx", 714ac49797cSLizhi Hou args->handle, args->type, abo->mem.userptr, 715ac49797cSLizhi Hou abo->mem.dev_addr, abo->mem.size); 716ac49797cSLizhi Hou put_obj: 717ac49797cSLizhi Hou /* Dereference object reference. Handle holds it now. */ 718ac49797cSLizhi Hou drm_gem_object_put(to_gobj(abo)); 719ac49797cSLizhi Hou return ret; 720ac49797cSLizhi Hou } 721ac49797cSLizhi Hou 722ac49797cSLizhi Hou int amdxdna_gem_pin_nolock(struct amdxdna_gem_obj *abo) 723ac49797cSLizhi Hou { 724ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev); 725ac49797cSLizhi Hou int ret; 726ac49797cSLizhi Hou 727*e486147cSLizhi Hou if (is_import_bo(abo)) 728*e486147cSLizhi Hou return 0; 729*e486147cSLizhi Hou 730ac49797cSLizhi Hou switch (abo->type) { 731ac49797cSLizhi Hou case AMDXDNA_BO_SHMEM: 732ac49797cSLizhi Hou case AMDXDNA_BO_DEV_HEAP: 733ac49797cSLizhi Hou ret = drm_gem_shmem_pin(&abo->base); 734ac49797cSLizhi Hou break; 735ac49797cSLizhi Hou case AMDXDNA_BO_DEV: 736ac49797cSLizhi Hou ret = drm_gem_shmem_pin(&abo->dev_heap->base); 737ac49797cSLizhi Hou break; 738ac49797cSLizhi Hou default: 739ac49797cSLizhi Hou ret = -EOPNOTSUPP; 740ac49797cSLizhi Hou } 741ac49797cSLizhi Hou 742ac49797cSLizhi Hou XDNA_DBG(xdna, "BO type %d ret %d", abo->type, ret); 743ac49797cSLizhi Hou return ret; 744ac49797cSLizhi Hou } 745ac49797cSLizhi Hou 746ac49797cSLizhi Hou int amdxdna_gem_pin(struct amdxdna_gem_obj *abo) 747ac49797cSLizhi Hou { 748ac49797cSLizhi Hou int ret; 749ac49797cSLizhi Hou 750ac49797cSLizhi Hou if (abo->type == AMDXDNA_BO_DEV) 751ac49797cSLizhi Hou abo = abo->dev_heap; 752ac49797cSLizhi Hou 753ac49797cSLizhi Hou mutex_lock(&abo->lock); 754ac49797cSLizhi Hou ret = amdxdna_gem_pin_nolock(abo); 755ac49797cSLizhi Hou mutex_unlock(&abo->lock); 756ac49797cSLizhi Hou 757ac49797cSLizhi Hou return ret; 758ac49797cSLizhi Hou } 759ac49797cSLizhi Hou 760ac49797cSLizhi Hou void amdxdna_gem_unpin(struct amdxdna_gem_obj *abo) 761ac49797cSLizhi Hou { 762*e486147cSLizhi Hou if (is_import_bo(abo)) 763*e486147cSLizhi Hou return; 764*e486147cSLizhi Hou 765ac49797cSLizhi Hou if (abo->type == AMDXDNA_BO_DEV) 766ac49797cSLizhi Hou abo = abo->dev_heap; 767ac49797cSLizhi Hou 768ac49797cSLizhi Hou mutex_lock(&abo->lock); 769ac49797cSLizhi Hou drm_gem_shmem_unpin(&abo->base); 770ac49797cSLizhi Hou mutex_unlock(&abo->lock); 771ac49797cSLizhi Hou } 772ac49797cSLizhi Hou 773ac49797cSLizhi Hou struct amdxdna_gem_obj *amdxdna_gem_get_obj(struct amdxdna_client *client, 774ac49797cSLizhi Hou u32 bo_hdl, u8 bo_type) 775ac49797cSLizhi Hou { 776ac49797cSLizhi Hou struct amdxdna_dev *xdna = client->xdna; 777ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 778ac49797cSLizhi Hou struct drm_gem_object *gobj; 779ac49797cSLizhi Hou 780ac49797cSLizhi Hou gobj = drm_gem_object_lookup(client->filp, bo_hdl); 781ac49797cSLizhi Hou if (!gobj) { 782ac49797cSLizhi Hou XDNA_DBG(xdna, "Can not find bo %d", bo_hdl); 783ac49797cSLizhi Hou return NULL; 784ac49797cSLizhi Hou } 785ac49797cSLizhi Hou 786ac49797cSLizhi Hou abo = to_xdna_obj(gobj); 787ac49797cSLizhi Hou if (bo_type == AMDXDNA_BO_INVALID || abo->type == bo_type) 788ac49797cSLizhi Hou return abo; 789ac49797cSLizhi Hou 790ac49797cSLizhi Hou drm_gem_object_put(gobj); 791ac49797cSLizhi Hou return NULL; 792ac49797cSLizhi Hou } 793ac49797cSLizhi Hou 794ac49797cSLizhi Hou int amdxdna_drm_get_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) 795ac49797cSLizhi Hou { 796ac49797cSLizhi Hou struct amdxdna_drm_get_bo_info *args = data; 797ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(dev); 798ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 799ac49797cSLizhi Hou struct drm_gem_object *gobj; 800ac49797cSLizhi Hou int ret = 0; 801ac49797cSLizhi Hou 80203c318a0SLizhi Hou if (args->ext || args->ext_flags || args->pad) 803ac49797cSLizhi Hou return -EINVAL; 804ac49797cSLizhi Hou 805ac49797cSLizhi Hou gobj = drm_gem_object_lookup(filp, args->handle); 806ac49797cSLizhi Hou if (!gobj) { 807ac49797cSLizhi Hou XDNA_DBG(xdna, "Lookup GEM object %d failed", args->handle); 808ac49797cSLizhi Hou return -ENOENT; 809ac49797cSLizhi Hou } 810ac49797cSLizhi Hou 811ac49797cSLizhi Hou abo = to_xdna_obj(gobj); 812ac49797cSLizhi Hou args->vaddr = abo->mem.userptr; 813ac49797cSLizhi Hou args->xdna_addr = abo->mem.dev_addr; 814ac49797cSLizhi Hou 815ac49797cSLizhi Hou if (abo->type != AMDXDNA_BO_DEV) 816ac49797cSLizhi Hou args->map_offset = drm_vma_node_offset_addr(&gobj->vma_node); 817ac49797cSLizhi Hou else 818ac49797cSLizhi Hou args->map_offset = AMDXDNA_INVALID_ADDR; 819ac49797cSLizhi Hou 820ac49797cSLizhi Hou XDNA_DBG(xdna, "BO hdl %d map_offset 0x%llx vaddr 0x%llx xdna_addr 0x%llx", 821ac49797cSLizhi Hou args->handle, args->map_offset, args->vaddr, args->xdna_addr); 822ac49797cSLizhi Hou 823ac49797cSLizhi Hou drm_gem_object_put(gobj); 824ac49797cSLizhi Hou return ret; 825ac49797cSLizhi Hou } 826ac49797cSLizhi Hou 827ac49797cSLizhi Hou /* 828ac49797cSLizhi Hou * The sync bo ioctl is to make sure the CPU cache is in sync with memory. 829ac49797cSLizhi Hou * This is required because NPU is not cache coherent device. CPU cache 830ac49797cSLizhi Hou * flushing/invalidation is expensive so it is best to handle this outside 831ac49797cSLizhi Hou * of the command submission path. This ioctl allows explicit cache 832ac49797cSLizhi Hou * flushing/invalidation outside of the critical path. 833ac49797cSLizhi Hou */ 834ac49797cSLizhi Hou int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev, 835ac49797cSLizhi Hou void *data, struct drm_file *filp) 836ac49797cSLizhi Hou { 837ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(dev); 838ac49797cSLizhi Hou struct amdxdna_drm_sync_bo *args = data; 839ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 840ac49797cSLizhi Hou struct drm_gem_object *gobj; 841ac49797cSLizhi Hou int ret; 842ac49797cSLizhi Hou 843ac49797cSLizhi Hou gobj = drm_gem_object_lookup(filp, args->handle); 844ac49797cSLizhi Hou if (!gobj) { 845ac49797cSLizhi Hou XDNA_ERR(xdna, "Lookup GEM object failed"); 846ac49797cSLizhi Hou return -ENOENT; 847ac49797cSLizhi Hou } 848ac49797cSLizhi Hou abo = to_xdna_obj(gobj); 849ac49797cSLizhi Hou 850ac49797cSLizhi Hou ret = amdxdna_gem_pin(abo); 851ac49797cSLizhi Hou if (ret) { 852ac49797cSLizhi Hou XDNA_ERR(xdna, "Pin BO %d failed, ret %d", args->handle, ret); 853ac49797cSLizhi Hou goto put_obj; 854ac49797cSLizhi Hou } 855ac49797cSLizhi Hou 856*e486147cSLizhi Hou if (is_import_bo(abo)) 857*e486147cSLizhi Hou drm_clflush_sg(abo->base.sgt); 858*e486147cSLizhi Hou else if (abo->type == AMDXDNA_BO_DEV) 859ac49797cSLizhi Hou drm_clflush_pages(abo->mem.pages, abo->mem.nr_pages); 860ac49797cSLizhi Hou else 861ac49797cSLizhi Hou drm_clflush_pages(abo->base.pages, gobj->size >> PAGE_SHIFT); 862ac49797cSLizhi Hou 863ac49797cSLizhi Hou amdxdna_gem_unpin(abo); 864ac49797cSLizhi Hou 865ac49797cSLizhi Hou XDNA_DBG(xdna, "Sync bo %d offset 0x%llx, size 0x%llx\n", 866ac49797cSLizhi Hou args->handle, args->offset, args->size); 867ac49797cSLizhi Hou 868ac49797cSLizhi Hou put_obj: 869ac49797cSLizhi Hou drm_gem_object_put(gobj); 870ac49797cSLizhi Hou return ret; 871ac49797cSLizhi Hou } 872