drm/i915: Update to Linux 3.11
authorFrançois Tigeot <ftigeot@wolfpond.org>
Sat, 21 Feb 2015 16:35:50 +0000 (17:35 +0100)
committerFrançois Tigeot <ftigeot@wolfpond.org>
Sat, 21 Feb 2015 16:37:41 +0000 (17:37 +0100)
* Valleyview/Baytrail support improvements. Baytrail support is
  no longer considered experimental.

* VECS engine support on Haswell. The Video Enhancement Command
  Streamer is used by libva for some post-processing tasks.

* Power management improvements, especially on Haswell.

* Hotplug improvements.

* Output and modeset improvements. Using 30bpp modes is now possible.

* Various bugfixes and Stability improvements, including memory
  corruption and GPU hang fixes after a suspend/resume sequence.

v2: i915_irq.c lock ordering fix, reported by zrj@

v3: backlight spinlock fixes from Romick

36 files changed:
sys/dev/drm/i915/Makefile
sys/dev/drm/i915/i915_debugfs.c
sys/dev/drm/i915/i915_dma.c
sys/dev/drm/i915/i915_drv.c
sys/dev/drm/i915/i915_drv.h
sys/dev/drm/i915/i915_gem.c
sys/dev/drm/i915/i915_gem_context.c
sys/dev/drm/i915/i915_gem_execbuffer.c
sys/dev/drm/i915/i915_gem_gtt.c
sys/dev/drm/i915/i915_gem_stolen.c
sys/dev/drm/i915/i915_gem_tiling.c
sys/dev/drm/i915/i915_irq.c
sys/dev/drm/i915/i915_reg.h
sys/dev/drm/i915/i915_suspend.c
sys/dev/drm/i915/i915_trace.h
sys/dev/drm/i915/i915_ums.c
sys/dev/drm/i915/intel_acpi.c [new file with mode: 0644]
sys/dev/drm/i915/intel_bios.c
sys/dev/drm/i915/intel_crt.c
sys/dev/drm/i915/intel_ddi.c
sys/dev/drm/i915/intel_display.c
sys/dev/drm/i915/intel_dp.c
sys/dev/drm/i915/intel_drv.h
sys/dev/drm/i915/intel_fb.c
sys/dev/drm/i915/intel_hdmi.c
sys/dev/drm/i915/intel_lvds.c
sys/dev/drm/i915/intel_opregion.c
sys/dev/drm/i915/intel_overlay.c
sys/dev/drm/i915/intel_panel.c
sys/dev/drm/i915/intel_pm.c
sys/dev/drm/i915/intel_ringbuffer.c
sys/dev/drm/i915/intel_ringbuffer.h
sys/dev/drm/i915/intel_sdvo.c
sys/dev/drm/i915/intel_sideband.c [new file with mode: 0644]
sys/dev/drm/i915/intel_sprite.c
sys/dev/drm/i915/intel_tv.c

index b4821d5..e655eaa 100644 (file)
@@ -13,6 +13,7 @@ SRCS  = \
        i915_irq.c \
        i915_suspend.c \
        i915_ums.c \
+       intel_acpi.c \
        intel_bios.c \
        intel_crt.c \
        intel_ddi.c \
@@ -24,6 +25,7 @@ SRCS  = \
        intel_lvds.c \
        intel_modes.c \
        intel_opregion.c \
+       intel_sideband.c \
        intel_overlay.c \
        intel_panel.c \
        intel_pm.c \
index 059000a..b07aee7 100644 (file)
@@ -57,11 +57,11 @@ static int i915_capabilities(struct seq_file *m, void *data)
 
        seq_printf(m, "gen: %d\n", info->gen);
        seq_printf(m, "pch: %d\n", INTEL_PCH_TYPE(dev));
-#define DEV_INFO_FLAG(x) seq_printf(m, #x ": %s\n", yesno(info->x))
-#define DEV_INFO_SEP ;
-       DEV_INFO_FLAGS;
-#undef DEV_INFO_FLAG
-#undef DEV_INFO_SEP
+#define PRINT_FLAG(x)  seq_printf(m, #x ": %s\n", yesno(info->x))
+#define SEP_SEMICOLON ;
+       DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG, SEP_SEMICOLON);
+#undef PRINT_FLAG
+#undef SEP_SEMICOLON
 
        return 0;
 }
@@ -192,6 +192,32 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
        } \
 } while (0)
 
+struct file_stats {
+       int count;
+       size_t total, active, inactive, unbound;
+};
+
+static int per_file_stats(int id, void *ptr, void *data)
+{
+       struct drm_i915_gem_object *obj = ptr;
+       struct file_stats *stats = data;
+
+       stats->count++;
+       stats->total += obj->base.size;
+
+       if (obj->gtt_space) {
+               if (!list_empty(&obj->ring_list))
+                       stats->active += obj->base.size;
+               else
+                       stats->inactive += obj->base.size;
+       } else {
+               if (!list_empty(&obj->global_list))
+                       stats->unbound += obj->base.size;
+       }
+
+       return 0;
+}
+
 static int i915_gem_object_info(struct seq_file *m, void* data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -200,6 +226,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
        u32 count, mappable_count, purgeable_count;
        size_t size, mappable_size, purgeable_size;
        struct drm_i915_gem_object *obj;
+       struct drm_file *file;
        int ret;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -211,7 +238,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
                   dev_priv->mm.object_memory);
 
        size = count = mappable_size = mappable_count = 0;
-       count_objects(&dev_priv->mm.bound_list, gtt_list);
+       count_objects(&dev_priv->mm.bound_list, global_list);
        seq_printf(m, "%u [%u] objects, %zu [%zu] bytes in gtt\n",
                   count, mappable_count, size, mappable_size);
 
@@ -226,7 +253,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
                   count, mappable_count, size, mappable_size);
 
        size = count = purgeable_size = purgeable_count = 0;
-       list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list) {
+       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) {
                size += obj->base.size, ++count;
                if (obj->madv == I915_MADV_DONTNEED)
                        purgeable_size += obj->base.size, ++purgeable_count;
@@ -234,7 +261,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
        seq_printf(m, "%u unbound objects, %zu bytes\n", count, size);
 
        size = count = mappable_size = mappable_count = 0;
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                if (obj->fault_mappable) {
                        size += obj->gtt_space->size;
                        ++count;
@@ -259,6 +286,21 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
                   dev_priv->gtt.total,
                   dev_priv->gtt.mappable_end - dev_priv->gtt.start);
 
+       seq_printf(m, "\n");
+       list_for_each_entry_reverse(file, &dev->filelist, lhead) {
+               struct file_stats stats;
+
+               memset(&stats, 0, sizeof(stats));
+               idr_for_each(&file->object_idr, per_file_stats, &stats);
+               seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu unbound)\n",
+                          get_pid_task(file->pid, PIDTYPE_PID)->comm,
+                          stats.count,
+                          stats.total,
+                          stats.active,
+                          stats.inactive,
+                          stats.unbound);
+       }
+
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -279,7 +321,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void* data)
                return ret;
 
        total_obj_size = total_gtt_size = count = 0;
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                if (list == PINNED_LIST && obj->pin_count == 0)
                        continue;
 
@@ -566,6 +608,7 @@ static const char *ring_str(int ring)
        case RCS: return "render";
        case VCS: return "bsd";
        case BCS: return "blt";
+       case VECS: return "vebox";
        default: return "";
        }
 }
@@ -600,73 +643,187 @@ static const char *purgeable_flag(int purgeable)
        return purgeable ? " purgeable" : "";
 }
 
-static void print_error_buffers(struct seq_file *m,
+static bool __i915_error_ok(struct drm_i915_error_state_buf *e)
+{
+
+       if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) {
+               e->err = -ENOSPC;
+               return false;
+       }
+
+       if (e->bytes == e->size - 1 || e->err)
+               return false;
+
+       return true;
+}
+
+static bool __i915_error_seek(struct drm_i915_error_state_buf *e,
+                             unsigned len)
+{
+       if (e->pos + len <= e->start) {
+               e->pos += len;
+               return false;
+       }
+
+       /* First vsnprintf needs to fit in its entirety for memmove */
+       if (len >= e->size) {
+               e->err = -EIO;
+               return false;
+       }
+
+       return true;
+}
+
+static void __i915_error_advance(struct drm_i915_error_state_buf *e,
+                                unsigned len)
+{
+       /* If this is first printf in this window, adjust it so that
+        * start position matches start of the buffer
+        */
+
+       if (e->pos < e->start) {
+               const size_t off = e->start - e->pos;
+
+               /* Should not happen but be paranoid */
+               if (off > len || e->bytes) {
+                       e->err = -EIO;
+                       return;
+               }
+
+               memmove(e->buf, e->buf + off, len - off);
+               e->bytes = len - off;
+               e->pos = e->start;
+               return;
+       }
+
+       e->bytes += len;
+       e->pos += len;
+}
+
+static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
+                              const char *f, va_list args)
+{
+       unsigned len;
+
+       if (!__i915_error_ok(e))
+               return;
+
+       /* Seek the first printf which is hits start position */
+       if (e->pos < e->start) {
+               len = vsnprintf(NULL, 0, f, args);
+               if (!__i915_error_seek(e, len))
+                       return;
+       }
+
+       len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args);
+       if (len >= e->size - e->bytes)
+               len = e->size - e->bytes - 1;
+
+       __i915_error_advance(e, len);
+}
+
+static void i915_error_puts(struct drm_i915_error_state_buf *e,
+                           const char *str)
+{
+       unsigned len;
+
+       if (!__i915_error_ok(e))
+               return;
+
+       len = strlen(str);
+
+       /* Seek the first printf which is hits start position */
+       if (e->pos < e->start) {
+               if (!__i915_error_seek(e, len))
+                       return;
+       }
+
+       if (len >= e->size - e->bytes)
+               len = e->size - e->bytes - 1;
+       memcpy(e->buf + e->bytes, str, len);
+
+       __i915_error_advance(e, len);
+}
+
+void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
+{
+       va_list args;
+
+       va_start(args, f);
+       i915_error_vprintf(e, f, args);
+       va_end(args);
+}
+
+#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
+#define err_puts(e, s) i915_error_puts(e, s)
+
+static void print_error_buffers(struct drm_i915_error_state_buf *m,
                                const char *name,
                                struct drm_i915_error_buffer *err,
                                int count)
 {
-       seq_printf(m, "%s [%d]:\n", name, count);
+       err_printf(m, "%s [%d]:\n", name, count);
 
        while (count--) {
-               seq_printf(m, "  %08x %8u %02x %02x %x %x%s%s%s%s%s%s%s",
+               err_printf(m, "  %08x %8u %02x %02x %x %x",
                           err->gtt_offset,
                           err->size,
                           err->read_domains,
                           err->write_domain,
-                          err->rseqno, err->wseqno,
-                          pin_flag(err->pinned),
-                          tiling_flag(err->tiling),
-                          dirty_flag(err->dirty),
-                          purgeable_flag(err->purgeable),
-                          err->ring != -1 ? " " : "",
-                          ring_str(err->ring),
-                          cache_level_str(err->cache_level));
+                          err->rseqno, err->wseqno);
+               err_puts(m, pin_flag(err->pinned));
+               err_puts(m, tiling_flag(err->tiling));
+               err_puts(m, dirty_flag(err->dirty));
+               err_puts(m, purgeable_flag(err->purgeable));
+               err_puts(m, err->ring != -1 ? " " : "");
+               err_puts(m, ring_str(err->ring));
+               err_puts(m, cache_level_str(err->cache_level));
 
                if (err->name)
-                       seq_printf(m, " (name: %d)", err->name);
+                       err_printf(m, " (name: %d)", err->name);
                if (err->fence_reg != I915_FENCE_REG_NONE)
-                       seq_printf(m, " (fence: %d)", err->fence_reg);
+                       err_printf(m, " (fence: %d)", err->fence_reg);
 
-               seq_printf(m, "\n");
+               err_puts(m, "\n");
                err++;
        }
 }
 
-static void i915_ring_error_state(struct seq_file *m,
+static void i915_ring_error_state(struct drm_i915_error_state_buf *m,
                                  struct drm_device *dev,
                                  struct drm_i915_error_state *error,
                                  unsigned ring)
 {
        BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */
-       seq_printf(m, "%s command stream:\n", ring_str(ring));
-       seq_printf(m, "  HEAD: 0x%08x\n", error->head[ring]);
-       seq_printf(m, "  TAIL: 0x%08x\n", error->tail[ring]);
-       seq_printf(m, "  CTL: 0x%08x\n", error->ctl[ring]);
-       seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd[ring]);
-       seq_printf(m, "  IPEIR: 0x%08x\n", error->ipeir[ring]);
-       seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr[ring]);
-       seq_printf(m, "  INSTDONE: 0x%08x\n", error->instdone[ring]);
+       err_printf(m, "%s command stream:\n", ring_str(ring));
+       err_printf(m, "  HEAD: 0x%08x\n", error->head[ring]);
+       err_printf(m, "  TAIL: 0x%08x\n", error->tail[ring]);
+       err_printf(m, "  CTL: 0x%08x\n", error->ctl[ring]);
+       err_printf(m, "  ACTHD: 0x%08x\n", error->acthd[ring]);
+       err_printf(m, "  IPEIR: 0x%08x\n", error->ipeir[ring]);
+       err_printf(m, "  IPEHR: 0x%08x\n", error->ipehr[ring]);
+       err_printf(m, "  INSTDONE: 0x%08x\n", error->instdone[ring]);
        if (ring == RCS && INTEL_INFO(dev)->gen >= 4)
-               seq_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr);
+               err_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr);
 
        if (INTEL_INFO(dev)->gen >= 4)
-               seq_printf(m, "  INSTPS: 0x%08x\n", error->instps[ring]);
-       seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
-       seq_printf(m, "  FADDR: 0x%08x\n", error->faddr[ring]);
+               err_printf(m, "  INSTPS: 0x%08x\n", error->instps[ring]);
+       err_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
+       err_printf(m, "  FADDR: 0x%08x\n", error->faddr[ring]);
        if (INTEL_INFO(dev)->gen >= 6) {
-               seq_printf(m, "  RC PSMI: 0x%08x\n", error->rc_psmi[ring]);
-               seq_printf(m, "  FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
-               seq_printf(m, "  SYNC_0: 0x%08x [last synced 0x%08x]\n",
+               err_printf(m, "  RC PSMI: 0x%08x\n", error->rc_psmi[ring]);
+               err_printf(m, "  FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
+               err_printf(m, "  SYNC_0: 0x%08x [last synced 0x%08x]\n",
                           error->semaphore_mboxes[ring][0],
                           error->semaphore_seqno[ring][0]);
-               seq_printf(m, "  SYNC_1: 0x%08x [last synced 0x%08x]\n",
+               err_printf(m, "  SYNC_1: 0x%08x [last synced 0x%08x]\n",
                           error->semaphore_mboxes[ring][1],
                           error->semaphore_seqno[ring][1]);
        }
-       seq_printf(m, "  seqno: 0x%08x\n", error->seqno[ring]);
-       seq_printf(m, "  waiting: %s\n", yesno(error->waiting[ring]));
-       seq_printf(m, "  ring->head: 0x%08x\n", error->cpu_ring_head[ring]);
-       seq_printf(m, "  ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]);
+       err_printf(m, "  seqno: 0x%08x\n", error->seqno[ring]);
+       err_printf(m, "  waiting: %s\n", yesno(error->waiting[ring]));
+       err_printf(m, "  ring->head: 0x%08x\n", error->cpu_ring_head[ring]);
+       err_printf(m, "  ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]);
 }
 
 struct i915_error_state_file_priv {
@@ -674,9 +831,11 @@ struct i915_error_state_file_priv {
        struct drm_i915_error_state *error;
 };
 
-static int i915_error_state(struct seq_file *m, void *unused)
+
+static int i915_error_state(struct i915_error_state_file_priv *error_priv,
+                           struct drm_i915_error_state_buf *m)
+
 {
-       struct i915_error_state_file_priv *error_priv = m->private;
        struct drm_device *dev = error_priv->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_error_state *error = error_priv->error;
@@ -684,34 +843,35 @@ static int i915_error_state(struct seq_file *m, void *unused)
        int i, j, page, offset, elt;
 
        if (!error) {
-               seq_printf(m, "no error state collected\n");
+               err_printf(m, "no error state collected\n");
                return 0;
        }
 
-       seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
+       err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
                   error->time.tv_usec);
-       seq_printf(m, "Kernel: " UTS_RELEASE "\n");
-       seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
-       seq_printf(m, "EIR: 0x%08x\n", error->eir);
-       seq_printf(m, "IER: 0x%08x\n", error->ier);
-       seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
-       seq_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake);
-       seq_printf(m, "DERRMR: 0x%08x\n", error->derrmr);
-       seq_printf(m, "CCID: 0x%08x\n", error->ccid);
+       err_printf(m, "Kernel: " UTS_RELEASE "\n");
+       err_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
+       err_printf(m, "EIR: 0x%08x\n", error->eir);
+       err_printf(m, "IER: 0x%08x\n", error->ier);
+       err_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
+       err_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake);
+       err_printf(m, "DERRMR: 0x%08x\n", error->derrmr);
+       err_printf(m, "CCID: 0x%08x\n", error->ccid);
 
        for (i = 0; i < dev_priv->num_fence_regs; i++)
-               seq_printf(m, "  fence[%d] = %08llx\n", i, error->fence[i]);
+               err_printf(m, "  fence[%d] = %08llx\n", i, error->fence[i]);
 
        for (i = 0; i < ARRAY_SIZE(error->extra_instdone); i++)
-               seq_printf(m, "  INSTDONE_%d: 0x%08x\n", i, error->extra_instdone[i]);
+               err_printf(m, "  INSTDONE_%d: 0x%08x\n", i,
+                          error->extra_instdone[i]);
 
        if (INTEL_INFO(dev)->gen >= 6) {
-               seq_printf(m, "ERROR: 0x%08x\n", error->error);
-               seq_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
+               err_printf(m, "ERROR: 0x%08x\n", error->error);
+               err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
        }
 
        if (INTEL_INFO(dev)->gen == 7)
-               seq_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
+               err_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
 
        for_each_ring(ring, dev_priv, i)
                i915_ring_error_state(m, dev, error, i);
@@ -730,24 +890,25 @@ static int i915_error_state(struct seq_file *m, void *unused)
                struct drm_i915_error_object *obj;
 
                if ((obj = error->ring[i].batchbuffer)) {
-                       seq_printf(m, "%s --- gtt_offset = 0x%08x\n",
+                       err_printf(m, "%s --- gtt_offset = 0x%08x\n",
                                   dev_priv->ring[i].name,
                                   obj->gtt_offset);
                        offset = 0;
                        for (page = 0; page < obj->page_count; page++) {
                                for (elt = 0; elt < PAGE_SIZE/4; elt++) {
-                                       seq_printf(m, "%08x :  %08x\n", offset, obj->pages[page][elt]);
+                                       err_printf(m, "%08x :  %08x\n", offset,
+                                                  obj->pages[page][elt]);
                                        offset += 4;
                                }
                        }
                }
 
                if (error->ring[i].num_requests) {
-                       seq_printf(m, "%s --- %d requests\n",
+                       err_printf(m, "%s --- %d requests\n",
                                   dev_priv->ring[i].name,
                                   error->ring[i].num_requests);
                        for (j = 0; j < error->ring[i].num_requests; j++) {
-                               seq_printf(m, "  seqno 0x%08x, emitted %ld, tail 0x%08x\n",
+                               err_printf(m, "  seqno 0x%08x, emitted %ld, tail 0x%08x\n",
                                           error->ring[i].requests[j].seqno,
                                           error->ring[i].requests[j].jiffies,
                                           error->ring[i].requests[j].tail);
@@ -755,13 +916,13 @@ static int i915_error_state(struct seq_file *m, void *unused)
                }
 
                if ((obj = error->ring[i].ringbuffer)) {
-                       seq_printf(m, "%s --- ringbuffer = 0x%08x\n",
+                       err_printf(m, "%s --- ringbuffer = 0x%08x\n",
                                   dev_priv->ring[i].name,
                                   obj->gtt_offset);
                        offset = 0;
                        for (page = 0; page < obj->page_count; page++) {
                                for (elt = 0; elt < PAGE_SIZE/4; elt++) {
-                                       seq_printf(m, "%08x :  %08x\n",
+                                       err_printf(m, "%08x :  %08x\n",
                                                   offset,
                                                   obj->pages[page][elt]);
                                        offset += 4;
@@ -771,12 +932,12 @@ static int i915_error_state(struct seq_file *m, void *unused)
 
                obj = error->ring[i].ctx;
                if (obj) {
-                       seq_printf(m, "%s --- HW Context = 0x%08x\n",
+                       err_printf(m, "%s --- HW Context = 0x%08x\n",
                                   dev_priv->ring[i].name,
                                   obj->gtt_offset);
                        offset = 0;
                        for (elt = 0; elt < PAGE_SIZE/16; elt += 4) {
-                               seq_printf(m, "[%04x] %08x %08x %08x %08x\n",
+                               err_printf(m, "[%04x] %08x %08x %08x %08x\n",
                                           offset,
                                           obj->pages[0][elt],
                                           obj->pages[0][elt+1],
@@ -802,8 +963,7 @@ i915_error_state_write(struct file *filp,
                       size_t cnt,
                       loff_t *ppos)
 {
-       struct seq_file *m = filp->private_data;
-       struct i915_error_state_file_priv *error_priv = m->private;
+       struct i915_error_state_file_priv *error_priv = filp->private_data;
        struct drm_device *dev = error_priv->dev;
        int ret;
 
@@ -838,25 +998,81 @@ static int i915_error_state_open(struct inode *inode, struct file *file)
                kref_get(&error_priv->error->ref);
        spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
 
-       return single_open(file, i915_error_state, error_priv);
+       file->private_data = error_priv;
+
+       return 0;
 }
 
 static int i915_error_state_release(struct inode *inode, struct file *file)
 {
-       struct seq_file *m = file->private_data;
-       struct i915_error_state_file_priv *error_priv = m->private;
+       struct i915_error_state_file_priv *error_priv = file->private_data;
 
        if (error_priv->error)
                kref_put(&error_priv->error->ref, i915_error_state_free);
        kfree(error_priv);
 
-       return single_release(inode, file);
+       return 0;
+}
+
+static ssize_t i915_error_state_read(struct file *file, char __user *userbuf,
+                                    size_t count, loff_t *pos)
+{
+       struct i915_error_state_file_priv *error_priv = file->private_data;
+       struct drm_i915_error_state_buf error_str;
+       loff_t tmp_pos = 0;
+       ssize_t ret_count = 0;
+       int ret = 0;
+
+       memset(&error_str, 0, sizeof(error_str));
+
+       /* We need to have enough room to store any i915_error_state printf
+        * so that we can move it to start position.
+        */
+       error_str.size = count + 1 > PAGE_SIZE ? count + 1 : PAGE_SIZE;
+       error_str.buf = kmalloc(error_str.size,
+                               GFP_TEMPORARY | __GFP_NORETRY | __GFP_NOWARN);
+
+       if (error_str.buf == NULL) {
+               error_str.size = PAGE_SIZE;
+               error_str.buf = kmalloc(error_str.size, GFP_TEMPORARY);
+       }
+
+       if (error_str.buf == NULL) {
+               error_str.size = 128;
+               error_str.buf = kmalloc(error_str.size, GFP_TEMPORARY);
+       }
+
+       if (error_str.buf == NULL)
+               return -ENOMEM;
+
+       error_str.start = *pos;
+
+       ret = i915_error_state(error_priv, &error_str);
+       if (ret)
+               goto out;
+
+       if (error_str.bytes == 0 && error_str.err) {
+               ret = error_str.err;
+               goto out;
+       }
+
+       ret_count = simple_read_from_buffer(userbuf, count, &tmp_pos,
+                                           error_str.buf,
+                                           error_str.bytes);
+
+       if (ret_count < 0)
+               ret = ret_count;
+       else
+               *pos = error_str.start + ret_count;
+out:
+       kfree(error_str.buf);
+       return ret ?: ret_count;
 }
 
 static const struct file_operations i915_error_state_fops = {
        .owner = THIS_MODULE,
        .open = i915_error_state_open,
-       .read = seq_read,
+       .read = i915_error_state_read,
        .write = i915_error_state_write,
        .llseek = default_llseek,
        .release = i915_error_state_release,
@@ -937,7 +1153,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                           MEMSTAT_VID_SHIFT);
                seq_printf(m, "Current P-state: %d\n",
                           (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
-       } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
+       } else if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) {
                u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
                u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
                u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
@@ -1005,6 +1221,26 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
 
                seq_printf(m, "Max overclocked frequency: %dMHz\n",
                           dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER);
+       } else if (IS_VALLEYVIEW(dev)) {
+               u32 freq_sts, val;
+
+               mutex_lock(&dev_priv->rps.hw_lock);
+               freq_sts = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
+               seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts);
+               seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq);
+
+               val = vlv_punit_read(dev_priv, PUNIT_FUSE_BUS1);
+               seq_printf(m, "max GPU freq: %d MHz\n",
+                          vlv_gpu_freq(dev_priv->mem_freq, val));
+
+               val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM);
+               seq_printf(m, "min GPU freq: %d MHz\n",
+                          vlv_gpu_freq(dev_priv->mem_freq, val));
+
+               seq_printf(m, "current GPU freq: %d MHz\n",
+                          vlv_gpu_freq(dev_priv->mem_freq,
+                                       (freq_sts >> 8) & 0xff));
+               mutex_unlock(&dev_priv->rps.hw_lock);
        } else {
                seq_printf(m, "no P-state info available\n");
        }
@@ -1286,6 +1522,25 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
        return 0;
 }
 
+static int i915_ips_status(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!HAS_IPS(dev)) {
+               seq_puts(m, "not supported\n");
+               return 0;
+       }
+
+       if (I915_READ(IPS_CTL) & IPS_ENABLE)
+               seq_puts(m, "enabled\n");
+       else
+               seq_puts(m, "disabled\n");
+
+       return 0;
+}
+
 static int i915_sr_status(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -1638,27 +1893,27 @@ static int i915_dpio_info(struct seq_file *m, void *data)
        seq_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL));
 
        seq_printf(m, "DPIO_DIV_A: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_DIV_A));
+                  vlv_dpio_read(dev_priv, _DPIO_DIV_A));
        seq_printf(m, "DPIO_DIV_B: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_DIV_B));
+                  vlv_dpio_read(dev_priv, _DPIO_DIV_B));
 
        seq_printf(m, "DPIO_REFSFR_A: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_REFSFR_A));
+                  vlv_dpio_read(dev_priv, _DPIO_REFSFR_A));
        seq_printf(m, "DPIO_REFSFR_B: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_REFSFR_B));
+                  vlv_dpio_read(dev_priv, _DPIO_REFSFR_B));
 
        seq_printf(m, "DPIO_CORE_CLK_A: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_CORE_CLK_A));
+                  vlv_dpio_read(dev_priv, _DPIO_CORE_CLK_A));
        seq_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_CORE_CLK_B));
+                  vlv_dpio_read(dev_priv, _DPIO_CORE_CLK_B));
 
-       seq_printf(m, "DPIO_LFP_COEFF_A: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_LFP_COEFF_A));
-       seq_printf(m, "DPIO_LFP_COEFF_B: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_LFP_COEFF_B));
+       seq_printf(m, "DPIO_LPF_COEFF_A: 0x%08x\n",
+                  vlv_dpio_read(dev_priv, _DPIO_LPF_COEFF_A));
+       seq_printf(m, "DPIO_LPF_COEFF_B: 0x%08x\n",
+                  vlv_dpio_read(dev_priv, _DPIO_LPF_COEFF_B));
 
        seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n",
-                  intel_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE));
+                  vlv_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE));
 
        mutex_unlock(&dev_priv->dpio_lock);
 
@@ -1776,7 +2031,8 @@ i915_drop_caches_set(void *data, u64 val)
        }
 
        if (val & DROP_UNBOUND) {
-               list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, gtt_list)
+               list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list,
+                                        global_list)
                        if (obj->pages_pin_count == 0) {
                                ret = i915_gem_object_put_pages(obj);
                                if (ret)
@@ -1808,7 +2064,11 @@ i915_max_freq_get(void *data, u64 *val)
        if (ret)
                return ret;
 
-       *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
+       if (IS_VALLEYVIEW(dev))
+               *val = vlv_gpu_freq(dev_priv->mem_freq,
+                                   dev_priv->rps.max_delay);
+       else
+               *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return 0;
@@ -1833,9 +2093,16 @@ i915_max_freq_set(void *data, u64 val)
        /*
         * Turbo will still be enabled, but won't go above the set value.
         */
-       do_div(val, GT_FREQUENCY_MULTIPLIER);
-       dev_priv->rps.max_delay = val;
-       gen6_set_rps(dev, val);
+       if (IS_VALLEYVIEW(dev)) {
+               val = vlv_freq_opcode(dev_priv->mem_freq, val);
+               dev_priv->rps.max_delay = val;
+               gen6_set_rps(dev, val);
+       } else {
+               do_div(val, GT_FREQUENCY_MULTIPLIER);
+               dev_priv->rps.max_delay = val;
+               gen6_set_rps(dev, val);
+       }
+
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return 0;
@@ -1859,7 +2126,11 @@ i915_min_freq_get(void *data, u64 *val)
        if (ret)
                return ret;
 
-       *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
+       if (IS_VALLEYVIEW(dev))
+               *val = vlv_gpu_freq(dev_priv->mem_freq,
+                                   dev_priv->rps.min_delay);
+       else
+               *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return 0;
@@ -1884,9 +2155,15 @@ i915_min_freq_set(void *data, u64 val)
        /*
         * Turbo will still be enabled, but won't go below the set value.
         */
-       do_div(val, GT_FREQUENCY_MULTIPLIER);
-       dev_priv->rps.min_delay = val;
-       gen6_set_rps(dev, val);
+       if (IS_VALLEYVIEW(dev)) {
+               val = vlv_freq_opcode(dev_priv->mem_freq, val);
+               dev_priv->rps.min_delay = val;
+               valleyview_set_rps(dev, val);
+       } else {
+               do_div(val, GT_FREQUENCY_MULTIPLIER);
+               dev_priv->rps.min_delay = val;
+               gen6_set_rps(dev, val);
+       }
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return 0;
@@ -2053,6 +2330,7 @@ static struct drm_info_list i915_debugfs_list[] = {
        {"i915_gem_hws", i915_hws_info, 0, (void *)RCS},
        {"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS},
        {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
+       {"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
        {"i915_rstdby_delays", i915_rstdby_delays, 0},
        {"i915_cur_delayinfo", i915_cur_delayinfo, 0},
        {"i915_delayfreq_table", i915_delayfreq_table, 0},
@@ -2062,6 +2340,7 @@ static struct drm_info_list i915_debugfs_list[] = {
        {"i915_ring_freq_table", i915_ring_freq_table, 0},
        {"i915_gfxec", i915_gfxec, 0},
        {"i915_fbc_status", i915_fbc_status, 0},
+       {"i915_ips_status", i915_ips_status, 0},
        {"i915_sr_status", i915_sr_status, 0},
        {"i915_opregion", i915_opregion, 0},
        {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
index 6a73107..3e9edc6 100644 (file)
@@ -990,8 +990,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
                value = 1;
                break;
        default:
-               DRM_DEBUG_DRIVER("Unknown parameter %d\n",
-                                param->param);
+               DRM_DEBUG("Unknown parameter %d\n", param->param);
                return -EINVAL;
        }
 
@@ -1314,8 +1313,10 @@ static int i915_load_modeset_init(struct drm_device *dev)
 cleanup_gem:
        mutex_lock(&dev->struct_mutex);
        i915_gem_cleanup_ringbuffer(dev);
+       i915_gem_context_fini(dev);
        mutex_unlock(&dev->struct_mutex);
        i915_gem_cleanup_aliasing_ppgtt(dev);
+       drm_mm_takedown(&dev_priv->mm.gtt_space);
 cleanup_irq:
        drm_irq_uninstall(dev);
 cleanup_gem_stolen:
@@ -1342,7 +1343,7 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
                return;
 
        ap->ranges[0].base = dev_priv->gtt.mappable_base;
-       ap->ranges[0].size = dev_priv->gtt.mappable_end - dev_priv->gtt.start;
+       ap->ranges[0].size = dev_priv->gtt.mappable_end;
 
        primary =
                pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
@@ -1351,7 +1352,30 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
 
        kfree(ap);
 }
+#endif
+
+static void i915_dump_device_info(struct drm_i915_private *dev_priv)
+{
+#if 0
+       const struct intel_device_info *info = dev_priv->info;
+
+#define PRINT_S(name) "%s"
+#define SEP_EMPTY
+#define PRINT_FLAG(name) info->name ? #name "," : ""
+#define SEP_COMMA ,
+       DRM_DEBUG_DRIVER("i915 device info: gen=%i, pciid=0x%04x flags="
+                        DEV_INFO_FOR_EACH_FLAG(PRINT_S, SEP_EMPTY),
+                        info->gen,
+                        dev_priv->dev->pdev->device,
+                        DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG, SEP_COMMA));
+#undef PRINT_S
+#undef SEP_EMPTY
+#undef PRINT_FLAG
+#undef SEP_COMMA
+#endif
+}
 
+#if 0
 /**
  * intel_early_sanitize_regs - clean up BIOS state
  * @dev: DRM device
@@ -1364,7 +1388,7 @@ static void intel_early_sanitize_regs(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (IS_HASWELL(dev))
+       if (HAS_FPGA_DBG_UNCLAIMED(dev))
                I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
 }
 #endif
@@ -1414,6 +1438,17 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        dev_priv->dev = dev;
        dev_priv->info = info;
 
+       lockinit(&dev_priv->irq_lock, "userirq", 0, LK_CANRECURSE);
+       lockinit(&dev_priv->gpu_error.lock, "915err", 0, LK_CANRECURSE);
+       lockinit(&dev_priv->rps.lock, "rps.l", 0, LK_CANRECURSE);
+       lockinit(&dev_priv->gt_lock, "915gt", 0, LK_CANRECURSE);
+       spin_init(&dev_priv->backlight.lock, "i915bl");
+       lockinit(&dev_priv->dpio_lock, "i915dpio", 0, LK_CANRECURSE);
+       lockinit(&dev_priv->rps.hw_lock, "i915 rps.hw_lock", 0, LK_CANRECURSE);
+       lockinit(&dev_priv->modeset_restore_lock, "i915mrl", 0, LK_CANRECURSE);
+
+       i915_dump_device_info(dev_priv);
+
        if (i915_get_bridge_dev(dev)) {
                ret = -EIO;
                goto free_priv;
@@ -1479,10 +1514,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                ret = -EIO;
                goto out_rmmap;
        }
-
-       i915_mtrr_setup(dev_priv, dev_priv->gtt.mappable_base,
-                       aperture_size);
 #endif
+       dev_priv->mm.gtt_mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base,
+                                                aperture_size);
 
        base = drm_get_resource_start(dev, mmio_bar);
        size = drm_get_resource_len(dev, mmio_bar);
@@ -1514,6 +1548,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        intel_detect_pch(dev);
 
        intel_irq_init(dev);
+       intel_pm_init(dev);
+       intel_gt_sanitize(dev);
        intel_gt_init(dev);
 
        /* Try to make sure MCHBAR is enabled before poking at it */
@@ -1541,14 +1577,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                pci_enable_msi(dev->pdev);
 #endif
 
-       lockinit(&dev_priv->irq_lock, "userirq", 0, LK_CANRECURSE);
-       lockinit(&dev_priv->gpu_error.lock, "915err", 0, LK_CANRECURSE);
-       spin_init(&dev_priv->rps.lock, "i915initrps");
-       lockinit(&dev_priv->dpio_lock, "i915dpio", 0, LK_CANRECURSE);
-
-       lockinit(&dev_priv->rps.hw_lock, "i915 rps.hw_lock", 0, LK_CANRECURSE);
-       lockinit(&dev_priv->modeset_restore_lock, "i915mrl", 0, LK_CANRECURSE);
-
        dev_priv->num_plane = 1;
        if (IS_VALLEYVIEW(dev))
                dev_priv->num_plane = 2;
@@ -1562,6 +1590,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        /* Start out suspended */
        dev_priv->mm.suspended = 1;
 
+       if (HAS_POWER_WELL(dev))
+               i915_init_power_well(dev);
+
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                ret = i915_load_modeset_init(dev);
                if (ret < 0) {
@@ -1593,6 +1624,11 @@ out_gem_unload:
        intel_teardown_mchbar(dev);
        destroy_workqueue(dev_priv->wq);
 out_mtrrfree:
+       arch_phys_wc_del(dev_priv->mm.gtt_mtrr);
+#if 0
+       io_mapping_free(dev_priv->gtt.mappable);
+#endif
+       dev_priv->gtt.gtt_remove(dev);
 put_bridge:
 free_priv:
        kfree(dev_priv);
@@ -1606,6 +1642,9 @@ int i915_driver_unload(struct drm_device *dev)
 
        intel_gpu_ips_teardown();
 
+       if (HAS_POWER_WELL(dev))
+               i915_remove_power_well(dev);
+
 #if 0
        i915_teardown_sysfs(dev);
 
@@ -1625,13 +1664,10 @@ int i915_driver_unload(struct drm_device *dev)
 
 #if 0
        io_mapping_free(dev_priv->gtt.mappable);
-       if (dev_priv->mm.gtt_mtrr >= 0) {
-               mtrr_del(dev_priv->mm.gtt_mtrr,
-                        dev_priv->gtt.mappable_base,
-                        dev_priv->mm.gtt->gtt_mappable_entries * PAGE_SIZE);
-               dev_priv->mm.gtt_mtrr = -1;
-       }
+#endif
+       arch_phys_wc_del(dev_priv->mm.gtt_mtrr);
 
+#if 0
        acpi_video_unregister();
 #endif
 
@@ -1646,10 +1682,10 @@ int i915_driver_unload(struct drm_device *dev)
                 * free the memory space allocated for the child device
                 * config parsed from VBT
                 */
-               if (dev_priv->child_dev && dev_priv->child_dev_num) {
-                       kfree(dev_priv->child_dev);
-                       dev_priv->child_dev = NULL;
-                       dev_priv->child_dev_num = 0;
+               if (dev_priv->vbt.child_dev && dev_priv->vbt.child_dev_num) {
+                       kfree(dev_priv->vbt.child_dev);
+                       dev_priv->vbt.child_dev = NULL;
+                       dev_priv->vbt.child_dev_num = 0;
                }
 
        }
@@ -1679,6 +1715,7 @@ int i915_driver_unload(struct drm_device *dev)
                        i915_free_hws(dev);
        }
 
+       drm_mm_takedown(&dev_priv->mm.gtt_space);
 #if 0
        if (dev_priv->regs != NULL)
                pci_iounmap(dev->pdev, dev_priv->regs);
@@ -1694,6 +1731,8 @@ int i915_driver_unload(struct drm_device *dev)
        destroy_workqueue(dev_priv->wq);
        pm_qos_remove_request(&dev_priv->pm_qos);
 
+       dev_priv->gtt.gtt_remove(dev);
+
        pci_dev_put(dev_priv->bridge_dev);
        drm_free(dev->dev_private, M_DRM);
 
@@ -1705,7 +1744,7 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file)
        struct drm_i915_file_private *file_priv;
 
        DRM_DEBUG_DRIVER("\n");
-       file_priv = kmalloc(sizeof(*file_priv), M_DRM, M_WAITOK);
+       file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
        if (!file_priv)
                return -ENOMEM;
 
index 305cc03..a942ee6 100644 (file)
 int i915_lvds_channel_mode __read_mostly = 0;
 TUNABLE_INT("drm.i915.lvds_channel_mode", &i915_lvds_channel_mode);
 
-int i915_disable_power_well __read_mostly = 0;
+int i915_disable_power_well __read_mostly = 1;
 module_param_named(disable_power_well, i915_disable_power_well, int, 0600);
 MODULE_PARM_DESC(disable_power_well,
-                "Disable the power well when possible (default: false)");
+                "Disable the power well when possible (default: true)");
 
 bool i915_enable_hangcheck __read_mostly = true;
 module_param_named(enable_hangcheck, i915_enable_hangcheck, bool, 0644);
@@ -50,6 +50,10 @@ MODULE_PARM_DESC(enable_hangcheck,
                "WARNING: Disabling this can cause system wide hangs. "
                "(default: true)");
 
+int i915_enable_ips __read_mostly = 1;
+module_param_named(enable_ips, i915_enable_ips, int, 0600);
+MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
+
 static struct drm_driver driver;
 
 #define INTEL_VGA_DEVICE(id, info) {           \
@@ -201,6 +205,7 @@ static const struct intel_device_info intel_ivybridge_m_info = {
        GEN7_FEATURES,
        .is_ivybridge = 1,
        .is_mobile = 1,
+       .has_fbc = 1,
 };
 
 static const struct intel_device_info intel_ivybridge_q_info = {
@@ -229,12 +234,19 @@ static const struct intel_device_info intel_valleyview_d_info = {
 static const struct intel_device_info intel_haswell_d_info = {
        GEN7_FEATURES,
        .is_haswell = 1,
+       .has_ddi = 1,
+       .has_fpga_dbg = 1,
+       .has_vebox_ring = 1,
 };
 
 static const struct intel_device_info intel_haswell_m_info = {
        GEN7_FEATURES,
        .is_haswell = 1,
        .is_mobile = 1,
+       .has_ddi = 1,
+       .has_fpga_dbg = 1,
+       .has_fbc = 1,
+       .has_vebox_ring = 1,
 };
 
 static const struct pci_device_id pciidlist[] = {              /* aka */
@@ -363,7 +375,6 @@ void intel_detect_pch(struct drm_device *dev)
         */
        if (INTEL_INFO(dev)->num_pipes == 0) {
                dev_priv->pch_type = PCH_NOP;
-               dev_priv->num_pch_pll = 0;
                return;
        }
 
@@ -382,34 +393,28 @@ void intel_detect_pch(struct drm_device *dev)
 
                        if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_IBX;
-                               dev_priv->num_pch_pll = 2;
                                DRM_DEBUG_KMS("Found Ibex Peak PCH\n");
                                WARN_ON(!IS_GEN5(dev));
                        } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_CPT;
-                               dev_priv->num_pch_pll = 2;
                                DRM_DEBUG_KMS("Found CougarPoint PCH\n");
                                WARN_ON(!(IS_GEN6(dev) || IS_IVYBRIDGE(dev)));
                        } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) {
                                /* PantherPoint is CPT compatible */
                                dev_priv->pch_type = PCH_CPT;
-                               dev_priv->num_pch_pll = 2;
                                DRM_DEBUG_KMS("Found PatherPoint PCH\n");
                                WARN_ON(!(IS_GEN6(dev) || IS_IVYBRIDGE(dev)));
                        } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_LPT;
-                               dev_priv->num_pch_pll = 0;
                                DRM_DEBUG_KMS("Found LynxPoint PCH\n");
                                WARN_ON(!IS_HASWELL(dev));
                                WARN_ON(IS_ULT(dev));
                        } else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_LPT;
-                               dev_priv->num_pch_pll = 0;
                                DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
                                WARN_ON(!IS_HASWELL(dev));
                                WARN_ON(!IS_ULT(dev));
                        }
-                       BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS);
                }
 #if 0
                pci_dev_put(pch);
@@ -471,12 +476,20 @@ static int i915_drm_freeze(struct drm_device *dev)
                 */
                list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
                        dev_priv->display.crtc_disable(crtc);
+
+               intel_modeset_suspend_hw(dev);
        }
 
        i915_save_state(dev);
 
        intel_opregion_fini(dev);
 
+#if 0
+       console_lock();
+       intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED);
+       console_unlock();
+#endif
+
        return 0;
 }
 
