svn commit: r289934 - head/sys/dev/drm2/i915

Jean-Sébastien Pédron dumbbell at FreeBSD.org
Sun Oct 25 14:42:58 UTC 2015


Author: dumbbell
Date: Sun Oct 25 14:42:56 2015
New Revision: 289934
URL: https://svnweb.freebsd.org/changeset/base/289934

Log:
  drm/i915: Reduce diff with Linux 3.8
  
  There is no functional change. The goal is to ease the future update to
  Linux 3.8's i915 driver.
  
  MFC after:	2 months

Modified:
  head/sys/dev/drm2/i915/i915_irq.c
  head/sys/dev/drm2/i915/intel_display.c

Modified: head/sys/dev/drm2/i915/i915_irq.c
==============================================================================
--- head/sys/dev/drm2/i915/i915_irq.c	Sun Oct 25 14:34:07 2015	(r289933)
+++ head/sys/dev/drm2/i915/i915_irq.c	Sun Oct 25 14:42:56 2015	(r289934)
@@ -132,8 +132,7 @@ i915_pipe_enabled(struct drm_device *dev
 /* Called from drm generic code, passed a 'crtc', which
  * we use as a pipe index
  */
-static u32
-i915_get_vblank_counter(struct drm_device *dev, int pipe)
+static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	unsigned long high_frame;
@@ -141,7 +140,7 @@ i915_get_vblank_counter(struct drm_devic
 	u32 high1, high2, low;
 
 	if (!i915_pipe_enabled(dev, pipe)) {
-		DRM_DEBUG("trying to get vblank count for disabled "
+		DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
 				"pipe %c\n", pipe_name(pipe));
 		return 0;
 	}
@@ -165,14 +164,13 @@ i915_get_vblank_counter(struct drm_devic
 	return (high1 << 8) | low;
 }
 
-static u32
-gm45_get_vblank_counter(struct drm_device *dev, int pipe)
+static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	int reg = PIPE_FRMCOUNT_GM45(pipe);
 
 	if (!i915_pipe_enabled(dev, pipe)) {
-		DRM_DEBUG("i915: trying to get vblank count for disabled "
+		DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
 				 "pipe %c\n", pipe_name(pipe));
 		return 0;
 	}
@@ -180,9 +178,8 @@ gm45_get_vblank_counter(struct drm_devic
 	return I915_READ(reg);
 }
 
-static int
-i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
-    int *vpos, int *hpos)
+static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
+			     int *vpos, int *hpos)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	u32 vbl = 0, position = 0;
@@ -191,7 +188,7 @@ i915_get_crtc_scanoutpos(struct drm_devi
 	int ret = 0;
 
 	if (!i915_pipe_enabled(dev, pipe)) {
-		DRM_DEBUG("i915: trying to get scanoutpos for disabled "
+		DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled "
 				 "pipe %c\n", pipe_name(pipe));
 		return 0;
 	}
@@ -247,9 +244,10 @@ i915_get_crtc_scanoutpos(struct drm_devi
 	return ret;
 }
 
-static int
-i915_get_vblank_timestamp(struct drm_device *dev, int pipe, int *max_error,
-    struct timeval *vblank_time, unsigned flags)
+static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
+			      int *max_error,
+			      struct timeval *vblank_time,
+			      unsigned flags)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc;
@@ -268,7 +266,7 @@ i915_get_vblank_timestamp(struct drm_dev
 
 	if (!crtc->enabled) {
 #if 0
-		DRM_DEBUG("crtc %d is disabled\n", pipe);
+		DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
 #endif
 		return -EBUSY;
 	}
@@ -282,19 +280,14 @@ i915_get_vblank_timestamp(struct drm_dev
 /*
  * Handle hotplug events outside the interrupt handler proper.
  */
-static void
-i915_hotplug_work_func(void *context, int pending)
+static void i915_hotplug_work_func(void *context, int pending)
 {
 	drm_i915_private_t *dev_priv = context;
 	struct drm_device *dev = dev_priv->dev;
-	struct drm_mode_config *mode_config;
+	struct drm_mode_config *mode_config = &dev->mode_config;
 	struct intel_encoder *encoder;
 
 	DRM_DEBUG("running encoder hotplug functions\n");
-	dev_priv = context;
-	dev = dev_priv->dev;
-
-	mode_config = &dev->mode_config;
 
 	sx_xlock(&mode_config->mutex);
 	DRM_DEBUG_KMS("running encoder hotplug functions\n");
@@ -350,29 +343,25 @@ static void notify_ring(struct drm_devic
 	if (ring->obj == NULL)
 		return;
 
-	CTR2(KTR_DRM, "request_complete %s %d", ring->name,
-	    ring->get_seqno(ring));
+	CTR2(KTR_DRM, "request_complete %s %d", ring->name, ring->get_seqno(ring));
 
 	mtx_lock(&dev_priv->irq_lock);
 	wakeup(ring);
 	mtx_unlock(&dev_priv->irq_lock);
-
 	if (i915_enable_hangcheck) {
 		dev_priv->hangcheck_count = 0;
 		callout_schedule(&dev_priv->hangcheck_timer,
-		    DRM_I915_HANGCHECK_PERIOD);
+			  DRM_I915_HANGCHECK_PERIOD);
 	}
 }
 
-static void
-gen6_pm_rps_work_func(void *arg, int pending)
+static void gen6_pm_rps_work(void *context, int pending)
 {
 	struct drm_device *dev;
-	drm_i915_private_t *dev_priv;
-	u8 new_delay;
+	drm_i915_private_t *dev_priv = context;
 	u32 pm_iir, pm_imr;
+	u8 new_delay;
 
-	dev_priv = (drm_i915_private_t *)arg;
 	dev = dev_priv->dev;
 	new_delay = dev_priv->cur_delay;
 
@@ -467,7 +456,7 @@ static void gen6_queue_rps_work(struct d
 	taskqueue_enqueue(dev_priv->tq, &dev_priv->rps_task);
 }
 
-static void valleyview_irq_handler(void *arg)
+static void valleyview_irq_handler(DRM_IRQ_ARGS)
 {
 	struct drm_device *dev = (struct drm_device *) arg;
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -518,7 +507,7 @@ static void valleyview_irq_handler(void 
 					 hotplug_status);
 			if (hotplug_status & dev_priv->hotplug_supported_mask)
 				taskqueue_enqueue(dev_priv->tq,
-				    &dev_priv->hotplug_task);
+					   &dev_priv->hotplug_task);
 
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
@@ -548,7 +537,8 @@ static void valleyview_irq_handler(void 
 		I915_WRITE(VLV_IIR, iir);
 	}
 
-out:;
+out:
+	return;
 }
 
 static void pch_irq_handler(struct drm_device *dev, u32 pch_iir)
@@ -557,42 +547,41 @@ static void pch_irq_handler(struct drm_d
 	int pipe;
 
 	if (pch_iir & SDE_AUDIO_POWER_MASK)
-		DRM_DEBUG("i915: PCH audio power change on port %d\n",
+		DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
 				 (pch_iir & SDE_AUDIO_POWER_MASK) >>
 				 SDE_AUDIO_POWER_SHIFT);
 
 	if (pch_iir & SDE_GMBUS)
-		DRM_DEBUG("i915: PCH GMBUS interrupt\n");
+		DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n");
 
 	if (pch_iir & SDE_AUDIO_HDCP_MASK)
-		DRM_DEBUG("i915: PCH HDCP audio interrupt\n");
+		DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n");
 
 	if (pch_iir & SDE_AUDIO_TRANS_MASK)
-		DRM_DEBUG("i915: PCH transcoder audio interrupt\n");
+		DRM_DEBUG_DRIVER("PCH transcoder audio interrupt\n");
 
 	if (pch_iir & SDE_POISON)
-		DRM_ERROR("i915: PCH poison interrupt\n");
+		DRM_ERROR("PCH poison interrupt\n");
 
 	if (pch_iir & SDE_FDI_MASK)
 		for_each_pipe(pipe)
-			DRM_DEBUG("  pipe %c FDI IIR: 0x%08x\n",
+			DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
 					 pipe_name(pipe),
 					 I915_READ(FDI_RX_IIR(pipe)));
 
 	if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE))
-		DRM_DEBUG("i915: PCH transcoder CRC done interrupt\n");
+		DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n");
 
 	if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR))
