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  | 
