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 ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to