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"