diff options
Diffstat (limited to 'shared-core')
-rw-r--r-- | shared-core/nouveau_irq.c | 97 |
1 files changed, 60 insertions, 37 deletions
diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index 1a52a584..08bd1da0 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -244,39 +244,53 @@ nouveau_graph_trapped_channel(struct drm_device *dev, int *channel_ret) return 0; } +struct nouveau_pgraph_trap { + int channel; + int class; + int subc, mthd, size; + uint32_t data, data2; +}; + static void -nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id) +nouveau_graph_trap_info(struct drm_device *dev, + struct nouveau_pgraph_trap *trap) { struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t address; - uint32_t channel, class; - uint32_t method, subc, data, data2; - uint32_t nsource, nstatus; - if (nouveau_graph_trapped_channel(dev, &channel)) - channel = -1; - - data = NV_READ(NV04_PGRAPH_TRAPPED_DATA); + if (nouveau_graph_trapped_channel(dev, &trap->channel)) + trap->channel = -1; address = NV_READ(NV04_PGRAPH_TRAPPED_ADDR); - method = address & 0x1FFC; + + trap->mthd = address & 0x1FFC; + trap->data = NV_READ(NV04_PGRAPH_TRAPPED_DATA); if (dev_priv->card_type < NV_10) { - subc = (address >> 13) & 0x7; - data2= 0; + trap->subc = (address >> 13) & 0x7; } else { - subc = (address >> 16) & 0x7; - data2= NV_READ(NV10_PGRAPH_TRAPPED_DATA_HIGH); + trap->subc = (address >> 16) & 0x7; + trap->data2 = NV_READ(NV10_PGRAPH_TRAPPED_DATA_HIGH); } - nsource = NV_READ(NV03_PGRAPH_NSOURCE); - nstatus = NV_READ(NV03_PGRAPH_NSTATUS); + if (dev_priv->card_type < NV_10) { - class = NV_READ(0x400180 + subc*4) & 0xFF; + trap->class = NV_READ(0x400180 + trap->subc*4) & 0xFF; } else if (dev_priv->card_type < NV_40) { - class = NV_READ(0x400160 + subc*4) & 0xFFF; + trap->class = NV_READ(0x400160 + trap->subc*4) & 0xFFF; } else if (dev_priv->card_type < NV_50) { - class = NV_READ(0x400160 + subc*4) & 0xFFFF; + trap->class = NV_READ(0x400160 + trap->subc*4) & 0xFFFF; } else { - class = NV_READ(0x400814); + trap->class = NV_READ(0x400814); } +} + +static void +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); DRM_INFO("%s - nSource:", id); nouveau_print_bitfield_names(nsource, nouveau_nsource_names, @@ -291,37 +305,29 @@ nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id) printk("\n"); DRM_INFO("%s - Ch %d/%d Class 0x%04x Mthd 0x%04x Data 0x%08x:0x%08x\n", - id, channel, subc, class, method, data2, data); + id, trap->channel, trap->subc, trap->class, trap->mthd, + trap->data2, trap->data); } static inline void nouveau_pgraph_intr_notify(struct drm_device *dev, uint32_t nsource) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_trap trap; int unhandled = 0; - if (nsource & NV03_PGRAPH_NSOURCE_NOTIFICATION && dev_priv->ttm) { - int channel; - if (!nouveau_graph_trapped_channel(dev, &channel)) { - nouveau_fence_handler(dev, channel); - } - } else - if (dev_priv->card_type == NV_04 && - (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) { - uint32_t class, mthd; + nouveau_graph_trap_info(dev, &trap); + if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { /* NV4 (nvidia TNT 1) reports software methods with * PGRAPH NOTIFY ILLEGAL_MTHD */ - mthd = NV_READ(NV04_PGRAPH_TRAPPED_ADDR) & 0x1FFC; - class = NV_READ(NV04_PGRAPH_CTX_SWITCH1) & 0xFFF; DRM_DEBUG("Got NV04 software method method %x for class %#x\n", - mthd, class); + trap.mthd, trap.class); - if (nouveau_sw_method_execute(dev, class, mthd)) { + if (nouveau_sw_method_execute(dev, trap.class, trap.mthd)) { DRM_ERROR("Unable to execute NV04 software method %x " "for object class %x. Please report.\n", - mthd, class); + trap.mthd, trap.class); unhandled = 1; } } else { @@ -329,13 +335,30 @@ nouveau_pgraph_intr_notify(struct drm_device *dev, uint32_t nsource) } if (unhandled) - nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY"); + nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap); } static inline void nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource) { - nouveau_graph_dump_trap_info(dev, "PGRAPH_ERROR"); + struct nouveau_pgraph_trap trap; + int unhandled = 0; + + nouveau_graph_trap_info(dev, &trap); + + if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { + if (trap.channel >= 0 && trap.mthd == 0x0150) { + nouveau_fence_handler(dev, trap.channel); + } else + if (nouveau_sw_method_execute(dev, trap.class, trap.mthd)) { + unhandled = 1; + } + } else { + unhandled = 1; + } + + if (unhandled) + nouveau_graph_dump_trap_info(dev, "PGRAPH_ERROR", &trap); } static inline void |