]>
Commit | Line | Data |
---|---|---|
4b223eef BS |
1 | /* |
2 | * Copyright 2010 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 | ||
760285e7 | 25 | #include <drm/drmP.h> |
4b223eef BS |
26 | |
27 | #include "nouveau_drv.h" | |
b2b09938 | 28 | #include "nouveau_mm.h" |
c420b2dc | 29 | #include "nouveau_fifo.h" |
b2b09938 BS |
30 | |
31 | static void nvc0_fifo_isr(struct drm_device *); | |
32 | ||
33 | struct nvc0_fifo_priv { | |
c420b2dc | 34 | struct nouveau_fifo_priv base; |
b2b09938 BS |
35 | struct nouveau_gpuobj *playlist[2]; |
36 | int cur_playlist; | |
37 | struct nouveau_vma user_vma; | |
ec9c0883 | 38 | int spoon_nr; |
b2b09938 BS |
39 | }; |
40 | ||
41 | struct nvc0_fifo_chan { | |
c420b2dc | 42 | struct nouveau_fifo_chan base; |
1233bd8d | 43 | struct nouveau_gpuobj *user; |
b2b09938 BS |
44 | }; |
45 | ||
46 | static void | |
47 | nvc0_fifo_playlist_update(struct drm_device *dev) | |
48 | { | |
49 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
50 | struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; | |
c420b2dc | 51 | struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO); |
b2b09938 BS |
52 | struct nouveau_gpuobj *cur; |
53 | int i, p; | |
54 | ||
55 | cur = priv->playlist[priv->cur_playlist]; | |
56 | priv->cur_playlist = !priv->cur_playlist; | |
57 | ||
58 | for (i = 0, p = 0; i < 128; i++) { | |
59 | if (!(nv_rd32(dev, 0x3004 + (i * 8)) & 1)) | |
60 | continue; | |
61 | nv_wo32(cur, p + 0, i); | |
62 | nv_wo32(cur, p + 4, 0x00000004); | |
63 | p += 8; | |
64 | } | |
65 | pinstmem->flush(dev); | |
66 | ||
67 | nv_wr32(dev, 0x002270, cur->vinst >> 12); | |
68 | nv_wr32(dev, 0x002274, 0x01f00000 | (p >> 3)); | |
69 | if (!nv_wait(dev, 0x00227c, 0x00100000, 0x00000000)) | |
70 | NV_ERROR(dev, "PFIFO - playlist update failed\n"); | |
71 | } | |
4b223eef | 72 | |
c420b2dc BS |
73 | static int |
74 | nvc0_fifo_context_new(struct nouveau_channel *chan, int engine) | |
4b223eef | 75 | { |
b2b09938 BS |
76 | struct drm_device *dev = chan->dev; |
77 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
78 | struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; | |
c420b2dc BS |
79 | struct nvc0_fifo_priv *priv = nv_engine(dev, engine); |
80 | struct nvc0_fifo_chan *fctx; | |
1233bd8d | 81 | u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4; |
c420b2dc | 82 | int ret, i; |
b2b09938 | 83 | |
c420b2dc BS |
84 | fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL); |
85 | if (!fctx) | |
b2b09938 | 86 | return -ENOMEM; |
b2b09938 BS |
87 | |
88 | chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) + | |
89 | priv->user_vma.offset + (chan->id * 0x1000), | |
90 | PAGE_SIZE); | |
91 | if (!chan->user) { | |
92 | ret = -ENOMEM; | |
93 | goto error; | |
94 | } | |
95 | ||
c420b2dc BS |
96 | /* allocate vram for control regs, map into polling area */ |
97 | ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, | |
98 | NVOBJ_FLAG_ZERO_ALLOC, &fctx->user); | |
b2b09938 BS |
99 | if (ret) |
100 | goto error; | |
101 | ||
c420b2dc BS |
102 | nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000, |
103 | *(struct nouveau_mem **)fctx->user->node); | |
104 | ||
105 | for (i = 0; i < 0x100; i += 4) | |
106 | nv_wo32(chan->ramin, i, 0x00000000); | |
107 | nv_wo32(chan->ramin, 0x08, lower_32_bits(fctx->user->vinst)); | |
108 | nv_wo32(chan->ramin, 0x0c, upper_32_bits(fctx->user->vinst)); | |
109 | nv_wo32(chan->ramin, 0x10, 0x0000face); | |
110 | nv_wo32(chan->ramin, 0x30, 0xfffff902); | |
111 | nv_wo32(chan->ramin, 0x48, lower_32_bits(ib_virt)); | |
112 | nv_wo32(chan->ramin, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 | | |
b2b09938 | 113 | upper_32_bits(ib_virt)); |
c420b2dc BS |
114 | nv_wo32(chan->ramin, 0x54, 0x00000002); |
115 | nv_wo32(chan->ramin, 0x84, 0x20400000); | |
116 | nv_wo32(chan->ramin, 0x94, 0x30000001); | |
117 | nv_wo32(chan->ramin, 0x9c, 0x00000100); | |
118 | nv_wo32(chan->ramin, 0xa4, 0x1f1f1f1f); | |
119 | nv_wo32(chan->ramin, 0xa8, 0x1f1f1f1f); | |
120 | nv_wo32(chan->ramin, 0xac, 0x0000001f); | |
121 | nv_wo32(chan->ramin, 0xb8, 0xf8000000); | |
122 | nv_wo32(chan->ramin, 0xf8, 0x10003080); /* 0x002310 */ | |
123 | nv_wo32(chan->ramin, 0xfc, 0x10000010); /* 0x002350 */ | |
b2b09938 BS |
124 | pinstmem->flush(dev); |
125 | ||
126 | nv_wr32(dev, 0x003000 + (chan->id * 8), 0xc0000000 | | |
127 | (chan->ramin->vinst >> 12)); | |
128 | nv_wr32(dev, 0x003004 + (chan->id * 8), 0x001f0001); | |
129 | nvc0_fifo_playlist_update(dev); | |
b2b09938 BS |
130 | |
131 | error: | |
c420b2dc BS |
132 | if (ret) |
133 | priv->base.base.context_del(chan, engine); | |
b2b09938 | 134 | return ret; |
4b223eef BS |
135 | } |
136 | ||
c420b2dc BS |
137 | static void |
138 | nvc0_fifo_context_del(struct nouveau_channel *chan, int engine) | |
4b223eef | 139 | { |
c420b2dc | 140 | struct nvc0_fifo_chan *fctx = chan->engctx[engine]; |
b2b09938 | 141 | struct drm_device *dev = chan->dev; |
b2b09938 BS |
142 | |
143 | nv_mask(dev, 0x003004 + (chan->id * 8), 0x00000001, 0x00000000); | |
144 | nv_wr32(dev, 0x002634, chan->id); | |
145 | if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id)) | |
146 | NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634)); | |
b2b09938 | 147 | nvc0_fifo_playlist_update(dev); |
b2b09938 BS |
148 | nv_wr32(dev, 0x003000 + (chan->id * 8), 0x00000000); |
149 | ||
c420b2dc | 150 | nouveau_gpuobj_ref(NULL, &fctx->user); |
b2b09938 BS |
151 | if (chan->user) { |
152 | iounmap(chan->user); | |
153 | chan->user = NULL; | |
154 | } | |
155 | ||
c420b2dc BS |
156 | chan->engctx[engine] = NULL; |
157 | kfree(fctx); | |
b2b09938 BS |
158 | } |
159 | ||
160 | static int | |
c420b2dc | 161 | nvc0_fifo_init(struct drm_device *dev, int engine) |
4b223eef | 162 | { |
b2b09938 | 163 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
c420b2dc | 164 | struct nvc0_fifo_priv *priv = nv_engine(dev, engine); |
0638df42 | 165 | struct nouveau_channel *chan; |
c420b2dc | 166 | int i; |
b2b09938 BS |
167 | |
168 | /* reset PFIFO, enable all available PSUBFIFO areas */ | |
169 | nv_mask(dev, 0x000200, 0x00000100, 0x00000000); | |
170 | nv_mask(dev, 0x000200, 0x00000100, 0x00000100); | |
171 | nv_wr32(dev, 0x000204, 0xffffffff); | |
172 | nv_wr32(dev, 0x002204, 0xffffffff); | |
173 | ||
ec9c0883 BS |
174 | priv->spoon_nr = hweight32(nv_rd32(dev, 0x002204)); |
175 | NV_DEBUG(dev, "PFIFO: %d subfifo(s)\n", priv->spoon_nr); | |
176 | ||
b2b09938 | 177 | /* assign engines to subfifos */ |
ec9c0883 BS |
178 | if (priv->spoon_nr >= 3) { |
179 | nv_wr32(dev, 0x002208, ~(1 << 0)); /* PGRAPH */ | |
180 | nv_wr32(dev, 0x00220c, ~(1 << 1)); /* PVP */ | |
181 | nv_wr32(dev, 0x002210, ~(1 << 1)); /* PPP */ | |
182 | nv_wr32(dev, 0x002214, ~(1 << 1)); /* PBSP */ | |
183 | nv_wr32(dev, 0x002218, ~(1 << 2)); /* PCE0 */ | |
184 | nv_wr32(dev, 0x00221c, ~(1 << 1)); /* PCE1 */ | |
185 | } | |
b2b09938 BS |
186 | |
187 | /* PSUBFIFO[n] */ | |
3dcbb02b | 188 | for (i = 0; i < priv->spoon_nr; i++) { |
b2b09938 BS |
189 | nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); |
190 | nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ | |
191 | nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */ | |
192 | } | |
193 | ||
194 | nv_mask(dev, 0x002200, 0x00000001, 0x00000001); | |
195 | nv_wr32(dev, 0x002254, 0x10000000 | priv->user_vma.offset >> 12); | |
196 | ||
197 | nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */ | |
198 | nv_wr32(dev, 0x002100, 0xffffffff); | |
199 | nv_wr32(dev, 0x002140, 0xbfffffff); | |
0638df42 BS |
200 | |
201 | /* restore PFIFO context table */ | |
202 | for (i = 0; i < 128; i++) { | |
203 | chan = dev_priv->channels.ptr[i]; | |
c420b2dc | 204 | if (!chan || !chan->engctx[engine]) |
0638df42 BS |
205 | continue; |
206 | ||
207 | nv_wr32(dev, 0x003000 + (i * 8), 0xc0000000 | | |
208 | (chan->ramin->vinst >> 12)); | |
209 | nv_wr32(dev, 0x003004 + (i * 8), 0x001f0001); | |
210 | } | |
211 | nvc0_fifo_playlist_update(dev); | |
212 | ||
4b223eef BS |
213 | return 0; |
214 | } | |
215 | ||
c420b2dc BS |
216 | static int |
217 | nvc0_fifo_fini(struct drm_device *dev, int engine, bool suspend) | |
218 | { | |
219 | int i; | |
220 | ||
221 | for (i = 0; i < 128; i++) { | |
222 | if (!(nv_rd32(dev, 0x003004 + (i * 8)) & 1)) | |
223 | continue; | |
224 | ||
225 | nv_mask(dev, 0x003004 + (i * 8), 0x00000001, 0x00000000); | |
226 | nv_wr32(dev, 0x002634, i); | |
227 | if (!nv_wait(dev, 0x002634, 0xffffffff, i)) { | |
228 | NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n", | |
229 | i, nv_rd32(dev, 0x002634)); | |
230 | return -EBUSY; | |
231 | } | |
232 | } | |
233 | ||
234 | nv_wr32(dev, 0x002140, 0x00000000); | |
235 | return 0; | |
236 | } | |
237 | ||
238 | ||
b2b09938 | 239 | struct nouveau_enum nvc0_fifo_fault_unit[] = { |
7a313473 BS |
240 | { 0x00, "PGRAPH" }, |
241 | { 0x03, "PEEPHOLE" }, | |
242 | { 0x04, "BAR1" }, | |
243 | { 0x05, "BAR3" }, | |
244 | { 0x07, "PFIFO" }, | |
245 | { 0x10, "PBSP" }, | |
246 | { 0x11, "PPPP" }, | |
247 | { 0x13, "PCOUNTER" }, | |
248 | { 0x14, "PVP" }, | |
249 | { 0x15, "PCOPY0" }, | |
250 | { 0x16, "PCOPY1" }, | |
251 | { 0x17, "PDAEMON" }, | |
b2b09938 BS |
252 | {} |
253 | }; | |
254 | ||
255 | struct nouveau_enum nvc0_fifo_fault_reason[] = { | |
e2966632 BS |
256 | { 0x00, "PT_NOT_PRESENT" }, |
257 | { 0x01, "PT_TOO_SHORT" }, | |
258 | { 0x02, "PAGE_NOT_PRESENT" }, | |
259 | { 0x03, "VM_LIMIT_EXCEEDED" }, | |
260 | { 0x04, "NO_CHANNEL" }, | |
261 | { 0x05, "PAGE_SYSTEM_ONLY" }, | |
262 | { 0x06, "PAGE_READ_ONLY" }, | |
263 | { 0x0a, "COMPRESSED_SYSRAM" }, | |
264 | { 0x0c, "INVALID_STORAGE_TYPE" }, | |
b2b09938 BS |
265 | {} |
266 | }; | |
267 | ||
7795bee0 BS |
268 | struct nouveau_enum nvc0_fifo_fault_hubclient[] = { |
269 | { 0x01, "PCOPY0" }, | |
270 | { 0x02, "PCOPY1" }, | |
271 | { 0x04, "DISPATCH" }, | |
272 | { 0x05, "CTXCTL" }, | |
273 | { 0x06, "PFIFO" }, | |
274 | { 0x07, "BAR_READ" }, | |
275 | { 0x08, "BAR_WRITE" }, | |
276 | { 0x0b, "PVP" }, | |
277 | { 0x0c, "PPPP" }, | |
278 | { 0x0d, "PBSP" }, | |
279 | { 0x11, "PCOUNTER" }, | |
280 | { 0x12, "PDAEMON" }, | |
281 | { 0x14, "CCACHE" }, | |
282 | { 0x15, "CCACHE_POST" }, | |
283 | {} | |
284 | }; | |
285 | ||
286 | struct nouveau_enum nvc0_fifo_fault_gpcclient[] = { | |
287 | { 0x01, "TEX" }, | |
288 | { 0x0c, "ESETUP" }, | |
289 | { 0x0e, "CTXCTL" }, | |
290 | { 0x0f, "PROP" }, | |
291 | {} | |
292 | }; | |
293 | ||
b2b09938 BS |
294 | struct nouveau_bitfield nvc0_fifo_subfifo_intr[] = { |
295 | /* { 0x00008000, "" } seen with null ib push */ | |
296 | { 0x00200000, "ILLEGAL_MTHD" }, | |
297 | { 0x00800000, "EMPTY_SUBC" }, | |
298 | {} | |
299 | }; | |
300 | ||
301 | static void | |
302 | nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit) | |
303 | { | |
304 | u32 inst = nv_rd32(dev, 0x2800 + (unit * 0x10)); | |
305 | u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10)); | |
306 | u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10)); | |
307 | u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10)); | |
7795bee0 | 308 | u32 client = (stat & 0x00001f00) >> 8; |
b2b09938 BS |
309 | |
310 | NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [", | |
311 | (stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo); | |
312 | nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f); | |
313 | printk("] from "); | |
314 | nouveau_enum_print(nvc0_fifo_fault_unit, unit); | |
7795bee0 BS |
315 | if (stat & 0x00000040) { |
316 | printk("/"); | |
317 | nouveau_enum_print(nvc0_fifo_fault_hubclient, client); | |
318 | } else { | |
319 | printk("/GPC%d/", (stat & 0x1f000000) >> 24); | |
320 | nouveau_enum_print(nvc0_fifo_fault_gpcclient, client); | |
321 | } | |
b2b09938 BS |
322 | printk(" on channel 0x%010llx\n", (u64)inst << 12); |
323 | } | |
324 | ||
d5316e25 BS |
325 | static int |
326 | nvc0_fifo_page_flip(struct drm_device *dev, u32 chid) | |
327 | { | |
c420b2dc | 328 | struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO); |
d5316e25 BS |
329 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
330 | struct nouveau_channel *chan = NULL; | |
331 | unsigned long flags; | |
332 | int ret = -EINVAL; | |
333 | ||
334 | spin_lock_irqsave(&dev_priv->channels.lock, flags); | |
c420b2dc | 335 | if (likely(chid >= 0 && chid < priv->base.channels)) { |
d5316e25 BS |
336 | chan = dev_priv->channels.ptr[chid]; |
337 | if (likely(chan)) | |
338 | ret = nouveau_finish_page_flip(chan, NULL); | |
339 | } | |
340 | spin_unlock_irqrestore(&dev_priv->channels.lock, flags); | |
341 | return ret; | |
342 | } | |
343 | ||
b2b09938 BS |
344 | static void |
345 | nvc0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit) | |
346 | { | |
347 | u32 stat = nv_rd32(dev, 0x040108 + (unit * 0x2000)); | |
348 | u32 addr = nv_rd32(dev, 0x0400c0 + (unit * 0x2000)); | |
349 | u32 data = nv_rd32(dev, 0x0400c4 + (unit * 0x2000)); | |
350 | u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f; | |
351 | u32 subc = (addr & 0x00070000); | |
352 | u32 mthd = (addr & 0x00003ffc); | |
d5316e25 | 353 | u32 show = stat; |
b2b09938 | 354 | |
d5316e25 BS |
355 | if (stat & 0x00200000) { |
356 | if (mthd == 0x0054) { | |
357 | if (!nvc0_fifo_page_flip(dev, chid)) | |
358 | show &= ~0x00200000; | |
359 | } | |
360 | } | |
361 | ||
362 | if (show) { | |
363 | NV_INFO(dev, "PFIFO%d:", unit); | |
364 | nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show); | |
365 | NV_INFO(dev, "PFIFO%d: ch %d subc %d mthd 0x%04x data 0x%08x\n", | |
366 | unit, chid, subc, mthd, data); | |
367 | } | |
b2b09938 BS |
368 | |
369 | nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008); | |
370 | nv_wr32(dev, 0x040108 + (unit * 0x2000), stat); | |
371 | } | |
372 | ||
373 | static void | |
374 | nvc0_fifo_isr(struct drm_device *dev) | |
375 | { | |
833dd822 BS |
376 | u32 mask = nv_rd32(dev, 0x002140); |
377 | u32 stat = nv_rd32(dev, 0x002100) & mask; | |
b2b09938 | 378 | |
cc8cd647 BS |
379 | if (stat & 0x00000100) { |
380 | NV_INFO(dev, "PFIFO: unknown status 0x00000100\n"); | |
381 | nv_wr32(dev, 0x002100, 0x00000100); | |
382 | stat &= ~0x00000100; | |
383 | } | |
384 | ||
b2b09938 BS |
385 | if (stat & 0x10000000) { |
386 | u32 units = nv_rd32(dev, 0x00259c); | |
387 | u32 u = units; | |
388 | ||
389 | while (u) { | |
390 | int i = ffs(u) - 1; | |
391 | nvc0_fifo_isr_vm_fault(dev, i); | |
392 | u &= ~(1 << i); | |
393 | } | |
394 | ||
395 | nv_wr32(dev, 0x00259c, units); | |
396 | stat &= ~0x10000000; | |
397 | } | |
398 | ||
399 | if (stat & 0x20000000) { | |
400 | u32 units = nv_rd32(dev, 0x0025a0); | |
401 | u32 u = units; | |
402 | ||
403 | while (u) { | |
404 | int i = ffs(u) - 1; | |
405 | nvc0_fifo_isr_subfifo_intr(dev, i); | |
406 | u &= ~(1 << i); | |
407 | } | |
408 | ||
409 | nv_wr32(dev, 0x0025a0, units); | |
410 | stat &= ~0x20000000; | |
411 | } | |
412 | ||
cc8cd647 BS |
413 | if (stat & 0x40000000) { |
414 | NV_INFO(dev, "PFIFO: unknown status 0x40000000\n"); | |
415 | nv_mask(dev, 0x002a00, 0x00000000, 0x00000000); | |
416 | stat &= ~0x40000000; | |
417 | } | |
418 | ||
b2b09938 BS |
419 | if (stat) { |
420 | NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat); | |
421 | nv_wr32(dev, 0x002100, stat); | |
cc8cd647 | 422 | nv_wr32(dev, 0x002140, 0); |
b2b09938 | 423 | } |
b2b09938 | 424 | } |
c420b2dc BS |
425 | |
426 | static void | |
427 | nvc0_fifo_destroy(struct drm_device *dev, int engine) | |
428 | { | |
429 | struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO); | |
430 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
431 | ||
432 | nouveau_vm_put(&priv->user_vma); | |
433 | nouveau_gpuobj_ref(NULL, &priv->playlist[1]); | |
434 | nouveau_gpuobj_ref(NULL, &priv->playlist[0]); | |
435 | ||
436 | dev_priv->eng[engine] = NULL; | |
437 | kfree(priv); | |
438 | } | |
439 | ||
440 | int | |
441 | nvc0_fifo_create(struct drm_device *dev) | |
442 | { | |
443 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
444 | struct nvc0_fifo_priv *priv; | |
445 | int ret; | |
446 | ||
447 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | |
448 | if (!priv) | |
449 | return -ENOMEM; | |
450 | ||
451 | priv->base.base.destroy = nvc0_fifo_destroy; | |
452 | priv->base.base.init = nvc0_fifo_init; | |
453 | priv->base.base.fini = nvc0_fifo_fini; | |
454 | priv->base.base.context_new = nvc0_fifo_context_new; | |
455 | priv->base.base.context_del = nvc0_fifo_context_del; | |
456 | priv->base.channels = 128; | |
457 | dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base; | |
458 | ||
459 | ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[0]); | |
460 | if (ret) | |
461 | goto error; | |
462 | ||
463 | ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[1]); | |
464 | if (ret) | |
465 | goto error; | |
466 | ||
467 | ret = nouveau_vm_get(dev_priv->bar1_vm, priv->base.channels * 0x1000, | |
468 | 12, NV_MEM_ACCESS_RW, &priv->user_vma); | |
469 | if (ret) | |
470 | goto error; | |
471 | ||
472 | nouveau_irq_register(dev, 8, nvc0_fifo_isr); | |
473 | error: | |
474 | if (ret) | |
475 | priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO); | |
476 | return ret; | |
477 | } |