@@ -502,6 +515,20 @@ i915_suspend(device_t kdev)
        return (error);
 }
 
+#if 0
+void intel_console_resume(struct work_struct *work)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(work, struct drm_i915_private,
+                            console_resume_work);
+       struct drm_device *dev = dev_priv->dev;
+
+       console_lock();
+       intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING);
+       console_unlock();
+}
+#endif
+
 static void intel_resume_hotplug(struct drm_device *dev)
 {
        struct drm_mode_config *mode_config = &dev->mode_config;
@@ -568,7 +595,7 @@ static int __i915_drm_thaw(struct drm_device *dev)
         */
 #if 0
        if (console_trylock()) {
-               intel_fbdev_set_suspend(dev, 0);
+               intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING);
                console_unlock();
        } else {
                schedule_work(&dev_priv->console_resume_work);
@@ -585,7 +612,7 @@ static int i915_drm_thaw(struct drm_device *dev)
 {
        int error = 0;
 
-       intel_gt_reset(dev);
+       intel_gt_sanitize(dev);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                mutex_lock(&dev->struct_mutex);
@@ -601,26 +628,43 @@ static int i915_drm_thaw(struct drm_device *dev)
 static int
 i915_resume(device_t kdev)
 {
-       struct drm_device *dev;
+       struct drm_device *dev = device_get_softc(kdev);
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       dev = device_get_softc(kdev);
-       DRM_DEBUG_KMS("starting resume\n");
 #if 0
+       if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+               return 0;
+
        if (pci_enable_device(dev->pdev))
                return -EIO;
 
        pci_set_master(dev->pdev);
 #endif
 
+       intel_gt_sanitize(dev);
+
+       /*
+        * Platforms with opregion should have sane BIOS, older ones (gen3 and
+        * earlier) need this since the BIOS might clear all our scratch PTEs.
+        */
+       if (drm_core_check_feature(dev, DRIVER_MODESET) &&
+           !dev_priv->opregion.header) {
+               mutex_lock(&dev->struct_mutex);
+               i915_gem_restore_gtt_mappings(dev);
+               mutex_unlock(&dev->struct_mutex);
+       }
+
        ret = -i915_drm_thaw(dev);
-       if (ret != 0)
-               return (ret);
+       if (ret)
+               return ret;
 
-       drm_kms_helper_poll_enable(dev);
        ret = bus_generic_resume(kdev);
-       DRM_DEBUG_KMS("finished resume %d\n", ret);
-       return (ret);
+       if (ret)
+               return ret;
+
+       drm_kms_helper_poll_enable(dev);
+       return 0;
 }
 
 /* XXX Hack for the old *BSD drm code base
@@ -814,37 +858,14 @@ static int gen6_do_reset(struct drm_device *dev)
 
 int intel_gpu_reset(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret = -ENODEV;
-
        switch (INTEL_INFO(dev)->gen) {
        case 7:
-       case 6:
-               ret = gen6_do_reset(dev);
-               break;
-       case 5:
-               ret = ironlake_do_reset(dev);
-               break;
-       case 4:
-               ret = i965_do_reset(dev);
-               break;
-       case 2:
-               ret = i8xx_do_reset(dev);
-               break;
-       }
-
-       /* Also reset the gpu hangman. */
-       if (dev_priv->gpu_error.stop_rings) {
-               DRM_INFO("Simulated gpu hang, resetting stop_rings\n");
-               dev_priv->gpu_error.stop_rings = 0;
-               if (ret == -ENODEV) {
-                       DRM_ERROR("Reset not implemented, but ignoring "
-                                 "error for simulated gpu hangs\n");
-                       ret = 0;
-               }
+       case 6: return gen6_do_reset(dev);
+       case 5: return ironlake_do_reset(dev);
+       case 4: return i965_do_reset(dev);
+       case 2: return i8xx_do_reset(dev);
+       default: return -ENODEV;
        }
-
-       return ret;
 }
 
 /**
@@ -865,6 +886,7 @@ int intel_gpu_reset(struct drm_device *dev)
 int i915_reset(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       bool simulated;
        int ret;
 
        if (!i915_try_reset)
@@ -874,13 +896,26 @@ int i915_reset(struct drm_device *dev)
 
        i915_gem_reset(dev);
 
-       ret = -ENODEV;
-       if (time_uptime - dev_priv->gpu_error.last_reset < 5)
+       simulated = dev_priv->gpu_error.stop_rings != 0;
+
+       if (!simulated && get_seconds() - dev_priv->gpu_error.last_reset < 5) {
                DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
-       else
+               ret = -ENODEV;
+       } else {
                ret = intel_gpu_reset(dev);
 
-       dev_priv->gpu_error.last_reset = time_uptime;
+               /* Also reset the gpu hangman. */
+               if (simulated) {
+                       DRM_INFO("Simulated gpu hang, resetting stop_rings\n");
+                       dev_priv->gpu_error.stop_rings = 0;
+                       if (ret == -ENODEV) {
+                               DRM_ERROR("Reset not implemented, but ignoring "
+                                         "error for simulated gpu hangs\n");
+                               ret = 0;
+                       }
+               } else
+                       dev_priv->gpu_error.last_reset = get_seconds();
+       }
        if (ret) {
                DRM_ERROR("Failed to reset chip.\n");
                mutex_unlock(&dev->struct_mutex);
@@ -1023,16 +1058,16 @@ MODULE_DEPEND(i915kms, iicbb, 1, 1, 1);
 static void
 ilk_dummy_write(struct drm_i915_private *dev_priv)
 {
-       /* WaIssueDummyWriteToWakeupFromRC6: Issue a dummy write to wake up the
-        * chip from rc6 before touching it for real. MI_MODE is masked, hence
-        * harmless to write 0 into. */
+       /* WaIssueDummyWriteToWakeupFromRC6:ilk Issue a dummy write to wake up
+        * the chip from rc6 before touching it for real. MI_MODE is masked,
+        * hence harmless to write 0 into. */
        I915_WRITE_NOTRACE(MI_MODE, 0);
 }
 
 static void
 hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg)
 {
-       if (IS_HASWELL(dev_priv->dev) &&
+       if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) &&
            (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
                DRM_ERROR("Unknown unclaimed register before writing to %x\n",
                          reg);
@@ -1043,7 +1078,7 @@ hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg)
 static void
 hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg)
 {
-       if (IS_HASWELL(dev_priv->dev) &&
+       if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) &&
            (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
                DRM_ERROR("Unclaimed write to %x\n", reg);
                I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
@@ -1053,19 +1088,19 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg)
 #define __i915_read(x, y) \
 u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
        u##x val = 0; \
+       lockmgr(&dev_priv->gt_lock, LK_EXCLUSIVE); \
        if (IS_GEN5(dev_priv->dev)) \
                ilk_dummy_write(dev_priv); \
        if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
-               lockmgr(&dev_priv->gt_lock, LK_EXCLUSIVE); \
                if (dev_priv->forcewake_count == 0) \
                        dev_priv->gt.force_wake_get(dev_priv); \
                val = DRM_READ##y(dev_priv->mmio_map, reg);     \
                if (dev_priv->forcewake_count == 0) \
                        dev_priv->gt.force_wake_put(dev_priv); \
-               lockmgr(&dev_priv->gt_lock, LK_RELEASE); \
        } else { \
                val = DRM_READ##y(dev_priv->mmio_map, reg);     \
        } \
+       lockmgr(&dev_priv->gt_lock, LK_RELEASE); \
        trace_i915_reg_rw(false, reg, val, sizeof(val)); \
        return val; \
 }
@@ -1080,6 +1115,7 @@ __i915_read(64, 64)
 void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
        u32 __fifo_ret = 0; \
        trace_i915_reg_rw(true, reg, val, sizeof(val)); \
+       lockmgr(&dev_priv->gt_lock, LK_EXCLUSIVE); \
        if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
                __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
        } \
@@ -1091,6 +1127,7 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
                gen6_gt_check_fifodbg(dev_priv); \
        } \
        hsw_unclaimed_reg_check(dev_priv, reg); \
+       lockmgr(&dev_priv->gt_lock, LK_RELEASE); \
 }
 
 __i915_write(8, 8)
index b4fae9e..433ab59 100644 (file)
@@ -74,6 +74,8 @@ enum plane {
 };
 #define plane_name(p) ((p) + 'A')
 
+#define sprite_name(p, s) ((p) * dev_priv->num_plane + (s) + 'A')
+
 enum port {
        PORT_A = 0,
        PORT_B,
@@ -84,6 +86,24 @@ enum port {
 };
 #define port_name(p) ((p) + 'A')
 
+enum intel_display_power_domain {
+       POWER_DOMAIN_PIPE_A,
+       POWER_DOMAIN_PIPE_B,
+       POWER_DOMAIN_PIPE_C,
+       POWER_DOMAIN_PIPE_A_PANEL_FITTER,
+       POWER_DOMAIN_PIPE_B_PANEL_FITTER,
+       POWER_DOMAIN_PIPE_C_PANEL_FITTER,
+       POWER_DOMAIN_TRANSCODER_A,
+       POWER_DOMAIN_TRANSCODER_B,
+       POWER_DOMAIN_TRANSCODER_C,
+       POWER_DOMAIN_TRANSCODER_EDP = POWER_DOMAIN_TRANSCODER_A + 0xF,
+};
+
+#define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A)
+#define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \
+               ((pipe) + POWER_DOMAIN_PIPE_A_PANEL_FITTER)
+#define POWER_DOMAIN_TRANSCODER(tran) ((tran) + POWER_DOMAIN_TRANSCODER_A)
+
 enum hpd_pin {
        HPD_NONE = 0,
        HPD_PORT_A = HPD_NONE, /* PORT_A is internal */
@@ -110,15 +130,38 @@ enum hpd_pin {
        list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
                if ((intel_encoder)->base.crtc == (__crtc))
 
-struct intel_pch_pll {
+struct drm_i915_private;
+
+enum intel_dpll_id {
+       DPLL_ID_PRIVATE = -1, /* non-shared dpll in use */
+       /* real shared dpll ids must be >= 0 */
+       DPLL_ID_PCH_PLL_A,
+       DPLL_ID_PCH_PLL_B,
+};
+#define I915_NUM_PLLS 2
+
+struct intel_dpll_hw_state {
+       uint32_t dpll;
+       uint32_t fp0;
+       uint32_t fp1;
+};
+
+struct intel_shared_dpll {
        int refcount; /* count of number of CRTCs sharing this PLL */
        int active; /* count of number of active CRTCs (i.e. DPMS on) */
        bool on; /* is the PLL actually active? Disabled during modeset */
-       int pll_reg;
-       int fp0_reg;
-       int fp1_reg;
+       const char *name;
+       /* should match the index in the dev_priv->shared_dplls array */
+       enum intel_dpll_id id;
+       struct intel_dpll_hw_state hw_state;
+       void (*enable)(struct drm_i915_private *dev_priv,
+                      struct intel_shared_dpll *pll);
+       void (*disable)(struct drm_i915_private *dev_priv,
+                       struct intel_shared_dpll *pll);
+       bool (*get_hw_state)(struct drm_i915_private *dev_priv,
+                            struct intel_shared_dpll *pll,
+                            struct intel_dpll_hw_state *hw_state);
 };
-#define I915_NUM_PLLS 2
 
 /* Used by dp and fdi links */
 struct intel_link_m_n {
@@ -173,7 +216,6 @@ struct opregion_header;
 struct opregion_acpi;
 struct opregion_swsci;
 struct opregion_asle;
-struct drm_i915_private;
 
 struct intel_opregion {
        struct opregion_header __iomem *header;
@@ -284,6 +326,8 @@ struct drm_i915_error_state {
 
 struct intel_crtc_config;
 struct intel_crtc;
+struct intel_limit;
+struct dpll;
 
 struct drm_i915_display_funcs {
        bool (*fbc_enabled)(struct drm_device *dev);
@@ -291,11 +335,28 @@ struct drm_i915_display_funcs {
        void (*disable_fbc)(struct drm_device *dev);
        int (*get_display_clock_speed)(struct drm_device *dev);
        int (*get_fifo_size)(struct drm_device *dev, int plane);
+       /**
+        * find_dpll() - Find the best values for the PLL
+        * @limit: limits for the PLL
+        * @crtc: current CRTC
+        * @target: target frequency in kHz
+        * @refclk: reference clock frequency in kHz
+        * @match_clock: if provided, @best_clock P divider must
+        *               match the P divider from @match_clock
+        *               used for LVDS downclocking
+        * @best_clock: best PLL values found
+        *
+        * Returns true on success, false on failure.
+        */
+       bool (*find_dpll)(const struct intel_limit *limit,
+                         struct drm_crtc *crtc,
+                         int target, int refclk,
+                         struct dpll *match_clock,
+                         struct dpll *best_clock);
        void (*update_wm)(struct drm_device *dev);
        void (*update_sprite_wm)(struct drm_device *dev, int pipe,
-                                uint32_t sprite_width, int pixel_size);
-       void (*update_linetime_wm)(struct drm_device *dev, int pipe,
-                                struct drm_display_mode *mode);
+                                uint32_t sprite_width, int pixel_size,
+                                bool enable);
        void (*modeset_global_resources)(struct drm_device *dev);
        /* Returns the active state of the crtc, and if the crtc is active,
         * fills out the pipe-config with the hw state. */
@@ -329,68 +390,56 @@ struct drm_i915_gt_funcs {
        void (*force_wake_put)(struct drm_i915_private *dev_priv);
 };
 
-#define DEV_INFO_FLAGS \
-       DEV_INFO_FLAG(is_mobile) DEV_INFO_SEP \
-       DEV_INFO_FLAG(is_i85x) DEV_INFO_SEP \
-       DEV_INFO_FLAG(is_i915g) DEV_INFO_SEP \
-       DEV_INFO_FLAG(is_i945gm) DEV_INFO_SEP \
-       DEV_INFO_FLAG(is_g33) DEV_INFO_SEP \
-       DEV_INFO_FLAG(need_gfx_hws) DEV_INFO_SEP \
-       DEV_INFO_FLAG(is_g4x) DEV_INFO_SEP \
-       DEV_INFO_FLAG(is_pineview) DEV_INFO_SEP \
-       DEV_INFO_FLAG(is_broadwater) DEV_INFO_SEP \
-       DEV_INFO_FLAG(is_crestline) DEV_INFO_SEP \
-       DEV_INFO_FLAG(is_ivybridge) DEV_INFO_SEP \
-       DEV_INFO_FLAG(is_valleyview) DEV_INFO_SEP \
-       DEV_INFO_FLAG(is_haswell) DEV_INFO_SEP \
-       DEV_INFO_FLAG(has_force_wake) DEV_INFO_SEP \
-       DEV_INFO_FLAG(has_fbc) DEV_INFO_SEP \
-       DEV_INFO_FLAG(has_pipe_cxsr) DEV_INFO_SEP \
-       DEV_INFO_FLAG(has_hotplug) DEV_INFO_SEP \
-       DEV_INFO_FLAG(cursor_needs_physical) DEV_INFO_SEP \
-       DEV_INFO_FLAG(has_overlay) DEV_INFO_SEP \
-       DEV_INFO_FLAG(overlay_needs_physical) DEV_INFO_SEP \
-       DEV_INFO_FLAG(supports_tv) DEV_INFO_SEP \
-       DEV_INFO_FLAG(has_bsd_ring) DEV_INFO_SEP \
-       DEV_INFO_FLAG(has_blt_ring) DEV_INFO_SEP \
-       DEV_INFO_FLAG(has_llc)
+#define DEV_INFO_FOR_EACH_FLAG(func, sep) \
+       func(is_mobile) sep \
+       func(is_i85x) sep \
+       func(is_i915g) sep \
+       func(is_i945gm) sep \
+       func(is_g33) sep \
+       func(need_gfx_hws) sep \
+       func(is_g4x) sep \
+       func(is_pineview) sep \
+       func(is_broadwater) sep \
+       func(is_crestline) sep \
+       func(is_ivybridge) sep \
+       func(is_valleyview) sep \
+       func(is_haswell) sep \
+       func(has_force_wake) sep \
+       func(has_fbc) sep \
+       func(has_pipe_cxsr) sep \
+       func(has_hotplug) sep \
+       func(cursor_needs_physical) sep \
+       func(has_overlay) sep \
+       func(overlay_needs_physical) sep \
+       func(supports_tv) sep \
+       func(has_bsd_ring) sep \
+       func(has_blt_ring) sep \
+       func(has_vebox_ring) sep \
+       func(has_llc) sep \
+       func(has_ddi) sep \
+       func(has_fpga_dbg)
+
+#define DEFINE_FLAG(name) u8 name:1
+#define SEP_SEMICOLON ;
 
 struct intel_device_info {
        u32 display_mmio_offset;
        u8 num_pipes:3;
        u8 gen;
-       u8 is_mobile:1;
-       u8 is_i85x:1;
-       u8 is_i915g:1;
-       u8 is_i945gm:1;
-       u8 is_g33:1;
-       u8 need_gfx_hws:1;
-       u8 is_g4x:1;
-       u8 is_pineview:1;
-       u8 is_broadwater:1;
-       u8 is_crestline:1;
-       u8 is_ivybridge:1;
-       u8 is_valleyview:1;
-       u8 has_force_wake:1;
-       u8 is_haswell:1;
-       u8 has_fbc:1;
-       u8 has_pipe_cxsr:1;
-       u8 has_hotplug:1;
-       u8 cursor_needs_physical:1;
-       u8 has_overlay:1;
-       u8 overlay_needs_physical:1;
-       u8 supports_tv:1;
-       u8 has_bsd_ring:1;
-       u8 has_blt_ring:1;
-       u8 has_llc:1;
+       DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG, SEP_SEMICOLON);
 };
 
+#undef DEFINE_FLAG
+#undef SEP_SEMICOLON
+
 enum i915_cache_level {
        I915_CACHE_NONE = 0,
        I915_CACHE_LLC,
        I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */
 };
 
+typedef uint32_t gen6_gtt_pte_t;
+
 /* The Graphics Translation Table is the way in which GEN hardware translates a
  * Graphics Virtual Address into a Physical Address. In addition to the normal
  * collateral associated with any va->pa translations GEN hardware also has a
@@ -426,6 +475,9 @@ struct i915_gtt {
                                   struct sg_table *st,
                                   unsigned int pg_start,
                                   enum i915_cache_level cache_level);
+       gen6_gtt_pte_t (*pte_encode)(struct drm_device *dev,
+                                    dma_addr_t addr,
+                                    enum i915_cache_level level);
 };
 #define gtt_total_entries(gtt) ((gtt).total >> PAGE_SHIFT)
 
@@ -447,19 +499,31 @@ struct i915_hw_ppgtt {
                               struct sg_table *st,
                               unsigned int pg_start,
                               enum i915_cache_level cache_level);
+       gen6_gtt_pte_t (*pte_encode)(struct drm_device *dev,
+                                    dma_addr_t addr,
+                                    enum i915_cache_level level);
        int (*enable)(struct drm_device *dev);
        void (*cleanup)(struct i915_hw_ppgtt *ppgtt);
 };
 
+struct i915_ctx_hang_stats {
+       /* This context had batch pending when hang was declared */
+       unsigned batch_pending;
+
+       /* This context had batch active when hang was declared */
+       unsigned batch_active;
+};
 
 /* This must match up with the value previously used for execbuf2.rsvd1. */
 #define DEFAULT_CONTEXT_ID 0
 struct i915_hw_context {
+       struct kref ref;
        int id;
        bool is_initialized;
        struct drm_i915_file_private *file_priv;
        struct intel_ring_buffer *ring;
        struct drm_i915_gem_object *obj;
+       struct i915_ctx_hang_stats hang_stats;
 };
 
 enum no_fbc_reason {
@@ -489,6 +553,7 @@ enum intel_sbi_destination {
 #define QUIRK_PIPEA_FORCE (1<<0)
 #define QUIRK_LVDS_SSC_DISABLE (1<<1)
 #define QUIRK_INVERT_BRIGHTNESS (1<<2)
+#define QUIRK_NO_PCH_PWM_ENABLE (1<<3)
 
 struct intel_fbdev;
 struct intel_fbc_work;
@@ -663,16 +728,18 @@ struct i915_suspend_saved_registers {
 
 struct intel_gen6_power_mgmt {
        struct work_struct work;
+       struct delayed_work vlv_work;
        u32 pm_iir;
        /* lock - irqsave spinlock that protectects the work_struct and
         * pm_iir. */
-       struct spinlock lock;
+       struct lock lock;
 
        /* The below variables an all the rps hw state are protected by
         * dev->struct mutext. */
        u8 cur_delay;
        u8 min_delay;
        u8 max_delay;
+       u8 rpe_delay;
        u8 hw_max;
 
        struct delayed_work delayed_resume_work;
@@ -709,6 +776,15 @@ struct intel_ilk_power_mgmt {
        struct drm_i915_gem_object *renderctx;
 };
 
+/* Power well structure for haswell */
+struct i915_power_well {
+       struct drm_device *device;
+       struct lock lock;
+       /* power well enable/disable usage count */
+       int count;
+       int i915_request;
+};
+
 struct i915_dri1_state {
        unsigned allow_batchbuffer : 1;
        u32 __iomem *gfx_hws_cpu_addr;
@@ -819,6 +895,15 @@ struct i915_gem_mm {
        u32 object_count;
 };
 
+struct drm_i915_error_state_buf {
+       unsigned bytes;
+       unsigned size;
+       int err;
+       u8 *buf;
+       loff_t start;
+       loff_t pos;
+};
+
 struct i915_gpu_error {
        /* For hangcheck timer */
 #define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
@@ -882,6 +967,37 @@ enum modeset_restore {
        MODESET_SUSPENDED,
 };
 
+struct intel_vbt_data {
+       struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
+       struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
+
+       /* Feature bits */
+       unsigned int int_tv_support:1;
+       unsigned int lvds_dither:1;
+       unsigned int lvds_vbt:1;
+       unsigned int int_crt_support:1;
+       unsigned int lvds_use_ssc:1;
+       unsigned int display_clock_mode:1;
+       unsigned int fdi_rx_polarity_inverted:1;
+       int lvds_ssc_freq;
+       unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
+
+       /* eDP */
+       int edp_rate;
+       int edp_lanes;
+       int edp_preemphasis;
+       int edp_vswing;
+       bool edp_initialized;
+       bool edp_support;
+       int edp_bpp;
+       struct edp_power_seq edp_pps;
+
+       int crt_ddc_pin;
+
+       int child_dev_num;
+       struct child_device_config *child_dev;
+};
+
 typedef struct drm_i915_private {
        struct drm_device *dev;
        struct kmem_cache *slab;
@@ -956,9 +1072,9 @@ typedef struct drm_i915_private {
                        HPD_MARK_DISABLED = 2
                } hpd_mark;
        } hpd_stats[HPD_NUM_PINS];
+       u32 hpd_event_bits;
        struct timer_list hotplug_reenable_timer;
 
-       int num_pch_pll;
        int num_plane;
 
        unsigned long cfb_size;
@@ -968,6 +1084,7 @@ typedef struct drm_i915_private {
        struct intel_fbc_work *fbc_work;
 
        struct intel_opregion opregion;
+       struct intel_vbt_data vbt;
 
        /* overlay */
        struct intel_overlay *overlay;
@@ -977,37 +1094,15 @@ typedef struct drm_i915_private {
        struct {
                int level;
                bool enabled;
+               struct spinlock lock; /* bl registers and the above bl fields */
                struct backlight_device *device;
        } backlight;
 
        /* LVDS info */
        struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
        struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
-
-       /* Feature bits from the VBIOS */
-       unsigned int int_tv_support:1;
-       unsigned int lvds_dither:1;
-       unsigned int lvds_vbt:1;
-       unsigned int int_crt_support:1;
-       unsigned int lvds_use_ssc:1;
-       unsigned int display_clock_mode:1;
-       unsigned int fdi_rx_polarity_inverted:1;
-       int lvds_ssc_freq;
-       unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
-       struct {
-               int rate;
-               int lanes;
-               int preemphasis;
-               int vswing;
-
-               bool initialized;
-               bool support;
-               int bpp;
-               struct edp_power_seq pps;
-       } edp;
        bool no_aux_handshake;
 
-       int crt_ddc_pin;
        struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */
        int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
        int num_fence_regs; /* 8 on pre-965, 16 otherwise */
@@ -1035,16 +1130,13 @@ typedef struct drm_i915_private {
        /* Kernel Modesetting */
 
        struct sdvo_device_mapping sdvo_mappings[2];
-       /* indicate whether the LVDS_BORDER should be enabled or not */
-       unsigned int lvds_border_bits;
-       /* Panel fitter placement and size for Ironlake+ */
-       u32 pch_pf_pos, pch_pf_size;
 
        struct drm_crtc *plane_to_crtc_mapping[3];
        struct drm_crtc *pipe_to_crtc_mapping[3];
        wait_queue_head_t pending_flip_queue;
 
-       struct intel_pch_pll pch_plls[I915_NUM_PLLS];
+       int num_shared_dpll;
+       struct intel_shared_dpll shared_dplls[I915_NUM_PLLS];
        struct intel_ddi_plls ddi_plls;
 
        /* Reclocking support */
@@ -1053,8 +1145,6 @@ typedef struct drm_i915_private {
        /* indicates the reduced downclock for LVDS*/
        int lvds_downclock;
        u16 orig_clock;
-       int child_dev_num;
-       struct child_device_config *child_dev;
 
        bool mchbar_need_disable;
 
@@ -1067,6 +1157,9 @@ typedef struct drm_i915_private {
         * mchdev_lock in intel_pm.c */
        struct intel_ilk_power_mgmt ips;
 
+       /* Haswell power well */
+       struct i915_power_well power_well;
+
        enum no_fbc_reason no_fbc_reason;
 
        struct drm_mm_node *compressed_fb;
@@ -1074,6 +1167,8 @@ typedef struct drm_i915_private {
 
        struct i915_gpu_error gpu_error;
 
+       struct drm_i915_gem_object *vlv_pctx;
+
        /* list of fbdev register on this device */
        struct intel_fbdev *fbdev;
 
@@ -1139,7 +1234,7 @@ struct drm_i915_gem_object {
        struct drm_mm_node *gtt_space;
        /** Stolen memory for this object, instead of being backed by shmem. */
        struct drm_mm_node *stolen;
-       struct list_head gtt_list;
+       struct list_head global_list;
 
        /** This object's place on the active/inactive lists */
        struct list_head ring_list;
@@ -1282,9 +1377,18 @@ struct drm_i915_gem_request {
        /** GEM sequence number associated with this request. */
        uint32_t seqno;
 
-       /** Postion in the ringbuffer of the end of the request */
+       /** Position in the ringbuffer of the start of the request */
+       u32 head;
+
+       /** Position in the ringbuffer of the end of the request */
        u32 tail;
 
+       /** Context related to this request */
+       struct i915_hw_context *ctx;
+
+       /** Batch buffer related to this request if any */
+       struct drm_i915_gem_object *batch_obj;
+
        /** Time at which this request was emitted, in jiffies. */
        unsigned long emitted_jiffies;
 
@@ -1302,6 +1406,8 @@ struct drm_i915_file_private {
                struct list_head request_list;
        } mm;
        struct idr context_idr;
+
+       struct i915_ctx_hang_stats hang_stats;
 };
 
 #define INTEL_INFO(dev)        (((struct drm_i915_private *) (dev)->dev_private)->info)
@@ -1352,6 +1458,7 @@ struct drm_i915_file_private {
 
 #define HAS_BSD(dev)            (INTEL_INFO(dev)->has_bsd_ring)
 #define HAS_BLT(dev)            (INTEL_INFO(dev)->has_blt_ring)
+#define HAS_VEBOX(dev)          (INTEL_INFO(dev)->has_vebox_ring)
 #define HAS_LLC(dev)            (INTEL_INFO(dev)->has_llc)
 #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
 
@@ -1382,10 +1489,13 @@ struct drm_i915_file_private {
 #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
 #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
 
+#define HAS_IPS(dev)           (IS_ULT(dev))
+
 #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5)
 
-#define HAS_DDI(dev)           (IS_HASWELL(dev))
+#define HAS_DDI(dev)           (INTEL_INFO(dev)->has_ddi)
 #define HAS_POWER_WELL(dev)    (IS_HASWELL(dev))
+#define HAS_FPGA_DBG_UNCLAIMED(dev)    (INTEL_INFO(dev)->has_fpga_dbg)
 
 #define INTEL_PCH_DEVICE_ID_MASK               0xff00
 #define INTEL_PCH_IBX_DEVICE_ID_TYPE           0x3b00
@@ -1447,6 +1557,7 @@ extern bool i915_enable_hangcheck __read_mostly;
 extern int i915_enable_ppgtt __read_mostly;
 extern unsigned int i915_preliminary_hw_support __read_mostly;
 extern int i915_disable_power_well __read_mostly;
+extern int i915_enable_ips __read_mostly;
 
 extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
 extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master);
@@ -1484,9 +1595,10 @@ void i915_hangcheck_elapsed(unsigned long data);
 void i915_handle_error(struct drm_device *dev, bool wedged);
 
 extern void intel_irq_init(struct drm_device *dev);
+extern void intel_pm_init(struct drm_device *dev);
 extern void intel_hpd_init(struct drm_device *dev);
 extern void intel_gt_init(struct drm_device *dev);
-extern void intel_gt_reset(struct drm_device *dev);
+extern void intel_gt_sanitize(struct drm_device *dev);
 
 void i915_error_state_free(struct kref *error_ref);
 
@@ -1496,8 +1608,6 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
 void
 i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
 
-void intel_enable_asle(struct drm_device *dev);
-
 #ifdef CONFIG_DEBUG_FS
 extern void i915_destroy_error_state(struct drm_device *dev);
 #else
@@ -1631,6 +1741,7 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj)
 {
        if (obj->fence_reg != I915_FENCE_REG_NONE) {
                struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+               WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count <= 0);
                dev_priv->fence_regs[obj->fence_reg].pin_count--;
        }
 }
@@ -1663,9 +1774,12 @@ void i915_gem_init_swizzling(struct drm_device *dev);
 void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
 int __must_check i915_gpu_idle(struct drm_device *dev);
 int __must_check i915_gem_idle(struct drm_device *dev);
-int i915_add_request(struct intel_ring_buffer *ring,
-                    struct drm_file *file,
-                    u32 *seqno);
+int __i915_add_request(struct intel_ring_buffer *ring,
+                      struct drm_file *file,
+                      struct drm_i915_gem_object *batch_obj,
+                      u32 *seqno);
+#define i915_add_request(ring, seqno) \
+       __i915_add_request(ring, NULL, NULL, seqno)
 int __must_check i915_wait_seqno(struct intel_ring_buffer *ring,
                                 uint32_t seqno);
 int i915_gem_fault(struct drm_device *dev, uint64_t offset, int prot,
@@ -1713,6 +1827,21 @@ void i915_gem_context_fini(struct drm_device *dev);
 void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
 int i915_switch_context(struct intel_ring_buffer *ring,
                        struct drm_file *file, int to_id);
+void i915_gem_context_free(struct kref *ctx_ref);
+static inline void i915_gem_context_reference(struct i915_hw_context *ctx)
+{
+       kref_get(&ctx->ref);
+}
+
+static inline void i915_gem_context_unreference(struct i915_hw_context *ctx)
+{
+       kref_put(&ctx->ref, i915_gem_context_free);
+}
+
+struct i915_ctx_hang_stats * __must_check
+i915_gem_context_get_hang_stats(struct intel_ring_buffer *ring,
+                               struct drm_file *file,
+                               u32 id);
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
                                  struct drm_file *file);
 int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
@@ -1792,6 +1921,8 @@ void i915_gem_object_check_coherency(struct drm_i915_gem_object *obj,
 /* i915_debugfs.c */
 int i915_debugfs_init(struct drm_minor *minor);
 void i915_debugfs_cleanup(struct drm_minor *minor);
+__printf(2, 3)
+void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
 
 /* i915_suspend.c */
 extern int i915_save_state(struct drm_device *dev);
@@ -1832,14 +1963,10 @@ extern int intel_opregion_setup(struct drm_device *dev);
 extern void intel_opregion_init(struct drm_device *dev);
 extern void intel_opregion_fini(struct drm_device *dev);
 extern void intel_opregion_asle_intr(struct drm_device *dev);
-extern void intel_opregion_gse_intr(struct drm_device *dev);
-extern void intel_opregion_enable_asle(struct drm_device *dev);
 #else
 static inline void intel_opregion_init(struct drm_device *dev) { return; }
 static inline void intel_opregion_fini(struct drm_device *dev) { return; }
 static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; }
-static inline void intel_opregion_gse_intr(struct drm_device *dev) { return; }
-static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; }
 #endif
 
 /* intel_acpi.c */
@@ -1853,6 +1980,7 @@ static inline void intel_unregister_dsm_handler(void) { return; }
 
 /* modesetting */
 extern void intel_modeset_init_hw(struct drm_device *dev);
+extern void intel_modeset_suspend_hw(struct drm_device *dev);
 extern void intel_modeset_init(struct drm_device *dev);
 extern void intel_modeset_gem_init(struct drm_device *dev);
 extern void intel_modeset_cleanup(struct drm_device *dev);
@@ -1864,6 +1992,9 @@ extern void intel_disable_fbc(struct drm_device *dev);
 extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
 extern void intel_init_pch_refclk(struct drm_device *dev);
 extern void gen6_set_rps(struct drm_device *dev, u8 val);
+extern void valleyview_set_rps(struct drm_device *dev, u8 val);
+extern int valleyview_rps_max_freq(struct drm_i915_private *dev_priv);
+extern int valleyview_rps_min_freq(struct drm_i915_private *dev_priv);
 extern void intel_detect_pch(struct drm_device *dev);
 extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
 extern int intel_enable_rc6(const struct drm_device *dev);
@@ -1877,10 +2008,11 @@ const struct intel_device_info *i915_get_device_id(int device);
 /* overlay */
 #ifdef CONFIG_DEBUG_FS
 extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
-extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error);
+extern void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e,
+                                           struct intel_overlay_error_state *error);
 
 extern struct intel_display_error_state *intel_display_capture_error_state(struct drm_device *dev);
-extern void intel_display_print_error_state(struct seq_file *m,
+extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e,
                                            struct drm_device *dev,
                                            struct intel_display_error_state *error);
 #endif
@@ -1895,8 +2027,20 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
 
 int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val);
 int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val);
-int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val);
-int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val);
+
+/* intel_sideband.c */
+u32 vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr);
+void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val);
+u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr);
+u32 vlv_dpio_read(struct drm_i915_private *dev_priv, int reg);
+void vlv_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val);
+u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg,
+                  enum intel_sbi_destination destination);
+void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value,
+                    enum intel_sbi_destination destination);
+
+int vlv_gpu_freq(int ddr_freq, int val);
+int vlv_freq_opcode(int ddr_freq, int val);
 
 #define __i915_read(x, y) \
        u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg);
index 95743d1..08a987f 100644 (file)
@@ -205,7 +205,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
 
        pinned = 0;
        mutex_lock(&dev->struct_mutex);
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list)
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
                if (obj->pin_count)
                        pinned += obj->gtt_space->size;
        mutex_unlock(&dev->struct_mutex);
@@ -216,6 +216,11 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
        return 0;
 }
 
+void i915_gem_object_free(struct drm_i915_gem_object *obj)
+{
+       kfree(obj);
+}
+
 static int
 i915_gem_create(struct drm_file *file,
                struct drm_device *dev,
@@ -694,7 +699,7 @@ i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno)
 
        ret = 0;
        if (seqno == ring->outstanding_lazy_request)
-               ret = i915_add_request(ring, NULL, NULL);
+               ret = i915_add_request(ring, NULL);
 
        return ret;
 }
@@ -822,6 +827,25 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno)
                            interruptible, NULL);
 }
 
