Set memory attributes on page
[pscnv.git] / pscnv / nvc0_fifo.c
blob5ccf8be1a6a134d802f702e70979db2818fcb6ae
1 /*
2 * Copyright (C) 2010 Christoph Bumiller.
3 * All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include "drm.h"
28 #include "nouveau_drv.h"
29 #include "nouveau_reg.h"
30 #include "pscnv_fifo.h"
31 #include "pscnv_chan.h"
33 struct nvc0_fifo_engine {
34 struct pscnv_fifo_engine base;
35 struct pscnv_bo *playlist[2];
36 int cur_playlist;
37 struct pscnv_bo *ctrl_bo;
38 struct drm_local_map *fifo_ctl;
41 #define nvc0_fifo(x) container_of(x, struct nvc0_fifo_engine, base)
43 static void nvc0_fifo_takedown(struct drm_device *dev);
44 static void nvc0_fifo_irq_handler(struct drm_device *dev, int irq);
45 static int nvc0_fifo_chan_init_ib (struct pscnv_chan *ch, uint32_t pb_handle, uint32_t flags, uint32_t slimask, uint64_t ib_start, uint32_t ib_order);
46 static void nvc0_fifo_chan_kill(struct pscnv_chan *ch);
48 int nvc0_fifo_init(struct drm_device *dev)
50 struct drm_nouveau_private *dev_priv = dev->dev_private;
51 struct nvc0_fifo_engine *res = kzalloc(sizeof *res, GFP_KERNEL);
52 int subfifo_count;
53 int i, ret;
55 if (!res) {
56 NV_ERROR(dev, "PFIFO: Couldn't allocate engine!\n");
57 return -ENOMEM;
60 res->base.takedown = nvc0_fifo_takedown;
61 res->base.chan_kill = nvc0_fifo_chan_kill;
62 res->base.chan_init_ib = nvc0_fifo_chan_init_ib;
64 res->ctrl_bo = pscnv_mem_alloc(dev, 128 * 0x1000,
65 PSCNV_GEM_CONTIG, 0, 0xf1f03e95);
67 if (!res->ctrl_bo) {
68 NV_ERROR(dev, "PFIFO: Couldn't allocate control area!\n");
69 kfree(res);
70 return -ENOMEM;
73 res->playlist[0] = pscnv_mem_alloc(dev, 0x1000, PSCNV_GEM_CONTIG, 0, 0x91a71157);
74 res->playlist[1] = pscnv_mem_alloc(dev, 0x1000, PSCNV_GEM_CONTIG, 0, 0x91a71157);
75 if (!res->playlist[0] || !res->playlist[1]) {
76 NV_ERROR(dev, "PFIFO: Couldn't allocate playlists!\n");
77 if (res->playlist[0])
78 pscnv_mem_free(res->playlist[0]);
79 if (res->playlist[1])
80 pscnv_mem_free(res->playlist[1]);
81 pscnv_mem_free(res->ctrl_bo);
82 kfree(res);
83 return -ENOMEM;
85 dev_priv->vm->map_kernel(res->playlist[0]);
86 dev_priv->vm->map_kernel(res->playlist[1]);
87 res->cur_playlist = 0;
89 dev_priv->vm->map_user(res->ctrl_bo);
91 if (!res->ctrl_bo->map1) {
92 NV_ERROR(dev, "PFIFO: Couldn't map control area!\n");
93 pscnv_mem_free(res->playlist[0]);
94 pscnv_mem_free(res->playlist[1]);
95 pscnv_mem_free(res->ctrl_bo);
96 kfree(res);
97 return -ENOMEM;
99 ret = drm_addmap(dev, drm_get_resource_start(dev, 1) +
100 res->ctrl_bo->map1->start, 128 << 12,
101 _DRM_REGISTERS, _DRM_KERNEL | _DRM_DRIVER, &res->fifo_ctl);
102 if (ret) {
103 NV_ERROR(dev, "PFIFO: Couldn't ioremap control area!\n");
104 pscnv_mem_free(res->playlist[0]);
105 pscnv_mem_free(res->playlist[1]);
106 pscnv_mem_free(res->ctrl_bo);
107 kfree(res);
108 return ret;
111 /* reset PFIFO, enable all available PSUBFIFO areas */
112 nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
113 nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
114 nv_wr32(dev, 0x000204, 0xffffffff);
115 nv_wr32(dev, 0x002204, 0xffffffff);
117 subfifo_count = hweight32(nv_rd32(dev, 0x002204));
119 /* assign engines to subfifos */
120 if (subfifo_count >= 3) {
121 nv_wr32(dev, 0x002208, ~(1 << 0)); /* PGRAPH */
122 nv_wr32(dev, 0x00220c, ~(1 << 1)); /* PVP */
123 nv_wr32(dev, 0x002210, ~(1 << 1)); /* PPP */
124 nv_wr32(dev, 0x002214, ~(1 << 1)); /* PBSP */
125 nv_wr32(dev, 0x002218, ~(1 << 2)); /* PCE0 (PCOPY0) */
126 nv_wr32(dev, 0x00221c, ~(1 << 1)); /* PCE1 (PCOPY1) */
129 /* PSUBFIFO[n] */
130 for (i = 0; i < subfifo_count; i++) {
131 nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
132 nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
133 nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */
136 #if 0
137 nv_wr32(dev, 0x204, 0);
138 nv_wr32(dev, 0x204, 7); /* PMC.SUBFIFO_ENABLE */
139 nv_wr32(dev, 0x2204, 7); /* PFIFO.SUBFIFO_ENABLE */
140 #endif
142 /* PFIFO.ENABLE */
143 nv_mask(dev, 0x002200, 0x00000001, 0x00000001);
145 /* PFIFO.POLL_AREA */
146 nv_wr32(dev, 0x2254, (1 << 28) | (res->ctrl_bo->map1->start >> 12));
148 dev_priv->fifo = &res->base;
150 nouveau_irq_register(dev, 8, nvc0_fifo_irq_handler);
152 nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
153 nv_wr32(dev, 0x002100, 0xffffffff);
154 nv_wr32(dev, 0x2140, 0xbfffffff); /* PFIFO_INTR_EN */
156 return 0;
159 static void nvc0_fifo_takedown(struct drm_device *dev)
161 struct drm_nouveau_private *dev_priv = dev->dev_private;
162 struct nvc0_fifo_engine *fifo = nvc0_fifo(dev_priv->fifo);
163 nv_wr32(dev, 0x2140, 0);
164 nouveau_irq_unregister(dev, 8);
165 /* XXX */
166 pscnv_mem_free(fifo->playlist[0]);
167 pscnv_mem_free(fifo->playlist[1]);
168 drm_rmmap(dev, fifo->fifo_ctl);
169 pscnv_mem_free(fifo->ctrl_bo);
170 kfree(fifo);
171 dev_priv->fifo = 0;
174 static void nvc0_fifo_playlist_update(struct drm_device *dev)
176 struct drm_nouveau_private *dev_priv = dev->dev_private;
177 struct nvc0_fifo_engine *fifo = nvc0_fifo(dev_priv->fifo);
178 int i, pos;
179 struct pscnv_bo *vo;
180 fifo->cur_playlist ^= 1;
181 vo = fifo->playlist[fifo->cur_playlist];
182 for (i = 0, pos = 0; i < 128; i++) {
183 if (nv_rd32(dev, 0x3004 + i * 8) & 1) {
184 nv_wv32(vo, pos, i);
185 nv_wv32(vo, pos + 4, 0x4);
186 pos += 8;
189 dev_priv->vm->bar_flush(dev);
191 nv_wr32(dev, 0x2270, vo->start >> 12);
192 nv_wr32(dev, 0x2274, 0x1f00000 | pos / 8);
194 if (!nv_wait(dev, 0x227c, (1 << 20), 0))
195 NV_WARN(dev, "WARNING: PFIFO 227c = 0x%08x\n",
196 nv_rd32(dev, 0x227c));
199 static void nvc0_fifo_chan_kill(struct pscnv_chan *ch)
201 struct drm_device *dev = ch->dev;
202 struct drm_nouveau_private *dev_priv = dev->dev_private;
203 /* bit 28: active,
204 * bit 12: loaded,
205 * bit 0: enabled
207 uint32_t status;
208 unsigned long flags;
210 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
211 status = nv_rd32(dev, 0x3004 + ch->cid * 8);
212 nv_wr32(dev, 0x3004 + ch->cid * 8, status & ~1);
213 nv_wr32(dev, 0x2634, ch->cid);
214 if (!nv_wait(dev, 0x2634, ~0, ch->cid))
215 NV_WARN(dev, "WARNING: 2634 = 0x%08x\n", nv_rd32(dev, 0x2634));
217 nvc0_fifo_playlist_update(dev);
219 if (nv_rd32(dev, 0x3004 + ch->cid * 8) & 0x1110) {
220 NV_WARN(dev, "WARNING: PFIFO kickoff fail :(\n");
222 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
225 #define nvchan_wr32(chan, ofst, val) \
226 DRM_WRITE32(fifo->fifo_ctl, ((chan)->cid * 0x1000 + ofst), val)
228 static int nvc0_fifo_chan_init_ib (struct pscnv_chan *ch, uint32_t pb_handle, uint32_t flags, uint32_t slimask, uint64_t ib_start, uint32_t ib_order) {
229 struct drm_device *dev = ch->dev;
230 struct drm_nouveau_private *dev_priv = dev->dev_private;
231 struct nvc0_fifo_engine *fifo = nvc0_fifo(dev_priv->fifo);
232 unsigned long irqflags;
234 int i;
235 uint64_t fifo_regs = fifo->ctrl_bo->start + (ch->cid << 12);
237 if (ib_order > 29)
238 return -EINVAL;
240 spin_lock_irqsave(&dev_priv->context_switch_lock, irqflags);
242 for (i = 0x40; i <= 0x50; i += 4)
243 nvchan_wr32(ch, i, 0);
244 for (i = 0x58; i <= 0x60; i += 4)
245 nvchan_wr32(ch, i, 0);
246 nvchan_wr32(ch, 0x88, 0);
247 nvchan_wr32(ch, 0x8c, 0);
249 for (i = 0; i < 0x100; i += 4)
250 nv_wv32(ch->bo, i, 0);
252 dev_priv->vm->bar_flush(dev);
254 nv_wv32(ch->bo, 0x08, fifo_regs);
255 nv_wv32(ch->bo, 0x0c, fifo_regs >> 32);
257 nv_wv32(ch->bo, 0x48, ib_start); /* IB */
258 nv_wv32(ch->bo, 0x4c,
259 (ib_start >> 32) | (ib_order << 16));
260 nv_wv32(ch->bo, 0x10, 0xface);
261 nv_wv32(ch->bo, 0x54, 0x2);
262 nv_wv32(ch->bo, 0x9c, 0x100);
263 nv_wv32(ch->bo, 0x84, 0x20400000);
264 nv_wv32(ch->bo, 0x94, 0x30000000 ^ slimask);
265 nv_wv32(ch->bo, 0xa4, 0x1f1f1f1f);
266 nv_wv32(ch->bo, 0xa8, 0x1f1f1f1f);
267 nv_wv32(ch->bo, 0xac, 0x1f);
268 nv_wv32(ch->bo, 0x30, 0xfffff902);
269 /* nv_wv32(chan->vo, 0xb8, 0xf8000000); */ /* previously omitted */
270 nv_wv32(ch->bo, 0xf8, 0x10003080);
271 nv_wv32(ch->bo, 0xfc, 0x10000010);
272 dev_priv->vm->bar_flush(dev);
274 nv_wr32(dev, 0x3000 + ch->cid * 8, 0xc0000000 | ch->bo->start >> 12);
275 nv_wr32(dev, 0x3004 + ch->cid * 8, 0x1f0001);
277 nvc0_fifo_playlist_update(dev);
279 spin_unlock_irqrestore(&dev_priv->context_switch_lock, irqflags);
281 dev_priv->engines[PSCNV_ENGINE_GRAPH]->
282 chan_alloc(dev_priv->engines[PSCNV_ENGINE_GRAPH], ch);
283 if (dev_priv->engines[PSCNV_ENGINE_COPY0])
284 dev_priv->engines[PSCNV_ENGINE_COPY0]->
285 chan_alloc(dev_priv->engines[PSCNV_ENGINE_COPY0], ch);
286 if (dev_priv->engines[PSCNV_ENGINE_COPY1])
287 dev_priv->engines[PSCNV_ENGINE_COPY1]->
288 chan_alloc(dev_priv->engines[PSCNV_ENGINE_COPY1], ch);
290 return 0;
293 static const char *pgf_unit_str(int unit)
295 switch (unit) {
296 case 0: return "PGRAPH";
297 case 3: return "PEEPHOLE";
298 case 4: return "FB BAR";
299 case 5: return "RAMIN BAR";
300 case 7: return "PUSHBUF";
301 default:
302 break;
304 return "(unknown unit)";
307 static const char *pgf_cause_str(uint32_t flags)
309 switch (flags & 0xf) {
310 case 0x0: return "PDE not present";
311 case 0x1: return "PT too short";
312 case 0x2: return "PTE not present";
313 case 0x3: return "LIMIT exceeded";
314 case 0x5: return "NOUSER";
315 case 0x6: return "PTE set read-only";
316 default:
317 break;
319 return "unknown cause";
322 static void nvc0_pfifo_page_fault(struct drm_device *dev, int unit)
324 uint64_t virt;
325 uint32_t chan, flags;
327 chan = nv_rd32(dev, 0x2800 + unit * 0x10) << 12;
328 virt = nv_rd32(dev, 0x2808 + unit * 0x10);
329 virt = (virt << 32) | nv_rd32(dev, 0x2804 + unit * 0x10);
330 flags = nv_rd32(dev, 0x280c + unit * 0x10);
332 NV_INFO(dev, "%s PAGE FAULT at 0x%010llx (%c, %s)\n",
333 pgf_unit_str(unit), virt,
334 (flags & 0x80) ? 'w' : 'r', pgf_cause_str(flags));
337 static void nvc0_pfifo_subfifo_fault(struct drm_device *dev, int unit)
339 int cid = nv_rd32(dev, 0x40120 + unit * 0x2000) & 0x7f;
340 int status = nv_rd32(dev, 0x40108 + unit * 0x2000);
341 uint32_t addr = nv_rd32(dev, 0x400c0 + unit * 0x2000);
342 uint32_t data = nv_rd32(dev, 0x400c4 + unit * 0x2000);
343 int sub = addr >> 16 & 7;
344 int mthd = addr & 0x3ffc;
345 int mode = addr >> 21 & 7;
347 if (status & 0x200000) {
348 NV_INFO(dev, "PSUBFIFO %d ILLEGAL_MTHD: ch %d sub %d mthd %04x%s [mode %d] data %08x\n", unit, cid, sub, mthd, ((addr & 1)?" NI":""), mode, data);
349 nv_wr32(dev, 0x400c0 + unit * 0x2000, 0x80600008);
350 nv_wr32(dev, 0x40108 + unit * 0x2000, 0x200000);
351 status &= ~0x200000;
353 if (status & 0x800000) {
354 NV_INFO(dev, "PSUBFIFO %d EMPTY_SUBCHANNEL: ch %d sub %d mthd %04x%s [mode %d] data %08x\n", unit, cid, sub, mthd, ((addr & 1)?" NI":""), mode, data);
355 nv_wr32(dev, 0x400c0 + unit * 0x2000, 0x80600008);
356 nv_wr32(dev, 0x40108 + unit * 0x2000, 0x800000);
357 status &= ~0x800000;
359 if (status) {
360 NV_INFO(dev, "unknown PSUBFIFO INTR: 0x%08x\n", status);
361 nv_wr32(dev, 0x4010c + unit * 0x2000, nv_rd32(dev, 0x4010c + unit * 0x2000) & ~status);
365 static void nvc0_fifo_irq_handler(struct drm_device *dev, int irq)
367 uint32_t status;
369 status = nv_rd32(dev, 0x2100) & nv_rd32(dev, 0x2140);
371 if (status & 1) {
372 NV_INFO(dev, "PFIFO INTR 1!\n");
373 nv_wr32(dev, 0x2100, 1);
374 status &= ~1;
377 if (status & 0x10000000) {
378 uint32_t bits = nv_rd32(dev, 0x259c);
379 uint32_t units = bits;
381 while (units) {
382 int i = ffs(units) - 1;
383 units &= ~(1 << i);
384 nvc0_pfifo_page_fault(dev, i);
386 nv_wr32(dev, 0x259c, bits); /* ack */
387 status &= ~0x10000000;
390 if (status & 0x20000000) {
391 uint32_t bits = nv_rd32(dev, 0x25a0);
392 uint32_t units = bits;
393 while (units) {
394 int i = ffs(units) - 1;
395 units &= ~(1 << i);
396 nvc0_pfifo_subfifo_fault(dev, i);
398 nv_wr32(dev, 0x25a0, bits); /* ack */
399 status &= ~0x20000000;
402 if (status & 0x00000100) {
403 uint32_t ibpk[2];
404 uint32_t data = nv_rd32(dev, 0x400c4);
406 ibpk[0] = nv_rd32(dev, 0x40110);
407 ibpk[1] = nv_rd32(dev, 0x40114);
409 NV_INFO(dev, "PFIFO FUCKUP: DATA = 0x%08x\n"
410 "IB PACKET = 0x%08x 0x%08x\n", data, ibpk[0], ibpk[1]);
411 // status &= ~0x100;
414 if (status) {
415 NV_INFO(dev, "unknown PFIFO INTR: 0x%08x\n", status);
416 /* disable interrupts */
417 nv_wr32(dev, 0x2140, nv_rd32(dev, 0x2140) & ~status);
421 uint64_t nvc0_fifo_ctrl_offs(struct drm_device *dev, int cid)
423 struct drm_nouveau_private *dev_priv = dev->dev_private;
424 struct nvc0_fifo_engine *fifo = nvc0_fifo(dev_priv->fifo);
425 return fifo->ctrl_bo->map1->start + cid * 0x1000;
428 #if 0
429 static volatile uint32_t *nvc0_fifo_ctrl_ptr(struct drm_device *dev, struct pscnv_chan *chan)
431 struct drm_nouveau_private *dev_priv = dev->dev_private;
432 struct nvc0_fifo_engine *fifo = nvc0_fifo(dev_priv->fifo);
433 return &fifo->fifo_ctl[chan->cid * 0x1000 / 4];
435 #endif