1 | /* $NetBSD: nouveau_engine_fifo_nv50.c,v 1.1.1.1 2014/08/06 12:36:24 riastradh Exp $ */ |
2 | |
3 | /* |
4 | * Copyright 2012 Red Hat Inc. |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
7 | * copy of this software and associated documentation files (the "Software"), |
8 | * to deal in the Software without restriction, including without limitation |
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
10 | * and/or sell copies of the Software, and to permit persons to whom the |
11 | * Software is furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
22 | * OTHER DEALINGS IN THE SOFTWARE. |
23 | * |
24 | * Authors: Ben Skeggs |
25 | */ |
26 | |
27 | #include <sys/cdefs.h> |
28 | __KERNEL_RCSID(0, "$NetBSD: nouveau_engine_fifo_nv50.c,v 1.1.1.1 2014/08/06 12:36:24 riastradh Exp $" ); |
29 | |
30 | #include <core/client.h> |
31 | #include <core/engctx.h> |
32 | #include <core/ramht.h> |
33 | #include <core/class.h> |
34 | |
35 | #include <subdev/timer.h> |
36 | #include <subdev/bar.h> |
37 | |
38 | #include <engine/dmaobj.h> |
39 | #include <engine/fifo.h> |
40 | |
41 | #include "nv04.h" |
42 | #include "nv50.h" |
43 | |
44 | /******************************************************************************* |
45 | * FIFO channel objects |
46 | ******************************************************************************/ |
47 | |
48 | static void |
49 | nv50_fifo_playlist_update_locked(struct nv50_fifo_priv *priv) |
50 | { |
51 | struct nouveau_bar *bar = nouveau_bar(priv); |
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 = priv->base.min, p = 0; i < priv->base.max; i++) { |
59 | if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000) |
60 | nv_wo32(cur, p++ * 4, i); |
61 | } |
62 | |
63 | bar->flush(bar); |
64 | |
65 | nv_wr32(priv, 0x0032f4, cur->addr >> 12); |
66 | nv_wr32(priv, 0x0032ec, p); |
67 | nv_wr32(priv, 0x002500, 0x00000101); |
68 | } |
69 | |
70 | void |
71 | nv50_fifo_playlist_update(struct nv50_fifo_priv *priv) |
72 | { |
73 | mutex_lock(&nv_subdev(priv)->mutex); |
74 | nv50_fifo_playlist_update_locked(priv); |
75 | mutex_unlock(&nv_subdev(priv)->mutex); |
76 | } |
77 | |
78 | static int |
79 | nv50_fifo_context_attach(struct nouveau_object *parent, |
80 | struct nouveau_object *object) |
81 | { |
82 | struct nouveau_bar *bar = nouveau_bar(parent); |
83 | struct nv50_fifo_base *base = (void *)parent->parent; |
84 | struct nouveau_gpuobj *ectx = (void *)object; |
85 | u64 limit = ectx->addr + ectx->size - 1; |
86 | u64 start = ectx->addr; |
87 | u32 addr; |
88 | |
89 | switch (nv_engidx(object->engine)) { |
90 | case NVDEV_ENGINE_SW : return 0; |
91 | case NVDEV_ENGINE_GR : addr = 0x0000; break; |
92 | case NVDEV_ENGINE_MPEG : addr = 0x0060; break; |
93 | default: |
94 | return -EINVAL; |
95 | } |
96 | |
97 | nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; |
98 | nv_wo32(base->eng, addr + 0x00, 0x00190000); |
99 | nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); |
100 | nv_wo32(base->eng, addr + 0x08, lower_32_bits(start)); |
101 | nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | |
102 | upper_32_bits(start)); |
103 | nv_wo32(base->eng, addr + 0x10, 0x00000000); |
104 | nv_wo32(base->eng, addr + 0x14, 0x00000000); |
105 | bar->flush(bar); |
106 | return 0; |
107 | } |
108 | |
109 | static int |
110 | nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend, |
111 | struct nouveau_object *object) |
112 | { |
113 | struct nouveau_bar *bar = nouveau_bar(parent); |
114 | struct nv50_fifo_priv *priv = (void *)parent->engine; |
115 | struct nv50_fifo_base *base = (void *)parent->parent; |
116 | struct nv50_fifo_chan *chan = (void *)parent; |
117 | u32 addr, me; |
118 | int ret = 0; |
119 | |
120 | switch (nv_engidx(object->engine)) { |
121 | case NVDEV_ENGINE_SW : return 0; |
122 | case NVDEV_ENGINE_GR : addr = 0x0000; break; |
123 | case NVDEV_ENGINE_MPEG : addr = 0x0060; break; |
124 | default: |
125 | return -EINVAL; |
126 | } |
127 | |
128 | /* HW bug workaround: |
129 | * |
130 | * PFIFO will hang forever if the connected engines don't report |
131 | * that they've processed the context switch request. |
132 | * |
133 | * In order for the kickoff to work, we need to ensure all the |
134 | * connected engines are in a state where they can answer. |
135 | * |
136 | * Newer chipsets don't seem to suffer from this issue, and well, |
137 | * there's also a "ignore these engines" bitmask reg we can use |
138 | * if we hit the issue there.. |
139 | */ |
140 | me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001); |
141 | |
142 | /* do the kickoff... */ |
143 | nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); |
144 | if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) { |
145 | nv_error(priv, "channel %d [%s] unload timeout\n" , |
146 | chan->base.chid, nouveau_client_name(chan)); |
147 | if (suspend) |
148 | ret = -EBUSY; |
149 | } |
150 | nv_wr32(priv, 0x00b860, me); |
151 | |
152 | if (ret == 0) { |
153 | nv_wo32(base->eng, addr + 0x00, 0x00000000); |
154 | nv_wo32(base->eng, addr + 0x04, 0x00000000); |
155 | nv_wo32(base->eng, addr + 0x08, 0x00000000); |
156 | nv_wo32(base->eng, addr + 0x0c, 0x00000000); |
157 | nv_wo32(base->eng, addr + 0x10, 0x00000000); |
158 | nv_wo32(base->eng, addr + 0x14, 0x00000000); |
159 | bar->flush(bar); |
160 | } |
161 | |
162 | return ret; |
163 | } |
164 | |
165 | static int |
166 | nv50_fifo_object_attach(struct nouveau_object *parent, |
167 | struct nouveau_object *object, u32 handle) |
168 | { |
169 | struct nv50_fifo_chan *chan = (void *)parent; |
170 | u32 context; |
171 | |
172 | if (nv_iclass(object, NV_GPUOBJ_CLASS)) |
173 | context = nv_gpuobj(object)->node->offset >> 4; |
174 | else |
175 | context = 0x00000004; /* just non-zero */ |
176 | |
177 | switch (nv_engidx(object->engine)) { |
178 | case NVDEV_ENGINE_DMAOBJ: |
179 | case NVDEV_ENGINE_SW : context |= 0x00000000; break; |
180 | case NVDEV_ENGINE_GR : context |= 0x00100000; break; |
181 | case NVDEV_ENGINE_MPEG : context |= 0x00200000; break; |
182 | default: |
183 | return -EINVAL; |
184 | } |
185 | |
186 | return nouveau_ramht_insert(chan->ramht, 0, handle, context); |
187 | } |
188 | |
189 | void |
190 | nv50_fifo_object_detach(struct nouveau_object *parent, int cookie) |
191 | { |
192 | struct nv50_fifo_chan *chan = (void *)parent; |
193 | nouveau_ramht_remove(chan->ramht, cookie); |
194 | } |
195 | |
196 | static int |
197 | nv50_fifo_chan_ctor_dma(struct nouveau_object *parent, |
198 | struct nouveau_object *engine, |
199 | struct nouveau_oclass *oclass, void *data, u32 size, |
200 | struct nouveau_object **pobject) |
201 | { |
202 | struct nouveau_bar *bar = nouveau_bar(parent); |
203 | struct nv50_fifo_base *base = (void *)parent; |
204 | struct nv50_fifo_chan *chan; |
205 | struct nv03_channel_dma_class *args = data; |
206 | int ret; |
207 | |
208 | if (size < sizeof(*args)) |
209 | return -EINVAL; |
210 | |
211 | ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, |
212 | 0x2000, args->pushbuf, |
213 | (1ULL << NVDEV_ENGINE_DMAOBJ) | |
214 | (1ULL << NVDEV_ENGINE_SW) | |
215 | (1ULL << NVDEV_ENGINE_GR) | |
216 | (1ULL << NVDEV_ENGINE_MPEG), &chan); |
217 | *pobject = nv_object(chan); |
218 | if (ret) |
219 | return ret; |
220 | |
221 | nv_parent(chan)->context_attach = nv50_fifo_context_attach; |
222 | nv_parent(chan)->context_detach = nv50_fifo_context_detach; |
223 | nv_parent(chan)->object_attach = nv50_fifo_object_attach; |
224 | nv_parent(chan)->object_detach = nv50_fifo_object_detach; |
225 | |
226 | ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, |
227 | &chan->ramht); |
228 | if (ret) |
229 | return ret; |
230 | |
231 | nv_wo32(base->ramfc, 0x08, lower_32_bits(args->offset)); |
232 | nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->offset)); |
233 | nv_wo32(base->ramfc, 0x10, lower_32_bits(args->offset)); |
234 | nv_wo32(base->ramfc, 0x14, upper_32_bits(args->offset)); |
235 | nv_wo32(base->ramfc, 0x3c, 0x003f6078); |
236 | nv_wo32(base->ramfc, 0x44, 0x01003fff); |
237 | nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); |
238 | nv_wo32(base->ramfc, 0x4c, 0xffffffff); |
239 | nv_wo32(base->ramfc, 0x60, 0x7fffffff); |
240 | nv_wo32(base->ramfc, 0x78, 0x00000000); |
241 | nv_wo32(base->ramfc, 0x7c, 0x30000001); |
242 | nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | |
243 | (4 << 24) /* SEARCH_FULL */ | |
244 | (chan->ramht->base.node->offset >> 4)); |
245 | bar->flush(bar); |
246 | return 0; |
247 | } |
248 | |
249 | static int |
250 | nv50_fifo_chan_ctor_ind(struct nouveau_object *parent, |
251 | struct nouveau_object *engine, |
252 | struct nouveau_oclass *oclass, void *data, u32 size, |
253 | struct nouveau_object **pobject) |
254 | { |
255 | struct nv50_channel_ind_class *args = data; |
256 | struct nouveau_bar *bar = nouveau_bar(parent); |
257 | struct nv50_fifo_base *base = (void *)parent; |
258 | struct nv50_fifo_chan *chan; |
259 | u64 ioffset, ilength; |
260 | int ret; |
261 | |
262 | if (size < sizeof(*args)) |
263 | return -EINVAL; |
264 | |
265 | ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, |
266 | 0x2000, args->pushbuf, |
267 | (1ULL << NVDEV_ENGINE_DMAOBJ) | |
268 | (1ULL << NVDEV_ENGINE_SW) | |
269 | (1ULL << NVDEV_ENGINE_GR) | |
270 | (1ULL << NVDEV_ENGINE_MPEG), &chan); |
271 | *pobject = nv_object(chan); |
272 | if (ret) |
273 | return ret; |
274 | |
275 | nv_parent(chan)->context_attach = nv50_fifo_context_attach; |
276 | nv_parent(chan)->context_detach = nv50_fifo_context_detach; |
277 | nv_parent(chan)->object_attach = nv50_fifo_object_attach; |
278 | nv_parent(chan)->object_detach = nv50_fifo_object_detach; |
279 | |
280 | ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, |
281 | &chan->ramht); |
282 | if (ret) |
283 | return ret; |
284 | |
285 | ioffset = args->ioffset; |
286 | ilength = order_base_2(args->ilength / 8); |
287 | |
288 | nv_wo32(base->ramfc, 0x3c, 0x403f6078); |
289 | nv_wo32(base->ramfc, 0x44, 0x01003fff); |
290 | nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); |
291 | nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); |
292 | nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); |
293 | nv_wo32(base->ramfc, 0x60, 0x7fffffff); |
294 | nv_wo32(base->ramfc, 0x78, 0x00000000); |
295 | nv_wo32(base->ramfc, 0x7c, 0x30000001); |
296 | nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | |
297 | (4 << 24) /* SEARCH_FULL */ | |
298 | (chan->ramht->base.node->offset >> 4)); |
299 | bar->flush(bar); |
300 | return 0; |
301 | } |
302 | |
303 | void |
304 | nv50_fifo_chan_dtor(struct nouveau_object *object) |
305 | { |
306 | struct nv50_fifo_chan *chan = (void *)object; |
307 | nouveau_ramht_ref(NULL, &chan->ramht); |
308 | nouveau_fifo_channel_destroy(&chan->base); |
309 | } |
310 | |
311 | static int |
312 | nv50_fifo_chan_init(struct nouveau_object *object) |
313 | { |
314 | struct nv50_fifo_priv *priv = (void *)object->engine; |
315 | struct nv50_fifo_base *base = (void *)object->parent; |
316 | struct nv50_fifo_chan *chan = (void *)object; |
317 | struct nouveau_gpuobj *ramfc = base->ramfc; |
318 | u32 chid = chan->base.chid; |
319 | int ret; |
320 | |
321 | ret = nouveau_fifo_channel_init(&chan->base); |
322 | if (ret) |
323 | return ret; |
324 | |
325 | nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12); |
326 | nv50_fifo_playlist_update(priv); |
327 | return 0; |
328 | } |
329 | |
330 | int |
331 | nv50_fifo_chan_fini(struct nouveau_object *object, bool suspend) |
332 | { |
333 | struct nv50_fifo_priv *priv = (void *)object->engine; |
334 | struct nv50_fifo_chan *chan = (void *)object; |
335 | u32 chid = chan->base.chid; |
336 | |
337 | /* remove channel from playlist, fifo will unload context */ |
338 | nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000); |
339 | nv50_fifo_playlist_update(priv); |
340 | nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000); |
341 | |
342 | return nouveau_fifo_channel_fini(&chan->base, suspend); |
343 | } |
344 | |
345 | static struct nouveau_ofuncs |
346 | nv50_fifo_ofuncs_dma = { |
347 | .ctor = nv50_fifo_chan_ctor_dma, |
348 | .dtor = nv50_fifo_chan_dtor, |
349 | .init = nv50_fifo_chan_init, |
350 | .fini = nv50_fifo_chan_fini, |
351 | .rd32 = _nouveau_fifo_channel_rd32, |
352 | .wr32 = _nouveau_fifo_channel_wr32, |
353 | }; |
354 | |
355 | static struct nouveau_ofuncs |
356 | nv50_fifo_ofuncs_ind = { |
357 | .ctor = nv50_fifo_chan_ctor_ind, |
358 | .dtor = nv50_fifo_chan_dtor, |
359 | .init = nv50_fifo_chan_init, |
360 | .fini = nv50_fifo_chan_fini, |
361 | .rd32 = _nouveau_fifo_channel_rd32, |
362 | .wr32 = _nouveau_fifo_channel_wr32, |
363 | }; |
364 | |
365 | static struct nouveau_oclass |
366 | nv50_fifo_sclass[] = { |
367 | { NV50_CHANNEL_DMA_CLASS, &nv50_fifo_ofuncs_dma }, |
368 | { NV50_CHANNEL_IND_CLASS, &nv50_fifo_ofuncs_ind }, |
369 | {} |
370 | }; |
371 | |
372 | /******************************************************************************* |
373 | * FIFO context - basically just the instmem reserved for the channel |
374 | ******************************************************************************/ |
375 | |
376 | static int |
377 | nv50_fifo_context_ctor(struct nouveau_object *parent, |
378 | struct nouveau_object *engine, |
379 | struct nouveau_oclass *oclass, void *data, u32 size, |
380 | struct nouveau_object **pobject) |
381 | { |
382 | struct nv50_fifo_base *base; |
383 | int ret; |
384 | |
385 | ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000, |
386 | 0x1000, NVOBJ_FLAG_HEAP, &base); |
387 | *pobject = nv_object(base); |
388 | if (ret) |
389 | return ret; |
390 | |
391 | ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0200, |
392 | 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc); |
393 | if (ret) |
394 | return ret; |
395 | |
396 | ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x1200, 0, |
397 | NVOBJ_FLAG_ZERO_ALLOC, &base->eng); |
398 | if (ret) |
399 | return ret; |
400 | |
401 | ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, 0, |
402 | &base->pgd); |
403 | if (ret) |
404 | return ret; |
405 | |
406 | ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd); |
407 | if (ret) |
408 | return ret; |
409 | |
410 | return 0; |
411 | } |
412 | |
413 | void |
414 | nv50_fifo_context_dtor(struct nouveau_object *object) |
415 | { |
416 | struct nv50_fifo_base *base = (void *)object; |
417 | nouveau_vm_ref(NULL, &base->vm, base->pgd); |
418 | nouveau_gpuobj_ref(NULL, &base->pgd); |
419 | nouveau_gpuobj_ref(NULL, &base->eng); |
420 | nouveau_gpuobj_ref(NULL, &base->ramfc); |
421 | nouveau_gpuobj_ref(NULL, &base->cache); |
422 | nouveau_fifo_context_destroy(&base->base); |
423 | } |
424 | |
425 | static struct nouveau_oclass |
426 | nv50_fifo_cclass = { |
427 | .handle = NV_ENGCTX(FIFO, 0x50), |
428 | .ofuncs = &(struct nouveau_ofuncs) { |
429 | .ctor = nv50_fifo_context_ctor, |
430 | .dtor = nv50_fifo_context_dtor, |
431 | .init = _nouveau_fifo_context_init, |
432 | .fini = _nouveau_fifo_context_fini, |
433 | .rd32 = _nouveau_fifo_context_rd32, |
434 | .wr32 = _nouveau_fifo_context_wr32, |
435 | }, |
436 | }; |
437 | |
438 | /******************************************************************************* |
439 | * PFIFO engine |
440 | ******************************************************************************/ |
441 | |
442 | static int |
443 | nv50_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, |
444 | struct nouveau_oclass *oclass, void *data, u32 size, |
445 | struct nouveau_object **pobject) |
446 | { |
447 | struct nv50_fifo_priv *priv; |
448 | int ret; |
449 | |
450 | ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv); |
451 | *pobject = nv_object(priv); |
452 | if (ret) |
453 | return ret; |
454 | |
455 | ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, |
456 | &priv->playlist[0]); |
457 | if (ret) |
458 | return ret; |
459 | |
460 | ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, |
461 | &priv->playlist[1]); |
462 | if (ret) |
463 | return ret; |
464 | |
465 | nv_subdev(priv)->unit = 0x00000100; |
466 | nv_subdev(priv)->intr = nv04_fifo_intr; |
467 | nv_engine(priv)->cclass = &nv50_fifo_cclass; |
468 | nv_engine(priv)->sclass = nv50_fifo_sclass; |
469 | priv->base.pause = nv04_fifo_pause; |
470 | priv->base.start = nv04_fifo_start; |
471 | return 0; |
472 | } |
473 | |
474 | void |
475 | nv50_fifo_dtor(struct nouveau_object *object) |
476 | { |
477 | struct nv50_fifo_priv *priv = (void *)object; |
478 | |
479 | nouveau_gpuobj_ref(NULL, &priv->playlist[1]); |
480 | nouveau_gpuobj_ref(NULL, &priv->playlist[0]); |
481 | |
482 | nouveau_fifo_destroy(&priv->base); |
483 | } |
484 | |
485 | int |
486 | nv50_fifo_init(struct nouveau_object *object) |
487 | { |
488 | struct nv50_fifo_priv *priv = (void *)object; |
489 | int ret, i; |
490 | |
491 | ret = nouveau_fifo_init(&priv->base); |
492 | if (ret) |
493 | return ret; |
494 | |
495 | nv_mask(priv, 0x000200, 0x00000100, 0x00000000); |
496 | nv_mask(priv, 0x000200, 0x00000100, 0x00000100); |
497 | nv_wr32(priv, 0x00250c, 0x6f3cfc34); |
498 | nv_wr32(priv, 0x002044, 0x01003fff); |
499 | |
500 | nv_wr32(priv, 0x002100, 0xffffffff); |
501 | nv_wr32(priv, 0x002140, 0xbfffffff); |
502 | |
503 | for (i = 0; i < 128; i++) |
504 | nv_wr32(priv, 0x002600 + (i * 4), 0x00000000); |
505 | nv50_fifo_playlist_update_locked(priv); |
506 | |
507 | nv_wr32(priv, 0x003200, 0x00000001); |
508 | nv_wr32(priv, 0x003250, 0x00000001); |
509 | nv_wr32(priv, 0x002500, 0x00000001); |
510 | return 0; |
511 | } |
512 | |
513 | struct nouveau_oclass * |
514 | nv50_fifo_oclass = &(struct nouveau_oclass) { |
515 | .handle = NV_ENGINE(FIFO, 0x50), |
516 | .ofuncs = &(struct nouveau_ofuncs) { |
517 | .ctor = nv50_fifo_ctor, |
518 | .dtor = nv50_fifo_dtor, |
519 | .init = nv50_fifo_init, |
520 | .fini = _nouveau_fifo_fini, |
521 | }, |
522 | }; |
523 | |