diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_debugfs.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_dma.c | 108 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_dma.h | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_gem.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_fifo.c | 8 |
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 @@ | |||
32 | void | 32 | void |
33 | nouveau_dma_pre_init(struct nouveau_channel *chan) | 33 | nouveau_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 | ||
180 | void | ||
181 | nv50_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 | |||
197 | static int | ||
198 | nv50_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 | |||
223 | static int | ||
224 | nv50_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 | |||
165 | int | 266 | int |
166 | nouveau_dma_wait(struct nouveau_channel *chan, int size) | 267 | nouveau_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 | ||
34 | void 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 { | |||
96 | static __must_check inline int | 99 | static __must_check inline int |
97 | RING_SPACE(struct nouveau_channel *chan, int size) | 100 | RING_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 */ |
849 | extern void nouveau_dma_pre_init(struct nouveau_channel *); | 854 | extern void nouveau_dma_pre_init(struct nouveau_channel *); |
850 | extern int nouveau_dma_init(struct nouveau_channel *); | 855 | extern int nouveau_dma_init(struct nouveau_channel *); |
851 | extern int nouveau_dma_wait(struct nouveau_channel *, int size); | 856 | extern 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 | ||
794 | out_next: | 803 | out_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); |