From e317dfdabfb836165fbe3b006e53a88a1bc7c264 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 2 May 2008 00:06:22 +1000 Subject: nv50: PGRAPH exception handling completely different from earlier chips --- shared-core/nouveau_irq.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'shared-core/nouveau_irq.c') diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index ec158d82..3e1e6e30 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -432,6 +432,49 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) NV_WRITE(NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); } +static void +nv50_pgraph_irq_handler(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t status; + + status = NV_READ(NV03_PGRAPH_INTR); + + if (status & 0x00000020) { + nouveau_pgraph_intr_error(dev, + NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD); + + status &= ~0x00000020; + NV_WRITE(NV03_PGRAPH_INTR, 0x00000020); + } + + if (status & 0x00100000) { + nouveau_pgraph_intr_error(dev, + NV03_PGRAPH_NSOURCE_DATA_ERROR); + + status &= ~0x00100000; + NV_WRITE(NV03_PGRAPH_INTR, 0x00100000); + } + + if (status & 0x00200000) { + nouveau_pgraph_intr_error(dev, + NV03_PGRAPH_NSOURCE_PROTECTION_ERROR); + + status &= ~0x00200000; + NV_WRITE(NV03_PGRAPH_INTR, 0x00200000); + } + + if (status) { + DRM_INFO("Unhandled PGRAPH_INTR - 0x%08x\n", status); + NV_WRITE(NV03_PGRAPH_INTR, status); + } + + if ((NV_READ(0x400500) & (1 << 16)) == 0) + NV_WRITE(0x400500, NV_READ(0x400500) | (1 << 16)); + + NV_WRITE(NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); +} + static void nouveau_crtc_irq_handler(struct drm_device *dev, int crtc) { @@ -485,7 +528,11 @@ nouveau_irq_handler(DRM_IRQ_ARGS) } if (status & NV_PMC_INTR_0_PGRAPH_PENDING) { - nouveau_pgraph_irq_handler(dev); + if (dev_priv->card_type >= NV_50) + nv50_pgraph_irq_handler(dev); + else + nouveau_pgraph_irq_handler(dev); + status &= ~NV_PMC_INTR_0_PGRAPH_PENDING; } -- cgit v1.2.3 From bfbe4ade3253330bd0c625d50fa2e7b5cb62dada Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 2 May 2008 00:50:21 +1000 Subject: nouveau: gather nsource in trap_info() The IRQ handling stuff really is a mess.. On the TODO :) --- shared-core/nouveau_irq.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'shared-core/nouveau_irq.c') diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index 3e1e6e30..85a70b55 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -251,6 +251,7 @@ struct nouveau_pgraph_trap { int class; int subc, mthd, size; uint32_t data, data2; + uint32_t nsource, nstatus; }; static void @@ -260,6 +261,12 @@ nouveau_graph_trap_info(struct drm_device *dev, struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t address; + trap->nsource = trap->nstatus = 0; + if (dev_priv->card_type < NV_50) { + trap->nsource = NV_READ(NV03_PGRAPH_NSOURCE); + trap->nstatus = NV_READ(NV03_PGRAPH_NSTATUS); + } + if (nouveau_graph_trapped_channel(dev, &trap->channel)) trap->channel = -1; address = NV_READ(NV04_PGRAPH_TRAPPED_ADDR); @@ -289,10 +296,7 @@ nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id, struct nouveau_pgraph_trap *trap) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t nsource, nstatus; - - nsource = NV_READ(NV03_PGRAPH_NSOURCE); - nstatus = NV_READ(NV03_PGRAPH_NSTATUS); + uint32_t nsource = trap->nsource, nstatus = trap->nstatus; DRM_INFO("%s - nSource:", id); nouveau_print_bitfield_names(nsource, nouveau_nsource_names, @@ -347,6 +351,7 @@ nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource) int unhandled = 0; nouveau_graph_trap_info(dev, &trap); + trap.nsource = nsource; if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { if (trap.channel >= 0 && trap.mthd == 0x0150) { -- cgit v1.2.3 From 5c4c778c0d7d3f4749efade3b1023b8b22c029a9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 2 May 2008 00:52:21 +1000 Subject: nouveau: restore original NV_PFIFO_CACHES_REASSIGN value in fifo handler Doesn't fix any issue I've seen, but is a potential issue if a FIFO IRQ occurs during channel creation/takedown. --- shared-core/nouveau_irq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'shared-core/nouveau_irq.c') diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index 85a70b55..ccbc7420 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -71,8 +71,9 @@ nouveau_fifo_irq_handler(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_engine *engine = &dev_priv->Engine; - uint32_t status; + uint32_t status, reassign; + reassign = NV_READ(NV03_PFIFO_CACHES) & 1; while ((status = NV_READ(NV03_PFIFO_INTR_0))) { uint32_t chid, get; @@ -121,7 +122,7 @@ nouveau_fifo_irq_handler(struct drm_device *dev) NV_WRITE(NV03_PFIFO_INTR_0, status); } - NV_WRITE(NV03_PFIFO_CACHES, 1); + NV_WRITE(NV03_PFIFO_CACHES, reassign); } NV_WRITE(NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING); -- cgit v1.2.3 From 77d20928b330acda5b6ceb469f50757b5300702b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 2 May 2008 00:53:42 +1000 Subject: nouveau: disable all card interrupts when unknown PFIFO IRQ occurs. This is possibly temporary. I can trigger an unending IRQ storm on G8x in some circumstances, and have no idea how to handle that particular PFIFO exception correctly yet. --- shared-core/nouveau_irq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'shared-core/nouveau_irq.c') diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index ccbc7420..103fd96b 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -120,6 +120,7 @@ nouveau_fifo_irq_handler(struct drm_device *dev) if (status) { DRM_INFO("Unhandled PFIFO_INTR - 0x%08x\n", status); NV_WRITE(NV03_PFIFO_INTR_0, status); + NV_WRITE(NV03_PMC_INTR_EN_0, 0); } NV_WRITE(NV03_PFIFO_CACHES, reassign); -- cgit v1.2.3 From 6d8062ac1e048c3643d3a9d2432e497e17f717de Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 2 May 2008 01:03:51 +1000 Subject: nouveau: guard against channels potentially not having a context, fix nv50 --- shared-core/nouveau_irq.c | 79 +++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 40 deletions(-) (limited to 'shared-core/nouveau_irq.c') diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index 103fd96b..d002f642 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -191,55 +191,54 @@ nouveau_print_bitfield_names(uint32_t value, } static int -nouveau_graph_trapped_channel(struct drm_device *dev, int *channel_ret) +nouveau_graph_chid_from_grctx(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine *engine = &dev_priv->Engine; - int channel; + uint32_t inst; + int i; - if (dev_priv->card_type < NV_10) { - channel = (NV_READ(NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0xf; - } else if (dev_priv->card_type < NV_40) { - channel = (NV_READ(NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; - } else - if (dev_priv->card_type < NV_50) { - uint32_t cur_grctx = (NV_READ(0x40032C) & 0xfffff) << 4; + if (dev_priv->card_type < NV_40) + return dev_priv->Engine.fifo.channels; + else + if (dev_priv->card_type < NV_50) + inst = (NV_READ(0x40032c) & 0xfffff) << 4; + else + inst = NV_READ(0x40032c) & 0xfffff; - /* 0x400704 *sometimes* contains a sensible channel ID, but - * mostly not.. for now lookup which channel owns the active - * PGRAPH context. Probably a better way, but this'll do - * for now. - */ - for (channel = 0; channel < 32; channel++) { - if (dev_priv->fifos[channel] == NULL) - continue; - if (cur_grctx == - dev_priv->fifos[channel]->ramin_grctx->instance) - break; - } - if (channel == 32) { - DRM_ERROR("AIII, unable to determine active channel " - "from PGRAPH context 0x%08x\n", cur_grctx); - return -EINVAL; - } - } else { - uint32_t cur_grctx = (NV_READ(0x40032C) & 0xfffff) << 12; + for (i = 0; i < dev_priv->Engine.fifo.channels; i++) { + struct nouveau_channel *chan = dev_priv->fifos[i]; + + if (!chan || !chan->ramin_grctx) + continue; - for (channel = 0; channel < 128; channel++) { - if (dev_priv->fifos[channel] == NULL) - continue; - if (cur_grctx == - dev_priv->fifos[channel]->ramin_grctx->instance) + if (dev_priv->card_type < NV_50) { + if (inst == chan->ramin_grctx->instance) + break; + } else { + if (inst == INSTANCE_RD(chan->ramin_grctx->gpuobj, 0)) break; - } - if (channel == 128) { - DRM_ERROR("AIII, unable to determine active channel " - "from PGRAPH context 0x%08x\n", cur_grctx); - return -EINVAL; } } - if (channel > engine->fifo.channels || !dev_priv->fifos[channel]) { + return i; +} + +static int +nouveau_graph_trapped_channel(struct drm_device *dev, int *channel_ret) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_engine *engine = &dev_priv->Engine; + int channel; + + if (dev_priv->card_type < NV_10) + channel = (NV_READ(NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0xf; + else + if (dev_priv->card_type < NV_40) + channel = (NV_READ(NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; + else + channel = nouveau_graph_chid_from_grctx(dev); + + if (channel >= engine->fifo.channels || !dev_priv->fifos[channel]) { DRM_ERROR("AIII, invalid/inactive channel id %d\n", channel); return -EINVAL; } -- cgit v1.2.3 From 3ac74f3208ed15a990a0a26742fbfe566f08aa80 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 2 May 2008 01:36:30 +1000 Subject: nv50: enable 0x400500 bit 0 after PGRAPH exception also No solid idea about what these 2 bits do, but nv50 can now survive a few PGRAPH exceptions just as nv40 does :) --- shared-core/nouveau_irq.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'shared-core/nouveau_irq.c') diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index d002f642..2a3d8a0b 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -475,8 +475,12 @@ nv50_pgraph_irq_handler(struct drm_device *dev) NV_WRITE(NV03_PGRAPH_INTR, status); } - if ((NV_READ(0x400500) & (1 << 16)) == 0) - NV_WRITE(0x400500, NV_READ(0x400500) | (1 << 16)); + { + const int isb = (1 << 16) | (1 << 0); + + if ((NV_READ(0x400500) & isb) != isb) + NV_WRITE(0x400500, NV_READ(0x400500) | isb); + } NV_WRITE(NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); } -- cgit v1.2.3