xref: /aosp_15_r20/external/libdrm/freedreno/kgsl/kgsl_ringbuffer.c (revision 7688df22e49036ff52a766b7101da3a49edadb8c)
1*7688df22SAndroid Build Coastguard Worker /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2*7688df22SAndroid Build Coastguard Worker 
3*7688df22SAndroid Build Coastguard Worker /*
4*7688df22SAndroid Build Coastguard Worker  * Copyright (C) 2013 Rob Clark <[email protected]>
5*7688df22SAndroid Build Coastguard Worker  *
6*7688df22SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
7*7688df22SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
8*7688df22SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
9*7688df22SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10*7688df22SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
11*7688df22SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
12*7688df22SAndroid Build Coastguard Worker  *
13*7688df22SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
14*7688df22SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
15*7688df22SAndroid Build Coastguard Worker  * Software.
16*7688df22SAndroid Build Coastguard Worker  *
17*7688df22SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18*7688df22SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19*7688df22SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20*7688df22SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21*7688df22SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22*7688df22SAndroid Build Coastguard Worker  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23*7688df22SAndroid Build Coastguard Worker  * SOFTWARE.
24*7688df22SAndroid Build Coastguard Worker  *
25*7688df22SAndroid Build Coastguard Worker  * Authors:
26*7688df22SAndroid Build Coastguard Worker  *    Rob Clark <[email protected]>
27*7688df22SAndroid Build Coastguard Worker  */
28*7688df22SAndroid Build Coastguard Worker 
29*7688df22SAndroid Build Coastguard Worker #include <assert.h>
30*7688df22SAndroid Build Coastguard Worker 
31*7688df22SAndroid Build Coastguard Worker #include "xf86atomic.h"
32*7688df22SAndroid Build Coastguard Worker #include "freedreno_ringbuffer.h"
33*7688df22SAndroid Build Coastguard Worker #include "kgsl_priv.h"
34*7688df22SAndroid Build Coastguard Worker 
35*7688df22SAndroid Build Coastguard Worker 
36*7688df22SAndroid Build Coastguard Worker /* because kgsl tries to validate the gpuaddr on kernel side in ISSUEIBCMDS,
37*7688df22SAndroid Build Coastguard Worker  * we can't use normal gem bo's for ringbuffer..  someday the kernel part
38*7688df22SAndroid Build Coastguard Worker  * needs to be reworked into a single sane drm driver :-/
39*7688df22SAndroid Build Coastguard Worker  */
40*7688df22SAndroid Build Coastguard Worker struct kgsl_rb_bo {
41*7688df22SAndroid Build Coastguard Worker 	struct kgsl_pipe *pipe;
42*7688df22SAndroid Build Coastguard Worker 	void    *hostptr;
43*7688df22SAndroid Build Coastguard Worker 	uint32_t gpuaddr;
44*7688df22SAndroid Build Coastguard Worker 	uint32_t size;
45*7688df22SAndroid Build Coastguard Worker };
46*7688df22SAndroid Build Coastguard Worker 
47*7688df22SAndroid Build Coastguard Worker struct kgsl_ringbuffer {
48*7688df22SAndroid Build Coastguard Worker 	struct fd_ringbuffer base;
49*7688df22SAndroid Build Coastguard Worker 	struct kgsl_rb_bo *bo;
50*7688df22SAndroid Build Coastguard Worker };
51*7688df22SAndroid Build Coastguard Worker 
to_kgsl_ringbuffer(struct fd_ringbuffer * x)52*7688df22SAndroid Build Coastguard Worker static inline struct kgsl_ringbuffer * to_kgsl_ringbuffer(struct fd_ringbuffer *x)
53*7688df22SAndroid Build Coastguard Worker {
54*7688df22SAndroid Build Coastguard Worker 	return (struct kgsl_ringbuffer *)x;
55*7688df22SAndroid Build Coastguard Worker }
56*7688df22SAndroid Build Coastguard Worker 
kgsl_rb_bo_del(struct kgsl_rb_bo * bo)57*7688df22SAndroid Build Coastguard Worker static void kgsl_rb_bo_del(struct kgsl_rb_bo *bo)
58*7688df22SAndroid Build Coastguard Worker {
59*7688df22SAndroid Build Coastguard Worker 	struct kgsl_sharedmem_free req = {
60*7688df22SAndroid Build Coastguard Worker 			.gpuaddr = bo->gpuaddr,
61*7688df22SAndroid Build Coastguard Worker 	};
62*7688df22SAndroid Build Coastguard Worker 	int ret;
63*7688df22SAndroid Build Coastguard Worker 
64*7688df22SAndroid Build Coastguard Worker 	drm_munmap(bo->hostptr, bo->size);
65*7688df22SAndroid Build Coastguard Worker 
66*7688df22SAndroid Build Coastguard Worker 	ret = ioctl(bo->pipe->fd, IOCTL_KGSL_SHAREDMEM_FREE, &req);
67*7688df22SAndroid Build Coastguard Worker 	if (ret) {
68*7688df22SAndroid Build Coastguard Worker 		ERROR_MSG("sharedmem free failed: %s", strerror(errno));
69*7688df22SAndroid Build Coastguard Worker 	}
70*7688df22SAndroid Build Coastguard Worker 
71*7688df22SAndroid Build Coastguard Worker 	free(bo);
72*7688df22SAndroid Build Coastguard Worker }
73*7688df22SAndroid Build Coastguard Worker 
kgsl_rb_bo_new(struct kgsl_pipe * pipe,uint32_t size)74*7688df22SAndroid Build Coastguard Worker static struct kgsl_rb_bo * kgsl_rb_bo_new(struct kgsl_pipe *pipe, uint32_t size)
75*7688df22SAndroid Build Coastguard Worker {
76*7688df22SAndroid Build Coastguard Worker 	struct kgsl_rb_bo *bo;
77*7688df22SAndroid Build Coastguard Worker 	struct kgsl_gpumem_alloc req = {
78*7688df22SAndroid Build Coastguard Worker 			.size = ALIGN(size, 4096),
79*7688df22SAndroid Build Coastguard Worker 			.flags = KGSL_MEMFLAGS_GPUREADONLY,
80*7688df22SAndroid Build Coastguard Worker 	};
81*7688df22SAndroid Build Coastguard Worker 	int ret;
82*7688df22SAndroid Build Coastguard Worker 
83*7688df22SAndroid Build Coastguard Worker 	bo = calloc(1, sizeof(*bo));
84*7688df22SAndroid Build Coastguard Worker 	if (!bo) {
85*7688df22SAndroid Build Coastguard Worker 		ERROR_MSG("allocation failed");
86*7688df22SAndroid Build Coastguard Worker 		return NULL;
87*7688df22SAndroid Build Coastguard Worker 	}
88*7688df22SAndroid Build Coastguard Worker 	ret = ioctl(pipe->fd, IOCTL_KGSL_GPUMEM_ALLOC, &req);
89*7688df22SAndroid Build Coastguard Worker 	if (ret) {
90*7688df22SAndroid Build Coastguard Worker 		ERROR_MSG("gpumem allocation failed: %s", strerror(errno));
91*7688df22SAndroid Build Coastguard Worker 		goto fail;
92*7688df22SAndroid Build Coastguard Worker 	}
93*7688df22SAndroid Build Coastguard Worker 
94*7688df22SAndroid Build Coastguard Worker 	bo->pipe = pipe;
95*7688df22SAndroid Build Coastguard Worker 	bo->gpuaddr = req.gpuaddr;
96*7688df22SAndroid Build Coastguard Worker 	bo->size = size;
97*7688df22SAndroid Build Coastguard Worker 	bo->hostptr = drm_mmap(NULL, size, PROT_WRITE|PROT_READ,
98*7688df22SAndroid Build Coastguard Worker 				MAP_SHARED, pipe->fd, req.gpuaddr);
99*7688df22SAndroid Build Coastguard Worker 
100*7688df22SAndroid Build Coastguard Worker 	return bo;
101*7688df22SAndroid Build Coastguard Worker fail:
102*7688df22SAndroid Build Coastguard Worker 	if (bo)
103*7688df22SAndroid Build Coastguard Worker 		kgsl_rb_bo_del(bo);
104*7688df22SAndroid Build Coastguard Worker 	return NULL;
105*7688df22SAndroid Build Coastguard Worker }
106*7688df22SAndroid Build Coastguard Worker 
kgsl_ringbuffer_hostptr(struct fd_ringbuffer * ring)107*7688df22SAndroid Build Coastguard Worker static void * kgsl_ringbuffer_hostptr(struct fd_ringbuffer *ring)
108*7688df22SAndroid Build Coastguard Worker {
109*7688df22SAndroid Build Coastguard Worker 	struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring);
110*7688df22SAndroid Build Coastguard Worker 	return kgsl_ring->bo->hostptr;
111*7688df22SAndroid Build Coastguard Worker }
112*7688df22SAndroid Build Coastguard Worker 
kgsl_ringbuffer_flush(struct fd_ringbuffer * ring,uint32_t * last_start,int in_fence_fd,int * out_fence_fd)113*7688df22SAndroid Build Coastguard Worker static int kgsl_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start,
114*7688df22SAndroid Build Coastguard Worker 		int in_fence_fd, int *out_fence_fd)
115*7688df22SAndroid Build Coastguard Worker {
116*7688df22SAndroid Build Coastguard Worker 	struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring);
117*7688df22SAndroid Build Coastguard Worker 	struct kgsl_pipe *kgsl_pipe = to_kgsl_pipe(ring->pipe);
118*7688df22SAndroid Build Coastguard Worker 	uint32_t offset = (uint8_t *)last_start - (uint8_t *)ring->start;
119*7688df22SAndroid Build Coastguard Worker 	struct kgsl_ibdesc ibdesc = {
120*7688df22SAndroid Build Coastguard Worker 			.gpuaddr     = kgsl_ring->bo->gpuaddr + offset,
121*7688df22SAndroid Build Coastguard Worker 			.hostptr     = last_start,
122*7688df22SAndroid Build Coastguard Worker 			.sizedwords  = ring->cur - last_start,
123*7688df22SAndroid Build Coastguard Worker 	};
124*7688df22SAndroid Build Coastguard Worker 	struct kgsl_ringbuffer_issueibcmds req = {
125*7688df22SAndroid Build Coastguard Worker 			.drawctxt_id = kgsl_pipe->drawctxt_id,
126*7688df22SAndroid Build Coastguard Worker 			.ibdesc_addr = (unsigned long)&ibdesc,
127*7688df22SAndroid Build Coastguard Worker 			.numibs      = 1,
128*7688df22SAndroid Build Coastguard Worker 			.flags       = KGSL_CONTEXT_SUBMIT_IB_LIST,
129*7688df22SAndroid Build Coastguard Worker 	};
130*7688df22SAndroid Build Coastguard Worker 	int ret;
131*7688df22SAndroid Build Coastguard Worker 
132*7688df22SAndroid Build Coastguard Worker 	assert(in_fence_fd == -1);
133*7688df22SAndroid Build Coastguard Worker 	assert(out_fence_fd == NULL);
134*7688df22SAndroid Build Coastguard Worker 
135*7688df22SAndroid Build Coastguard Worker 	kgsl_pipe_pre_submit(kgsl_pipe);
136*7688df22SAndroid Build Coastguard Worker 
137*7688df22SAndroid Build Coastguard Worker 	/* z180_cmdstream_issueibcmds() is made of fail: */
138*7688df22SAndroid Build Coastguard Worker 	if (ring->pipe->id == FD_PIPE_2D) {
139*7688df22SAndroid Build Coastguard Worker 		/* fix up size field in last cmd packet */
140*7688df22SAndroid Build Coastguard Worker 		uint32_t last_size = (uint32_t)(ring->cur - last_start);
141*7688df22SAndroid Build Coastguard Worker 		/* 5 is length of first packet, 2 for the two 7f000000's */
142*7688df22SAndroid Build Coastguard Worker 		last_start[2] = last_size - (5 + 2);
143*7688df22SAndroid Build Coastguard Worker 		ibdesc.gpuaddr = kgsl_ring->bo->gpuaddr;
144*7688df22SAndroid Build Coastguard Worker 		ibdesc.hostptr = kgsl_ring->bo->hostptr;
145*7688df22SAndroid Build Coastguard Worker 		ibdesc.sizedwords = 0x145;
146*7688df22SAndroid Build Coastguard Worker 		req.timestamp = (uintptr_t)kgsl_ring->bo->hostptr;
147*7688df22SAndroid Build Coastguard Worker 	}
148*7688df22SAndroid Build Coastguard Worker 
149*7688df22SAndroid Build Coastguard Worker 	do {
150*7688df22SAndroid Build Coastguard Worker 		ret = ioctl(kgsl_pipe->fd, IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS, &req);
151*7688df22SAndroid Build Coastguard Worker 	} while ((ret == -1) && ((errno == EINTR) || (errno == EAGAIN)));
152*7688df22SAndroid Build Coastguard Worker 	if (ret)
153*7688df22SAndroid Build Coastguard Worker 		ERROR_MSG("issueibcmds failed!  %d (%s)", ret, strerror(errno));
154*7688df22SAndroid Build Coastguard Worker 
155*7688df22SAndroid Build Coastguard Worker 	ring->last_timestamp = req.timestamp;
156*7688df22SAndroid Build Coastguard Worker 	ring->last_start = ring->cur;
157*7688df22SAndroid Build Coastguard Worker 
158*7688df22SAndroid Build Coastguard Worker 	kgsl_pipe_post_submit(kgsl_pipe, req.timestamp);
159*7688df22SAndroid Build Coastguard Worker 
160*7688df22SAndroid Build Coastguard Worker 	return ret;
161*7688df22SAndroid Build Coastguard Worker }
162*7688df22SAndroid Build Coastguard Worker 
kgsl_ringbuffer_emit_reloc(struct fd_ringbuffer * ring,const struct fd_reloc * r)163*7688df22SAndroid Build Coastguard Worker static void kgsl_ringbuffer_emit_reloc(struct fd_ringbuffer *ring,
164*7688df22SAndroid Build Coastguard Worker 		const struct fd_reloc *r)
165*7688df22SAndroid Build Coastguard Worker {
166*7688df22SAndroid Build Coastguard Worker 	struct kgsl_bo *kgsl_bo = to_kgsl_bo(r->bo);
167*7688df22SAndroid Build Coastguard Worker 	uint32_t addr = kgsl_bo_gpuaddr(kgsl_bo, r->offset);
168*7688df22SAndroid Build Coastguard Worker 	assert(addr);
169*7688df22SAndroid Build Coastguard Worker 	if (r->shift < 0)
170*7688df22SAndroid Build Coastguard Worker 		addr >>= -r->shift;
171*7688df22SAndroid Build Coastguard Worker 	else
172*7688df22SAndroid Build Coastguard Worker 		addr <<= r->shift;
173*7688df22SAndroid Build Coastguard Worker 	(*ring->cur++) = addr | r->or;
174*7688df22SAndroid Build Coastguard Worker 	kgsl_pipe_add_submit(to_kgsl_pipe(ring->pipe), kgsl_bo);
175*7688df22SAndroid Build Coastguard Worker }
176*7688df22SAndroid Build Coastguard Worker 
kgsl_ringbuffer_emit_reloc_ring(struct fd_ringbuffer * ring,struct fd_ringbuffer * target,uint32_t cmd_idx)177*7688df22SAndroid Build Coastguard Worker static uint32_t kgsl_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
178*7688df22SAndroid Build Coastguard Worker 		struct fd_ringbuffer *target, uint32_t cmd_idx)
179*7688df22SAndroid Build Coastguard Worker {
180*7688df22SAndroid Build Coastguard Worker 	struct kgsl_ringbuffer *target_ring = to_kgsl_ringbuffer(target);
181*7688df22SAndroid Build Coastguard Worker 	assert(cmd_idx == 0);
182*7688df22SAndroid Build Coastguard Worker 	(*ring->cur++) = target_ring->bo->gpuaddr;
183*7688df22SAndroid Build Coastguard Worker 	return 	offset_bytes(target->cur, target->start);
184*7688df22SAndroid Build Coastguard Worker }
185*7688df22SAndroid Build Coastguard Worker 
kgsl_ringbuffer_destroy(struct fd_ringbuffer * ring)186*7688df22SAndroid Build Coastguard Worker static void kgsl_ringbuffer_destroy(struct fd_ringbuffer *ring)
187*7688df22SAndroid Build Coastguard Worker {
188*7688df22SAndroid Build Coastguard Worker 	struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring);
189*7688df22SAndroid Build Coastguard Worker 	if (ring->last_timestamp)
190*7688df22SAndroid Build Coastguard Worker 		fd_pipe_wait(ring->pipe, ring->last_timestamp);
191*7688df22SAndroid Build Coastguard Worker 	if (kgsl_ring->bo)
192*7688df22SAndroid Build Coastguard Worker 		kgsl_rb_bo_del(kgsl_ring->bo);
193*7688df22SAndroid Build Coastguard Worker 	free(kgsl_ring);
194*7688df22SAndroid Build Coastguard Worker }
195*7688df22SAndroid Build Coastguard Worker 
196*7688df22SAndroid Build Coastguard Worker static const struct fd_ringbuffer_funcs funcs = {
197*7688df22SAndroid Build Coastguard Worker 		.hostptr = kgsl_ringbuffer_hostptr,
198*7688df22SAndroid Build Coastguard Worker 		.flush = kgsl_ringbuffer_flush,
199*7688df22SAndroid Build Coastguard Worker 		.emit_reloc = kgsl_ringbuffer_emit_reloc,
200*7688df22SAndroid Build Coastguard Worker 		.emit_reloc_ring = kgsl_ringbuffer_emit_reloc_ring,
201*7688df22SAndroid Build Coastguard Worker 		.destroy = kgsl_ringbuffer_destroy,
202*7688df22SAndroid Build Coastguard Worker };
203*7688df22SAndroid Build Coastguard Worker 
kgsl_ringbuffer_new(struct fd_pipe * pipe,uint32_t size,enum fd_ringbuffer_flags flags)204*7688df22SAndroid Build Coastguard Worker drm_private struct fd_ringbuffer * kgsl_ringbuffer_new(struct fd_pipe *pipe,
205*7688df22SAndroid Build Coastguard Worker 		uint32_t size, enum fd_ringbuffer_flags flags)
206*7688df22SAndroid Build Coastguard Worker {
207*7688df22SAndroid Build Coastguard Worker 	struct kgsl_ringbuffer *kgsl_ring;
208*7688df22SAndroid Build Coastguard Worker 	struct fd_ringbuffer *ring = NULL;
209*7688df22SAndroid Build Coastguard Worker 
210*7688df22SAndroid Build Coastguard Worker 	assert(!flags);
211*7688df22SAndroid Build Coastguard Worker 
212*7688df22SAndroid Build Coastguard Worker 	kgsl_ring = calloc(1, sizeof(*kgsl_ring));
213*7688df22SAndroid Build Coastguard Worker 	if (!kgsl_ring) {
214*7688df22SAndroid Build Coastguard Worker 		ERROR_MSG("allocation failed");
215*7688df22SAndroid Build Coastguard Worker 		goto fail;
216*7688df22SAndroid Build Coastguard Worker 	}
217*7688df22SAndroid Build Coastguard Worker 
218*7688df22SAndroid Build Coastguard Worker 	ring = &kgsl_ring->base;
219*7688df22SAndroid Build Coastguard Worker 	atomic_set(&ring->refcnt, 1);
220*7688df22SAndroid Build Coastguard Worker 
221*7688df22SAndroid Build Coastguard Worker 	ring->funcs = &funcs;
222*7688df22SAndroid Build Coastguard Worker 	ring->size = size;
223*7688df22SAndroid Build Coastguard Worker 
224*7688df22SAndroid Build Coastguard Worker 	kgsl_ring->bo = kgsl_rb_bo_new(to_kgsl_pipe(pipe), size);
225*7688df22SAndroid Build Coastguard Worker 	if (!kgsl_ring->bo) {
226*7688df22SAndroid Build Coastguard Worker 		ERROR_MSG("ringbuffer allocation failed");
227*7688df22SAndroid Build Coastguard Worker 		goto fail;
228*7688df22SAndroid Build Coastguard Worker 	}
229*7688df22SAndroid Build Coastguard Worker 
230*7688df22SAndroid Build Coastguard Worker 	return ring;
231*7688df22SAndroid Build Coastguard Worker fail:
232*7688df22SAndroid Build Coastguard Worker 	if (ring)
233*7688df22SAndroid Build Coastguard Worker 		fd_ringbuffer_del(ring);
234*7688df22SAndroid Build Coastguard Worker 	return NULL;
235*7688df22SAndroid Build Coastguard Worker }
236