-		DRM_DEBUG("i915: PCH transcoder CRC error interrupt\n");
+		DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n");
 
 	if (pch_iir & SDE_TRANSB_FIFO_UNDER)
-		DRM_DEBUG("i915: PCH transcoder B underrun interrupt\n");
+		DRM_DEBUG_DRIVER("PCH transcoder B underrun interrupt\n");
 	if (pch_iir & SDE_TRANSA_FIFO_UNDER)
-		DRM_DEBUG("PCH transcoder A underrun interrupt\n");
+		DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
 }
 
-static void 
-ivybridge_irq_handler(void *arg)
+static void ivybridge_irq_handler(DRM_IRQ_ARGS)
 {
 	struct drm_device *dev = (struct drm_device *) arg;
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -606,7 +595,7 @@ ivybridge_irq_handler(void *arg)
 	I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
 	POSTING_READ(DEIER);
 
- 	gt_iir = I915_READ(GTIIR);
+	gt_iir = I915_READ(GTIIR);
 	if (gt_iir) {
 		snb_gt_irq_handler(dev, dev_priv, gt_iir);
 		I915_WRITE(GTIIR, gt_iir);
@@ -666,10 +655,9 @@ static void ilk_gt_irq_handler(struct dr
 		notify_ring(dev, &dev_priv->rings[VCS]);
 }
 
-static void
-ironlake_irq_handler(void *arg)
+static void ironlake_irq_handler(DRM_IRQ_ARGS)
 {
-	struct drm_device *dev = arg;
+	struct drm_device *dev = (struct drm_device *) arg;
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
 	u32 hotplug_mask;
@@ -703,9 +691,8 @@ ironlake_irq_handler(void *arg)
 	else
 		snb_gt_irq_handler(dev, dev_priv, gt_iir);
 
-	if (de_iir & DE_GSE) {
+	if (de_iir & DE_GSE)
 		intel_opregion_gse_intr(dev);
-	}
 
 	if (de_iir & DE_PLANEA_FLIP_DONE) {
 		intel_prepare_page_flip(dev, 0);
@@ -757,8 +744,7 @@ done:
  * Fire an error uevent so userspace can see that a hang or error
  * was detected.
  */
-static void
-i915_error_work_func(void *context, int pending)
+static void i915_error_work_func(void *context, int pending)
 {
 	drm_i915_private_t *dev_priv = context;
 	struct drm_device *dev = dev_priv->dev;
@@ -766,7 +752,7 @@ i915_error_work_func(void *context, int 
 	/* kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); */
 
 	if (atomic_load_acq_int(&dev_priv->mm.wedged)) {
-		DRM_DEBUG("i915: resetting chip\n");
+		DRM_DEBUG_DRIVER("resetting chip\n");
 		/* kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); */
 		if (!i915_reset(dev)) {
 			atomic_store_rel_int(&dev_priv->mm.wedged, 0);
@@ -779,1192 +765,1381 @@ i915_error_work_func(void *context, int 
 	}
 }
 
-#define pr_err(...) printf(__VA_ARGS__)
-
-static void i915_report_and_clear_eir(struct drm_device *dev)
+static struct drm_i915_error_object *
+i915_error_object_create(struct drm_i915_private *dev_priv,
+			 struct drm_i915_gem_object *src)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 eir = I915_READ(EIR);
-	int pipe;
+	struct drm_i915_error_object *dst;
+	struct sf_buf *sf;
+	void *d, *s;
+	int page, page_count;
+	u32 reloc_offset;
 
-	if (!eir)
-		return;
+	if (src == NULL || src->pages == NULL)
+		return NULL;
 
-	printf("i915: render error detected, EIR: 0x%08x\n", eir);
+	page_count = src->base.size / PAGE_SIZE;
 
-	if (IS_G4X(dev)) {
-		if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) {
-			u32 ipeir = I915_READ(IPEIR_I965);
+	dst = malloc(sizeof(*dst) + page_count * sizeof(u32 *), DRM_I915_GEM,
+	    M_NOWAIT);
+	if (dst == NULL)
+		return (NULL);
 
-			pr_err("  IPEIR: 0x%08x\n", I915_READ(IPEIR_I965));
-			pr_err("  IPEHR: 0x%08x\n", I915_READ(IPEHR_I965));
-			pr_err("  INSTDONE: 0x%08x\n",
-			       I915_READ(INSTDONE_I965));
-			pr_err("  INSTPS: 0x%08x\n", I915_READ(INSTPS));
-			pr_err("  INSTDONE1: 0x%08x\n", I915_READ(INSTDONE1));
-			pr_err("  ACTHD: 0x%08x\n", I915_READ(ACTHD_I965));
-			I915_WRITE(IPEIR_I965, ipeir);
-			POSTING_READ(IPEIR_I965);
-		}
-		if (eir & GM45_ERROR_PAGE_TABLE) {
-			u32 pgtbl_err = I915_READ(PGTBL_ER);
-			pr_err("page table error\n");
-			pr_err("  PGTBL_ER: 0x%08x\n", pgtbl_err);
-			I915_WRITE(PGTBL_ER, pgtbl_err);
-			POSTING_READ(PGTBL_ER);
-		}
-	}
+	reloc_offset = src->gtt_offset;
+	for (page = 0; page < page_count; page++) {
+		d = malloc(PAGE_SIZE, DRM_I915_GEM, M_NOWAIT);
+		if (d == NULL)
+			goto unwind;
 
-	if (!IS_GEN2(dev)) {
-		if (eir & I915_ERROR_PAGE_TABLE) {
-			u32 pgtbl_err = I915_READ(PGTBL_ER);
-			pr_err("page table error\n");
-			pr_err("  PGTBL_ER: 0x%08x\n", pgtbl_err);
-			I915_WRITE(PGTBL_ER, pgtbl_err);
-			POSTING_READ(PGTBL_ER);
+		if (reloc_offset < dev_priv->mm.gtt_mappable_end &&
+		    src->has_global_gtt_mapping) {
+			/* Simply ignore tiling or any overlapping fence.
+			 * It's part of the error state, and this hopefully
+			 * captures what the GPU read.
+			 */
+			s = pmap_mapdev_attr(src->base.dev->agp->base +
+			    reloc_offset, PAGE_SIZE, PAT_WRITE_COMBINING);
+			memcpy(d, s, PAGE_SIZE);
+			pmap_unmapdev((vm_offset_t)s, PAGE_SIZE);
+		} else {
+			drm_clflush_pages(&src->pages[page], 1);
+
+			sched_pin();
+			sf = sf_buf_alloc(src->pages[page], SFB_CPUPRIVATE |
+			    SFB_NOWAIT);
+			if (sf != NULL) {
+				s = (void *)(uintptr_t)sf_buf_kva(sf);
+				memcpy(d, s, PAGE_SIZE);
+				sf_buf_free(sf);
+			} else {
+				bzero(d, PAGE_SIZE);
+				strcpy(d, "XXXKIB");
+			}
+			sched_unpin();
+
+			drm_clflush_pages(&src->pages[page], 1);
 		}
-	}
 
-	if (eir & I915_ERROR_MEMORY_REFRESH) {
-		pr_err("memory refresh error:\n");
-		for_each_pipe(pipe)
-			pr_err("pipe %c stat: 0x%08x\n",
-			       pipe_name(pipe), I915_READ(PIPESTAT(pipe)));
-		/* pipestat has already been acked */
+		dst->pages[page] = d;
+
+		reloc_offset += PAGE_SIZE;
 	}
-	if (eir & I915_ERROR_INSTRUCTION) {
-		pr_err("instruction error\n");
-		pr_err("  INSTPM: 0x%08x\n", I915_READ(INSTPM));
-		if (INTEL_INFO(dev)->gen < 4) {
-			u32 ipeir = I915_READ(IPEIR);
+	dst->page_count = page_count;
+	dst->gtt_offset = src->gtt_offset;
 
-			pr_err("  IPEIR: 0x%08x\n", I915_READ(IPEIR));
-			pr_err("  IPEHR: 0x%08x\n", I915_READ(IPEHR));
-			pr_err("  INSTDONE: 0x%08x\n", I915_READ(INSTDONE));
-			pr_err("  ACTHD: 0x%08x\n", I915_READ(ACTHD));
-			I915_WRITE(IPEIR, ipeir);
-			POSTING_READ(IPEIR);
-		} else {
-			u32 ipeir = I915_READ(IPEIR_I965);
+	return dst;
 
-			pr_err("  IPEIR: 0x%08x\n", I915_READ(IPEIR_I965));
-			pr_err("  IPEHR: 0x%08x\n", I915_READ(IPEHR_I965));
-			pr_err("  INSTDONE: 0x%08x\n",
-			       I915_READ(INSTDONE_I965));
-			pr_err("  INSTPS: 0x%08x\n", I915_READ(INSTPS));
-			pr_err("  INSTDONE1: 0x%08x\n", I915_READ(INSTDONE1));
-			pr_err("  ACTHD: 0x%08x\n", I915_READ(ACTHD_I965));
-			I915_WRITE(IPEIR_I965, ipeir);
-			POSTING_READ(IPEIR_I965);
-		}
-	}
+unwind:
+	while (page--)
+		free(dst->pages[page], DRM_I915_GEM);
+	free(dst, DRM_I915_GEM);
+	return NULL;
+}
 
-	I915_WRITE(EIR, eir);
-	POSTING_READ(EIR);
-	eir = I915_READ(EIR);
-	if (eir) {
-		/*
-		 * some errors might have become stuck,
-		 * mask them.
-		 */
-		DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
-		I915_WRITE(EMR, I915_READ(EMR) | eir);
-		I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
-	}
+static void
+i915_error_object_free(struct drm_i915_error_object *obj)
+{
+	int page;
+
+	if (obj == NULL)
+		return;
+
+	for (page = 0; page < obj->page_count; page++)
+		free(obj->pages[page], DRM_I915_GEM);
+
+	free(obj, DRM_I915_GEM);
 }
 
-/**
- * i915_handle_error - handle an error interrupt
- * @dev: drm device
- *
- * Do some basic checking of regsiter state at error interrupt time and
- * dump it to the syslog.  Also call i915_capture_error_state() to make
- * sure we get a record and make it available in debugfs.  Fire a uevent
- * so userspace knows something bad happened (should trigger collection
- * of a ring dump etc.).
- */
-void i915_handle_error(struct drm_device *dev, bool wedged)
+void
+i915_error_state_free(struct drm_i915_error_state *error)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_ring_buffer *ring;
 	int i;
 
-	i915_capture_error_state(dev);
-	i915_report_and_clear_eir(dev);
+	for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
+		i915_error_object_free(error->ring[i].batchbuffer);
+		i915_error_object_free(error->ring[i].ringbuffer);
+		free(error->ring[i].requests, DRM_I915_GEM);
+	}
 
-	if (wedged) {
-		mtx_lock(&dev_priv->error_completion_lock);
-		dev_priv->error_completion = 0;
-		dev_priv->mm.wedged = 1;
-		/* unlock acts as rel barrier for store to wedged */
-		mtx_unlock(&dev_priv->error_completion_lock);
+	free(error->active_bo, DRM_I915_GEM);
+	free(error->overlay, DRM_I915_GEM);
+	free(error, DRM_I915_GEM);
+}
 
-		/*
-		 * Wakeup waiting processes so they don't hang
-		 */
-		for_each_ring(ring, dev_priv, i) {
-			mtx_lock(&dev_priv->irq_lock);
-			wakeup(ring);
-			mtx_unlock(&dev_priv->irq_lock);
-		}
+static void capture_bo(struct drm_i915_error_buffer *err,
+		       struct drm_i915_gem_object *obj)
+{
+	err->size = obj->base.size;
+	err->name = obj->base.name;
+	err->seqno = obj->last_rendering_seqno;
+	err->gtt_offset = obj->gtt_offset;
+	err->read_domains = obj->base.read_domains;
+	err->write_domain = obj->base.write_domain;
+	err->fence_reg = obj->fence_reg;
+	err->pinned = 0;
+	if (obj->pin_count > 0)
+		err->pinned = 1;
+	if (obj->user_pin_count > 0)
+		err->pinned = -1;
+	err->tiling = obj->tiling_mode;
+	err->dirty = obj->dirty;
+	err->purgeable = obj->madv != I915_MADV_WILLNEED;
+	err->ring = obj->ring ? obj->ring->id : -1;
+	err->cache_level = obj->cache_level;
+}
+
+static u32 capture_active_bo(struct drm_i915_error_buffer *err,
+			     int count, struct list_head *head)
+{
+	struct drm_i915_gem_object *obj;
+	int i = 0;
+
+	list_for_each_entry(obj, head, mm_list) {
+		capture_bo(err++, obj);
+		if (++i == count)
+			break;
 	}
 
-	taskqueue_enqueue(dev_priv->tq, &dev_priv->error_task);
+	return i;
 }
 
-static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
+static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
+			     int count, struct list_head *head)
 {
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_i915_gem_object *obj;
-	struct intel_unpin_work *work;
-	bool stall_detected;
+	int i = 0;
 
-	/* Ignore early vblank irqs */
-	if (intel_crtc == NULL)
-		return;
+	list_for_each_entry(obj, head, gtt_list) {
+		if (obj->pin_count == 0)
+			continue;
 
-	mtx_lock(&dev->event_lock);
-	work = intel_crtc->unpin_work;
-
-	if (work == NULL || work->pending || !work->enable_stall_check) {
-		/* Either the pending flip IRQ arrived, or we're too early. Don't check */
-		mtx_unlock(&dev->event_lock);
-		return;
-	}
-
-	/* Potential stall - if we see that the flip has happened, assume a missed interrupt */
-	obj = work->pending_flip_obj;
-	if (INTEL_INFO(dev)->gen >= 4) {
-		int dspsurf = DSPSURF(intel_crtc->plane);
-		stall_detected = I915_HI_DISPBASE(I915_READ(dspsurf)) ==
-					obj->gtt_offset;
-	} else {
-		int dspaddr = DSPADDR(intel_crtc->plane);
-		stall_detected = I915_READ(dspaddr) == (obj->gtt_offset +
-							crtc->y * crtc->fb->pitches[0] +
-							crtc->x * crtc->fb->bits_per_pixel/8);
+		capture_bo(err++, obj);
+		if (++i == count)
+			break;
 	}
 
-	mtx_unlock(&dev->event_lock);
-
-	if (stall_detected) {
-		DRM_DEBUG("Pageflip stall detected\n");
-		intel_prepare_page_flip(dev, intel_crtc->plane);
-	}
+	return i;
 }
 
-/* Called from drm generic code, passed 'crtc' which
- * we use as a pipe index
- */
-static int
-i915_enable_vblank(struct drm_device *dev, int pipe)
+static void i915_gem_record_fences(struct drm_device *dev,
+				   struct drm_i915_error_state *error)
 {
-	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-
-	if (!i915_pipe_enabled(dev, pipe))
-		return -EINVAL;
-
-	mtx_lock(&dev_priv->irq_lock);
-	if (INTEL_INFO(dev)->gen >= 4)
-		i915_enable_pipestat(dev_priv, pipe,
-				     PIPE_START_VBLANK_INTERRUPT_ENABLE);
-	else
-		i915_enable_pipestat(dev_priv, pipe,
-				     PIPE_VBLANK_INTERRUPT_ENABLE);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int i;
 
-	/* maintain vblank delivery even in deep C-states */
-	if (dev_priv->info->gen == 3)
-		I915_WRITE(INSTPM, _MASKED_BIT_DISABLE(INSTPM_AGPBUSY_DIS));
-	mtx_unlock(&dev_priv->irq_lock);
-	CTR1(KTR_DRM, "i915_enable_vblank %d", pipe);
+	/* Fences */
+	switch (INTEL_INFO(dev)->gen) {
+	case 7:
+	case 6:
+		for (i = 0; i < 16; i++)
+			error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
+		break;
+	case 5:
+	case 4:
+		for (i = 0; i < 16; i++)
+			error->fence[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
+		break;
+	case 3:
+		if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+			for (i = 0; i < 8; i++)
+				error->fence[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
+	case 2:
+		for (i = 0; i < 8; i++)
+			error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
+		break;
 
-	return 0;
+	}
 }
 
-static int
-ironlake_enable_vblank(struct drm_device *dev, int pipe)
+static struct drm_i915_error_object *
+i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
+			     struct intel_ring_buffer *ring)
 {
-	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-
-	if (!i915_pipe_enabled(dev, pipe))
-		return -EINVAL;
+	struct drm_i915_gem_object *obj;
+	u32 seqno;
 
-	mtx_lock(&dev_priv->irq_lock);
-	ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
-	    DE_PIPEA_VBLANK : DE_PIPEB_VBLANK);
-	mtx_unlock(&dev_priv->irq_lock);
-	CTR1(KTR_DRM, "ironlake_enable_vblank %d", pipe);
+	if (!ring->get_seqno)
+		return NULL;
 
-	return 0;
-}
+	seqno = ring->get_seqno(ring);
+	list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
+		if (obj->ring != ring)
+			continue;
 
-static int
-ivybridge_enable_vblank(struct drm_device *dev, int pipe)
-{
-	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+		if (i915_seqno_passed(seqno, obj->last_rendering_seqno))
+			continue;
 
-	if (!i915_pipe_enabled(dev, pipe))
-		return -EINVAL;
+		if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0)
+			continue;
 
-	mtx_lock(&dev_priv->irq_lock);
-	ironlake_enable_display_irq(dev_priv,
-				    DE_PIPEA_VBLANK_IVB << (5 * pipe));
-	mtx_unlock(&dev_priv->irq_lock);
-	CTR1(KTR_DRM, "ivybridge_enable_vblank %d", pipe);
+		/* We need to copy these to an anonymous buffer as the simplest
+		 * method to avoid being overwritten by userspace.
+		 */
+		return i915_error_object_create(dev_priv, obj);
+	}
 
-	return 0;
+	return NULL;
 }
 
-static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
+static void i915_record_ring_state(struct drm_device *dev,
+				   struct drm_i915_error_state *error,
+				   struct intel_ring_buffer *ring)
 {
-	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	u32 dpfl, imr;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (!i915_pipe_enabled(dev, pipe))
-		return -EINVAL;
+	if (INTEL_INFO(dev)->gen >= 6) {
+		error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring));
+		error->semaphore_mboxes[ring->id][0]
+			= I915_READ(RING_SYNC_0(ring->mmio_base));
+		error->semaphore_mboxes[ring->id][1]
+			= I915_READ(RING_SYNC_1(ring->mmio_base));
+	}
 
-	mtx_lock(&dev_priv->irq_lock);
-	dpfl = I915_READ(VLV_DPFLIPSTAT);
-	imr = I915_READ(VLV_IMR);
-	if (pipe == 0) {
-		dpfl |= PIPEA_VBLANK_INT_EN;
-		imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
+	if (INTEL_INFO(dev)->gen >= 4) {
+		error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base));
+		error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base));
+		error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base));
+		error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base));
+		error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base));
+		if (ring->id == RCS) {
+			error->instdone1 = I915_READ(INSTDONE1);
+			error->bbaddr = I915_READ64(BB_ADDR);
+		}
 	} else {
-		dpfl |= PIPEA_VBLANK_INT_EN;
-		imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+		error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX);
+		error->ipeir[ring->id] = I915_READ(IPEIR);
+		error->ipehr[ring->id] = I915_READ(IPEHR);
+		error->instdone[ring->id] = I915_READ(INSTDONE);
 	}