+static int
+i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj,
+                                    struct intel_ring_buffer *ring)
+{
+       i915_gem_retire_requests_ring(ring);
+
+       /* Manually manage the write flush as we may have not yet
+        * retired the buffer.
+        *
+        * Note that the last_write_seqno is always the earlier of
+        * the two (read/write) seqno, so if we haved successfully waited,
+        * we know we have passed the last write.
+        */
+       obj->last_write_seqno = 0;
+       obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
+
+       return 0;
+}
+
 /**
  * Ensures that all rendering to the object has completed and the object is
  * safe to unbind from the GTT or access from the CPU.
@@ -842,18 +866,7 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
        if (ret)
                return ret;
 
-       i915_gem_retire_requests_ring(ring);
-
-       /* Manually manage the write flush as we may have not yet
-        * retired the buffer.
-        */
-       if (obj->last_write_seqno &&
-           i915_seqno_passed(seqno, obj->last_write_seqno)) {
-               obj->last_write_seqno = 0;
-               obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
-       }
-
-       return 0;
+       return i915_gem_object_wait_rendering__tail(obj, ring);
 }
 
 /* A nonblocking variant of the above wait. This is a highly dangerous routine
@@ -889,19 +902,10 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj,
        mutex_unlock(&dev->struct_mutex);
        ret = __wait_seqno(ring, seqno, reset_counter, true, NULL);
        mutex_lock(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
-       i915_gem_retire_requests_ring(ring);
-
-       /* Manually manage the write flush as we may have not yet
-        * retired the buffer.
-        */
-       if (obj->last_write_seqno &&
-           i915_seqno_passed(seqno, obj->last_write_seqno)) {
-               obj->last_write_seqno = 0;
-               obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
-       }
-
-       return ret;
+       return i915_gem_object_wait_rendering__tail(obj, ring);
 }
 
 /**
@@ -1384,7 +1388,7 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
        /* ->put_pages might need to allocate memory for the bit17 swizzle
         * array, hence protect them from being reaped by removing them from gtt
         * lists early. */
-       list_del(&obj->gtt_list);
+       list_del(&obj->global_list);
 
        ops->put_pages(obj);
        obj->pages = NULL;
@@ -1470,7 +1474,7 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
        if (ret)
                return ret;
 
-       list_add_tail(&obj->gtt_list, &dev_priv->mm.unbound_list);
+       list_add_tail(&obj->global_list, &dev_priv->mm.unbound_list);
        return 0;
 }
 
@@ -1483,6 +1487,10 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
        u32 seqno = intel_ring_get_seqno(ring);
 
        BUG_ON(ring == NULL);
+       if (obj->ring != ring && obj->last_write_seqno) {
+               /* Keep the seqno relative to the current ring */
+               obj->last_write_seqno = seqno;
+       }
        obj->ring = ring;
 
        /* Add a reference if we're newly entering the active list. */
@@ -1608,17 +1616,18 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno)
        return 0;
 }
 
-int
-i915_add_request(struct intel_ring_buffer *ring,
-                struct drm_file *file,
-                u32 *out_seqno)
+int __i915_add_request(struct intel_ring_buffer *ring,
+                      struct drm_file *file,
+                      struct drm_i915_gem_object *obj,
+                      u32 *out_seqno)
 {
        drm_i915_private_t *dev_priv = ring->dev->dev_private;
        struct drm_i915_gem_request *request;
-       u32 request_ring_position;
+       u32 request_ring_position, request_start;
        int was_empty;
        int ret;
 
+       request_start = intel_ring_get_tail(ring);
        /*
         * Emit any outstanding flushes - execbuf can fail to emit the flush
         * after having emitted the batchbuffer command. Hence we need to fix
@@ -1650,7 +1659,21 @@ i915_add_request(struct intel_ring_buffer *ring,
 
        request->seqno = intel_ring_get_seqno(ring);
        request->ring = ring;
+       request->head = request_start;
        request->tail = request_ring_position;
+       request->ctx = ring->last_context;
+       request->batch_obj = obj;
+
+       /* Whilst this request exists, batch_obj will be on the
+        * active_list, and so will hold the active reference. Only when this
+        * request is retired will the the batch_obj be moved onto the
+        * inactive_list and lose its active reference. Hence we do not need
+        * to explicitly hold another reference here.
+        */
+
+       if (request->ctx)
+               i915_gem_context_reference(request->ctx);
+
        request->emitted_jiffies = jiffies;
        was_empty = list_empty(&ring->request_list);
        list_add_tail(&request->list, &ring->request_list);
@@ -1702,9 +1725,114 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
        spin_unlock(&file_priv->mm.lock);
 }
 
+static bool i915_head_inside_object(u32 acthd, struct drm_i915_gem_object *obj)
+{
+       if (acthd >= obj->gtt_offset &&
+           acthd < obj->gtt_offset + obj->base.size)
+               return true;
+
+       return false;
+}
+
+static bool i915_head_inside_request(const u32 acthd_unmasked,
+                                    const u32 request_start,
+                                    const u32 request_end)
+{
+       const u32 acthd = acthd_unmasked & HEAD_ADDR;
+
+       if (request_start < request_end) {
+               if (acthd >= request_start && acthd < request_end)
+                       return true;
+       } else if (request_start > request_end) {
+               if (acthd >= request_start || acthd < request_end)
+                       return true;
+       }
+
+       return false;
+}
+
+static bool i915_request_guilty(struct drm_i915_gem_request *request,
+                               const u32 acthd, bool *inside)
+{
+       /* There is a possibility that unmasked head address
+        * pointing inside the ring, matches the batch_obj address range.
+        * However this is extremely unlikely.
+        */
+
+       if (request->batch_obj) {
+               if (i915_head_inside_object(acthd, request->batch_obj)) {
+                       *inside = true;
+                       return true;
+               }
+       }
+
+       if (i915_head_inside_request(acthd, request->head, request->tail)) {
+               *inside = false;
+               return true;
+       }
+
+       return false;
+}
+
+static void i915_set_reset_status(struct intel_ring_buffer *ring,
+                                 struct drm_i915_gem_request *request,
+                                 u32 acthd)
+{
+       struct i915_ctx_hang_stats *hs = NULL;
+       bool inside, guilty;
+
+       /* Innocent until proven guilty */
+       guilty = false;
+
+       if (ring->hangcheck.action != wait &&
+           i915_request_guilty(request, acthd, &inside)) {
+               DRM_ERROR("%s hung %s bo (0x%x ctx %d) at 0x%x\n",
+                         ring->name,
+                         inside ? "inside" : "flushing",
+                         request->batch_obj ?
+                         request->batch_obj->gtt_offset : 0,
+                         request->ctx ? request->ctx->id : 0,
+                         acthd);
+
+               guilty = true;
+       }
+
+       /* If contexts are disabled or this is the default context, use
+        * file_priv->reset_state
+        */
+       if (request->ctx && request->ctx->id != DEFAULT_CONTEXT_ID)
+               hs = &request->ctx->hang_stats;
+       else if (request->file_priv)
+               hs = &request->file_priv->hang_stats;
+
+       if (hs) {
+               if (guilty)
+                       hs->batch_active++;
+               else
+                       hs->batch_pending++;
+       }
+}
+
+static void i915_gem_free_request(struct drm_i915_gem_request *request)
+{
+       list_del(&request->list);
+       i915_gem_request_remove_from_client(request);
+
+       if (request->ctx)
+               i915_gem_context_unreference(request->ctx);
+
+       kfree(request);
+}
+
 static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
                                      struct intel_ring_buffer *ring)
 {
+       u32 completed_seqno;
+       u32 acthd;
+
+       acthd = intel_ring_get_active_head(ring);
+       completed_seqno = ring->get_seqno(ring, false);
+
        while (!list_empty(&ring->request_list)) {
                struct drm_i915_gem_request *request;
 
@@ -1712,9 +1840,10 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
                                           struct drm_i915_gem_request,
                                           list);
 
-               list_del(&request->list);
-               i915_gem_request_remove_from_client(request);
-               drm_free(request, M_DRM);
+               if (request->seqno > completed_seqno)
+                       i915_set_reset_status(ring, request, acthd);
+
+               i915_gem_free_request(request);
        }
 
        while (!list_empty(&ring->active_list)) {
@@ -1735,7 +1864,17 @@ void i915_gem_restore_fences(struct drm_device *dev)
 
        for (i = 0; i < dev_priv->num_fence_regs; i++) {
                struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
-               i915_gem_write_fence(dev, i, reg->obj);
+
+               /*
+                * Commit delayed tiling changes if we have an object still
+                * attached to the fence, otherwise just clear the fence.
+                */
+               if (reg->obj) {
+                       i915_gem_object_update_fence(reg->obj, reg,
+                                                    reg->obj->tiling_mode);
+               } else {
+                       i915_gem_write_fence(dev, i, NULL);
+               }
        }
 }
 
@@ -1794,9 +1933,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
                 */
                ring->last_retired_head = request->tail;
 
-               list_del(&request->list);
-               i915_gem_request_remove_from_client(request);
-               kfree(request);
+               i915_gem_free_request(request);
        }
 
        /* Move any buffers on the active list that are no longer referenced
@@ -1843,7 +1980,7 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
 
        list_for_each_entry_safe(obj, next,
                                 &dev_priv->mm.unbound_list,
-                                gtt_list) {
+                                global_list) {
 #if 0
                if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) &&
                    i915_gem_object_put_pages(obj) == 0) {
@@ -1905,7 +2042,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
        idle = true;
        for_each_ring(ring, dev_priv, i) {
                if (ring->gpu_caches_dirty)
-                       i915_add_request(ring, NULL, NULL);
+                       i915_add_request(ring, NULL);
 
                idle &= list_empty(&ring->request_list);
        }
@@ -2150,7 +2287,7 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
 
        i915_gem_object_put_pages_gtt(obj);
 
-       list_del_init(&obj->gtt_list);
+       list_del_init(&obj->global_list);
        list_del_init(&obj->mm_list);
        /* Avoid an unnecessary call to unbind on rebind. */
        obj->map_and_fenceable = true;
@@ -2191,7 +2328,6 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
        drm_i915_private_t *dev_priv = dev->dev_private;
        int fence_reg;
        int fence_pitch_shift;
-       uint64_t val;
 
        if (INTEL_INFO(dev)->gen >= 6) {
                fence_reg = FENCE_REG_SANDYBRIDGE_0;
@@ -2201,8 +2337,23 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
                fence_pitch_shift = I965_FENCE_PITCH_SHIFT;
        }
 
+       fence_reg += reg * 8;
+
+       /* To w/a incoherency with non-atomic 64-bit register updates,
+        * we split the 64-bit update into two 32-bit writes. In order
+        * for a partial fence not to be evaluated between writes, we
+        * precede the update with write to turn off the fence register,
+        * and only enable the fence as the last step.
+        *
+        * For extra levels of paranoia, we make sure each step lands
+        * before applying the next step.
+        */
+       I915_WRITE(fence_reg, 0);
+       POSTING_READ(fence_reg);
+
        if (obj) {
                u32 size = obj->gtt_space->size;
+               uint64_t val;
 
                val = (uint64_t)((obj->gtt_offset + size - 4096) &
                                 0xfffff000) << 32;
@@ -2211,12 +2362,16 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
                if (obj->tiling_mode == I915_TILING_Y)
                        val |= 1 << I965_FENCE_TILING_Y_SHIFT;
                val |= I965_FENCE_REG_VALID;
-       } else
-               val = 0;
 
-       fence_reg += reg * 8;
-       I915_WRITE64(fence_reg, val);
-       POSTING_READ(fence_reg);
+               I915_WRITE(fence_reg + 4, val >> 32);
+               POSTING_READ(fence_reg + 4);
+
+               I915_WRITE(fence_reg + 0, val);
+               POSTING_READ(fence_reg);
+       } else {
+               I915_WRITE(fence_reg + 4, 0);
+               POSTING_READ(fence_reg + 4);
+       }
 }
 
 static void i915_write_fence_reg(struct drm_device *dev, int reg,
@@ -2311,6 +2466,10 @@ static void i915_gem_write_fence(struct drm_device *dev, int reg,
        if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj))
                cpu_mfence();
 
+       WARN(obj && (!obj->stride || !obj->tiling_mode),
+            "bogus fence setup with stride: 0x%x, tiling mode: %i\n",
+            obj->stride, obj->tiling_mode);
+
        switch (INTEL_INFO(dev)->gen) {
        case 7:
        case 6:
@@ -2338,26 +2497,13 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
                                         struct drm_i915_fence_reg *fence,
                                         bool enable)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int fence_reg = fence_number(dev_priv, fence);
-
-       /* In order to fully serialize access to the fenced region and
-        * the update to the fence register we need to take extreme
-        * measures on SNB+. In theory, the write to the fence register
-        * flushes all memory transactions before, and coupled with the
-        * mb() placed around the register write we serialise all memory
-        * operations with respect to the changes in the tiler. Yet, on
-        * SNB+ we need to take a step further and emit an explicit wbinvd()
-        * on each processor in order to manually flush all memory
-        * transactions before updating the fence register.
-        */
-       if (HAS_LLC(obj->base.dev))
-               cpu_wbinvd_on_all_cpus();
-       i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL);
+       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+       int reg = fence_number(dev_priv, fence);
+
+       i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL);
 
        if (enable) {
-               obj->fence_reg = fence_reg;
+               obj->fence_reg = reg;
                fence->obj = obj;
                list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list);
        } else {
@@ -2365,6 +2511,7 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
                fence->obj = NULL;
                list_del_init(&fence->lru_list);
        }
+       obj->fence_dirty = false;
 }
 
 static int
@@ -2494,7 +2641,6 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
                return 0;
 
        i915_gem_object_update_fence(obj, reg, enable);
-       obj->fence_dirty = false;
 
        return 0;
 }
@@ -2536,7 +2682,7 @@ static void i915_gem_verify_gtt(struct drm_device *dev)
        struct drm_i915_gem_object *obj;
        int err = 0;
 
-       list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+       list_for_each_entry(obj, &dev_priv->mm.global_list, global_list) {
                if (obj->gtt_space == NULL) {
                        printk(KERN_ERR "object found on GTT list with no space reserved\n");
                        err++;
@@ -2580,9 +2726,11 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
 {
        struct drm_device *dev = obj->base.dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_mm_node *free_space;
-       uint32_t size, fence_size, fence_alignment, unfenced_alignment;
+       struct drm_mm_node *node;
+       u32 size, fence_size, fence_alignment, unfenced_alignment;
        bool mappable, fenceable;
+       size_t gtt_max = map_and_fenceable ?
+               dev_priv->gtt.mappable_end : dev_priv->gtt.total;
        int ret;
 
        fence_size = i915_gem_get_gtt_size(dev,
@@ -2609,33 +2757,34 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
        /* If the object is bigger than the entire aperture, reject it early
         * before evicting everything in a vain attempt to find space.
         */
-       if (obj->base.size >
-           (map_and_fenceable ? dev_priv->gtt.mappable_end : dev_priv->gtt.total)) {
-               DRM_ERROR("Attempting to bind an object larger than the aperture\n");
+       if (obj->base.size > gtt_max) {
+               DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%zu\n",
+                         obj->base.size,
+                         map_and_fenceable ? "mappable" : "total",
+                         gtt_max);
                return -E2BIG;
        }
 
  search_free:
        if (map_and_fenceable)
-               free_space =
-                       drm_mm_search_free_in_range_color(&dev_priv->mm.gtt_space,
+               node = drm_mm_search_free_in_range_color(&dev_priv->mm.gtt_space,
                                                          size, alignment, obj->cache_level,
                                                          0, dev_priv->gtt.mappable_end,
                                                          false);
        else
-               free_space = drm_mm_search_free_color(&dev_priv->mm.gtt_space,
+               node = drm_mm_search_free_color(&dev_priv->mm.gtt_space,
                                                      size, alignment, obj->cache_level,
                                                      false);
-       if (free_space != NULL) {
+       if (node != NULL) {
                if (map_and_fenceable)
                        obj->gtt_space =
-                               drm_mm_get_block_range_generic(free_space,
+                               drm_mm_get_block_range_generic(node,
                                                               size, alignment, obj->cache_level,
                                                               0, dev_priv->gtt.mappable_end,
                                                               false);
                else
                        obj->gtt_space =
-                               drm_mm_get_block_generic(free_space,
+                               drm_mm_get_block_generic(node,
                                                         size, alignment, obj->cache_level,
                                                         false);
        }
@@ -2671,7 +2820,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
                goto search_free;
        }
 
-       list_add_tail(&obj->gtt_list, &dev_priv->mm.bound_list);
+       list_add_tail(&obj->global_list, &dev_priv->mm.bound_list);
        list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
 
        obj->gtt_offset = obj->gtt_space->start;
@@ -2685,6 +2834,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
 
        obj->map_and_fenceable = mappable && fenceable;
 
+       trace_i915_gem_object_bind(obj, map_and_fenceable);
        i915_gem_verify_gtt(dev);
        return 0;
 }
@@ -3358,7 +3508,7 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
                          const struct drm_i915_gem_object_ops *ops)
 {
        INIT_LIST_HEAD(&obj->mm_list);
-       INIT_LIST_HEAD(&obj->gtt_list);
+       INIT_LIST_HEAD(&obj->global_list);
        INIT_LIST_HEAD(&obj->ring_list);
        INIT_LIST_HEAD(&obj->exec_list);
 
@@ -3460,13 +3610,23 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
                dev_priv->mm.interruptible = was_interruptible;
        }
 
+       /* Stolen objects don't hold a ref, but do hold pin count. Fix that up
+        * before progressing. */
+       if (obj->stolen)
+               i915_gem_object_unpin_pages(obj);
+
+       if (WARN_ON(obj->pages_pin_count))
+               obj->pages_pin_count = 0;
+       i915_gem_object_put_pages(obj);
        drm_gem_free_mmap_offset(&obj->base);
 
+       BUG_ON(obj->pages);
+
        drm_gem_object_release(&obj->base);
        i915_gem_info_remove_obj(dev_priv, obj->base.size);
 
-       drm_free(obj->bit_17, M_DRM);
-       drm_free(obj, M_DRM);
+       kfree(obj->bit_17);
+       i915_gem_object_free(obj);
 }
 
 int
@@ -3606,12 +3766,21 @@ static int i915_gem_init_rings(struct drm_device *dev)
                        goto cleanup_bsd_ring;
        }
 
+       if (HAS_VEBOX(dev)) {
+               ret = intel_init_vebox_ring_buffer(dev);
+               if (ret)
+                       goto cleanup_blt_ring;
+       }
+
+
        ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000));
        if (ret)
-               goto cleanup_blt_ring;
+               goto cleanup_vebox_ring;
 
        return 0;
 
+cleanup_vebox_ring:
+       intel_cleanup_ring_buffer(&dev_priv->ring[VECS]);
 cleanup_blt_ring:
        intel_cleanup_ring_buffer(&dev_priv->ring[BCS]);
 cleanup_bsd_ring:
@@ -4275,6 +4444,7 @@ i915_gem_assert_pages_not_mapped(struct drm_device *dev, vm_page_t *ma,
                        }
                }
        }
+       obj->fence_dirty = false;
 }
 #endif
 
index 3dd6d56..8572d44 100644 (file)
@@ -114,7 +114,7 @@ static int get_context_size(struct drm_device *dev)
        case 7:
                reg = I915_READ(GEN7_CXT_SIZE);
                if (IS_HASWELL(dev))
-                       ret = HSW_CXT_TOTAL_SIZE(reg) * 64;
+                       ret = HSW_CXT_TOTAL_SIZE;
                else
                        ret = GEN7_CXT_TOTAL_SIZE(reg) * 64;
                break;
@@ -125,10 +125,10 @@ static int get_context_size(struct drm_device *dev)
        return ret;
 }
 
-static void do_destroy(struct i915_hw_context *ctx)
+void i915_gem_context_free(struct kref *ctx_ref)
 {
-       if (ctx->file_priv)
-               idr_remove(&ctx->file_priv->context_idr, ctx->id);
+       struct i915_hw_context *ctx = container_of(ctx_ref,
+                                                  typeof(*ctx), ref);
 
        drm_gem_object_unreference(&ctx->obj->base);
        kfree(ctx);
@@ -146,6 +146,7 @@ create_hw_context(struct drm_device *dev,
        if (ctx == NULL)
                return ERR_PTR(-ENOMEM);
 
+       kref_init(&ctx->ref);
        ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size);
        if (ctx->obj == NULL) {
                kfree(ctx);
@@ -156,7 +157,8 @@ create_hw_context(struct drm_device *dev,
        if (INTEL_INFO(dev)->gen >= 7) {
                ret = i915_gem_object_set_cache_level(ctx->obj,
                                                      I915_CACHE_LLC_MLC);
-               if (ret)
+               /* Failure shouldn't ever happen this early */
+               if (WARN_ON(ret))
                        goto err_out;
        }
 
@@ -170,18 +172,18 @@ create_hw_context(struct drm_device *dev,
        if (file_priv == NULL)
                return ctx;
 
-       ctx->file_priv = file_priv;
-
        ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID + 1, 0,
                        GFP_KERNEL);
        if (ret < 0)
                goto err_out;
+
+       ctx->file_priv = file_priv;
        ctx->id = ret;
 
        return ctx;
 
 err_out:
-       do_destroy(ctx);
+       i915_gem_context_unreference(ctx);
        return ERR_PTR(ret);
 }
 
@@ -214,12 +216,16 @@ static int create_default_context(struct drm_i915_private *dev_priv)
         */
        dev_priv->ring[RCS].default_context = ctx;
        ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false, false);
-       if (ret)
+       if (ret) {
+               DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret);
                goto err_destroy;
+       }
 
        ret = do_switch(ctx);
