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