Tizen 2.0 Release
[profile/ivi/osmesa.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
43 #include "drm.h"
44 #include "radeon_drm.h"
45
46 #include "r600_context.h"
47 #include "radeon_reg.h"
48 #include "r600_cmdbuf.h"
49 #include "radeon_bocs_wrapper.h"
50
51 #ifdef HAVE_LIBDRM_RADEON
52 #include "radeon_cs_int.h"
53 #else
54 #include "radeon_cs_int_drm.h"
55 #endif
56
57 struct r600_cs_manager_legacy
58 {
59     struct radeon_cs_manager    base;
60     struct radeon_context       *ctx;
61     /* hack for scratch stuff */
62     uint32_t                    pending_age;
63     uint32_t                    pending_count;
64 };
65
66 struct r600_cs_reloc_legacy {
67     struct radeon_cs_reloc  base;
68     uint32_t                cindices;
69     uint32_t                *indices;
70     uint32_t                *reloc_indices;
71 };
72
73 static struct radeon_cs_int *r600_cs_create(struct radeon_cs_manager *csm,
74                                             uint32_t ndw)
75 {
76     struct radeon_cs_int *csi;
77
78     csi = (struct radeon_cs_int*)calloc(1, sizeof(struct radeon_cs_int));
79     if (csi == NULL) {
80         return NULL;
81     }
82     csi->csm = csm;
83     csi->ndw = (ndw + 0x3FF) & (~0x3FF);
84     csi->packets = (uint32_t*)malloc(4*csi->ndw);
85     if (csi->packets == NULL) {
86         free(csi);
87         return NULL;
88     }
89     csi->relocs_total_size = 0;
90     return csi;
91 }
92
93 static int r600_cs_write_reloc(struct radeon_cs_int *csi,
94                                struct radeon_bo *bo,
95                                uint32_t read_domain,
96                                uint32_t write_domain,
97                                uint32_t flags)
98 {
99     struct r600_cs_reloc_legacy *relocs;
100     int i;
101
102     relocs = (struct r600_cs_reloc_legacy *)csi->relocs;
103     /* check domains */
104     if ((read_domain && write_domain) || (!read_domain && !write_domain)) {
105         /* in one CS a bo can only be in read or write domain but not
106          * in read & write domain at the same sime
107          */
108         return -EINVAL;
109     }
110     if (read_domain == RADEON_GEM_DOMAIN_CPU) {
111         return -EINVAL;
112     }
113     if (write_domain == RADEON_GEM_DOMAIN_CPU) {
114         return -EINVAL;
115     }
116     /* check if bo is already referenced */
117     for(i = 0; i < csi->crelocs; i++) {
118         uint32_t *indices;
119         uint32_t *reloc_indices;
120
121         if (relocs[i].base.bo->handle == bo->handle) {
122             /* Check domains must be in read or write. As we check already
123              * checked that in argument one of the read or write domain was
124              * set we only need to check that if previous reloc as the read
125              * domain set then the read_domain should also be set for this
126              * new relocation.
127              */
128             if (relocs[i].base.read_domain && !read_domain) {
129                 return -EINVAL;
130             }
131             if (relocs[i].base.write_domain && !write_domain) {
132                 return -EINVAL;
133             }
134             relocs[i].base.read_domain |= read_domain;
135             relocs[i].base.write_domain |= write_domain;
136             /* save indice */
137             relocs[i].cindices++;
138             indices = (uint32_t*)realloc(relocs[i].indices,
139                                          relocs[i].cindices * 4);
140             reloc_indices = (uint32_t*)realloc(relocs[i].reloc_indices,
141                                                relocs[i].cindices * 4);
142             if ( (indices == NULL) || (reloc_indices == NULL) ) {
143                 relocs[i].cindices -= 1;
144                 return -ENOMEM;
145             }
146             relocs[i].indices = indices;
147             relocs[i].reloc_indices = reloc_indices;
148             relocs[i].indices[relocs[i].cindices - 1] = csi->cdw;
149             relocs[i].reloc_indices[relocs[i].cindices - 1] = csi->cdw;
150             csi->section_cdw += 2;
151             csi->cdw += 2;
152
153             return 0;
154         }
155     }
156     /* add bo to reloc */
157     relocs = (struct r600_cs_reloc_legacy*)
158              realloc(csi->relocs,
159                      sizeof(struct r600_cs_reloc_legacy) * (csi->crelocs + 1));
160     if (relocs == NULL) {
161         return -ENOMEM;
162     }
163     csi->relocs = relocs;
164     relocs[csi->crelocs].base.bo = bo;
165     relocs[csi->crelocs].base.read_domain = read_domain;
166     relocs[csi->crelocs].base.write_domain = write_domain;
167     relocs[csi->crelocs].base.flags = flags;
168     relocs[csi->crelocs].indices = (uint32_t*)malloc(4);
169     relocs[csi->crelocs].reloc_indices = (uint32_t*)malloc(4);
170     if ( (relocs[csi->crelocs].indices == NULL) || (relocs[csi->crelocs].reloc_indices == NULL) )
171     {
172         return -ENOMEM;
173     }
174
175     relocs[csi->crelocs].indices[0] = csi->cdw;
176     relocs[csi->crelocs].reloc_indices[0] = csi->cdw;
177     csi->section_cdw += 2;
178     csi->cdw += 2;
179     relocs[csi->crelocs].cindices = 1;
180     csi->relocs_total_size += radeon_bo_legacy_relocs_size(bo);
181     csi->crelocs++;
182
183     radeon_bo_ref(bo);
184
185     return 0;
186 }
187
188 static int r600_cs_begin(struct radeon_cs_int *csi,
189                     uint32_t ndw,
190                     const char *file,
191                     const char *func,
192                     int line)
193 {
194     if (csi->section_ndw) {
195         fprintf(stderr, "CS already in a section(%s,%s,%d)\n",
196                 csi->section_file, csi->section_func, csi->section_line);
197         fprintf(stderr, "CS can't start section(%s,%s,%d)\n",
198                 file, func, line);
199         return -EPIPE;
200     }
201
202     csi->section_ndw = ndw;
203     csi->section_cdw = 0;
204     csi->section_file = file;
205     csi->section_func = func;
206     csi->section_line = line;
207
208     if (csi->cdw + ndw > csi->ndw) {
209         uint32_t tmp, *ptr;
210         int num = (ndw > 0x400) ? ndw : 0x400;
211
212         tmp = (csi->cdw + num + 0x3FF) & (~0x3FF);
213         ptr = (uint32_t*)realloc(csi->packets, 4 * tmp);
214         if (ptr == NULL) {
215             return -ENOMEM;
216         }
217         csi->packets = ptr;
218         csi->ndw = tmp;
219     }
220
221     return 0;
222 }
223
224 static int r600_cs_end(struct radeon_cs_int *csi,
225                   const char *file,
226                   const char *func,
227                   int line)
228
229 {
230     if (!csi->section_ndw) {
231         fprintf(stderr, "CS no section to end at (%s,%s,%d)\n",
232                 file, func, line);
233         return -EPIPE;
234     }
235
236     if ( csi->section_ndw != csi->section_cdw ) {
237         fprintf(stderr, "CS section size missmatch start at (%s,%s,%d) %d vs %d\n",
238                 csi->section_file, csi->section_func, csi->section_line, csi->section_ndw, csi->section_cdw);
239         fprintf(stderr, "csi->section_ndw = %d, csi->cdw = %d, csi->section_cdw = %d \n",
240                 csi->section_ndw, csi->cdw, csi->section_cdw);
241         fprintf(stderr, "CS section end at (%s,%s,%d)\n",
242                 file, func, line);
243         return -EPIPE;
244     }
245     csi->section_ndw = 0;
246
247     if (csi->cdw > csi->ndw) {
248             fprintf(stderr, "CS section overflow at (%s,%s,%d) cdw %d ndw %d\n",
249                     csi->section_file, csi->section_func, csi->section_line,csi->cdw,csi->ndw);
250             fprintf(stderr, "CS section end at (%s,%s,%d)\n",
251                     file, func, line);
252             assert(0);
253     }
254
255     return 0;
256 }
257
258 static int r600_cs_process_relocs(struct radeon_cs_int *csi, 
259                                   uint32_t * reloc_chunk,
260                                   uint32_t * length_dw_reloc_chunk) 
261 {
262     struct r600_cs_manager_legacy *csm = (struct r600_cs_manager_legacy*)csi->csm;
263     struct r600_cs_reloc_legacy *relocs;
264     int i, j, r;
265
266     uint32_t offset_dw = 0;
267
268     csm = (struct r600_cs_manager_legacy*)csi->csm;
269     relocs = (struct r600_cs_reloc_legacy *)csi->relocs;
270 restart:
271     for (i = 0; i < csi->crelocs; i++) {
272             uint32_t soffset, eoffset;
273
274             r = radeon_bo_legacy_validate(relocs[i].base.bo,
275                                           &soffset, &eoffset);
276             if (r == -EAGAIN) {
277                     goto restart;
278             }
279             if (r) {
280                     fprintf(stderr, "invalid bo(%p) [0x%08X, 0x%08X]\n",
281                             relocs[i].base.bo, soffset, eoffset);
282                     return r;
283             }
284
285             for (j = 0; j < relocs[i].cindices; j++) {
286                     /* pkt3 nop header in ib chunk */
287                     csi->packets[relocs[i].reloc_indices[j]] = 0xC0001000;
288                     /* reloc index in ib chunk */
289                     csi->packets[relocs[i].reloc_indices[j] + 1] = offset_dw;
290             }
291
292             /* asic offset in reloc chunk */ /* see alex drm r600_nomm_relocate */
293             reloc_chunk[offset_dw] = soffset;
294             reloc_chunk[offset_dw + 3] = 0;
295
296             offset_dw += 4;
297     }
298
299     *length_dw_reloc_chunk = offset_dw;
300
301     return 0;
302 }
303
304 static int r600_cs_set_age(struct radeon_cs_int *csi) /* -------------- */
305 {
306     struct r600_cs_manager_legacy *csm = (struct r600_cs_manager_legacy*)csi->csm;
307     struct r600_cs_reloc_legacy *relocs;
308     int i;
309
310     relocs = (struct r600_cs_reloc_legacy *)csi->relocs;
311     for (i = 0; i < csi->crelocs; i++) {
312         radeon_bo_legacy_pending(relocs[i].base.bo, csm->pending_age);
313         radeon_bo_unref(relocs[i].base.bo);
314     }
315     return 0;
316 }
317
318 #if 0
319 static void dump_cmdbuf(struct radeon_cs_int *csi)
320 {
321         int i;
322         fprintf(stderr,"--start--\n");
323         for (i = 0; i < csi->cdw; i++){
324                 fprintf(stderr,"0x%08x\n", csi->packets[i]);
325         }
326         fprintf(stderr,"--end--\n");
327
328 }
329 #endif
330
331 static int r600_cs_emit(struct radeon_cs_int *csi)
332 {
333     struct r600_cs_manager_legacy *csm = (struct r600_cs_manager_legacy*)csi->csm;
334     struct drm_radeon_cs       cs_cmd;
335     struct drm_radeon_cs_chunk cs_chunk[2];
336     uint32_t length_dw_reloc_chunk;
337     uint64_t chunk_ptrs[2];
338     uint32_t *reloc_chunk;
339     int r;
340     int retry = 0;
341
342     /* TODO : put chip level things here if need. */
343     /* csm->ctx->vtbl.emit_cs_header(cs, csm->ctx); */
344
345     csm->pending_count = 1;
346
347     reloc_chunk = (uint32_t*)calloc(1, csi->crelocs * 4 * 4);
348
349     r = r600_cs_process_relocs(csi, reloc_chunk, &length_dw_reloc_chunk);
350     if (r) {
351         free(reloc_chunk);
352         return 0;
353     }
354
355     /* raw ib chunk */
356     cs_chunk[0].chunk_id   = RADEON_CHUNK_ID_IB;
357     cs_chunk[0].length_dw  = csi->cdw;
358     cs_chunk[0].chunk_data = (unsigned long)(csi->packets);
359
360     /* reloc chaunk */
361     cs_chunk[1].chunk_id   = RADEON_CHUNK_ID_RELOCS;
362     cs_chunk[1].length_dw  = length_dw_reloc_chunk;
363     cs_chunk[1].chunk_data = (unsigned long)reloc_chunk;
364
365     chunk_ptrs[0] = (uint64_t)(unsigned long)&(cs_chunk[0]);
366     chunk_ptrs[1] = (uint64_t)(unsigned long)&(cs_chunk[1]);
367
368     cs_cmd.num_chunks = 2;
369     /* cs_cmd.cs_id      = 0; */
370     cs_cmd.chunks     = (uint64_t)(unsigned long)chunk_ptrs;
371
372     //dump_cmdbuf(cs);
373
374     do 
375     {
376         r = drmCommandWriteRead(csi->csm->fd, DRM_RADEON_CS, &cs_cmd, sizeof(cs_cmd));
377         retry++;
378     } while (r == -EAGAIN && retry < 1000);
379
380     if (r) {
381         free(reloc_chunk);
382         return r;
383     }
384
385     csm->pending_age = cs_cmd.cs_id;
386
387     r600_cs_set_age(csi);
388
389     csi->csm->read_used = 0;
390     csi->csm->vram_write_used = 0;
391     csi->csm->gart_write_used = 0;
392
393     free(reloc_chunk);
394
395     return 0;
396 }
397
398 static void inline r600_cs_free_reloc(void *relocs_p, int crelocs)
399 {
400     struct r600_cs_reloc_legacy *relocs = relocs_p;
401     int i;
402     if (!relocs_p)
403       return;
404     for (i = 0; i < crelocs; i++)
405     {
406         free(relocs[i].indices);
407         free(relocs[i].reloc_indices);
408     }
409 }
410
411 static int r600_cs_destroy(struct radeon_cs_int *csi)
412 {
413     r600_cs_free_reloc(csi->relocs, csi->crelocs);
414     free(csi->relocs);
415     free(csi->packets);
416     free(csi);
417     return 0;
418 }
419
420 static int r600_cs_erase(struct radeon_cs_int *csi)
421 {
422     r600_cs_free_reloc(csi->relocs, csi->crelocs);
423     free(csi->relocs);
424     csi->relocs_total_size = 0;
425     csi->relocs = NULL;
426     csi->crelocs = 0;
427     csi->cdw = 0;
428     return 0;
429 }
430
431 static int r600_cs_need_flush(struct radeon_cs_int *csi)
432 {
433     /* this function used to flush when the BO usage got to
434      * a certain size, now the higher levels handle this better */
435     return 0;
436 }
437
438 static void r600_cs_print(struct radeon_cs_int *csi, FILE *file)
439 {
440 }
441
442 static struct radeon_cs_funcs  r600_cs_funcs = {
443     r600_cs_create,
444     r600_cs_write_reloc,
445     r600_cs_begin,
446     r600_cs_end,
447     r600_cs_emit,
448     r600_cs_destroy,
449     r600_cs_erase,
450     r600_cs_need_flush,
451     r600_cs_print
452 };
453
454 struct radeon_cs_manager * r600_radeon_cs_manager_legacy_ctor(struct radeon_context *ctx)
455 {
456     struct r600_cs_manager_legacy *csm;
457
458     csm = (struct r600_cs_manager_legacy*)
459           calloc(1, sizeof(struct r600_cs_manager_legacy));
460     if (csm == NULL) {
461         return NULL;
462     }
463     csm->base.funcs = &r600_cs_funcs;
464     csm->base.fd = ctx->dri.fd;
465     csm->ctx = ctx;
466     csm->pending_age = 1;
467     return (struct radeon_cs_manager*)csm;
468 }
469
470 void r600InitCmdBuf(context_t *r600) /* from rcommonInitCmdBuf */
471 {
472         radeonContextPtr rmesa = &r600->radeon;
473         GLuint size;
474
475     if(r600->radeon.radeonScreen->chip_family >= CHIP_FAMILY_CEDAR)
476     {
477         evergreenInitAtoms(r600);
478     }
479     else
480     {
481         r600InitAtoms(r600);
482     }   
483
484         /* Initialize command buffer */
485         size = 256 * driQueryOptioni(&rmesa->optionCache,
486                                      "command_buffer_size");
487         if (size < 2 * rmesa->hw.max_state_size) {
488                 size = 2 * rmesa->hw.max_state_size + 65535;
489         }
490         if (size > 64 * 256)
491                 size = 64 * 256;
492
493         if (rmesa->radeonScreen->kernel_mm) {
494                 int fd = rmesa->radeonScreen->driScreen->fd;
495                 rmesa->cmdbuf.csm = radeon_cs_manager_gem_ctor(fd);
496         } else {
497                 rmesa->cmdbuf.csm = r600_radeon_cs_manager_legacy_ctor(rmesa);
498         }
499         if (rmesa->cmdbuf.csm == NULL) {
500                 /* FIXME: fatal error */
501                 return;
502         }
503         rmesa->cmdbuf.cs = radeon_cs_create(rmesa->cmdbuf.csm, size);
504         assert(rmesa->cmdbuf.cs != NULL);
505         rmesa->cmdbuf.size = size;
506
507         radeon_cs_space_set_flush(rmesa->cmdbuf.cs,
508                                   (void (*)(void *))rmesa->glCtx->Driver.Flush, rmesa->glCtx);
509
510         if (!rmesa->radeonScreen->kernel_mm) {
511                 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_VRAM, rmesa->radeonScreen->texSize[0]);
512                 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_GTT, rmesa->radeonScreen->gartTextures.size);
513         } else {
514                 struct drm_radeon_gem_info mminfo;
515
516                 if (!drmCommandWriteRead(rmesa->dri.fd, DRM_RADEON_GEM_INFO, &mminfo, sizeof(mminfo)))
517                 {
518                         radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_VRAM, mminfo.vram_visible);
519                         radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_GTT, mminfo.gart_size);
520                 }
521         }
522 }
523