-       if (ret)
+       if (ret) {
+               DRM_DEBUG_DRIVER("Switch failed %d\n", ret);
                goto err_unpin;
+       }
 
        DRM_DEBUG_DRIVER("Default HW context loaded\n");
        return 0;
@@ -227,7 +233,7 @@ static int create_default_context(struct drm_i915_private *dev_priv)
 err_unpin:
        i915_gem_object_unpin(ctx->obj);
 err_destroy:
-       do_destroy(ctx);
+       i915_gem_context_unreference(ctx);
        return ret;
 }
 
@@ -237,6 +243,7 @@ void i915_gem_context_init(struct drm_device *dev)
 
        if (!HAS_HW_CONTEXTS(dev)) {
                dev_priv->hw_contexts_disabled = true;
+               DRM_DEBUG_DRIVER("Disabling HW Contexts; old hardware\n");
                return;
        }
 
@@ -249,11 +256,13 @@ void i915_gem_context_init(struct drm_device *dev)
 
        if (dev_priv->hw_context_size > (1<<20)) {
                dev_priv->hw_contexts_disabled = true;
+               DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size\n");
                return;
        }
 
        if (create_default_context(dev_priv)) {
                dev_priv->hw_contexts_disabled = true;
+               DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed\n");
                return;
        }
 
@@ -263,6 +272,7 @@ void i915_gem_context_init(struct drm_device *dev)
 void i915_gem_context_fini(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context;
 
        if (dev_priv->hw_contexts_disabled)
                return;
@@ -272,9 +282,16 @@ void i915_gem_context_fini(struct drm_device *dev)
         * other code, leading to spurious errors. */
        intel_gpu_reset(dev);
 
-       i915_gem_object_unpin(dev_priv->ring[RCS].default_context->obj);
+       i915_gem_object_unpin(dctx->obj);
 
-       do_destroy(dev_priv->ring[RCS].default_context);
+       /* When default context is created and switched to, base object refcount
+        * will be 2 (+1 from object creation and +1 from do_switch()).
+        * i915_gem_context_fini() will be called after gpu_idle() has switched
+        * to default context. So we need to unreference the base object once
+        * to offset the do_switch part, so that i915_gem_context_unreference()
+        * can then free the base object correctly. */
+       drm_gem_object_unreference(&dctx->obj->base);
+       i915_gem_context_unreference(dctx);
 }
 
 static int context_idr_cleanup(int id, void *p, void *data)
@@ -283,11 +300,38 @@ static int context_idr_cleanup(int id, void *p, void *data)
 
        BUG_ON(id == DEFAULT_CONTEXT_ID);
 
-       do_destroy(ctx);
-
+       i915_gem_context_unreference(ctx);
        return 0;
 }
 
+struct i915_ctx_hang_stats *
+i915_gem_context_get_hang_stats(struct intel_ring_buffer *ring,
+                               struct drm_file *file,
+                               u32 id)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct drm_i915_file_private *file_priv = file->driver_priv;
+       struct i915_hw_context *to;
+
+       if (dev_priv->hw_contexts_disabled)
+               return ERR_PTR(-ENOENT);
+
+       if (ring->id != RCS)
+               return ERR_PTR(-EINVAL);
+
+       if (file == NULL)
+               return ERR_PTR(-EINVAL);
+
+       if (id == DEFAULT_CONTEXT_ID)
+               return &file_priv->hang_stats;
+
+       to = i915_gem_context_get(file->driver_priv, id);
+       if (to == NULL)
+               return ERR_PTR(-ENOENT);
+
+       return &to->hang_stats;
+}
+
 void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
 {
        struct drm_i915_file_private *file_priv = file->driver_priv;
@@ -326,6 +370,7 @@ mi_set_context(struct intel_ring_buffer *ring,
        if (ret)
                return ret;
 
+       /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw */
        if (IS_GEN7(ring->dev))
                intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE);
        else
@@ -354,13 +399,13 @@ mi_set_context(struct intel_ring_buffer *ring,
 static int do_switch(struct i915_hw_context *to)
 {
        struct intel_ring_buffer *ring = to->ring;
-       struct drm_i915_gem_object *from_obj = ring->last_context_obj;
+       struct i915_hw_context *from = ring->last_context;
        u32 hw_flags = 0;
        int ret;
 
-       BUG_ON(from_obj != NULL && from_obj->pin_count == 0);
+       BUG_ON(from != NULL && from->obj != NULL && from->obj->pin_count == 0);
 
-       if (from_obj == to->obj)
+       if (from == to)
                return 0;
 
        ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false, false);
@@ -383,7 +428,7 @@ static int do_switch(struct i915_hw_context *to)
 
        if (!to->is_initialized || is_default_context(to))
                hw_flags |= MI_RESTORE_INHIBIT;
-       else if (WARN_ON_ONCE(from_obj == to->obj)) /* not yet expected */
+       else if (WARN_ON_ONCE(from == to)) /* not yet expected */
                hw_flags |= MI_FORCE_RESTORE;
 
        ret = mi_set_context(ring, to, hw_flags);
@@ -398,9 +443,9 @@ static int do_switch(struct i915_hw_context *to)
         * is a bit suboptimal because the retiring can occur simply after the
         * MI_SET_CONTEXT instead of when the next seqno has completed.
         */
-       if (from_obj != NULL) {
-               from_obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
-               i915_gem_object_move_to_active(from_obj, ring);
+       if (from != NULL) {
+               from->obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
+               i915_gem_object_move_to_active(from->obj, ring);
                /* As long as MI_SET_CONTEXT is serializing, ie. it flushes the
                 * whole damn pipeline, we don't need to explicitly mark the
                 * object dirty. The only exception is that the context must be
@@ -408,15 +453,26 @@ static int do_switch(struct i915_hw_context *to)
                 * able to defer doing this until we know the object would be
                 * swapped, but there is no way to do that yet.
                 */
-               from_obj->dirty = 1;
-               BUG_ON(from_obj->ring != ring);
-               i915_gem_object_unpin(from_obj);
+               from->obj->dirty = 1;
+               BUG_ON(from->obj->ring != ring);
+
+               ret = i915_add_request(ring, NULL);
+               if (ret) {
+                       /* Too late, we've already scheduled a context switch.
+                        * Try to undo the change so that the hw state is
+                        * consistent with out tracking. In case of emergency,
+                        * scream.
+                        */
+                       WARN_ON(mi_set_context(ring, from, MI_RESTORE_INHIBIT));
+                       return ret;
+               }
 
-               drm_gem_object_unreference(&from_obj->base);
+               i915_gem_object_unpin(from->obj);
+               i915_gem_context_unreference(from);
        }
 
-       drm_gem_object_reference(&to->obj->base);
-       ring->last_context_obj = to->obj;
+       i915_gem_context_reference(to);
+       ring->last_context = to;
        to->is_initialized = true;
 
        return 0;
@@ -445,6 +501,8 @@ int i915_switch_context(struct intel_ring_buffer *ring,
        if (dev_priv->hw_contexts_disabled)
                return 0;
 
+       WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
+
        if (ring != &dev_priv->ring[RCS])
                return 0;
 
@@ -513,8 +571,8 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
                return -ENOENT;
        }
 
-       do_destroy(ctx);
-
+       idr_remove(&ctx->file_priv->context_idr, ctx->id);
+       i915_gem_context_unreference(ctx);
        mutex_unlock(&dev->struct_mutex);
 
        DRM_DEBUG_DRIVER("HW context %d destroyed\n", args->ctx_id);
index a26d94a..e9b1906 100644 (file)
@@ -791,7 +791,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
                        obj->dirty = 1;
                        obj->last_write_seqno = intel_ring_get_seqno(ring);
                        if (obj->pin_count) /* check for potential scanout */
-                               intel_mark_fb_busy(obj);
+                               intel_mark_fb_busy(obj, ring);
                }
 
                trace_i915_gem_object_change_domain(obj, old_read, old_write);
@@ -801,13 +801,14 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
 static void
 i915_gem_execbuffer_retire_commands(struct drm_device *dev,
                                    struct drm_file *file,
-                                   struct intel_ring_buffer *ring)
+                                   struct intel_ring_buffer *ring,
+                                   struct drm_i915_gem_object *obj)
 {
        /* Unconditionally force add_request to emit a full flush. */
        ring->gpu_caches_dirty = true;
 
        /* Add a breadcrumb for the completion of the batch buffer */
-       (void)i915_add_request(ring, file, NULL);
+       (void)__i915_add_request(ring, file, obj, NULL);
 }
 
 static int
@@ -887,6 +888,15 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                        return -EPERM;
                }
                break;
+       case I915_EXEC_VEBOX:
+               ring = &dev_priv->ring[VECS];
+               if (ctx_id != 0) {
+                       DRM_DEBUG("Ring %s doesn't support contexts\n",
+                                 ring->name);
+                       return -EPERM;
+               }
+               break;
+
        default:
                DRM_DEBUG("execbuf with unknown ring: %d\n",
                          (int)(args->flags & I915_EXEC_RING_MASK));
@@ -1076,7 +1086,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags);
 
        i915_gem_execbuffer_move_to_active(&eb->objects, ring);
-       i915_gem_execbuffer_retire_commands(dev, file, ring);
+       i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
 
 err:
        eb_destroy(eb);
index 4c4d56c..f9c896d 100644 (file)
@@ -29,8 +29,6 @@
 
 #include <linux/highmem.h>
 
-typedef uint32_t gen6_gtt_pte_t;
-
 /* PPGTT stuff */
 #define GEN6_GTT_ADDR_ENCODE(addr)     ((addr) | (((addr) >> 28) & 0xff0))
 
@@ -45,29 +43,22 @@ typedef uint32_t gen6_gtt_pte_t;
 #define GEN6_PTE_CACHE_LLC_MLC         (3 << 1)
 #define GEN6_PTE_ADDR_ENCODE(addr)     GEN6_GTT_ADDR_ENCODE(addr)
 
-static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
-                                            dma_addr_t addr,
-                                            enum i915_cache_level level)
+static gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
+                                     dma_addr_t addr,
+                                     enum i915_cache_level level)
 {
        gen6_gtt_pte_t pte = GEN6_PTE_VALID;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
        case I915_CACHE_LLC_MLC:
-               /* Haswell doesn't set L3 this way */
-               if (IS_HASWELL(dev))
-                       pte |= GEN6_PTE_CACHE_LLC;
-               else
-                       pte |= GEN6_PTE_CACHE_LLC_MLC;
+               pte |= GEN6_PTE_CACHE_LLC_MLC;
                break;
        case I915_CACHE_LLC:
                pte |= GEN6_PTE_CACHE_LLC;
                break;
        case I915_CACHE_NONE:
-               if (IS_HASWELL(dev))
-                       pte |= HSW_PTE_UNCACHED;
-               else
-                       pte |= GEN6_PTE_UNCACHED;
+               pte |= GEN6_PTE_UNCACHED;
                break;
        default:
                BUG();
@@ -76,6 +67,40 @@ static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
        return pte;
 }
 
+#define BYT_PTE_WRITEABLE              (1 << 1)
+#define BYT_PTE_SNOOPED_BY_CPU_CACHES  (1 << 2)
+
+static gen6_gtt_pte_t byt_pte_encode(struct drm_device *dev,
+                                    dma_addr_t addr,
+                                    enum i915_cache_level level)
+{
+       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       pte |= GEN6_PTE_ADDR_ENCODE(addr);
+
+       /* Mark the page as writeable.  Other platforms don't have a
+        * setting for read-only/writable, so this matches that behavior.
+        */
+       pte |= BYT_PTE_WRITEABLE;
+
+       if (level != I915_CACHE_NONE)
+               pte |= BYT_PTE_SNOOPED_BY_CPU_CACHES;
+
+       return pte;
+}
+
+static gen6_gtt_pte_t hsw_pte_encode(struct drm_device *dev,
+                                    dma_addr_t addr,
+                                    enum i915_cache_level level)
+{
+       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       pte |= GEN6_PTE_ADDR_ENCODE(addr);
+
+       if (level != I915_CACHE_NONE)
+               pte |= GEN6_PTE_CACHE_LLC;
+
+       return pte;
+}
+
 static int gen6_ppgtt_enable(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -85,6 +110,8 @@ static int gen6_ppgtt_enable(struct drm_device *dev)
        uint32_t pd_entry, first_pd_entry_in_global_pt;
        int i;
 
+       WARN_ON(ppgtt->pd_offset & 0x3f);
+
        first_pd_entry_in_global_pt = 512 * 1024 - I915_PPGTT_PD_ENTRIES;
        for (i = 0; i < ppgtt->num_pd_entries; i++) {
                dma_addr_t pt_addr;
@@ -153,9 +180,9 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
        unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
        unsigned last_pte, i;
 
-       scratch_pte = gen6_pte_encode(ppgtt->dev,
-                                     ppgtt->scratch_page_dma_addr,
-                                     I915_CACHE_LLC);
+       scratch_pte = ppgtt->pte_encode(ppgtt->dev,
+                                       ppgtt->scratch_page_dma_addr,
+                                       I915_CACHE_LLC);
 
        while (num_entries) {
                last_pte = first_pte + num_entries;
@@ -198,7 +225,7 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
 
                for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) {
                        page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
-                       pt_vaddr[j] = gen6_pte_encode(ppgtt->dev, page_addr,
+                       pt_vaddr[j] = ppgtt->pte_encode(ppgtt->dev, page_addr,
                                                      cache_level);
 
                        /* grab the next page */
@@ -253,6 +280,13 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
         */
        first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt);
 
+       if (IS_HASWELL(dev)) {
+               ppgtt->pte_encode = hsw_pte_encode;
+       } else if (IS_VALLEYVIEW(dev)) {
+               ppgtt->pte_encode = byt_pte_encode;
+       } else {
+               ppgtt->pte_encode = gen6_pte_encode;
+       }
        ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
        ppgtt->enable = gen6_ppgtt_enable;
        ppgtt->clear_range = gen6_ppgtt_clear_range;
@@ -322,31 +356,6 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
        dev_priv->mm.aliasing_ppgtt = NULL;
 }
 
-#if 0
-void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
-       vm_page_t m;
-       int i;
-
-       if (!ppgtt)
-               return;
-       dev_priv->mm.aliasing_ppgtt = NULL;
-
-       for (i = 0; i < ppgtt->num_pd_entries; i++) {
-               m = ppgtt->pt_pages[i];
-               if (m != NULL) {
-                       vm_page_busy_wait(m, FALSE, "i915gem");
-                       vm_page_unwire(m, 0);
-                       vm_page_free(m);
-               }
-       }
-       drm_free(ppgtt->pt_pages, M_DRM);
-       drm_free(ppgtt, M_DRM);
-}
-#endif
-
 static void
 i915_ppgtt_insert_pages(struct i915_hw_ppgtt *ppgtt, unsigned first_entry,
     unsigned num_entries, vm_page_t *pages, enum i915_cache_level cache_level)
@@ -366,7 +375,7 @@ i915_ppgtt_insert_pages(struct i915_hw_ppgtt *ppgtt, unsigned first_entry,
 
                for (i = first_pte; i < last_pte; i++) {
                        page_addr = VM_PAGE_TO_PHYS(*pages);
-                       pt_vaddr[i] = gen6_pte_encode(ppgtt->dev, page_addr,
+                       pt_vaddr[i] = ppgtt->pte_encode(ppgtt->dev, page_addr,
                                                 cache_level);
 
                        pages++;
@@ -443,7 +452,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
        dev_priv->gtt.gtt_clear_range(dev, dev_priv->gtt.start / PAGE_SIZE,
                                      dev_priv->gtt.total / PAGE_SIZE);
 
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                i915_gem_clflush_object(obj);
                i915_gem_gtt_bind_object(obj, obj->cache_level);
        }
@@ -472,28 +481,24 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
  * within the global GTT as well as accessible by the GPU through the GMADR
  * mapped BAR (dev_priv->mm.gtt->gtt).
  */
+#if 0
 static void gen6_ggtt_insert_entries(struct drm_device *dev,
                                     struct sg_table *st,
                                     unsigned int first_entry,
                                     enum i915_cache_level level)
 {
-#if 0
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct scatterlist *sg = st->sgl;
-       gtt_pte_t __iomem *gtt_entries =
-               (gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
-       int unused, i = 0;
-       unsigned int len, m = 0;
+       gen6_gtt_pte_t __iomem *gtt_entries =
+               (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
+       int i = 0;
+       struct sg_page_iter sg_iter;
        dma_addr_t addr;
 
-       for_each_sg(st->sgl, sg, st->nents, unused) {
-               len = sg_dma_len(sg) >> PAGE_SHIFT;
-               for (m = 0; m < len; m++) {
-                       addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
-                       iowrite32(gen6_pte_encode(dev, addr, level),
-                                 &gtt_entries[i]);
-                       i++;
-               }
+       for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
+               addr = sg_page_iter_dma_address(&sg_iter);
+               iowrite32(dev_priv->gtt.pte_encode(dev, addr, level),
+                         &gtt_entries[i]);
+               i++;
        }
 
        /* XXX: This serves as a posting read to make sure that the PTE has
@@ -504,7 +509,7 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
         */
        if (i != 0)
                WARN_ON(readl(&gtt_entries[i-1])
-                       != gen6_pte_encode(dev, addr, level));
+                       != dev_priv->gtt.pte_encode(dev, addr, level));
 
        /* This next bit makes the above posting read even more important. We
         * want to flush the TLBs only after we're certain all the PTE updates
@@ -512,7 +517,6 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
         */
        I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
        POSTING_READ(GFX_FLSH_CNTL_GEN6);
-#endif
 }
 
 static void gen6_ggtt_clear_range(struct drm_device *dev,
@@ -530,12 +534,14 @@ static void gen6_ggtt_clear_range(struct drm_device *dev,
                 first_entry, num_entries, max_entries))
                num_entries = max_entries;
 
-       scratch_pte = gen6_pte_encode(dev, dev_priv->gtt.scratch_page_dma,
-                                     I915_CACHE_LLC);
+       scratch_pte = dev_priv->gtt.pte_encode(dev,
+                                              dev_priv->gtt.scratch_page_dma,
+                                              I915_CACHE_LLC);
        for (i = 0; i < num_entries; i++)
                iowrite32(scratch_pte, &gtt_base[i]);
        readl(gtt_base);
 }
+#endif
 
 static void i915_ggtt_insert_entries(struct drm_device *dev,
                                     struct sg_table *st,
@@ -699,24 +705,115 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
        i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 }
 
-int i915_gem_gtt_init(struct drm_device *dev)
+#if 0
+static int gen6_gmch_probe(struct drm_device *dev,
+                          size_t *gtt_total,
+                          size_t *stolen,
+                          phys_addr_t *mappable_base,
+                          unsigned long *mappable_end)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       phys_addr_t gtt_bus_addr;
+       unsigned int gtt_size;
+       u16 snb_gmch_ctl;
+       int ret;
+
+       *mappable_base = pci_resource_start(dev->pdev, 2);
+       *mappable_end = pci_resource_len(dev->pdev, 2);
 
-       /* On modern platforms we need not worry ourself with the legacy
-        * hostbridge query stuff. Skip it entirely
+       /* 64/512MB is the current min/max we actually know of, but this is just
+        * a coarse sanity check.
         */
-       if (INTEL_INFO(dev)->gen < 6 || 1) {
-               dev_priv->mm.gtt = intel_gtt_get();
-               if (!dev_priv->mm.gtt) {
-                       DRM_ERROR("Failed to initialize GTT\n");
-                       return -ENODEV;
-               }
+       if ((*mappable_end < (64<<20) || (*mappable_end > (512<<20)))) {
+               DRM_ERROR("Unknown GMADR size (%lx)\n",
+                         dev_priv->gtt.mappable_end);
+               return -ENXIO;
+       }
+
+       if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(40)))
+               pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(40));
+       pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+       gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl);
+
+       if (IS_GEN7(dev) && !IS_VALLEYVIEW(dev))
+               *stolen = gen7_get_stolen_size(snb_gmch_ctl);
+       else
+               *stolen = gen6_get_stolen_size(snb_gmch_ctl);
+
+       *gtt_total = (gtt_size / sizeof(gen6_gtt_pte_t)) << PAGE_SHIFT;
+
+       /* For Modern GENs the PTEs and register space are split in the BAR */
+       gtt_bus_addr = pci_resource_start(dev->pdev, 0) +
+               (pci_resource_len(dev->pdev, 0) / 2);
+
+       dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size);
+       if (!dev_priv->gtt.gsm) {
+               DRM_ERROR("Failed to map the gtt page table\n");
+               return -ENOMEM;
+       }
+
+       ret = setup_scratch_page(dev);
+       if (ret)
+               DRM_ERROR("Scratch setup failed\n");
+
+       dev_priv->gtt.gtt_clear_range = gen6_ggtt_clear_range;
+       dev_priv->gtt.gtt_insert_entries = gen6_ggtt_insert_entries;
+
+       return 0;
+}
+
+static void gen6_gmch_remove(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       iounmap(dev_priv->gtt.gsm);
+       teardown_scratch_page(dev_priv->dev);
+}
+#endif
+
+static int i915_gmch_probe(struct drm_device *dev,
+                          size_t *gtt_total,
+                          size_t *stolen,
+                          phys_addr_t *mappable_base,
+                          unsigned long *mappable_end)
+{
+       return 0;
+}
+
+static void i915_gmch_remove(struct drm_device *dev)
+{
+}
+
+int i915_gem_gtt_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /* XXX Legacy agp stuff */
+       dev_priv->mm.gtt = intel_gtt_get();
+       if (!dev_priv->mm.gtt) {
+               DRM_ERROR("Failed to initialize GTT\n");
+               return -ENODEV;
+       }
+
+       if (INTEL_INFO(dev)->gen <= 5 || 1) {
+               dev_priv->gtt.gtt_probe = i915_gmch_probe;
+               dev_priv->gtt.gtt_remove = i915_gmch_remove;
 
                dev_priv->gtt.do_idle_maps = needs_idle_maps(dev);
 
                dev_priv->gtt.gtt_clear_range = i915_ggtt_clear_range;
                dev_priv->gtt.gtt_insert_entries = i915_ggtt_insert_entries;
+#if 0
+       } else {
+               dev_priv->gtt.gtt_probe = gen6_gmch_probe;
+               dev_priv->gtt.gtt_remove = gen6_gmch_remove;
+#endif
+               if (IS_HASWELL(dev)) {
+                       dev_priv->gtt.pte_encode = hsw_pte_encode;
+               } else if (IS_VALLEYVIEW(dev)) {
+                       dev_priv->gtt.pte_encode = byt_pte_encode;
+               } else {
+                       dev_priv->gtt.pte_encode = gen6_pte_encode;
+               }
 
                return 0;
        }
@@ -725,13 +822,13 @@ int i915_gem_gtt_init(struct drm_device *dev)
        if (!dev_priv->mm.gtt)
                return -ENOMEM;
 
-       /* GMADR is the PCI aperture used by SW to access tiled GFX surfaces in a linear fashion. */
-       DRM_INFO("Memory usable by graphics device = %dM\n", dev_priv->mm.gtt->gtt_total_entries >> 8);
-       DRM_DEBUG_DRIVER("GMADR size = %dM\n", dev_priv->mm.gtt->gtt_mappable_entries >> 8);
-       DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", dev_priv->mm.gtt->stolen_size >> 20);
-
-       dev_priv->gtt.gtt_clear_range = gen6_ggtt_clear_range;
-       dev_priv->gtt.gtt_insert_entries = gen6_ggtt_insert_entries;
+       /* GMADR is the PCI mmio aperture into the global GTT. */
+       DRM_INFO("Memory usable by graphics device = %zdM\n",
+                dev_priv->gtt.total >> 20);
+       DRM_DEBUG_DRIVER("GMADR size = %ldM\n",
+                        dev_priv->gtt.mappable_end >> 20);
+       DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n",
+                        dev_priv->gtt.stolen_size >> 20);
 
        return 0;
 }
index ca378d6..5cd1dbd 100644 (file)
@@ -62,7 +62,10 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
         * its value of TOLUD.
         */
        base = 0;
-       if (INTEL_INFO(dev)->gen >= 6) {
+       if (IS_VALLEYVIEW(dev)) {
+               pci_read_config_dword(dev->pdev, 0x5c, &base);
+               base &= ~((1<<20) - 1);
+       } else if (INTEL_INFO(dev)->gen >= 6) {
                /* Read Base Data of Stolen Memory Register (BDSM) directly.
                 * Note that there is also a MCHBAR miror at 0x1080c0 or
                 * we could use device 2:0x5c instead.
@@ -136,6 +139,7 @@ static int i915_setup_compression(struct drm_device *dev, int size)
 err_fb:
        drm_mm_put_block(compressed_fb);
 err:
+       pr_info_once("drm: not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size);
        return -ENOSPC;
 }
 
@@ -143,7 +147,7 @@ int i915_gem_stolen_setup_compression(struct drm_device *dev, int size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (dev_priv->mm.stolen_base == 0)
+       if (!drm_mm_initialized(&dev_priv->mm.stolen))
                return -ENODEV;
 
        if (size < dev_priv->cfb_size)
@@ -175,6 +179,9 @@ void i915_gem_cleanup_stolen(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       if (!drm_mm_initialized(&dev_priv->mm.stolen))
+               return;
+
        i915_gem_stolen_cleanup_compression(dev);
        drm_mm_takedown(&dev_priv->mm.stolen);
 }
@@ -182,6 +189,7 @@ void i915_gem_cleanup_stolen(struct drm_device *dev)
 int i915_gem_init_stolen(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       int bios_reserved = 0;
 
        dev_priv->mm.stolen_base = i915_stolen_to_physical(dev);
        if (dev_priv->mm.stolen_base == 0)
@@ -190,8 +198,181 @@ int i915_gem_init_stolen(struct drm_device *dev)
        DRM_DEBUG_KMS("found %zd bytes of stolen memory at %08lx\n",
                      dev_priv->gtt.stolen_size, dev_priv->mm.stolen_base);
 
+       if (IS_VALLEYVIEW(dev))
+               bios_reserved = 1024*1024; /* top 1M on VLV/BYT */
+
        /* Basic memrange allocator for stolen space */
-       drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size);
+       drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size -
+                   bios_reserved);
 
        return 0;
 }
+
+static int i915_gem_object_get_pages_stolen(struct drm_i915_gem_object *obj)
+{
+       BUG();
+       return -EINVAL;
+}
+
+static void i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj)
+{
+#if 0
+       /* Should only be called during free */
+       sg_free_table(obj->pages);
+       kfree(obj->pages);
+#else
+       BUG();
+#endif
+}
+
+static const struct drm_i915_gem_object_ops i915_gem_object_stolen_ops = {
+       .get_pages = i915_gem_object_get_pages_stolen,
+       .put_pages = i915_gem_object_put_pages_stolen,
+};
+
+static struct drm_i915_gem_object *
+_i915_gem_object_create_stolen(struct drm_device *dev,
+                              struct drm_mm_node *stolen)
+{
+       struct drm_i915_gem_object *obj;
+
+#if 0
+       obj = i915_gem_object_alloc(dev);
+#else
+       obj = NULL;
+#endif
+       if (obj == NULL)
+               return NULL;
+
+       if (drm_gem_private_object_init(dev, &obj->base, stolen->size))
+               goto cleanup;
+
+       i915_gem_object_init(obj, &i915_gem_object_stolen_ops);
+
+#if 0
+       obj->pages = i915_pages_create_for_stolen(dev,
+                                                 stolen->start, stolen->size);
+#else
+       obj->pages = NULL;
+#endif
+       if (obj->pages == NULL)
+               goto cleanup;
+
+       obj->has_dma_mapping = true;
+       i915_gem_object_pin_pages(obj);
+       obj->stolen = stolen;
+
+       obj->base.write_domain = I915_GEM_DOMAIN_GTT;
+       obj->base.read_domains = I915_GEM_DOMAIN_GTT;
+       obj->cache_level = I915_CACHE_NONE;
+
+       return obj;
+
+cleanup:
+       i915_gem_object_free(obj);
+       return NULL;
+}
+
+struct drm_i915_gem_object *
+i915_gem_object_create_stolen(struct drm_device *dev, u32 size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj;
+       struct drm_mm_node *stolen;
+
+       if (!drm_mm_initialized(&dev_priv->mm.stolen))
+               return NULL;
+
+       DRM_DEBUG_KMS("creating stolen object: size=%x\n", size);
+       if (size == 0)
+               return NULL;
+
+       stolen = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0);
+       if (stolen)
+               stolen = drm_mm_get_block(stolen, size, 4096);
+       if (stolen == NULL)
+               return NULL;
+
+       obj = _i915_gem_object_create_stolen(dev, stolen);
+       if (obj)
+               return obj;
+
+       drm_mm_put_block(stolen);
+       return NULL;
+}
+
+struct drm_i915_gem_object *
+i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
+                                              u32 stolen_offset,
+                                              u32 gtt_offset,
+                                              u32 size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj;
+       struct drm_mm_node *stolen;
+
+       if (!drm_mm_initialized(&dev_priv->mm.stolen))
+               return NULL;
+
+       DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n",
+                       stolen_offset, gtt_offset, size);
+
+       /* KISS and expect everything to be page-aligned */
+       BUG_ON(stolen_offset & 4095);
+       BUG_ON(size & 4095);
+
+       if (WARN_ON(size == 0))
+               return NULL;
+
+#if 0
+       stolen = drm_mm_create_block(&dev_priv->mm.stolen,
+                                    stolen_offset, size,
+                                    false);
+#else
+       stolen = NULL;
+#endif
+       if (stolen == NULL) {
+               DRM_DEBUG_KMS("failed to allocate stolen space\n");
+               return NULL;
+       }
+
+       obj = _i915_gem_object_create_stolen(dev, stolen);
+       if (obj == NULL) {
+               DRM_DEBUG_KMS("failed to allocate stolen object\n");
+               drm_mm_put_block(stolen);
+               return NULL;
+       }
+
+       /* Some objects just need physical mem from stolen space */
+       if (gtt_offset == -1)
+               return obj;
+
+#if 0
+       /* To simplify the initialisation sequence between KMS and GTT,
+        * we allow construction of the stolen object prior to
+        * setting up the GTT space. The actual reservation will occur
+        * later.
+        */
+       if (drm_mm_initialized(&dev_priv->mm.gtt_space)) {
+               obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space,
+                                                    gtt_offset, size,
+                                                    false);
+               if (obj->gtt_space == NULL) {
+                       DRM_DEBUG_KMS("failed to allocate stolen GTT space\n");
+                       drm_gem_object_unreference(&obj->base);
+                       return NULL;
+               }
+       } else
+               obj->gtt_space = I915_GTT_RESERVED;
+
+       obj->gtt_offset = gtt_offset;
+       obj->has_global_gtt_mapping = 1;
+
+       list_add_tail(&obj->global_list, &dev_priv->mm.bound_list);
+       list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
+
+       return obj;
+#else
+       return NULL;
+#endif
+}
index a57b15a..64af0a1 100644 (file)
@@ -485,7 +485,7 @@ i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
        for (i = 0; i < page_count; i++) {
                char new_bit_17 = VM_PAGE_TO_PHYS(obj->pages[i]) >> 17;
                if ((new_bit_17 & 0x1) !=
-                   (test_bit(i, obj->bit_17) ? 1 : 0)) {
+                   (test_bit(i, obj->bit_17) != 0)) {
                        i915_gem_swizzle_page(obj->pages[i]);
                        vm_page_dirty(obj->pages[i]);
                }
index 33bdc17..ac8fb2d 100644 (file)
@@ -65,15 +65,6 @@ static const u32 hpd_status_gen4[] = {
        [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
 };
 
-static const u32 hpd_status_i965[] = {
-        [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
-        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I965,
-        [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I965,
-        [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
-        [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
-        [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
-};
-
 static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
        [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
@@ -83,9 +74,6 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
        [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
 };
 
-static void ibx_hpd_irq_setup(struct drm_device *dev);
-static void i915_hpd_irq_setup(struct drm_device *dev);
-
 /* For display hotplug interrupt */
 static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
@@ -107,6 +95,211 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
        }
 }
 
+static bool ivb_can_enable_err_int(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *crtc;
+       enum i915_pipe pipe;
+
+       for_each_pipe(pipe) {
+               crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+
+               if (crtc->cpu_fifo_underrun_disabled)
+                       return false;
+       }
+
+       return true;
+}
+
+static bool cpt_can_enable_serr_int(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum i915_pipe pipe;
+       struct intel_crtc *crtc;
+
+       for_each_pipe(pipe) {
+               crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+
+               if (crtc->pch_fifo_underrun_disabled)
+                       return false;
+       }
+
+       return true;
+}
+
+static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
+                                                enum i915_pipe pipe, bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN :
+                                         DE_PIPEB_FIFO_UNDERRUN;
+
+       if (enable)
+               ironlake_enable_display_irq(dev_priv, bit);
+       else
+               ironlake_disable_display_irq(dev_priv, bit);
+}
+
+static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
+                                                 bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (enable) {
+               if (!ivb_can_enable_err_int(dev))
+                       return;
+
+               I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN_A |
+                                        ERR_INT_FIFO_UNDERRUN_B |
+                                        ERR_INT_FIFO_UNDERRUN_C);
+
+               ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+       } else {
+               ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+       }
+}
+
+static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc,
+                                           bool enable)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER :
+                                               SDE_TRANSB_FIFO_UNDER;
+
+       if (enable)
+               I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~bit);
+       else
+               I915_WRITE(SDEIMR, I915_READ(SDEIMR) | bit);
+
+       POSTING_READ(SDEIMR);
+}
+
+static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
+                                           enum transcoder pch_transcoder,
+                                           bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (enable) {
+               if (!cpt_can_enable_serr_int(dev))
+                       return;
+
+               I915_WRITE(SERR_INT, SERR_INT_TRANS_A_FIFO_UNDERRUN |
+                                    SERR_INT_TRANS_B_FIFO_UNDERRUN |
+                                    SERR_INT_TRANS_C_FIFO_UNDERRUN);
+
+               I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~SDE_ERROR_CPT);
+       } else {
+               I915_WRITE(SDEIMR, I915_READ(SDEIMR) | SDE_ERROR_CPT);
+       }
+
+       POSTING_READ(SDEIMR);
+}
+
+/**
+ * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages
+ * @dev: drm device
+ * @pipe: pipe
+ * @enable: true if we want to report FIFO underrun errors, false otherwise
+ *
+ * This function makes us disable or enable CPU fifo underruns for a specific
+ * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun
+ * reporting for one pipe may also disable all the other CPU error interruts for
+ * the other pipes, due to the fact that there's just one interrupt mask/enable
+ * bit for all the pipes.
+ *
+ * Returns the previous state of underrun reporting.
+ */
+bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+                                          enum i915_pipe pipe, bool enable)
+{
+       struct drm_i915_private *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);
+       bool ret;
+
+       lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
+
+       ret = !intel_crtc->cpu_fifo_underrun_disabled;
+
+       if (enable == ret)
+               goto done;
+
+       intel_crtc->cpu_fifo_underrun_disabled = !enable;
+
+       if (IS_GEN5(dev) || IS_GEN6(dev))
+               ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
+       else if (IS_GEN7(dev))
+               ivybridge_set_fifo_underrun_reporting(dev, enable);
+
+done:
+       lockmgr(&dev_priv->irq_lock, LK_RELEASE);
+       return ret;
+}
+
+/**
+ * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages
+ * @dev: drm device
+ * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
+ * @enable: true if we want to report FIFO underrun errors, false otherwise
+ *
+ * This function makes us disable or enable PCH fifo underruns for a specific
+ * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO
+ * underrun reporting for one transcoder may also disable all the other PCH
+ * error interruts for the other transcoders, due to the fact that there's just
+ * one interrupt mask/enable bit for all the transcoders.
+ *
+ * Returns the previous state of underrun reporting.
+ */
+bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
+                                          enum transcoder pch_transcoder,
+                                          bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum i915_pipe p;
+       struct drm_crtc *crtc;
+       struct intel_crtc *intel_crtc;
+       bool ret;
+
+       if (HAS_PCH_LPT(dev)) {
+               crtc = NULL;
+               for_each_pipe(p) {
+                       struct drm_crtc *c = dev_priv->pipe_to_crtc_mapping[p];
+                       if (intel_pipe_has_type(c, INTEL_OUTPUT_ANALOG)) {
+                               crtc = c;
+                               break;
+                       }
+               }
+               if (!crtc) {
+                       DRM_ERROR("PCH FIFO underrun, but no CRTC using the PCH found\n");
+                       return false;
+               }
+       } else {
+               crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
+       }
+       intel_crtc = to_intel_crtc(crtc);
+
+       lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
+
+       ret = !intel_crtc->pch_fifo_underrun_disabled;
+
+       if (enable == ret)
+               goto done;
+
+       intel_crtc->pch_fifo_underrun_disabled = !enable;
+
+       if (HAS_PCH_IBX(dev))
+               ibx_set_fifo_underrun_reporting(intel_crtc, enable);
+       else
+               cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
+
+done:
+       lockmgr(&dev_priv->irq_lock, LK_RELEASE);
+       return ret;
+}
+
+
 void
 i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 {
@@ -137,27 +330,20 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 }
 
 /**
- * intel_enable_asle - enable ASLE interrupt for OpRegion
+ * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
  */