-	I915_WRITE(VLV_DPFLIPSTAT, dpfl);
-	I915_WRITE(VLV_IMR, imr);
-	mtx_unlock(&dev_priv->irq_lock);
 
-	return 0;
+	sleepq_lock(ring);
+	error->waiting[ring->id] = sleepq_sleepcnt(ring, 0) != 0;
+	sleepq_release(ring);
+	error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base));
+	error->seqno[ring->id] = ring->get_seqno(ring);
+	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->cpu_ring_head[ring->id] = ring->head;
+	error->cpu_ring_tail[ring->id] = ring->tail;
 }
 
-/* Called from drm generic code, passed 'crtc' which
- * we use as a pipe index
- */
-static void
-i915_disable_vblank(struct drm_device *dev, int pipe)
+static void i915_gem_record_rings(struct drm_device *dev,
+				  struct drm_i915_error_state *error)
 {
-	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_ring_buffer *ring;
+	struct drm_i915_gem_request *request;
+	int i, count;
 
-	mtx_lock(&dev_priv->irq_lock);
-	if (dev_priv->info->gen == 3)
-		I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_AGPBUSY_DIS));
+	for_each_ring(ring, dev_priv, i) {
+		i915_record_ring_state(dev, error, ring);
 
-	i915_disable_pipestat(dev_priv, pipe,
-	    PIPE_VBLANK_INTERRUPT_ENABLE |
-	    PIPE_START_VBLANK_INTERRUPT_ENABLE);
-	mtx_unlock(&dev_priv->irq_lock);
-	CTR1(KTR_DRM, "i915_disable_vblank %d", pipe);
-}
+		error->ring[i].batchbuffer =
+			i915_error_first_batchbuffer(dev_priv, ring);
 
