diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
| -rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 391 | 
1 files changed, 261 insertions, 130 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a4dc97f8b9f..2cd97d1cc92 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -287,6 +287,10 @@ static void i915_hotplug_work_func(struct work_struct *work)  	struct drm_mode_config *mode_config = &dev->mode_config;  	struct intel_encoder *encoder; +	/* HPD irq before everything is fully set up. */ +	if (!dev_priv->enable_hotplug_processing) +		return; +  	mutex_lock(&mode_config->mutex);  	DRM_DEBUG_KMS("running encoder hotplug functions\n"); @@ -300,9 +304,6 @@ static void i915_hotplug_work_func(struct work_struct *work)  	drm_helper_hpd_irq_event(dev);  } -/* defined intel_pm.c */ -extern spinlock_t mchdev_lock; -  static void ironlake_handle_rps_change(struct drm_device *dev)  {  	drm_i915_private_t *dev_priv = dev->dev_private; @@ -355,8 +356,8 @@ static void notify_ring(struct drm_device *dev,  	wake_up_all(&ring->irq_queue);  	if (i915_enable_hangcheck) { -		dev_priv->hangcheck_count = 0; -		mod_timer(&dev_priv->hangcheck_timer, +		dev_priv->gpu_error.hangcheck_count = 0; +		mod_timer(&dev_priv->gpu_error.hangcheck_timer,  			  round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));  	}  } @@ -524,6 +525,20 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,  	queue_work(dev_priv->wq, &dev_priv->rps.work);  } +static void gmbus_irq_handler(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; + +	wake_up_all(&dev_priv->gmbus_wait_queue); +} + +static void dp_aux_irq_handler(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; + +	wake_up_all(&dev_priv->gmbus_wait_queue); +} +  static irqreturn_t valleyview_irq_handler(int irq, void *arg)  {  	struct drm_device *dev = (struct drm_device *) arg; @@ -533,7 +548,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)  	unsigned long irqflags;  	int pipe;  	u32 pipe_stats[I915_MAX_PIPES]; -	bool blc_event;  	atomic_inc(&dev_priv->irq_received); @@ -590,8 +604,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)  			I915_READ(PORT_HOTPLUG_STAT);  		} -		if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) -			blc_event = true; +		if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) +			gmbus_irq_handler(dev);  		if (pm_iir & GEN6_PM_DEFERRED_EVENTS)  			gen6_queue_rps_work(dev_priv, pm_iir); @@ -618,8 +632,11 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)  				 (pch_iir & SDE_AUDIO_POWER_MASK) >>  				 SDE_AUDIO_POWER_SHIFT); +	if (pch_iir & SDE_AUX_MASK) +		dp_aux_irq_handler(dev); +  	if (pch_iir & SDE_GMBUS) -		DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n"); +		gmbus_irq_handler(dev);  	if (pch_iir & SDE_AUDIO_HDCP_MASK)  		DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n"); @@ -662,10 +679,10 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)  				 SDE_AUDIO_POWER_SHIFT_CPT);  	if (pch_iir & SDE_AUX_MASK_CPT) -		DRM_DEBUG_DRIVER("AUX channel interrupt\n"); +		dp_aux_irq_handler(dev);  	if (pch_iir & SDE_GMBUS_CPT) -		DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n"); +		gmbus_irq_handler(dev);  	if (pch_iir & SDE_AUDIO_CP_REQ_CPT)  		DRM_DEBUG_DRIVER("Audio CP request interrupt\n"); @@ -703,6 +720,9 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)  	de_iir = I915_READ(DEIIR);  	if (de_iir) { +		if (de_iir & DE_AUX_CHANNEL_A_IVB) +			dp_aux_irq_handler(dev); +  		if (de_iir & DE_GSE_IVB)  			intel_opregion_gse_intr(dev); @@ -758,7 +778,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)  	struct drm_device *dev = (struct drm_device *) arg;  	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;  	int ret = IRQ_NONE; -	u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; +	u32 de_iir, gt_iir, de_ier, pm_iir;  	atomic_inc(&dev_priv->irq_received); @@ -769,11 +789,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)  	de_iir = I915_READ(DEIIR);  	gt_iir = I915_READ(GTIIR); -	pch_iir = I915_READ(SDEIIR);  	pm_iir = I915_READ(GEN6_PMIIR); -	if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && -	    (!IS_GEN6(dev) || pm_iir == 0)) +	if (de_iir == 0 && gt_iir == 0 && (!IS_GEN6(dev) || pm_iir == 0))  		goto done;  	ret = IRQ_HANDLED; @@ -783,6 +801,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)  	else  		snb_gt_irq_handler(dev, dev_priv, gt_iir); +	if (de_iir & DE_AUX_CHANNEL_A) +		dp_aux_irq_handler(dev); +  	if (de_iir & DE_GSE)  		intel_opregion_gse_intr(dev); @@ -804,10 +825,15 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)  	/* check event from PCH */  	if (de_iir & DE_PCH_EVENT) { +		u32 pch_iir = I915_READ(SDEIIR); +  		if (HAS_PCH_CPT(dev))  			cpt_irq_handler(dev, pch_iir);  		else  			ibx_irq_handler(dev, pch_iir); + +		/* should clear PCH hotplug event before clear CPU irq */ +		I915_WRITE(SDEIIR, pch_iir);  	}  	if (IS_GEN5(dev) &&  de_iir & DE_PCU_EVENT) @@ -816,8 +842,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)  	if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS)  		gen6_queue_rps_work(dev_priv, pm_iir); -	/* should clear PCH hotplug event before clear CPU irq */ -	I915_WRITE(SDEIIR, pch_iir);  	I915_WRITE(GTIIR, gt_iir);  	I915_WRITE(DEIIR, de_iir);  	I915_WRITE(GEN6_PMIIR, pm_iir); @@ -838,23 +862,60 @@ done:   */  static void i915_error_work_func(struct work_struct *work)  { -	drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, -						    error_work); +	struct i915_gpu_error *error = container_of(work, struct i915_gpu_error, +						    work); +	drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t, +						    gpu_error);  	struct drm_device *dev = dev_priv->dev; +	struct intel_ring_buffer *ring;  	char *error_event[] = { "ERROR=1", NULL };  	char *reset_event[] = { "RESET=1", NULL };  	char *reset_done_event[] = { "ERROR=0", NULL }; +	int i, ret;  	kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); -	if (atomic_read(&dev_priv->mm.wedged)) { +	/* +	 * Note that there's only one work item which does gpu resets, so we +	 * need not worry about concurrent gpu resets potentially incrementing +	 * error->reset_counter twice. We only need to take care of another +	 * racing irq/hangcheck declaring the gpu dead for a second time. A +	 * quick check for that is good enough: schedule_work ensures the +	 * correct ordering between hang detection and this work item, and since +	 * the reset in-progress bit is only ever set by code outside of this +	 * work we don't need to worry about any other races. +	 */ +	if (i915_reset_in_progress(error) && !i915_terminally_wedged(error)) {  		DRM_DEBUG_DRIVER("resetting chip\n"); -		kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); -		if (!i915_reset(dev)) { -			atomic_set(&dev_priv->mm.wedged, 0); -			kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); +		kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, +				   reset_event); + +		ret = i915_reset(dev); + +		if (ret == 0) { +			/* +			 * After all the gem state is reset, increment the reset +			 * counter and wake up everyone waiting for the reset to +			 * complete. +			 * +			 * Since unlock operations are a one-sided barrier only, +			 * we need to insert a barrier here to order any seqno +			 * updates before +			 * the counter increment. +			 */ +			smp_mb__before_atomic_inc(); +			atomic_inc(&dev_priv->gpu_error.reset_counter); + +			kobject_uevent_env(&dev->primary->kdev.kobj, +					   KOBJ_CHANGE, reset_done_event); +		} else { +			atomic_set(&error->reset_counter, I915_WEDGED);  		} -		complete_all(&dev_priv->error_completion); + +		for_each_ring(ring, dev_priv, i) +			wake_up_all(&ring->irq_queue); + +		wake_up_all(&dev_priv->gpu_error.reset_queue);  	}  } @@ -915,7 +976,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv,  			goto unwind;  		local_irq_save(flags); -		if (reloc_offset < dev_priv->mm.gtt_mappable_end && +		if (reloc_offset < dev_priv->gtt.mappable_end &&  		    src->has_global_gtt_mapping) {  			void __iomem *s; @@ -924,10 +985,18 @@ i915_error_object_create(struct drm_i915_private *dev_priv,  			 * captures what the GPU read.  			 */ -			s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, +			s = io_mapping_map_atomic_wc(dev_priv->gtt.mappable,  						     reloc_offset);  			memcpy_fromio(d, s, PAGE_SIZE);  			io_mapping_unmap_atomic(s); +		} else if (src->stolen) { +			unsigned long offset; + +			offset = dev_priv->mm.stolen_base; +			offset += src->stolen->start; +			offset += i << PAGE_SHIFT; + +			memcpy_fromio(d, (void __iomem *) offset, PAGE_SIZE);  		} else {  			struct page *page;  			void *s; @@ -1074,6 +1143,8 @@ static void i915_gem_record_fences(struct drm_device *dev,  			error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4));  		break; +	default: +		BUG();  	}  } @@ -1087,6 +1158,18 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,  	if (!ring->get_seqno)  		return NULL; +	if (HAS_BROKEN_CS_TLB(dev_priv->dev)) { +		u32 acthd = I915_READ(ACTHD); + +		if (WARN_ON(ring->id != RCS)) +			return NULL; + +		obj = ring->private; +		if (acthd >= obj->gtt_offset && +		    acthd < obj->gtt_offset + obj->base.size) +			return i915_error_object_create(dev_priv, obj); +	} +  	seqno = ring->get_seqno(ring, false);  	list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {  		if (obj->ring != ring) @@ -1145,6 +1228,7 @@ static void i915_record_ring_state(struct drm_device *dev,  	error->acthd[ring->id] = intel_ring_get_active_head(ring);  	error->head[ring->id] = I915_READ_HEAD(ring);  	error->tail[ring->id] = I915_READ_TAIL(ring); +	error->ctl[ring->id] = I915_READ_CTL(ring);  	error->cpu_ring_head[ring->id] = ring->head;  	error->cpu_ring_tail[ring->id] = ring->tail; @@ -1209,9 +1293,9 @@ static void i915_capture_error_state(struct drm_device *dev)  	unsigned long flags;  	int i, pipe; -	spin_lock_irqsave(&dev_priv->error_lock, flags); -	error = dev_priv->first_error; -	spin_unlock_irqrestore(&dev_priv->error_lock, flags); +	spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); +	error = dev_priv->gpu_error.first_error; +	spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);  	if (error)  		return; @@ -1222,7 +1306,8 @@ static void i915_capture_error_state(struct drm_device *dev)  		return;  	} -	DRM_INFO("capturing error event; look for more information in /debug/dri/%d/i915_error_state\n", +	DRM_INFO("capturing error event; look for more information in" +		 "/sys/kernel/debug/dri/%d/i915_error_state\n",  		 dev->primary->index);  	kref_init(&error->ref); @@ -1239,6 +1324,16 @@ static void i915_capture_error_state(struct drm_device *dev)  	else  		error->ier = I915_READ(IER); +	if (INTEL_INFO(dev)->gen >= 6) +		error->derrmr = I915_READ(DERRMR); + +	if (IS_VALLEYVIEW(dev)) +		error->forcewake = I915_READ(FORCEWAKE_VLV); +	else if (INTEL_INFO(dev)->gen >= 7) +		error->forcewake = I915_READ(FORCEWAKE_MT); +	else if (INTEL_INFO(dev)->gen == 6) +		error->forcewake = I915_READ(FORCEWAKE); +  	for_each_pipe(pipe)  		error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); @@ -1295,12 +1390,12 @@ static void i915_capture_error_state(struct drm_device *dev)  	error->overlay = intel_overlay_capture_error_state(dev);  	error->display = intel_display_capture_error_state(dev); -	spin_lock_irqsave(&dev_priv->error_lock, flags); -	if (dev_priv->first_error == NULL) { -		dev_priv->first_error = error; +	spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); +	if (dev_priv->gpu_error.first_error == NULL) { +		dev_priv->gpu_error.first_error = error;  		error = NULL;  	} -	spin_unlock_irqrestore(&dev_priv->error_lock, flags); +	spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);  	if (error)  		i915_error_state_free(&error->ref); @@ -1312,10 +1407,10 @@ void i915_destroy_error_state(struct drm_device *dev)  	struct drm_i915_error_state *error;  	unsigned long flags; -	spin_lock_irqsave(&dev_priv->error_lock, flags); -	error = dev_priv->first_error; -	dev_priv->first_error = NULL; -	spin_unlock_irqrestore(&dev_priv->error_lock, flags); +	spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); +	error = dev_priv->gpu_error.first_error; +	dev_priv->gpu_error.first_error = NULL; +	spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);  	if (error)  		kref_put(&error->ref, i915_error_state_free); @@ -1436,17 +1531,18 @@ void i915_handle_error(struct drm_device *dev, bool wedged)  	i915_report_and_clear_eir(dev);  	if (wedged) { -		INIT_COMPLETION(dev_priv->error_completion); -		atomic_set(&dev_priv->mm.wedged, 1); +		atomic_set_mask(I915_RESET_IN_PROGRESS_FLAG, +				&dev_priv->gpu_error.reset_counter);  		/* -		 * Wakeup waiting processes so they don't hang +		 * Wakeup waiting processes so that the reset work item +		 * doesn't deadlock trying to grab various locks.  		 */  		for_each_ring(ring, dev_priv, i)  			wake_up_all(&ring->irq_queue);  	} -	queue_work(dev_priv->wq, &dev_priv->error_work); +	queue_work(dev_priv->wq, &dev_priv->gpu_error.work);  }  static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) @@ -1677,7 +1773,7 @@ static bool i915_hangcheck_hung(struct drm_device *dev)  {  	drm_i915_private_t *dev_priv = dev->dev_private; -	if (dev_priv->hangcheck_count++ > 1) { +	if (dev_priv->gpu_error.hangcheck_count++ > 1) {  		bool hung = true;  		DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); @@ -1736,25 +1832,29 @@ void i915_hangcheck_elapsed(unsigned long data)  			goto repeat;  		} -		dev_priv->hangcheck_count = 0; +		dev_priv->gpu_error.hangcheck_count = 0;  		return;  	}  	i915_get_extra_instdone(dev, instdone); -	if (memcmp(dev_priv->last_acthd, acthd, sizeof(acthd)) == 0 && -	    memcmp(dev_priv->prev_instdone, instdone, sizeof(instdone)) == 0) { +	if (memcmp(dev_priv->gpu_error.last_acthd, acthd, +		   sizeof(acthd)) == 0 && +	    memcmp(dev_priv->gpu_error.prev_instdone, instdone, +		   sizeof(instdone)) == 0) {  		if (i915_hangcheck_hung(dev))  			return;  	} else { -		dev_priv->hangcheck_count = 0; +		dev_priv->gpu_error.hangcheck_count = 0; -		memcpy(dev_priv->last_acthd, acthd, sizeof(acthd)); -		memcpy(dev_priv->prev_instdone, instdone, sizeof(instdone)); +		memcpy(dev_priv->gpu_error.last_acthd, acthd, +		       sizeof(acthd)); +		memcpy(dev_priv->gpu_error.prev_instdone, instdone, +		       sizeof(instdone));  	}  repeat:  	/* Reset timer case chip hangs without another request being added */ -	mod_timer(&dev_priv->hangcheck_timer, +	mod_timer(&dev_priv->gpu_error.hangcheck_timer,  		  round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));  } @@ -1824,7 +1924,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev)   * This register is the same on all known PCH chips.   */ -static void ironlake_enable_pch_hotplug(struct drm_device *dev) +static void ibx_enable_hotplug(struct drm_device *dev)  {  	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;  	u32	hotplug; @@ -1837,14 +1937,36 @@ static void ironlake_enable_pch_hotplug(struct drm_device *dev)  	I915_WRITE(PCH_PORT_HOTPLUG, hotplug);  } +static void ibx_irq_postinstall(struct drm_device *dev) +{ +	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	u32 mask; + +	if (HAS_PCH_IBX(dev)) +		mask = SDE_HOTPLUG_MASK | +		       SDE_GMBUS | +		       SDE_AUX_MASK; +	else +		mask = SDE_HOTPLUG_MASK_CPT | +		       SDE_GMBUS_CPT | +		       SDE_AUX_MASK_CPT; + +	I915_WRITE(SDEIIR, I915_READ(SDEIIR)); +	I915_WRITE(SDEIMR, ~mask); +	I915_WRITE(SDEIER, mask); +	POSTING_READ(SDEIER); + +	ibx_enable_hotplug(dev); +} +  static int ironlake_irq_postinstall(struct drm_device *dev)  {  	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;  	/* enable kind of interrupts always enabled */  	u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | -			   DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE; +			   DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | +			   DE_AUX_CHANNEL_A;  	u32 render_irqs; -	u32 hotplug_mask;  	dev_priv->irq_mask = ~display_mask; @@ -1872,27 +1994,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)  	I915_WRITE(GTIER, render_irqs);  	POSTING_READ(GTIER); -	if (HAS_PCH_CPT(dev)) { -		hotplug_mask = (SDE_CRT_HOTPLUG_CPT | -				SDE_PORTB_HOTPLUG_CPT | -				SDE_PORTC_HOTPLUG_CPT | -				SDE_PORTD_HOTPLUG_CPT); -	} else { -		hotplug_mask = (SDE_CRT_HOTPLUG | -				SDE_PORTB_HOTPLUG | -				SDE_PORTC_HOTPLUG | -				SDE_PORTD_HOTPLUG | -				SDE_AUX_MASK); -	} - -	dev_priv->pch_irq_mask = ~hotplug_mask; - -	I915_WRITE(SDEIIR, I915_READ(SDEIIR)); -	I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); -	I915_WRITE(SDEIER, hotplug_mask); -	POSTING_READ(SDEIER); - -	ironlake_enable_pch_hotplug(dev); +	ibx_irq_postinstall(dev);  	if (IS_IRONLAKE_M(dev)) {  		/* Clear & enable PCU event interrupts */ @@ -1912,9 +2014,9 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)  		DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB |  		DE_PLANEC_FLIP_DONE_IVB |  		DE_PLANEB_FLIP_DONE_IVB | -		DE_PLANEA_FLIP_DONE_IVB; +		DE_PLANEA_FLIP_DONE_IVB | +		DE_AUX_CHANNEL_A_IVB;  	u32 render_irqs; -	u32 hotplug_mask;  	dev_priv->irq_mask = ~display_mask; @@ -1938,18 +2040,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)  	I915_WRITE(GTIER, render_irqs);  	POSTING_READ(GTIER); -	hotplug_mask = (SDE_CRT_HOTPLUG_CPT | -			SDE_PORTB_HOTPLUG_CPT | -			SDE_PORTC_HOTPLUG_CPT | -			SDE_PORTD_HOTPLUG_CPT); -	dev_priv->pch_irq_mask = ~hotplug_mask; - -	I915_WRITE(SDEIIR, I915_READ(SDEIIR)); -	I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); -	I915_WRITE(SDEIER, hotplug_mask); -	POSTING_READ(SDEIER); - -	ironlake_enable_pch_hotplug(dev); +	ibx_irq_postinstall(dev);  	return 0;  } @@ -1958,7 +2049,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)  {  	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;  	u32 enable_mask; -	u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);  	u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;  	u32 render_irqs;  	u16 msid; @@ -1987,6 +2077,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev)  	msid |= (1<<14);  	pci_write_config_word(dev_priv->dev->pdev, 0x98, msid); +	I915_WRITE(PORT_HOTPLUG_EN, 0); +	POSTING_READ(PORT_HOTPLUG_EN); +  	I915_WRITE(VLV_IMR, dev_priv->irq_mask);  	I915_WRITE(VLV_IER, enable_mask);  	I915_WRITE(VLV_IIR, 0xffffffff); @@ -1995,6 +2088,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)  	POSTING_READ(VLV_IER);  	i915_enable_pipestat(dev_priv, 0, pipestat_enable); +	i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);  	i915_enable_pipestat(dev_priv, 1, pipestat_enable);  	I915_WRITE(VLV_IIR, 0xffffffff); @@ -2015,13 +2109,22 @@ static int valleyview_irq_postinstall(struct drm_device *dev)  #endif  	I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE); + +	return 0; +} + +static void valleyview_hpd_irq_setup(struct drm_device *dev) +{ +	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); +  	/* Note HDMI and DP share bits */ -	if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) -		hotplug_en |= HDMIB_HOTPLUG_INT_EN; -	if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) -		hotplug_en |= HDMIC_HOTPLUG_INT_EN; -	if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) -		hotplug_en |= HDMID_HOTPLUG_INT_EN; +	if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) +		hotplug_en |= PORTB_HOTPLUG_INT_EN; +	if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) +		hotplug_en |= PORTC_HOTPLUG_INT_EN; +	if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) +		hotplug_en |= PORTD_HOTPLUG_INT_EN;  	if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)  		hotplug_en |= SDVOC_HOTPLUG_INT_EN;  	if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) @@ -2032,8 +2135,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)  	}  	I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); - -	return 0;  }  static void valleyview_irq_uninstall(struct drm_device *dev) @@ -2263,6 +2364,9 @@ static int i915_irq_postinstall(struct drm_device *dev)  		I915_USER_INTERRUPT;  	if (I915_HAS_HOTPLUG(dev)) { +		I915_WRITE(PORT_HOTPLUG_EN, 0); +		POSTING_READ(PORT_HOTPLUG_EN); +  		/* Enable in IER... */  		enable_mask |= I915_DISPLAY_PORT_INTERRUPT;  		/* and unmask in IMR */ @@ -2273,15 +2377,25 @@ static int i915_irq_postinstall(struct drm_device *dev)  	I915_WRITE(IER, enable_mask);  	POSTING_READ(IER); +	intel_opregion_enable_asle(dev); + +	return 0; +} + +static void i915_hpd_irq_setup(struct drm_device *dev) +{ +	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	u32 hotplug_en; +  	if (I915_HAS_HOTPLUG(dev)) { -		u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); +		hotplug_en = I915_READ(PORT_HOTPLUG_EN); -		if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) -			hotplug_en |= HDMIB_HOTPLUG_INT_EN; -		if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) -			hotplug_en |= HDMIC_HOTPLUG_INT_EN; -		if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) -			hotplug_en |= HDMID_HOTPLUG_INT_EN; +		if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) +			hotplug_en |= PORTB_HOTPLUG_INT_EN; +		if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) +			hotplug_en |= PORTC_HOTPLUG_INT_EN; +		if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) +			hotplug_en |= PORTD_HOTPLUG_INT_EN;  		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)  			hotplug_en |= SDVOC_HOTPLUG_INT_EN;  		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) @@ -2295,10 +2409,6 @@ static int i915_irq_postinstall(struct drm_device *dev)  		I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);  	} - -	intel_opregion_enable_asle(dev); - -	return 0;  }  static irqreturn_t i915_irq_handler(int irq, void *arg) @@ -2458,7 +2568,6 @@ static void i965_irq_preinstall(struct drm_device * dev)  static int i965_irq_postinstall(struct drm_device *dev)  {  	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -	u32 hotplug_en;  	u32 enable_mask;  	u32 error_mask; @@ -2479,6 +2588,7 @@ static int i965_irq_postinstall(struct drm_device *dev)  	dev_priv->pipestat[0] = 0;  	dev_priv->pipestat[1] = 0; +	i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);  	/*  	 * Enable some error detection, note the instruction error mask @@ -2499,14 +2609,27 @@ static int i965_irq_postinstall(struct drm_device *dev)  	I915_WRITE(IER, enable_mask);  	POSTING_READ(IER); +	I915_WRITE(PORT_HOTPLUG_EN, 0); +	POSTING_READ(PORT_HOTPLUG_EN); + +	intel_opregion_enable_asle(dev); + +	return 0; +} + +static void i965_hpd_irq_setup(struct drm_device *dev) +{ +	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	u32 hotplug_en; +  	/* Note HDMI and DP share hotplug bits */  	hotplug_en = 0; -	if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) -		hotplug_en |= HDMIB_HOTPLUG_INT_EN; -	if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) -		hotplug_en |= HDMIC_HOTPLUG_INT_EN; -	if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) -		hotplug_en |= HDMID_HOTPLUG_INT_EN; +	if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) +		hotplug_en |= PORTB_HOTPLUG_INT_EN; +	if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) +		hotplug_en |= PORTC_HOTPLUG_INT_EN; +	if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) +		hotplug_en |= PORTD_HOTPLUG_INT_EN;  	if (IS_G4X(dev)) {  		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X)  			hotplug_en |= SDVOC_HOTPLUG_INT_EN; @@ -2533,10 +2656,6 @@ static int i965_irq_postinstall(struct drm_device *dev)  	/* Ignore TV since it's buggy */  	I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); - -	intel_opregion_enable_asle(dev); - -	return 0;  }  static irqreturn_t i965_irq_handler(int irq, void *arg) @@ -2632,6 +2751,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)  		if (blc_event || (iir & I915_ASLE_INTERRUPT))  			intel_opregion_asle_intr(dev); +		if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) +			gmbus_irq_handler(dev); +  		/* With MSI, interrupts are only generated when iir  		 * transitions from zero to nonzero.  If another bit got  		 * set while we were handling the existing iir bits, then @@ -2683,10 +2805,16 @@ void intel_irq_init(struct drm_device *dev)  	struct drm_i915_private *dev_priv = dev->dev_private;  	INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); -	INIT_WORK(&dev_priv->error_work, i915_error_work_func); +	INIT_WORK(&dev_priv->gpu_error.work, i915_error_work_func);  	INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);  	INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); +	setup_timer(&dev_priv->gpu_error.hangcheck_timer, +		    i915_hangcheck_elapsed, +		    (unsigned long) dev); + +	pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); +  	dev->driver->get_vblank_counter = i915_get_vblank_counter;  	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */  	if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { @@ -2707,7 +2835,8 @@ void intel_irq_init(struct drm_device *dev)  		dev->driver->irq_uninstall = valleyview_irq_uninstall;  		dev->driver->enable_vblank = valleyview_enable_vblank;  		dev->driver->disable_vblank = valleyview_disable_vblank; -	} else if (IS_IVYBRIDGE(dev)) { +		dev_priv->display.hpd_irq_setup = valleyview_hpd_irq_setup; +	} else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {  		/* Share pre & uninstall handlers with ILK/SNB */  		dev->driver->irq_handler = ivybridge_irq_handler;  		dev->driver->irq_preinstall = ironlake_irq_preinstall; @@ -2715,14 +2844,6 @@ void intel_irq_init(struct drm_device *dev)  		dev->driver->irq_uninstall = ironlake_irq_uninstall;  		dev->driver->enable_vblank = ivybridge_enable_vblank;  		dev->driver->disable_vblank = ivybridge_disable_vblank; -	} else if (IS_HASWELL(dev)) { -		/* Share interrupts handling with IVB */ -		dev->driver->irq_handler = ivybridge_irq_handler; -		dev->driver->irq_preinstall = ironlake_irq_preinstall; -		dev->driver->irq_postinstall = ivybridge_irq_postinstall; -		dev->driver->irq_uninstall = ironlake_irq_uninstall; -		dev->driver->enable_vblank = ivybridge_enable_vblank; -		dev->driver->disable_vblank = ivybridge_disable_vblank;  	} else if (HAS_PCH_SPLIT(dev)) {  		dev->driver->irq_handler = ironlake_irq_handler;  		dev->driver->irq_preinstall = ironlake_irq_preinstall; @@ -2741,13 +2862,23 @@ void intel_irq_init(struct drm_device *dev)  			dev->driver->irq_postinstall = i915_irq_postinstall;  			dev->driver->irq_uninstall = i915_irq_uninstall;  			dev->driver->irq_handler = i915_irq_handler; +			dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;  		} else {  			dev->driver->irq_preinstall = i965_irq_preinstall;  			dev->driver->irq_postinstall = i965_irq_postinstall;  			dev->driver->irq_uninstall = i965_irq_uninstall;  			dev->driver->irq_handler = i965_irq_handler; +			dev_priv->display.hpd_irq_setup = i965_hpd_irq_setup;  		}  		dev->driver->enable_vblank = i915_enable_vblank;  		dev->driver->disable_vblank = i915_disable_vblank;  	}  } + +void intel_hpd_init(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; + +	if (dev_priv->display.hpd_irq_setup) +		dev_priv->display.hpd_irq_setup(dev); +}  |