summaryrefslogtreecommitdiff
path: root/shared-core
diff options
context:
space:
mode:
Diffstat (limited to 'shared-core')
-rw-r--r--shared-core/nouveau_irq.c97
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