-static void
-ironlake_disable_vblank(struct drm_device *dev, int pipe)
-{
-	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+		error->ring[i].ringbuffer =
+			i915_error_object_create(dev_priv, ring->obj);
 
-	mtx_lock(&dev_priv->irq_lock);
-	ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
-	    DE_PIPEA_VBLANK : DE_PIPEB_VBLANK);
-	mtx_unlock(&dev_priv->irq_lock);
-	CTR1(KTR_DRM, "ironlake_disable_vblank %d", pipe);
-}
+		count = 0;
+		list_for_each_entry(request, &ring->request_list, list)
+			count++;
 
-static void
-ivybridge_disable_vblank(struct drm_device *dev, int pipe)
-{
-	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+		error->ring[i].num_requests = count;
+		error->ring[i].requests =
+			malloc(count*sizeof(struct drm_i915_error_request),
+				DRM_I915_GEM, M_WAITOK);
+		if (error->ring[i].requests == NULL) {
+			error->ring[i].num_requests = 0;
+			continue;
+		}
 
-	mtx_lock(&dev_priv->irq_lock);
-	ironlake_disable_display_irq(dev_priv,
-				     DE_PIPEA_VBLANK_IVB << (pipe * 5));
-	mtx_unlock(&dev_priv->irq_lock);
-	CTR1(KTR_DRM, "ivybridge_disable_vblank %d", pipe);
+		count = 0;
+		list_for_each_entry(request, &ring->request_list, list) {
+			struct drm_i915_error_request *erq;
+
+			erq = &error->ring[i].requests[count++];
+			erq->seqno = request->seqno;
+			erq->jiffies = request->emitted_jiffies;
+			erq->tail = request->tail;
+		}
+	}
 }
 