-void intel_enable_asle(struct drm_device *dev)
+static void i915_enable_asle_pipestat(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
 
-       /* FIXME: opregion/asle for VLV */
-       if (IS_VALLEYVIEW(dev))
+       if (!dev_priv->opregion.asle || !IS_MOBILE(dev))
                return;
 
        lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
 
-       if (HAS_PCH_SPLIT(dev))
-               ironlake_enable_display_irq(dev_priv, DE_GSE);
-       else {
-               i915_enable_pipestat(dev_priv, 1,
-                                    PIPE_LEGACY_BLC_EVENT_ENABLE);
-               if (INTEL_INFO(dev)->gen >= 4)
-                       i915_enable_pipestat(dev_priv, 0,
-                                            PIPE_LEGACY_BLC_EVENT_ENABLE);
-       }
+       i915_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE);
+       if (INTEL_INFO(dev)->gen >= 4)
+               i915_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE);
 
        lockmgr(&dev_priv->irq_lock, LK_RELEASE);
 }
@@ -175,10 +361,16 @@ static int
 i915_pipe_enabled(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
-                                                                     pipe);
 
-       return I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE;
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               /* Locking is horribly broken here, but whatever. */
+               struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+               return intel_crtc->active;
+       } else {
+               return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
+       }
 }
 
 /* Called from drm generic code, passed a 'crtc', which
@@ -328,6 +520,21 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
                                                     crtc);
 }
 
+static int intel_hpd_irq_event(struct drm_device *dev, struct drm_connector *connector)
+{
+       enum drm_connector_status old_status;
+
+       WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+       old_status = connector->status;
+
+       connector->status = connector->funcs->detect(connector, false);
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
+                     connector->base.id,
+                     drm_get_connector_name(connector),
+                     old_status, connector->status);
+       return (old_status != connector->status);
+}
+
 /*
  * Handle hotplug events outside the interrupt handler proper.
  */
@@ -343,6 +550,8 @@ static void i915_hotplug_work_func(struct work_struct *work)
        struct intel_encoder *intel_encoder;
        struct drm_connector *connector;
        bool hpd_disabled = false;
+       bool changed = false;
+       u32 hpd_event_bits;
 
        /* HPD irq before everything is fully set up. */
        if (!dev_priv->enable_hotplug_processing)
@@ -352,6 +561,9 @@ static void i915_hotplug_work_func(struct work_struct *work)
        DRM_DEBUG_KMS("running encoder hotplug functions\n");
 
        lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
+
+       hpd_event_bits = dev_priv->hpd_event_bits;
+       dev_priv->hpd_event_bits = 0;
        list_for_each_entry(connector, &mode_config->connector_list, head) {
                intel_connector = to_intel_connector(connector);
                intel_encoder = intel_connector->encoder;
@@ -366,6 +578,10 @@ static void i915_hotplug_work_func(struct work_struct *work)
                                | DRM_CONNECTOR_POLL_DISCONNECT;
                        hpd_disabled = true;
                }
+               if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {
+                       DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n",
+                                     drm_get_connector_name(connector), intel_encoder->hpd_pin);
+               }
        }
         /* if there were no outputs to poll, poll was disabled,
          * therefore make sure it's enabled when disabling HPD on
@@ -378,14 +594,20 @@ static void i915_hotplug_work_func(struct work_struct *work)
 
        lockmgr(&dev_priv->irq_lock, LK_RELEASE);
 
-       list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
-               if (intel_encoder->hot_plug)
-                       intel_encoder->hot_plug(intel_encoder);
-
+       list_for_each_entry(connector, &mode_config->connector_list, head) {
+               intel_connector = to_intel_connector(connector);
+               intel_encoder = intel_connector->encoder;
+               if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {
+                       if (intel_encoder->hot_plug)
+                               intel_encoder->hot_plug(intel_encoder);
+                       if (intel_hpd_irq_event(dev, connector))
+                               changed = true;
+               }
+       }
        mutex_unlock(&mode_config->mutex);
 
-       /* Just fire off a uevent and let userspace tell us what to do */
-       drm_helper_hpd_irq_event(dev);
+       if (changed)
+               drm_kms_helper_hotplug_event(dev);
 }
 
 static void ironlake_handle_rps_change(struct drm_device *dev)
@@ -437,7 +659,6 @@ static void notify_ring(struct drm_device *dev,
 
        wake_up_all(&ring->irq_queue);
        if (i915_enable_hangcheck) {
-               dev_priv->gpu_error.hangcheck_count = 0;
                mod_timer(&dev_priv->gpu_error.hangcheck_timer,
                          round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
        }
@@ -450,29 +671,52 @@ static void gen6_pm_rps_work(struct work_struct *work)
        u32 pm_iir, pm_imr;
        u8 new_delay;
 
-       spin_lock(&dev_priv->rps.lock);
+       lockmgr(&dev_priv->rps.lock, LK_EXCLUSIVE);
        pm_iir = dev_priv->rps.pm_iir;
        dev_priv->rps.pm_iir = 0;
        pm_imr = I915_READ(GEN6_PMIMR);
-       I915_WRITE(GEN6_PMIMR, 0);
-       spin_unlock(&dev_priv->rps.lock);
+       /* Make sure not to corrupt PMIMR state used by ringbuffer code */
+       I915_WRITE(GEN6_PMIMR, pm_imr & ~GEN6_PM_RPS_EVENTS);
+       lockmgr(&dev_priv->rps.lock, LK_RELEASE);
 
-       if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0)
+       if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0)
                return;
 
        mutex_lock(&dev_priv->rps.hw_lock);
 
-       if (pm_iir & GEN6_PM_RP_UP_THRESHOLD)
+       if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
                new_delay = dev_priv->rps.cur_delay + 1;
-       else
+
+               /*
+                * For better performance, jump directly
+                * to RPe if we're below it.
+                */
+               if (IS_VALLEYVIEW(dev_priv->dev) &&
+                   dev_priv->rps.cur_delay < dev_priv->rps.rpe_delay)
+                       new_delay = dev_priv->rps.rpe_delay;
+       } else
                new_delay = dev_priv->rps.cur_delay - 1;
 
        /* sysfs frequency interfaces may have snuck in while servicing the
         * interrupt
         */
-       if (!(new_delay > dev_priv->rps.max_delay ||
-             new_delay < dev_priv->rps.min_delay)) {
-               gen6_set_rps(dev_priv->dev, new_delay);
+       if (new_delay >= dev_priv->rps.min_delay &&
+           new_delay <= dev_priv->rps.max_delay) {
+               if (IS_VALLEYVIEW(dev_priv->dev))
+                       valleyview_set_rps(dev_priv->dev, new_delay);
+               else
+                       gen6_set_rps(dev_priv->dev, new_delay);
+       }
+
+       if (IS_VALLEYVIEW(dev_priv->dev)) {
+               /*
+                * On VLV, when we enter RC6 we may not be at the minimum
+                * voltage level, so arm a timer to check.  It should only
+                * fire when there's activity or once after we've entered
+                * RC6, and then won't be re-armed until the next RPS interrupt.
+                */
+               mod_delayed_work(dev_priv->wq, &dev_priv->rps.vlv_work,
+                                msecs_to_jiffies(100));
        }
 
        mutex_unlock(&dev_priv->rps.hw_lock);
@@ -518,7 +762,7 @@ static void ivybridge_parity_work(struct work_struct *work)
        I915_WRITE(GEN7_MISCCPCTL, misccpctl);
 
        lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
-       dev_priv->gt_irq_mask &= ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+       dev_priv->gt_irq_mask &= ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
        lockmgr(&dev_priv->irq_lock, LK_RELEASE);
 
@@ -539,7 +783,7 @@ static void ivybridge_handle_parity_error(struct drm_device *dev)
                return;
 
        lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
-       dev_priv->gt_irq_mask |= GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+       dev_priv->gt_irq_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
        lockmgr(&dev_priv->irq_lock, LK_RELEASE);
 
@@ -551,25 +795,26 @@ static void snb_gt_irq_handler(struct drm_device *dev,
                               u32 gt_iir)
 {
 
-       if (gt_iir & (GEN6_RENDER_USER_INTERRUPT |
-                     GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT))
+       if (gt_iir &
+           (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT))
                notify_ring(dev, &dev_priv->ring[RCS]);
-       if (gt_iir & GEN6_BSD_USER_INTERRUPT)
+       if (gt_iir & GT_BSD_USER_INTERRUPT)
                notify_ring(dev, &dev_priv->ring[VCS]);
-       if (gt_iir & GEN6_BLITTER_USER_INTERRUPT)
+       if (gt_iir & GT_BLT_USER_INTERRUPT)
                notify_ring(dev, &dev_priv->ring[BCS]);
 
-       if (gt_iir & (GT_GEN6_BLT_CS_ERROR_INTERRUPT |
-                     GT_GEN6_BSD_CS_ERROR_INTERRUPT |
-                     GT_RENDER_CS_ERROR_INTERRUPT)) {
+       if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT |
+                     GT_BSD_CS_ERROR_INTERRUPT |
+                     GT_RENDER_CS_MASTER_ERROR_INTERRUPT)) {
                DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir);
                i915_handle_error(dev, false);
        }
 
-       if (gt_iir & GT_GEN7_L3_PARITY_ERROR_INTERRUPT)
+       if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
                ivybridge_handle_parity_error(dev);
 }
 
+/* Legacy way of handling PM interrupts */
 static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
                                u32 pm_iir)
 {
@@ -584,11 +829,11 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
         * The mask bit in IMR is cleared by dev_priv->rps.work.
         */
 
-       spin_lock(&dev_priv->rps.lock);
+       lockmgr(&dev_priv->rps.lock, LK_EXCLUSIVE);
        dev_priv->rps.pm_iir |= pm_iir;
        I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
        POSTING_READ(GEN6_PMIMR);
-       spin_unlock(&dev_priv->rps.lock);
+       lockmgr(&dev_priv->rps.lock, LK_RELEASE);
 
        queue_work(dev_priv->wq, &dev_priv->rps.work);
 }
@@ -596,13 +841,16 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
 #define HPD_STORM_DETECT_PERIOD 1000
 #define HPD_STORM_THRESHOLD 5
 
-static inline bool hotplug_irq_storm_detect(struct drm_device *dev,
-                                           u32 hotplug_trigger,
-                                           const u32 *hpd)
+static inline void intel_hpd_irq_handler(struct drm_device *dev,
+                                        u32 hotplug_trigger,
+                                        const u32 *hpd)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        int i;
-       bool ret = false;
+       bool storm_detected = false;
+
+       if (!hotplug_trigger)
+               return;
 
        lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
 
@@ -612,6 +860,7 @@ static inline bool hotplug_irq_storm_detect(struct drm_device *dev,
                    dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED)
                        continue;
 
+               dev_priv->hpd_event_bits |= (1 << i);
                if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies,
                                   dev_priv->hpd_stats[i].hpd_last_jiffies
                                   + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) {
@@ -619,8 +868,9 @@ static inline bool hotplug_irq_storm_detect(struct drm_device *dev,
                        dev_priv->hpd_stats[i].hpd_cnt = 0;
                } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) {
                        dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED;
+                       dev_priv->hpd_event_bits &= ~(1 << i);
                        DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i);
-                       ret = true;
+                       storm_detected = true;
                } else {
                        dev_priv->hpd_stats[i].hpd_cnt++;
                }
@@ -628,7 +878,11 @@ static inline bool hotplug_irq_storm_detect(struct drm_device *dev,
 
        lockmgr(&dev_priv->irq_lock, LK_RELEASE);
 
-       return ret;
+       if (storm_detected)
+               dev_priv->display.hpd_irq_setup(dev);
+
+       queue_work(dev_priv->wq,
+                  &dev_priv->hotplug_work);
 }
 
 static void gmbus_irq_handler(struct drm_device *dev)
@@ -645,6 +899,36 @@ static void dp_aux_irq_handler(struct drm_device *dev)
        wake_up_all(&dev_priv->gmbus_wait_queue);
 }
 
+/* Unlike gen6_queue_rps_work() from which this function is originally derived,
+ * we must be able to deal with other PM interrupts. This is complicated because
+ * of the way in which we use the masks to defer the RPS work (which for
+ * posterity is necessary because of forcewake).
+ */
+static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
+                              u32 pm_iir)
+{
+       lockmgr(&dev_priv->rps.lock, LK_EXCLUSIVE);
+       dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
+       if (dev_priv->rps.pm_iir) {
+               I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
+               /* never want to mask useful interrupts. (also posting read) */
+               WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
+               /* TODO: if queue_work is slow, move it out of the spinlock */
+               queue_work(dev_priv->wq, &dev_priv->rps.work);
+       }
+       lockmgr(&dev_priv->rps.lock, LK_RELEASE);
+
+       if (pm_iir & ~GEN6_PM_RPS_EVENTS) {
+               if (pm_iir & PM_VEBOX_USER_INTERRUPT)
+                       notify_ring(dev_priv->dev, &dev_priv->ring[VECS]);
+
+               if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) {
+                       DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir);
+                       i915_handle_error(dev_priv->dev, false);
+               }
+       }
+}
+
 static irqreturn_t valleyview_irq_handler(void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -699,12 +983,9 @@ static irqreturn_t valleyview_irq_handler(void *arg)
 
                        DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
                                         hotplug_status);
-                       if (hotplug_trigger) {
-                               if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
-                                       i915_hpd_irq_setup(dev);
-                               queue_work(dev_priv->wq,
-                                          &dev_priv->hotplug_work);
-                       }
+
+                       intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
+
                        I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
                        I915_READ(PORT_HOTPLUG_STAT);
                }
@@ -712,7 +993,7 @@ static irqreturn_t valleyview_irq_handler(void *arg)
                if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
                        gmbus_irq_handler(dev);
 
-               if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
+               if (pm_iir & GEN6_PM_RPS_EVENTS)
                        gen6_queue_rps_work(dev_priv, pm_iir);
 
                I915_WRITE(GTIIR, gt_iir);
@@ -730,15 +1011,14 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
        int pipe;
        u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
-       if (hotplug_trigger) {
-               if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx))
-                       ibx_hpd_irq_setup(dev);
-               queue_work(dev_priv->wq, &dev_priv->hotplug_work);
-       }
-       if (pch_iir & SDE_AUDIO_POWER_MASK)
+       intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
+
+       if (pch_iir & SDE_AUDIO_POWER_MASK) {
+               int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
+                              SDE_AUDIO_POWER_SHIFT);
                DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
-                                (pch_iir & SDE_AUDIO_POWER_MASK) >>
-                                SDE_AUDIO_POWER_SHIFT);
+                                port_name(port));
+       }
 
        if (pch_iir & SDE_AUX_MASK)
                dp_aux_irq_handler(dev);
@@ -767,10 +1047,64 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
        if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR))
                DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n");
 
-       if (pch_iir & SDE_TRANSB_FIFO_UNDER)
-               DRM_DEBUG_DRIVER("PCH transcoder B underrun interrupt\n");
        if (pch_iir & SDE_TRANSA_FIFO_UNDER)
-               DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
+               if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
+                                                         false))
+                       DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
+
+       if (pch_iir & SDE_TRANSB_FIFO_UNDER)
+               if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
+                                                         false))
+                       DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
+}
+
+static void ivb_err_int_handler(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 err_int = I915_READ(GEN7_ERR_INT);
+
+       if (err_int & ERR_INT_POISON)
+               DRM_ERROR("Poison interrupt\n");
+
+       if (err_int & ERR_INT_FIFO_UNDERRUN_A)
+               if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false))
+                       DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n");
+
+       if (err_int & ERR_INT_FIFO_UNDERRUN_B)
+               if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false))
+                       DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n");
+
+       if (err_int & ERR_INT_FIFO_UNDERRUN_C)
+               if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_C, false))
+                       DRM_DEBUG_DRIVER("Pipe C FIFO underrun\n");
+
+       I915_WRITE(GEN7_ERR_INT, err_int);
+}
+
+static void cpt_serr_int_handler(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 serr_int = I915_READ(SERR_INT);
+
+       if (serr_int & SERR_INT_POISON)
+               DRM_ERROR("PCH poison interrupt\n");
+
+       if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN)
+               if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
+                                                         false))
+                       DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
+
+       if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN)
+               if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
+                                                         false))
+                       DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
+
+       if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN)
+               if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C,
+                                                         false))
+                       DRM_DEBUG_DRIVER("PCH transcoder C FIFO underrun\n");
+
+       I915_WRITE(SERR_INT, serr_int);
 }
 
 static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
@@ -779,15 +1113,14 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
        int pipe;
        u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
-       if (hotplug_trigger) {
-               if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt))
-                       ibx_hpd_irq_setup(dev);
-               queue_work(dev_priv->wq, &dev_priv->hotplug_work);
+       intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
+
+       if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
+               int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
+                              SDE_AUDIO_POWER_SHIFT_CPT);
+               DRM_DEBUG_DRIVER("PCH audio power change on port %c\n",
+                                port_name(port));
        }
-       if (pch_iir & SDE_AUDIO_POWER_MASK_CPT)
-               DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
-                                (pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
-                                SDE_AUDIO_POWER_SHIFT_CPT);
 
        if (pch_iir & SDE_AUX_MASK_CPT)
                dp_aux_irq_handler(dev);
@@ -806,6 +1139,9 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
                        DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
                                         pipe_name(pipe),
                                         I915_READ(FDI_RX_IIR(pipe)));
+
+       if (pch_iir & SDE_ERROR_CPT)
+               cpt_serr_int_handler(dev);
 }
 
 static irqreturn_t ivybridge_irq_handler(void *arg)
@@ -817,6 +1153,14 @@ static irqreturn_t ivybridge_irq_handler(void *arg)
 
        atomic_inc(&dev_priv->irq_received);
 
+       /* We get interrupts on unclaimed registers, so check for this before we
+        * do any I915_{READ,WRITE}. */
+       if (IS_HASWELL(dev) &&
+           (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
+               DRM_ERROR("Unclaimed register before interrupt\n");
+               I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+       }
+
        /* disable master interrupt before clearing iir  */
        de_ier = I915_READ(DEIER);
        I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
@@ -832,6 +1176,15 @@ static irqreturn_t ivybridge_irq_handler(void *arg)
                POSTING_READ(SDEIER);
        }
 
+       /* On Haswell, also mask ERR_INT because we don't want to risk
+        * generating "unclaimed register" interrupts from inside the interrupt
+        * handler. */
+       if (IS_HASWELL(dev)) {
+               lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
+               ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+               lockmgr(&dev_priv->irq_lock, LK_RELEASE);
+       }
+
        gt_iir = I915_READ(GTIIR);
        if (gt_iir) {
                snb_gt_irq_handler(dev, dev_priv, gt_iir);
@@ -840,11 +1193,14 @@ static irqreturn_t ivybridge_irq_handler(void *arg)
 
        de_iir = I915_READ(DEIIR);
        if (de_iir) {
+               if (de_iir & DE_ERR_INT_IVB)
+                       ivb_err_int_handler(dev);
+
                if (de_iir & DE_AUX_CHANNEL_A_IVB)
                        dp_aux_irq_handler(dev);
 
                if (de_iir & DE_GSE_IVB)
-                       intel_opregion_gse_intr(dev);
+                       intel_opregion_asle_intr(dev);
 
                for (i = 0; i < 3; i++) {
                        if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
@@ -870,11 +1226,20 @@ static irqreturn_t ivybridge_irq_handler(void *arg)
 
        pm_iir = I915_READ(GEN6_PMIIR);
        if (pm_iir) {
-               if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
+               if (IS_HASWELL(dev))
+                       hsw_pm_irq_handler(dev_priv, pm_iir);
+               else if (pm_iir & GEN6_PM_RPS_EVENTS)
                        gen6_queue_rps_work(dev_priv, pm_iir);
                I915_WRITE(GEN6_PMIIR, pm_iir);
        }
 
+       if (IS_HASWELL(dev)) {
+               lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
+               if (ivb_can_enable_err_int(dev))
+                       ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+               lockmgr(&dev_priv->irq_lock, LK_RELEASE);
+       }
+
        I915_WRITE(DEIER, de_ier);
        POSTING_READ(DEIER);
        if (!HAS_PCH_NOP(dev)) {
@@ -887,9 +1252,10 @@ static void ilk_gt_irq_handler(struct drm_device *dev,
                               struct drm_i915_private *dev_priv,
                               u32 gt_iir)
 {
-       if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
+       if (gt_iir &
+           (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT))
                notify_ring(dev, &dev_priv->ring[RCS]);
-       if (gt_iir & GT_BSD_USER_INTERRUPT)
+       if (gt_iir & ILK_BSD_USER_INTERRUPT)
                notify_ring(dev, &dev_priv->ring[VCS]);
 }
 
@@ -931,7 +1297,7 @@ static irqreturn_t ironlake_irq_handler(void *arg)
                dp_aux_irq_handler(dev);
 
        if (de_iir & DE_GSE)
-               intel_opregion_gse_intr(dev);
+               intel_opregion_asle_intr(dev);
 
        if (de_iir & DE_PIPEA_VBLANK)
                drm_handle_vblank(dev, 0);
@@ -939,6 +1305,17 @@ static irqreturn_t ironlake_irq_handler(void *arg)
        if (de_iir & DE_PIPEB_VBLANK)
                drm_handle_vblank(dev, 1);
 
+       if (de_iir & DE_POISON)
+               DRM_ERROR("Poison interrupt\n");
+
+       if (de_iir & DE_PIPEA_FIFO_UNDERRUN)
+               if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false))
+                       DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n");
+
+       if (de_iir & DE_PIPEB_FIFO_UNDERRUN)
+               if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false))
+                       DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n");
+
        if (de_iir & DE_PLANEA_FLIP_DONE) {
                intel_prepare_page_flip(dev, 0);
                intel_finish_page_flip_plane(dev, 0);
@@ -965,7 +1342,7 @@ static irqreturn_t ironlake_irq_handler(void *arg)
        if (IS_GEN5(dev) &&  de_iir & DE_PCU_EVENT)
                ironlake_handle_rps_change(dev);
 
-       if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS)
+       if (IS_GEN6(dev) && pm_iir & GEN6_PM_RPS_EVENTS)
                gen6_queue_rps_work(dev_priv, pm_iir);
 
        I915_WRITE(GTIIR, gt_iir);
@@ -1192,11 +1569,13 @@ i915_error_state_free(struct drm_device *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);
+               i915_error_object_free(error->ring[i].ctx);
                kfree(error->ring[i].requests);
        }
 
        kfree(error->active_bo);
        kfree(error->overlay);
+       kfree(error->display);
        kfree(error);
 }
 static void capture_bo(struct drm_i915_error_buffer *err,
@@ -1243,7 +1622,7 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
        struct drm_i915_gem_object *obj;
        int i = 0;
 
-       list_for_each_entry(obj, head, gtt_list) {
+       list_for_each_entry(obj, head, global_list) {
                if (obj->pin_count == 0)
                        continue;
 
@@ -1385,7 +1764,7 @@ static void i915_gem_record_active_context(struct intel_ring_buffer *ring,
        if (ring->id != RCS || !error->ccid)
                return;
 
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                if ((error->ccid & PAGE_MASK) == obj->gtt_offset) {
                        ering->ctx = i915_error_object_create_sized(dev_priv,
                                                                    obj, 1);
@@ -1522,7 +1901,7 @@ static void i915_capture_error_state(struct drm_device *dev)
        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.bound_list, gtt_list)
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
                if (obj->pin_count)
                        i++;
        error->pinned_bo_count = i - error->active_bo_count;
@@ -1892,42 +2271,28 @@ ring_last_seqno(struct intel_ring_buffer *ring)
                          struct drm_i915_gem_request, list)->seqno;
 }
 
-static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
+static bool
+ring_idle(struct intel_ring_buffer *ring, u32 seqno)
 {
-       if (list_empty(&ring->request_list) ||
-           i915_seqno_passed(ring->get_seqno(ring, false),
-                             ring_last_seqno(ring))) {
-               /* Issue a wake-up to catch stuck h/w. */
-#if 0 /* XXX From OpenBSD */
-               if (waitqueue_active(&ring->irq_queue)) {
-                       DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
-                                 ring->name);
-                       wake_up_all(&ring->irq_queue);
-                       *err = true;
-               }
-#else
-               wake_up_all(&ring->irq_queue);
-#endif
-               return true;
-       }
-       return false;
+       return (list_empty(&ring->request_list) ||
+               i915_seqno_passed(seqno, ring_last_seqno(ring)));
 }
 
-static bool semaphore_passed(struct intel_ring_buffer *ring)
+static struct intel_ring_buffer *
+semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno)
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
-       u32 acthd = intel_ring_get_active_head(ring) & HEAD_ADDR;
-       struct intel_ring_buffer *signaller;
-       u32 cmd, ipehr, acthd_min;
+       u32 cmd, ipehr, acthd, acthd_min;
 
        ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
        if ((ipehr & ~(0x3 << 16)) !=
            (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER))
-               return false;
+               return NULL;
 
        /* ACTHD is likely pointing to the dword after the actual command,
         * so scan backwards until we find the MBOX.
         */
+       acthd = intel_ring_get_active_head(ring) & HEAD_ADDR;
        acthd_min = max((int)acthd - 3 * 4, 0);
        do {
                cmd = ioread32(ring->virtual_start + acthd);
@@ -1936,124 +2301,216 @@ static bool semaphore_passed(struct intel_ring_buffer *ring)
 
                acthd -= 4;
                if (acthd < acthd_min)
-                       return false;
+                       return NULL;
        } while (1);
 
-       signaller = &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3];
-       return i915_seqno_passed(signaller->get_seqno(signaller, false),
-                                ioread32(ring->virtual_start+acthd+4)+1);
+       *seqno = ioread32(ring->virtual_start+acthd+4)+1;
+       return &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3];
 }
 
-static bool kick_ring(struct intel_ring_buffer *ring)
+static int semaphore_passed(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;
-       }
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct intel_ring_buffer *signaller;
+       u32 seqno, ctl;
 
-       if (INTEL_INFO(dev)->gen >= 6 &&
-           tmp & RING_WAIT_SEMAPHORE &&
-           semaphore_passed(ring)) {
-               DRM_ERROR("Kicking stuck semaphore on %s\n",
-                         ring->name);
-               I915_WRITE_CTL(ring, tmp);
-               return true;
-       }
-       return false;
+       ring->hangcheck.deadlock = true;
+
+       signaller = semaphore_waits_for(ring, &seqno);
+       if (signaller == NULL || signaller->hangcheck.deadlock)
+               return -1;
+
+       /* cursory check for an unkickable deadlock */
+       ctl = I915_READ_CTL(signaller);
+       if (ctl & RING_WAIT_SEMAPHORE && semaphore_passed(signaller) < 0)
+               return -1;
+
+       return i915_seqno_passed(signaller->get_seqno(signaller, false), seqno);
 }
 
-static bool i915_hangcheck_hung(struct drm_device *dev)
+static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-
-       if (dev_priv->gpu_error.hangcheck_count++ > 1) {
-               bool hung = true;
+       struct intel_ring_buffer *ring;
+       int i;
 
-               DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
-               i915_handle_error(dev, true);
+       for_each_ring(ring, dev_priv, i)
+               ring->hangcheck.deadlock = false;
+}
 
-               if (!IS_GEN2(dev)) {
-                       struct intel_ring_buffer *ring;
-                       int i;
+static enum intel_ring_hangcheck_action
+ring_stuck(struct intel_ring_buffer *ring, u32 acthd)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp;
 
-                       /* 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);
-               }
+       if (ring->hangcheck.acthd != acthd)
+               return active;
 
+       if (IS_GEN2(dev))
                return hung;
+
+       /* 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.
+        */
+       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 kick;
        }
 
-       return false;
+       if (INTEL_INFO(dev)->gen >= 6 && tmp & RING_WAIT_SEMAPHORE) {
+               switch (semaphore_passed(ring)) {
+               default:
+                       return hung;
+               case 1:
+                       DRM_ERROR("Kicking stuck semaphore on %s\n",
+                                 ring->name);
+                       I915_WRITE_CTL(ring, tmp);
+                       return kick;
+               case 0:
+                       return wait;
+               }
+       }
+
+       return hung;
 }
 
 /**
  * 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.
+ * batchbuffers in a long time. We keep track per ring seqno progress and
+ * if there are no progress, hangcheck score for that ring is increased.
+ * Further, acthd is inspected to see if the ring is stuck. On stuck case
+ * we kick the ring. If we see no progress on three subsequent calls
+ * we assume chip is wedged and try to fix it by resetting the chip.
  */
 void i915_hangcheck_elapsed(unsigned long data)
 {
        struct drm_device *dev = (struct drm_device *)data;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       uint32_t acthd[I915_NUM_RINGS], instdone[I915_NUM_INSTDONE_REG];
        struct intel_ring_buffer *ring;
-       bool err = false, idle;
        int i;
+       int busy_count = 0, rings_hung = 0;
+       bool stuck[I915_NUM_RINGS] = { 0 };
+#define BUSY 1
+#define KICK 5
+#define HUNG 20
+#define FIRE 30
 
        if (!i915_enable_hangcheck)
                return;
 
-       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);
-       }
+               u32 seqno, acthd;
+               bool busy = true;
+
+               semaphore_clear_deadlocks(dev_priv);
+
+               seqno = ring->get_seqno(ring, false);
+               acthd = intel_ring_get_active_head(ring);
+
+               if (ring->hangcheck.seqno == seqno) {
+                       if (ring_idle(ring, seqno)) {
+                               if (waitqueue_active(&ring->irq_queue)) {
+                                       /* Issue a wake-up to catch stuck h/w. */
+                                       DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
+                                                 ring->name);
+                                       wake_up_all(&ring->irq_queue);
+                                       ring->hangcheck.score += HUNG;
+                               } else
+                                       busy = false;
+                       } else {
+                               int score;
+
+                               /* We always increment the hangcheck score
+                                * if the ring is busy and still processing
+                                * the same request, so that no single request
+                                * can run indefinitely (such as a chain of
+                                * batches). The only time we do not increment
+                                * the hangcheck score on this ring, if this
+                                * ring is in a legitimate wait for another
+                                * ring. In that case the waiting ring is a
+                                * victim and we want to be sure we catch the
+                                * right culprit. Then every time we do kick
+                                * the ring, add a small increment to the
+                                * score so that we can catch a batch that is
+                                * being repeatedly kicked and so responsible
+                                * for stalling the machine.
+                                */
+                               ring->hangcheck.action = ring_stuck(ring,
+                                                                   acthd);
+
+                               switch (ring->hangcheck.action) {
+                               case wait:
+                                       score = 0;
+                                       break;
+                               case active:
+                                       score = BUSY;
+                                       break;
+                               case kick:
+                                       score = KICK;
+                                       break;
+                               case hung:
+                                       score = HUNG;
+                                       stuck[i] = true;
+                                       break;
+                               }
+                               ring->hangcheck.score += score;
+                       }
+               } else {
+                       /* Gradually reduce the count so that we catch DoS
+                        * attempts across multiple batches.
+                        */
+                       if (ring->hangcheck.score > 0)
+                               ring->hangcheck.score--;
+               }
 
