1*ac49797cSLizhi Hou // SPDX-License-Identifier: GPL-2.0 2*ac49797cSLizhi Hou /* 3*ac49797cSLizhi Hou * Copyright (C) 2024, Advanced Micro Devices, Inc. 4*ac49797cSLizhi Hou */ 5*ac49797cSLizhi Hou 6*ac49797cSLizhi Hou #include <drm/amdxdna_accel.h> 7*ac49797cSLizhi Hou #include <drm/drm_cache.h> 8*ac49797cSLizhi Hou #include <drm/drm_device.h> 9*ac49797cSLizhi Hou #include <drm/drm_gem.h> 10*ac49797cSLizhi Hou #include <drm/drm_gem_shmem_helper.h> 11*ac49797cSLizhi Hou #include <linux/iosys-map.h> 12*ac49797cSLizhi Hou #include <linux/vmalloc.h> 13*ac49797cSLizhi Hou 14*ac49797cSLizhi Hou #include "amdxdna_ctx.h" 15*ac49797cSLizhi Hou #include "amdxdna_gem.h" 16*ac49797cSLizhi Hou #include "amdxdna_pci_drv.h" 17*ac49797cSLizhi Hou 18*ac49797cSLizhi Hou #define XDNA_MAX_CMD_BO_SIZE SZ_32K 19*ac49797cSLizhi Hou 20*ac49797cSLizhi Hou static int 21*ac49797cSLizhi Hou amdxdna_gem_insert_node_locked(struct amdxdna_gem_obj *abo, bool use_vmap) 22*ac49797cSLizhi Hou { 23*ac49797cSLizhi Hou struct amdxdna_client *client = abo->client; 24*ac49797cSLizhi Hou struct amdxdna_dev *xdna = client->xdna; 25*ac49797cSLizhi Hou struct amdxdna_mem *mem = &abo->mem; 26*ac49797cSLizhi Hou u64 offset; 27*ac49797cSLizhi Hou u32 align; 28*ac49797cSLizhi Hou int ret; 29*ac49797cSLizhi Hou 30*ac49797cSLizhi Hou align = 1 << max(PAGE_SHIFT, xdna->dev_info->dev_mem_buf_shift); 31*ac49797cSLizhi Hou ret = drm_mm_insert_node_generic(&abo->dev_heap->mm, &abo->mm_node, 32*ac49797cSLizhi Hou mem->size, align, 33*ac49797cSLizhi Hou 0, DRM_MM_INSERT_BEST); 34*ac49797cSLizhi Hou if (ret) { 35*ac49797cSLizhi Hou XDNA_ERR(xdna, "Failed to alloc dev bo memory, ret %d", ret); 36*ac49797cSLizhi Hou return ret; 37*ac49797cSLizhi Hou } 38*ac49797cSLizhi Hou 39*ac49797cSLizhi Hou mem->dev_addr = abo->mm_node.start; 40*ac49797cSLizhi Hou offset = mem->dev_addr - abo->dev_heap->mem.dev_addr; 41*ac49797cSLizhi Hou mem->userptr = abo->dev_heap->mem.userptr + offset; 42*ac49797cSLizhi Hou mem->pages = &abo->dev_heap->base.pages[offset >> PAGE_SHIFT]; 43*ac49797cSLizhi Hou mem->nr_pages = mem->size >> PAGE_SHIFT; 44*ac49797cSLizhi Hou 45*ac49797cSLizhi Hou if (use_vmap) { 46*ac49797cSLizhi Hou mem->kva = vmap(mem->pages, mem->nr_pages, VM_MAP, PAGE_KERNEL); 47*ac49797cSLizhi Hou if (!mem->kva) { 48*ac49797cSLizhi Hou XDNA_ERR(xdna, "Failed to vmap"); 49*ac49797cSLizhi Hou drm_mm_remove_node(&abo->mm_node); 50*ac49797cSLizhi Hou return -EFAULT; 51*ac49797cSLizhi Hou } 52*ac49797cSLizhi Hou } 53*ac49797cSLizhi Hou 54*ac49797cSLizhi Hou return 0; 55*ac49797cSLizhi Hou } 56*ac49797cSLizhi Hou 57*ac49797cSLizhi Hou static void amdxdna_gem_obj_free(struct drm_gem_object *gobj) 58*ac49797cSLizhi Hou { 59*ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev); 60*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); 61*ac49797cSLizhi Hou struct iosys_map map = IOSYS_MAP_INIT_VADDR(abo->mem.kva); 62*ac49797cSLizhi Hou 63*ac49797cSLizhi Hou XDNA_DBG(xdna, "BO type %d xdna_addr 0x%llx", abo->type, abo->mem.dev_addr); 64*ac49797cSLizhi Hou if (abo->pinned) 65*ac49797cSLizhi Hou amdxdna_gem_unpin(abo); 66*ac49797cSLizhi Hou 67*ac49797cSLizhi Hou if (abo->type == AMDXDNA_BO_DEV) { 68*ac49797cSLizhi Hou mutex_lock(&abo->client->mm_lock); 69*ac49797cSLizhi Hou drm_mm_remove_node(&abo->mm_node); 70*ac49797cSLizhi Hou mutex_unlock(&abo->client->mm_lock); 71*ac49797cSLizhi Hou 72*ac49797cSLizhi Hou vunmap(abo->mem.kva); 73*ac49797cSLizhi Hou drm_gem_object_put(to_gobj(abo->dev_heap)); 74*ac49797cSLizhi Hou drm_gem_object_release(gobj); 75*ac49797cSLizhi Hou mutex_destroy(&abo->lock); 76*ac49797cSLizhi Hou kfree(abo); 77*ac49797cSLizhi Hou return; 78*ac49797cSLizhi Hou } 79*ac49797cSLizhi Hou 80*ac49797cSLizhi Hou if (abo->type == AMDXDNA_BO_DEV_HEAP) 81*ac49797cSLizhi Hou drm_mm_takedown(&abo->mm); 82*ac49797cSLizhi Hou 83*ac49797cSLizhi Hou drm_gem_vunmap_unlocked(gobj, &map); 84*ac49797cSLizhi Hou mutex_destroy(&abo->lock); 85*ac49797cSLizhi Hou drm_gem_shmem_free(&abo->base); 86*ac49797cSLizhi Hou } 87*ac49797cSLizhi Hou 88*ac49797cSLizhi Hou static const struct drm_gem_object_funcs amdxdna_gem_dev_obj_funcs = { 89*ac49797cSLizhi Hou .free = amdxdna_gem_obj_free, 90*ac49797cSLizhi Hou }; 91*ac49797cSLizhi Hou 92*ac49797cSLizhi Hou static bool amdxdna_hmm_invalidate(struct mmu_interval_notifier *mni, 93*ac49797cSLizhi Hou const struct mmu_notifier_range *range, 94*ac49797cSLizhi Hou unsigned long cur_seq) 95*ac49797cSLizhi Hou { 96*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo = container_of(mni, struct amdxdna_gem_obj, 97*ac49797cSLizhi Hou mem.notifier); 98*ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev); 99*ac49797cSLizhi Hou 100*ac49797cSLizhi Hou XDNA_DBG(xdna, "Invalid range 0x%llx, 0x%lx, type %d", 101*ac49797cSLizhi Hou abo->mem.userptr, abo->mem.size, abo->type); 102*ac49797cSLizhi Hou 103*ac49797cSLizhi Hou if (!mmu_notifier_range_blockable(range)) 104*ac49797cSLizhi Hou return false; 105*ac49797cSLizhi Hou 106*ac49797cSLizhi Hou xdna->dev_info->ops->hmm_invalidate(abo, cur_seq); 107*ac49797cSLizhi Hou 108*ac49797cSLizhi Hou return true; 109*ac49797cSLizhi Hou } 110*ac49797cSLizhi Hou 111*ac49797cSLizhi Hou static const struct mmu_interval_notifier_ops amdxdna_hmm_ops = { 112*ac49797cSLizhi Hou .invalidate = amdxdna_hmm_invalidate, 113*ac49797cSLizhi Hou }; 114*ac49797cSLizhi Hou 115*ac49797cSLizhi Hou static void amdxdna_hmm_unregister(struct amdxdna_gem_obj *abo) 116*ac49797cSLizhi Hou { 117*ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev); 118*ac49797cSLizhi Hou 119*ac49797cSLizhi Hou if (!xdna->dev_info->ops->hmm_invalidate) 120*ac49797cSLizhi Hou return; 121*ac49797cSLizhi Hou 122*ac49797cSLizhi Hou mmu_interval_notifier_remove(&abo->mem.notifier); 123*ac49797cSLizhi Hou kvfree(abo->mem.pfns); 124*ac49797cSLizhi Hou abo->mem.pfns = NULL; 125*ac49797cSLizhi Hou } 126*ac49797cSLizhi Hou 127*ac49797cSLizhi Hou static int amdxdna_hmm_register(struct amdxdna_gem_obj *abo, unsigned long addr, 128*ac49797cSLizhi Hou size_t len) 129*ac49797cSLizhi Hou { 130*ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev); 131*ac49797cSLizhi Hou u32 nr_pages; 132*ac49797cSLizhi Hou int ret; 133*ac49797cSLizhi Hou 134*ac49797cSLizhi Hou if (!xdna->dev_info->ops->hmm_invalidate) 135*ac49797cSLizhi Hou return 0; 136*ac49797cSLizhi Hou 137*ac49797cSLizhi Hou if (abo->mem.pfns) 138*ac49797cSLizhi Hou return -EEXIST; 139*ac49797cSLizhi Hou 140*ac49797cSLizhi Hou nr_pages = (PAGE_ALIGN(addr + len) - (addr & PAGE_MASK)) >> PAGE_SHIFT; 141*ac49797cSLizhi Hou abo->mem.pfns = kvcalloc(nr_pages, sizeof(*abo->mem.pfns), 142*ac49797cSLizhi Hou GFP_KERNEL); 143*ac49797cSLizhi Hou if (!abo->mem.pfns) 144*ac49797cSLizhi Hou return -ENOMEM; 145*ac49797cSLizhi Hou 146*ac49797cSLizhi Hou ret = mmu_interval_notifier_insert_locked(&abo->mem.notifier, 147*ac49797cSLizhi Hou current->mm, 148*ac49797cSLizhi Hou addr, 149*ac49797cSLizhi Hou len, 150*ac49797cSLizhi Hou &amdxdna_hmm_ops); 151*ac49797cSLizhi Hou if (ret) { 152*ac49797cSLizhi Hou XDNA_ERR(xdna, "Insert mmu notifier failed, ret %d", ret); 153*ac49797cSLizhi Hou kvfree(abo->mem.pfns); 154*ac49797cSLizhi Hou } 155*ac49797cSLizhi Hou abo->mem.userptr = addr; 156*ac49797cSLizhi Hou 157*ac49797cSLizhi Hou return ret; 158*ac49797cSLizhi Hou } 159*ac49797cSLizhi Hou 160*ac49797cSLizhi Hou static int amdxdna_gem_obj_mmap(struct drm_gem_object *gobj, 161*ac49797cSLizhi Hou struct vm_area_struct *vma) 162*ac49797cSLizhi Hou { 163*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); 164*ac49797cSLizhi Hou unsigned long num_pages; 165*ac49797cSLizhi Hou int ret; 166*ac49797cSLizhi Hou 167*ac49797cSLizhi Hou ret = amdxdna_hmm_register(abo, vma->vm_start, gobj->size); 168*ac49797cSLizhi Hou if (ret) 169*ac49797cSLizhi Hou return ret; 170*ac49797cSLizhi Hou 171*ac49797cSLizhi Hou ret = drm_gem_shmem_mmap(&abo->base, vma); 172*ac49797cSLizhi Hou if (ret) 173*ac49797cSLizhi Hou goto hmm_unreg; 174*ac49797cSLizhi Hou 175*ac49797cSLizhi Hou num_pages = gobj->size >> PAGE_SHIFT; 176*ac49797cSLizhi Hou /* Try to insert the pages */ 177*ac49797cSLizhi Hou vm_flags_mod(vma, VM_MIXEDMAP, VM_PFNMAP); 178*ac49797cSLizhi Hou ret = vm_insert_pages(vma, vma->vm_start, abo->base.pages, &num_pages); 179*ac49797cSLizhi Hou if (ret) 180*ac49797cSLizhi Hou XDNA_ERR(abo->client->xdna, "Failed insert pages, ret %d", ret); 181*ac49797cSLizhi Hou 182*ac49797cSLizhi Hou return 0; 183*ac49797cSLizhi Hou 184*ac49797cSLizhi Hou hmm_unreg: 185*ac49797cSLizhi Hou amdxdna_hmm_unregister(abo); 186*ac49797cSLizhi Hou return ret; 187*ac49797cSLizhi Hou } 188*ac49797cSLizhi Hou 189*ac49797cSLizhi Hou static vm_fault_t amdxdna_gem_vm_fault(struct vm_fault *vmf) 190*ac49797cSLizhi Hou { 191*ac49797cSLizhi Hou return drm_gem_shmem_vm_ops.fault(vmf); 192*ac49797cSLizhi Hou } 193*ac49797cSLizhi Hou 194*ac49797cSLizhi Hou static void amdxdna_gem_vm_open(struct vm_area_struct *vma) 195*ac49797cSLizhi Hou { 196*ac49797cSLizhi Hou drm_gem_shmem_vm_ops.open(vma); 197*ac49797cSLizhi Hou } 198*ac49797cSLizhi Hou 199*ac49797cSLizhi Hou static void amdxdna_gem_vm_close(struct vm_area_struct *vma) 200*ac49797cSLizhi Hou { 201*ac49797cSLizhi Hou struct drm_gem_object *gobj = vma->vm_private_data; 202*ac49797cSLizhi Hou 203*ac49797cSLizhi Hou amdxdna_hmm_unregister(to_xdna_obj(gobj)); 204*ac49797cSLizhi Hou drm_gem_shmem_vm_ops.close(vma); 205*ac49797cSLizhi Hou } 206*ac49797cSLizhi Hou 207*ac49797cSLizhi Hou static const struct vm_operations_struct amdxdna_gem_vm_ops = { 208*ac49797cSLizhi Hou .fault = amdxdna_gem_vm_fault, 209*ac49797cSLizhi Hou .open = amdxdna_gem_vm_open, 210*ac49797cSLizhi Hou .close = amdxdna_gem_vm_close, 211*ac49797cSLizhi Hou }; 212*ac49797cSLizhi Hou 213*ac49797cSLizhi Hou static const struct drm_gem_object_funcs amdxdna_gem_shmem_funcs = { 214*ac49797cSLizhi Hou .free = amdxdna_gem_obj_free, 215*ac49797cSLizhi Hou .print_info = drm_gem_shmem_object_print_info, 216*ac49797cSLizhi Hou .pin = drm_gem_shmem_object_pin, 217*ac49797cSLizhi Hou .unpin = drm_gem_shmem_object_unpin, 218*ac49797cSLizhi Hou .get_sg_table = drm_gem_shmem_object_get_sg_table, 219*ac49797cSLizhi Hou .vmap = drm_gem_shmem_object_vmap, 220*ac49797cSLizhi Hou .vunmap = drm_gem_shmem_object_vunmap, 221*ac49797cSLizhi Hou .mmap = amdxdna_gem_obj_mmap, 222*ac49797cSLizhi Hou .vm_ops = &amdxdna_gem_vm_ops, 223*ac49797cSLizhi Hou }; 224*ac49797cSLizhi Hou 225*ac49797cSLizhi Hou static struct amdxdna_gem_obj * 226*ac49797cSLizhi Hou amdxdna_gem_create_obj(struct drm_device *dev, size_t size) 227*ac49797cSLizhi Hou { 228*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 229*ac49797cSLizhi Hou 230*ac49797cSLizhi Hou abo = kzalloc(sizeof(*abo), GFP_KERNEL); 231*ac49797cSLizhi Hou if (!abo) 232*ac49797cSLizhi Hou return ERR_PTR(-ENOMEM); 233*ac49797cSLizhi Hou 234*ac49797cSLizhi Hou abo->pinned = false; 235*ac49797cSLizhi Hou abo->assigned_hwctx = AMDXDNA_INVALID_CTX_HANDLE; 236*ac49797cSLizhi Hou mutex_init(&abo->lock); 237*ac49797cSLizhi Hou 238*ac49797cSLizhi Hou abo->mem.userptr = AMDXDNA_INVALID_ADDR; 239*ac49797cSLizhi Hou abo->mem.dev_addr = AMDXDNA_INVALID_ADDR; 240*ac49797cSLizhi Hou abo->mem.size = size; 241*ac49797cSLizhi Hou 242*ac49797cSLizhi Hou return abo; 243*ac49797cSLizhi Hou } 244*ac49797cSLizhi Hou 245*ac49797cSLizhi Hou /* For drm_driver->gem_create_object callback */ 246*ac49797cSLizhi Hou struct drm_gem_object * 247*ac49797cSLizhi Hou amdxdna_gem_create_object_cb(struct drm_device *dev, size_t size) 248*ac49797cSLizhi Hou { 249*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 250*ac49797cSLizhi Hou 251*ac49797cSLizhi Hou abo = amdxdna_gem_create_obj(dev, size); 252*ac49797cSLizhi Hou if (IS_ERR(abo)) 253*ac49797cSLizhi Hou return ERR_CAST(abo); 254*ac49797cSLizhi Hou 255*ac49797cSLizhi Hou to_gobj(abo)->funcs = &amdxdna_gem_shmem_funcs; 256*ac49797cSLizhi Hou 257*ac49797cSLizhi Hou return to_gobj(abo); 258*ac49797cSLizhi Hou } 259*ac49797cSLizhi Hou 260*ac49797cSLizhi Hou static struct amdxdna_gem_obj * 261*ac49797cSLizhi Hou amdxdna_drm_alloc_shmem(struct drm_device *dev, 262*ac49797cSLizhi Hou struct amdxdna_drm_create_bo *args, 263*ac49797cSLizhi Hou struct drm_file *filp) 264*ac49797cSLizhi Hou { 265*ac49797cSLizhi Hou struct amdxdna_client *client = filp->driver_priv; 266*ac49797cSLizhi Hou struct drm_gem_shmem_object *shmem; 267*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 268*ac49797cSLizhi Hou 269*ac49797cSLizhi Hou shmem = drm_gem_shmem_create(dev, args->size); 270*ac49797cSLizhi Hou if (IS_ERR(shmem)) 271*ac49797cSLizhi Hou return ERR_CAST(shmem); 272*ac49797cSLizhi Hou 273*ac49797cSLizhi Hou shmem->map_wc = false; 274*ac49797cSLizhi Hou 275*ac49797cSLizhi Hou abo = to_xdna_obj(&shmem->base); 276*ac49797cSLizhi Hou abo->client = client; 277*ac49797cSLizhi Hou abo->type = AMDXDNA_BO_SHMEM; 278*ac49797cSLizhi Hou 279*ac49797cSLizhi Hou return abo; 280*ac49797cSLizhi Hou } 281*ac49797cSLizhi Hou 282*ac49797cSLizhi Hou static struct amdxdna_gem_obj * 283*ac49797cSLizhi Hou amdxdna_drm_create_dev_heap(struct drm_device *dev, 284*ac49797cSLizhi Hou struct amdxdna_drm_create_bo *args, 285*ac49797cSLizhi Hou struct drm_file *filp) 286*ac49797cSLizhi Hou { 287*ac49797cSLizhi Hou struct amdxdna_client *client = filp->driver_priv; 288*ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(dev); 289*ac49797cSLizhi Hou struct drm_gem_shmem_object *shmem; 290*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 291*ac49797cSLizhi Hou int ret; 292*ac49797cSLizhi Hou 293*ac49797cSLizhi Hou if (args->size > xdna->dev_info->dev_mem_size) { 294*ac49797cSLizhi Hou XDNA_DBG(xdna, "Invalid dev heap size 0x%llx, limit 0x%lx", 295*ac49797cSLizhi Hou args->size, xdna->dev_info->dev_mem_size); 296*ac49797cSLizhi Hou return ERR_PTR(-EINVAL); 297*ac49797cSLizhi Hou } 298*ac49797cSLizhi Hou 299*ac49797cSLizhi Hou mutex_lock(&client->mm_lock); 300*ac49797cSLizhi Hou if (client->dev_heap) { 301*ac49797cSLizhi Hou XDNA_DBG(client->xdna, "dev heap is already created"); 302*ac49797cSLizhi Hou ret = -EBUSY; 303*ac49797cSLizhi Hou goto mm_unlock; 304*ac49797cSLizhi Hou } 305*ac49797cSLizhi Hou 306*ac49797cSLizhi Hou shmem = drm_gem_shmem_create(dev, args->size); 307*ac49797cSLizhi Hou if (IS_ERR(shmem)) { 308*ac49797cSLizhi Hou ret = PTR_ERR(shmem); 309*ac49797cSLizhi Hou goto mm_unlock; 310*ac49797cSLizhi Hou } 311*ac49797cSLizhi Hou 312*ac49797cSLizhi Hou shmem->map_wc = false; 313*ac49797cSLizhi Hou abo = to_xdna_obj(&shmem->base); 314*ac49797cSLizhi Hou 315*ac49797cSLizhi Hou abo->type = AMDXDNA_BO_DEV_HEAP; 316*ac49797cSLizhi Hou abo->client = client; 317*ac49797cSLizhi Hou abo->mem.dev_addr = client->xdna->dev_info->dev_mem_base; 318*ac49797cSLizhi Hou drm_mm_init(&abo->mm, abo->mem.dev_addr, abo->mem.size); 319*ac49797cSLizhi Hou 320*ac49797cSLizhi Hou client->dev_heap = abo; 321*ac49797cSLizhi Hou drm_gem_object_get(to_gobj(abo)); 322*ac49797cSLizhi Hou mutex_unlock(&client->mm_lock); 323*ac49797cSLizhi Hou 324*ac49797cSLizhi Hou return abo; 325*ac49797cSLizhi Hou 326*ac49797cSLizhi Hou mm_unlock: 327*ac49797cSLizhi Hou mutex_unlock(&client->mm_lock); 328*ac49797cSLizhi Hou return ERR_PTR(ret); 329*ac49797cSLizhi Hou } 330*ac49797cSLizhi Hou 331*ac49797cSLizhi Hou struct amdxdna_gem_obj * 332*ac49797cSLizhi Hou amdxdna_drm_alloc_dev_bo(struct drm_device *dev, 333*ac49797cSLizhi Hou struct amdxdna_drm_create_bo *args, 334*ac49797cSLizhi Hou struct drm_file *filp, bool use_vmap) 335*ac49797cSLizhi Hou { 336*ac49797cSLizhi Hou struct amdxdna_client *client = filp->driver_priv; 337*ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(dev); 338*ac49797cSLizhi Hou size_t aligned_sz = PAGE_ALIGN(args->size); 339*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo, *heap; 340*ac49797cSLizhi Hou int ret; 341*ac49797cSLizhi Hou 342*ac49797cSLizhi Hou mutex_lock(&client->mm_lock); 343*ac49797cSLizhi Hou heap = client->dev_heap; 344*ac49797cSLizhi Hou if (!heap) { 345*ac49797cSLizhi Hou ret = -EINVAL; 346*ac49797cSLizhi Hou goto mm_unlock; 347*ac49797cSLizhi Hou } 348*ac49797cSLizhi Hou 349*ac49797cSLizhi Hou if (heap->mem.userptr == AMDXDNA_INVALID_ADDR) { 350*ac49797cSLizhi Hou XDNA_ERR(xdna, "Invalid dev heap userptr"); 351*ac49797cSLizhi Hou ret = -EINVAL; 352*ac49797cSLizhi Hou goto mm_unlock; 353*ac49797cSLizhi Hou } 354*ac49797cSLizhi Hou 355*ac49797cSLizhi Hou if (args->size > heap->mem.size) { 356*ac49797cSLizhi Hou XDNA_ERR(xdna, "Invalid dev bo size 0x%llx, limit 0x%lx", 357*ac49797cSLizhi Hou args->size, heap->mem.size); 358*ac49797cSLizhi Hou ret = -EINVAL; 359*ac49797cSLizhi Hou goto mm_unlock; 360*ac49797cSLizhi Hou } 361*ac49797cSLizhi Hou 362*ac49797cSLizhi Hou abo = amdxdna_gem_create_obj(&xdna->ddev, aligned_sz); 363*ac49797cSLizhi Hou if (IS_ERR(abo)) { 364*ac49797cSLizhi Hou ret = PTR_ERR(abo); 365*ac49797cSLizhi Hou goto mm_unlock; 366*ac49797cSLizhi Hou } 367*ac49797cSLizhi Hou to_gobj(abo)->funcs = &amdxdna_gem_dev_obj_funcs; 368*ac49797cSLizhi Hou abo->type = AMDXDNA_BO_DEV; 369*ac49797cSLizhi Hou abo->client = client; 370*ac49797cSLizhi Hou abo->dev_heap = heap; 371*ac49797cSLizhi Hou ret = amdxdna_gem_insert_node_locked(abo, use_vmap); 372*ac49797cSLizhi Hou if (ret) { 373*ac49797cSLizhi Hou XDNA_ERR(xdna, "Failed to alloc dev bo memory, ret %d", ret); 374*ac49797cSLizhi Hou goto mm_unlock; 375*ac49797cSLizhi Hou } 376*ac49797cSLizhi Hou 377*ac49797cSLizhi Hou drm_gem_object_get(to_gobj(heap)); 378*ac49797cSLizhi Hou drm_gem_private_object_init(&xdna->ddev, to_gobj(abo), aligned_sz); 379*ac49797cSLizhi Hou 380*ac49797cSLizhi Hou mutex_unlock(&client->mm_lock); 381*ac49797cSLizhi Hou return abo; 382*ac49797cSLizhi Hou 383*ac49797cSLizhi Hou mm_unlock: 384*ac49797cSLizhi Hou mutex_unlock(&client->mm_lock); 385*ac49797cSLizhi Hou return ERR_PTR(ret); 386*ac49797cSLizhi Hou } 387*ac49797cSLizhi Hou 388*ac49797cSLizhi Hou static struct amdxdna_gem_obj * 389*ac49797cSLizhi Hou amdxdna_drm_create_cmd_bo(struct drm_device *dev, 390*ac49797cSLizhi Hou struct amdxdna_drm_create_bo *args, 391*ac49797cSLizhi Hou struct drm_file *filp) 392*ac49797cSLizhi Hou { 393*ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(dev); 394*ac49797cSLizhi Hou struct drm_gem_shmem_object *shmem; 395*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 396*ac49797cSLizhi Hou struct iosys_map map; 397*ac49797cSLizhi Hou int ret; 398*ac49797cSLizhi Hou 399*ac49797cSLizhi Hou if (args->size > XDNA_MAX_CMD_BO_SIZE) { 400*ac49797cSLizhi Hou XDNA_ERR(xdna, "Command bo size 0x%llx too large", args->size); 401*ac49797cSLizhi Hou return ERR_PTR(-EINVAL); 402*ac49797cSLizhi Hou } 403*ac49797cSLizhi Hou 404*ac49797cSLizhi Hou if (args->size < sizeof(struct amdxdna_cmd)) { 405*ac49797cSLizhi Hou XDNA_DBG(xdna, "Command BO size 0x%llx too small", args->size); 406*ac49797cSLizhi Hou return ERR_PTR(-EINVAL); 407*ac49797cSLizhi Hou } 408*ac49797cSLizhi Hou 409*ac49797cSLizhi Hou shmem = drm_gem_shmem_create(dev, args->size); 410*ac49797cSLizhi Hou if (IS_ERR(shmem)) 411*ac49797cSLizhi Hou return ERR_CAST(shmem); 412*ac49797cSLizhi Hou 413*ac49797cSLizhi Hou shmem->map_wc = false; 414*ac49797cSLizhi Hou abo = to_xdna_obj(&shmem->base); 415*ac49797cSLizhi Hou 416*ac49797cSLizhi Hou abo->type = AMDXDNA_BO_CMD; 417*ac49797cSLizhi Hou abo->client = filp->driver_priv; 418*ac49797cSLizhi Hou 419*ac49797cSLizhi Hou ret = drm_gem_vmap_unlocked(to_gobj(abo), &map); 420*ac49797cSLizhi Hou if (ret) { 421*ac49797cSLizhi Hou XDNA_ERR(xdna, "Vmap cmd bo failed, ret %d", ret); 422*ac49797cSLizhi Hou goto release_obj; 423*ac49797cSLizhi Hou } 424*ac49797cSLizhi Hou abo->mem.kva = map.vaddr; 425*ac49797cSLizhi Hou 426*ac49797cSLizhi Hou return abo; 427*ac49797cSLizhi Hou 428*ac49797cSLizhi Hou release_obj: 429*ac49797cSLizhi Hou drm_gem_shmem_free(shmem); 430*ac49797cSLizhi Hou return ERR_PTR(ret); 431*ac49797cSLizhi Hou } 432*ac49797cSLizhi Hou 433*ac49797cSLizhi Hou int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) 434*ac49797cSLizhi Hou { 435*ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(dev); 436*ac49797cSLizhi Hou struct amdxdna_drm_create_bo *args = data; 437*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 438*ac49797cSLizhi Hou int ret; 439*ac49797cSLizhi Hou 440*ac49797cSLizhi Hou if (args->flags || args->vaddr || !args->size) 441*ac49797cSLizhi Hou return -EINVAL; 442*ac49797cSLizhi Hou 443*ac49797cSLizhi Hou XDNA_DBG(xdna, "BO arg type %d vaddr 0x%llx size 0x%llx flags 0x%llx", 444*ac49797cSLizhi Hou args->type, args->vaddr, args->size, args->flags); 445*ac49797cSLizhi Hou switch (args->type) { 446*ac49797cSLizhi Hou case AMDXDNA_BO_SHMEM: 447*ac49797cSLizhi Hou abo = amdxdna_drm_alloc_shmem(dev, args, filp); 448*ac49797cSLizhi Hou break; 449*ac49797cSLizhi Hou case AMDXDNA_BO_DEV_HEAP: 450*ac49797cSLizhi Hou abo = amdxdna_drm_create_dev_heap(dev, args, filp); 451*ac49797cSLizhi Hou break; 452*ac49797cSLizhi Hou case AMDXDNA_BO_DEV: 453*ac49797cSLizhi Hou abo = amdxdna_drm_alloc_dev_bo(dev, args, filp, false); 454*ac49797cSLizhi Hou break; 455*ac49797cSLizhi Hou case AMDXDNA_BO_CMD: 456*ac49797cSLizhi Hou abo = amdxdna_drm_create_cmd_bo(dev, args, filp); 457*ac49797cSLizhi Hou break; 458*ac49797cSLizhi Hou default: 459*ac49797cSLizhi Hou return -EINVAL; 460*ac49797cSLizhi Hou } 461*ac49797cSLizhi Hou if (IS_ERR(abo)) 462*ac49797cSLizhi Hou return PTR_ERR(abo); 463*ac49797cSLizhi Hou 464*ac49797cSLizhi Hou /* ready to publish object to userspace */ 465*ac49797cSLizhi Hou ret = drm_gem_handle_create(filp, to_gobj(abo), &args->handle); 466*ac49797cSLizhi Hou if (ret) { 467*ac49797cSLizhi Hou XDNA_ERR(xdna, "Create handle failed"); 468*ac49797cSLizhi Hou goto put_obj; 469*ac49797cSLizhi Hou } 470*ac49797cSLizhi Hou 471*ac49797cSLizhi Hou XDNA_DBG(xdna, "BO hdl %d type %d userptr 0x%llx xdna_addr 0x%llx size 0x%lx", 472*ac49797cSLizhi Hou args->handle, args->type, abo->mem.userptr, 473*ac49797cSLizhi Hou abo->mem.dev_addr, abo->mem.size); 474*ac49797cSLizhi Hou put_obj: 475*ac49797cSLizhi Hou /* Dereference object reference. Handle holds it now. */ 476*ac49797cSLizhi Hou drm_gem_object_put(to_gobj(abo)); 477*ac49797cSLizhi Hou return ret; 478*ac49797cSLizhi Hou } 479*ac49797cSLizhi Hou 480*ac49797cSLizhi Hou int amdxdna_gem_pin_nolock(struct amdxdna_gem_obj *abo) 481*ac49797cSLizhi Hou { 482*ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev); 483*ac49797cSLizhi Hou int ret; 484*ac49797cSLizhi Hou 485*ac49797cSLizhi Hou switch (abo->type) { 486*ac49797cSLizhi Hou case AMDXDNA_BO_SHMEM: 487*ac49797cSLizhi Hou case AMDXDNA_BO_DEV_HEAP: 488*ac49797cSLizhi Hou ret = drm_gem_shmem_pin(&abo->base); 489*ac49797cSLizhi Hou break; 490*ac49797cSLizhi Hou case AMDXDNA_BO_DEV: 491*ac49797cSLizhi Hou ret = drm_gem_shmem_pin(&abo->dev_heap->base); 492*ac49797cSLizhi Hou break; 493*ac49797cSLizhi Hou default: 494*ac49797cSLizhi Hou ret = -EOPNOTSUPP; 495*ac49797cSLizhi Hou } 496*ac49797cSLizhi Hou 497*ac49797cSLizhi Hou XDNA_DBG(xdna, "BO type %d ret %d", abo->type, ret); 498*ac49797cSLizhi Hou return ret; 499*ac49797cSLizhi Hou } 500*ac49797cSLizhi Hou 501*ac49797cSLizhi Hou int amdxdna_gem_pin(struct amdxdna_gem_obj *abo) 502*ac49797cSLizhi Hou { 503*ac49797cSLizhi Hou int ret; 504*ac49797cSLizhi Hou 505*ac49797cSLizhi Hou if (abo->type == AMDXDNA_BO_DEV) 506*ac49797cSLizhi Hou abo = abo->dev_heap; 507*ac49797cSLizhi Hou 508*ac49797cSLizhi Hou mutex_lock(&abo->lock); 509*ac49797cSLizhi Hou ret = amdxdna_gem_pin_nolock(abo); 510*ac49797cSLizhi Hou mutex_unlock(&abo->lock); 511*ac49797cSLizhi Hou 512*ac49797cSLizhi Hou return ret; 513*ac49797cSLizhi Hou } 514*ac49797cSLizhi Hou 515*ac49797cSLizhi Hou void amdxdna_gem_unpin(struct amdxdna_gem_obj *abo) 516*ac49797cSLizhi Hou { 517*ac49797cSLizhi Hou if (abo->type == AMDXDNA_BO_DEV) 518*ac49797cSLizhi Hou abo = abo->dev_heap; 519*ac49797cSLizhi Hou 520*ac49797cSLizhi Hou mutex_lock(&abo->lock); 521*ac49797cSLizhi Hou drm_gem_shmem_unpin(&abo->base); 522*ac49797cSLizhi Hou mutex_unlock(&abo->lock); 523*ac49797cSLizhi Hou } 524*ac49797cSLizhi Hou 525*ac49797cSLizhi Hou struct amdxdna_gem_obj *amdxdna_gem_get_obj(struct amdxdna_client *client, 526*ac49797cSLizhi Hou u32 bo_hdl, u8 bo_type) 527*ac49797cSLizhi Hou { 528*ac49797cSLizhi Hou struct amdxdna_dev *xdna = client->xdna; 529*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 530*ac49797cSLizhi Hou struct drm_gem_object *gobj; 531*ac49797cSLizhi Hou 532*ac49797cSLizhi Hou gobj = drm_gem_object_lookup(client->filp, bo_hdl); 533*ac49797cSLizhi Hou if (!gobj) { 534*ac49797cSLizhi Hou XDNA_DBG(xdna, "Can not find bo %d", bo_hdl); 535*ac49797cSLizhi Hou return NULL; 536*ac49797cSLizhi Hou } 537*ac49797cSLizhi Hou 538*ac49797cSLizhi Hou abo = to_xdna_obj(gobj); 539*ac49797cSLizhi Hou if (bo_type == AMDXDNA_BO_INVALID || abo->type == bo_type) 540*ac49797cSLizhi Hou return abo; 541*ac49797cSLizhi Hou 542*ac49797cSLizhi Hou drm_gem_object_put(gobj); 543*ac49797cSLizhi Hou return NULL; 544*ac49797cSLizhi Hou } 545*ac49797cSLizhi Hou 546*ac49797cSLizhi Hou int amdxdna_drm_get_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) 547*ac49797cSLizhi Hou { 548*ac49797cSLizhi Hou struct amdxdna_drm_get_bo_info *args = data; 549*ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(dev); 550*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 551*ac49797cSLizhi Hou struct drm_gem_object *gobj; 552*ac49797cSLizhi Hou int ret = 0; 553*ac49797cSLizhi Hou 554*ac49797cSLizhi Hou if (args->ext || args->ext_flags) 555*ac49797cSLizhi Hou return -EINVAL; 556*ac49797cSLizhi Hou 557*ac49797cSLizhi Hou gobj = drm_gem_object_lookup(filp, args->handle); 558*ac49797cSLizhi Hou if (!gobj) { 559*ac49797cSLizhi Hou XDNA_DBG(xdna, "Lookup GEM object %d failed", args->handle); 560*ac49797cSLizhi Hou return -ENOENT; 561*ac49797cSLizhi Hou } 562*ac49797cSLizhi Hou 563*ac49797cSLizhi Hou abo = to_xdna_obj(gobj); 564*ac49797cSLizhi Hou args->vaddr = abo->mem.userptr; 565*ac49797cSLizhi Hou args->xdna_addr = abo->mem.dev_addr; 566*ac49797cSLizhi Hou 567*ac49797cSLizhi Hou if (abo->type != AMDXDNA_BO_DEV) 568*ac49797cSLizhi Hou args->map_offset = drm_vma_node_offset_addr(&gobj->vma_node); 569*ac49797cSLizhi Hou else 570*ac49797cSLizhi Hou args->map_offset = AMDXDNA_INVALID_ADDR; 571*ac49797cSLizhi Hou 572*ac49797cSLizhi Hou XDNA_DBG(xdna, "BO hdl %d map_offset 0x%llx vaddr 0x%llx xdna_addr 0x%llx", 573*ac49797cSLizhi Hou args->handle, args->map_offset, args->vaddr, args->xdna_addr); 574*ac49797cSLizhi Hou 575*ac49797cSLizhi Hou drm_gem_object_put(gobj); 576*ac49797cSLizhi Hou return ret; 577*ac49797cSLizhi Hou } 578*ac49797cSLizhi Hou 579*ac49797cSLizhi Hou /* 580*ac49797cSLizhi Hou * The sync bo ioctl is to make sure the CPU cache is in sync with memory. 581*ac49797cSLizhi Hou * This is required because NPU is not cache coherent device. CPU cache 582*ac49797cSLizhi Hou * flushing/invalidation is expensive so it is best to handle this outside 583*ac49797cSLizhi Hou * of the command submission path. This ioctl allows explicit cache 584*ac49797cSLizhi Hou * flushing/invalidation outside of the critical path. 585*ac49797cSLizhi Hou */ 586*ac49797cSLizhi Hou int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev, 587*ac49797cSLizhi Hou void *data, struct drm_file *filp) 588*ac49797cSLizhi Hou { 589*ac49797cSLizhi Hou struct amdxdna_dev *xdna = to_xdna_dev(dev); 590*ac49797cSLizhi Hou struct amdxdna_drm_sync_bo *args = data; 591*ac49797cSLizhi Hou struct amdxdna_gem_obj *abo; 592*ac49797cSLizhi Hou struct drm_gem_object *gobj; 593*ac49797cSLizhi Hou int ret; 594*ac49797cSLizhi Hou 595*ac49797cSLizhi Hou gobj = drm_gem_object_lookup(filp, args->handle); 596*ac49797cSLizhi Hou if (!gobj) { 597*ac49797cSLizhi Hou XDNA_ERR(xdna, "Lookup GEM object failed"); 598*ac49797cSLizhi Hou return -ENOENT; 599*ac49797cSLizhi Hou } 600*ac49797cSLizhi Hou abo = to_xdna_obj(gobj); 601*ac49797cSLizhi Hou 602*ac49797cSLizhi Hou ret = amdxdna_gem_pin(abo); 603*ac49797cSLizhi Hou if (ret) { 604*ac49797cSLizhi Hou XDNA_ERR(xdna, "Pin BO %d failed, ret %d", args->handle, ret); 605*ac49797cSLizhi Hou goto put_obj; 606*ac49797cSLizhi Hou } 607*ac49797cSLizhi Hou 608*ac49797cSLizhi Hou if (abo->type == AMDXDNA_BO_DEV) 609*ac49797cSLizhi Hou drm_clflush_pages(abo->mem.pages, abo->mem.nr_pages); 610*ac49797cSLizhi Hou else 611*ac49797cSLizhi Hou drm_clflush_pages(abo->base.pages, gobj->size >> PAGE_SHIFT); 612*ac49797cSLizhi Hou 613*ac49797cSLizhi Hou amdxdna_gem_unpin(abo); 614*ac49797cSLizhi Hou 615*ac49797cSLizhi Hou XDNA_DBG(xdna, "Sync bo %d offset 0x%llx, size 0x%llx\n", 616*ac49797cSLizhi Hou args->handle, args->offset, args->size); 617*ac49797cSLizhi Hou 618*ac49797cSLizhi Hou put_obj: 619*ac49797cSLizhi Hou drm_gem_object_put(gobj); 620*ac49797cSLizhi Hou return ret; 621*ac49797cSLizhi Hou } 622