xref: /linux/drivers/accel/amdxdna/amdxdna_gem.c (revision 2c1ed907520c50326b8f604907a8478b27881a2e)
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>
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
amdxdna_gem_insert_node_locked(struct amdxdna_gem_obj * abo,bool use_vmap)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 
amdxdna_gem_obj_free(struct drm_gem_object * gobj)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 
amdxdna_hmm_invalidate(struct mmu_interval_notifier * mni,const struct mmu_notifier_range * range,unsigned long cur_seq)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 
amdxdna_hmm_unregister(struct amdxdna_gem_obj * abo)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 
amdxdna_hmm_register(struct amdxdna_gem_obj * abo,unsigned long addr,size_t len)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 
amdxdna_gem_obj_mmap(struct drm_gem_object * gobj,struct vm_area_struct * vma)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 
amdxdna_gem_vm_fault(struct vm_fault * vmf)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 
amdxdna_gem_vm_open(struct vm_area_struct * vma)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 
amdxdna_gem_vm_close(struct vm_area_struct * vma)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 *
amdxdna_gem_create_obj(struct drm_device * dev,size_t size)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 *
amdxdna_gem_create_object_cb(struct drm_device * dev,size_t size)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 *
amdxdna_drm_alloc_shmem(struct drm_device * dev,struct amdxdna_drm_create_bo * args,struct drm_file * filp)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 *
amdxdna_drm_create_dev_heap(struct drm_device * dev,struct amdxdna_drm_create_bo * args,struct drm_file * filp)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 *
amdxdna_drm_alloc_dev_bo(struct drm_device * dev,struct amdxdna_drm_create_bo * args,struct drm_file * filp,bool use_vmap)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 *
amdxdna_drm_create_cmd_bo(struct drm_device * dev,struct amdxdna_drm_create_bo * args,struct drm_file * filp)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 
amdxdna_drm_create_bo_ioctl(struct drm_device * dev,void * data,struct drm_file * filp)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 
amdxdna_gem_pin_nolock(struct amdxdna_gem_obj * abo)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 
amdxdna_gem_pin(struct amdxdna_gem_obj * abo)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 
amdxdna_gem_unpin(struct amdxdna_gem_obj * abo)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 
amdxdna_gem_get_obj(struct amdxdna_client * client,u32 bo_hdl,u8 bo_type)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 
amdxdna_drm_get_bo_info_ioctl(struct drm_device * dev,void * data,struct drm_file * filp)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 
555*03c318a0SLizhi Hou 	if (args->ext || args->ext_flags || args->pad)
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  */
amdxdna_drm_sync_bo_ioctl(struct drm_device * dev,void * data,struct drm_file * filp)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