-       /* If all work is done then ACTHD clearly hasn't advanced. */
-       if (idle) {
-               if (err) {
-                       if (i915_hangcheck_hung(dev))
-                               return;
+               ring->hangcheck.seqno = seqno;
+               ring->hangcheck.acthd = acthd;
+               busy_count += busy;
+       }
 
-                       goto repeat;
+       for_each_ring(ring, dev_priv, i) {
+               if (ring->hangcheck.score > FIRE) {
+                       DRM_ERROR("%s on %s\n",
+                                 stuck[i] ? "stuck" : "no progress",
+                                 ring->name);
+                       rings_hung++;
                }
-
-               dev_priv->gpu_error.hangcheck_count = 0;
-               return;
        }
 
-       i915_get_extra_instdone(dev, instdone);
-       if (memcmp(dev_priv->gpu_error.last_acthd, acthd,
-                  sizeof(acthd)) == 0 &&
-           memcmp(dev_priv->gpu_error.prev_instdone, instdone,
-                  sizeof(instdone)) == 0) {
-               if (i915_hangcheck_hung(dev))
-                       return;
-       } else {
-               dev_priv->gpu_error.hangcheck_count = 0;
+       if (rings_hung)
+               return i915_handle_error(dev, true);
 
-               memcpy(dev_priv->gpu_error.last_acthd, acthd,
-                      sizeof(acthd));
-               memcpy(dev_priv->gpu_error.prev_instdone, instdone,
-                      sizeof(instdone));
-       }
+       if (busy_count)
+               /* Reset timer case chip hangs without another request
+                * being added */
+               mod_timer(&dev_priv->gpu_error.hangcheck_timer,
+                         round_jiffies_up(jiffies +
+                                          DRM_I915_HANGCHECK_JIFFIES));
+}
 
-repeat:
-       /* Reset timer case chip hangs without another request being added */
-       mod_timer(&dev_priv->gpu_error.hangcheck_timer,
-                 round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
+static void ibx_irq_preinstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (HAS_PCH_NOP(dev))
+               return;
+
+       /* south display irq */
+       I915_WRITE(SDEIMR, 0xffffffff);
+       /*
+        * SDEIER is also touched by the interrupt handler to work around missed
+        * PCH interrupts. Hence we can't update it after the interrupt handler
+        * is enabled - instead we unconditionally enable all PCH interrupt
+        * sources here, but then only unmask them as needed with SDEIMR.
+        */
+       I915_WRITE(SDEIER, 0xffffffff);
+       POSTING_READ(SDEIER);
 }
 
 /* drm_dma.h hooks
@@ -2077,19 +2534,34 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
        I915_WRITE(GTIER, 0x0);
        POSTING_READ(GTIER);
 
-       if (HAS_PCH_NOP(dev))
-               return;
+       ibx_irq_preinstall(dev);
+}
 
-       /* south display irq */
-       I915_WRITE(SDEIMR, 0xffffffff);
-       /*
-        * SDEIER is also touched by the interrupt handler to work around missed
-        * PCH interrupts. Hence we can't update it after the interrupt handler
-        * is enabled - instead we unconditionally enable all PCH interrupt
-        * sources here, but then only unmask them as needed with SDEIMR.
-        */
-       I915_WRITE(SDEIER, 0xffffffff);
-       POSTING_READ(SDEIER);
+static void ivybridge_irq_preinstall(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       atomic_set(&dev_priv->irq_received, 0);
+
+       I915_WRITE(HWSTAM, 0xeffe);
+
+       /* XXX hotplug from PCH */
+
+       I915_WRITE(DEIMR, 0xffffffff);
+       I915_WRITE(DEIER, 0x0);
+       POSTING_READ(DEIER);
+
+       /* and GT */
+       I915_WRITE(GTIMR, 0xffffffff);
+       I915_WRITE(GTIER, 0x0);
+       POSTING_READ(GTIER);
+
+       /* Power management */
+       I915_WRITE(GEN6_PMIMR, 0xffffffff);
+       I915_WRITE(GEN6_PMIER, 0x0);
+       POSTING_READ(GEN6_PMIER);
+
+       ibx_irq_preinstall(dev);
 }
 
 static void valleyview_irq_preinstall(struct drm_device *dev)
@@ -2165,14 +2637,18 @@ static void ibx_irq_postinstall(struct drm_device *dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 mask;
 
-       if (HAS_PCH_IBX(dev))
-               mask = SDE_GMBUS | SDE_AUX_MASK;
-       else
-               mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
-
        if (HAS_PCH_NOP(dev))
                return;
 
+       if (HAS_PCH_IBX(dev)) {
+               mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER |
+                      SDE_TRANSA_FIFO_UNDER | SDE_POISON;
+       } else {
+               mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT;
+
+               I915_WRITE(SERR_INT, I915_READ(SERR_INT));
+       }
+
        I915_WRITE(SDEIIR, I915_READ(SDEIIR));
        I915_WRITE(SDEIMR, ~mask);
 }
@@ -2183,15 +2659,17 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        /* enable kind of interrupts always enabled */
        u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
                           DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
-                          DE_AUX_CHANNEL_A;
-       u32 render_irqs;
+                          DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN |
+                          DE_PIPEA_FIFO_UNDERRUN | DE_POISON;
+       u32 gt_irqs;
 
        dev_priv->irq_mask = ~display_mask;
 
        /* should always can generate irq */
        I915_WRITE(DEIIR, I915_READ(DEIIR));
        I915_WRITE(DEIMR, dev_priv->irq_mask);
-       I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK);
+       I915_WRITE(DEIER, display_mask |
+                         DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT);
        POSTING_READ(DEIER);
 
        dev_priv->gt_irq_mask = ~0;
@@ -2199,26 +2677,28 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 
+       gt_irqs = GT_RENDER_USER_INTERRUPT;
+
        if (IS_GEN6(dev))
-               render_irqs =
-                       GT_USER_INTERRUPT |
-                       GEN6_BSD_USER_INTERRUPT |
-                       GEN6_BLITTER_USER_INTERRUPT;
+               gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
        else
-               render_irqs =
-                       GT_USER_INTERRUPT |
-                       GT_PIPE_NOTIFY |
-                       GT_BSD_USER_INTERRUPT;
-       I915_WRITE(GTIER, render_irqs);
+               gt_irqs |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT |
+                          ILK_BSD_USER_INTERRUPT;
+
+       I915_WRITE(GTIER, gt_irqs);
        POSTING_READ(GTIER);
 
        ibx_irq_postinstall(dev);
 
        if (IS_IRONLAKE_M(dev)) {
-               /* Clear & enable PCU event interrupts */
-               I915_WRITE(DEIIR, DE_PCU_EVENT);
-               I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
+               /* Enable PCU event interrupts
+                *
+                * spinlocking not required here for correctness since interrupt
+                * setup is guaranteed to run in single-threaded context. But we
+                * need it to make the assert_spin_locked happy. */
+               lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
                ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
+               lockmgr(&dev_priv->irq_lock, LK_RELEASE);
        }
 
        return 0;
@@ -2233,12 +2713,15 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
                DE_PLANEC_FLIP_DONE_IVB |
                DE_PLANEB_FLIP_DONE_IVB |
                DE_PLANEA_FLIP_DONE_IVB |
-               DE_AUX_CHANNEL_A_IVB;
-       u32 render_irqs;
+               DE_AUX_CHANNEL_A_IVB |
+               DE_ERR_INT_IVB;
+       u32 pm_irqs = GEN6_PM_RPS_EVENTS;
+       u32 gt_irqs;
 
        dev_priv->irq_mask = ~display_mask;
 
        /* should always can generate irq */
+       I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
        I915_WRITE(DEIIR, I915_READ(DEIIR));
        I915_WRITE(DEIMR, dev_priv->irq_mask);
        I915_WRITE(DEIER,
@@ -2248,16 +2731,32 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
                   DE_PIPEA_VBLANK_IVB);
        POSTING_READ(DEIER);
 
-       dev_priv->gt_irq_mask = ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+       dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 
-       render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT |
-               GEN6_BLITTER_USER_INTERRUPT | GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
-       I915_WRITE(GTIER, render_irqs);
+       gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT |
+                 GT_BLT_USER_INTERRUPT | GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+       I915_WRITE(GTIER, gt_irqs);
        POSTING_READ(GTIER);
 
+       I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+       if (HAS_VEBOX(dev))
+               pm_irqs |= PM_VEBOX_USER_INTERRUPT |
+                       PM_VEBOX_CS_ERROR_INTERRUPT;
+
+       /* Our enable/disable rps functions may touch these registers so
+        * make sure to set a known state for only the non-RPS bits.
+        * The RMW is extra paranoia since this should be called after being set
+        * to a known state in preinstall.
+        * */
+       I915_WRITE(GEN6_PMIMR,
+                  (I915_READ(GEN6_PMIMR) | ~GEN6_PM_RPS_EVENTS) & ~pm_irqs);
+       I915_WRITE(GEN6_PMIER,
+                  (I915_READ(GEN6_PMIER) & GEN6_PM_RPS_EVENTS) | pm_irqs);
+       POSTING_READ(GEN6_PMIER);
+
        ibx_irq_postinstall(dev);
 
        return 0;
@@ -2266,10 +2765,9 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
 static int valleyview_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 gt_irqs;
        u32 enable_mask;
        u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
-       u32 render_irqs;
-       u16 msid;
 
        enable_mask = I915_DISPLAY_PORT_INTERRUPT;
        enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
@@ -2285,13 +2783,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
                I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
                I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
 
-       /* Hack for broken MSIs on VLV */
-       pci_write_config_dword(dev_priv->dev->pdev, 0x94, 0xfee00000);
-       pci_read_config_word(dev->pdev, 0x98, &msid);
-       msid &= 0xff; /* mask out delivery bits */
-       msid |= (1<<14);
-       pci_write_config_word(dev_priv->dev->pdev, 0x98, msid);
-
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        POSTING_READ(PORT_HOTPLUG_EN);
 
@@ -2312,9 +2803,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 
-       render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT |
-               GEN6_BLITTER_USER_INTERRUPT;
-       I915_WRITE(GTIER, render_irqs);
+       gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT |
+               GT_BLT_USER_INTERRUPT;
+       I915_WRITE(GTIER, gt_irqs);
        POSTING_READ(GTIER);
 
        /* ack & enable invalid PTE error interrupts */
@@ -2366,6 +2857,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
        I915_WRITE(DEIMR, 0xffffffff);
        I915_WRITE(DEIER, 0x0);
        I915_WRITE(DEIIR, I915_READ(DEIIR));
+       if (IS_GEN7(dev))
+               I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
 
        I915_WRITE(GTIMR, 0xffffffff);
        I915_WRITE(GTIER, 0x0);
@@ -2377,6 +2870,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
        I915_WRITE(SDEIMR, 0xffffffff);
        I915_WRITE(SDEIER, 0x0);
        I915_WRITE(SDEIIR, I915_READ(SDEIIR));
+       if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev))
+               I915_WRITE(SERR_INT, I915_READ(SERR_INT));
 }
 
 static void i8xx_irq_preinstall(struct drm_device * dev)
@@ -2589,7 +3084,7 @@ static int i915_irq_postinstall(struct drm_device *dev)
        I915_WRITE(IER, enable_mask);
        POSTING_READ(IER);
 
-       intel_opregion_enable_asle(dev);
+       i915_enable_asle_pipestat(dev);
 
        return 0;
 }
@@ -2677,12 +3172,9 @@ static irqreturn_t i915_irq_handler(void *arg)
 
                        DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
                                  hotplug_status);
-                       if (hotplug_trigger) {
-                               if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
-                                       i915_hpd_irq_setup(dev);
-                               queue_work(dev_priv->wq,
-                                          &dev_priv->hotplug_work);
-                       }
+
+                       intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
+
                        I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
                        POSTING_READ(PORT_HOTPLUG_STAT);
                }
@@ -2819,7 +3311,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        POSTING_READ(PORT_HOTPLUG_EN);
 
-       intel_opregion_enable_asle(dev);
+       i915_enable_asle_pipestat(dev);
 
        return 0;
 }
@@ -2908,17 +3400,14 @@ static irqreturn_t i965_irq_handler(void *arg)
                        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
                        u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ?
                                                                  HOTPLUG_INT_STATUS_G4X :
-                                                                 HOTPLUG_INT_STATUS_I965);
+                                                                 HOTPLUG_INT_STATUS_I915);
 
                        DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
                                  hotplug_status);
-                       if (hotplug_trigger) {
-                               if (hotplug_irq_storm_detect(dev, hotplug_trigger,
-                                                           IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965))
-                                       i915_hpd_irq_setup(dev);
-                               queue_work(dev_priv->wq,
-                                          &dev_priv->hotplug_work);
-                       }
+
+                       intel_hpd_irq_handler(dev, hotplug_trigger,
+                                             IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
+
                        I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
                        I915_READ(PORT_HOTPLUG_STAT);
                }
@@ -3065,9 +3554,9 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->disable_vblank = valleyview_disable_vblank;
                dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
        } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
-               /* Share pre & uninstall handlers with ILK/SNB */
+               /* Share uninstall handlers with ILK/SNB */
                dev->driver->irq_handler = ivybridge_irq_handler;
-               dev->driver->irq_preinstall = ironlake_irq_preinstall;
+               dev->driver->irq_preinstall = ivybridge_irq_preinstall;
                dev->driver->irq_postinstall = ivybridge_irq_postinstall;
                dev->driver->irq_uninstall = ironlake_irq_uninstall;
                dev->driver->enable_vblank = ivybridge_enable_vblank;
@@ -3122,6 +3611,11 @@ void intel_hpd_init(struct drm_device *dev)
                if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
                        connector->polled = DRM_CONNECTOR_POLL_HPD;
        }
+
+       /* Interrupt setup is already guaranteed to be single-threaded, this is
+        * just to make the assert_spin_locked checks happy. */
+       lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
        if (dev_priv->display.hpd_irq_setup)
                dev_priv->display.hpd_irq_setup(dev);
+       lockmgr(&dev_priv->irq_lock, LK_RELEASE);
 }
index 2d6b62e..342f1f3 100644 (file)
 #define   VGA_MSR_MEM_EN (1<<1)
 #define   VGA_MSR_CGA_MODE (1<<0)
 
-/*
- * SR01 is the only VGA register touched on non-UMS setups.
- * VLV doesn't do UMS, so the sequencer index/data registers
- * are the only VGA registers which need to include
- * display_mmio_offset.
- */
-#define VGA_SR_INDEX (dev_priv->info->display_mmio_offset + 0x3c4)
+#define VGA_SR_INDEX 0x3c4
 #define SR01                   1
-#define VGA_SR_DATA (dev_priv->info->display_mmio_offset + 0x3c5)
+#define VGA_SR_DATA 0x3c5
 
 #define VGA_AR_INDEX 0x3c0
 #define   VGA_AR_VID_EN (1<<5)
 #define  MI_SEMAPHORE_UPDATE       (1<<21)
 #define  MI_SEMAPHORE_COMPARE      (1<<20)
 #define  MI_SEMAPHORE_REGISTER     (1<<18)
-#define  MI_SEMAPHORE_SYNC_RV      (2<<16)
-#define  MI_SEMAPHORE_SYNC_RB      (0<<16)
-#define  MI_SEMAPHORE_SYNC_VR      (0<<16)
-#define  MI_SEMAPHORE_SYNC_VB      (2<<16)
-#define  MI_SEMAPHORE_SYNC_BR      (2<<16)
-#define  MI_SEMAPHORE_SYNC_BV      (0<<16)
-#define  MI_SEMAPHORE_SYNC_INVALID  (1<<0)
+#define  MI_SEMAPHORE_SYNC_VR      (0<<16) /* RCS  wait for VCS  (RVSYNC) */
+#define  MI_SEMAPHORE_SYNC_VER     (1<<16) /* RCS  wait for VECS (RVESYNC) */
+#define  MI_SEMAPHORE_SYNC_BR      (2<<16) /* RCS  wait for BCS  (RBSYNC) */
+#define  MI_SEMAPHORE_SYNC_BV      (0<<16) /* VCS  wait for BCS  (VBSYNC) */
+#define  MI_SEMAPHORE_SYNC_VEV     (1<<16) /* VCS  wait for VECS (VVESYNC) */
+#define  MI_SEMAPHORE_SYNC_RV      (2<<16) /* VCS  wait for RCS  (VRSYNC) */
+#define  MI_SEMAPHORE_SYNC_RB      (0<<16) /* BCS  wait for RCS  (BRSYNC) */
+#define  MI_SEMAPHORE_SYNC_VEB     (1<<16) /* BCS  wait for VECS (BVESYNC) */
+#define  MI_SEMAPHORE_SYNC_VB      (2<<16) /* BCS  wait for VCS  (BVSYNC) */
+#define  MI_SEMAPHORE_SYNC_BVE     (0<<16) /* VECS wait for BCS  (VEBSYNC) */
+#define  MI_SEMAPHORE_SYNC_VVE     (1<<16) /* VECS wait for VCS  (VEVSYNC) */
+#define  MI_SEMAPHORE_SYNC_RVE     (2<<16) /* VECS wait for RCS  (VERSYNC) */
+#define  MI_SEMAPHORE_SYNC_INVALID  (3<<16)
 /*
  * 3D instructions used by the kernel
  */
 #define  DEBUG_RESET_DISPLAY           (1<<9)
 
 /*
- * DPIO - a special bus for various display related registers to hide behind:
- *  0x800c: m1, m2, n, p1, p2, k dividers
- *  0x8014: REF and SFR select
- *  0x8014: N divider, VCO select
- *  0x801c/3c: core clock bits
- *  0x8048/68: low pass filter coefficients
- *  0x8100: fast clock controls
+ * IOSF sideband
+ */
+#define VLV_IOSF_DOORBELL_REQ                  (VLV_DISPLAY_BASE + 0x2100)
+#define   IOSF_DEVFN_SHIFT                     24
+#define   IOSF_OPCODE_SHIFT                    16
+#define   IOSF_PORT_SHIFT                      8
+#define   IOSF_BYTE_ENABLES_SHIFT              4
+#define   IOSF_BAR_SHIFT                       1
+#define   IOSF_SB_BUSY                         (1<<0)
+#define   IOSF_PORT_PUNIT                      0x4
+#define   IOSF_PORT_NC                         0x11
+#define   IOSF_PORT_DPIO                       0x12
+#define VLV_IOSF_DATA                          (VLV_DISPLAY_BASE + 0x2104)
+#define VLV_IOSF_ADDR                          (VLV_DISPLAY_BASE + 0x2108)
+
+#define PUNIT_OPCODE_REG_READ                  6
+#define PUNIT_OPCODE_REG_WRITE                 7
+
+#define PUNIT_REG_GPU_LFM                      0xd3
+#define PUNIT_REG_GPU_FREQ_REQ                 0xd4
+#define PUNIT_REG_GPU_FREQ_STS                 0xd8
+#define PUNIT_REG_MEDIA_TURBO_FREQ_REQ         0xdc
+
+#define PUNIT_FUSE_BUS2                                0xf6 /* bits 47:40 */
+#define PUNIT_FUSE_BUS1                                0xf5 /* bits 55:48 */
+
+#define IOSF_NC_FB_GFX_FREQ_FUSE               0x1c
+#define   FB_GFX_MAX_FREQ_FUSE_SHIFT           3
+#define   FB_GFX_MAX_FREQ_FUSE_MASK            0x000007f8
+#define   FB_GFX_FGUARANTEED_FREQ_FUSE_SHIFT   11
+#define   FB_GFX_FGUARANTEED_FREQ_FUSE_MASK    0x0007f800
+#define IOSF_NC_FB_GFX_FMAX_FUSE_HI            0x34
+#define   FB_FMAX_VMIN_FREQ_HI_MASK            0x00000007
+#define IOSF_NC_FB_GFX_FMAX_FUSE_LO            0x30
+#define   FB_FMAX_VMIN_FREQ_LO_SHIFT           27
+#define   FB_FMAX_VMIN_FREQ_LO_MASK            0xf8000000
+
+/*
+ * DPIO - a special bus for various display related registers to hide behind
  *
  * DPIO is VLV only.
+ *
+ * Note: digital port B is DDI0, digital pot C is DDI1
  */
-#define DPIO_PKT                       (VLV_DISPLAY_BASE + 0x2100)
-#define  DPIO_RID                      (0<<24)
-#define  DPIO_OP_WRITE                 (1<<16)
-#define  DPIO_OP_READ                  (0<<16)
-#define  DPIO_PORTID                   (0x12<<8)
-#define  DPIO_BYTE                     (0xf<<4)
-#define  DPIO_BUSY                     (1<<0) /* status only */
-#define DPIO_DATA                      (VLV_DISPLAY_BASE + 0x2104)
-#define DPIO_REG                       (VLV_DISPLAY_BASE + 0x2108)
+#define DPIO_DEVFN                     0
+#define DPIO_OPCODE_REG_WRITE          1
+#define DPIO_OPCODE_REG_READ           0
+
 #define DPIO_CTL                       (VLV_DISPLAY_BASE + 0x2110)
 #define  DPIO_MODSEL1                  (1<<3) /* if ref clk b == 27 */
 #define  DPIO_MODSEL0                  (1<<2) /* if ref clk a == 27 */
 #define  DPIO_SFR_BYPASS               (1<<1)
 #define  DPIO_RESET                    (1<<0)
 
+#define _DPIO_TX3_SWING_CTL4_A         0x690
+#define _DPIO_TX3_SWING_CTL4_B         0x2a90
+#define DPIO_TX3_SWING_CTL4(pipe) _PIPE(pipe, _DPIO_TX_SWING_CTL4_A, \
+                                       _DPIO_TX3_SWING_CTL4_B)
+
+/*
+ * Per pipe/PLL DPIO regs
+ */
 #define _DPIO_DIV_A                    0x800c
 #define   DPIO_POST_DIV_SHIFT          (28) /* 3 bits */
+#define   DPIO_POST_DIV_DAC            0
+#define   DPIO_POST_DIV_HDMIDP         1 /* DAC 225-400M rate */
+#define   DPIO_POST_DIV_LVDS1          2
+#define   DPIO_POST_DIV_LVDS2          3
 #define   DPIO_K_SHIFT                 (24) /* 4 bits */
 #define   DPIO_P1_SHIFT                        (21) /* 3 bits */
 #define   DPIO_P2_SHIFT                        (16) /* 5 bits */
 #define _DPIO_CORE_CLK_B               0x803c
 #define DPIO_CORE_CLK(pipe) _PIPE(pipe, _DPIO_CORE_CLK_A, _DPIO_CORE_CLK_B)
 
-#define _DPIO_LFP_COEFF_A              0x8048
-#define _DPIO_LFP_COEFF_B              0x8068
-#define DPIO_LFP_COEFF(pipe) _PIPE(pipe, _DPIO_LFP_COEFF_A, _DPIO_LFP_COEFF_B)
+#define _DPIO_IREF_CTL_A               0x8040
+#define _DPIO_IREF_CTL_B               0x8060
+#define DPIO_IREF_CTL(pipe) _PIPE(pipe, _DPIO_IREF_CTL_A, _DPIO_IREF_CTL_B)
+
+#define DPIO_IREF_BCAST                        0xc044
+#define _DPIO_IREF_A                   0x8044
+#define _DPIO_IREF_B                   0x8064
+#define DPIO_IREF(pipe) _PIPE(pipe, _DPIO_IREF_A, _DPIO_IREF_B)
+
+#define _DPIO_PLL_CML_A                        0x804c
+#define _DPIO_PLL_CML_B                        0x806c
+#define DPIO_PLL_CML(pipe) _PIPE(pipe, _DPIO_PLL_CML_A, _DPIO_PLL_CML_B)
+
+#define _DPIO_LPF_COEFF_A              0x8048
+#define _DPIO_LPF_COEFF_B              0x8068
+#define DPIO_LPF_COEFF(pipe) _PIPE(pipe, _DPIO_LPF_COEFF_A, _DPIO_LPF_COEFF_B)
+
+#define DPIO_CALIBRATION               0x80ac
 
 #define DPIO_FASTCLK_DISABLE           0x8100
 
-#define DPIO_DATA_CHANNEL1             0x8220
-#define DPIO_DATA_CHANNEL2             0x8420
+/*
+ * Per DDI channel DPIO regs
+ */
+
+#define _DPIO_PCS_TX_0                 0x8200
+#define _DPIO_PCS_TX_1                 0x8400
+#define   DPIO_PCS_TX_LANE2_RESET      (1<<16)
+#define   DPIO_PCS_TX_LANE1_RESET      (1<<7)
+#define DPIO_PCS_TX(port) _PORT(port, _DPIO_PCS_TX_0, _DPIO_PCS_TX_1)
+
+#define _DPIO_PCS_CLK_0                        0x8204
+#define _DPIO_PCS_CLK_1                        0x8404
+#define   DPIO_PCS_CLK_CRI_RXEB_EIOS_EN        (1<<22)
+#define   DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN (1<<21)
+#define   DPIO_PCS_CLK_DATAWIDTH_SHIFT (6)
+#define   DPIO_PCS_CLK_SOFT_RESET      (1<<5)
+#define DPIO_PCS_CLK(port) _PORT(port, _DPIO_PCS_CLK_0, _DPIO_PCS_CLK_1)
+
+#define _DPIO_PCS_CTL_OVR1_A           0x8224
+#define _DPIO_PCS_CTL_OVR1_B           0x8424
+#define DPIO_PCS_CTL_OVER1(port) _PORT(port, _DPIO_PCS_CTL_OVR1_A, \
+                                      _DPIO_PCS_CTL_OVR1_B)
+
+#define _DPIO_PCS_STAGGER0_A           0x822c
+#define _DPIO_PCS_STAGGER0_B           0x842c
+#define DPIO_PCS_STAGGER0(port) _PORT(port, _DPIO_PCS_STAGGER0_A, \
+                                     _DPIO_PCS_STAGGER0_B)
+
+#define _DPIO_PCS_STAGGER1_A           0x8230
+#define _DPIO_PCS_STAGGER1_B           0x8430
+#define DPIO_PCS_STAGGER1(port) _PORT(port, _DPIO_PCS_STAGGER1_A, \
+                                     _DPIO_PCS_STAGGER1_B)
+
+#define _DPIO_PCS_CLOCKBUF0_A          0x8238
+#define _DPIO_PCS_CLOCKBUF0_B          0x8438
+#define DPIO_PCS_CLOCKBUF0(port) _PORT(port, _DPIO_PCS_CLOCKBUF0_A, \
+                                      _DPIO_PCS_CLOCKBUF0_B)
+
+#define _DPIO_PCS_CLOCKBUF8_A          0x825c
+#define _DPIO_PCS_CLOCKBUF8_B          0x845c
+#define DPIO_PCS_CLOCKBUF8(port) _PORT(port, _DPIO_PCS_CLOCKBUF8_A, \
+                                      _DPIO_PCS_CLOCKBUF8_B)
+
+#define _DPIO_TX_SWING_CTL2_A          0x8288
+#define _DPIO_TX_SWING_CTL2_B          0x8488
+#define DPIO_TX_SWING_CTL2(port) _PORT(port, _DPIO_TX_SWING_CTL2_A, \
+                                      _DPIO_TX_SWING_CTL2_B)
+
+#define _DPIO_TX_SWING_CTL3_A          0x828c
+#define _DPIO_TX_SWING_CTL3_B          0x848c
+#define DPIO_TX_SWING_CTL3(port) _PORT(port, _DPIO_TX_SWING_CTL3_A, \
+                                      _DPIO_TX_SWING_CTL3_B)
+
+#define _DPIO_TX_SWING_CTL4_A          0x8290
+#define _DPIO_TX_SWING_CTL4_B          0x8490
+#define DPIO_TX_SWING_CTL4(port) _PORT(port, _DPIO_TX_SWING_CTL4_A, \
+                                      _DPIO_TX_SWING_CTL4_B)
+
+#define _DPIO_TX_OCALINIT_0            0x8294
+#define _DPIO_TX_OCALINIT_1            0x8494
+#define   DPIO_TX_OCALINIT_EN          (1<<31)
+#define DPIO_TX_OCALINIT(port) _PORT(port, _DPIO_TX_OCALINIT_0, \
+                                    _DPIO_TX_OCALINIT_1)
+
+#define _DPIO_TX_CTL_0                 0x82ac
+#define _DPIO_TX_CTL_1                 0x84ac
+#define DPIO_TX_CTL(port) _PORT(port, _DPIO_TX_CTL_0, _DPIO_TX_CTL_1)
+
+#define _DPIO_TX_LANE_0                        0x82b8
+#define _DPIO_TX_LANE_1                        0x84b8
+#define DPIO_TX_LANE(port) _PORT(port, _DPIO_TX_LANE_0, _DPIO_TX_LANE_1)
+
+#define _DPIO_DATA_CHANNEL1            0x8220
+#define _DPIO_DATA_CHANNEL2            0x8420
+#define DPIO_DATA_CHANNEL(port) _PORT(port, _DPIO_DATA_CHANNEL1, _DPIO_DATA_CHANNEL2)
+
+#define _DPIO_PORT0_PCS0               0x0220
+#define _DPIO_PORT0_PCS1               0x0420
+#define _DPIO_PORT1_PCS2               0x2620
+#define _DPIO_PORT1_PCS3               0x2820
+#define DPIO_DATA_LANE_A(port) _PORT(port, _DPIO_PORT0_PCS0, _DPIO_PORT1_PCS2)
+#define DPIO_DATA_LANE_B(port) _PORT(port, _DPIO_PORT0_PCS1, _DPIO_PORT1_PCS3)
+#define DPIO_DATA_CHANNEL1              0x8220
+#define DPIO_DATA_CHANNEL2              0x8420
 
 /*
  * Fence registers
 #define RENDER_RING_BASE       0x02000
 #define BSD_RING_BASE          0x04000
 #define GEN6_BSD_RING_BASE     0x12000
+#define VEBOX_RING_BASE                0x1a000
 #define BLT_RING_BASE          0x22000
 #define RING_TAIL(base)                ((base)+0x30)
 #define RING_HEAD(base)                ((base)+0x34)
 #define RING_CTL(base)         ((base)+0x3c)
 #define RING_SYNC_0(base)      ((base)+0x40)
 #define RING_SYNC_1(base)      ((base)+0x44)
-#define GEN6_RVSYNC (RING_SYNC_0(RENDER_RING_BASE))
-#define GEN6_RBSYNC (RING_SYNC_1(RENDER_RING_BASE))
-#define GEN6_VRSYNC (RING_SYNC_1(GEN6_BSD_RING_BASE))
-#define GEN6_VBSYNC (RING_SYNC_0(GEN6_BSD_RING_BASE))
-#define GEN6_BRSYNC (RING_SYNC_0(BLT_RING_BASE))
-#define GEN6_BVSYNC (RING_SYNC_1(BLT_RING_BASE))
+#define RING_SYNC_2(base)      ((base)+0x48)
+#define GEN6_RVSYNC    (RING_SYNC_0(RENDER_RING_BASE))
+#define GEN6_RBSYNC    (RING_SYNC_1(RENDER_RING_BASE))
+#define GEN6_RVESYNC   (RING_SYNC_2(RENDER_RING_BASE))
+#define GEN6_VBSYNC    (RING_SYNC_0(GEN6_BSD_RING_BASE))
+#define GEN6_VRSYNC    (RING_SYNC_1(GEN6_BSD_RING_BASE))
+#define GEN6_VVESYNC   (RING_SYNC_2(GEN6_BSD_RING_BASE))
+#define GEN6_BRSYNC    (RING_SYNC_0(BLT_RING_BASE))
+#define GEN6_BVSYNC    (RING_SYNC_1(BLT_RING_BASE))
+#define GEN6_BVESYNC   (RING_SYNC_2(BLT_RING_BASE))
+#define GEN6_VEBSYNC   (RING_SYNC_0(VEBOX_RING_BASE))
+#define GEN6_VERSYNC   (RING_SYNC_1(VEBOX_RING_BASE))
+#define GEN6_VEVSYNC   (RING_SYNC_2(VEBOX_RING_BASE))
+#define GEN6_NOSYNC 0
 #define RING_MAX_IDLE(base)    ((base)+0x54)
 #define RING_HWS_PGA(base)     ((base)+0x80)
 #define RING_HWS_PGA_GEN6(base)        ((base)+0x2080)
 #define DONE_REG               0x40b0
 #define BSD_HWS_PGA_GEN7       (0x04180)
 #define BLT_HWS_PGA_GEN7       (0x04280)
+#define VEBOX_HWS_PGA_GEN7     (0x04380)
 #define RING_ACTHD(base)       ((base)+0x74)
 #define RING_NOPID(base)       ((base)+0x94)
 #define RING_IMR(base)         ((base)+0xa8)
 
 #define ERROR_GEN6     0x040a0
 #define GEN7_ERR_INT   0x44040
-#define   ERR_INT_MMIO_UNCLAIMED (1<<13)
+#define   ERR_INT_POISON               (1<<31)
+#define   ERR_INT_MMIO_UNCLAIMED       (1<<13)
+#define   ERR_INT_FIFO_UNDERRUN_C      (1<<6)
+#define   ERR_INT_FIFO_UNDERRUN_B      (1<<3)
+#define   ERR_INT_FIFO_UNDERRUN_A      (1<<0)
 
 #define FPGA_DBG               0x42300
 #define   FPGA_DBG_RM_NOCLAIM  (1<<31)
 #define VLV_IIR                (VLV_DISPLAY_BASE + 0x20a4)
 #define VLV_IMR                (VLV_DISPLAY_BASE + 0x20a8)
 #define VLV_ISR                (VLV_DISPLAY_BASE + 0x20ac)
-#define   I915_PIPE_CONTROL_NOTIFY_INTERRUPT           (1<<18)
-#define   I915_DISPLAY_PORT_INTERRUPT                  (1<<17)
-#define   I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT   (1<<15)
-#define   I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT     (1<<14) /* p-state */
-#define   I915_HWB_OOM_INTERRUPT                       (1<<13)
-#define   I915_SYNC_STATUS_INTERRUPT                   (1<<12)
-#define   I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT  (1<<11)
-#define   I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT  (1<<10)
-#define   I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT    (1<<9)
-#define   I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT  (1<<8)
-#define   I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT         (1<<7)
-#define   I915_DISPLAY_PIPE_A_EVENT_INTERRUPT          (1<<6)
-#define   I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT         (1<<5)
-#define   I915_DISPLAY_PIPE_B_EVENT_INTERRUPT          (1<<4)
-#define   I915_DEBUG_INTERRUPT                         (1<<2)
-#define   I915_USER_INTERRUPT                          (1<<1)
-#define   I915_ASLE_INTERRUPT                          (1<<0)
-#define   I915_BSD_USER_INTERRUPT                      (1<<25)
+#define VLV_PCBR       (VLV_DISPLAY_BASE + 0x2120)
 #define   DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */
 #define EIR            0x020b0
 #define EMR            0x020b4
                                        will not assert AGPBUSY# and will only
                                        be delivered when out of C3. */
 #define   INSTPM_FORCE_ORDERING                                (1<<7) /* GEN6+ */
