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