Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Apr 14-17, 2025
Register
Loading...
Note: File does not exist in v4.6.
  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
 25#include "drmP.h"
 26
 27#include "nouveau_drv.h"
 28#include "nouveau_mm.h"
 29#include "nouveau_fifo.h"
 30
 31static void nvc0_fifo_isr(struct drm_device *);
 32
 33struct nvc0_fifo_priv {
 34	struct nouveau_fifo_priv base;
 35	struct nouveau_gpuobj *playlist[2];
 36	int cur_playlist;
 37	struct nouveau_vma user_vma;
 38	int spoon_nr;
 39};
 40
 41struct nvc0_fifo_chan {
 42	struct nouveau_fifo_chan base;
 43	struct nouveau_gpuobj *user;
 44};
 45
 46static void
 47nvc0_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;
 51	struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
 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}
 72
 73static int
 74nvc0_fifo_context_new(struct nouveau_channel *chan, int engine)
 75{
 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;
 79	struct nvc0_fifo_priv *priv = nv_engine(dev, engine);
 80	struct nvc0_fifo_chan *fctx;
 81	u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
 82	int ret, i;
 83
 84	fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
 85	if (!fctx)
 86		return -ENOMEM;
 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
 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);
 99	if (ret)
100		goto error;
101
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 |
113				   upper_32_bits(ib_virt));
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 */
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);
130
131error:
132	if (ret)
133		priv->base.base.context_del(chan, engine);
134	return ret;
135}
136
137static void
138nvc0_fifo_context_del(struct nouveau_channel *chan, int engine)
139{
140	struct nvc0_fifo_chan *fctx = chan->engctx[engine];
141	struct drm_device *dev = chan->dev;
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));
147	nvc0_fifo_playlist_update(dev);
148	nv_wr32(dev, 0x003000 + (chan->id * 8), 0x00000000);
149
150	nouveau_gpuobj_ref(NULL, &fctx->user);
151	if (chan->user) {
152		iounmap(chan->user);
153		chan->user = NULL;
154	}
155
156	chan->engctx[engine] = NULL;
157	kfree(fctx);
158}
159
160static int
161nvc0_fifo_init(struct drm_device *dev, int engine)
162{
163	struct drm_nouveau_private *dev_priv = dev->dev_private;
164	struct nvc0_fifo_priv *priv = nv_engine(dev, engine);
165	struct nouveau_channel *chan;
166	int i;
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
174	priv->spoon_nr = hweight32(nv_rd32(dev, 0x002204));
175	NV_DEBUG(dev, "PFIFO: %d subfifo(s)\n", priv->spoon_nr);
176
177	/* assign engines to subfifos */
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	}
186
187	/* PSUBFIFO[n] */
188	for (i = 0; i < priv->spoon_nr; i++) {
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);
200
201	/* restore PFIFO context table */
202	for (i = 0; i < 128; i++) {
203		chan = dev_priv->channels.ptr[i];
204		if (!chan || !chan->engctx[engine])
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
213	return 0;
214}
215
216static int
217nvc0_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
239struct nouveau_enum nvc0_fifo_fault_unit[] = {
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" },
252	{}
253};
254
255struct nouveau_enum nvc0_fifo_fault_reason[] = {
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" },
265	{}
266};
267
268struct 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
286struct nouveau_enum nvc0_fifo_fault_gpcclient[] = {
287	{ 0x01, "TEX" },
288	{ 0x0c, "ESETUP" },
289	{ 0x0e, "CTXCTL" },
290	{ 0x0f, "PROP" },
291	{}
292};
293
294struct nouveau_bitfield nvc0_fifo_subfifo_intr[] = {
295/*	{ 0x00008000, "" }	seen with null ib push */
296	{ 0x00200000, "ILLEGAL_MTHD" },
297	{ 0x00800000, "EMPTY_SUBC" },
298	{}
299};
300
301static void
302nvc0_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));
308	u32 client = (stat & 0x00001f00) >> 8;
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);
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	}
322	printk(" on channel 0x%010llx\n", (u64)inst << 12);
323}
324
325static int
326nvc0_fifo_page_flip(struct drm_device *dev, u32 chid)
327{
328	struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
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);
335	if (likely(chid >= 0 && chid < priv->base.channels)) {
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
344static void
345nvc0_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);
353	u32 show = stat;
354
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	}
368
369	nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008);
370	nv_wr32(dev, 0x040108 + (unit * 0x2000), stat);
371}
372
373static void
374nvc0_fifo_isr(struct drm_device *dev)
375{
376	u32 stat = nv_rd32(dev, 0x002100);
377
378	if (stat & 0x00000100) {
379		NV_INFO(dev, "PFIFO: unknown status 0x00000100\n");
380		nv_wr32(dev, 0x002100, 0x00000100);
381		stat &= ~0x00000100;
382	}
383
384	if (stat & 0x10000000) {
385		u32 units = nv_rd32(dev, 0x00259c);
386		u32 u = units;
387
388		while (u) {
389			int i = ffs(u) - 1;
390			nvc0_fifo_isr_vm_fault(dev, i);
391			u &= ~(1 << i);
392		}
393
394		nv_wr32(dev, 0x00259c, units);
395		stat &= ~0x10000000;
396	}
397
398	if (stat & 0x20000000) {
399		u32 units = nv_rd32(dev, 0x0025a0);
400		u32 u = units;
401
402		while (u) {
403			int i = ffs(u) - 1;
404			nvc0_fifo_isr_subfifo_intr(dev, i);
405			u &= ~(1 << i);
406		}
407
408		nv_wr32(dev, 0x0025a0, units);
409		stat &= ~0x20000000;
410	}
411
412	if (stat & 0x40000000) {
413		NV_INFO(dev, "PFIFO: unknown status 0x40000000\n");
414		nv_mask(dev, 0x002a00, 0x00000000, 0x00000000);
415		stat &= ~0x40000000;
416	}
417
418	if (stat) {
419		NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat);
420		nv_wr32(dev, 0x002100, stat);
421		nv_wr32(dev, 0x002140, 0);
422	}
423}
424
425static void
426nvc0_fifo_destroy(struct drm_device *dev, int engine)
427{
428	struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
429	struct drm_nouveau_private *dev_priv = dev->dev_private;
430
431	nouveau_vm_put(&priv->user_vma);
432	nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
433	nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
434
435	dev_priv->eng[engine] = NULL;
436	kfree(priv);
437}
438
439int
440nvc0_fifo_create(struct drm_device *dev)
441{
442	struct drm_nouveau_private *dev_priv = dev->dev_private;
443	struct nvc0_fifo_priv *priv;
444	int ret;
445
446	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
447	if (!priv)
448		return -ENOMEM;
449
450	priv->base.base.destroy = nvc0_fifo_destroy;
451	priv->base.base.init = nvc0_fifo_init;
452	priv->base.base.fini = nvc0_fifo_fini;
453	priv->base.base.context_new = nvc0_fifo_context_new;
454	priv->base.base.context_del = nvc0_fifo_context_del;
455	priv->base.channels = 128;
456	dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
457
458	ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[0]);
459	if (ret)
460		goto error;
461
462	ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[1]);
463	if (ret)
464		goto error;
465
466	ret = nouveau_vm_get(dev_priv->bar1_vm, priv->base.channels * 0x1000,
467			     12, NV_MEM_ACCESS_RW, &priv->user_vma);
468	if (ret)
469		goto error;
470
471	nouveau_irq_register(dev, 8, nvc0_fifo_isr);
472error:
473	if (ret)
474		priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
475	return ret;
476}