+#define   INSTPM_TLB_INVALIDATE        (1<<9)
+#define   INSTPM_SYNC_FLUSH    (1<<5)
 #define ACTHD          0x020c8
 #define FW_BLC         0x020d8
 #define FW_BLC2                0x020dc
 #define CACHE_MODE_1           0x7004 /* IVB+ */
 #define   PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6)
 
-/* GEN6 interrupt control
- * Note that the per-ring interrupt bits do alias with the global interrupt bits
- * in GTIMR. */
-#define GEN6_RENDER_HWSTAM     0x2098
-#define GEN6_RENDER_IMR                0x20a8
-#define   GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT         (1 << 8)
-#define   GEN6_RENDER_PPGTT_PAGE_FAULT                 (1 << 7)
-#define   GEN6_RENDER_TIMEOUT_COUNTER_EXPIRED          (1 << 6)
-#define   GEN6_RENDER_L3_PARITY_ERROR                  (1 << 5)
-#define   GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT    (1 << 4)
-#define   GEN6_RENDER_COMMAND_PARSER_MASTER_ERROR      (1 << 3)
-#define   GEN6_RENDER_SYNC_STATUS                      (1 << 2)
-#define   GEN6_RENDER_DEBUG_INTERRUPT                  (1 << 1)
-#define   GEN6_RENDER_USER_INTERRUPT                   (1 << 0)
-
-#define GEN6_BLITTER_HWSTAM    0x22098
-#define GEN6_BLITTER_IMR       0x220a8
-#define   GEN6_BLITTER_MI_FLUSH_DW_NOTIFY_INTERRUPT    (1 << 26)
-#define   GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR     (1 << 25)
-#define   GEN6_BLITTER_SYNC_STATUS                     (1 << 24)
-#define   GEN6_BLITTER_USER_INTERRUPT                  (1 << 22)
-
 #define GEN6_BLITTER_ECOSKPD   0x221d0
 #define   GEN6_BLITTER_LOCK_SHIFT                      16
 #define   GEN6_BLITTER_FBC_NOTIFY                      (1<<3)
 #define   GEN6_BSD_SLEEP_INDICATOR     (1 << 3)
 #define   GEN6_BSD_GO_INDICATOR                (1 << 4)
 
-#define GEN6_BSD_HWSTAM                        0x12098
-#define GEN6_BSD_IMR                   0x120a8
-#define   GEN6_BSD_USER_INTERRUPT      (1 << 12)
+/* On modern GEN architectures interrupt control consists of two sets
+ * of registers. The first set pertains to the ring generating the
+ * interrupt. The second control is for the functional block generating the
+ * interrupt. These are PM, GT, DE, etc.
+ *
+ * Luckily *knocks on wood* all the ring interrupt bits match up with the
+ * GT interrupt bits, so we don't need to duplicate the defines.
+ *
+ * These defines should cover us well from SNB->HSW with minor exceptions
+ * it can also work on ILK.
+ */
+#define GT_BLT_FLUSHDW_NOTIFY_INTERRUPT                (1 << 26)
+#define GT_BLT_CS_ERROR_INTERRUPT              (1 << 25)
+#define GT_BLT_USER_INTERRUPT                  (1 << 22)
+#define GT_BSD_CS_ERROR_INTERRUPT              (1 << 15)
+#define GT_BSD_USER_INTERRUPT                  (1 << 12)
+#define GT_RENDER_L3_PARITY_ERROR_INTERRUPT    (1 <<  5) /* !snb */
+#define GT_RENDER_PIPECTL_NOTIFY_INTERRUPT     (1 <<  4)
+#define GT_RENDER_CS_MASTER_ERROR_INTERRUPT    (1 <<  3)
+#define GT_RENDER_SYNC_STATUS_INTERRUPT                (1 <<  2)
+#define GT_RENDER_DEBUG_INTERRUPT              (1 <<  1)
+#define GT_RENDER_USER_INTERRUPT               (1 <<  0)
+
+#define PM_VEBOX_CS_ERROR_INTERRUPT            (1 << 12) /* hsw+ */
+#define PM_VEBOX_USER_INTERRUPT                        (1 << 10) /* hsw+ */
+
+/* These are all the "old" interrupts */
+#define ILK_BSD_USER_INTERRUPT                         (1<<5)
+#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT             (1<<18)
+#define I915_DISPLAY_PORT_INTERRUPT                    (1<<17)
+#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT     (1<<15)
+#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT       (1<<14) /* p-state */
+#define I915_HWB_OOM_INTERRUPT                         (1<<13)
+#define I915_SYNC_STATUS_INTERRUPT                     (1<<12)
+#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT    (1<<11)
+#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT    (1<<10)
+#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT      (1<<9)
+#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT    (1<<8)
+#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT           (1<<7)
+#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT            (1<<6)
+#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT           (1<<5)
+#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT            (1<<4)
+#define I915_DEBUG_INTERRUPT                           (1<<2)
+#define I915_USER_INTERRUPT                            (1<<1)
+#define I915_ASLE_INTERRUPT                            (1<<0)
+#define I915_BSD_USER_INTERRUPT                                (1 << 25)
 
 #define GEN6_BSD_RNCID                 0x12198
 
 #define   DPFC_CTL_EN          (1<<31)
 #define   DPFC_CTL_PLANEA      (0<<30)
 #define   DPFC_CTL_PLANEB      (1<<30)
+#define   IVB_DPFC_CTL_PLANE_SHIFT     (29)
 #define   DPFC_CTL_FENCE_EN    (1<<29)
+#define   IVB_DPFC_CTL_FENCE_EN        (1<<28)
 #define   DPFC_CTL_PERSISTENT_MODE     (1<<25)
 #define   DPFC_SR_EN           (1<<10)
 #define   DPFC_CTL_LIMIT_1X    (0<<6)
 #define ILK_DPFC_CHICKEN       0x43224
 #define ILK_FBC_RT_BASE                0x2128
 #define   ILK_FBC_RT_VALID     (1<<0)
+#define   SNB_FBC_FRONT_BUFFER (1<<1)
 
 #define ILK_DISPLAY_CHICKEN1   0x42000
 #define   ILK_FBCQ_DIS         (1<<22)
 #define   SNB_CPU_FENCE_ENABLE (1<<29)
 #define DPFC_CPU_FENCE_OFFSET  0x100104
 
+/* Framebuffer compression for Ivybridge */
+#define IVB_FBC_RT_BASE                        0x7020
+
+#define IPS_CTL                0x43408
+#define   IPS_ENABLE   (1 << 31)
+
+#define MSG_FBC_REND_STATE     0x50380
+#define   FBC_REND_NUKE                (1<<2)
+#define   FBC_REND_CACHE_CLEAN (1<<1)
+
+#define _HSW_PIPE_SLICE_CHICKEN_1_A    0x420B0
+#define _HSW_PIPE_SLICE_CHICKEN_1_B    0x420B4
+#define   HSW_BYPASS_FBC_QUEUE         (1<<22)
+#define HSW_PIPE_SLICE_CHICKEN_1(pipe) _PIPE(pipe, + \
+                                            _HSW_PIPE_SLICE_CHICKEN_1_A, + \
+                                            _HSW_PIPE_SLICE_CHICKEN_1_B)
+
+#define HSW_CLKGATE_DISABLE_PART_1     0x46500
+#define   HSW_DPFC_GATING_DISABLE      (1<<23)
 
 /*
  * GPIO regs
 #define   DPLL_FPA01_P1_POST_DIV_MASK  0x00ff0000 /* i915 */
 #define   DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */
 #define   DPLL_LOCK_VLV                        (1<<15)
+#define   DPLL_INTEGRATED_CRI_CLK_VLV  (1<<14)
 #define   DPLL_INTEGRATED_CLOCK_VLV    (1<<13)
+#define   DPLL_PORTC_READY_MASK                (0xf << 4)
+#define   DPLL_PORTB_READY_MASK                (0xf)
 
 #define   DPLL_FPA01_P1_POST_DIV_MASK_I830     0x001f0000
 /*
 #define  DSTATE_PLL_D3_OFF                     (1<<3)
 #define  DSTATE_GFX_CLOCK_GATING               (1<<1)
 #define  DSTATE_DOT_CLOCK_GATING               (1<<0)
-#define DSPCLK_GATE_D          0x6200
+#define DSPCLK_GATE_D  (dev_priv->info->display_mmio_offset + 0x6200)
 # define DPUNIT_B_CLOCK_GATE_DISABLE           (1 << 30) /* 965 */
 # define VSUNIT_CLOCK_GATE_DISABLE             (1 << 29) /* 965 */
 # define VRHUNIT_CLOCK_GATE_DISABLE            (1 << 28) /* 965 */
 #define FW_BLC_SELF_VLV                (VLV_DISPLAY_BASE + 0x6500)
 #define  FW_CSPWRDWNEN         (1<<15)
 
+#define MI_ARB_VLV             (VLV_DISPLAY_BASE + 0x6504)
+
 /*
  * Palette regs
  */
                                         GEN7_CXT_EXTENDED_SIZE(ctx_reg) + \
                                         GEN7_CXT_GT1_SIZE(ctx_reg) + \
                                         GEN7_CXT_VFSTATE_SIZE(ctx_reg))
-#define HSW_CXT_POWER_SIZE(ctx_reg)    ((ctx_reg >> 26) & 0x3f)
-#define HSW_CXT_RING_SIZE(ctx_reg)     ((ctx_reg >> 23) & 0x7)
-#define HSW_CXT_RENDER_SIZE(ctx_reg)   ((ctx_reg >> 15) & 0xff)
-#define HSW_CXT_TOTAL_SIZE(ctx_reg)    (HSW_CXT_POWER_SIZE(ctx_reg) + \
-                                        HSW_CXT_RING_SIZE(ctx_reg) + \
-                                        HSW_CXT_RENDER_SIZE(ctx_reg) + \
-                                        GEN7_CXT_VFSTATE_SIZE(ctx_reg))
-
+/* Haswell does have the CXT_SIZE register however it does not appear to be
+ * valid. Now, docs explain in dwords what is in the context object. The full
+ * size is 70720 bytes, however, the power context and execlist context will
+ * never be saved (power context is stored elsewhere, and execlists don't work
+ * on HSW) - so the final size is 66944 bytes, which rounds to 17 pages.
+ */
+#define HSW_CXT_TOTAL_SIZE             (17 * PAGE_SIZE)
 
 /*
  * Overlay regs
 #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV       (1 << 2)
 
 #define PORT_HOTPLUG_STAT      (dev_priv->info->display_mmio_offset + 0x61114)
-/* HDMI/DP bits are gen4+ */
-#define   PORTB_HOTPLUG_LIVE_STATUS               (1 << 29)
+/*
+ * HDMI/DP bits are gen4+
+ *
+ * WARNING: Bspec for hpd status bits on gen4 seems to be completely confused.
+ * Please check the detailed lore in the commit message for for experimental
+ * evidence.
+ */
+#define   PORTD_HOTPLUG_LIVE_STATUS               (1 << 29)
 #define   PORTC_HOTPLUG_LIVE_STATUS               (1 << 28)
-#define   PORTD_HOTPLUG_LIVE_STATUS               (1 << 27)
+#define   PORTB_HOTPLUG_LIVE_STATUS               (1 << 27)
 #define   PORTD_HOTPLUG_INT_STATUS             (3 << 21)
 #define   PORTC_HOTPLUG_INT_STATUS             (3 << 19)
 #define   PORTB_HOTPLUG_INT_STATUS             (3 << 17)
 /* SDVO is different across gen3/4 */
 #define   SDVOC_HOTPLUG_INT_STATUS_G4X         (1 << 3)
 #define   SDVOB_HOTPLUG_INT_STATUS_G4X         (1 << 2)
+/*
+ * Bspec seems to be seriously misleaded about the SDVO hpd bits on i965g/gm,
+ * since reality corrobates that they're the same as on gen3. But keep these
+ * bits here (and the comment!) to help any other lost wanderers back onto the
+ * right tracks.
+ */
 #define   SDVOC_HOTPLUG_INT_STATUS_I965                (3 << 4)
 #define   SDVOB_HOTPLUG_INT_STATUS_I965                (3 << 2)
 #define   SDVOC_HOTPLUG_INT_STATUS_I915                (1 << 7)
                                                 PORTC_HOTPLUG_INT_STATUS | \
                                                 PORTD_HOTPLUG_INT_STATUS)
 
-#define HOTPLUG_INT_STATUS_I965                        (CRT_HOTPLUG_INT_STATUS | \
-                                                SDVOB_HOTPLUG_INT_STATUS_I965 | \
-                                                SDVOC_HOTPLUG_INT_STATUS_I965 | \
-                                                PORTB_HOTPLUG_INT_STATUS | \
-                                                PORTC_HOTPLUG_INT_STATUS | \
-                                                PORTD_HOTPLUG_INT_STATUS)
-
 #define HOTPLUG_INT_STATUS_I915                        (CRT_HOTPLUG_INT_STATUS | \
                                                 SDVOB_HOTPLUG_INT_STATUS_I915 | \
                                                 SDVOC_HOTPLUG_INT_STATUS_I915 | \
 #define   BLM_PIPE_A                   (0 << 29)
 #define   BLM_PIPE_B                   (1 << 29)
 #define   BLM_PIPE_C                   (2 << 29) /* ivb + */
+#define   BLM_TRANSCODER_A             BLM_PIPE_A /* hsw */
+#define   BLM_TRANSCODER_B             BLM_PIPE_B
+#define   BLM_TRANSCODER_C             BLM_PIPE_C
+#define   BLM_TRANSCODER_EDP           (3 << 29)
 #define   BLM_PIPE(pipe)               ((pipe) << 29)
 #define   BLM_POLARITY_I965            (1 << 28) /* gen4 only */
 #define   BLM_PHASE_IN_INTERUPT_STATUS (1 << 26)
 #define   DP_PRE_EMPHASIS_SHIFT                22
 
 /* How many wires to use. I guess 3 was too hard */
-#define   DP_PORT_WIDTH_1              (0 << 19)
-#define   DP_PORT_WIDTH_2              (1 << 19)
-#define   DP_PORT_WIDTH_4              (3 << 19)
+#define   DP_PORT_WIDTH(width)         (((width) - 1) << 19)
 #define   DP_PORT_WIDTH_MASK           (7 << 19)
 
 /* Mystic DPCD version 1.1 special mode */
  * which is after the LUTs, so we want the bytes for our color format.
  * For our current usage, this is always 3, one byte for R, G and B.
  */
-#define _PIPEA_GMCH_DATA_M                     0x70050
-#define _PIPEB_GMCH_DATA_M                     0x71050
+#define _PIPEA_DATA_M_G4X      0x70050
+#define _PIPEB_DATA_M_G4X      0x71050
 
 /* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */
 #define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */
+#define  TU_SIZE_SHIFT         25
 #define  TU_SIZE_MASK           (0x3f << 25)
 
 #define  DATA_LINK_M_N_MASK    (0xffffff)
 #define  DATA_LINK_N_MAX       (0x800000)
 
-#define _PIPEA_GMCH_DATA_N                     0x70054
-#define _PIPEB_GMCH_DATA_N                     0x71054
+#define _PIPEA_DATA_N_G4X      0x70054
+#define _PIPEB_DATA_N_G4X      0x71054
+#define   PIPE_GMCH_DATA_N_MASK                        (0xffffff)
 
 /*
  * Computing Link M and N values for the Display Port link
  * Attributes and VB-ID.
  */
 
-#define _PIPEA_DP_LINK_M                               0x70060
-#define _PIPEB_DP_LINK_M                               0x71060
+#define _PIPEA_LINK_M_G4X      0x70060
+#define _PIPEB_LINK_M_G4X      0x71060
+#define   PIPEA_DP_LINK_M_MASK                 (0xffffff)
 
-#define _PIPEA_DP_LINK_N                               0x70064
-#define _PIPEB_DP_LINK_N                               0x71064
+#define _PIPEA_LINK_N_G4X      0x70064
+#define _PIPEB_LINK_N_G4X      0x71064
+#define   PIPEA_DP_LINK_N_MASK                 (0xffffff)
 
-#define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M)
-#define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N)
-#define PIPE_DP_LINK_M(pipe) _PIPE(pipe, _PIPEA_DP_LINK_M, _PIPEB_DP_LINK_M)
-#define PIPE_DP_LINK_N(pipe) _PIPE(pipe, _PIPEA_DP_LINK_N, _PIPEB_DP_LINK_N)
+#define PIPE_DATA_M_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_M_G4X, _PIPEB_DATA_M_G4X)
+#define PIPE_DATA_N_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_N_G4X, _PIPEB_DATA_N_G4X)
+#define PIPE_LINK_M_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_M_G4X, _PIPEB_LINK_M_G4X)
+#define PIPE_LINK_N_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_N_G4X, _PIPEB_LINK_N_G4X)
 
 /* Display & cursor control */
 
 #define   PIPECONF_INTERLACED_ILK              (3 << 21)
 #define   PIPECONF_INTERLACED_DBL_ILK          (4 << 21) /* ilk/snb only */
 #define   PIPECONF_PFIT_PF_INTERLACED_DBL_ILK  (5 << 21) /* ilk/snb only */
+#define   PIPECONF_INTERLACE_MODE_MASK         (7 << 21)
 #define   PIPECONF_CXSR_DOWNCLOCK      (1<<16)
 #define   PIPECONF_COLOR_RANGE_SELECT  (1 << 13)
 #define   PIPECONF_BPC_MASK    (0x7 << 5)
 #define WM3S_LP_IVB            0x45128
 #define  WM1S_LP_EN            (1<<31)
 
+#define HSW_WM_LP_VAL(lat, fbc, pri, cur) \
+       (WM3_LP_EN | ((lat) << WM1_LP_LATENCY_SHIFT) | \
+        ((fbc) << WM1_LP_FBC_SHIFT) | ((pri) << WM1_LP_SR_SHIFT) | (cur))
+
 /* Memory latency timer register */
 #define MLTR_ILK               0x11222
 #define  MLTR_WM1_SHIFT                0
 #define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC)
 #define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE)
 
-#define _SPACNTR               0x72180
+#define _SPACNTR               (VLV_DISPLAY_BASE + 0x72180)
 #define   SP_ENABLE                    (1<<31)
 #define   SP_GEAMMA_ENABLE             (1<<30)
 #define   SP_PIXFORMAT_MASK            (0xf<<26)
 #define   SP_YUV_ORDER_YVYU            (2<<16)
 #define   SP_YUV_ORDER_VYUY            (3<<16)
 #define   SP_TILED                     (1<<10)
-#define _SPALINOFF             0x72184
-#define _SPASTRIDE             0x72188
-#define _SPAPOS                        0x7218c
-#define _SPASIZE               0x72190
-#define _SPAKEYMINVAL          0x72194
-#define _SPAKEYMSK             0x72198
-#define _SPASURF               0x7219c
-#define _SPAKEYMAXVAL          0x721a0
-#define _SPATILEOFF            0x721a4
-#define _SPACONSTALPHA         0x721a8
-#define _SPAGAMC               0x721f4
-
-#define _SPBCNTR               0x72280
-#define _SPBLINOFF             0x72284
-#define _SPBSTRIDE             0x72288
-#define _SPBPOS                        0x7228c
-#define _SPBSIZE               0x72290
-#define _SPBKEYMINVAL          0x72294
-#define _SPBKEYMSK             0x72298
-#define _SPBSURF               0x7229c
-#define _SPBKEYMAXVAL          0x722a0
-#define _SPBTILEOFF            0x722a4
-#define _SPBCONSTALPHA         0x722a8
-#define _SPBGAMC               0x722f4
+#define _SPALINOFF             (VLV_DISPLAY_BASE + 0x72184)
+#define _SPASTRIDE             (VLV_DISPLAY_BASE + 0x72188)
+#define _SPAPOS                        (VLV_DISPLAY_BASE + 0x7218c)
+#define _SPASIZE               (VLV_DISPLAY_BASE + 0x72190)
+#define _SPAKEYMINVAL          (VLV_DISPLAY_BASE + 0x72194)
+#define _SPAKEYMSK             (VLV_DISPLAY_BASE + 0x72198)
+#define _SPASURF               (VLV_DISPLAY_BASE + 0x7219c)
+#define _SPAKEYMAXVAL          (VLV_DISPLAY_BASE + 0x721a0)
+#define _SPATILEOFF            (VLV_DISPLAY_BASE + 0x721a4)
+#define _SPACONSTALPHA         (VLV_DISPLAY_BASE + 0x721a8)
+#define _SPAGAMC               (VLV_DISPLAY_BASE + 0x721f4)
+
+#define _SPBCNTR               (VLV_DISPLAY_BASE + 0x72280)
+#define _SPBLINOFF             (VLV_DISPLAY_BASE + 0x72284)
+#define _SPBSTRIDE             (VLV_DISPLAY_BASE + 0x72288)
+#define _SPBPOS                        (VLV_DISPLAY_BASE + 0x7228c)
+#define _SPBSIZE               (VLV_DISPLAY_BASE + 0x72290)
+#define _SPBKEYMINVAL          (VLV_DISPLAY_BASE + 0x72294)
+#define _SPBKEYMSK             (VLV_DISPLAY_BASE + 0x72298)
+#define _SPBSURF               (VLV_DISPLAY_BASE + 0x7229c)
+#define _SPBKEYMAXVAL          (VLV_DISPLAY_BASE + 0x722a0)
+#define _SPBTILEOFF            (VLV_DISPLAY_BASE + 0x722a4)
+#define _SPBCONSTALPHA         (VLV_DISPLAY_BASE + 0x722a8)
+#define _SPBGAMC               (VLV_DISPLAY_BASE + 0x722f4)
 
 #define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR)
 #define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF)
 #define _LGC_PALETTE_B           0x4a800
 #define LGC_PALETTE(pipe) _PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B)
 
+#define _GAMMA_MODE_A          0x4a480
+#define _GAMMA_MODE_B          0x4ac80
+#define GAMMA_MODE(pipe) _PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B)
+#define GAMMA_MODE_MODE_MASK   (3 << 0)
+#define GAMMA_MODE_MODE_8BIT   (0 << 0)
+#define GAMMA_MODE_MODE_10BIT  (1 << 0)
+#define GAMMA_MODE_MODE_12BIT  (2 << 0)
+#define GAMMA_MODE_MODE_SPLIT  (3 << 0)
+
 /* interrupts */
 #define DE_MASTER_IRQ_CONTROL   (1 << 31)
 #define DE_SPRITEB_FLIP_DONE    (1 << 29)
 #define DE_PIPEA_FIFO_UNDERRUN  (1 << 0)
 
 /* More Ivybridge lolz */
-#define DE_ERR_DEBUG_IVB               (1<<30)
+#define DE_ERR_INT_IVB                 (1<<30)
 #define DE_GSE_IVB                     (1<<29)
 #define DE_PCH_EVENT_IVB               (1<<28)
 #define DE_DP_A_HOTPLUG_IVB            (1<<27)
 #define DEIIR   0x44008
 #define DEIER   0x4400c
 
-/* GT interrupt.
- * Note that for gen6+ the ring-specific interrupt bits do alias with the
- * corresponding bits in the per-ring interrupt control registers. */
-#define GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT   (1 << 26)
-#define GT_GEN6_BLT_CS_ERROR_INTERRUPT         (1 << 25)
-#define GT_GEN6_BLT_USER_INTERRUPT             (1 << 22)
-#define GT_GEN6_BSD_CS_ERROR_INTERRUPT         (1 << 15)
-#define GT_GEN6_BSD_USER_INTERRUPT             (1 << 12)
-#define GT_BSD_USER_INTERRUPT                  (1 << 5) /* ilk only */
-#define GT_GEN7_L3_PARITY_ERROR_INTERRUPT      (1 << 5)
-#define GT_PIPE_NOTIFY                         (1 << 4)
-#define GT_RENDER_CS_ERROR_INTERRUPT           (1 << 3)
-#define GT_SYNC_STATUS                         (1 << 2)
-#define GT_USER_INTERRUPT                      (1 << 0)
-
 #define GTISR   0x44010
 #define GTIMR   0x44014
 #define GTIIR   0x44018
 # define CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE     (1 << 5)
 # define CHICKEN3_DGMG_DONE_FIX_DISABLE                (1 << 2)
 
+#define CHICKEN_PAR1_1         0x42080
+#define  FORCE_ARB_IDLE_PLANES (1 << 14)
+
 #define DISP_ARB_CTL   0x45000
 #define  DISP_TILE_SURFACE_SWIZZLING   (1<<13)
 #define  DISP_FBC_WM_DIS               (1<<15)
                                 SDE_PORTC_HOTPLUG_CPT |        \
                                 SDE_PORTB_HOTPLUG_CPT)
 #define SDE_GMBUS_CPT          (1 << 17)
+#define SDE_ERROR_CPT          (1 << 16)
 #define SDE_AUDIO_CP_REQ_C_CPT (1 << 10)
 #define SDE_AUDIO_CP_CHG_C_CPT (1 << 9)
 #define SDE_FDI_RXC_CPT                (1 << 8)
 #define SDEIIR  0xc4008
 #define SDEIER  0xc400c
 
+#define SERR_INT                       0xc4040
+#define  SERR_INT_POISON               (1<<31)
+#define  SERR_INT_TRANS_C_FIFO_UNDERRUN        (1<<6)
+#define  SERR_INT_TRANS_B_FIFO_UNDERRUN        (1<<3)
+#define  SERR_INT_TRANS_A_FIFO_UNDERRUN        (1<<0)
+
 /* digital port hotplug */
 #define PCH_PORT_HOTPLUG        0xc4030                /* SHOTPLUG_CTL */
 #define PORTD_HOTPLUG_ENABLE            (1 << 20)
 
 #define _PCH_DPLL_A              0xc6014
 #define _PCH_DPLL_B              0xc6018
-#define _PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B)
+#define PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B)
 
 #define _PCH_FPA0                0xc6040
 #define  FP_CB_TUNE            (0x3<<22)
 #define _PCH_FPA1                0xc6044
 #define _PCH_FPB0                0xc6048
 #define _PCH_FPB1                0xc604c
-#define _PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0)
-#define _PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1)
+#define PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0)
+#define PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1)
 
 #define PCH_DPLL_TEST           0xc606c
 
 #define PCH_SSC4_AUX_PARMS      0xc6214
 
 #define PCH_DPLL_SEL           0xc7000
-#define  TRANSA_DPLL_ENABLE    (1<<3)
-#define         TRANSA_DPLLB_SEL       (1<<0)
-#define         TRANSA_DPLLA_SEL       0
-#define  TRANSB_DPLL_ENABLE    (1<<7)
-#define         TRANSB_DPLLB_SEL       (1<<4)
-#define         TRANSB_DPLLA_SEL       (0)
-#define  TRANSC_DPLL_ENABLE    (1<<11)
-#define         TRANSC_DPLLB_SEL       (1<<8)
-#define         TRANSC_DPLLA_SEL       (0)
+#define         TRANS_DPLLB_SEL(pipe)          (1 << (pipe * 4))
+#define         TRANS_DPLLA_SEL(pipe)          0
+#define  TRANS_DPLL_ENABLE(pipe)       (1 << (pipe * 4 + 3))
 
 /* transcoder */
 
-#define _TRANS_HTOTAL_A          0xe0000
-#define  TRANS_HTOTAL_SHIFT     16
-#define  TRANS_HACTIVE_SHIFT    0
-#define _TRANS_HBLANK_A          0xe0004
-#define  TRANS_HBLANK_END_SHIFT 16
-#define  TRANS_HBLANK_START_SHIFT 0
-#define _TRANS_HSYNC_A           0xe0008
-#define  TRANS_HSYNC_END_SHIFT  16
-#define  TRANS_HSYNC_START_SHIFT 0
-#define _TRANS_VTOTAL_A          0xe000c
-#define  TRANS_VTOTAL_SHIFT     16
-#define  TRANS_VACTIVE_SHIFT    0
-#define _TRANS_VBLANK_A          0xe0010
-#define  TRANS_VBLANK_END_SHIFT 16
-#define  TRANS_VBLANK_START_SHIFT 0
-#define _TRANS_VSYNC_A           0xe0014
-#define  TRANS_VSYNC_END_SHIFT  16
-#define  TRANS_VSYNC_START_SHIFT 0
-#define _TRANS_VSYNCSHIFT_A    0xe0028
-
-#define _TRANSA_DATA_M1          0xe0030
-#define _TRANSA_DATA_N1          0xe0034
-#define _TRANSA_DATA_M2          0xe0038
-#define _TRANSA_DATA_N2          0xe003c
-#define _TRANSA_DP_LINK_M1       0xe0040
-#define _TRANSA_DP_LINK_N1       0xe0044
-#define _TRANSA_DP_LINK_M2       0xe0048
-#define _TRANSA_DP_LINK_N2       0xe004c
+#define _PCH_TRANS_HTOTAL_A            0xe0000
+#define  TRANS_HTOTAL_SHIFT            16
+#define  TRANS_HACTIVE_SHIFT           0
+#define _PCH_TRANS_HBLANK_A            0xe0004
+#define  TRANS_HBLANK_END_SHIFT                16
+#define  TRANS_HBLANK_START_SHIFT      0
+#define _PCH_TRANS_HSYNC_A             0xe0008
+#define  TRANS_HSYNC_END_SHIFT         16
+#define  TRANS_HSYNC_START_SHIFT       0
+#define _PCH_TRANS_VTOTAL_A            0xe000c
+#define  TRANS_VTOTAL_SHIFT            16
+#define  TRANS_VACTIVE_SHIFT           0
+#define _PCH_TRANS_VBLANK_A            0xe0010
+#define  TRANS_VBLANK_END_SHIFT                16
+#define  TRANS_VBLANK_START_SHIFT      0
+#define _PCH_TRANS_VSYNC_A             0xe0014
+#define  TRANS_VSYNC_END_SHIFT         16
+#define  TRANS_VSYNC_START_SHIFT       0
+#define _PCH_TRANS_VSYNCSHIFT_A                0xe0028
+
+#define _PCH_TRANSA_DATA_M1    0xe0030
+#define _PCH_TRANSA_DATA_N1    0xe0034
+#define _PCH_TRANSA_DATA_M2    0xe0038
+#define _PCH_TRANSA_DATA_N2    0xe003c
+#define _PCH_TRANSA_LINK_M1    0xe0040
+#define _PCH_TRANSA_LINK_N1    0xe0044
+#define _PCH_TRANSA_LINK_M2    0xe0048
+#define _PCH_TRANSA_LINK_N2    0xe004c
 
 /* Per-transcoder DIP controls */
 
 #define HSW_TVIDEO_DIP_VSC_DATA(trans) \
         _TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B)
 
