xref: /linux/drivers/accel/amdxdna/amdxdna_gem.c (revision ac49797c1815d4f8f04b7053b2998c546283c89e)
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