aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_debugfs.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.c108
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.h21
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c15
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fifo.c8
6 files changed, 155 insertions, 15 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
index d79db3698f16..89e36ee057c8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c
+++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
@@ -47,12 +47,23 @@ nouveau_debugfs_channel_info(struct seq_file *m, void *data)
47 seq_printf(m, " cur: 0x%08x\n", chan->dma.cur << 2); 47 seq_printf(m, " cur: 0x%08x\n", chan->dma.cur << 2);
48 seq_printf(m, " put: 0x%08x\n", chan->dma.put << 2); 48 seq_printf(m, " put: 0x%08x\n", chan->dma.put << 2);
49 seq_printf(m, " free: 0x%08x\n", chan->dma.free << 2); 49 seq_printf(m, " free: 0x%08x\n", chan->dma.free << 2);
50 if (chan->dma.ib_max) {
51 seq_printf(m, " ib max: 0x%08x\n", chan->dma.ib_max);
52 seq_printf(m, " ib put: 0x%08x\n", chan->dma.ib_put);
53 seq_printf(m, " ib free: 0x%08x\n", chan->dma.ib_free);
54 }
50 55
51 seq_printf(m, "gpu fifo state:\n"); 56 seq_printf(m, "gpu fifo state:\n");
52 seq_printf(m, " get: 0x%08x\n", 57 seq_printf(m, " get: 0x%08x\n",
53 nvchan_rd32(chan, chan->user_get)); 58 nvchan_rd32(chan, chan->user_get));
54 seq_printf(m, " put: 0x%08x\n", 59 seq_printf(m, " put: 0x%08x\n",
55 nvchan_rd32(chan, chan->user_put)); 60 nvchan_rd32(chan, chan->user_put));
61 if (chan->dma.ib_max) {
62 seq_printf(m, " ib get: 0x%08x\n",
63 nvchan_rd32(chan, 0x88));
64 seq_printf(m, " ib put: 0x%08x\n",
65 nvchan_rd32(chan, 0x8c));
66 }
56 67
57 seq_printf(m, "last fence : %d\n", chan->fence.sequence); 68 seq_printf(m, "last fence : %d\n", chan->fence.sequence);
58 seq_printf(m, "last signalled: %d\n", chan->fence.sequence_ack); 69 seq_printf(m, "last signalled: %d\n", chan->fence.sequence_ack);
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
index 50d9e67745af..b9c80bb17250 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
@@ -32,7 +32,22 @@
32void 32void
33nouveau_dma_pre_init(struct nouveau_channel *chan) 33nouveau_dma_pre_init(struct nouveau_channel *chan)
34{ 34{
35 chan->dma.max = (chan->pushbuf_bo->bo.mem.size >> 2) - 2; 35 struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
36 struct nouveau_bo *pushbuf = chan->pushbuf_bo;
37
38 if (dev_priv->card_type == NV_50) {
39 const int ib_size = pushbuf->bo.mem.size / 2;
40
41 chan->dma.ib_base = (pushbuf->bo.mem.size - ib_size) >> 2;
42 chan->dma.ib_max = (ib_size / 8) - 1;
43 chan->dma.ib_put = 0;
44 chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
45
46 chan->dma.max = (pushbuf->bo.mem.size - ib_size) >> 2;
47 } else {
48 chan->dma.max = (pushbuf->bo.mem.size >> 2) - 2;
49 }
50
36 chan->dma.put = 0; 51 chan->dma.put = 0;
37 chan->dma.cur = chan->dma.put; 52 chan->dma.cur = chan->dma.put;
38 chan->dma.free = chan->dma.max - chan->dma.cur; 53 chan->dma.free = chan->dma.max - chan->dma.cur;
@@ -162,12 +177,101 @@ READ_GET(struct nouveau_channel *chan, uint32_t *prev_get, uint32_t *timeout)
162 return (val - chan->pushbuf_base) >> 2; 177 return (val - chan->pushbuf_base) >> 2;
163} 178}
164 179
180void
181nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo,
182 int delta, int dwords)
183{
184 struct nouveau_bo *pb = chan->pushbuf_bo;
185 uint64_t offset = (bo->bo.mem.mm_node->start << PAGE_SHIFT) + delta;
186 int ip = (chan->dma.ib_put * 2) + chan->dma.ib_base;
187
188 BUG_ON(chan->dma.ib_free < 1);
189 nouveau_bo_wr32(pb, ip++, offset);
190 nouveau_bo_wr32(pb, ip++, dwords << 10);
191
192 chan->dma.ib_put = (chan->dma.ib_put + 1) & chan->dma.ib_max;
193 nvchan_wr32(chan, 0x8c, chan->dma.ib_put);
194 chan->dma.ib_free--;
195}
196
197static int
198nv50_dma_push_wait(struct nouveau_channel *chan, int count)
199{
200 uint32_t cnt = 0, prev_get = 0;
201
202 while (chan->dma.ib_free < count) {
203 uint32_t get = nvchan_rd32(chan, 0x88);
204 if (get != prev_get) {
205 prev_get = get;
206 cnt = 0;
207 }
208
209 if ((++cnt & 0xff) == 0) {
210 DRM_UDELAY(1);
211 if (cnt > 100000)
212 return -EBUSY;
213 }
214
215 chan->dma.ib_free = get - chan->dma.ib_put;
216 if (chan->dma.ib_free <= 0)
217 chan->dma.ib_free += chan->dma.ib_max + 1;
218 }
219
220 return 0;
221}
222
223static int
224nv50_dma_wait(struct nouveau_channel *chan, int slots, int count)
225{
226 uint32_t cnt = 0, prev_get = 0;
227 int ret;
228
229 ret = nv50_dma_push_wait(chan, slots + 1);
230 if (unlikely(ret))
231 return ret;
232
233 while (chan->dma.free < count) {
234 int get = READ_GET(chan, &prev_get, &cnt);
235 if (unlikely(get < 0)) {
236 if (get == -EINVAL)
237 continue;
238
239 return get;
240 }
241
242 if (get <= chan->dma.cur) {
243 chan->dma.free = chan->dma.max - chan->dma.cur;
244 if (chan->dma.free >= count)
245 break;
246
247 FIRE_RING(chan);
248 do {
249 get = READ_GET(chan, &prev_get, &cnt);
250 if (unlikely(get < 0)) {
251 if (get == -EINVAL)
252 continue;
253 return get;
254 }
255 } while (get == 0);
256 chan->dma.cur = 0;
257 chan->dma.put = 0;
258 }
259
260 chan->dma.free = get - chan->dma.cur - 1;
261 }
262
263 return 0;
264}
265
165int 266int
166nouveau_dma_wait(struct nouveau_channel *chan, int size) 267nouveau_dma_wait(struct nouveau_channel *chan, int slots, int size)
167{ 268{
168 uint32_t prev_get = 0, cnt = 0; 269 uint32_t prev_get = 0, cnt = 0;
169 int get; 270 int get;
170 271
272 if (chan->dma.ib_max)
273 return nv50_dma_wait(chan, slots, size);
274
171 while (chan->dma.free < size) { 275 while (chan->dma.free < size) {
172 get = READ_GET(chan, &prev_get, &cnt); 276 get = READ_GET(chan, &prev_get, &cnt);
173 if (unlikely(get == -EBUSY)) 277 if (unlikely(get == -EBUSY))
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h
index dabfd655f93e..da6e16dafa4d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.h
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.h
@@ -31,6 +31,9 @@
31#define NOUVEAU_DMA_DEBUG 0 31#define NOUVEAU_DMA_DEBUG 0
32#endif 32#endif
33 33
34void nv50_dma_push(struct nouveau_channel *, struct nouveau_bo *,
35 int delta, int dwords);
36
34/* 37/*
35 * There's a hw race condition where you can't jump to your PUT offset, 38 * There's a hw race condition where you can't jump to your PUT offset,
36 * to avoid this we jump to offset + SKIPS and fill the difference with 39 * to avoid this we jump to offset + SKIPS and fill the difference with
@@ -96,13 +99,11 @@ enum {
96static __must_check inline int 99static __must_check inline int
97RING_SPACE(struct nouveau_channel *chan, int size) 100RING_SPACE(struct nouveau_channel *chan, int size)
98{ 101{
99 if (chan->dma.free < size) { 102 int ret;
100 int ret;
101 103
102 ret = nouveau_dma_wait(chan, size); 104 ret = nouveau_dma_wait(chan, 1, size);
103 if (ret) 105 if (ret)
104 return ret; 106 return ret;
105 }
106 107
107 chan->dma.free -= size; 108 chan->dma.free -= size;
108 return 0; 109 return 0;
@@ -146,7 +147,13 @@ FIRE_RING(struct nouveau_channel *chan)
146 return; 147 return;
147 chan->accel_done = true; 148 chan->accel_done = true;
148 149
149 WRITE_PUT(chan->dma.cur); 150 if (chan->dma.ib_max) {
151 nv50_dma_push(chan, chan->pushbuf_bo, chan->dma.put << 2,
152 chan->dma.cur - chan->dma.put);
153 } else {
154 WRITE_PUT(chan->dma.cur);
155 }
156
150 chan->dma.put = chan->dma.cur; 157 chan->dma.put = chan->dma.cur;
151} 158}
152 159
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 52cc13bd02b9..d221044e0793 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -239,6 +239,11 @@ struct nouveau_channel {
239 int cur; 239 int cur;
240 int put; 240 int put;
241 /* access via pushbuf_bo */ 241 /* access via pushbuf_bo */
242
243 int ib_base;
244 int ib_max;
245 int ib_free;
246 int ib_put;
242 } dma; 247 } dma;
243 248
244 uint32_t sw_subchannel[8]; 249 uint32_t sw_subchannel[8];
@@ -848,7 +853,7 @@ nouveau_debugfs_channel_fini(struct nouveau_channel *chan)
848/* nouveau_dma.c */ 853/* nouveau_dma.c */
849extern void nouveau_dma_pre_init(struct nouveau_channel *); 854extern void nouveau_dma_pre_init(struct nouveau_channel *);
850extern int nouveau_dma_init(struct nouveau_channel *); 855extern int nouveau_dma_init(struct nouveau_channel *);
851extern int nouveau_dma_wait(struct nouveau_channel *, int size); 856extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
852 857
853/* nouveau_acpi.c */ 858/* nouveau_acpi.c */
854#ifdef CONFIG_ACPI 859#ifdef CONFIG_ACPI
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 70cc30803e3b..986b67099f6c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -707,7 +707,7 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data,
707 uint32_t retaddy; 707 uint32_t retaddy;
708 708
709 if (chan->dma.free < 4 + NOUVEAU_DMA_SKIPS) { 709 if (chan->dma.free < 4 + NOUVEAU_DMA_SKIPS) {
710 ret = nouveau_dma_wait(chan, 4 + NOUVEAU_DMA_SKIPS); 710 ret = nouveau_dma_wait(chan, 0, 4 + NOUVEAU_DMA_SKIPS);
711 if (ret) { 711 if (ret) {
712 NV_ERROR(dev, "jmp_space: %d\n", ret); 712 NV_ERROR(dev, "jmp_space: %d\n", ret);
713 goto out; 713 goto out;
@@ -754,6 +754,15 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data,
754 } 754 }
755 } 755 }
756 756
757 if (chan->dma.ib_max) {
758 ret = nouveau_dma_wait(chan, 2, 6);
759 if (ret) {
760 NV_INFO(dev, "nv50cal_space: %d\n", ret);
761 goto out;
762 }
763
764 nv50_dma_push(chan, pbbo, req->offset, req->nr_dwords);
765 } else
757 if (PUSHBUF_CAL) { 766 if (PUSHBUF_CAL) {
758 ret = RING_SPACE(chan, 2); 767 ret = RING_SPACE(chan, 2);
759 if (ret) { 768 if (ret) {
@@ -792,6 +801,10 @@ out:
792 kfree(bo); 801 kfree(bo);
793 802
794out_next: 803out_next:
804 if (chan->dma.ib_max) {
805 req->suffix0 = 0x00000000;
806 req->suffix1 = 0x00000000;
807 } else
795 if (PUSHBUF_CAL) { 808 if (PUSHBUF_CAL) {
796 req->suffix0 = 0x00020000; 809 req->suffix0 = 0x00020000;
797 req->suffix1 = 0x00000000; 810 req->suffix1 = 0x00000000;
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
index 369ecb4cee57..e20c0e2474f3 100644
--- a/drivers/gpu/drm/nouveau/nv50_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv50_fifo.c
@@ -283,17 +283,17 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
283 283
284 dev_priv->engine.instmem.prepare_access(dev, true); 284 dev_priv->engine.instmem.prepare_access(dev, true);
285 285
286 nv_wo32(dev, ramfc, 0x08/4, chan->pushbuf_base);
287 nv_wo32(dev, ramfc, 0x10/4, chan->pushbuf_base);
288 nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4); 286 nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4);
289 nv_wo32(dev, ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4)); 287 nv_wo32(dev, ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4));
290 nv_wo32(dev, ramfc, 0x3c/4, 0x00086078);
291 nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff); 288 nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff);
292 nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff); 289 nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff);
293 nv_wo32(dev, ramfc, 0x40/4, 0x00000000); 290 nv_wo32(dev, ramfc, 0x40/4, 0x00000000);
294 nv_wo32(dev, ramfc, 0x7c/4, 0x30000001); 291 nv_wo32(dev, ramfc, 0x7c/4, 0x30000001);
295 nv_wo32(dev, ramfc, 0x78/4, 0x00000000); 292 nv_wo32(dev, ramfc, 0x78/4, 0x00000000);
296 nv_wo32(dev, ramfc, 0x4c/4, 0xffffffff); 293 nv_wo32(dev, ramfc, 0x3c/4, 0x403f6078);
294 nv_wo32(dev, ramfc, 0x50/4, chan->pushbuf_base +
295 chan->dma.ib_base * 4);
296 nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16);
297 297
298 if (!IS_G80) { 298 if (!IS_G80) {
299 nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id); 299 nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id);