-#define _TRANS_HTOTAL_B          0xe1000
-#define _TRANS_HBLANK_B          0xe1004
-#define _TRANS_HSYNC_B           0xe1008
-#define _TRANS_VTOTAL_B          0xe100c
-#define _TRANS_VBLANK_B          0xe1010
-#define _TRANS_VSYNC_B           0xe1014
-#define _TRANS_VSYNCSHIFT_B     0xe1028
-
-#define TRANS_HTOTAL(pipe) _PIPE(pipe, _TRANS_HTOTAL_A, _TRANS_HTOTAL_B)
-#define TRANS_HBLANK(pipe) _PIPE(pipe, _TRANS_HBLANK_A, _TRANS_HBLANK_B)
-#define TRANS_HSYNC(pipe) _PIPE(pipe, _TRANS_HSYNC_A, _TRANS_HSYNC_B)
-#define TRANS_VTOTAL(pipe) _PIPE(pipe, _TRANS_VTOTAL_A, _TRANS_VTOTAL_B)
-#define TRANS_VBLANK(pipe) _PIPE(pipe, _TRANS_VBLANK_A, _TRANS_VBLANK_B)
-#define TRANS_VSYNC(pipe) _PIPE(pipe, _TRANS_VSYNC_A, _TRANS_VSYNC_B)
-#define TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _TRANS_VSYNCSHIFT_A, \
-                                    _TRANS_VSYNCSHIFT_B)
-
-#define _TRANSB_DATA_M1          0xe1030
-#define _TRANSB_DATA_N1          0xe1034
-#define _TRANSB_DATA_M2          0xe1038
-#define _TRANSB_DATA_N2          0xe103c
-#define _TRANSB_DP_LINK_M1       0xe1040
-#define _TRANSB_DP_LINK_N1       0xe1044
-#define _TRANSB_DP_LINK_M2       0xe1048
-#define _TRANSB_DP_LINK_N2       0xe104c
-
-#define TRANSDATA_M1(pipe) _PIPE(pipe, _TRANSA_DATA_M1, _TRANSB_DATA_M1)
-#define TRANSDATA_N1(pipe) _PIPE(pipe, _TRANSA_DATA_N1, _TRANSB_DATA_N1)
-#define TRANSDATA_M2(pipe) _PIPE(pipe, _TRANSA_DATA_M2, _TRANSB_DATA_M2)
-#define TRANSDATA_N2(pipe) _PIPE(pipe, _TRANSA_DATA_N2, _TRANSB_DATA_N2)
-#define TRANSDPLINK_M1(pipe) _PIPE(pipe, _TRANSA_DP_LINK_M1, _TRANSB_DP_LINK_M1)
-#define TRANSDPLINK_N1(pipe) _PIPE(pipe, _TRANSA_DP_LINK_N1, _TRANSB_DP_LINK_N1)
-#define TRANSDPLINK_M2(pipe) _PIPE(pipe, _TRANSA_DP_LINK_M2, _TRANSB_DP_LINK_M2)
-#define TRANSDPLINK_N2(pipe) _PIPE(pipe, _TRANSA_DP_LINK_N2, _TRANSB_DP_LINK_N2)
-
-#define _TRANSACONF              0xf0008
-#define _TRANSBCONF              0xf1008
-#define TRANSCONF(plane) _PIPE(plane, _TRANSACONF, _TRANSBCONF)
+#define _PCH_TRANS_HTOTAL_B          0xe1000
+#define _PCH_TRANS_HBLANK_B          0xe1004
+#define _PCH_TRANS_HSYNC_B           0xe1008
+#define _PCH_TRANS_VTOTAL_B          0xe100c
+#define _PCH_TRANS_VBLANK_B          0xe1010
+#define _PCH_TRANS_VSYNC_B           0xe1014
+#define _PCH_TRANS_VSYNCSHIFT_B         0xe1028
+
+#define PCH_TRANS_HTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_HTOTAL_A, _PCH_TRANS_HTOTAL_B)
+#define PCH_TRANS_HBLANK(pipe) _PIPE(pipe, _PCH_TRANS_HBLANK_A, _PCH_TRANS_HBLANK_B)
+#define PCH_TRANS_HSYNC(pipe) _PIPE(pipe, _PCH_TRANS_HSYNC_A, _PCH_TRANS_HSYNC_B)
+#define PCH_TRANS_VTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_VTOTAL_A, _PCH_TRANS_VTOTAL_B)
+#define PCH_TRANS_VBLANK(pipe) _PIPE(pipe, _PCH_TRANS_VBLANK_A, _PCH_TRANS_VBLANK_B)
+#define PCH_TRANS_VSYNC(pipe) _PIPE(pipe, _PCH_TRANS_VSYNC_A, _PCH_TRANS_VSYNC_B)
+#define PCH_TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _PCH_TRANS_VSYNCSHIFT_A, \
+                                        _PCH_TRANS_VSYNCSHIFT_B)
+
+#define _PCH_TRANSB_DATA_M1    0xe1030
+#define _PCH_TRANSB_DATA_N1    0xe1034
+#define _PCH_TRANSB_DATA_M2    0xe1038
+#define _PCH_TRANSB_DATA_N2    0xe103c
+#define _PCH_TRANSB_LINK_M1    0xe1040
+#define _PCH_TRANSB_LINK_N1    0xe1044
+#define _PCH_TRANSB_LINK_M2    0xe1048
+#define _PCH_TRANSB_LINK_N2    0xe104c
+
+#define PCH_TRANS_DATA_M1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M1, _PCH_TRANSB_DATA_M1)
+#define PCH_TRANS_DATA_N1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N1, _PCH_TRANSB_DATA_N1)
+#define PCH_TRANS_DATA_M2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M2, _PCH_TRANSB_DATA_M2)
+#define PCH_TRANS_DATA_N2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N2, _PCH_TRANSB_DATA_N2)
+#define PCH_TRANS_LINK_M1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M1, _PCH_TRANSB_LINK_M1)
+#define PCH_TRANS_LINK_N1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N1, _PCH_TRANSB_LINK_N1)
+#define PCH_TRANS_LINK_M2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M2, _PCH_TRANSB_LINK_M2)
+#define PCH_TRANS_LINK_N2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N2, _PCH_TRANSB_LINK_N2)
+
+#define _PCH_TRANSACONF              0xf0008
+#define _PCH_TRANSBCONF              0xf1008
+#define PCH_TRANSCONF(pipe) _PIPE(pipe, _PCH_TRANSACONF, _PCH_TRANSBCONF)
+#define LPT_TRANSCONF          _PCH_TRANSACONF /* lpt has only one transcoder */
 #define  TRANS_DISABLE          (0<<31)
 #define  TRANS_ENABLE           (1<<31)
 #define  TRANS_STATE_MASK       (1<<30)
 #define  FDI_LINK_TRAIN_600MV_3_5DB_SNB_B      (0x39<<22)
 #define  FDI_LINK_TRAIN_800MV_0DB_SNB_B                (0x38<<22)
 #define  FDI_LINK_TRAIN_VOL_EMP_MASK           (0x3f<<22)
-#define  FDI_DP_PORT_WIDTH_X1           (0<<19)
-#define  FDI_DP_PORT_WIDTH_X2           (1<<19)
-#define  FDI_DP_PORT_WIDTH_X3           (2<<19)
-#define  FDI_DP_PORT_WIDTH_X4           (3<<19)
+#define  FDI_DP_PORT_WIDTH_SHIFT               19
+#define  FDI_DP_PORT_WIDTH_MASK                        (7 << FDI_DP_PORT_WIDTH_SHIFT)
+#define  FDI_DP_PORT_WIDTH(width)           (((width) - 1) << FDI_DP_PORT_WIDTH_SHIFT)
 #define  FDI_TX_ENHANCE_FRAME_ENABLE    (1<<18)
 /* Ironlake: hardwired to 1 */
 #define  FDI_TX_PLL_ENABLE              (1<<14)
 /* train, dp width same as FDI_TX */
 #define  FDI_FS_ERRC_ENABLE            (1<<27)
 #define  FDI_FE_ERRC_ENABLE            (1<<26)
-#define  FDI_DP_PORT_WIDTH_X8           (7<<19)
 #define  FDI_RX_POLARITY_REVERSED_LPT  (1<<16)
 #define  FDI_8BPC                       (0<<16)
 #define  FDI_10BPC                      (1<<16)
 #define  FDI_LINK_TRAIN_PATTERN_IDLE_CPT       (2<<8)
 #define  FDI_LINK_TRAIN_NORMAL_CPT             (3<<8)
 #define  FDI_LINK_TRAIN_PATTERN_MASK_CPT       (3<<8)
-/* LPT */
-#define  FDI_PORT_WIDTH_2X_LPT                 (1<<19)
-#define  FDI_PORT_WIDTH_1X_LPT                 (0<<19)
 
 #define _FDI_RXA_MISC                  0xf0010
 #define _FDI_RXB_MISC                  0xf1010
 #define EDP_LINK_TRAIN_600MV_0DB_IVB           (0x30 <<22)
 #define EDP_LINK_TRAIN_600MV_3_5DB_IVB         (0x36 <<22)
 #define EDP_LINK_TRAIN_800MV_0DB_IVB           (0x38 <<22)
-#define EDP_LINK_TRAIN_800MV_3_5DB_IVB         (0x33 <<22)
+#define EDP_LINK_TRAIN_800MV_3_5DB_IVB         (0x3e <<22)
 
 /* legacy values */
 #define EDP_LINK_TRAIN_500MV_0DB_IVB           (0x00 <<22)
 #define   GEN6_RC_CTL_RC6_ENABLE               (1<<18)
 #define   GEN6_RC_CTL_RC1e_ENABLE              (1<<20)
 #define   GEN6_RC_CTL_RC7_ENABLE               (1<<22)
+#define   GEN7_RC_CTL_TO_MODE                  (1<<28)
 #define   GEN6_RC_CTL_EI_MODE(x)               ((x)<<27)
 #define   GEN6_RC_CTL_HW_ENABLE                        (1<<31)
 #define GEN6_RP_DOWN_TIMEOUT                   0xA010
 #define  GEN6_PM_RP_DOWN_THRESHOLD             (1<<4)
 #define  GEN6_PM_RP_UP_EI_EXPIRED              (1<<2)
 #define  GEN6_PM_RP_DOWN_EI_EXPIRED            (1<<1)
-#define  GEN6_PM_DEFERRED_EVENTS               (GEN6_PM_RP_UP_THRESHOLD | \
+#define  GEN6_PM_RPS_EVENTS                    (GEN6_PM_RP_UP_THRESHOLD | \
                                                 GEN6_PM_RP_DOWN_THRESHOLD | \
                                                 GEN6_PM_RP_DOWN_TIMEOUT)
 
 #define   GEN6_PCODE_FREQ_IA_RATIO_SHIFT       8
 #define   GEN6_PCODE_FREQ_RING_RATIO_SHIFT     16
 
-#define VLV_IOSF_DOORBELL_REQ                  0x182100
-#define   IOSF_DEVFN_SHIFT                     24
-#define   IOSF_OPCODE_SHIFT                    16
-#define   IOSF_PORT_SHIFT                      8
-#define   IOSF_BYTE_ENABLES_SHIFT              4
-#define   IOSF_BAR_SHIFT                       1
-#define   IOSF_SB_BUSY                         (1<<0)
-#define   IOSF_PORT_PUNIT                      0x4
-#define VLV_IOSF_DATA                          0x182104
-#define VLV_IOSF_ADDR                          0x182108
-
-#define PUNIT_OPCODE_REG_READ                  6
-#define PUNIT_OPCODE_REG_WRITE                 7
-
 #define GEN6_GT_CORE_STATUS            0x138060
 #define   GEN6_CORE_CPD_STATE_MASK     (7<<4)
 #define   GEN6_RCn_MASK                        7
 #define  TRANS_DDI_EDP_INPUT_B_ONOFF   (5<<12)
 #define  TRANS_DDI_EDP_INPUT_C_ONOFF   (6<<12)
 #define  TRANS_DDI_BFI_ENABLE          (1<<4)
-#define  TRANS_DDI_PORT_WIDTH_X1       (0<<1)
-#define  TRANS_DDI_PORT_WIDTH_X2       (1<<1)
-#define  TRANS_DDI_PORT_WIDTH_X4       (3<<1)
 
 /* DisplayPort Transport Control */
 #define DP_TP_CTL_A                    0x64040
 #define  DDI_BUF_PORT_REVERSAL                 (1<<16)
 #define  DDI_BUF_IS_IDLE                       (1<<7)
 #define  DDI_A_4_LANES                         (1<<4)
-#define  DDI_PORT_WIDTH_X1                     (0<<1)
-#define  DDI_PORT_WIDTH_X2                     (1<<1)
-#define  DDI_PORT_WIDTH_X4                     (3<<1)
+#define  DDI_PORT_WIDTH(width)                 (((width) - 1) << 1)
 #define  DDI_INIT_DISPLAY_DETECTED             (1<<0)
 
 /* DDI Buffer Translations */
 #define  SFUSE_STRAP_DDIC_DETECTED     (1<<1)
 #define  SFUSE_STRAP_DDID_DETECTED     (1<<0)
 
+#define WM_MISC                                0x45260
+#define  WM_MISC_DATA_PARTITION_5_6    (1 << 0)
+
 #define WM_DBG                         0x45280
 #define  WM_DBG_DISALLOW_MULTIPLE_LP   (1<<0)
 #define  WM_DBG_DISALLOW_MAXFIFO       (1<<1)
 #define _PIPE_A_CSC_COEFF_RV_GV        0x49020
 #define _PIPE_A_CSC_COEFF_BV   0x49024
 #define _PIPE_A_CSC_MODE       0x49028
+#define   CSC_BLACK_SCREEN_OFFSET      (1 << 2)
+#define   CSC_POSITION_BEFORE_GAMMA    (1 << 1)
+#define   CSC_MODE_YUV_TO_RGB          (1 << 0)
 #define _PIPE_A_CSC_PREOFF_HI  0x49030
 #define _PIPE_A_CSC_PREOFF_ME  0x49034
 #define _PIPE_A_CSC_PREOFF_LO  0x49038
 #define _PIPE_B_CSC_POSTOFF_ME 0x49144
 #define _PIPE_B_CSC_POSTOFF_LO 0x49148
 
-#define CSC_BLACK_SCREEN_OFFSET (1 << 2)
-#define CSC_POSITION_BEFORE_GAMMA (1 << 1)
-#define CSC_MODE_YUV_TO_RGB (1 << 0)
-
 #define PIPE_CSC_COEFF_RY_GY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY)
 #define PIPE_CSC_COEFF_BY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY)
 #define PIPE_CSC_COEFF_RU_GU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU)
index 369b3d8..ed42361 100644 (file)
@@ -202,6 +202,8 @@ static void i915_save_display(struct drm_device *dev)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_save_display_reg(dev);
 
+       spin_lock(&dev_priv->backlight.lock);
+
        /* LVDS state */
        if (HAS_PCH_SPLIT(dev)) {
                dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL);
@@ -222,6 +224,8 @@ static void i915_save_display(struct drm_device *dev)
                        dev_priv->regfile.saveLVDS = I915_READ(LVDS);
        }
 
+       spin_unlock(&dev_priv->backlight.lock);
+
        if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev))
                dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
 
@@ -265,6 +269,8 @@ static void i915_restore_display(struct drm_device *dev)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_restore_display_reg(dev);
 
+       spin_lock(&dev_priv->backlight.lock);
+
        /* LVDS state */
        if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
                I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
@@ -304,6 +310,8 @@ static void i915_restore_display(struct drm_device *dev)
                I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
        }
 
+       spin_unlock(&dev_priv->backlight.lock);
+
        /* only restore FBC info on the platform that supports FBC*/
        intel_disable_fbc(dev);
        if (I915_HAS_FBC(dev)) {
index 1541324..9622bdb 100644 (file)
 #ifndef _I915_TRACE_H_
 #define _I915_TRACE_H_
 
+#define trace_i915_flip_complete(a,b)
+#define trace_i915_flip_request(a,b)
+
 #define trace_i915_gem_evict(a,b,c,d)
 #define trace_i915_gem_evict_everything(a)
 
+#define trace_i915_gem_object_bind(a, b)
 #define trace_i915_gem_object_change_domain(a,b,c)
 
 #define trace_i915_ring_wait_begin(a)
index 6c4ccff..51bb9b5 100644 (file)
@@ -41,7 +41,7 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum i915_pipe pipe)
                return false;
 
        if (HAS_PCH_SPLIT(dev))
-               dpll_reg = _PCH_DPLL(pipe);
+               dpll_reg = PCH_DPLL(pipe);
        else
                dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B;
 
@@ -148,13 +148,13 @@ void i915_save_display_reg(struct drm_device *dev)
                dev_priv->regfile.savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ);
                dev_priv->regfile.savePFA_WIN_POS = I915_READ(_PFA_WIN_POS);
 
-               dev_priv->regfile.saveTRANSACONF = I915_READ(_TRANSACONF);
-               dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A);
-               dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A);
-               dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A);
-               dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_TRANS_VTOTAL_A);
-               dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_TRANS_VBLANK_A);
-               dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_TRANS_VSYNC_A);
+               dev_priv->regfile.saveTRANSACONF = I915_READ(_PCH_TRANSACONF);
+               dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_PCH_TRANS_HTOTAL_A);
+               dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_PCH_TRANS_HBLANK_A);
+               dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_PCH_TRANS_HSYNC_A);
+               dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_PCH_TRANS_VTOTAL_A);
+               dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_PCH_TRANS_VBLANK_A);
+               dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_PCH_TRANS_VSYNC_A);
        }
 
        dev_priv->regfile.saveDSPACNTR = I915_READ(_DSPACNTR);
@@ -205,13 +205,13 @@ void i915_save_display_reg(struct drm_device *dev)
                dev_priv->regfile.savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ);
                dev_priv->regfile.savePFB_WIN_POS = I915_READ(_PFB_WIN_POS);
 
-               dev_priv->regfile.saveTRANSBCONF = I915_READ(_TRANSBCONF);
-               dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B);
-               dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B);
-               dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B);
-               dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_TRANS_VTOTAL_B);
-               dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_TRANS_VBLANK_B);
-               dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_TRANS_VSYNC_B);
+               dev_priv->regfile.saveTRANSBCONF = I915_READ(_PCH_TRANSBCONF);
+               dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_PCH_TRANS_HTOTAL_B);
+               dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_PCH_TRANS_HBLANK_B);
+               dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_PCH_TRANS_HSYNC_B);
+               dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_PCH_TRANS_VTOTAL_B);
+               dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_PCH_TRANS_VBLANK_B);
+               dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_PCH_TRANS_VSYNC_B);
        }
 
        dev_priv->regfile.saveDSPBCNTR = I915_READ(_DSPBCNTR);
@@ -259,14 +259,14 @@ void i915_save_display_reg(struct drm_device *dev)
                dev_priv->regfile.saveDP_B = I915_READ(DP_B);
                dev_priv->regfile.saveDP_C = I915_READ(DP_C);
                dev_priv->regfile.saveDP_D = I915_READ(DP_D);
-               dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M);
-               dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M);
-               dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N);
-               dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N);
-               dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M);
-               dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M);
-               dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N);
-               dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N);
+               dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_DATA_M_G4X);
+               dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_DATA_M_G4X);
+               dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_DATA_N_G4X);
+               dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_DATA_N_G4X);
+               dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_LINK_M_G4X);
+               dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_LINK_M_G4X);
+               dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_LINK_N_G4X);
+               dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_LINK_N_G4X);
        }
        /* FIXME: regfile.save TV & SDVO state */
 
@@ -282,14 +282,14 @@ void i915_restore_display_reg(struct drm_device *dev)
 
        /* Display port ratios (must be done before clock is set) */
        if (SUPPORTS_INTEGRATED_DP(dev)) {
-               I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M);
-               I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M);
-               I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N);
-               I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N);
-               I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M);
-               I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M);
-               I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N);
-               I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N);
+               I915_WRITE(_PIPEA_DATA_M_G4X, dev_priv->regfile.savePIPEA_GMCH_DATA_M);
+               I915_WRITE(_PIPEB_DATA_M_G4X, dev_priv->regfile.savePIPEB_GMCH_DATA_M);
+               I915_WRITE(_PIPEA_DATA_N_G4X, dev_priv->regfile.savePIPEA_GMCH_DATA_N);
+               I915_WRITE(_PIPEB_DATA_N_G4X, dev_priv->regfile.savePIPEB_GMCH_DATA_N);
+               I915_WRITE(_PIPEA_LINK_M_G4X, dev_priv->regfile.savePIPEA_DP_LINK_M);
+               I915_WRITE(_PIPEB_LINK_M_G4X, dev_priv->regfile.savePIPEB_DP_LINK_M);
+               I915_WRITE(_PIPEA_LINK_N_G4X, dev_priv->regfile.savePIPEA_DP_LINK_N);
+               I915_WRITE(_PIPEB_LINK_N_G4X, dev_priv->regfile.savePIPEB_DP_LINK_N);
        }
 
        /* Fences */
@@ -379,13 +379,13 @@ void i915_restore_display_reg(struct drm_device *dev)
                I915_WRITE(_PFA_WIN_SZ, dev_priv->regfile.savePFA_WIN_SZ);
                I915_WRITE(_PFA_WIN_POS, dev_priv->regfile.savePFA_WIN_POS);
 
-               I915_WRITE(_TRANSACONF, dev_priv->regfile.saveTRANSACONF);
-               I915_WRITE(_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A);
-               I915_WRITE(_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A);
-               I915_WRITE(_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A);
-               I915_WRITE(_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A);
-               I915_WRITE(_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A);
-               I915_WRITE(_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A);
+               I915_WRITE(_PCH_TRANSACONF, dev_priv->regfile.saveTRANSACONF);
+               I915_WRITE(_PCH_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A);
+               I915_WRITE(_PCH_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A);
+               I915_WRITE(_PCH_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A);
+               I915_WRITE(_PCH_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A);
+               I915_WRITE(_PCH_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A);
+               I915_WRITE(_PCH_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A);
        }
 
        /* Restore plane info */
@@ -448,13 +448,13 @@ void i915_restore_display_reg(struct drm_device *dev)
                I915_WRITE(_PFB_WIN_SZ, dev_priv->regfile.savePFB_WIN_SZ);
                I915_WRITE(_PFB_WIN_POS, dev_priv->regfile.savePFB_WIN_POS);
 
-               I915_WRITE(_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF);
-               I915_WRITE(_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B);
-               I915_WRITE(_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B);
-               I915_WRITE(_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B);
-               I915_WRITE(_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B);
-               I915_WRITE(_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B);
-               I915_WRITE(_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B);
+               I915_WRITE(_PCH_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF);
+               I915_WRITE(_PCH_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B);
+               I915_WRITE(_PCH_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B);
+               I915_WRITE(_PCH_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B);
+               I915_WRITE(_PCH_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B);
+               I915_WRITE(_PCH_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B);
+               I915_WRITE(_PCH_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B);
        }
 
        /* Restore plane info */
diff --git a/sys/dev/drm/i915/intel_acpi.c b/sys/dev/drm/i915/intel_acpi.c
new file mode 100644 (file)
index 0000000..8210c75
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Intel ACPI functions
+ *
+ * _DSM related code stolen from nouveau_acpi.c.
+ */
+#include <linux/pci.h>
+
+#include <drm/drmP.h>
+#include "i915_drv.h"
+
+#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
+
+#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */
+#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
+
+#if 0
+static struct intel_dsm_priv {
+       acpi_handle dhandle;
+} intel_dsm_priv;
+
+static const u8 intel_dsm_guid[] = {
+       0xd3, 0x73, 0xd8, 0x7e,
+       0xd0, 0xc2,
+       0x4f, 0x4e,
+       0xa8, 0x54,
+       0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
+};
+
+static int intel_dsm(acpi_handle handle, int func, int arg)
+{
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_object_list input;
+       union acpi_object params[4];
+       union acpi_object *obj;
+       u32 result;
+       int ret = 0;
+
+       input.count = 4;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_BUFFER;
+       params[0].buffer.length = sizeof(intel_dsm_guid);
+       params[0].buffer.pointer = (char *)intel_dsm_guid;
+       params[1].type = ACPI_TYPE_INTEGER;
+       params[1].integer.value = INTEL_DSM_REVISION_ID;
+       params[2].type = ACPI_TYPE_INTEGER;
+       params[2].integer.value = func;
+       params[3].type = ACPI_TYPE_INTEGER;
+       params[3].integer.value = arg;
+
+       ret = acpi_evaluate_object(handle, "_DSM", &input, &output);
+       if (ret) {
+               DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
+               return ret;
+       }
+
+       obj = (union acpi_object *)output.pointer;
+
+       result = 0;
+       switch (obj->type) {
+       case ACPI_TYPE_INTEGER:
+               result = obj->integer.value;
+               break;
+
+       case ACPI_TYPE_BUFFER:
+               if (obj->buffer.length == 4) {
+                       result = (obj->buffer.pointer[0] |
+                               (obj->buffer.pointer[1] <<  8) |
+                               (obj->buffer.pointer[2] << 16) |
+                               (obj->buffer.pointer[3] << 24));
+                       break;
+               }
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       if (result == 0x80000002)
+               ret = -ENODEV;
+
+       kfree(output.pointer);
+       return ret;
+}
+
+static char *intel_dsm_port_name(u8 id)
+{
+       switch (id) {
+       case 0:
+               return "Reserved";
+       case 1:
+               return "Analog VGA";
+       case 2:
+               return "LVDS";
+       case 3:
+               return "Reserved";
+       case 4:
+               return "HDMI/DVI_B";
+       case 5:
+               return "HDMI/DVI_C";
+       case 6:
+               return "HDMI/DVI_D";
+       case 7:
+               return "DisplayPort_A";
+       case 8:
+               return "DisplayPort_B";
+       case 9:
+               return "DisplayPort_C";
+       case 0xa:
+               return "DisplayPort_D";
+       case 0xb:
+       case 0xc:
+       case 0xd:
+               return "Reserved";
+       case 0xe:
+               return "WiDi";
+       default:
+               return "bad type";
+       }
+}
+
+static char *intel_dsm_mux_type(u8 type)
+{
+       switch (type) {
+       case 0:
+               return "unknown";
+       case 1:
+               return "No MUX, iGPU only";
+       case 2:
+               return "No MUX, dGPU only";
+       case 3:
+               return "MUXed between iGPU and dGPU";
+       default:
+               return "bad type";
+       }
+}
+
+static void intel_dsm_platform_mux_info(void)
+{
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_object_list input;
+       union acpi_object params[4];
+       union acpi_object *pkg;
+       int i, ret;
+
+       input.count = 4;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_BUFFER;
+       params[0].buffer.length = sizeof(intel_dsm_guid);
+       params[0].buffer.pointer = (char *)intel_dsm_guid;
+       params[1].type = ACPI_TYPE_INTEGER;
+       params[1].integer.value = INTEL_DSM_REVISION_ID;
+       params[2].type = ACPI_TYPE_INTEGER;
+       params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO;
+       params[3].type = ACPI_TYPE_INTEGER;
+       params[3].integer.value = 0;
+
+       ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input,
+                                  &output);
+       if (ret) {
+               DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
+               goto out;
+       }
+
+       pkg = (union acpi_object *)output.pointer;
+
+       if (pkg->type == ACPI_TYPE_PACKAGE) {
+               union acpi_object *connector_count = &pkg->package.elements[0];
+               DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
+                         (unsigned long long)connector_count->integer.value);
+               for (i = 1; i < pkg->package.count; i++) {
+                       union acpi_object *obj = &pkg->package.elements[i];
+                       union acpi_object *connector_id =
+                               &obj->package.elements[0];
+                       union acpi_object *info = &obj->package.elements[1];
+                       DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
+                                 (unsigned long long)connector_id->integer.value);
+                       DRM_DEBUG_DRIVER("  port id: %s\n",
+                              intel_dsm_port_name(info->buffer.pointer[0]));
+                       DRM_DEBUG_DRIVER("  display mux info: %s\n",
+                              intel_dsm_mux_type(info->buffer.pointer[1]));
+                       DRM_DEBUG_DRIVER("  aux/dc mux info: %s\n",
+                              intel_dsm_mux_type(info->buffer.pointer[2]));
+                       DRM_DEBUG_DRIVER("  hpd mux info: %s\n",
+                              intel_dsm_mux_type(info->buffer.pointer[3]));
+               }
+       }
+
+out:
+       kfree(output.pointer);
+}
+
+static bool intel_dsm_pci_probe(struct pci_dev *pdev)
+{
+       acpi_handle dhandle, intel_handle;
+       acpi_status status;
+       int ret;
+
+       dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
+       if (!dhandle)
+               return false;
+
+       status = acpi_get_handle(dhandle, "_DSM", &intel_handle);
+       if (ACPI_FAILURE(status)) {
+               DRM_DEBUG_KMS("no _DSM method for intel device\n");
+               return false;
+       }
+
+       ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0);
+       if (ret < 0) {
+               DRM_DEBUG_KMS("failed to get supported _DSM functions\n");
+               return false;
+       }
+
+       intel_dsm_priv.dhandle = dhandle;
+
+       intel_dsm_platform_mux_info();
+       return true;
+}
+
+static bool intel_dsm_detect(void)
+{
+       char acpi_method_name[255] = { 0 };
+       struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
+       struct pci_dev *pdev = NULL;
+       bool has_dsm = false;
+       int vga_count = 0;
+
+       while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
+               vga_count++;
+               has_dsm |= intel_dsm_pci_probe(pdev);
+       }
+
+       if (vga_count == 2 && has_dsm) {
+               acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
+               DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",
+                                acpi_method_name);
+               return true;
+       }
+
+       return false;
+}
+
+void intel_register_dsm_handler(void)
+{
+       if (!intel_dsm_detect())
+               return;
+}
+#endif
+
+void intel_unregister_dsm_handler(void)
+{
+}
index 2fd657c..58d1032 100644 (file)
@@ -211,7 +211,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        if (!lvds_options)
                return;
 
-       dev_priv->lvds_dither = lvds_options->pixel_dither;
+       dev_priv->vbt.lvds_dither = lvds_options->pixel_dither;
        if (lvds_options->panel_type == 0xff)
                return;
 
@@ -225,7 +225,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        if (!lvds_lfp_data_ptrs)
                return;
 
-       dev_priv->lvds_vbt = 1;
+       dev_priv->vbt.lvds_vbt = 1;
 
        panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
                                               lvds_lfp_data_ptrs,
@@ -237,7 +237,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
 
        fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing);
 
-       dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode;
+       dev_priv->vbt.lfp_lvds_vbt_mode = panel_fixed_mode;
 
        DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n");
        drm_mode_debug_printmodeline(panel_fixed_mode);
@@ -273,9 +273,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
                /* check the resolution, just to be sure */
                if (fp_timing->x_res == panel_fixed_mode->hdisplay &&
                    fp_timing->y_res == panel_fixed_mode->vdisplay) {
-                       dev_priv->bios_lvds_val = fp_timing->lvds_reg_val;
+                       dev_priv->vbt.bios_lvds_val = fp_timing->lvds_reg_val;
                        DRM_DEBUG_KMS("VBT initial LVDS value %x\n",
-                                     dev_priv->bios_lvds_val);
+                                     dev_priv->vbt.bios_lvds_val);
                }
        }
 }
@@ -315,7 +315,7 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
 
        fill_detail_timing_data(panel_fixed_mode, dvo_timing + index);
 
-       dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode;
+       dev_priv->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode;
 
        DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n");
        drm_mode_debug_printmodeline(panel_fixed_mode);
@@ -344,20 +344,20 @@ parse_general_features(struct drm_i915_private *dev_priv,
 
        general = find_section(bdb, BDB_GENERAL_FEATURES);
        if (general) {
-               dev_priv->int_tv_support = general->int_tv_support;
-               dev_priv->int_crt_support = general->int_crt_support;
-               dev_priv->lvds_use_ssc = general->enable_ssc;
-               dev_priv->lvds_ssc_freq =
+               dev_priv->vbt.int_tv_support = general->int_tv_support;
+               dev_priv->vbt.int_crt_support = general->int_crt_support;
+               dev_priv->vbt.lvds_use_ssc = general->enable_ssc;
+               dev_priv->vbt.lvds_ssc_freq =
                        intel_bios_ssc_frequency(dev, general->ssc_freq);
-               dev_priv->display_clock_mode = general->display_clock_mode;
-               dev_priv->fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted;
+               dev_priv->vbt.display_clock_mode = general->display_clock_mode;
+               dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted;
                DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n",
-                             dev_priv->int_tv_support,
-                             dev_priv->int_crt_support,
-                             dev_priv->lvds_use_ssc,
-                             dev_priv->lvds_ssc_freq,
-                             dev_priv->display_clock_mode,
-                             dev_priv->fdi_rx_polarity_inverted);
+                             dev_priv->vbt.int_tv_support,
+                             dev_priv->vbt.int_crt_support,
+                             dev_priv->vbt.lvds_use_ssc,
+                             dev_priv->vbt.lvds_ssc_freq,
+                             dev_priv->vbt.display_clock_mode,
+                             dev_priv->vbt.fdi_rx_polarity_inverted);
        }
 }
 
@@ -374,7 +374,7 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
                        int bus_pin = general->crt_ddc_gmbus_pin;
                        DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
                        if (intel_gmbus_is_port_valid(bus_pin))
-                               dev_priv->crt_ddc_pin = bus_pin;
+                               dev_priv->vbt.crt_ddc_pin = bus_pin;
                } else {
                        DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
    &n