aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Barbieri2010-01-29 02:53:24 -0600
committerBen Skeggs2010-02-15 18:16:37 -0600
commitb496c63143e9a4ca02011582329bce2df99d9b7c (patch)
tree4721c7af5a12c86646c272524a48ea2d39eebf9d /nouveau
parent4a17be4a86cde1065908576e44f3710f6d9d68af (diff)
downloadlibdrm-b496c63143e9a4ca02011582329bce2df99d9b7c.tar.gz
libdrm-b496c63143e9a4ca02011582329bce2df99d9b7c.tar.xz
libdrm-b496c63143e9a4ca02011582329bce2df99d9b7c.zip
nouveau: interface changes for 0.0.16 DRM
This commit encompasses the changes necessary to run on top of the 0.0.16 nouveau interface, additional APIs to support the new features of the interface, as well as code from Luca Barbieri to improve the pushbuf interface, which just happens to break nouveau's libdrm ABI so was delayed until now. API changes as a result of 0.0.16 DRM interface: 1. No more bo_pin()/bo_unpin(), these were only there for UMS and we no longer support it. 2. Any random nouveau_bo can be submitted to the GPU as a push buffer. 3. Relocations can be applied on any nouveau_bo This patch changes the pushbuffer ABI to: 1. No longer use/expose nouveau_pushbuffer. Everything is directly in nouveau_channel. This saves the extra "pushbuf" pointer dereference. 2. Use cur/end pointers instead of tracking the remaining size. Pushing data now only needs to alter cur and not both cur and remaining. The goal is to make the *_RING macros faster and make the interface simpler and cleaner in the process. The *_RING APIs are unchanged, but those are inlined and the ABI is changed. Also, anything accessing pushbuf->remaining instead of using AVAIL_RING will need to be fixed.
Diffstat (limited to 'nouveau')
-rw-r--r--nouveau/Makefile.am6
-rw-r--r--nouveau/nouveau_bo.c83
-rw-r--r--nouveau/nouveau_bo.h14
-rw-r--r--nouveau/nouveau_channel.h5
-rw-r--r--nouveau/nouveau_device.c8
-rw-r--r--nouveau/nouveau_private.h13
-rw-r--r--nouveau/nouveau_pushbuf.c375
-rw-r--r--nouveau/nouveau_pushbuf.h26
-rw-r--r--nouveau/nouveau_reloc.c132
-rw-r--r--nouveau/nouveau_reloc.h32
10 files changed, 344 insertions, 350 deletions
diff --git a/nouveau/Makefile.am b/nouveau/Makefile.am
index 70bbbb27..5d759c5e 100644
--- a/nouveau/Makefile.am
+++ b/nouveau/Makefile.am
@@ -18,7 +18,8 @@ libdrm_nouveau_la_SOURCES = \
18 nouveau_notifier.c \ 18 nouveau_notifier.c \
19 nouveau_bo.c \ 19 nouveau_bo.c \
20 nouveau_resource.c \ 20 nouveau_resource.c \
21 nouveau_private.h 21 nouveau_private.h \
22 nouveau_reloc.c
22 23
23libdrm_nouveaucommonincludedir = ${includedir}/nouveau 24libdrm_nouveaucommonincludedir = ${includedir}/nouveau
24libdrm_nouveaucommoninclude_HEADERS = \ 25libdrm_nouveaucommoninclude_HEADERS = \
@@ -29,7 +30,8 @@ libdrm_nouveaucommoninclude_HEADERS = \
29 nouveau_pushbuf.h \ 30 nouveau_pushbuf.h \
30 nouveau_bo.h \ 31 nouveau_bo.h \
31 nouveau_resource.h \ 32 nouveau_resource.h \
32 nouveau_class.h 33 nouveau_class.h \
34 nouveau_reloc.h
33 35
34 36
35libdrm_nouveauincludedir = ${includedir}/drm 37libdrm_nouveauincludedir = ${includedir}/drm
diff --git a/nouveau/nouveau_bo.c b/nouveau/nouveau_bo.c
index 10cc8a67..49736364 100644
--- a/nouveau/nouveau_bo.c
+++ b/nouveau/nouveau_bo.c
@@ -201,14 +201,6 @@ nouveau_bo_new_tile(struct nouveau_device *dev, uint32_t flags, int align,
201 nouveau_bo_ref(NULL, (void *)nvbo); 201 nouveau_bo_ref(NULL, (void *)nvbo);
202 return ret; 202 return ret;
203 } 203 }
204
205 if (flags & NOUVEAU_BO_PIN) {
206 ret = nouveau_bo_pin((void *)nvbo, nvbo->flags);
207 if (ret) {
208 nouveau_bo_ref(NULL, (void *)nvbo);
209 return ret;
210 }
211 }
212 } 204 }
213 205
214 *bo = &nvbo->base; 206 *bo = &nvbo->base;
@@ -219,16 +211,7 @@ int
219nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, int align, 211nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, int align,
220 int size, struct nouveau_bo **bo) 212 int size, struct nouveau_bo **bo)
221{ 213{
222 uint32_t tile_flags = 0; 214 return nouveau_bo_new_tile(dev, flags, align, size, 0, 0, bo);
223
224 if (flags & NOUVEAU_BO_TILED) {
225 if (flags & NOUVEAU_BO_ZTILE)
226 tile_flags = 0x2800;
227 else
228 tile_flags = 0x7000;
229 }
230
231 return nouveau_bo_new_tile(dev, flags, align, size, 0, tile_flags, bo);
232} 215}
233 216
234int 217int
@@ -483,62 +466,6 @@ nouveau_bo_unmap(struct nouveau_bo *bo)
483} 466}
484 467
485int 468int
486nouveau_bo_pin(struct nouveau_bo *bo, uint32_t flags)
487{
488 struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
489 struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
490 struct drm_nouveau_gem_pin req;
491 int ret;
492
493 if (nvbo->pinned)
494 return 0;
495
496 if (!nvbo->handle)
497 return -EINVAL;
498
499 /* Now force it to stay put :) */
500 req.handle = nvbo->handle;
501 req.domain = 0;
502 if (flags & NOUVEAU_BO_VRAM)
503 req.domain |= NOUVEAU_GEM_DOMAIN_VRAM;
504 if (flags & NOUVEAU_BO_GART)
505 req.domain |= NOUVEAU_GEM_DOMAIN_GART;
506
507 ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_PIN, &req,
508 sizeof(struct drm_nouveau_gem_pin));
509 if (ret)
510 return ret;
511 nvbo->offset = req.offset;
512 nvbo->domain = req.domain;
513 nvbo->pinned = 1;
514
515 /* Fill in public nouveau_bo members */
516 if (nvbo->domain & NOUVEAU_GEM_DOMAIN_VRAM)
517 bo->flags = NOUVEAU_BO_VRAM;
518 if (nvbo->domain & NOUVEAU_GEM_DOMAIN_GART)
519 bo->flags = NOUVEAU_BO_GART;
520 bo->offset = nvbo->offset;
521
522 return 0;
523}
524
525void
526nouveau_bo_unpin(struct nouveau_bo *bo)
527{
528 struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
529 struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
530 struct drm_nouveau_gem_unpin req;
531
532 if (!nvbo->pinned)
533 return;
534
535 req.handle = nvbo->handle;
536 drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_UNPIN, &req, sizeof(req));
537
538 nvbo->pinned = bo->offset = bo->flags = 0;
539}
540
541int
542nouveau_bo_busy(struct nouveau_bo *bo, uint32_t access) 469nouveau_bo_busy(struct nouveau_bo *bo, uint32_t access)
543{ 470{
544 return nouveau_bo_wait(bo, (access & NOUVEAU_BO_WR), 1, 1); 471 return nouveau_bo_wait(bo, (access & NOUVEAU_BO_WR), 1, 1);
@@ -565,7 +492,7 @@ nouveau_bo_pending(struct nouveau_bo *bo)
565struct drm_nouveau_gem_pushbuf_bo * 492struct drm_nouveau_gem_pushbuf_bo *
566nouveau_bo_emit_buffer(struct nouveau_channel *chan, struct nouveau_bo *bo) 493nouveau_bo_emit_buffer(struct nouveau_channel *chan, struct nouveau_bo *bo)
567{ 494{
568 struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf); 495 struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
569 struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 496 struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
570 struct drm_nouveau_gem_pushbuf_bo *pbbo; 497 struct drm_nouveau_gem_pushbuf_bo *pbbo;
571 struct nouveau_bo *ref = NULL; 498 struct nouveau_bo *ref = NULL;
@@ -607,8 +534,8 @@ nouveau_bo_emit_buffer(struct nouveau_channel *chan, struct nouveau_bo *bo)
607 pbbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART; 534 pbbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART;
608 pbbo->read_domains = 0; 535 pbbo->read_domains = 0;
609 pbbo->write_domains = 0; 536 pbbo->write_domains = 0;
610 pbbo->presumed_domain = nvbo->domain; 537 pbbo->presumed.domain = nvbo->domain;
611 pbbo->presumed_offset = nvbo->offset; 538 pbbo->presumed.offset = nvbo->offset;
612 pbbo->presumed_ok = 1; 539 pbbo->presumed.valid = 1;
613 return pbbo; 540 return pbbo;
614} 541}
diff --git a/nouveau/nouveau_bo.h b/nouveau/nouveau_bo.h
index fdad63ef..1e77ab0f 100644
--- a/nouveau/nouveau_bo.h
+++ b/nouveau/nouveau_bo.h
@@ -30,13 +30,9 @@
30#define NOUVEAU_BO_WR (1 << 3) 30#define NOUVEAU_BO_WR (1 << 3)
31#define NOUVEAU_BO_RDWR (NOUVEAU_BO_RD | NOUVEAU_BO_WR) 31#define NOUVEAU_BO_RDWR (NOUVEAU_BO_RD | NOUVEAU_BO_WR)
32#define NOUVEAU_BO_MAP (1 << 4) 32#define NOUVEAU_BO_MAP (1 << 4)
33#define NOUVEAU_BO_PIN (1 << 5)
34#define NOUVEAU_BO_LOW (1 << 6) 33#define NOUVEAU_BO_LOW (1 << 6)
35#define NOUVEAU_BO_HIGH (1 << 7) 34#define NOUVEAU_BO_HIGH (1 << 7)
36#define NOUVEAU_BO_OR (1 << 8) 35#define NOUVEAU_BO_OR (1 << 8)
37#define NOUVEAU_BO_LOCAL (1 << 9)
38#define NOUVEAU_BO_TILED (1 << 10)
39#define NOUVEAU_BO_ZTILE (1 << 11)
40#define NOUVEAU_BO_INVAL (1 << 12) 36#define NOUVEAU_BO_INVAL (1 << 12)
41#define NOUVEAU_BO_NOSYNC (1 << 13) 37#define NOUVEAU_BO_NOSYNC (1 << 13)
42#define NOUVEAU_BO_NOWAIT (1 << 14) 38#define NOUVEAU_BO_NOWAIT (1 << 14)
@@ -52,10 +48,6 @@ struct nouveau_bo {
52 48
53 uint32_t tile_mode; 49 uint32_t tile_mode;
54 uint32_t tile_flags; 50 uint32_t tile_flags;
55
56 /* Available when buffer is pinned *only* */
57 uint32_t flags;
58 uint64_t offset;
59}; 51};
60 52
61int 53int
@@ -98,12 +90,6 @@ void
98nouveau_bo_unmap(struct nouveau_bo *); 90nouveau_bo_unmap(struct nouveau_bo *);
99 91
100int 92int
101nouveau_bo_pin(struct nouveau_bo *, uint32_t flags);
102
103void
104nouveau_bo_unpin(struct nouveau_bo *);
105
106int
107nouveau_bo_busy(struct nouveau_bo *, uint32_t access); 93nouveau_bo_busy(struct nouveau_bo *, uint32_t access);
108 94
109uint32_t 95uint32_t
diff --git a/nouveau/nouveau_channel.h b/nouveau/nouveau_channel.h
index 294f7497..ddcf8e49 100644
--- a/nouveau/nouveau_channel.h
+++ b/nouveau/nouveau_channel.h
@@ -29,11 +29,12 @@ struct nouveau_subchannel {
29}; 29};
30 30
31struct nouveau_channel { 31struct nouveau_channel {
32 uint32_t *cur;
33 uint32_t *end;
34
32 struct nouveau_device *device; 35 struct nouveau_device *device;
33 int id; 36 int id;
34 37
35 struct nouveau_pushbuf *pushbuf;
36
37 struct nouveau_grobj *nullobj; 38 struct nouveau_grobj *nullobj;
38 struct nouveau_grobj *vram; 39 struct nouveau_grobj *vram;
39 struct nouveau_grobj *gart; 40 struct nouveau_grobj *gart;
diff --git a/nouveau/nouveau_device.c b/nouveau/nouveau_device.c
index 0982d3b6..c5253914 100644
--- a/nouveau/nouveau_device.c
+++ b/nouveau/nouveau_device.c
@@ -26,7 +26,7 @@
26 26
27#include "nouveau_private.h" 27#include "nouveau_private.h"
28 28
29#if NOUVEAU_DRM_HEADER_PATCHLEVEL != 15 29#if NOUVEAU_DRM_HEADER_PATCHLEVEL != 16
30#error nouveau_drm.h does not match expected patchlevel, update libdrm. 30#error nouveau_drm.h does not match expected patchlevel, update libdrm.
31#endif 31#endif
32 32
@@ -54,12 +54,6 @@ nouveau_device_open_existing(struct nouveau_device **dev, int close,
54 nvdev->ctx = ctx; 54 nvdev->ctx = ctx;
55 nvdev->needs_close = close; 55 nvdev->needs_close = close;
56 56
57 ret = drmCommandNone(nvdev->fd, DRM_NOUVEAU_CARD_INIT);
58 if (ret) {
59 nouveau_device_close((void *)&nvdev);
60 return ret;
61 }
62
63 ret = nouveau_device_get_param(&nvdev->base, 57 ret = nouveau_device_get_param(&nvdev->base,
64 NOUVEAU_GETPARAM_VM_VRAM_BASE, &value); 58 NOUVEAU_GETPARAM_VM_VRAM_BASE, &value);
65 if (ret) { 59 if (ret) {
diff --git a/nouveau/nouveau_private.h b/nouveau/nouveau_private.h
index 39758d18..c08fa384 100644
--- a/nouveau/nouveau_private.h
+++ b/nouveau/nouveau_private.h
@@ -35,14 +35,11 @@
35#include "nouveau_bo.h" 35#include "nouveau_bo.h"
36#include "nouveau_resource.h" 36#include "nouveau_resource.h"
37#include "nouveau_pushbuf.h" 37#include "nouveau_pushbuf.h"
38#include "nouveau_reloc.h"
38 39
39#define CALPB_BUFFERS 4 40#define CALPB_BUFFERS 4
40#define CALPB_BUFSZ 16384 41#define CALPB_BUFSZ 16384
41struct nouveau_pushbuf_priv { 42struct nouveau_pushbuf_priv {
42 struct nouveau_pushbuf base;
43
44 int no_aper_update;
45 int use_cal;
46 uint32_t cal_suffix0; 43 uint32_t cal_suffix0;
47 uint32_t cal_suffix1; 44 uint32_t cal_suffix1;
48 struct nouveau_bo *buffer[CALPB_BUFFERS]; 45 struct nouveau_bo *buffer[CALPB_BUFFERS];
@@ -50,15 +47,19 @@ struct nouveau_pushbuf_priv {
50 int current_offset; 47 int current_offset;
51 48
52 unsigned *pushbuf; 49 unsigned *pushbuf;
53 unsigned size; 50 unsigned size;
54 51
55 unsigned marker; 52 uint32_t *marker;
53 unsigned marker_offset;
56 unsigned marker_relocs; 54 unsigned marker_relocs;
55 unsigned marker_push;
57 56
58 struct drm_nouveau_gem_pushbuf_bo *buffers; 57 struct drm_nouveau_gem_pushbuf_bo *buffers;
59 unsigned nr_buffers; 58 unsigned nr_buffers;
60 struct drm_nouveau_gem_pushbuf_reloc *relocs; 59 struct drm_nouveau_gem_pushbuf_reloc *relocs;
61 unsigned nr_relocs; 60 unsigned nr_relocs;
61 struct drm_nouveau_gem_pushbuf_push push[NOUVEAU_GEM_MAX_PUSH];
62 unsigned nr_push;
62}; 63};
63#define nouveau_pushbuf(n) ((struct nouveau_pushbuf_priv *)(n)) 64#define nouveau_pushbuf(n) ((struct nouveau_pushbuf_priv *)(n))
64 65
diff --git a/nouveau/nouveau_pushbuf.c b/nouveau/nouveau_pushbuf.c
index 7da3a47a..28b8018a 100644
--- a/nouveau/nouveau_pushbuf.c
+++ b/nouveau/nouveau_pushbuf.c
@@ -31,7 +31,7 @@
31#define PB_MIN_USER_DWORDS 2048 31#define PB_MIN_USER_DWORDS 2048
32 32
33static int 33static int
34nouveau_pushbuf_space_call(struct nouveau_channel *chan, unsigned min) 34nouveau_pushbuf_space(struct nouveau_channel *chan, unsigned min)
35{ 35{
36 struct nouveau_channel_priv *nvchan = nouveau_channel(chan); 36 struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
37 struct nouveau_pushbuf_priv *nvpb = &nvchan->pb; 37 struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
@@ -41,8 +41,8 @@ nouveau_pushbuf_space_call(struct nouveau_channel *chan, unsigned min)
41 if (min < PB_MIN_USER_DWORDS) 41 if (min < PB_MIN_USER_DWORDS)
42 min = PB_MIN_USER_DWORDS; 42 min = PB_MIN_USER_DWORDS;
43 43
44 nvpb->current_offset = nvpb->base.cur - nvpb->pushbuf; 44 nvpb->current_offset = chan->cur - nvpb->pushbuf;
45 if (nvpb->current_offset + min + 2 <= nvpb->size) 45 if (chan->cur + min + 2 <= chan->end)
46 return 0; 46 return 0;
47 47
48 nvpb->current++; 48 nvpb->current++;
@@ -58,38 +58,13 @@ nouveau_pushbuf_space_call(struct nouveau_channel *chan, unsigned min)
58 nvpb->pushbuf = bo->map; 58 nvpb->pushbuf = bo->map;
59 nvpb->current_offset = 0; 59 nvpb->current_offset = 0;
60 60
61 nvpb->base.channel = chan; 61 chan->cur = nvpb->pushbuf;
62 nvpb->base.remaining = nvpb->size; 62 chan->end = nvpb->pushbuf + nvpb->size;
63 nvpb->base.cur = nvpb->pushbuf;
64 63
65 nouveau_bo_unmap(bo); 64 nouveau_bo_unmap(bo);
66 return 0; 65 return 0;
67} 66}
68 67
69static int
70nouveau_pushbuf_space(struct nouveau_channel *chan, unsigned min)
71{
72 struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
73 struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
74
75 if (nvpb->use_cal)
76 return nouveau_pushbuf_space_call(chan, min);
77
78 if (nvpb->pushbuf) {
79 free(nvpb->pushbuf);
80 nvpb->pushbuf = NULL;
81 }
82
83 nvpb->size = min < PB_MIN_USER_DWORDS ? PB_MIN_USER_DWORDS : min;
84 nvpb->pushbuf = malloc(sizeof(uint32_t) * nvpb->size);
85
86 nvpb->base.channel = chan;
87 nvpb->base.remaining = nvpb->size;
88 nvpb->base.cur = nvpb->pushbuf;
89
90 return 0;
91}
92
93static void 68static void
94nouveau_pushbuf_fini_call(struct nouveau_channel *chan) 69nouveau_pushbuf_fini_call(struct nouveau_channel *chan)
95{ 70{
@@ -99,46 +74,43 @@ nouveau_pushbuf_fini_call(struct nouveau_channel *chan)
99 74
100 for (i = 0; i < CALPB_BUFFERS; i++) 75 for (i = 0; i < CALPB_BUFFERS; i++)
101 nouveau_bo_ref(NULL, &nvpb->buffer[i]); 76 nouveau_bo_ref(NULL, &nvpb->buffer[i]);
102 nvpb->use_cal = 0;
103 nvpb->pushbuf = NULL; 77 nvpb->pushbuf = NULL;
104} 78}
105 79
106static void 80static int
107nouveau_pushbuf_init_call(struct nouveau_channel *chan) 81nouveau_pushbuf_init_call(struct nouveau_channel *chan)
108{ 82{
109 struct drm_nouveau_gem_pushbuf_call req; 83 struct drm_nouveau_gem_pushbuf req;
110 struct nouveau_channel_priv *nvchan = nouveau_channel(chan); 84 struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
111 struct nouveau_pushbuf_priv *nvpb = &nvchan->pb; 85 struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
112 struct nouveau_device *dev = chan->device; 86 struct nouveau_device *dev = chan->device;
87 uint32_t flags = 0;
113 int i, ret; 88 int i, ret;
114 89
90 if (nvchan->drm.pushbuf_domains & NOUVEAU_GEM_DOMAIN_GART)
91 flags |= NOUVEAU_BO_GART;
92 else
93 flags |= NOUVEAU_BO_VRAM;
94
115 req.channel = chan->id; 95 req.channel = chan->id;
116 req.handle = 0; 96 req.nr_push = 0;
117 ret = drmCommandWriteRead(nouveau_device(dev)->fd, 97 ret = drmCommandWriteRead(nouveau_device(dev)->fd,
118 DRM_NOUVEAU_GEM_PUSHBUF_CALL2, 98 DRM_NOUVEAU_GEM_PUSHBUF, &req, sizeof(req));
119 &req, sizeof(req)); 99 if (ret)
120 if (ret) { 100 return ret;
121 ret = drmCommandWriteRead(nouveau_device(dev)->fd,
122 DRM_NOUVEAU_GEM_PUSHBUF_CALL2,
123 &req, sizeof(req));
124 if (ret)
125 return;
126
127 nvpb->no_aper_update = 1;
128 }
129 101
130 for (i = 0; i < CALPB_BUFFERS; i++) { 102 for (i = 0; i < CALPB_BUFFERS; i++) {
131 ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 103 ret = nouveau_bo_new(dev, flags | NOUVEAU_BO_MAP,
132 0, CALPB_BUFSZ, &nvpb->buffer[i]); 104 0, CALPB_BUFSZ, &nvpb->buffer[i]);
133 if (ret) { 105 if (ret) {
134 nouveau_pushbuf_fini_call(chan); 106 nouveau_pushbuf_fini_call(chan);
135 return; 107 return ret;
136 } 108 }
137 } 109 }
138 110
139 nvpb->use_cal = 1;
140 nvpb->cal_suffix0 = req.suffix0; 111 nvpb->cal_suffix0 = req.suffix0;
141 nvpb->cal_suffix1 = req.suffix1; 112 nvpb->cal_suffix1 = req.suffix1;
113 return 0;
142} 114}
143 115
144int 116int
@@ -148,25 +120,18 @@ nouveau_pushbuf_init(struct nouveau_channel *chan)
148 struct nouveau_pushbuf_priv *nvpb = &nvchan->pb; 120 struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
149 int ret; 121 int ret;
150 122
151 nouveau_pushbuf_init_call(chan); 123 ret = nouveau_pushbuf_init_call(chan);
124 if (ret)
125 return ret;
152 126
153 ret = nouveau_pushbuf_space(chan, 0); 127 ret = nouveau_pushbuf_space(chan, 0);
154 if (ret) { 128 if (ret)
155 if (nvpb->use_cal) { 129 return ret;
156 nouveau_pushbuf_fini_call(chan);
157 ret = nouveau_pushbuf_space(chan, 0);
158 }
159
160 if (ret)
161 return ret;
162 }
163 130
164 nvpb->buffers = calloc(NOUVEAU_GEM_MAX_BUFFERS, 131 nvpb->buffers = calloc(NOUVEAU_GEM_MAX_BUFFERS,
165 sizeof(struct drm_nouveau_gem_pushbuf_bo)); 132 sizeof(struct drm_nouveau_gem_pushbuf_bo));
166 nvpb->relocs = calloc(NOUVEAU_GEM_MAX_RELOCS, 133 nvpb->relocs = calloc(NOUVEAU_GEM_MAX_RELOCS,
167 sizeof(struct drm_nouveau_gem_pushbuf_reloc)); 134 sizeof(struct drm_nouveau_gem_pushbuf_reloc));
168
169 chan->pushbuf = &nvpb->base;
170 return 0; 135 return 0;
171} 136}
172 137
@@ -180,92 +145,129 @@ nouveau_pushbuf_fini(struct nouveau_channel *chan)
180 free(nvpb->relocs); 145 free(nvpb->relocs);
181} 146}
182 147
148static int
149nouveau_pushbuf_bo_add(struct nouveau_channel *chan, struct nouveau_bo *bo,
150 unsigned offset, unsigned length)
151{
152 struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
153 struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
154 struct drm_nouveau_gem_pushbuf_push *p = &nvpb->push[nvpb->nr_push++];
155 struct drm_nouveau_gem_pushbuf_bo *pbbo;
156 struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
157
158 pbbo = nouveau_bo_emit_buffer(chan, bo);
159 if (!pbbo)
160 return -ENOMEM;
161 pbbo->valid_domains &= nvchan->drm.pushbuf_domains;
162 pbbo->read_domains |= nvchan->drm.pushbuf_domains;
163 nvbo->pending_refcnt++;
164
165 p->bo_index = pbbo - nvpb->buffers;
166 p->offset = offset;
167 p->length = length;
168 return 0;
169}
170
171int
172nouveau_pushbuf_submit(struct nouveau_channel *chan, struct nouveau_bo *bo,
173 unsigned offset, unsigned length)
174{
175 struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
176 int ret, len;
177
178 if ((AVAIL_RING(chan) + nvpb->current_offset) != nvpb->size) {
179 if (nvpb->cal_suffix0 || nvpb->cal_suffix1) {
180 *(chan->cur++) = nvpb->cal_suffix0;
181 *(chan->cur++) = nvpb->cal_suffix1;
182 }
183
184 len = (chan->cur - nvpb->pushbuf) - nvpb->current_offset;
185
186 ret = nouveau_pushbuf_bo_add(chan, nvpb->buffer[nvpb->current],
187 nvpb->current_offset * 4, len * 4);
188 if (ret)
189 return ret;
190
191 nvpb->current_offset += len;
192 }
193
194 return bo ? nouveau_pushbuf_bo_add(chan, bo, offset, length) : 0;
195}
196
197static void
198nouveau_pushbuf_bo_unref(struct nouveau_pushbuf_priv *nvpb, int index)
199{
200 struct drm_nouveau_gem_pushbuf_bo *pbbo = &nvpb->buffers[index];
201 struct nouveau_bo *bo = (void *)(unsigned long)pbbo->user_priv;
202 struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
203
204 if (--nvbo->pending_refcnt)
205 return;
206
207 if (pbbo->presumed.valid == 0) {
208 nvbo->domain = pbbo->presumed.domain;
209 nvbo->offset = pbbo->presumed.offset;
210 }
211
212 nvbo->pending = NULL;
213 nouveau_bo_ref(NULL, &bo);
214
215 /* we only ever remove from the tail of the pending lists,
216 * so this is safe.
217 */
218 nvpb->nr_buffers--;
219}
220
183int 221int
184nouveau_pushbuf_flush(struct nouveau_channel *chan, unsigned min) 222nouveau_pushbuf_flush(struct nouveau_channel *chan, unsigned min)
185{ 223{
186 struct nouveau_device_priv *nvdev = nouveau_device(chan->device); 224 struct nouveau_device_priv *nvdev = nouveau_device(chan->device);
187 struct nouveau_channel_priv *nvchan = nouveau_channel(chan); 225 struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
188 struct nouveau_pushbuf_priv *nvpb = &nvchan->pb; 226 struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
227 struct drm_nouveau_gem_pushbuf req;
189 unsigned i; 228 unsigned i;
190 int ret; 229 int ret;
191 230
192 if (nvpb->base.remaining == nvpb->size) 231 ret = nouveau_pushbuf_submit(chan, NULL, 0, 0);
232 if (ret)
233 return ret;
234
235 if (!nvpb->nr_push)
193 return 0; 236 return 0;
194 237
195 if (nvpb->use_cal) { 238 req.channel = chan->id;
196 struct drm_nouveau_gem_pushbuf_call req; 239 req.nr_push = nvpb->nr_push;
197 240 req.push = (uint64_t)(unsigned long)nvpb->push;
198 *(nvpb->base.cur++) = nvpb->cal_suffix0; 241 req.nr_buffers = nvpb->nr_buffers;
199 *(nvpb->base.cur++) = nvpb->cal_suffix1; 242 req.buffers = (uint64_t)(unsigned long)nvpb->buffers;
200 if (nvpb->base.remaining > 2) /* space() will fixup if not */ 243 req.nr_relocs = nvpb->nr_relocs;
201 nvpb->base.remaining -= 2; 244 req.relocs = (uint64_t)(unsigned long)nvpb->relocs;
202 245 req.suffix0 = nvpb->cal_suffix0;
203restart_cal: 246 req.suffix1 = nvpb->cal_suffix1;
204 req.channel = chan->id; 247
205 req.handle = nvpb->buffer[nvpb->current]->handle; 248 do {
206 req.offset = nvpb->current_offset * 4; 249 ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_PUSHBUF,
207 req.nr_buffers = nvpb->nr_buffers;
208 req.buffers = (uint64_t)(unsigned long)nvpb->buffers;
209 req.nr_relocs = nvpb->nr_relocs;
210 req.relocs = (uint64_t)(unsigned long)nvpb->relocs;
211 req.nr_dwords = (nvpb->base.cur - nvpb->pushbuf) -
212 nvpb->current_offset;
213 req.suffix0 = nvpb->cal_suffix0;
214 req.suffix1 = nvpb->cal_suffix1;
215 ret = drmCommandWriteRead(nvdev->fd, nvpb->no_aper_update ?
216 DRM_NOUVEAU_GEM_PUSHBUF_CALL :
217 DRM_NOUVEAU_GEM_PUSHBUF_CALL2,
218 &req, sizeof(req)); 250 &req, sizeof(req));
219 if (ret == -EAGAIN) 251 } while (ret == -EAGAIN);
220 goto restart_cal; 252 nvpb->cal_suffix0 = req.suffix0;
221 nvpb->cal_suffix0 = req.suffix0; 253 nvpb->cal_suffix1 = req.suffix1;
222 nvpb->cal_suffix1 = req.suffix1; 254 nvdev->base.vm_vram_size = req.vram_available;
223 if (!nvpb->no_aper_update) { 255 nvdev->base.vm_gart_size = req.gart_available;
224 nvdev->base.vm_vram_size = req.vram_available;
225 nvdev->base.vm_gart_size = req.gart_available;
226 }
227 } else {
228 struct drm_nouveau_gem_pushbuf req;
229
230restart_push:
231 req.channel = chan->id;
232 req.nr_dwords = nvpb->size - nvpb->base.remaining;
233 req.dwords = (uint64_t)(unsigned long)nvpb->pushbuf;
234 req.nr_buffers = nvpb->nr_buffers;
235 req.buffers = (uint64_t)(unsigned long)nvpb->buffers;
236 req.nr_relocs = nvpb->nr_relocs;
237 req.relocs = (uint64_t)(unsigned long)nvpb->relocs;
238 ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_PUSHBUF,
239 &req, sizeof(req));
240 if (ret == -EAGAIN)
241 goto restart_push;
242 }
243
244 256
245 /* Update presumed offset/domain for any buffers that moved. 257 /* Update presumed offset/domain for any buffers that moved.
246 * Dereference all buffers on validate list 258 * Dereference all buffers on validate list
247 */ 259 */
248 for (i = 0; i < nvpb->nr_relocs; i++) { 260 for (i = 0; i < nvpb->nr_relocs; i++) {
249 struct drm_nouveau_gem_pushbuf_reloc *r = &nvpb->relocs[i]; 261 nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].bo_index);
250 struct drm_nouveau_gem_pushbuf_bo *pbbo = 262 nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].reloc_bo_index);
251 &nvpb->buffers[r->bo_index];
252 struct nouveau_bo *bo = (void *)(unsigned long)pbbo->user_priv;
253 struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
254
255 if (--nvbo->pending_refcnt)
256 continue;
257
258 if (pbbo->presumed_ok == 0) {
259 nvbo->domain = pbbo->presumed_domain;
260 nvbo->offset = pbbo->presumed_offset;
261 }
262
263 nvbo->pending = NULL;
264 nouveau_bo_ref(NULL, &bo);
265 } 263 }
266 264
265 for (i = 0; i < nvpb->nr_push; i++)
266 nouveau_pushbuf_bo_unref(nvpb, nvpb->push[i].bo_index);
267
267 nvpb->nr_buffers = 0; 268 nvpb->nr_buffers = 0;
268 nvpb->nr_relocs = 0; 269 nvpb->nr_relocs = 0;
270 nvpb->nr_push = 0;
269 271
270 /* Allocate space for next push buffer */ 272 /* Allocate space for next push buffer */
271 assert(!nouveau_pushbuf_space(chan, min)); 273 assert(!nouveau_pushbuf_space(chan, min));
@@ -273,7 +275,7 @@ restart_push:
273 if (chan->flush_notify) 275 if (chan->flush_notify)
274 chan->flush_notify(chan); 276 chan->flush_notify(chan);
275 277
276 nvpb->marker = 0; 278 nvpb->marker = NULL;
277 return ret; 279 return ret;
278} 280}
279 281
@@ -281,7 +283,7 @@ int
281nouveau_pushbuf_marker_emit(struct nouveau_channel *chan, 283nouveau_pushbuf_marker_emit(struct nouveau_channel *chan,
282 unsigned wait_dwords, unsigned wait_relocs) 284 unsigned wait_dwords, unsigned wait_relocs)
283{ 285{
284 struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf); 286 struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
285 287
286 if (AVAIL_RING(chan) < wait_dwords) 288 if (AVAIL_RING(chan) < wait_dwords)
287 return nouveau_pushbuf_flush(chan, wait_dwords); 289 return nouveau_pushbuf_flush(chan, wait_dwords);
@@ -289,7 +291,9 @@ nouveau_pushbuf_marker_emit(struct nouveau_channel *chan,
289 if (nvpb->nr_relocs + wait_relocs >= NOUVEAU_GEM_MAX_RELOCS) 291 if (nvpb->nr_relocs + wait_relocs >= NOUVEAU_GEM_MAX_RELOCS)
290 return nouveau_pushbuf_flush(chan, wait_dwords); 292 return nouveau_pushbuf_flush(chan, wait_dwords);
291 293
292 nvpb->marker = nvpb->base.cur - nvpb->pushbuf; 294 nvpb->marker = chan->cur;
295 nvpb->marker_offset = nvpb->current_offset;
296 nvpb->marker_push = nvpb->nr_push;
293 nvpb->marker_relocs = nvpb->nr_relocs; 297 nvpb->marker_relocs = nvpb->nr_relocs;
294 return 0; 298 return 0;
295} 299}
@@ -297,7 +301,7 @@ nouveau_pushbuf_marker_emit(struct nouveau_channel *chan,
297void 301void
298nouveau_pushbuf_marker_undo(struct nouveau_channel *chan) 302nouveau_pushbuf_marker_undo(struct nouveau_channel *chan)
299{ 303{
300 struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf); 304 struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
301 unsigned i; 305 unsigned i;
302 306
303 if (!nvpb->marker) 307 if (!nvpb->marker)
@@ -305,49 +309,19 @@ nouveau_pushbuf_marker_undo(struct nouveau_channel *chan)
305 309
306 /* undo any relocs/buffers added to the list since last marker */ 310 /* undo any relocs/buffers added to the list since last marker */
307 for (i = nvpb->marker_relocs; i < nvpb->nr_relocs; i++) { 311 for (i = nvpb->marker_relocs; i < nvpb->nr_relocs; i++) {
308 struct drm_nouveau_gem_pushbuf_reloc *r = &nvpb->relocs[i]; 312 nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].bo_index);
309 struct drm_nouveau_gem_pushbuf_bo *pbbo = 313 nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].reloc_bo_index);
310 &nvpb->buffers[r->bo_index];
311 struct nouveau_bo *bo = (void *)(unsigned long)pbbo->user_priv;
312 struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
313
314 if (--nvbo->pending_refcnt)
315 continue;
316
317 nvbo->pending = NULL;
318 nouveau_bo_ref(NULL, &bo);
319 nvpb->nr_buffers--;
320 } 314 }
321 nvpb->nr_relocs = nvpb->marker_relocs; 315 nvpb->nr_relocs = nvpb->marker_relocs;
322 316
323 /* reset pushbuf back to last marker */ 317 for (i = nvpb->marker_push; i < nvpb->nr_push; i++)
324 nvpb->base.cur = nvpb->pushbuf + nvpb->marker; 318 nouveau_pushbuf_bo_unref(nvpb, nvpb->push[i].bo_index);
325 nvpb->base.remaining = nvpb->size - nvpb->marker; 319 nvpb->nr_push = nvpb->marker_push;
326 nvpb->marker = 0;
327}
328
329static uint32_t
330nouveau_pushbuf_calc_reloc(struct drm_nouveau_gem_pushbuf_bo *pbbo,
331 struct drm_nouveau_gem_pushbuf_reloc *r)
332{
333 uint32_t push = 0;
334
335 if (r->flags & NOUVEAU_GEM_RELOC_LOW)
336 push = (pbbo->presumed_offset + r->data);
337 else
338 if (r->flags & NOUVEAU_GEM_RELOC_HIGH)
339 push = (pbbo->presumed_offset + r->data) >> 32;
340 else
341 push = r->data;
342
343 if (r->flags & NOUVEAU_GEM_RELOC_OR) {
344 if (pbbo->presumed_domain & NOUVEAU_GEM_DOMAIN_VRAM)
345 push |= r->vor;
346 else
347 push |= r->tor;
348 }
349 320
350 return push; 321 /* reset pushbuf back to last marker */
322 chan->cur = nvpb->marker;
323 nvpb->current_offset = nvpb->marker_offset;
324 nvpb->marker = NULL;
351} 325}
352 326
353int 327int
@@ -355,66 +329,15 @@ nouveau_pushbuf_emit_reloc(struct nouveau_channel *chan, void *ptr,
355 struct nouveau_bo *bo, uint32_t data, uint32_t data2, 329 struct nouveau_bo *bo, uint32_t data, uint32_t data2,
356 uint32_t flags, uint32_t vor, uint32_t tor) 330 uint32_t flags, uint32_t vor, uint32_t tor)
357{ 331{
358 struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf); 332 struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
359 struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 333 int ret;
360 struct drm_nouveau_gem_pushbuf_reloc *r;
361 struct drm_nouveau_gem_pushbuf_bo *pbbo;
362 uint32_t domains = 0;
363
364 if (nvpb->nr_relocs >= NOUVEAU_GEM_MAX_RELOCS) {
365 fprintf(stderr, "too many relocs!!\n");
366 return -ENOMEM;
367 }
368
369 if (nvbo->user && (flags & NOUVEAU_BO_WR)) {
370 fprintf(stderr, "write to user buffer!!\n");
371 return -EINVAL;
372 }
373
374 pbbo = nouveau_bo_emit_buffer(chan, bo);
375 if (!pbbo) {
376 fprintf(stderr, "buffer emit fail :(\n");
377 return -ENOMEM;
378 }
379
380 nvbo->pending_refcnt++;
381
382 if (flags & NOUVEAU_BO_VRAM)
383 domains |= NOUVEAU_GEM_DOMAIN_VRAM;
384 if (flags & NOUVEAU_BO_GART)
385 domains |= NOUVEAU_GEM_DOMAIN_GART;
386
387 if (!(pbbo->valid_domains & domains)) {
388 fprintf(stderr, "no valid domains remain!\n");
389 return -EINVAL;
390 }
391 pbbo->valid_domains &= domains;
392 334
393 assert(flags & NOUVEAU_BO_RDWR); 335 ret = nouveau_reloc_emit(chan, nvpb->buffer[nvpb->current],
394 if (flags & NOUVEAU_BO_RD) { 336 (char *)ptr - (char *)nvpb->pushbuf, ptr,
395 pbbo->read_domains |= domains; 337 bo, data, data2, flags, vor, tor);
396 } 338 if (ret)
397 if (flags & NOUVEAU_BO_WR) { 339 return ret;
398 pbbo->write_domains |= domains;
399 nvbo->write_marker = 1;
400 }
401 340
402 r = nvpb->relocs + nvpb->nr_relocs++;
403 r->bo_index = pbbo - nvpb->buffers;
404 r->reloc_index = (uint32_t *)ptr - nvpb->pushbuf;
405 r->flags = 0;
406 if (flags & NOUVEAU_BO_LOW)
407 r->flags |= NOUVEAU_GEM_RELOC_LOW;
408 if (flags & NOUVEAU_BO_HIGH)
409 r->flags |= NOUVEAU_GEM_RELOC_HIGH;
410 if (flags & NOUVEAU_BO_OR)
411 r->flags |= NOUVEAU_GEM_RELOC_OR;
412 r->data = data;
413 r->vor = vor;
414 r->tor = tor;
415
416 *(uint32_t *)ptr = (flags & NOUVEAU_BO_DUMMY) ? 0 :
417 nouveau_pushbuf_calc_reloc(pbbo, r);
418 return 0; 341 return 0;
419} 342}
420 343
diff --git a/nouveau/nouveau_pushbuf.h b/nouveau/nouveau_pushbuf.h
index 46982afa..52d13a0a 100644
--- a/nouveau/nouveau_pushbuf.h
+++ b/nouveau/nouveau_pushbuf.h
@@ -29,13 +29,6 @@
29#include "nouveau_bo.h" 29#include "nouveau_bo.h"
30#include "nouveau_grobj.h" 30#include "nouveau_grobj.h"
31 31
32struct nouveau_pushbuf {
33 struct nouveau_channel *channel;
34
35 unsigned remaining;
36 uint32_t *cur;
37};
38
39int 32int
40nouveau_pushbuf_flush(struct nouveau_channel *, unsigned min); 33nouveau_pushbuf_flush(struct nouveau_channel *, unsigned min);
41 34
@@ -51,6 +44,10 @@ nouveau_pushbuf_emit_reloc(struct nouveau_channel *, void *ptr,
51 struct nouveau_bo *, uint32_t data, uint32_t data2, 44 struct nouveau_bo *, uint32_t data, uint32_t data2,
52 uint32_t flags, uint32_t vor, uint32_t tor); 45 uint32_t flags, uint32_t vor, uint32_t tor);
53 46
47int
48nouveau_pushbuf_submit(struct nouveau_channel *chan, struct nouveau_bo *bo,
49 unsigned offset, unsigned length);
50
54/* Push buffer access macros */ 51/* Push buffer access macros */
55static __inline__ int 52static __inline__ int
56MARK_RING(struct nouveau_channel *chan, unsigned dwords, unsigned relocs) 53MARK_RING(struct nouveau_channel *chan, unsigned dwords, unsigned relocs)
@@ -67,14 +64,14 @@ MARK_UNDO(struct nouveau_channel *chan)
67static __inline__ void 64static __inline__ void
68OUT_RING(struct nouveau_channel *chan, unsigned data) 65OUT_RING(struct nouveau_channel *chan, unsigned data)
69{ 66{
70 *(chan->pushbuf->cur++) = (data); 67 *(chan->cur++) = (data);
71} 68}
72 69
73static __inline__ void 70static __inline__ void
74OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned size) 71OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned size)
75{ 72{
76 memcpy(chan->pushbuf->cur, data, size * 4); 73 memcpy(chan->cur, data, size * 4);
77 chan->pushbuf->cur += size; 74 chan->cur += size;
78} 75}
79 76
80static __inline__ void 77static __inline__ void
@@ -88,13 +85,13 @@ OUT_RINGf(struct nouveau_channel *chan, float f)
88static __inline__ unsigned 85static __inline__ unsigned
89AVAIL_RING(struct nouveau_channel *chan) 86AVAIL_RING(struct nouveau_channel *chan)
90{ 87{
91 return chan->pushbuf->remaining; 88 return chan->end - chan->cur;
92} 89}
93 90
94static __inline__ void 91static __inline__ void
95WAIT_RING(struct nouveau_channel *chan, unsigned size) 92WAIT_RING(struct nouveau_channel *chan, unsigned size)
96{ 93{
97 if (chan->pushbuf->remaining < size) 94 if (chan->cur + size > chan->end)
98 nouveau_pushbuf_flush(chan, size); 95 nouveau_pushbuf_flush(chan, size);
99} 96}
100 97
@@ -108,7 +105,6 @@ BEGIN_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr,
108 105
109 WAIT_RING(chan, size + 1); 106 WAIT_RING(chan, size + 1);
110 OUT_RING(chan, (gr->subc << 13) | (size << 18) | mthd); 107 OUT_RING(chan, (gr->subc << 13) | (size << 18) | mthd);
111 chan->pushbuf->remaining -= (size + 1);
112} 108}
113 109
114/* non-incrementing BEGIN_RING */ 110/* non-incrementing BEGIN_RING */
@@ -147,7 +143,7 @@ static __inline__ int
147OUT_RELOC(struct nouveau_channel *chan, struct nouveau_bo *bo, 143OUT_RELOC(struct nouveau_channel *chan, struct nouveau_bo *bo,
148 unsigned data, unsigned flags, unsigned vor, unsigned tor) 144 unsigned data, unsigned flags, unsigned vor, unsigned tor)
149{ 145{
150 return nouveau_pushbuf_emit_reloc(chan, chan->pushbuf->cur++, bo, 146 return nouveau_pushbuf_emit_reloc(chan, chan->cur++, bo,
151 data, 0, flags, vor, tor); 147 data, 0, flags, vor, tor);
152} 148}
153 149
@@ -156,7 +152,7 @@ OUT_RELOC2(struct nouveau_channel *chan, struct nouveau_bo *bo,
156 unsigned data, unsigned data2, unsigned flags, 152 unsigned data, unsigned data2, unsigned flags,
157 unsigned vor, unsigned tor) 153 unsigned vor, unsigned tor)
158{ 154{
159 return nouveau_pushbuf_emit_reloc(chan, chan->pushbuf->cur++, bo, 155 return nouveau_pushbuf_emit_reloc(chan, chan->cur++, bo,
160 data, data2, flags, vor, tor); 156 data, data2, flags, vor, tor);
161} 157}
162 158
diff --git a/nouveau/nouveau_reloc.c b/nouveau/nouveau_reloc.c
new file mode 100644
index 00000000..301482b0
--- /dev/null
+++ b/nouveau/nouveau_reloc.c
@@ -0,0 +1,132 @@
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
30static uint32_t
31nouveau_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
54int
55nouveau_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 rpbbo = nouveau_bo_emit_buffer(chan, reloc_bo);
77 if (!rpbbo)
78 return -ENOMEM;
79 nouveau_bo(reloc_bo)->pending_refcnt++;
80
81 pbbo = nouveau_bo_emit_buffer(chan, bo);
82 if (!pbbo) {
83 fprintf(stderr, "buffer emit fail :(\n");
84 return -ENOMEM;
85 }
86 nouveau_bo(bo)->pending_refcnt++;
87
88 if (flags & NOUVEAU_BO_VRAM)
89 domains |= NOUVEAU_GEM_DOMAIN_VRAM;
90 if (flags & NOUVEAU_BO_GART)
91 domains |= NOUVEAU_GEM_DOMAIN_GART;
92
93 if (!(pbbo->valid_domains & domains)) {
94 fprintf(stderr, "no valid domains remain!\n");
95 return -EINVAL;
96 }
97 pbbo->valid_domains &= domains;
98
99 assert(flags & NOUVEAU_BO_RDWR);
100 if (flags & NOUVEAU_BO_RD) {
101 pbbo->read_domains |= domains;
102 }
103 if (flags & NOUVEAU_BO_WR) {
104 pbbo->write_domains |= domains;
105 nvbo->write_marker = 1;
106 }
107
108 r = nvpb->relocs + nvpb->nr_relocs++;
109 r->reloc_bo_index = rpbbo - nvpb->buffers;
110 r->reloc_bo_offset = reloc_offset;
111 r->bo_index = pbbo - nvpb->buffers;
112 r->flags = 0;
113 if (flags & NOUVEAU_BO_LOW)
114 r->flags |= NOUVEAU_GEM_RELOC_LOW;
115 if (flags & NOUVEAU_BO_HIGH)
116 r->flags |= NOUVEAU_GEM_RELOC_HIGH;
117 if (flags & NOUVEAU_BO_OR)
118 r->flags |= NOUVEAU_GEM_RELOC_OR;
119 r->data = data;
120 r->vor = vor;
121 r->tor = tor;
122
123 if (reloc_ptr) {
124 if (flags & NOUVEAU_BO_DUMMY)
125 *reloc_ptr = 0;
126 else
127 *reloc_ptr = nouveau_reloc_calc(pbbo, r);
128 }
129
130 return 0;
131}
132
diff --git a/nouveau/nouveau_reloc.h b/nouveau/nouveau_reloc.h
new file mode 100644
index 00000000..24ddb52e
--- /dev/null
+++ b/nouveau/nouveau_reloc.h
@@ -0,0 +1,32 @@
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#ifndef __NOUVEAU_RELOC_H__
24#define __NOUVEAU_RELOC_H__
25
26int
27nouveau_reloc_emit(struct nouveau_channel *chan, struct nouveau_bo *reloc_bo,
28 uint32_t reloc_offset, uint32_t *reloc_ptr,
29 struct nouveau_bo *bo, uint32_t data, uint32_t data2,
30 uint32_t flags, uint32_t vor, uint32_t tor);
31
32#endif