]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
1b1e6b39cd861059395de2dd55f06c8ce659991f
[karo-tx-linux.git] / drivers / gpu / drm / nouveau / core / engine / fifo / nvc0.c
1 /*
2  * Copyright 2012 Red Hat Inc.
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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: Ben Skeggs
23  */
24
25 #include <core/client.h>
26 #include <core/handle.h>
27 #include <core/namedb.h>
28 #include <core/gpuobj.h>
29 #include <core/engctx.h>
30 #include <core/event.h>
31 #include <core/class.h>
32 #include <core/enum.h>
33
34 #include <subdev/timer.h>
35 #include <subdev/bar.h>
36 #include <subdev/fb.h>
37 #include <subdev/vm.h>
38
39 #include <engine/dmaobj.h>
40 #include <engine/fifo.h>
41
42 struct nvc0_fifo_priv {
43         struct nouveau_fifo base;
44         struct nouveau_gpuobj *runlist[2];
45         int cur_runlist;
46         struct {
47                 struct nouveau_gpuobj *mem;
48                 struct nouveau_vma bar;
49         } user;
50         int spoon_nr;
51 };
52
53 struct nvc0_fifo_base {
54         struct nouveau_fifo_base base;
55         struct nouveau_gpuobj *pgd;
56         struct nouveau_vm *vm;
57 };
58
59 struct nvc0_fifo_chan {
60         struct nouveau_fifo_chan base;
61 };
62
63 /*******************************************************************************
64  * FIFO channel objects
65  ******************************************************************************/
66
67 static void
68 nvc0_fifo_runlist_update(struct nvc0_fifo_priv *priv)
69 {
70         struct nouveau_bar *bar = nouveau_bar(priv);
71         struct nouveau_gpuobj *cur;
72         int i, p;
73
74         mutex_lock(&nv_subdev(priv)->mutex);
75         cur = priv->runlist[priv->cur_runlist];
76         priv->cur_runlist = !priv->cur_runlist;
77
78         for (i = 0, p = 0; i < 128; i++) {
79                 if (!(nv_rd32(priv, 0x003004 + (i * 8)) & 1))
80                         continue;
81                 nv_wo32(cur, p + 0, i);
82                 nv_wo32(cur, p + 4, 0x00000004);
83                 p += 8;
84         }
85         bar->flush(bar);
86
87         nv_wr32(priv, 0x002270, cur->addr >> 12);
88         nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3));
89         if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000))
90                 nv_error(priv, "runlist update failed\n");
91         mutex_unlock(&nv_subdev(priv)->mutex);
92 }
93
94 static int
95 nvc0_fifo_context_attach(struct nouveau_object *parent,
96                          struct nouveau_object *object)
97 {
98         struct nouveau_bar *bar = nouveau_bar(parent);
99         struct nvc0_fifo_base *base = (void *)parent->parent;
100         struct nouveau_engctx *ectx = (void *)object;
101         u32 addr;
102         int ret;
103
104         switch (nv_engidx(object->engine)) {
105         case NVDEV_ENGINE_SW   : return 0;
106         case NVDEV_ENGINE_GR   : addr = 0x0210; break;
107         case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
108         case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
109         case NVDEV_ENGINE_BSP  : addr = 0x0270; break;
110         case NVDEV_ENGINE_VP   : addr = 0x0250; break;
111         case NVDEV_ENGINE_PPP  : addr = 0x0260; break;
112         default:
113                 return -EINVAL;
114         }
115
116         if (!ectx->vma.node) {
117                 ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
118                                             NV_MEM_ACCESS_RW, &ectx->vma);
119                 if (ret)
120                         return ret;
121
122                 nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
123         }
124
125         nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
126         nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
127         bar->flush(bar);
128         return 0;
129 }
130
131 static int
132 nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
133                          struct nouveau_object *object)
134 {
135         struct nouveau_bar *bar = nouveau_bar(parent);
136         struct nvc0_fifo_priv *priv = (void *)parent->engine;
137         struct nvc0_fifo_base *base = (void *)parent->parent;
138         struct nvc0_fifo_chan *chan = (void *)parent;
139         u32 addr;
140
141         switch (nv_engidx(object->engine)) {
142         case NVDEV_ENGINE_SW   : return 0;
143         case NVDEV_ENGINE_GR   : addr = 0x0210; break;
144         case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
145         case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
146         case NVDEV_ENGINE_BSP  : addr = 0x0270; break;
147         case NVDEV_ENGINE_VP   : addr = 0x0250; break;
148         case NVDEV_ENGINE_PPP  : addr = 0x0260; break;
149         default:
150                 return -EINVAL;
151         }
152
153         nv_wr32(priv, 0x002634, chan->base.chid);
154         if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
155                 nv_error(priv, "channel %d [%s] kick timeout\n",
156                          chan->base.chid, nouveau_client_name(chan));
157                 if (suspend)
158                         return -EBUSY;
159         }
160
161         nv_wo32(base, addr + 0x00, 0x00000000);
162         nv_wo32(base, addr + 0x04, 0x00000000);
163         bar->flush(bar);
164         return 0;
165 }
166
167 static int
168 nvc0_fifo_chan_ctor(struct nouveau_object *parent,
169                     struct nouveau_object *engine,
170                     struct nouveau_oclass *oclass, void *data, u32 size,
171                     struct nouveau_object **pobject)
172 {
173         struct nouveau_bar *bar = nouveau_bar(parent);
174         struct nvc0_fifo_priv *priv = (void *)engine;
175         struct nvc0_fifo_base *base = (void *)parent;
176         struct nvc0_fifo_chan *chan;
177         struct nv50_channel_ind_class *args = data;
178         u64 usermem, ioffset, ilength;
179         int ret, i;
180
181         if (size < sizeof(*args))
182                 return -EINVAL;
183
184         ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
185                                           priv->user.bar.offset, 0x1000,
186                                           args->pushbuf,
187                                           (1ULL << NVDEV_ENGINE_SW) |
188                                           (1ULL << NVDEV_ENGINE_GR) |
189                                           (1ULL << NVDEV_ENGINE_COPY0) |
190                                           (1ULL << NVDEV_ENGINE_COPY1) |
191                                           (1ULL << NVDEV_ENGINE_BSP) |
192                                           (1ULL << NVDEV_ENGINE_VP) |
193                                           (1ULL << NVDEV_ENGINE_PPP), &chan);
194         *pobject = nv_object(chan);
195         if (ret)
196                 return ret;
197
198         nv_parent(chan)->context_attach = nvc0_fifo_context_attach;
199         nv_parent(chan)->context_detach = nvc0_fifo_context_detach;
200
201         usermem = chan->base.chid * 0x1000;
202         ioffset = args->ioffset;
203         ilength = order_base_2(args->ilength / 8);
204
205         for (i = 0; i < 0x1000; i += 4)
206                 nv_wo32(priv->user.mem, usermem + i, 0x00000000);
207
208         nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
209         nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
210         nv_wo32(base, 0x10, 0x0000face);
211         nv_wo32(base, 0x30, 0xfffff902);
212         nv_wo32(base, 0x48, lower_32_bits(ioffset));
213         nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
214         nv_wo32(base, 0x54, 0x00000002);
215         nv_wo32(base, 0x84, 0x20400000);
216         nv_wo32(base, 0x94, 0x30000001);
217         nv_wo32(base, 0x9c, 0x00000100);
218         nv_wo32(base, 0xa4, 0x1f1f1f1f);
219         nv_wo32(base, 0xa8, 0x1f1f1f1f);
220         nv_wo32(base, 0xac, 0x0000001f);
221         nv_wo32(base, 0xb8, 0xf8000000);
222         nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
223         nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
224         bar->flush(bar);
225         return 0;
226 }
227
228 static int
229 nvc0_fifo_chan_init(struct nouveau_object *object)
230 {
231         struct nouveau_gpuobj *base = nv_gpuobj(object->parent);
232         struct nvc0_fifo_priv *priv = (void *)object->engine;
233         struct nvc0_fifo_chan *chan = (void *)object;
234         u32 chid = chan->base.chid;
235         int ret;
236
237         ret = nouveau_fifo_channel_init(&chan->base);
238         if (ret)
239                 return ret;
240
241         nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12);
242         nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001);
243         nvc0_fifo_runlist_update(priv);
244         return 0;
245 }
246
247 static void nvc0_fifo_intr_engine(struct nvc0_fifo_priv *priv);
248
249 static int
250 nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
251 {
252         struct nvc0_fifo_priv *priv = (void *)object->engine;
253         struct nvc0_fifo_chan *chan = (void *)object;
254         u32 chid = chan->base.chid;
255
256         nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000);
257         nvc0_fifo_runlist_update(priv);
258
259         nvc0_fifo_intr_engine(priv);
260
261         nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000);
262
263         return nouveau_fifo_channel_fini(&chan->base, suspend);
264 }
265
266 static struct nouveau_ofuncs
267 nvc0_fifo_ofuncs = {
268         .ctor = nvc0_fifo_chan_ctor,
269         .dtor = _nouveau_fifo_channel_dtor,
270         .init = nvc0_fifo_chan_init,
271         .fini = nvc0_fifo_chan_fini,
272         .rd32 = _nouveau_fifo_channel_rd32,
273         .wr32 = _nouveau_fifo_channel_wr32,
274 };
275
276 static struct nouveau_oclass
277 nvc0_fifo_sclass[] = {
278         { NVC0_CHANNEL_IND_CLASS, &nvc0_fifo_ofuncs },
279         {}
280 };
281
282 /*******************************************************************************
283  * FIFO context - instmem heap and vm setup
284  ******************************************************************************/
285
286 static int
287 nvc0_fifo_context_ctor(struct nouveau_object *parent,
288                        struct nouveau_object *engine,
289                        struct nouveau_oclass *oclass, void *data, u32 size,
290                        struct nouveau_object **pobject)
291 {
292         struct nvc0_fifo_base *base;
293         int ret;
294
295         ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
296                                           0x1000, NVOBJ_FLAG_ZERO_ALLOC |
297                                           NVOBJ_FLAG_HEAP, &base);
298         *pobject = nv_object(base);
299         if (ret)
300                 return ret;
301
302         ret = nouveau_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0,
303                                 &base->pgd);
304         if (ret)
305                 return ret;
306
307         nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
308         nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
309         nv_wo32(base, 0x0208, 0xffffffff);
310         nv_wo32(base, 0x020c, 0x000000ff);
311
312         ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
313         if (ret)
314                 return ret;
315
316         return 0;
317 }
318
319 static void
320 nvc0_fifo_context_dtor(struct nouveau_object *object)
321 {
322         struct nvc0_fifo_base *base = (void *)object;
323         nouveau_vm_ref(NULL, &base->vm, base->pgd);
324         nouveau_gpuobj_ref(NULL, &base->pgd);
325         nouveau_fifo_context_destroy(&base->base);
326 }
327
328 static struct nouveau_oclass
329 nvc0_fifo_cclass = {
330         .handle = NV_ENGCTX(FIFO, 0xc0),
331         .ofuncs = &(struct nouveau_ofuncs) {
332                 .ctor = nvc0_fifo_context_ctor,
333                 .dtor = nvc0_fifo_context_dtor,
334                 .init = _nouveau_fifo_context_init,
335                 .fini = _nouveau_fifo_context_fini,
336                 .rd32 = _nouveau_fifo_context_rd32,
337                 .wr32 = _nouveau_fifo_context_wr32,
338         },
339 };
340
341 /*******************************************************************************
342  * PFIFO engine
343  ******************************************************************************/
344
345 static const struct nouveau_enum nvc0_fifo_fault_unit[] = {
346         { 0x00, "PGRAPH", NULL, NVDEV_ENGINE_GR },
347         { 0x03, "PEEPHOLE" },
348         { 0x04, "BAR1" },
349         { 0x05, "BAR3" },
350         { 0x07, "PFIFO", NULL, NVDEV_ENGINE_FIFO },
351         { 0x10, "PBSP", NULL, NVDEV_ENGINE_BSP },
352         { 0x11, "PPPP", NULL, NVDEV_ENGINE_PPP },
353         { 0x13, "PCOUNTER" },
354         { 0x14, "PVP", NULL, NVDEV_ENGINE_VP },
355         { 0x15, "PCOPY0", NULL, NVDEV_ENGINE_COPY0 },
356         { 0x16, "PCOPY1", NULL, NVDEV_ENGINE_COPY1 },
357         { 0x17, "PDAEMON" },
358         {}
359 };
360
361 static const struct nouveau_enum nvc0_fifo_fault_reason[] = {
362         { 0x00, "PT_NOT_PRESENT" },
363         { 0x01, "PT_TOO_SHORT" },
364         { 0x02, "PAGE_NOT_PRESENT" },
365         { 0x03, "VM_LIMIT_EXCEEDED" },
366         { 0x04, "NO_CHANNEL" },
367         { 0x05, "PAGE_SYSTEM_ONLY" },
368         { 0x06, "PAGE_READ_ONLY" },
369         { 0x0a, "COMPRESSED_SYSRAM" },
370         { 0x0c, "INVALID_STORAGE_TYPE" },
371         {}
372 };
373
374 static const struct nouveau_enum nvc0_fifo_fault_hubclient[] = {
375         { 0x01, "PCOPY0" },
376         { 0x02, "PCOPY1" },
377         { 0x04, "DISPATCH" },
378         { 0x05, "CTXCTL" },
379         { 0x06, "PFIFO" },
380         { 0x07, "BAR_READ" },
381         { 0x08, "BAR_WRITE" },
382         { 0x0b, "PVP" },
383         { 0x0c, "PPPP" },
384         { 0x0d, "PBSP" },
385         { 0x11, "PCOUNTER" },
386         { 0x12, "PDAEMON" },
387         { 0x14, "CCACHE" },
388         { 0x15, "CCACHE_POST" },
389         {}
390 };
391
392 static const struct nouveau_enum nvc0_fifo_fault_gpcclient[] = {
393         { 0x01, "TEX" },
394         { 0x0c, "ESETUP" },
395         { 0x0e, "CTXCTL" },
396         { 0x0f, "PROP" },
397         {}
398 };
399
400 static const struct nouveau_bitfield nvc0_fifo_pbdma_intr[] = {
401 /*      { 0x00008000, "" }      seen with null ib push */
402         { 0x00200000, "ILLEGAL_MTHD" },
403         { 0x00800000, "EMPTY_SUBC" },
404         {}
405 };
406
407 static void
408 nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit)
409 {
410         u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10));
411         u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10));
412         u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
413         u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
414         u32 client = (stat & 0x00001f00) >> 8;
415         const struct nouveau_enum *en;
416         struct nouveau_engine *engine;
417         struct nouveau_object *engctx = NULL;
418
419         switch (unit) {
420         case 3: /* PEEPHOLE */
421                 nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
422                 break;
423         case 4: /* BAR1 */
424                 nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
425                 break;
426         case 5: /* BAR3 */
427                 nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
428                 break;
429         default:
430                 break;
431         }
432
433         nv_error(priv, "%s fault at 0x%010llx [", (stat & 0x00000080) ?
434                  "write" : "read", (u64)vahi << 32 | valo);
435         nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f);
436         pr_cont("] from ");
437         en = nouveau_enum_print(nvc0_fifo_fault_unit, unit);
438         if (stat & 0x00000040) {
439                 pr_cont("/");
440                 nouveau_enum_print(nvc0_fifo_fault_hubclient, client);
441         } else {
442                 pr_cont("/GPC%d/", (stat & 0x1f000000) >> 24);
443                 nouveau_enum_print(nvc0_fifo_fault_gpcclient, client);
444         }
445
446         if (en && en->data2) {
447                 engine = nouveau_engine(priv, en->data2);
448                 if (engine)
449                         engctx = nouveau_engctx_get(engine, inst);
450
451         }
452         pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12,
453                         nouveau_client_name(engctx));
454
455         nouveau_engctx_put(engctx);
456 }
457
458 static int
459 nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
460 {
461         struct nvc0_fifo_chan *chan = NULL;
462         struct nouveau_handle *bind;
463         unsigned long flags;
464         int ret = -EINVAL;
465
466         spin_lock_irqsave(&priv->base.lock, flags);
467         if (likely(chid >= priv->base.min && chid <= priv->base.max))
468                 chan = (void *)priv->base.channel[chid];
469         if (unlikely(!chan))
470                 goto out;
471
472         bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
473         if (likely(bind)) {
474                 if (!mthd || !nv_call(bind->object, mthd, data))
475                         ret = 0;
476                 nouveau_namedb_put(bind);
477         }
478
479 out:
480         spin_unlock_irqrestore(&priv->base.lock, flags);
481         return ret;
482 }
483
484 static void
485 nvc0_fifo_isr_pbdma_intr(struct nvc0_fifo_priv *priv, int unit)
486 {
487         u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
488         u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
489         u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
490         u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0x7f;
491         u32 subc = (addr & 0x00070000) >> 16;
492         u32 mthd = (addr & 0x00003ffc);
493         u32 show = stat;
494
495         if (stat & 0x00800000) {
496                 if (!nvc0_fifo_swmthd(priv, chid, mthd, data))
497                         show &= ~0x00800000;
498         }
499
500         if (show) {
501                 nv_error(priv, "PBDMA%d:", unit);
502                 nouveau_bitfield_print(nvc0_fifo_pbdma_intr, show);
503                 pr_cont("\n");
504                 nv_error(priv,
505                          "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
506                          unit, chid,
507                          nouveau_client_name_for_fifo_chid(&priv->base, chid),
508                          subc, mthd, data);
509         }
510
511         nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
512         nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
513 }
514
515 static void
516 nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
517 {
518         u32 intr = nv_rd32(priv, 0x0025a8 + (engn * 0x04));
519         u32 inte = nv_rd32(priv, 0x002628);
520         u32 unkn;
521
522         for (unkn = 0; unkn < 8; unkn++) {
523                 u32 ints = (intr >> (unkn * 0x04)) & inte;
524                 if (ints & 0x1) {
525                         nouveau_event_trigger(priv->base.uevent, 0);
526                         ints &= ~1;
527                 }
528                 if (ints) {
529                         nv_error(priv, "ENGINE %d %d %01x", engn, unkn, ints);
530                         nv_mask(priv, 0x002628, ints, 0);
531                 }
532         }
533
534         nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
535 }
536
537 static void
538 nvc0_fifo_intr_engine(struct nvc0_fifo_priv *priv)
539 {
540         u32 mask = nv_rd32(priv, 0x0025a4);
541         while (mask) {
542                 u32 unit = __ffs(mask);
543                 nvc0_fifo_intr_engine_unit(priv, unit);
544                 mask &= ~(1 << unit);
545         }
546 }
547
548 static void
549 nvc0_fifo_intr(struct nouveau_subdev *subdev)
550 {
551         struct nvc0_fifo_priv *priv = (void *)subdev;
552         u32 mask = nv_rd32(priv, 0x002140);
553         u32 stat = nv_rd32(priv, 0x002100) & mask;
554
555         if (stat & 0x00000001) {
556                 u32 intr = nv_rd32(priv, 0x00252c);
557                 nv_warn(priv, "INTR 0x00000001: 0x%08x\n", intr);
558                 nv_wr32(priv, 0x002100, 0x00000001);
559                 stat &= ~0x00000001;
560         }
561
562         if (stat & 0x00000100) {
563                 u32 intr = nv_rd32(priv, 0x00254c);
564                 nv_warn(priv, "INTR 0x00000100: 0x%08x\n", intr);
565                 nv_wr32(priv, 0x002100, 0x00000100);
566                 stat &= ~0x00000100;
567         }
568
569         if (stat & 0x00010000) {
570                 u32 intr = nv_rd32(priv, 0x00256c);
571                 nv_warn(priv, "INTR 0x00010000: 0x%08x\n", intr);
572                 nv_wr32(priv, 0x002100, 0x00010000);
573                 stat &= ~0x00010000;
574         }
575
576         if (stat & 0x01000000) {
577                 u32 intr = nv_rd32(priv, 0x00258c);
578                 nv_warn(priv, "INTR 0x01000000: 0x%08x\n", intr);
579                 nv_wr32(priv, 0x002100, 0x01000000);
580                 stat &= ~0x01000000;
581         }
582
583         if (stat & 0x10000000) {
584                 u32 units = nv_rd32(priv, 0x00259c);
585                 u32 u = units;
586
587                 while (u) {
588                         int i = ffs(u) - 1;
589                         nvc0_fifo_isr_vm_fault(priv, i);
590                         u &= ~(1 << i);
591                 }
592
593                 nv_wr32(priv, 0x00259c, units);
594                 stat &= ~0x10000000;
595         }
596
597         if (stat & 0x20000000) {
598                 u32 units = nv_rd32(priv, 0x0025a0);
599                 u32 u = units;
600
601                 while (u) {
602                         int i = __ffs(u);
603                         nvc0_fifo_isr_pbdma_intr(priv, i);
604                         u &= ~(1 << i);
605                 }
606
607                 nv_wr32(priv, 0x0025a0, units);
608                 stat &= ~0x20000000;
609         }
610
611         if (stat & 0x40000000) {
612                 u32 intr0 = nv_rd32(priv, 0x0025a4);
613                 u32 intr1 = nv_mask(priv, 0x002a00, 0x00000000, 0x00000);
614                 nv_debug(priv, "INTR 0x40000000: 0x%08x 0x%08x\n",
615                                intr0, intr1);
616                 stat &= ~0x40000000;
617         }
618
619         if (stat & 0x80000000) {
620                 nvc0_fifo_intr_engine(priv);
621                 stat &= ~0x80000000;
622         }
623
624         if (stat) {
625                 nv_error(priv, "INTR 0x%08x\n", stat);
626                 nv_mask(priv, 0x002140, stat, 0x00000000);
627                 nv_wr32(priv, 0x002100, stat);
628         }
629 }
630
631 static void
632 nvc0_fifo_uevent_enable(struct nouveau_event *event, int index)
633 {
634         struct nvc0_fifo_priv *priv = event->priv;
635         nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
636 }
637
638 static void
639 nvc0_fifo_uevent_disable(struct nouveau_event *event, int index)
640 {
641         struct nvc0_fifo_priv *priv = event->priv;
642         nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
643 }
644
645 static int
646 nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
647                struct nouveau_oclass *oclass, void *data, u32 size,
648                struct nouveau_object **pobject)
649 {
650         struct nvc0_fifo_priv *priv;
651         int ret;
652
653         ret = nouveau_fifo_create(parent, engine, oclass, 0, 127, &priv);
654         *pobject = nv_object(priv);
655         if (ret)
656                 return ret;
657
658         ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
659                                 &priv->runlist[0]);
660         if (ret)
661                 return ret;
662
663         ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
664                                 &priv->runlist[1]);
665         if (ret)
666                 return ret;
667
668         ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 0x1000, 0x1000, 0,
669                                 &priv->user.mem);
670         if (ret)
671                 return ret;
672
673         ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
674                                 &priv->user.bar);
675         if (ret)
676                 return ret;
677
678         priv->base.uevent->enable = nvc0_fifo_uevent_enable;
679         priv->base.uevent->disable = nvc0_fifo_uevent_disable;
680         priv->base.uevent->priv = priv;
681
682         nv_subdev(priv)->unit = 0x00000100;
683         nv_subdev(priv)->intr = nvc0_fifo_intr;
684         nv_engine(priv)->cclass = &nvc0_fifo_cclass;
685         nv_engine(priv)->sclass = nvc0_fifo_sclass;
686         return 0;
687 }
688
689 static void
690 nvc0_fifo_dtor(struct nouveau_object *object)
691 {
692         struct nvc0_fifo_priv *priv = (void *)object;
693
694         nouveau_gpuobj_unmap(&priv->user.bar);
695         nouveau_gpuobj_ref(NULL, &priv->user.mem);
696         nouveau_gpuobj_ref(NULL, &priv->runlist[1]);
697         nouveau_gpuobj_ref(NULL, &priv->runlist[0]);
698
699         nouveau_fifo_destroy(&priv->base);
700 }
701
702 static int
703 nvc0_fifo_init(struct nouveau_object *object)
704 {
705         struct nvc0_fifo_priv *priv = (void *)object;
706         int ret, i;
707
708         ret = nouveau_fifo_init(&priv->base);
709         if (ret)
710                 return ret;
711
712         nv_wr32(priv, 0x000204, 0xffffffff);
713         nv_wr32(priv, 0x002204, 0xffffffff);
714
715         priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204));
716         nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr);
717
718         /* assign engines to PBDMAs */
719         if (priv->spoon_nr >= 3) {
720                 nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */
721                 nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */
722                 nv_wr32(priv, 0x002210, ~(1 << 1)); /* PPP */
723                 nv_wr32(priv, 0x002214, ~(1 << 1)); /* PBSP */
724                 nv_wr32(priv, 0x002218, ~(1 << 2)); /* PCE0 */
725                 nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */
726         }
727
728         /* PBDMA[n] */
729         for (i = 0; i < priv->spoon_nr; i++) {
730                 nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
731                 nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
732                 nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
733         }
734
735         nv_mask(priv, 0x002200, 0x00000001, 0x00000001);
736         nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
737
738         nv_wr32(priv, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
739         nv_wr32(priv, 0x002100, 0xffffffff);
740         nv_wr32(priv, 0x002140, 0x3fffffff);
741         nv_wr32(priv, 0x002628, 0x00000001); /* ENGINE_INTR_EN */
742         return 0;
743 }
744
745 struct nouveau_oclass *
746 nvc0_fifo_oclass = &(struct nouveau_oclass) {
747         .handle = NV_ENGINE(FIFO, 0xc0),
748         .ofuncs = &(struct nouveau_ofuncs) {
749                 .ctor = nvc0_fifo_ctor,
750                 .dtor = nvc0_fifo_dtor,
751                 .init = nvc0_fifo_init,
752                 .fini = _nouveau_fifo_fini,
753         },
754 };