xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/nouveau/nvkm/core/nouveau_nvkm_core_gpuobj.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
1 /*	$NetBSD: nouveau_nvkm_core_gpuobj.c,v 1.5 2021/12/18 23:45:34 riastradh Exp $	*/
2 
3 /*
4  * Copyright 2012 Red Hat Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors: Ben Skeggs
25  */
26 #include <sys/cdefs.h>
27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_core_gpuobj.c,v 1.5 2021/12/18 23:45:34 riastradh Exp $");
28 
29 #include <core/gpuobj.h>
30 #include <core/engine.h>
31 
32 #include <subdev/instmem.h>
33 #include <subdev/bar.h>
34 #include <subdev/mmu.h>
35 
36 #ifdef __NetBSD__
37 
38 /*
39  * XXX I think this should be done with bus_space, but the depth of
40  * abstractions is dizzying and I'm not actually sure where these
41  * pointers come from.
42  */
43 
44 #  define	__iomem			__nvkm_gpuobj_iomem
45 #  define	ioread32_native		fake_ioread32_native
46 #  define	iowrite32_native	fake_iowrite32_native
47 
48 static inline uint32_t
ioread32_native(const void __iomem * ptr)49 ioread32_native(const void __iomem *ptr)
50 {
51 	uint32_t v;
52 
53 	v = *(const uint32_t __iomem *)ptr;
54 	membar_consumer();
55 
56 	return v;
57 }
58 
59 static inline void
iowrite32_native(uint32_t v,void __iomem * ptr)60 iowrite32_native(uint32_t v, void __iomem *ptr)
61 {
62 
63 	membar_producer();
64 	*(uint32_t __iomem *)ptr = v;
65 }
66 
67 #endif
68 
69 /* fast-path, where backend is able to provide direct pointer to memory */
70 static u32
nvkm_gpuobj_rd32_fast(struct nvkm_gpuobj * gpuobj,u32 offset)71 nvkm_gpuobj_rd32_fast(struct nvkm_gpuobj *gpuobj, u32 offset)
72 {
73 	return ioread32_native((const char __iomem *)gpuobj->map + offset);
74 }
75 
76 static void
nvkm_gpuobj_wr32_fast(struct nvkm_gpuobj * gpuobj,u32 offset,u32 data)77 nvkm_gpuobj_wr32_fast(struct nvkm_gpuobj *gpuobj, u32 offset, u32 data)
78 {
79 	iowrite32_native(data, (char __iomem *)gpuobj->map + offset);
80 }
81 
82 #ifdef __NetBSD__
83 #  undef	ioread32_native
84 #  undef	iowrite32_native
85 #endif
86 
87 /* accessor functions for gpuobjs allocated directly from instmem */
88 static int
nvkm_gpuobj_heap_map(struct nvkm_gpuobj * gpuobj,u64 offset,struct nvkm_vmm * vmm,struct nvkm_vma * vma,void * argv,u32 argc)89 nvkm_gpuobj_heap_map(struct nvkm_gpuobj *gpuobj, u64 offset,
90 		     struct nvkm_vmm *vmm, struct nvkm_vma *vma,
91 		     void *argv, u32 argc)
92 {
93 	return nvkm_memory_map(gpuobj->memory, offset, vmm, vma, argv, argc);
94 }
95 
96 static u32
nvkm_gpuobj_heap_rd32(struct nvkm_gpuobj * gpuobj,u32 offset)97 nvkm_gpuobj_heap_rd32(struct nvkm_gpuobj *gpuobj, u32 offset)
98 {
99 	return nvkm_ro32(gpuobj->memory, offset);
100 }
101 
102 static void
nvkm_gpuobj_heap_wr32(struct nvkm_gpuobj * gpuobj,u32 offset,u32 data)103 nvkm_gpuobj_heap_wr32(struct nvkm_gpuobj *gpuobj, u32 offset, u32 data)
104 {
105 	nvkm_wo32(gpuobj->memory, offset, data);
106 }
107 
108 static const struct nvkm_gpuobj_func nvkm_gpuobj_heap;
109 static void
nvkm_gpuobj_heap_release(struct nvkm_gpuobj * gpuobj)110 nvkm_gpuobj_heap_release(struct nvkm_gpuobj *gpuobj)
111 {
112 	gpuobj->func = &nvkm_gpuobj_heap;
113 	nvkm_done(gpuobj->memory);
114 }
115 
116 static const struct nvkm_gpuobj_func
117 nvkm_gpuobj_heap_fast = {
118 	.release = nvkm_gpuobj_heap_release,
119 	.rd32 = nvkm_gpuobj_rd32_fast,
120 	.wr32 = nvkm_gpuobj_wr32_fast,
121 	.map = nvkm_gpuobj_heap_map,
122 };
123 
124 static const struct nvkm_gpuobj_func
125 nvkm_gpuobj_heap_slow = {
126 	.release = nvkm_gpuobj_heap_release,
127 	.rd32 = nvkm_gpuobj_heap_rd32,
128 	.wr32 = nvkm_gpuobj_heap_wr32,
129 	.map = nvkm_gpuobj_heap_map,
130 };
131 
132 static void *
nvkm_gpuobj_heap_acquire(struct nvkm_gpuobj * gpuobj)133 nvkm_gpuobj_heap_acquire(struct nvkm_gpuobj *gpuobj)
134 {
135 	gpuobj->map = nvkm_kmap(gpuobj->memory);
136 	if (likely(gpuobj->map))
137 		gpuobj->func = &nvkm_gpuobj_heap_fast;
138 	else
139 		gpuobj->func = &nvkm_gpuobj_heap_slow;
140 	return gpuobj->map;
141 }
142 
143 static const struct nvkm_gpuobj_func
144 nvkm_gpuobj_heap = {
145 	.acquire = nvkm_gpuobj_heap_acquire,
146 	.map = nvkm_gpuobj_heap_map,
147 };
148 
149 /* accessor functions for gpuobjs sub-allocated from a parent gpuobj */
150 static int
nvkm_gpuobj_map(struct nvkm_gpuobj * gpuobj,u64 offset,struct nvkm_vmm * vmm,struct nvkm_vma * vma,void * argv,u32 argc)151 nvkm_gpuobj_map(struct nvkm_gpuobj *gpuobj, u64 offset,
152 		struct nvkm_vmm *vmm, struct nvkm_vma *vma,
153 		void *argv, u32 argc)
154 {
155 	return nvkm_memory_map(gpuobj->parent, gpuobj->node->offset + offset,
156 			       vmm, vma, argv, argc);
157 }
158 
159 static u32
nvkm_gpuobj_rd32(struct nvkm_gpuobj * gpuobj,u32 offset)160 nvkm_gpuobj_rd32(struct nvkm_gpuobj *gpuobj, u32 offset)
161 {
162 	return nvkm_ro32(gpuobj->parent, gpuobj->node->offset + offset);
163 }
164 
165 static void
nvkm_gpuobj_wr32(struct nvkm_gpuobj * gpuobj,u32 offset,u32 data)166 nvkm_gpuobj_wr32(struct nvkm_gpuobj *gpuobj, u32 offset, u32 data)
167 {
168 	nvkm_wo32(gpuobj->parent, gpuobj->node->offset + offset, data);
169 }
170 
171 static const struct nvkm_gpuobj_func nvkm_gpuobj_func;
172 static void
nvkm_gpuobj_release(struct nvkm_gpuobj * gpuobj)173 nvkm_gpuobj_release(struct nvkm_gpuobj *gpuobj)
174 {
175 	gpuobj->func = &nvkm_gpuobj_func;
176 	nvkm_done(gpuobj->parent);
177 }
178 
179 static const struct nvkm_gpuobj_func
180 nvkm_gpuobj_fast = {
181 	.release = nvkm_gpuobj_release,
182 	.rd32 = nvkm_gpuobj_rd32_fast,
183 	.wr32 = nvkm_gpuobj_wr32_fast,
184 	.map = nvkm_gpuobj_map,
185 };
186 
187 static const struct nvkm_gpuobj_func
188 nvkm_gpuobj_slow = {
189 	.release = nvkm_gpuobj_release,
190 	.rd32 = nvkm_gpuobj_rd32,
191 	.wr32 = nvkm_gpuobj_wr32,
192 	.map = nvkm_gpuobj_map,
193 };
194 
195 static void *
nvkm_gpuobj_acquire(struct nvkm_gpuobj * gpuobj)196 nvkm_gpuobj_acquire(struct nvkm_gpuobj *gpuobj)
197 {
198 	gpuobj->map = nvkm_kmap(gpuobj->parent);
199 	if (likely(gpuobj->map)) {
200 		gpuobj->map  = (u8 *)gpuobj->map + gpuobj->node->offset;
201 		gpuobj->func = &nvkm_gpuobj_fast;
202 	} else {
203 		gpuobj->func = &nvkm_gpuobj_slow;
204 	}
205 	return gpuobj->map;
206 }
207 
208 static const struct nvkm_gpuobj_func
209 nvkm_gpuobj_func = {
210 	.acquire = nvkm_gpuobj_acquire,
211 	.map = nvkm_gpuobj_map,
212 };
213 
214 static int
nvkm_gpuobj_ctor(struct nvkm_device * device,u32 size,int align,bool zero,struct nvkm_gpuobj * parent,struct nvkm_gpuobj * gpuobj)215 nvkm_gpuobj_ctor(struct nvkm_device *device, u32 size, int align, bool zero,
216 		 struct nvkm_gpuobj *parent, struct nvkm_gpuobj *gpuobj)
217 {
218 	u32 offset;
219 	int ret;
220 
221 	if (parent) {
222 		if (align >= 0) {
223 			ret = nvkm_mm_head(&parent->heap, 0, 1, size, size,
224 					   max(align, 1), &gpuobj->node);
225 		} else {
226 			ret = nvkm_mm_tail(&parent->heap, 0, 1, size, size,
227 					   -align, &gpuobj->node);
228 		}
229 		if (ret)
230 			return ret;
231 
232 		gpuobj->parent = parent;
233 		gpuobj->func = &nvkm_gpuobj_func;
234 		gpuobj->addr = parent->addr + gpuobj->node->offset;
235 		gpuobj->size = gpuobj->node->length;
236 
237 		if (zero) {
238 			nvkm_kmap(gpuobj);
239 			for (offset = 0; offset < gpuobj->size; offset += 4)
240 				nvkm_wo32(gpuobj, offset, 0x00000000);
241 			nvkm_done(gpuobj);
242 		}
243 	} else {
244 		ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size,
245 				      abs(align), zero, &gpuobj->memory);
246 		if (ret)
247 			return ret;
248 
249 		gpuobj->func = &nvkm_gpuobj_heap;
250 		gpuobj->addr = nvkm_memory_addr(gpuobj->memory);
251 		gpuobj->size = nvkm_memory_size(gpuobj->memory);
252 	}
253 
254 	return nvkm_mm_init(&gpuobj->heap, 0, 0, gpuobj->size, 1);
255 }
256 
257 void
nvkm_gpuobj_del(struct nvkm_gpuobj ** pgpuobj)258 nvkm_gpuobj_del(struct nvkm_gpuobj **pgpuobj)
259 {
260 	struct nvkm_gpuobj *gpuobj = *pgpuobj;
261 	if (gpuobj) {
262 		if (gpuobj->parent)
263 			nvkm_mm_free(&gpuobj->parent->heap, &gpuobj->node);
264 		nvkm_mm_fini(&gpuobj->heap);
265 		nvkm_memory_unref(&gpuobj->memory);
266 		kfree(*pgpuobj);
267 		*pgpuobj = NULL;
268 	}
269 }
270 
271 int
nvkm_gpuobj_new(struct nvkm_device * device,u32 size,int align,bool zero,struct nvkm_gpuobj * parent,struct nvkm_gpuobj ** pgpuobj)272 nvkm_gpuobj_new(struct nvkm_device *device, u32 size, int align, bool zero,
273 		struct nvkm_gpuobj *parent, struct nvkm_gpuobj **pgpuobj)
274 {
275 	struct nvkm_gpuobj *gpuobj;
276 	int ret;
277 
278 	if (!(gpuobj = *pgpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL)))
279 		return -ENOMEM;
280 
281 	ret = nvkm_gpuobj_ctor(device, size, align, zero, parent, gpuobj);
282 	if (ret)
283 		nvkm_gpuobj_del(pgpuobj);
284 	return ret;
285 }
286 
287 /* the below is basically only here to support sharing the paged dma object
288  * for PCI(E)GART on <=nv4x chipsets, and should *not* be expected to work
289  * anywhere else.
290  */
291 
292 int
nvkm_gpuobj_wrap(struct nvkm_memory * memory,struct nvkm_gpuobj ** pgpuobj)293 nvkm_gpuobj_wrap(struct nvkm_memory *memory, struct nvkm_gpuobj **pgpuobj)
294 {
295 	if (!(*pgpuobj = kzalloc(sizeof(**pgpuobj), GFP_KERNEL)))
296 		return -ENOMEM;
297 
298 	(*pgpuobj)->addr = nvkm_memory_addr(memory);
299 	(*pgpuobj)->size = nvkm_memory_size(memory);
300 	return 0;
301 }
302 
303 void
nvkm_gpuobj_memcpy_to(struct nvkm_gpuobj * dst,u32 dstoffset,void * src,u32 length)304 nvkm_gpuobj_memcpy_to(struct nvkm_gpuobj *dst, u32 dstoffset, void *src,
305 		      u32 length)
306 {
307 	int i;
308 
309 	for (i = 0; i < length; i += 4)
310 		nvkm_wo32(dst, dstoffset + i, *(u32 *)(src + i));
311 }
312 
313 void
nvkm_gpuobj_memcpy_from(void * dst,struct nvkm_gpuobj * src,u32 srcoffset,u32 length)314 nvkm_gpuobj_memcpy_from(void *dst, struct nvkm_gpuobj *src, u32 srcoffset,
315 			u32 length)
316 {
317 	int i;
318 
319 	for (i = 0; i < length; i += 4)
320 		((u32 *)src)[i / 4] = nvkm_ro32(src, srcoffset + i);
321 }
322