-static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
+static void i915_capture_error_state(struct drm_device *dev)
 {
-	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	u32 dpfl, imr;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_gem_object *obj;
+	struct drm_i915_error_state *error;
+	int i, pipe;
 
-	mtx_lock(&dev_priv->irq_lock);
-	dpfl = I915_READ(VLV_DPFLIPSTAT);
-	imr = I915_READ(VLV_IMR);
-	if (pipe == 0) {
-		dpfl &= ~PIPEA_VBLANK_INT_EN;
-		imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
-	} else {
-		dpfl &= ~PIPEB_VBLANK_INT_EN;
-		imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+	mtx_lock(&dev_priv->error_lock);
+	error = dev_priv->first_error;
+	mtx_unlock(&dev_priv->error_lock);
+	if (error)
+		return;
+
+	/* Account for pipe specific data like PIPE*STAT */
+	error = malloc(sizeof(*error), DRM_I915_GEM, M_NOWAIT | M_ZERO);
+	if (!error) {
+		DRM_DEBUG_DRIVER("out of memory, not capturing error state\n");
+		return;
 	}
-	I915_WRITE(VLV_IMR, imr);
-	I915_WRITE(VLV_DPFLIPSTAT, dpfl);
-	mtx_unlock(&dev_priv->irq_lock);
-}
 
-static u32
-ring_last_seqno(struct intel_ring_buffer *ring)
-{
+	DRM_INFO("capturing error event; look for more information in sysctl hw.dri.%d.info.i915_error_state\n",
+		 dev->sysctl_node_idx);
 
-	if (list_empty(&ring->request_list))
-		return (0);
-	else
-		return (list_entry(ring->request_list.prev,
-		    struct drm_i915_gem_request, list)->seqno);
-}
+	refcount_init(&error->ref, 1);
+	error->eir = I915_READ(EIR);
+	error->pgtbl_er = I915_READ(PGTBL_ER);
 
-static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
-{
-	if (list_empty(&ring->request_list) ||
-	    i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) {
-		/* Issue a wake-up to catch stuck h/w. */
-		sleepq_lock(ring);
-		if (sleepq_sleepcnt(ring, 0) != 0) {
-			sleepq_release(ring);
-			DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
-				  ring->name);
-			wakeup(ring);
-			*err = true;
-		} else
-			sleepq_release(ring);
-		return true;
-	}
-	return false;
-}
-
-static bool kick_ring(struct intel_ring_buffer *ring)
-{
-	struct drm_device *dev = ring->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 tmp = I915_READ_CTL(ring);
-	if (tmp & RING_WAIT) {
-		DRM_ERROR("Kicking stuck wait on %s\n",
-			  ring->name);
-		I915_WRITE_CTL(ring, tmp);
-		return true;
-	}
-	return false;
-}
-
-static bool i915_hangcheck_hung(struct drm_device *dev)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-
-	if (dev_priv->hangcheck_count++ > 1) {
-		bool hung = true;
-
-		DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
-		i915_handle_error(dev, true);
-
-		if (!IS_GEN2(dev)) {
-			struct intel_ring_buffer *ring;
-			int i;
+	if (HAS_PCH_SPLIT(dev))
+		error->ier = I915_READ(DEIER) | I915_READ(GTIER);
+	else if (IS_VALLEYVIEW(dev))
+		error->ier = I915_READ(GTIER) | I915_READ(VLV_IER);
+	else if (IS_GEN2(dev))
+		error->ier = I915_READ16(IER);
+	else
+		error->ier = I915_READ(IER);
 
-			/* Is the chip hanging on a WAIT_FOR_EVENT?
-			 * If so we can simply poke the RB_WAIT bit
-			 * and break the hang. This should work on
-			 * all but the second generation chipsets.
-			 */
-			for_each_ring(ring, dev_priv, i)
-				hung &= !kick_ring(ring);
-		}
+	for_each_pipe(pipe)
+		error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
 
-		return hung;
+	if (INTEL_INFO(dev)->gen >= 6) {
+		error->error = I915_READ(ERROR_GEN6);
+		error->done_reg = I915_READ(DONE_REG);
 	}
 
-	return false;
-}
+	i915_gem_record_fences(dev, error);
+	i915_gem_record_rings(dev, error);
 
