OSDN Git Service

modetest: do not include config.h
[android-x86/external-libdrm.git] / nouveau / nouveau_reloc.c
1 /*
2  * Copyright 2010 Nouveau Project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include "nouveau_private.h"
29
30 static uint32_t
31 nouveau_reloc_calc(struct drm_nouveau_gem_pushbuf_bo *pbbo,
32                    struct drm_nouveau_gem_pushbuf_reloc *r)
33 {
34         uint32_t push = 0;
35
36         if (r->flags & NOUVEAU_GEM_RELOC_LOW)
37                 push = (pbbo->presumed.offset + r->data);
38         else
39         if (r->flags & NOUVEAU_GEM_RELOC_HIGH)
40                 push = (pbbo->presumed.offset + r->data) >> 32;
41         else
42                 push = r->data;
43
44         if (r->flags & NOUVEAU_GEM_RELOC_OR) {
45                 if (pbbo->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM)
46                         push |= r->vor;
47                 else
48                         push |= r->tor;
49         }
50
51         return push;
52 }
53
54 int
55 nouveau_reloc_emit(struct nouveau_channel *chan, struct nouveau_bo *reloc_bo,
56                    uint32_t reloc_offset, uint32_t *reloc_ptr,
57                    struct nouveau_bo *bo, uint32_t data, uint32_t data2,
58                    uint32_t flags, uint32_t vor, uint32_t tor)
59 {
60         struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
61         struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
62         struct drm_nouveau_gem_pushbuf_reloc *r;
63         struct drm_nouveau_gem_pushbuf_bo *pbbo, *rpbbo;
64         uint32_t domains = 0;
65
66         if (nvpb->nr_relocs >= NOUVEAU_GEM_MAX_RELOCS) {
67                 fprintf(stderr, "too many relocs!!\n");
68                 return -ENOMEM;
69         }
70
71         if (nvbo->user && (flags & NOUVEAU_BO_WR)) {
72                 fprintf(stderr, "write to user buffer!!\n");
73                 return -EINVAL;
74         }
75
76         /* We're about to reloc a user buffer, better make sure we don't cause
77          * a double migration.
78          */
79         if (!(nvbo->flags & (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM)))
80                 nvbo->flags |= (flags & (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM));
81
82         /* add buffer to validation list */
83         pbbo = nouveau_bo_emit_buffer(chan, bo);
84         if (!pbbo) {
85                 fprintf(stderr, "buffer emit fail :(\n");
86                 return -ENOMEM;
87         }
88         nouveau_bo(bo)->pending_refcnt++;
89
90         if (flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) {
91                 if (flags & NOUVEAU_BO_VRAM)
92                         domains |= NOUVEAU_GEM_DOMAIN_VRAM;
93                 if (flags & NOUVEAU_BO_GART)
94                         domains |= NOUVEAU_GEM_DOMAIN_GART;
95         } else
96                 domains |= nvbo->domain;
97
98         if (!(pbbo->valid_domains & domains)) {
99                 fprintf(stderr, "no valid domains remain!\n");
100                 return -EINVAL;
101         }
102         pbbo->valid_domains &= domains;
103
104         assert(flags & NOUVEAU_BO_RDWR);
105         if (flags & NOUVEAU_BO_RD) {
106                 pbbo->read_domains |= domains;
107         }
108         if (flags & NOUVEAU_BO_WR) {
109                 pbbo->write_domains |= domains;
110                 nvbo->write_marker = 1;
111         }
112
113         /* nvc0 gallium driver uses reloc_emit() with NULL target buffer
114          * to inform bufmgr of a buffer's use - however, we need something
115          * to track, so create a reloc for now, and hope it never triggers
116          * (it shouldn't, constant virtual address..)..
117          */
118         if (!reloc_bo) {
119                 reloc_bo  = nvpb->buffer[nvpb->current];
120                 reloc_offset = 0;
121                 reloc_ptr = NULL;
122         }
123
124         /* add reloc target bo to validation list, and create the reloc */
125         rpbbo = nouveau_bo_emit_buffer(chan, reloc_bo);
126         if (!rpbbo)
127                 return -ENOMEM;
128         nouveau_bo(reloc_bo)->pending_refcnt++;
129
130         r = nvpb->relocs + nvpb->nr_relocs++;
131         r->reloc_bo_index = rpbbo - nvpb->buffers;
132         r->reloc_bo_offset = reloc_offset;
133         r->bo_index = pbbo - nvpb->buffers;
134         r->flags = 0;
135         if (flags & NOUVEAU_BO_LOW)
136                 r->flags |= NOUVEAU_GEM_RELOC_LOW;
137         if (flags & NOUVEAU_BO_HIGH)
138                 r->flags |= NOUVEAU_GEM_RELOC_HIGH;
139         if (flags & NOUVEAU_BO_OR)
140                 r->flags |= NOUVEAU_GEM_RELOC_OR;
141         r->data = data;
142         r->vor = vor;
143         r->tor = tor;
144
145         if (reloc_ptr) {
146                 if (flags & NOUVEAU_BO_DUMMY)
147                         *reloc_ptr = 0;
148                 else
149                         *reloc_ptr = nouveau_reloc_calc(pbbo, r);
150         }
151
152         return 0;
153 }
154