radeon/r600: use new libdrm_radeon api
[mesa.git] / src / mesa / drivers / dri / r600 / r600_cmdbuf.c
1 /*
2 Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
3
4 The Weather Channel (TM) funded Tungsten Graphics to develop the
5 initial release of the Radeon 8500 driver under the XFree86 license.
6 This notice must be preserved.
7
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
15
16 The above copyright notice and this permission notice (including the
17 next paragraph) shall be included in all copies or substantial
18 portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28 **************************************************************************/
29
30 /**
31 * Mostly coppied from \radeon\radeon_cs_legacy.c
32 */
33
34 #include <errno.h>
35
36 #include "main/glheader.h"
37 #include "main/state.h"
38 #include "main/imports.h"
39 #include "main/macros.h"
40 #include "main/context.h"
41 #include "main/simple_list.h"
42 #include "swrast/swrast.h"
43
44 #include "drm.h"
45 #include "radeon_drm.h"
46
47 #include "r600_context.h"
48 #include "radeon_reg.h"
49 #include "r600_cmdbuf.h"
50 #include "r600_emit.h"
51 #include "radeon_bocs_wrapper.h"
52 #include "radeon_mipmap_tree.h"
53 #include "radeon_reg.h"
54
55 #ifdef HAVE_LIBDRM_RADEON
56 #include "radeon_cs_int.h"
57 #else
58 #include "radeon_cs_int_drm.h"
59 #endif
60
61 struct r600_cs_manager_legacy
62 {
63 struct radeon_cs_manager base;
64 struct radeon_context *ctx;
65 /* hack for scratch stuff */
66 uint32_t pending_age;
67 uint32_t pending_count;
68 };
69
70 struct r600_cs_reloc_legacy {
71 struct radeon_cs_reloc base;
72 uint32_t cindices;
73 uint32_t *indices;
74 uint32_t *reloc_indices;
75 };
76
77 static struct radeon_cs_int *r600_cs_create(struct radeon_cs_manager *csm,
78 uint32_t ndw)
79 {
80 struct radeon_cs_int *csi;
81
82 csi = (struct radeon_cs_int*)calloc(1, sizeof(struct radeon_cs_int));
83 if (csi == NULL) {
84 return NULL;
85 }
86 csi->csm = csm;
87 csi->ndw = (ndw + 0x3FF) & (~0x3FF);
88 csi->packets = (uint32_t*)malloc(4*csi->ndw);
89 if (csi->packets == NULL) {
90 free(csi);
91 return NULL;
92 }
93 csi->relocs_total_size = 0;
94 return csi;
95 }
96
97 static int r600_cs_write_reloc(struct radeon_cs_int *csi,
98 struct radeon_bo *bo,
99 uint32_t read_domain,
100 uint32_t write_domain,
101 uint32_t flags)
102 {
103 struct r600_cs_reloc_legacy *relocs;
104 int i;
105
106 relocs = (struct r600_cs_reloc_legacy *)csi->relocs;
107 /* check domains */
108 if ((read_domain && write_domain) || (!read_domain && !write_domain)) {
109 /* in one CS a bo can only be in read or write domain but not
110 * in read & write domain at the same sime
111 */
112 return -EINVAL;
113 }
114 if (read_domain == RADEON_GEM_DOMAIN_CPU) {
115 return -EINVAL;
116 }
117 if (write_domain == RADEON_GEM_DOMAIN_CPU) {
118 return -EINVAL;
119 }
120 /* check if bo is already referenced */
121 for(i = 0; i < csi->crelocs; i++) {
122 uint32_t *indices;
123 uint32_t *reloc_indices;
124
125 if (relocs[i].base.bo->handle == bo->handle) {
126 /* Check domains must be in read or write. As we check already
127 * checked that in argument one of the read or write domain was
128 * set we only need to check that if previous reloc as the read
129 * domain set then the read_domain should also be set for this
130 * new relocation.
131 */
132 if (relocs[i].base.read_domain && !read_domain) {
133 return -EINVAL;
134 }
135 if (relocs[i].base.write_domain && !write_domain) {
136 return -EINVAL;
137 }
138 relocs[i].base.read_domain |= read_domain;
139 relocs[i].base.write_domain |= write_domain;
140 /* save indice */
141 relocs[i].cindices++;
142 indices = (uint32_t*)realloc(relocs[i].indices,
143 relocs[i].cindices * 4);
144 reloc_indices = (uint32_t*)realloc(relocs[i].reloc_indices,
145 relocs[i].cindices * 4);
146 if ( (indices == NULL) || (reloc_indices == NULL) ) {
147 relocs[i].cindices -= 1;
148 return -ENOMEM;
149 }
150 relocs[i].indices = indices;
151 relocs[i].reloc_indices = reloc_indices;
152 relocs[i].indices[relocs[i].cindices - 1] = csi->cdw;
153 relocs[i].reloc_indices[relocs[i].cindices - 1] = csi->cdw;
154 csi->section_cdw += 2;
155 csi->cdw += 2;
156
157 return 0;
158 }
159 }
160 /* add bo to reloc */
161 relocs = (struct r600_cs_reloc_legacy*)
162 realloc(csi->relocs,
163 sizeof(struct r600_cs_reloc_legacy) * (csi->crelocs + 1));
164 if (relocs == NULL) {
165 return -ENOMEM;
166 }
167 csi->relocs = relocs;
168 relocs[csi->crelocs].base.bo = bo;
169 relocs[csi->crelocs].base.read_domain = read_domain;
170 relocs[csi->crelocs].base.write_domain = write_domain;
171 relocs[csi->crelocs].base.flags = flags;
172 relocs[csi->crelocs].indices = (uint32_t*)malloc(4);
173 relocs[csi->crelocs].reloc_indices = (uint32_t*)malloc(4);
174 if ( (relocs[csi->crelocs].indices == NULL) || (relocs[csi->crelocs].reloc_indices == NULL) )
175 {
176 return -ENOMEM;
177 }
178
179 relocs[csi->crelocs].indices[0] = csi->cdw;
180 relocs[csi->crelocs].reloc_indices[0] = csi->cdw;
181 csi->section_cdw += 2;
182 csi->cdw += 2;
183 relocs[csi->crelocs].cindices = 1;
184 csi->relocs_total_size += radeon_bo_legacy_relocs_size(bo);
185 csi->crelocs++;
186
187 radeon_bo_ref(bo);
188
189 return 0;
190 }
191
192 static int r600_cs_begin(struct radeon_cs_int *csi,
193 uint32_t ndw,
194 const char *file,
195 const char *func,
196 int line)
197 {
198 if (csi->section_ndw) {
199 fprintf(stderr, "CS already in a section(%s,%s,%d)\n",
200 csi->section_file, csi->section_func, csi->section_line);
201 fprintf(stderr, "CS can't start section(%s,%s,%d)\n",
202 file, func, line);
203 return -EPIPE;
204 }
205
206 csi->section_ndw = ndw;
207 csi->section_cdw = 0;
208 csi->section_file = file;
209 csi->section_func = func;
210 csi->section_line = line;
211
212 if (csi->cdw + ndw > csi->ndw) {
213 uint32_t tmp, *ptr;
214 int num = (ndw > 0x400) ? ndw : 0x400;
215
216 tmp = (csi->cdw + num + 0x3FF) & (~0x3FF);
217 ptr = (uint32_t*)realloc(csi->packets, 4 * tmp);
218 if (ptr == NULL) {
219 return -ENOMEM;
220 }
221 csi->packets = ptr;
222 csi->ndw = tmp;
223 }
224
225 return 0;
226 }
227
228 static int r600_cs_end(struct radeon_cs_int *csi,
229 const char *file,
230 const char *func,
231 int line)
232
233 {
234 if (!csi->section_ndw) {
235 fprintf(stderr, "CS no section to end at (%s,%s,%d)\n",
236 file, func, line);
237 return -EPIPE;
238 }
239
240 if ( csi->section_ndw != csi->section_cdw ) {
241 fprintf(stderr, "CS section size missmatch start at (%s,%s,%d) %d vs %d\n",
242 csi->section_file, csi->section_func, csi->section_line, csi->section_ndw, csi->section_cdw);
243 fprintf(stderr, "csi->section_ndw = %d, csi->cdw = %d, csi->section_cdw = %d \n",
244 csi->section_ndw, csi->cdw, csi->section_cdw);
245 fprintf(stderr, "CS section end at (%s,%s,%d)\n",
246 file, func, line);
247 return -EPIPE;
248 }
249 csi->section_ndw = 0;
250
251 if (csi->cdw > csi->ndw) {
252 fprintf(stderr, "CS section overflow at (%s,%s,%d) cdw %d ndw %d\n",
253 csi->section_file, csi->section_func, csi->section_line,csi->cdw,csi->ndw);
254 fprintf(stderr, "CS section end at (%s,%s,%d)\n",
255 file, func, line);
256 assert(0);
257 }
258
259 return 0;
260 }
261
262 static int r600_cs_process_relocs(struct radeon_cs_int *csi,
263 uint32_t * reloc_chunk,
264 uint32_t * length_dw_reloc_chunk)
265 {
266 struct r600_cs_manager_legacy *csm = (struct r600_cs_manager_legacy*)csi->csm;
267 struct r600_cs_reloc_legacy *relocs;
268 int i, j, r;
269
270 uint32_t offset_dw = 0;
271
272 csm = (struct r600_cs_manager_legacy*)csi->csm;
273 relocs = (struct r600_cs_reloc_legacy *)csi->relocs;
274 restart:
275 for (i = 0; i < csi->crelocs; i++) {
276 uint32_t soffset, eoffset;
277
278 r = radeon_bo_legacy_validate(relocs[i].base.bo,
279 &soffset, &eoffset);
280 if (r == -EAGAIN) {
281 goto restart;
282 }
283 if (r) {
284 fprintf(stderr, "invalid bo(%p) [0x%08X, 0x%08X]\n",
285 relocs[i].base.bo, soffset, eoffset);
286 return r;
287 }
288
289 for (j = 0; j < relocs[i].cindices; j++) {
290 /* pkt3 nop header in ib chunk */
291 csi->packets[relocs[i].reloc_indices[j]] = 0xC0001000;
292 /* reloc index in ib chunk */
293 csi->packets[relocs[i].reloc_indices[j] + 1] = offset_dw;
294 }
295
296 /* asic offset in reloc chunk */ /* see alex drm r600_nomm_relocate */
297 reloc_chunk[offset_dw] = soffset;
298 reloc_chunk[offset_dw + 3] = 0;
299
300 offset_dw += 4;
301 }
302
303 *length_dw_reloc_chunk = offset_dw;
304
305 return 0;
306 }
307
308 static int r600_cs_set_age(struct radeon_cs_int *csi) /* -------------- */
309 {
310 struct r600_cs_manager_legacy *csm = (struct r600_cs_manager_legacy*)csi->csm;
311 struct r600_cs_reloc_legacy *relocs;
312 int i;
313
314 relocs = (struct r600_cs_reloc_legacy *)csi->relocs;
315 for (i = 0; i < csi->crelocs; i++) {
316 radeon_bo_legacy_pending(relocs[i].base.bo, csm->pending_age);
317 radeon_bo_unref(relocs[i].base.bo);
318 }
319 return 0;
320 }
321
322 #if 0
323 static void dump_cmdbuf(struct radeon_cs_int *csi)
324 {
325 int i;
326 fprintf(stderr,"--start--\n");
327 for (i = 0; i < csi->cdw; i++){
328 fprintf(stderr,"0x%08x\n", csi->packets[i]);
329 }
330 fprintf(stderr,"--end--\n");
331
332 }
333 #endif
334
335 static int r600_cs_emit(struct radeon_cs_int *csi)
336 {
337 struct r600_cs_manager_legacy *csm = (struct r600_cs_manager_legacy*)csi->csm;
338 struct drm_radeon_cs cs_cmd;
339 struct drm_radeon_cs_chunk cs_chunk[2];
340 uint32_t length_dw_reloc_chunk;
341 uint64_t chunk_ptrs[2];
342 uint32_t *reloc_chunk;
343 int r;
344 int retry = 0;
345
346 /* TODO : put chip level things here if need. */
347 /* csm->ctx->vtbl.emit_cs_header(cs, csm->ctx); */
348
349 csm->pending_count = 1;
350
351 reloc_chunk = (uint32_t*)calloc(1, csi->crelocs * 4 * 4);
352
353 r = r600_cs_process_relocs(csi, reloc_chunk, &length_dw_reloc_chunk);
354 if (r) {
355 free(reloc_chunk);
356 return 0;
357 }
358
359 /* raw ib chunk */
360 cs_chunk[0].chunk_id = RADEON_CHUNK_ID_IB;
361 cs_chunk[0].length_dw = csi->cdw;
362 cs_chunk[0].chunk_data = (unsigned long)(csi->packets);
363
364 /* reloc chaunk */
365 cs_chunk[1].chunk_id = RADEON_CHUNK_ID_RELOCS;
366 cs_chunk[1].length_dw = length_dw_reloc_chunk;
367 cs_chunk[1].chunk_data = (unsigned long)reloc_chunk;
368
369 chunk_ptrs[0] = (uint64_t)(unsigned long)&(cs_chunk[0]);
370 chunk_ptrs[1] = (uint64_t)(unsigned long)&(cs_chunk[1]);
371
372 cs_cmd.num_chunks = 2;
373 /* cs_cmd.cs_id = 0; */
374 cs_cmd.chunks = (uint64_t)(unsigned long)chunk_ptrs;
375
376 //dump_cmdbuf(cs);
377
378 do
379 {
380 r = drmCommandWriteRead(csi->csm->fd, DRM_RADEON_CS, &cs_cmd, sizeof(cs_cmd));
381 retry++;
382 } while (r == -EAGAIN && retry < 1000);
383
384 if (r) {
385 free(reloc_chunk);
386 return r;
387 }
388
389 csm->pending_age = cs_cmd.cs_id;
390
391 r600_cs_set_age(csi);
392
393 csi->csm->read_used = 0;
394 csi->csm->vram_write_used = 0;
395 csi->csm->gart_write_used = 0;
396
397 free(reloc_chunk);
398
399 return 0;
400 }
401
402 static void inline r600_cs_free_reloc(void *relocs_p, int crelocs)
403 {
404 struct r600_cs_reloc_legacy *relocs = relocs_p;
405 int i;
406 if (!relocs_p)
407 return;
408 for (i = 0; i < crelocs; i++)
409 {
410 free(relocs[i].indices);
411 free(relocs[i].reloc_indices);
412 }
413 }
414
415 static int r600_cs_destroy(struct radeon_cs_int *csi)
416 {
417 r600_cs_free_reloc(csi->relocs, csi->crelocs);
418 free(csi->relocs);
419 free(csi->packets);
420 free(csi);
421 return 0;
422 }
423
424 static int r600_cs_erase(struct radeon_cs_int *csi)
425 {
426 r600_cs_free_reloc(csi->relocs, csi->crelocs);
427 free(csi->relocs);
428 csi->relocs_total_size = 0;
429 csi->relocs = NULL;
430 csi->crelocs = 0;
431 csi->cdw = 0;
432 return 0;
433 }
434
435 static int r600_cs_need_flush(struct radeon_cs_int *csi)
436 {
437 /* this function used to flush when the BO usage got to
438 * a certain size, now the higher levels handle this better */
439 return 0;
440 }
441
442 static void r600_cs_print(struct radeon_cs_int *csi, FILE *file)
443 {
444 }
445
446 static struct radeon_cs_funcs r600_cs_funcs = {
447 r600_cs_create,
448 r600_cs_write_reloc,
449 r600_cs_begin,
450 r600_cs_end,
451 r600_cs_emit,
452 r600_cs_destroy,
453 r600_cs_erase,
454 r600_cs_need_flush,
455 r600_cs_print
456 };
457
458 struct radeon_cs_manager * r600_radeon_cs_manager_legacy_ctor(struct radeon_context *ctx)
459 {
460 struct r600_cs_manager_legacy *csm;
461
462 csm = (struct r600_cs_manager_legacy*)
463 calloc(1, sizeof(struct r600_cs_manager_legacy));
464 if (csm == NULL) {
465 return NULL;
466 }
467 csm->base.funcs = &r600_cs_funcs;
468 csm->base.fd = ctx->dri.fd;
469 csm->ctx = ctx;
470 csm->pending_age = 1;
471 return (struct radeon_cs_manager*)csm;
472 }
473
474 void r600InitCmdBuf(context_t *r600) /* from rcommonInitCmdBuf */
475 {
476 radeonContextPtr rmesa = &r600->radeon;
477 GLuint size;
478
479 r600InitAtoms(r600);
480
481 /* Initialize command buffer */
482 size = 256 * driQueryOptioni(&rmesa->optionCache,
483 "command_buffer_size");
484 if (size < 2 * rmesa->hw.max_state_size) {
485 size = 2 * rmesa->hw.max_state_size + 65535;
486 }
487 if (size > 64 * 256)
488 size = 64 * 256;
489
490 if (rmesa->radeonScreen->kernel_mm) {
491 int fd = rmesa->radeonScreen->driScreen->fd;
492 rmesa->cmdbuf.csm = radeon_cs_manager_gem_ctor(fd);
493 } else {
494 rmesa->cmdbuf.csm = r600_radeon_cs_manager_legacy_ctor(rmesa);
495 }
496 if (rmesa->cmdbuf.csm == NULL) {
497 /* FIXME: fatal error */
498 return;
499 }
500 rmesa->cmdbuf.cs = radeon_cs_create(rmesa->cmdbuf.csm, size);
501 assert(rmesa->cmdbuf.cs != NULL);
502 rmesa->cmdbuf.size = size;
503
504 radeon_cs_space_set_flush(rmesa->cmdbuf.cs,
505 (void (*)(void *))rmesa->glCtx->Driver.Flush, rmesa->glCtx);
506
507 if (!rmesa->radeonScreen->kernel_mm) {
508 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_VRAM, rmesa->radeonScreen->texSize[0]);
509 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_GTT, rmesa->radeonScreen->gartTextures.size);
510 } else {
511 struct drm_radeon_gem_info mminfo;
512
513 if (!drmCommandWriteRead(rmesa->dri.fd, DRM_RADEON_GEM_INFO, &mminfo, sizeof(mminfo)))
514 {
515 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_VRAM, mminfo.vram_visible);
516 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_GTT, mminfo.gart_size);
517 }
518 }
519 }
520