-/**
- * This is called when the chip hasn't reported back with completed
- * batchbuffers in a long time. The first time this is called we simply record
- * ACTHD. If ACTHD hasn't changed by the time the hangcheck timer elapses
- * again, we assume the chip is wedged and try to fix it.
- */
-void
-i915_hangcheck_elapsed(void *context)
-{
-	struct drm_device *dev = (struct drm_device *)context;
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	uint32_t acthd[I915_NUM_RINGS], instdone, instdone1;
-	struct intel_ring_buffer *ring;
-	bool err = false, idle;
-	int i;
+	/* Record buffers on the active and pinned lists. */
+	error->active_bo = NULL;
+	error->pinned_bo = NULL;
 
-	if (!i915_enable_hangcheck)
-		return;
+	i = 0;
+	list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list)
+		i++;
+	error->active_bo_count = i;
+	list_for_each_entry(obj, &dev_priv->mm.gtt_list, mm_list)
+		if (obj->pin_count)
+			i++;
+	error->pinned_bo_count = i - error->active_bo_count;
 
-	memset(acthd, 0, sizeof(acthd));
-	idle = true;
-	for_each_ring(ring, dev_priv, i) {
-	    idle &= i915_hangcheck_ring_idle(ring, &err);
-	    acthd[i] = intel_ring_get_active_head(ring);
+	error->active_bo = NULL;
+	error->pinned_bo = NULL;
+	if (i) {
+		error->active_bo = malloc(sizeof(*error->active_bo)*i,
+					   DRM_I915_GEM, M_NOWAIT);
+		if (error->active_bo)
+			error->pinned_bo =
+				error->active_bo + error->active_bo_count;
 	}
 
-	/* If all work is done then ACTHD clearly hasn't advanced. */
-	if (idle) {
-		if (err) {

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list