xref: /aosp_15_r20/external/libdrm/radeon/radeon_cs_gem.c (revision 7688df22e49036ff52a766b7101da3a49edadb8c)
1*7688df22SAndroid Build Coastguard Worker /*
2*7688df22SAndroid Build Coastguard Worker  * Copyright © 2008 Jérôme Glisse
3*7688df22SAndroid Build Coastguard Worker  * All Rights Reserved.
4*7688df22SAndroid Build Coastguard Worker  *
5*7688df22SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining
6*7688df22SAndroid Build Coastguard Worker  * a copy of this software and associated documentation files (the
7*7688df22SAndroid Build Coastguard Worker  * "Software"), to deal in the Software without restriction, including
8*7688df22SAndroid Build Coastguard Worker  * without limitation the rights to use, copy, modify, merge, publish,
9*7688df22SAndroid Build Coastguard Worker  * distribute, sub license, and/or sell copies of the Software, and to
10*7688df22SAndroid Build Coastguard Worker  * permit persons to whom the Software is furnished to do so, subject to
11*7688df22SAndroid Build Coastguard Worker  * the following conditions:
12*7688df22SAndroid Build Coastguard Worker  *
13*7688df22SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14*7688df22SAndroid Build Coastguard Worker  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15*7688df22SAndroid Build Coastguard Worker  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16*7688df22SAndroid Build Coastguard Worker  * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
17*7688df22SAndroid Build Coastguard Worker  * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18*7688df22SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*7688df22SAndroid Build Coastguard Worker  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20*7688df22SAndroid Build Coastguard Worker  * USE OR OTHER DEALINGS IN THE SOFTWARE.
21*7688df22SAndroid Build Coastguard Worker  *
22*7688df22SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the
23*7688df22SAndroid Build Coastguard Worker  * next paragraph) shall be included in all copies or substantial portions
24*7688df22SAndroid Build Coastguard Worker  * of the Software.
25*7688df22SAndroid Build Coastguard Worker  */
26*7688df22SAndroid Build Coastguard Worker /*
27*7688df22SAndroid Build Coastguard Worker  * Authors:
28*7688df22SAndroid Build Coastguard Worker  *      Aapo Tahkola <[email protected]>
29*7688df22SAndroid Build Coastguard Worker  *      Nicolai Haehnle <[email protected]>
30*7688df22SAndroid Build Coastguard Worker  *      Jérôme Glisse <[email protected]>
31*7688df22SAndroid Build Coastguard Worker  */
32*7688df22SAndroid Build Coastguard Worker #include <assert.h>
33*7688df22SAndroid Build Coastguard Worker #include <errno.h>
34*7688df22SAndroid Build Coastguard Worker #include <stdlib.h>
35*7688df22SAndroid Build Coastguard Worker #include <string.h>
36*7688df22SAndroid Build Coastguard Worker #include <pthread.h>
37*7688df22SAndroid Build Coastguard Worker #include <sys/ioctl.h>
38*7688df22SAndroid Build Coastguard Worker #include "radeon_cs.h"
39*7688df22SAndroid Build Coastguard Worker #include "radeon_cs_int.h"
40*7688df22SAndroid Build Coastguard Worker #include "radeon_bo_int.h"
41*7688df22SAndroid Build Coastguard Worker #include "radeon_cs_gem.h"
42*7688df22SAndroid Build Coastguard Worker #include "radeon_bo_gem.h"
43*7688df22SAndroid Build Coastguard Worker #include "drm.h"
44*7688df22SAndroid Build Coastguard Worker #include "libdrm_macros.h"
45*7688df22SAndroid Build Coastguard Worker #include "xf86drm.h"
46*7688df22SAndroid Build Coastguard Worker #include "xf86atomic.h"
47*7688df22SAndroid Build Coastguard Worker #include "radeon_drm.h"
48*7688df22SAndroid Build Coastguard Worker 
49*7688df22SAndroid Build Coastguard Worker /* Add LIBDRM_RADEON_BOF_FILES to libdrm_radeon_la_SOURCES when building with BOF_DUMP */
50*7688df22SAndroid Build Coastguard Worker #define CS_BOF_DUMP 0
51*7688df22SAndroid Build Coastguard Worker #if CS_BOF_DUMP
52*7688df22SAndroid Build Coastguard Worker #include "bof.h"
53*7688df22SAndroid Build Coastguard Worker #endif
54*7688df22SAndroid Build Coastguard Worker 
55*7688df22SAndroid Build Coastguard Worker struct radeon_cs_manager_gem {
56*7688df22SAndroid Build Coastguard Worker     struct radeon_cs_manager    base;
57*7688df22SAndroid Build Coastguard Worker     uint32_t                    device_id;
58*7688df22SAndroid Build Coastguard Worker     unsigned                    nbof;
59*7688df22SAndroid Build Coastguard Worker };
60*7688df22SAndroid Build Coastguard Worker 
61*7688df22SAndroid Build Coastguard Worker #pragma pack(1)
62*7688df22SAndroid Build Coastguard Worker struct cs_reloc_gem {
63*7688df22SAndroid Build Coastguard Worker     uint32_t    handle;
64*7688df22SAndroid Build Coastguard Worker     uint32_t    read_domain;
65*7688df22SAndroid Build Coastguard Worker     uint32_t    write_domain;
66*7688df22SAndroid Build Coastguard Worker     uint32_t    flags;
67*7688df22SAndroid Build Coastguard Worker };
68*7688df22SAndroid Build Coastguard Worker 
69*7688df22SAndroid Build Coastguard Worker #pragma pack()
70*7688df22SAndroid Build Coastguard Worker #define RELOC_SIZE (sizeof(struct cs_reloc_gem) / sizeof(uint32_t))
71*7688df22SAndroid Build Coastguard Worker 
72*7688df22SAndroid Build Coastguard Worker struct cs_gem {
73*7688df22SAndroid Build Coastguard Worker     struct radeon_cs_int        base;
74*7688df22SAndroid Build Coastguard Worker     struct drm_radeon_cs        cs;
75*7688df22SAndroid Build Coastguard Worker     struct drm_radeon_cs_chunk  chunks[2];
76*7688df22SAndroid Build Coastguard Worker     unsigned                    nrelocs;
77*7688df22SAndroid Build Coastguard Worker     uint32_t                    *relocs;
78*7688df22SAndroid Build Coastguard Worker     struct radeon_bo_int        **relocs_bo;
79*7688df22SAndroid Build Coastguard Worker };
80*7688df22SAndroid Build Coastguard Worker 
81*7688df22SAndroid Build Coastguard Worker static pthread_mutex_t id_mutex = PTHREAD_MUTEX_INITIALIZER;
82*7688df22SAndroid Build Coastguard Worker static uint32_t cs_id_source = 0;
83*7688df22SAndroid Build Coastguard Worker 
84*7688df22SAndroid Build Coastguard Worker /**
85*7688df22SAndroid Build Coastguard Worker  * result is undefined if called with ~0
86*7688df22SAndroid Build Coastguard Worker  */
get_first_zero(const uint32_t n)87*7688df22SAndroid Build Coastguard Worker static uint32_t get_first_zero(const uint32_t n)
88*7688df22SAndroid Build Coastguard Worker {
89*7688df22SAndroid Build Coastguard Worker     /* __builtin_ctz returns number of trailing zeros. */
90*7688df22SAndroid Build Coastguard Worker     return 1 << __builtin_ctz(~n);
91*7688df22SAndroid Build Coastguard Worker }
92*7688df22SAndroid Build Coastguard Worker 
93*7688df22SAndroid Build Coastguard Worker /**
94*7688df22SAndroid Build Coastguard Worker  * Returns a free id for cs.
95*7688df22SAndroid Build Coastguard Worker  * If there is no free id we return zero
96*7688df22SAndroid Build Coastguard Worker  **/
generate_id(void)97*7688df22SAndroid Build Coastguard Worker static uint32_t generate_id(void)
98*7688df22SAndroid Build Coastguard Worker {
99*7688df22SAndroid Build Coastguard Worker     uint32_t r = 0;
100*7688df22SAndroid Build Coastguard Worker     pthread_mutex_lock( &id_mutex );
101*7688df22SAndroid Build Coastguard Worker     /* check for free ids */
102*7688df22SAndroid Build Coastguard Worker     if (cs_id_source != ~r) {
103*7688df22SAndroid Build Coastguard Worker         /* find first zero bit */
104*7688df22SAndroid Build Coastguard Worker         r = get_first_zero(cs_id_source);
105*7688df22SAndroid Build Coastguard Worker 
106*7688df22SAndroid Build Coastguard Worker         /* set id as reserved */
107*7688df22SAndroid Build Coastguard Worker         cs_id_source |= r;
108*7688df22SAndroid Build Coastguard Worker     }
109*7688df22SAndroid Build Coastguard Worker     pthread_mutex_unlock( &id_mutex );
110*7688df22SAndroid Build Coastguard Worker     return r;
111*7688df22SAndroid Build Coastguard Worker }
112*7688df22SAndroid Build Coastguard Worker 
113*7688df22SAndroid Build Coastguard Worker /**
114*7688df22SAndroid Build Coastguard Worker  * Free the id for later reuse
115*7688df22SAndroid Build Coastguard Worker  **/
free_id(uint32_t id)116*7688df22SAndroid Build Coastguard Worker static void free_id(uint32_t id)
117*7688df22SAndroid Build Coastguard Worker {
118*7688df22SAndroid Build Coastguard Worker     pthread_mutex_lock( &id_mutex );
119*7688df22SAndroid Build Coastguard Worker 
120*7688df22SAndroid Build Coastguard Worker     cs_id_source &= ~id;
121*7688df22SAndroid Build Coastguard Worker 
122*7688df22SAndroid Build Coastguard Worker     pthread_mutex_unlock( &id_mutex );
123*7688df22SAndroid Build Coastguard Worker }
124*7688df22SAndroid Build Coastguard Worker 
cs_gem_create(struct radeon_cs_manager * csm,uint32_t ndw)125*7688df22SAndroid Build Coastguard Worker static struct radeon_cs_int *cs_gem_create(struct radeon_cs_manager *csm,
126*7688df22SAndroid Build Coastguard Worker                                        uint32_t ndw)
127*7688df22SAndroid Build Coastguard Worker {
128*7688df22SAndroid Build Coastguard Worker     struct cs_gem *csg;
129*7688df22SAndroid Build Coastguard Worker 
130*7688df22SAndroid Build Coastguard Worker     /* max cmd buffer size is 64Kb */
131*7688df22SAndroid Build Coastguard Worker     if (ndw > (64 * 1024 / 4)) {
132*7688df22SAndroid Build Coastguard Worker         return NULL;
133*7688df22SAndroid Build Coastguard Worker     }
134*7688df22SAndroid Build Coastguard Worker     csg = (struct cs_gem*)calloc(1, sizeof(struct cs_gem));
135*7688df22SAndroid Build Coastguard Worker     if (csg == NULL) {
136*7688df22SAndroid Build Coastguard Worker         return NULL;
137*7688df22SAndroid Build Coastguard Worker     }
138*7688df22SAndroid Build Coastguard Worker     csg->base.csm = csm;
139*7688df22SAndroid Build Coastguard Worker     csg->base.ndw = 64 * 1024 / 4;
140*7688df22SAndroid Build Coastguard Worker     csg->base.packets = (uint32_t*)calloc(1, 64 * 1024);
141*7688df22SAndroid Build Coastguard Worker     if (csg->base.packets == NULL) {
142*7688df22SAndroid Build Coastguard Worker         free(csg);
143*7688df22SAndroid Build Coastguard Worker         return NULL;
144*7688df22SAndroid Build Coastguard Worker     }
145*7688df22SAndroid Build Coastguard Worker     csg->base.relocs_total_size = 0;
146*7688df22SAndroid Build Coastguard Worker     csg->base.crelocs = 0;
147*7688df22SAndroid Build Coastguard Worker     csg->base.id = generate_id();
148*7688df22SAndroid Build Coastguard Worker     csg->nrelocs = 4096 / (4 * 4) ;
149*7688df22SAndroid Build Coastguard Worker     csg->relocs_bo = (struct radeon_bo_int**)calloc(1,
150*7688df22SAndroid Build Coastguard Worker                                                 csg->nrelocs*sizeof(void*));
151*7688df22SAndroid Build Coastguard Worker     if (csg->relocs_bo == NULL) {
152*7688df22SAndroid Build Coastguard Worker         free(csg->base.packets);
153*7688df22SAndroid Build Coastguard Worker         free(csg);
154*7688df22SAndroid Build Coastguard Worker         return NULL;
155*7688df22SAndroid Build Coastguard Worker     }
156*7688df22SAndroid Build Coastguard Worker     csg->base.relocs = csg->relocs = (uint32_t*)calloc(1, 4096);
157*7688df22SAndroid Build Coastguard Worker     if (csg->relocs == NULL) {
158*7688df22SAndroid Build Coastguard Worker         free(csg->relocs_bo);
159*7688df22SAndroid Build Coastguard Worker         free(csg->base.packets);
160*7688df22SAndroid Build Coastguard Worker         free(csg);
161*7688df22SAndroid Build Coastguard Worker         return NULL;
162*7688df22SAndroid Build Coastguard Worker     }
163*7688df22SAndroid Build Coastguard Worker     csg->chunks[0].chunk_id = RADEON_CHUNK_ID_IB;
164*7688df22SAndroid Build Coastguard Worker     csg->chunks[0].length_dw = 0;
165*7688df22SAndroid Build Coastguard Worker     csg->chunks[0].chunk_data = (uint64_t)(uintptr_t)csg->base.packets;
166*7688df22SAndroid Build Coastguard Worker     csg->chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS;
167*7688df22SAndroid Build Coastguard Worker     csg->chunks[1].length_dw = 0;
168*7688df22SAndroid Build Coastguard Worker     csg->chunks[1].chunk_data = (uint64_t)(uintptr_t)csg->relocs;
169*7688df22SAndroid Build Coastguard Worker     return (struct radeon_cs_int*)csg;
170*7688df22SAndroid Build Coastguard Worker }
171*7688df22SAndroid Build Coastguard Worker 
cs_gem_write_reloc(struct radeon_cs_int * cs,struct radeon_bo * bo,uint32_t read_domain,uint32_t write_domain,uint32_t flags)172*7688df22SAndroid Build Coastguard Worker static int cs_gem_write_reloc(struct radeon_cs_int *cs,
173*7688df22SAndroid Build Coastguard Worker                               struct radeon_bo *bo,
174*7688df22SAndroid Build Coastguard Worker                               uint32_t read_domain,
175*7688df22SAndroid Build Coastguard Worker                               uint32_t write_domain,
176*7688df22SAndroid Build Coastguard Worker                               uint32_t flags)
177*7688df22SAndroid Build Coastguard Worker {
178*7688df22SAndroid Build Coastguard Worker     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
179*7688df22SAndroid Build Coastguard Worker     struct cs_gem *csg = (struct cs_gem*)cs;
180*7688df22SAndroid Build Coastguard Worker     struct cs_reloc_gem *reloc;
181*7688df22SAndroid Build Coastguard Worker     uint32_t idx;
182*7688df22SAndroid Build Coastguard Worker     unsigned i;
183*7688df22SAndroid Build Coastguard Worker 
184*7688df22SAndroid Build Coastguard Worker     assert(boi->space_accounted);
185*7688df22SAndroid Build Coastguard Worker 
186*7688df22SAndroid Build Coastguard Worker     /* check domains */
187*7688df22SAndroid Build Coastguard Worker     if ((read_domain && write_domain) || (!read_domain && !write_domain)) {
188*7688df22SAndroid Build Coastguard Worker         /* in one CS a bo can only be in read or write domain but not
189*7688df22SAndroid Build Coastguard Worker          * in read & write domain at the same time
190*7688df22SAndroid Build Coastguard Worker          */
191*7688df22SAndroid Build Coastguard Worker         return -EINVAL;
192*7688df22SAndroid Build Coastguard Worker     }
193*7688df22SAndroid Build Coastguard Worker     if (read_domain == RADEON_GEM_DOMAIN_CPU) {
194*7688df22SAndroid Build Coastguard Worker         return -EINVAL;
195*7688df22SAndroid Build Coastguard Worker     }
196*7688df22SAndroid Build Coastguard Worker     if (write_domain == RADEON_GEM_DOMAIN_CPU) {
197*7688df22SAndroid Build Coastguard Worker         return -EINVAL;
198*7688df22SAndroid Build Coastguard Worker     }
199*7688df22SAndroid Build Coastguard Worker     /* use bit field hash function to determine
200*7688df22SAndroid Build Coastguard Worker        if this bo is for sure not in this cs.*/
201*7688df22SAndroid Build Coastguard Worker     if ((atomic_read((atomic_t *)radeon_gem_get_reloc_in_cs(bo)) & cs->id)) {
202*7688df22SAndroid Build Coastguard Worker         /* check if bo is already referenced.
203*7688df22SAndroid Build Coastguard Worker          * Scanning from end to begin reduces cycles with mesa because
204*7688df22SAndroid Build Coastguard Worker          * it often relocates same shared dma bo again. */
205*7688df22SAndroid Build Coastguard Worker         for(i = cs->crelocs; i != 0;) {
206*7688df22SAndroid Build Coastguard Worker             --i;
207*7688df22SAndroid Build Coastguard Worker             idx = i * RELOC_SIZE;
208*7688df22SAndroid Build Coastguard Worker             reloc = (struct cs_reloc_gem*)&csg->relocs[idx];
209*7688df22SAndroid Build Coastguard Worker             if (reloc->handle == bo->handle) {
210*7688df22SAndroid Build Coastguard Worker                 /* Check domains must be in read or write. As we check already
211*7688df22SAndroid Build Coastguard Worker                  * checked that in argument one of the read or write domain was
212*7688df22SAndroid Build Coastguard Worker                  * set we only need to check that if previous reloc as the read
213*7688df22SAndroid Build Coastguard Worker                  * domain set then the read_domain should also be set for this
214*7688df22SAndroid Build Coastguard Worker                  * new relocation.
215*7688df22SAndroid Build Coastguard Worker                  */
216*7688df22SAndroid Build Coastguard Worker                 /* the DDX expects to read and write from same pixmap */
217*7688df22SAndroid Build Coastguard Worker                 if (write_domain && (reloc->read_domain & write_domain)) {
218*7688df22SAndroid Build Coastguard Worker                     reloc->read_domain = 0;
219*7688df22SAndroid Build Coastguard Worker                     reloc->write_domain = write_domain;
220*7688df22SAndroid Build Coastguard Worker                 } else if (read_domain & reloc->write_domain) {
221*7688df22SAndroid Build Coastguard Worker                     reloc->read_domain = 0;
222*7688df22SAndroid Build Coastguard Worker                 } else {
223*7688df22SAndroid Build Coastguard Worker                     if (write_domain != reloc->write_domain)
224*7688df22SAndroid Build Coastguard Worker                         return -EINVAL;
225*7688df22SAndroid Build Coastguard Worker                     if (read_domain != reloc->read_domain)
226*7688df22SAndroid Build Coastguard Worker                         return -EINVAL;
227*7688df22SAndroid Build Coastguard Worker                 }
228*7688df22SAndroid Build Coastguard Worker 
229*7688df22SAndroid Build Coastguard Worker                 reloc->read_domain |= read_domain;
230*7688df22SAndroid Build Coastguard Worker                 reloc->write_domain |= write_domain;
231*7688df22SAndroid Build Coastguard Worker                 /* update flags */
232*7688df22SAndroid Build Coastguard Worker                 reloc->flags |= (flags & reloc->flags);
233*7688df22SAndroid Build Coastguard Worker                 /* write relocation packet */
234*7688df22SAndroid Build Coastguard Worker                 radeon_cs_write_dword((struct radeon_cs *)cs, 0xc0001000);
235*7688df22SAndroid Build Coastguard Worker                 radeon_cs_write_dword((struct radeon_cs *)cs, idx);
236*7688df22SAndroid Build Coastguard Worker                 return 0;
237*7688df22SAndroid Build Coastguard Worker             }
238*7688df22SAndroid Build Coastguard Worker         }
239*7688df22SAndroid Build Coastguard Worker     }
240*7688df22SAndroid Build Coastguard Worker     /* new relocation */
241*7688df22SAndroid Build Coastguard Worker     if (csg->base.crelocs >= csg->nrelocs) {
242*7688df22SAndroid Build Coastguard Worker         /* allocate more memory (TODO: should use a slab allocator maybe) */
243*7688df22SAndroid Build Coastguard Worker         uint32_t *tmp, size;
244*7688df22SAndroid Build Coastguard Worker         size = ((csg->nrelocs + 1) * sizeof(struct radeon_bo*));
245*7688df22SAndroid Build Coastguard Worker         tmp = (uint32_t*)realloc(csg->relocs_bo, size);
246*7688df22SAndroid Build Coastguard Worker         if (tmp == NULL) {
247*7688df22SAndroid Build Coastguard Worker             return -ENOMEM;
248*7688df22SAndroid Build Coastguard Worker         }
249*7688df22SAndroid Build Coastguard Worker         csg->relocs_bo = (struct radeon_bo_int **)tmp;
250*7688df22SAndroid Build Coastguard Worker         size = ((csg->nrelocs + 1) * RELOC_SIZE * 4);
251*7688df22SAndroid Build Coastguard Worker         tmp = (uint32_t*)realloc(csg->relocs, size);
252*7688df22SAndroid Build Coastguard Worker         if (tmp == NULL) {
253*7688df22SAndroid Build Coastguard Worker             return -ENOMEM;
254*7688df22SAndroid Build Coastguard Worker         }
255*7688df22SAndroid Build Coastguard Worker         cs->relocs = csg->relocs = tmp;
256*7688df22SAndroid Build Coastguard Worker         csg->nrelocs += 1;
257*7688df22SAndroid Build Coastguard Worker         csg->chunks[1].chunk_data = (uint64_t)(uintptr_t)csg->relocs;
258*7688df22SAndroid Build Coastguard Worker     }
259*7688df22SAndroid Build Coastguard Worker     csg->relocs_bo[csg->base.crelocs] = boi;
260*7688df22SAndroid Build Coastguard Worker     idx = (csg->base.crelocs++) * RELOC_SIZE;
261*7688df22SAndroid Build Coastguard Worker     reloc = (struct cs_reloc_gem*)&csg->relocs[idx];
262*7688df22SAndroid Build Coastguard Worker     reloc->handle = bo->handle;
263*7688df22SAndroid Build Coastguard Worker     reloc->read_domain = read_domain;
264*7688df22SAndroid Build Coastguard Worker     reloc->write_domain = write_domain;
265*7688df22SAndroid Build Coastguard Worker     reloc->flags = flags;
266*7688df22SAndroid Build Coastguard Worker     csg->chunks[1].length_dw += RELOC_SIZE;
267*7688df22SAndroid Build Coastguard Worker     radeon_bo_ref(bo);
268*7688df22SAndroid Build Coastguard Worker     /* bo might be referenced from another context so have to use atomic operations */
269*7688df22SAndroid Build Coastguard Worker     atomic_add((atomic_t *)radeon_gem_get_reloc_in_cs(bo), cs->id);
270*7688df22SAndroid Build Coastguard Worker     cs->relocs_total_size += boi->size;
271*7688df22SAndroid Build Coastguard Worker     radeon_cs_write_dword((struct radeon_cs *)cs, 0xc0001000);
272*7688df22SAndroid Build Coastguard Worker     radeon_cs_write_dword((struct radeon_cs *)cs, idx);
273*7688df22SAndroid Build Coastguard Worker     return 0;
274*7688df22SAndroid Build Coastguard Worker }
275*7688df22SAndroid Build Coastguard Worker 
cs_gem_begin(struct radeon_cs_int * cs,uint32_t ndw,const char * file,const char * func,int line)276*7688df22SAndroid Build Coastguard Worker static int cs_gem_begin(struct radeon_cs_int *cs,
277*7688df22SAndroid Build Coastguard Worker                         uint32_t ndw,
278*7688df22SAndroid Build Coastguard Worker                         const char *file,
279*7688df22SAndroid Build Coastguard Worker                         const char *func,
280*7688df22SAndroid Build Coastguard Worker                         int line)
281*7688df22SAndroid Build Coastguard Worker {
282*7688df22SAndroid Build Coastguard Worker 
283*7688df22SAndroid Build Coastguard Worker     if (cs->section_ndw) {
284*7688df22SAndroid Build Coastguard Worker         fprintf(stderr, "CS already in a section(%s,%s,%d)\n",
285*7688df22SAndroid Build Coastguard Worker                 cs->section_file, cs->section_func, cs->section_line);
286*7688df22SAndroid Build Coastguard Worker         fprintf(stderr, "CS can't start section(%s,%s,%d)\n",
287*7688df22SAndroid Build Coastguard Worker                 file, func, line);
288*7688df22SAndroid Build Coastguard Worker         return -EPIPE;
289*7688df22SAndroid Build Coastguard Worker     }
290*7688df22SAndroid Build Coastguard Worker     cs->section_ndw = ndw;
291*7688df22SAndroid Build Coastguard Worker     cs->section_cdw = 0;
292*7688df22SAndroid Build Coastguard Worker     cs->section_file = file;
293*7688df22SAndroid Build Coastguard Worker     cs->section_func = func;
294*7688df22SAndroid Build Coastguard Worker     cs->section_line = line;
295*7688df22SAndroid Build Coastguard Worker 
296*7688df22SAndroid Build Coastguard Worker     if (cs->cdw + ndw > cs->ndw) {
297*7688df22SAndroid Build Coastguard Worker         uint32_t tmp, *ptr;
298*7688df22SAndroid Build Coastguard Worker 
299*7688df22SAndroid Build Coastguard Worker         /* round up the required size to a multiple of 1024 */
300*7688df22SAndroid Build Coastguard Worker         tmp = (cs->cdw + ndw + 0x3FF) & (~0x3FF);
301*7688df22SAndroid Build Coastguard Worker         ptr = (uint32_t*)realloc(cs->packets, 4 * tmp);
302*7688df22SAndroid Build Coastguard Worker         if (ptr == NULL) {
303*7688df22SAndroid Build Coastguard Worker             return -ENOMEM;
304*7688df22SAndroid Build Coastguard Worker         }
305*7688df22SAndroid Build Coastguard Worker         cs->packets = ptr;
306*7688df22SAndroid Build Coastguard Worker         cs->ndw = tmp;
307*7688df22SAndroid Build Coastguard Worker     }
308*7688df22SAndroid Build Coastguard Worker     return 0;
309*7688df22SAndroid Build Coastguard Worker }
310*7688df22SAndroid Build Coastguard Worker 
cs_gem_end(struct radeon_cs_int * cs,const char * file,const char * func,int line)311*7688df22SAndroid Build Coastguard Worker static int cs_gem_end(struct radeon_cs_int *cs,
312*7688df22SAndroid Build Coastguard Worker                       const char *file,
313*7688df22SAndroid Build Coastguard Worker                       const char *func,
314*7688df22SAndroid Build Coastguard Worker                       int line)
315*7688df22SAndroid Build Coastguard Worker 
316*7688df22SAndroid Build Coastguard Worker {
317*7688df22SAndroid Build Coastguard Worker     if (!cs->section_ndw) {
318*7688df22SAndroid Build Coastguard Worker         fprintf(stderr, "CS no section to end at (%s,%s,%d)\n",
319*7688df22SAndroid Build Coastguard Worker                 file, func, line);
320*7688df22SAndroid Build Coastguard Worker         return -EPIPE;
321*7688df22SAndroid Build Coastguard Worker     }
322*7688df22SAndroid Build Coastguard Worker     if (cs->section_ndw != cs->section_cdw) {
323*7688df22SAndroid Build Coastguard Worker         fprintf(stderr, "CS section size mismatch start at (%s,%s,%d) %d vs %d\n",
324*7688df22SAndroid Build Coastguard Worker                 cs->section_file, cs->section_func, cs->section_line, cs->section_ndw, cs->section_cdw);
325*7688df22SAndroid Build Coastguard Worker         fprintf(stderr, "CS section end at (%s,%s,%d)\n",
326*7688df22SAndroid Build Coastguard Worker                 file, func, line);
327*7688df22SAndroid Build Coastguard Worker 
328*7688df22SAndroid Build Coastguard Worker         /* We must reset the section even when there is error. */
329*7688df22SAndroid Build Coastguard Worker         cs->section_ndw = 0;
330*7688df22SAndroid Build Coastguard Worker         return -EPIPE;
331*7688df22SAndroid Build Coastguard Worker     }
332*7688df22SAndroid Build Coastguard Worker     cs->section_ndw = 0;
333*7688df22SAndroid Build Coastguard Worker     return 0;
334*7688df22SAndroid Build Coastguard Worker }
335*7688df22SAndroid Build Coastguard Worker 
336*7688df22SAndroid Build Coastguard Worker #if CS_BOF_DUMP
cs_gem_dump_bof(struct radeon_cs_int * cs)337*7688df22SAndroid Build Coastguard Worker static void cs_gem_dump_bof(struct radeon_cs_int *cs)
338*7688df22SAndroid Build Coastguard Worker {
339*7688df22SAndroid Build Coastguard Worker     struct cs_gem *csg = (struct cs_gem*)cs;
340*7688df22SAndroid Build Coastguard Worker     struct radeon_cs_manager_gem *csm;
341*7688df22SAndroid Build Coastguard Worker     bof_t *bcs, *blob, *array, *bo, *size, *handle, *device_id, *root;
342*7688df22SAndroid Build Coastguard Worker     char tmp[256];
343*7688df22SAndroid Build Coastguard Worker     unsigned i;
344*7688df22SAndroid Build Coastguard Worker 
345*7688df22SAndroid Build Coastguard Worker     csm = (struct radeon_cs_manager_gem *)cs->csm;
346*7688df22SAndroid Build Coastguard Worker     root = device_id = bcs = blob = array = bo = size = handle = NULL;
347*7688df22SAndroid Build Coastguard Worker     root = bof_object();
348*7688df22SAndroid Build Coastguard Worker     if (root == NULL)
349*7688df22SAndroid Build Coastguard Worker         goto out_err;
350*7688df22SAndroid Build Coastguard Worker     device_id = bof_int32(csm->device_id);
351*7688df22SAndroid Build Coastguard Worker     if (device_id == NULL)
352*7688df22SAndroid Build Coastguard Worker         return;
353*7688df22SAndroid Build Coastguard Worker     if (bof_object_set(root, "device_id", device_id))
354*7688df22SAndroid Build Coastguard Worker         goto out_err;
355*7688df22SAndroid Build Coastguard Worker     bof_decref(device_id);
356*7688df22SAndroid Build Coastguard Worker     device_id = NULL;
357*7688df22SAndroid Build Coastguard Worker     /* dump relocs */
358*7688df22SAndroid Build Coastguard Worker     blob = bof_blob(csg->nrelocs * 16, csg->relocs);
359*7688df22SAndroid Build Coastguard Worker     if (blob == NULL)
360*7688df22SAndroid Build Coastguard Worker         goto out_err;
361*7688df22SAndroid Build Coastguard Worker     if (bof_object_set(root, "reloc", blob))
362*7688df22SAndroid Build Coastguard Worker         goto out_err;
363*7688df22SAndroid Build Coastguard Worker     bof_decref(blob);
364*7688df22SAndroid Build Coastguard Worker     blob = NULL;
365*7688df22SAndroid Build Coastguard Worker     /* dump cs */
366*7688df22SAndroid Build Coastguard Worker     blob = bof_blob(cs->cdw * 4, cs->packets);
367*7688df22SAndroid Build Coastguard Worker     if (blob == NULL)
368*7688df22SAndroid Build Coastguard Worker         goto out_err;
369*7688df22SAndroid Build Coastguard Worker     if (bof_object_set(root, "pm4", blob))
370*7688df22SAndroid Build Coastguard Worker         goto out_err;
371*7688df22SAndroid Build Coastguard Worker     bof_decref(blob);
372*7688df22SAndroid Build Coastguard Worker     blob = NULL;
373*7688df22SAndroid Build Coastguard Worker     /* dump bo */
374*7688df22SAndroid Build Coastguard Worker     array = bof_array();
375*7688df22SAndroid Build Coastguard Worker     if (array == NULL)
376*7688df22SAndroid Build Coastguard Worker         goto out_err;
377*7688df22SAndroid Build Coastguard Worker     for (i = 0; i < csg->base.crelocs; i++) {
378*7688df22SAndroid Build Coastguard Worker         bo = bof_object();
379*7688df22SAndroid Build Coastguard Worker         if (bo == NULL)
380*7688df22SAndroid Build Coastguard Worker             goto out_err;
381*7688df22SAndroid Build Coastguard Worker         size = bof_int32(csg->relocs_bo[i]->size);
382*7688df22SAndroid Build Coastguard Worker         if (size == NULL)
383*7688df22SAndroid Build Coastguard Worker             goto out_err;
384*7688df22SAndroid Build Coastguard Worker         if (bof_object_set(bo, "size", size))
385*7688df22SAndroid Build Coastguard Worker             goto out_err;
386*7688df22SAndroid Build Coastguard Worker         bof_decref(size);
387*7688df22SAndroid Build Coastguard Worker         size = NULL;
388*7688df22SAndroid Build Coastguard Worker         handle = bof_int32(csg->relocs_bo[i]->handle);
389*7688df22SAndroid Build Coastguard Worker         if (handle == NULL)
390*7688df22SAndroid Build Coastguard Worker             goto out_err;
391*7688df22SAndroid Build Coastguard Worker         if (bof_object_set(bo, "handle", handle))
392*7688df22SAndroid Build Coastguard Worker             goto out_err;
393*7688df22SAndroid Build Coastguard Worker         bof_decref(handle);
394*7688df22SAndroid Build Coastguard Worker         handle = NULL;
395*7688df22SAndroid Build Coastguard Worker         radeon_bo_map((struct radeon_bo*)csg->relocs_bo[i], 0);
396*7688df22SAndroid Build Coastguard Worker         blob = bof_blob(csg->relocs_bo[i]->size, csg->relocs_bo[i]->ptr);
397*7688df22SAndroid Build Coastguard Worker         radeon_bo_unmap((struct radeon_bo*)csg->relocs_bo[i]);
398*7688df22SAndroid Build Coastguard Worker         if (blob == NULL)
399*7688df22SAndroid Build Coastguard Worker             goto out_err;
400*7688df22SAndroid Build Coastguard Worker         if (bof_object_set(bo, "data", blob))
401*7688df22SAndroid Build Coastguard Worker             goto out_err;
402*7688df22SAndroid Build Coastguard Worker         bof_decref(blob);
403*7688df22SAndroid Build Coastguard Worker         blob = NULL;
404*7688df22SAndroid Build Coastguard Worker         if (bof_array_append(array, bo))
405*7688df22SAndroid Build Coastguard Worker             goto out_err;
406*7688df22SAndroid Build Coastguard Worker         bof_decref(bo);
407*7688df22SAndroid Build Coastguard Worker         bo = NULL;
408*7688df22SAndroid Build Coastguard Worker     }
409*7688df22SAndroid Build Coastguard Worker     if (bof_object_set(root, "bo", array))
410*7688df22SAndroid Build Coastguard Worker         goto out_err;
411*7688df22SAndroid Build Coastguard Worker     sprintf(tmp, "d-0x%04X-%08d.bof", csm->device_id, csm->nbof++);
412*7688df22SAndroid Build Coastguard Worker     bof_dump_file(root, tmp);
413*7688df22SAndroid Build Coastguard Worker out_err:
414*7688df22SAndroid Build Coastguard Worker     bof_decref(blob);
415*7688df22SAndroid Build Coastguard Worker     bof_decref(array);
416*7688df22SAndroid Build Coastguard Worker     bof_decref(bo);
417*7688df22SAndroid Build Coastguard Worker     bof_decref(size);
418*7688df22SAndroid Build Coastguard Worker     bof_decref(handle);
419*7688df22SAndroid Build Coastguard Worker     bof_decref(device_id);
420*7688df22SAndroid Build Coastguard Worker     bof_decref(root);
421*7688df22SAndroid Build Coastguard Worker }
422*7688df22SAndroid Build Coastguard Worker #endif
423*7688df22SAndroid Build Coastguard Worker 
cs_gem_emit(struct radeon_cs_int * cs)424*7688df22SAndroid Build Coastguard Worker static int cs_gem_emit(struct radeon_cs_int *cs)
425*7688df22SAndroid Build Coastguard Worker {
426*7688df22SAndroid Build Coastguard Worker     struct cs_gem *csg = (struct cs_gem*)cs;
427*7688df22SAndroid Build Coastguard Worker     uint64_t chunk_array[2];
428*7688df22SAndroid Build Coastguard Worker     unsigned i;
429*7688df22SAndroid Build Coastguard Worker     int r;
430*7688df22SAndroid Build Coastguard Worker 
431*7688df22SAndroid Build Coastguard Worker     while (cs->cdw & 7)
432*7688df22SAndroid Build Coastguard Worker 	radeon_cs_write_dword((struct radeon_cs *)cs, 0x80000000);
433*7688df22SAndroid Build Coastguard Worker 
434*7688df22SAndroid Build Coastguard Worker #if CS_BOF_DUMP
435*7688df22SAndroid Build Coastguard Worker     cs_gem_dump_bof(cs);
436*7688df22SAndroid Build Coastguard Worker #endif
437*7688df22SAndroid Build Coastguard Worker     csg->chunks[0].length_dw = cs->cdw;
438*7688df22SAndroid Build Coastguard Worker 
439*7688df22SAndroid Build Coastguard Worker     chunk_array[0] = (uint64_t)(uintptr_t)&csg->chunks[0];
440*7688df22SAndroid Build Coastguard Worker     chunk_array[1] = (uint64_t)(uintptr_t)&csg->chunks[1];
441*7688df22SAndroid Build Coastguard Worker 
442*7688df22SAndroid Build Coastguard Worker     csg->cs.num_chunks = 2;
443*7688df22SAndroid Build Coastguard Worker     csg->cs.chunks = (uint64_t)(uintptr_t)chunk_array;
444*7688df22SAndroid Build Coastguard Worker 
445*7688df22SAndroid Build Coastguard Worker     r = drmCommandWriteRead(cs->csm->fd, DRM_RADEON_CS,
446*7688df22SAndroid Build Coastguard Worker                             &csg->cs, sizeof(struct drm_radeon_cs));
447*7688df22SAndroid Build Coastguard Worker     for (i = 0; i < csg->base.crelocs; i++) {
448*7688df22SAndroid Build Coastguard Worker         csg->relocs_bo[i]->space_accounted = 0;
449*7688df22SAndroid Build Coastguard Worker         /* bo might be referenced from another context so have to use atomic operations */
450*7688df22SAndroid Build Coastguard Worker         atomic_dec((atomic_t *)radeon_gem_get_reloc_in_cs((struct radeon_bo*)csg->relocs_bo[i]), cs->id);
451*7688df22SAndroid Build Coastguard Worker         radeon_bo_unref((struct radeon_bo *)csg->relocs_bo[i]);
452*7688df22SAndroid Build Coastguard Worker         csg->relocs_bo[i] = NULL;
453*7688df22SAndroid Build Coastguard Worker     }
454*7688df22SAndroid Build Coastguard Worker 
455*7688df22SAndroid Build Coastguard Worker     cs->csm->read_used = 0;
456*7688df22SAndroid Build Coastguard Worker     cs->csm->vram_write_used = 0;
457*7688df22SAndroid Build Coastguard Worker     cs->csm->gart_write_used = 0;
458*7688df22SAndroid Build Coastguard Worker     return r;
459*7688df22SAndroid Build Coastguard Worker }
460*7688df22SAndroid Build Coastguard Worker 
cs_gem_destroy(struct radeon_cs_int * cs)461*7688df22SAndroid Build Coastguard Worker static int cs_gem_destroy(struct radeon_cs_int *cs)
462*7688df22SAndroid Build Coastguard Worker {
463*7688df22SAndroid Build Coastguard Worker     struct cs_gem *csg = (struct cs_gem*)cs;
464*7688df22SAndroid Build Coastguard Worker 
465*7688df22SAndroid Build Coastguard Worker     free_id(cs->id);
466*7688df22SAndroid Build Coastguard Worker     free(csg->relocs_bo);
467*7688df22SAndroid Build Coastguard Worker     free(cs->relocs);
468*7688df22SAndroid Build Coastguard Worker     free(cs->packets);
469*7688df22SAndroid Build Coastguard Worker     free(cs);
470*7688df22SAndroid Build Coastguard Worker     return 0;
471*7688df22SAndroid Build Coastguard Worker }
472*7688df22SAndroid Build Coastguard Worker 
cs_gem_erase(struct radeon_cs_int * cs)473*7688df22SAndroid Build Coastguard Worker static int cs_gem_erase(struct radeon_cs_int *cs)
474*7688df22SAndroid Build Coastguard Worker {
475*7688df22SAndroid Build Coastguard Worker     struct cs_gem *csg = (struct cs_gem*)cs;
476*7688df22SAndroid Build Coastguard Worker     unsigned i;
477*7688df22SAndroid Build Coastguard Worker 
478*7688df22SAndroid Build Coastguard Worker     if (csg->relocs_bo) {
479*7688df22SAndroid Build Coastguard Worker         for (i = 0; i < csg->base.crelocs; i++) {
480*7688df22SAndroid Build Coastguard Worker             if (csg->relocs_bo[i]) {
481*7688df22SAndroid Build Coastguard Worker                 /* bo might be referenced from another context so have to use atomic operations */
482*7688df22SAndroid Build Coastguard Worker                 atomic_dec((atomic_t *)radeon_gem_get_reloc_in_cs((struct radeon_bo*)csg->relocs_bo[i]), cs->id);
483*7688df22SAndroid Build Coastguard Worker                 radeon_bo_unref((struct radeon_bo *)csg->relocs_bo[i]);
484*7688df22SAndroid Build Coastguard Worker                 csg->relocs_bo[i] = NULL;
485*7688df22SAndroid Build Coastguard Worker             }
486*7688df22SAndroid Build Coastguard Worker         }
487*7688df22SAndroid Build Coastguard Worker     }
488*7688df22SAndroid Build Coastguard Worker     cs->relocs_total_size = 0;
489*7688df22SAndroid Build Coastguard Worker     cs->cdw = 0;
490*7688df22SAndroid Build Coastguard Worker     cs->section_ndw = 0;
491*7688df22SAndroid Build Coastguard Worker     cs->crelocs = 0;
492*7688df22SAndroid Build Coastguard Worker     csg->chunks[0].length_dw = 0;
493*7688df22SAndroid Build Coastguard Worker     csg->chunks[1].length_dw = 0;
494*7688df22SAndroid Build Coastguard Worker     return 0;
495*7688df22SAndroid Build Coastguard Worker }
496*7688df22SAndroid Build Coastguard Worker 
cs_gem_need_flush(struct radeon_cs_int * cs)497*7688df22SAndroid Build Coastguard Worker static int cs_gem_need_flush(struct radeon_cs_int *cs)
498*7688df22SAndroid Build Coastguard Worker {
499*7688df22SAndroid Build Coastguard Worker     return 0; //(cs->relocs_total_size > (32*1024*1024));
500*7688df22SAndroid Build Coastguard Worker }
501*7688df22SAndroid Build Coastguard Worker 
cs_gem_print(struct radeon_cs_int * cs,FILE * file)502*7688df22SAndroid Build Coastguard Worker static void cs_gem_print(struct radeon_cs_int *cs, FILE *file)
503*7688df22SAndroid Build Coastguard Worker {
504*7688df22SAndroid Build Coastguard Worker     struct radeon_cs_manager_gem *csm;
505*7688df22SAndroid Build Coastguard Worker     unsigned int i;
506*7688df22SAndroid Build Coastguard Worker 
507*7688df22SAndroid Build Coastguard Worker     csm = (struct radeon_cs_manager_gem *)cs->csm;
508*7688df22SAndroid Build Coastguard Worker     fprintf(file, "VENDORID:DEVICEID 0x%04X:0x%04X\n", 0x1002, csm->device_id);
509*7688df22SAndroid Build Coastguard Worker     for (i = 0; i < cs->cdw; i++) {
510*7688df22SAndroid Build Coastguard Worker         fprintf(file, "0x%08X\n", cs->packets[i]);
511*7688df22SAndroid Build Coastguard Worker     }
512*7688df22SAndroid Build Coastguard Worker }
513*7688df22SAndroid Build Coastguard Worker 
514*7688df22SAndroid Build Coastguard Worker static const struct radeon_cs_funcs radeon_cs_gem_funcs = {
515*7688df22SAndroid Build Coastguard Worker     .cs_create = cs_gem_create,
516*7688df22SAndroid Build Coastguard Worker     .cs_write_reloc = cs_gem_write_reloc,
517*7688df22SAndroid Build Coastguard Worker     .cs_begin = cs_gem_begin,
518*7688df22SAndroid Build Coastguard Worker     .cs_end = cs_gem_end,
519*7688df22SAndroid Build Coastguard Worker     .cs_emit = cs_gem_emit,
520*7688df22SAndroid Build Coastguard Worker     .cs_destroy = cs_gem_destroy,
521*7688df22SAndroid Build Coastguard Worker     .cs_erase = cs_gem_erase,
522*7688df22SAndroid Build Coastguard Worker     .cs_need_flush = cs_gem_need_flush,
523*7688df22SAndroid Build Coastguard Worker     .cs_print = cs_gem_print,
524*7688df22SAndroid Build Coastguard Worker };
525*7688df22SAndroid Build Coastguard Worker 
radeon_get_device_id(int fd,uint32_t * device_id)526*7688df22SAndroid Build Coastguard Worker static int radeon_get_device_id(int fd, uint32_t *device_id)
527*7688df22SAndroid Build Coastguard Worker {
528*7688df22SAndroid Build Coastguard Worker     struct drm_radeon_info info = {};
529*7688df22SAndroid Build Coastguard Worker     int r;
530*7688df22SAndroid Build Coastguard Worker 
531*7688df22SAndroid Build Coastguard Worker     *device_id = 0;
532*7688df22SAndroid Build Coastguard Worker     info.request = RADEON_INFO_DEVICE_ID;
533*7688df22SAndroid Build Coastguard Worker     info.value = (uintptr_t)device_id;
534*7688df22SAndroid Build Coastguard Worker     r = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info,
535*7688df22SAndroid Build Coastguard Worker                             sizeof(struct drm_radeon_info));
536*7688df22SAndroid Build Coastguard Worker     return r;
537*7688df22SAndroid Build Coastguard Worker }
538*7688df22SAndroid Build Coastguard Worker 
radeon_cs_manager_gem_ctor(int fd)539*7688df22SAndroid Build Coastguard Worker drm_public struct radeon_cs_manager *radeon_cs_manager_gem_ctor(int fd)
540*7688df22SAndroid Build Coastguard Worker {
541*7688df22SAndroid Build Coastguard Worker     struct radeon_cs_manager_gem *csm;
542*7688df22SAndroid Build Coastguard Worker 
543*7688df22SAndroid Build Coastguard Worker     csm = calloc(1, sizeof(struct radeon_cs_manager_gem));
544*7688df22SAndroid Build Coastguard Worker     if (csm == NULL) {
545*7688df22SAndroid Build Coastguard Worker         return NULL;
546*7688df22SAndroid Build Coastguard Worker     }
547*7688df22SAndroid Build Coastguard Worker     csm->base.funcs = &radeon_cs_gem_funcs;
548*7688df22SAndroid Build Coastguard Worker     csm->base.fd = fd;
549*7688df22SAndroid Build Coastguard Worker     radeon_get_device_id(fd, &csm->device_id);
550*7688df22SAndroid Build Coastguard Worker     return &csm->base;
551*7688df22SAndroid Build Coastguard Worker }
552*7688df22SAndroid Build Coastguard Worker 
radeon_cs_manager_gem_dtor(struct radeon_cs_manager * csm)553*7688df22SAndroid Build Coastguard Worker drm_public void radeon_cs_manager_gem_dtor(struct radeon_cs_manager *csm)
554*7688df22SAndroid Build Coastguard Worker {
555*7688df22SAndroid Build Coastguard Worker     free(csm);
556*7688df22SAndroid Build Coastguard Worker }
557