Merge branch 'drm-intel-fixes' into drm-intel-next
authorChris Wilson <chris@chris-wilson.co.uk>
Mon, 15 Nov 2010 06:49:30 +0000 (06:49 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Mon, 15 Nov 2010 06:49:30 +0000 (06:49 +0000)
Conflicts:
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/intel_ringbuffer.c

21 files changed:
drivers/char/agp/intel-agp.h
drivers/char/agp/intel-gtt.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_evict.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_trace.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
include/drm/drmP.h
include/drm/drm_mm.h
include/drm/i915_drm.h

index 90539df..010e3de 100644 (file)
@@ -75,6 +75,8 @@
 #define I810_GMS_DISABLE       0x00000000
 #define I810_PGETBL_CTL                0x2020
 #define I810_PGETBL_ENABLED    0x00000001
+/* Note: PGETBL_CTL2 has a different offset on G33. */
+#define I965_PGETBL_CTL2       0x20c4
 #define I965_PGETBL_SIZE_MASK  0x0000000e
 #define I965_PGETBL_SIZE_512KB (0 << 1)
 #define I965_PGETBL_SIZE_256KB (1 << 1)
 #define I965_PGETBL_SIZE_1MB   (3 << 1)
 #define I965_PGETBL_SIZE_2MB   (4 << 1)
 #define I965_PGETBL_SIZE_1_5MB (5 << 1)
-#define G33_PGETBL_SIZE_MASK    (3 << 8)
-#define G33_PGETBL_SIZE_1M      (1 << 8)
-#define G33_PGETBL_SIZE_2M      (2 << 8)
+#define G33_GMCH_SIZE_MASK     (3 << 8)
+#define G33_GMCH_SIZE_1M       (1 << 8)
+#define G33_GMCH_SIZE_2M       (2 << 8)
+#define G4x_GMCH_SIZE_MASK     (0xf << 8)
+#define G4x_GMCH_SIZE_1M       (0x1 << 8)
+#define G4x_GMCH_SIZE_2M       (0x3 << 8)
+#define G4x_GMCH_SIZE_VT_1M    (0x9 << 8)
+#define G4x_GMCH_SIZE_VT_1_5M  (0xa << 8)
+#define G4x_GMCH_SIZE_VT_2M    (0xc << 8)
 
 #define I810_DRAM_CTL          0x3000
 #define I810_DRAM_ROW_0                0x00000001
index 9272c38..fc1637c 100644 (file)
@@ -73,6 +73,7 @@ struct intel_gtt_driver {
        unsigned int is_g33 : 1;
        unsigned int is_pineview : 1;
        unsigned int is_ironlake : 1;
+       unsigned int has_pgtbl_enable : 1;
        unsigned int dma_mask_size : 8;
        /* Chipset specific GTT setup */
        int (*setup)(void);
@@ -95,7 +96,7 @@ static struct _intel_private {
        u8 __iomem *registers;
        phys_addr_t gtt_bus_addr;
        phys_addr_t gma_bus_addr;
-       phys_addr_t pte_bus_addr;
+       u32 PGETBL_save;
        u32 __iomem *gtt;               /* I915G */
        int num_dcache_entries;
        union {
@@ -113,6 +114,7 @@ static struct _intel_private {
 #define IS_G33         intel_private.driver->is_g33
 #define IS_PINEVIEW    intel_private.driver->is_pineview
 #define IS_IRONLAKE    intel_private.driver->is_ironlake
+#define HAS_PGTBL_EN   intel_private.driver->has_pgtbl_enable
 
 static void intel_agp_free_sglist(struct agp_memory *mem)
 {
@@ -642,41 +644,85 @@ static unsigned int intel_gtt_stolen_entries(void)
        return stolen_entries;
 }
 
-static unsigned int intel_gtt_total_entries(void)
+static void i965_adjust_pgetbl_size(unsigned int size_flag)
+{
+       u32 pgetbl_ctl, pgetbl_ctl2;
+
+       /* ensure that ppgtt is disabled */
+       pgetbl_ctl2 = readl(intel_private.registers+I965_PGETBL_CTL2);
+       pgetbl_ctl2 &= ~I810_PGETBL_ENABLED;
+       writel(pgetbl_ctl2, intel_private.registers+I965_PGETBL_CTL2);
+
+       /* write the new ggtt size */
+       pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+       pgetbl_ctl &= ~I965_PGETBL_SIZE_MASK;
+       pgetbl_ctl |= size_flag;
+       writel(pgetbl_ctl, intel_private.registers+I810_PGETBL_CTL);
+}
+
+static unsigned int i965_gtt_total_entries(void)
 {
        int size;
+       u32 pgetbl_ctl;
+       u16 gmch_ctl;
 
-       if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) {
-               u32 pgetbl_ctl;
-               pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+       pci_read_config_word(intel_private.bridge_dev,
+                            I830_GMCH_CTRL, &gmch_ctl);
 
-               switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
-               case I965_PGETBL_SIZE_128KB:
-                       size = KB(128);
-                       break;
-               case I965_PGETBL_SIZE_256KB:
-                       size = KB(256);
-                       break;
-               case I965_PGETBL_SIZE_512KB:
-                       size = KB(512);
+       if (INTEL_GTT_GEN == 5) {
+               switch (gmch_ctl & G4x_GMCH_SIZE_MASK) {
+               case G4x_GMCH_SIZE_1M:
+               case G4x_GMCH_SIZE_VT_1M:
+                       i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1MB);
                        break;
-               case I965_PGETBL_SIZE_1MB:
-                       size = KB(1024);
+               case G4x_GMCH_SIZE_VT_1_5M:
+                       i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1_5MB);
                        break;
-               case I965_PGETBL_SIZE_2MB:
-                       size = KB(2048);
+               case G4x_GMCH_SIZE_2M:
+               case G4x_GMCH_SIZE_VT_2M:
+                       i965_adjust_pgetbl_size(I965_PGETBL_SIZE_2MB);
                        break;
-               case I965_PGETBL_SIZE_1_5MB:
-                       size = KB(1024 + 512);
-                       break;
-               default:
-                       dev_info(&intel_private.pcidev->dev,
-                                "unknown page table size, assuming 512KB\n");
-                       size = KB(512);
                }
+       }
 
-               return size/4;
-       } else if (INTEL_GTT_GEN == 6) {
+       pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+
+       switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
+       case I965_PGETBL_SIZE_128KB:
+               size = KB(128);
+               break;
+       case I965_PGETBL_SIZE_256KB:
+               size = KB(256);
+               break;
+       case I965_PGETBL_SIZE_512KB:
+               size = KB(512);
+               break;
+       /* GTT pagetable sizes bigger than 512KB are not possible on G33! */
+       case I965_PGETBL_SIZE_1MB:
+               size = KB(1024);
+               break;
+       case I965_PGETBL_SIZE_2MB:
+               size = KB(2048);
+               break;
+       case I965_PGETBL_SIZE_1_5MB:
+               size = KB(1024 + 512);
+               break;
+       default:
+               dev_info(&intel_private.pcidev->dev,
+                        "unknown page table size, assuming 512KB\n");
+               size = KB(512);
+       }
+
+       return size/4;
+}
+
+static unsigned int intel_gtt_total_entries(void)
+{
+       int size;
+
+       if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5)
+               return i965_gtt_total_entries();
+       else if (INTEL_GTT_GEN == 6) {
                u16 snb_gmch_ctl;
 
                pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
@@ -755,6 +801,14 @@ static int intel_gtt_init(void)
        intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries();
        intel_private.base.gtt_total_entries = intel_gtt_total_entries();
 
+       /* save the PGETBL reg for resume */
+       intel_private.PGETBL_save =
+               readl(intel_private.registers+I810_PGETBL_CTL)
+                       & ~I810_PGETBL_ENABLED;
+       /* we only ever restore the register when enabling the PGTBL... */
+       if (HAS_PGTBL_EN)
+               intel_private.PGETBL_save |= I810_PGETBL_ENABLED;
+
        dev_info(&intel_private.bridge_dev->dev,
                        "detected gtt size: %dK total, %dK mappable\n",
                        intel_private.base.gtt_total_entries * 4,
@@ -873,10 +927,10 @@ static void i830_write_entry(dma_addr_t addr, unsigned int entry,
        writel(addr | pte_flags, intel_private.gtt + entry);
 }
 
-static void intel_enable_gtt(void)
+static bool intel_enable_gtt(void)
 {
        u32 gma_addr;
-       u16 gmch_ctrl;
+       u8 __iomem *reg;
 
        if (INTEL_GTT_GEN == 2)
                pci_read_config_dword(intel_private.pcidev, I810_GMADDR,
@@ -887,13 +941,38 @@ static void intel_enable_gtt(void)
 
        intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK);
 
-       pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl);
-       gmch_ctrl |= I830_GMCH_ENABLED;
-       pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl);
+       if (INTEL_GTT_GEN >= 6)
+           return true;
 
-       writel(intel_private.pte_bus_addr|I810_PGETBL_ENABLED,
-              intel_private.registers+I810_PGETBL_CTL);
-       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+       if (INTEL_GTT_GEN == 2) {
+               u16 gmch_ctrl;
+
+               pci_read_config_word(intel_private.bridge_dev,
+                                    I830_GMCH_CTRL, &gmch_ctrl);
+               gmch_ctrl |= I830_GMCH_ENABLED;
+               pci_write_config_word(intel_private.bridge_dev,
+                                     I830_GMCH_CTRL, gmch_ctrl);
+
+               pci_read_config_word(intel_private.bridge_dev,
+                                    I830_GMCH_CTRL, &gmch_ctrl);
+               if ((gmch_ctrl & I830_GMCH_ENABLED) == 0) {
+                       dev_err(&intel_private.pcidev->dev,
+                               "failed to enable the GTT: GMCH_CTRL=%x\n",
+                               gmch_ctrl);
+                       return false;
+               }
+       }
+
+       reg = intel_private.registers+I810_PGETBL_CTL;
+       writel(intel_private.PGETBL_save, reg);
+       if (HAS_PGTBL_EN && (readl(reg) & I810_PGETBL_ENABLED) == 0) {
+               dev_err(&intel_private.pcidev->dev,
+                       "failed to enable the GTT: PGETBL=%x [expected %x]\n",
+                       readl(reg), intel_private.PGETBL_save);
+               return false;
+       }
+
+       return true;
 }
 
 static int i830_setup(void)
@@ -908,8 +987,6 @@ static int i830_setup(void)
                return -ENOMEM;
 
        intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
-       intel_private.pte_bus_addr =
-               readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
 
        intel_i830_setup_flush();
 
@@ -934,7 +1011,8 @@ static int intel_fake_agp_configure(void)
 {
        int i;
 
-       intel_enable_gtt();
+       if (!intel_enable_gtt())
+           return -EIO;
 
        agp_bridge->gart_bus_addr = intel_private.gma_bus_addr;
 
@@ -1265,9 +1343,6 @@ static int i9xx_setup(void)
                intel_private.gtt_bus_addr = reg_addr + gtt_offset;
        }
 
-       intel_private.pte_bus_addr =
-               readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-
        intel_i9xx_setup_flush();
 
        return 0;
@@ -1328,6 +1403,7 @@ static const struct intel_gtt_driver i81x_gtt_driver = {
 };
 static const struct intel_gtt_driver i8xx_gtt_driver = {
        .gen = 2,
+       .has_pgtbl_enable = 1,
        .setup = i830_setup,
        .cleanup = i830_cleanup,
        .write_entry = i830_write_entry,
@@ -1337,6 +1413,7 @@ static const struct intel_gtt_driver i8xx_gtt_driver = {
 };
 static const struct intel_gtt_driver i915_gtt_driver = {
        .gen = 3,
+       .has_pgtbl_enable = 1,
        .setup = i9xx_setup,
        .cleanup = i9xx_cleanup,
        /* i945 is the last gpu to need phys mem (for overlay and cursors). */
@@ -1367,6 +1444,7 @@ static const struct intel_gtt_driver pineview_gtt_driver = {
 };
 static const struct intel_gtt_driver i965_gtt_driver = {
        .gen = 4,
+       .has_pgtbl_enable = 1,
        .setup = i9xx_setup,
        .cleanup = i9xx_cleanup,
        .write_entry = i965_write_entry,
index a6bfc30..c59515b 100644 (file)
@@ -392,9 +392,35 @@ void drm_mm_init_scan(struct drm_mm *mm, unsigned long size,
        mm->scanned_blocks = 0;
        mm->scan_hit_start = 0;
        mm->scan_hit_size = 0;
+       mm->scan_check_range = 0;
 }
 EXPORT_SYMBOL(drm_mm_init_scan);
 
+/**
+ * Initializa lru scanning.
+ *
+ * This simply sets up the scanning routines with the parameters for the desired
+ * hole. This version is for range-restricted scans.
+ *
+ * Warning: As long as the scan list is non-empty, no other operations than
+ * adding/removing nodes to/from the scan list are allowed.
+ */
+void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size,
+                                unsigned alignment,
+                                unsigned long start,
+                                unsigned long end)
+{
+       mm->scan_alignment = alignment;
+       mm->scan_size = size;
+       mm->scanned_blocks = 0;
+       mm->scan_hit_start = 0;
+       mm->scan_hit_size = 0;
+       mm->scan_start = start;
+       mm->scan_end = end;
+       mm->scan_check_range = 1;
+}
+EXPORT_SYMBOL(drm_mm_init_scan_with_range);
+
 /**
  * Add a node to the scan list that might be freed to make space for the desired
  * hole.
@@ -406,6 +432,8 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
        struct drm_mm *mm = node->mm;
        struct list_head *prev_free, *next_free;
        struct drm_mm_node *prev_node, *next_node;
+       unsigned long adj_start;
+       unsigned long adj_end;
 
        mm->scanned_blocks++;
 
@@ -452,7 +480,17 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
        node->free_stack.prev = prev_free;
        node->free_stack.next = next_free;
 
-       if (check_free_hole(node->start, node->start + node->size,
+       if (mm->scan_check_range) {
+               adj_start = node->start < mm->scan_start ?
+                       mm->scan_start : node->start;
+               adj_end = node->start + node->size > mm->scan_end ?
+                       mm->scan_end : node->start + node->size;
+       } else {
+               adj_start = node->start;
+               adj_end = node->start + node->size;
+       }
+
+       if (check_free_hole(adj_start , adj_end,
                            mm->scan_size, mm->scan_alignment)) {
                mm->scan_hit_start = node->start;
                mm->scan_hit_size = node->size;
index 1f4f3ce..4c8fae9 100644 (file)
@@ -32,6 +32,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include "intel_drv.h"
+#include "intel_ringbuffer.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
 
@@ -124,7 +125,10 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
        if (obj->fence_reg != I915_FENCE_REG_NONE)
                seq_printf(m, " (fence: %d)", obj->fence_reg);
        if (obj->gtt_space != NULL)
-               seq_printf(m, " (gtt_offset: %08x)", obj->gtt_offset);
+               seq_printf(m, " (gtt offset: %08x, size: %08x)",
+                          obj->gtt_offset, (unsigned int)obj->gtt_space->size);
+       if (obj->pin_mappable || obj->fault_mappable)
+               seq_printf(m, " (mappable)");
        if (obj->ring != NULL)
                seq_printf(m, " (%s)", obj->ring->name);
 }
@@ -201,6 +205,10 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
        seq_printf(m, "%zu object bytes\n", dev_priv->mm.object_memory);
        seq_printf(m, "%u pinned\n", dev_priv->mm.pin_count);
        seq_printf(m, "%zu pin bytes\n", dev_priv->mm.pin_memory);
+       seq_printf(m, "%u mappable objects in gtt\n", dev_priv->mm.gtt_mappable_count);
+       seq_printf(m, "%zu mappable gtt bytes\n", dev_priv->mm.gtt_mappable_memory);
+       seq_printf(m, "%zu mappable gtt used bytes\n", dev_priv->mm.mappable_gtt_used);
+       seq_printf(m, "%zu mappable gtt total\n", dev_priv->mm.mappable_gtt_total);
        seq_printf(m, "%u objects in gtt\n", dev_priv->mm.gtt_count);
        seq_printf(m, "%zu gtt bytes\n", dev_priv->mm.gtt_memory);
        seq_printf(m, "%zu gtt total\n", dev_priv->mm.gtt_total);
@@ -265,24 +273,67 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_request *gem_request;
-       int ret;
+       int ret, count;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
 
-       seq_printf(m, "Request:\n");
-       list_for_each_entry(gem_request, &dev_priv->render_ring.request_list,
-                       list) {
-               seq_printf(m, "    %d @ %d\n",
-                          gem_request->seqno,
-                          (int) (jiffies - gem_request->emitted_jiffies));
+       count = 0;
+       if (!list_empty(&dev_priv->render_ring.request_list)) {
+               seq_printf(m, "Render requests:\n");
+               list_for_each_entry(gem_request,
+                                   &dev_priv->render_ring.request_list,
+                                   list) {
+                       seq_printf(m, "    %d @ %d\n",
+                                  gem_request->seqno,
+                                  (int) (jiffies - gem_request->emitted_jiffies));
+               }
+               count++;
+       }
+       if (!list_empty(&dev_priv->bsd_ring.request_list)) {
+               seq_printf(m, "BSD requests:\n");
+               list_for_each_entry(gem_request,
+                                   &dev_priv->bsd_ring.request_list,
+                                   list) {
+                       seq_printf(m, "    %d @ %d\n",
+                                  gem_request->seqno,
+                                  (int) (jiffies - gem_request->emitted_jiffies));
+               }
+               count++;
+       }
+       if (!list_empty(&dev_priv->blt_ring.request_list)) {
+               seq_printf(m, "BLT requests:\n");
+               list_for_each_entry(gem_request,
+                                   &dev_priv->blt_ring.request_list,
+                                   list) {
+                       seq_printf(m, "    %d @ %d\n",
+                                  gem_request->seqno,
+                                  (int) (jiffies - gem_request->emitted_jiffies));
+               }
+               count++;
        }
        mutex_unlock(&dev->struct_mutex);
 
+       if (count == 0)
+               seq_printf(m, "No requests\n");
+
        return 0;
 }
 
+static void i915_ring_seqno_info(struct seq_file *m,
+                                struct intel_ring_buffer *ring)
+{
+       if (ring->get_seqno) {
+               seq_printf(m, "Current sequence (%s): %d\n",
+                          ring->name, ring->get_seqno(ring));
+               seq_printf(m, "Waiter sequence (%s):  %d\n",
+                          ring->name, ring->waiting_seqno);
+               seq_printf(m, "IRQ sequence (%s):     %d\n",
+                          ring->name, ring->irq_seqno);
+       }
+}
+
 static int i915_gem_seqno_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -294,15 +345,9 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data)
        if (ret)
                return ret;
 
-       if (dev_priv->render_ring.status_page.page_addr != NULL) {
-               seq_printf(m, "Current sequence: %d\n",
-                          dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
-       } else {
-               seq_printf(m, "Current sequence: hws uninitialized\n");
-       }
-       seq_printf(m, "Waiter sequence:  %d\n",
-                       dev_priv->mm.waiting_gem_seqno);
-       seq_printf(m, "IRQ sequence:     %d\n", dev_priv->mm.irq_gem_seqno);
+       i915_ring_seqno_info(m, &dev_priv->render_ring);
+       i915_ring_seqno_info(m, &dev_priv->bsd_ring);
+       i915_ring_seqno_info(m, &dev_priv->blt_ring);
 
        mutex_unlock(&dev->struct_mutex);
 
@@ -354,16 +399,9 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
        }
        seq_printf(m, "Interrupts received: %d\n",
                   atomic_read(&dev_priv->irq_received));
-       if (dev_priv->render_ring.status_page.page_addr != NULL) {
-               seq_printf(m, "Current sequence:    %d\n",
-                          dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
-       } else {
-               seq_printf(m, "Current sequence:    hws uninitialized\n");
-       }
-       seq_printf(m, "Waiter sequence:     %d\n",
-                  dev_priv->mm.waiting_gem_seqno);
-       seq_printf(m, "IRQ sequence:        %d\n",
-                  dev_priv->mm.irq_gem_seqno);
+       i915_ring_seqno_info(m, &dev_priv->render_ring);
+       i915_ring_seqno_info(m, &dev_priv->bsd_ring);
+       i915_ring_seqno_info(m, &dev_priv->blt_ring);
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -385,24 +423,12 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
        for (i = 0; i < dev_priv->num_fence_regs; i++) {
                struct drm_gem_object *obj = dev_priv->fence_regs[i].obj;
 
-               if (obj == NULL) {
-                       seq_printf(m, "Fenced object[%2d] = unused\n", i);
-               } else {
-                       struct drm_i915_gem_object *obj_priv;
-
-                       obj_priv = to_intel_bo(obj);
-                       seq_printf(m, "Fenced object[%2d] = %p: %s "
-                                  "%08x %08zx %08x %s %08x %08x %d",
-                                  i, obj, get_pin_flag(obj_priv),
-                                  obj_priv->gtt_offset,
-                                  obj->size, obj_priv->stride,
-                                  get_tiling_flag(obj_priv),
-                                  obj->read_domains, obj->write_domain,
-                                  obj_priv->last_rendering_seqno);
-                       if (obj->name)
-                               seq_printf(m, " (name: %d)", obj->name);
-                       seq_printf(m, "\n");
-               }
+               seq_printf(m, "Fenced object[%2d] = ", i);
+               if (obj == NULL)
+                       seq_printf(m, "unused");
+               else
+                       describe_obj(m, to_intel_bo(obj));
+               seq_printf(m, "\n");
        }
        mutex_unlock(&dev->struct_mutex);
 
@@ -414,10 +440,18 @@ static int i915_hws_info(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       int i;
+       struct intel_ring_buffer *ring;
        volatile u32 *hws;
+       int i;
+
+       switch ((uintptr_t)node->info_ent->data) {
+       case RING_RENDER: ring = &dev_priv->render_ring; break;
+       case RING_BSD: ring = &dev_priv->bsd_ring; break;
+       case RING_BLT: ring = &dev_priv->blt_ring; break;
+       default: return -EINVAL;
+       }
 
-       hws = (volatile u32 *)dev_priv->render_ring.status_page.page_addr;
+       hws = (volatile u32 *)ring->status_page.page_addr;
        if (hws == NULL)
                return 0;
 
@@ -477,19 +511,27 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
        int ret;
 
+       switch ((uintptr_t)node->info_ent->data) {
+       case RING_RENDER: ring = &dev_priv->render_ring; break;
+       case RING_BSD: ring = &dev_priv->bsd_ring; break;
+       case RING_BLT: ring = &dev_priv->blt_ring; break;
+       default: return -EINVAL;
+       }
+
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
 
-       if (!dev_priv->render_ring.gem_object) {
+       if (!ring->gem_object) {
                seq_printf(m, "No ringbuffer setup\n");
        } else {
-               u8 *virt = dev_priv->render_ring.virtual_start;
+               u8 *virt = ring->virtual_start;
                uint32_t off;
 
-               for (off = 0; off < dev_priv->render_ring.size; off += 4) {
+               for (off = 0; off < ring->size; off += 4) {
                        uint32_t *ptr = (uint32_t *)(virt + off);
                        seq_printf(m, "%08x :  %08x\n", off, *ptr);
                }
@@ -504,19 +546,39 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       unsigned int head, tail;
+       struct intel_ring_buffer *ring;
 
-       head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
-       tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
+       switch ((uintptr_t)node->info_ent->data) {
+       case RING_RENDER: ring = &dev_priv->render_ring; break;
+       case RING_BSD: ring = &dev_priv->bsd_ring; break;
+       case RING_BLT: ring = &dev_priv->blt_ring; break;
+       default: return -EINVAL;
+       }
+
+       if (ring->size == 0)
+           return 0;
 
-       seq_printf(m, "RingHead :  %08x\n", head);
-       seq_printf(m, "RingTail :  %08x\n", tail);
-       seq_printf(m, "RingSize :  %08lx\n", dev_priv->render_ring.size);
-       seq_printf(m, "Acthd :     %08x\n", I915_READ(INTEL_INFO(dev)->gen >= 4 ? ACTHD_I965 : ACTHD));
+       seq_printf(m, "Ring %s:\n", ring->name);
+       seq_printf(m, "  Head :    %08x\n", I915_READ_HEAD(ring) & HEAD_ADDR);
+       seq_printf(m, "  Tail :    %08x\n", I915_READ_TAIL(ring) & TAIL_ADDR);
+       seq_printf(m, "  Size :    %08x\n", ring->size);
+       seq_printf(m, "  Active :  %08x\n", intel_ring_get_active_head(ring));
+       seq_printf(m, "  Control : %08x\n", I915_READ_CTL(ring));
+       seq_printf(m, "  Start :   %08x\n", I915_READ_START(ring));
 
        return 0;
 }
 
+static const char *ring_str(int ring)
+{
+       switch (ring) {
+       case RING_RENDER: return "render";
+       case RING_BSD: return "bsd";
+       case RING_BLT: return "blt";
+       default: return "";
+       }
+}
+
 static const char *pin_flag(int pinned)
 {
        if (pinned > 0)
@@ -568,23 +630,39 @@ static int i915_error_state(struct seq_file *m, void *unused)
                   error->time.tv_usec);
        seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
        seq_printf(m, "EIR: 0x%08x\n", error->eir);
-       seq_printf(m, "  PGTBL_ER: 0x%08x\n", error->pgtbl_er);
-       seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm);
+       seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
+       if (INTEL_INFO(dev)->gen >= 6) {
+               seq_printf(m, "ERROR: 0x%08x\n", error->error);
+               seq_printf(m, "Blitter command stream:\n");
+               seq_printf(m, "  ACTHD:    0x%08x\n", error->bcs_acthd);
+               seq_printf(m, "  IPEIR:    0x%08x\n", error->bcs_ipeir);
+               seq_printf(m, "  IPEHR:    0x%08x\n", error->bcs_ipehr);
+               seq_printf(m, "  INSTDONE: 0x%08x\n", error->bcs_instdone);
+               seq_printf(m, "  seqno:    0x%08x\n", error->bcs_seqno);
+               seq_printf(m, "Video (BSD) command stream:\n");
+               seq_printf(m, "  ACTHD:    0x%08x\n", error->vcs_acthd);
+               seq_printf(m, "  IPEIR:    0x%08x\n", error->vcs_ipeir);
+               seq_printf(m, "  IPEHR:    0x%08x\n", error->vcs_ipehr);
+               seq_printf(m, "  INSTDONE: 0x%08x\n", error->vcs_instdone);
+               seq_printf(m, "  seqno:    0x%08x\n", error->vcs_seqno);
+       }
+       seq_printf(m, "Render command stream:\n");
+       seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd);
        seq_printf(m, "  IPEIR: 0x%08x\n", error->ipeir);
        seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr);
        seq_printf(m, "  INSTDONE: 0x%08x\n", error->instdone);
-       seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd);
        if (INTEL_INFO(dev)->gen >= 4) {
-               seq_printf(m, "  INSTPS: 0x%08x\n", error->instps);
                seq_printf(m, "  INSTDONE1: 0x%08x\n", error->instdone1);
+               seq_printf(m, "  INSTPS: 0x%08x\n", error->instps);
        }
-       seq_printf(m, "seqno: 0x%08x\n", error->seqno);
+       seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm);
+       seq_printf(m, "  seqno: 0x%08x\n", error->seqno);
 
        if (error->active_bo_count) {
                seq_printf(m, "Buffers [%d]:\n", error->active_bo_count);
 
                for (i = 0; i < error->active_bo_count; i++) {
-                       seq_printf(m, "  %08x %8zd %08x %08x %08x%s%s%s%s",
+                       seq_printf(m, "  %08x %8zd %08x %08x %08x%s%s%s%s %s",
                                   error->active_bo[i].gtt_offset,
                                   error->active_bo[i].size,
                                   error->active_bo[i].read_domains,
@@ -593,7 +671,8 @@ static int i915_error_state(struct seq_file *m, void *unused)
                                   pin_flag(error->active_bo[i].pinned),
                                   tiling_flag(error->active_bo[i].tiling),
                                   dirty_flag(error->active_bo[i].dirty),
-                                  purgeable_flag(error->active_bo[i].purgeable));
+                                  purgeable_flag(error->active_bo[i].purgeable),
+                                  ring_str(error->active_bo[i].ring));
 
                        if (error->active_bo[i].name)
                                seq_printf(m, " (name: %d)", error->active_bo[i].name);
@@ -943,7 +1022,6 @@ i915_wedged_write(struct file *filp,
                  loff_t *ppos)
 {
        struct drm_device *dev = filp->private_data;
-       drm_i915_private_t *dev_priv = dev->dev_private;
        char buf[20];
        int val = 1;
 
@@ -959,12 +1037,7 @@ i915_wedged_write(struct file *filp,
        }
 
        DRM_INFO("Manually setting wedged to %d\n", val);
-
-       atomic_set(&dev_priv->mm.wedged, val);
-       if (val) {
-               wake_up_all(&dev_priv->irq_queue);
-               queue_work(dev_priv->wq, &dev_priv->error_work);
-       }
+       i915_handle_error(dev, val);
 
        return cnt;
 }
@@ -1028,9 +1101,15 @@ static struct drm_info_list i915_debugfs_list[] = {
        {"i915_gem_seqno", i915_gem_seqno_info, 0},
        {"i915_gem_fence_regs", i915_gem_fence_regs_info, 0},
        {"i915_gem_interrupt", i915_interrupt_info, 0},
-       {"i915_gem_hws", i915_hws_info, 0},
-       {"i915_ringbuffer_data", i915_ringbuffer_data, 0},
-       {"i915_ringbuffer_info", i915_ringbuffer_info, 0},
+       {"i915_gem_hws", i915_hws_info, 0, (void *)RING_RENDER},
+       {"i915_gem_hws_blt", i915_hws_info, 0, (void *)RING_BLT},
+       {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)RING_BSD},
+       {"i915_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RING_RENDER},
+       {"i915_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RING_RENDER},
+       {"i915_bsd_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RING_BSD},
+       {"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RING_BSD},
+       {"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RING_BLT},
+       {"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RING_BLT},
        {"i915_batchbuffers", i915_batchbuffer_info, 0},
        {"i915_error_state", i915_error_state, 0},
        {"i915_rstdby_delays", i915_rstdby_delays, 0},
index 7a26f4d..4cd0491 100644 (file)
@@ -106,8 +106,8 @@ void i915_kernel_lost_context(struct drm_device * dev)
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                return;
 
-       ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
-       ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
+       ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+       ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
        ring->space = ring->head - (ring->tail + 8);
        if (ring->space < 0)
                ring->space += ring->size;
@@ -131,9 +131,9 @@ static int i915_dma_cleanup(struct drm_device * dev)
                drm_irq_uninstall(dev);
 
        mutex_lock(&dev->struct_mutex);
-       intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
-       intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
-       intel_cleanup_ring_buffer(dev, &dev_priv->blt_ring);
+       intel_cleanup_ring_buffer(&dev_priv->render_ring);
+       intel_cleanup_ring_buffer(&dev_priv->bsd_ring);
+       intel_cleanup_ring_buffer(&dev_priv->blt_ring);
        mutex_unlock(&dev->struct_mutex);
 
        /* Clear the HWS virtual address at teardown */
@@ -221,7 +221,7 @@ static int i915_dma_resume(struct drm_device * dev)
        DRM_DEBUG_DRIVER("hw status page @ %p\n",
                                ring->status_page.page_addr);
        if (ring->status_page.gfx_addr != 0)
-               intel_ring_setup_status_page(dev, ring);
+               intel_ring_setup_status_page(ring);
        else
                I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
 
@@ -263,7 +263,7 @@ static int i915_dma_init(struct drm_device *dev, void *data,
  * instruction detected will be given a size of zero, which is a
  * signal to abort the rest of the buffer.
  */
-static int do_validate_cmd(int cmd)
+static int validate_cmd(int cmd)
 {
        switch (((cmd >> 29) & 0x7)) {
        case 0x0:
@@ -321,40 +321,27 @@ static int do_validate_cmd(int cmd)
        return 0;
 }
 
-static int validate_cmd(int cmd)
-{
-       int ret = do_validate_cmd(cmd);
-
-/*     printk("validate_cmd( %x ): %d\n", cmd, ret); */
-
-       return ret;
-}
-
 static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       int i;
+       int i, ret;
 
        if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.size - 8)
                return -EINVAL;
 
-       BEGIN_LP_RING((dwords+1)&~1);
-
        for (i = 0; i < dwords;) {
-               int cmd, sz;
-
-               cmd = buffer[i];
-
-               if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
+               int sz = validate_cmd(buffer[i]);
+               if (sz == 0 || i + sz > dwords)
                        return -EINVAL;
-
-               OUT_RING(cmd);
-
-               while (++i, --sz) {
-                       OUT_RING(buffer[i]);
-               }
+               i += sz;
        }
 
+       ret = BEGIN_LP_RING((dwords+1)&~1);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < dwords; i++)
+               OUT_RING(buffer[i]);
        if (dwords & 1)
                OUT_RING(0);
 
@@ -368,7 +355,9 @@ i915_emit_box(struct drm_device *dev,
              struct drm_clip_rect *boxes,
              int i, int DR1, int DR4)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_clip_rect box = boxes[i];
+       int ret;
 
        if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
                DRM_ERROR("Bad box %d,%d..%d,%d\n",
@@ -377,22 +366,27 @@ i915_emit_box(struct drm_device *dev,
        }
 
        if (INTEL_INFO(dev)->gen >= 4) {
-               BEGIN_LP_RING(4);
+               ret = BEGIN_LP_RING(4);
+               if (ret)
+                       return ret;
+
                OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
                OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
                OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
                OUT_RING(DR4);
-               ADVANCE_LP_RING();
        } else {
-               BEGIN_LP_RING(6);
+               ret = BEGIN_LP_RING(6);
+               if (ret)
+                       return ret;
+
                OUT_RING(GFX_OP_DRAWRECT_INFO);
                OUT_RING(DR1);
                OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
                OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
                OUT_RING(DR4);
                OUT_RING(0);
-               ADVANCE_LP_RING();
        }
+       ADVANCE_LP_RING();
 
        return 0;
 }
@@ -412,12 +406,13 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
        if (master_priv->sarea_priv)
                master_priv->sarea_priv->last_enqueue = dev_priv->counter;
 
-       BEGIN_LP_RING(4);
-       OUT_RING(MI_STORE_DWORD_INDEX);
-       OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
-       OUT_RING(dev_priv->counter);
-       OUT_RING(0);
-       ADVANCE_LP_RING();
+       if (BEGIN_LP_RING(4) == 0) {
+               OUT_RING(MI_STORE_DWORD_INDEX);
+               OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+               OUT_RING(dev_priv->counter);
+               OUT_RING(0);
+               ADVANCE_LP_RING();
+       }
 }
 
 static int i915_dispatch_cmdbuffer(struct drm_device * dev,
@@ -458,8 +453,9 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
                                     drm_i915_batchbuffer_t * batch,
                                     struct drm_clip_rect *cliprects)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int nbox = batch->num_cliprects;
-       int i = 0, count;
+       int i, count, ret;
 
        if ((batch->start | batch->used) & 0x7) {
                DRM_ERROR("alignment");
@@ -469,17 +465,19 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
        i915_kernel_lost_context(dev);
 
        count = nbox ? nbox : 1;
-
        for (i = 0; i < count; i++) {
                if (i < nbox) {
-                       int ret = i915_emit_box(dev, cliprects, i,
-                                               batch->DR1, batch->DR4);
+                       ret = i915_emit_box(dev, cliprects, i,
+                                           batch->DR1, batch->DR4);
                        if (ret)
                                return ret;
                }
 
                if (!IS_I830(dev) && !IS_845G(dev)) {
-                       BEGIN_LP_RING(2);
+                       ret = BEGIN_LP_RING(2);
+                       if (ret)
+                               return ret;
+
                        if (INTEL_INFO(dev)->gen >= 4) {
                                OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
                                OUT_RING(batch->start);
@@ -487,26 +485,29 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
                                OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
                                OUT_RING(batch->start | MI_BATCH_NON_SECURE);
                        }
-                       ADVANCE_LP_RING();
                } else {
-                       BEGIN_LP_RING(4);
+                       ret = BEGIN_LP_RING(4);
+                       if (ret)
+                               return ret;
+
                        OUT_RING(MI_BATCH_BUFFER);
                        OUT_RING(batch->start | MI_BATCH_NON_SECURE);
                        OUT_RING(batch->start + batch->used - 4);
                        OUT_RING(0);
-                       ADVANCE_LP_RING();
                }
+               ADVANCE_LP_RING();
        }
 
 
        if (IS_G4X(dev) || IS_GEN5(dev)) {
-               BEGIN_LP_RING(2);
-               OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP);
-               OUT_RING(MI_NOOP);
-               ADVANCE_LP_RING();
+               if (BEGIN_LP_RING(2) == 0) {
+                       OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP);
+                       OUT_RING(MI_NOOP);
+                       ADVANCE_LP_RING();
+               }
        }
-       i915_emit_breadcrumb(dev);
 
+       i915_emit_breadcrumb(dev);
        return 0;
 }
 
@@ -515,6 +516,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv =
                dev->primary->master->driver_priv;
+       int ret;
 
        if (!master_priv->sarea_priv)
                return -EINVAL;
@@ -526,12 +528,13 @@ static int i915_dispatch_flip(struct drm_device * dev)
 
        i915_kernel_lost_context(dev);
 
-       BEGIN_LP_RING(2);
+       ret = BEGIN_LP_RING(10);
+       if (ret)
+               return ret;
+
        OUT_RING(MI_FLUSH | MI_READ_FLUSH);
        OUT_RING(0);
-       ADVANCE_LP_RING();
 
-       BEGIN_LP_RING(6);
        OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
        OUT_RING(0);
        if (dev_priv->current_page == 0) {
@@ -542,21 +545,21 @@ static int i915_dispatch_flip(struct drm_device * dev)
                dev_priv->current_page = 0;
        }
        OUT_RING(0);
-       ADVANCE_LP_RING();
 
-       BEGIN_LP_RING(2);
        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
        OUT_RING(0);
+
        ADVANCE_LP_RING();
 
        master_priv->sarea_priv->last_enqueue = dev_priv->counter++;
 
-       BEGIN_LP_RING(4);
-       OUT_RING(MI_STORE_DWORD_INDEX);
-       OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
-       OUT_RING(dev_priv->counter);
-       OUT_RING(0);
-       ADVANCE_LP_RING();
+       if (BEGIN_LP_RING(4) == 0) {
+               OUT_RING(MI_STORE_DWORD_INDEX);
+               OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+               OUT_RING(dev_priv->counter);
+               OUT_RING(0);
+               ADVANCE_LP_RING();
+       }
 
        master_priv->sarea_priv->pf_current_page = dev_priv->current_page;
        return 0;
@@ -567,7 +570,7 @@ static int i915_quiescent(struct drm_device * dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        i915_kernel_lost_context(dev);
-       return intel_wait_ring_buffer(dev, &dev_priv->render_ring,
+       return intel_wait_ring_buffer(&dev_priv->render_ring,
                                      dev_priv->render_ring.size - 8);
 }
 
@@ -767,6 +770,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
        case I915_PARAM_HAS_BLT:
                value = HAS_BLT(dev);
                break;
+       case I915_PARAM_HAS_RELAXED_FENCING:
+               value = 1;
+               break;
        default:
                DRM_DEBUG_DRIVER("Unknown parameter %d\n",
                                 param->param);
@@ -1192,13 +1198,17 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
        return can_switch;
 }
 
-static int i915_load_modeset_init(struct drm_device *dev,
-                                 unsigned long prealloc_size,
-                                 unsigned long agp_size)
+static int i915_load_modeset_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long prealloc_size, gtt_size, mappable_size;
        int ret = 0;
 
+       prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT;
+       gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT;
+       mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
+       gtt_size -= PAGE_SIZE;
+
        /* Basic memrange allocator for stolen space (aka mm.vram) */
        drm_mm_init(&dev_priv->mm.vram, 0, prealloc_size);
 
@@ -1211,7 +1221,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
         * at the last page of the aperture.  One page should be enough to
         * keep any prefetching inside of the aperture.
         */
-       i915_gem_do_init(dev, prealloc_size, agp_size - 4096);
+       i915_gem_do_init(dev, prealloc_size, mappable_size, gtt_size);
 
        mutex_lock(&dev->struct_mutex);
        ret = i915_gem_init_ringbuffer(dev);
@@ -1881,7 +1891,6 @@ EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
 int i915_driver_load(struct drm_device *dev, unsigned long flags)
 {
        struct drm_i915_private *dev_priv;
-       resource_size_t base, size;
        int ret = 0, mmio_bar;
        uint32_t agp_size, prealloc_size;
        /* i915 has 4 more counters */
@@ -1899,11 +1908,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        dev_priv->dev = dev;
        dev_priv->info = (struct intel_device_info *) flags;
 
-       /* Add register map (needed for suspend/resume) */
-       mmio_bar = IS_GEN2(dev) ? 1 : 0;
-       base = pci_resource_start(dev->pdev, mmio_bar);
-       size = pci_resource_len(dev->pdev, mmio_bar);
-
        if (i915_get_bridge_dev(dev)) {
                ret = -EIO;
                goto free_priv;
@@ -1913,16 +1917,26 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        if (IS_GEN2(dev))
                dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30));
 
-       dev_priv->regs = ioremap(base, size);
+       mmio_bar = IS_GEN2(dev) ? 1 : 0;
+       dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, 0);
        if (!dev_priv->regs) {
                DRM_ERROR("failed to map registers\n");
                ret = -EIO;
                goto put_bridge;
        }
 
+       dev_priv->mm.gtt = intel_gtt_get();
+       if (!dev_priv->mm.gtt) {
+               DRM_ERROR("Failed to initialize GTT\n");
+               ret = -ENODEV;
+               goto out_iomapfree;
+       }
+
+       prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT;
+       agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
+
         dev_priv->mm.gtt_mapping =
-               io_mapping_create_wc(dev->agp->base,
-                                    dev->agp->agp_info.aper_size * 1024*1024);
+               io_mapping_create_wc(dev->agp->base, agp_size);
        if (dev_priv->mm.gtt_mapping == NULL) {
                ret = -EIO;
                goto out_rmmap;
@@ -1934,24 +1948,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
         * MTRR if present.  Even if a UC MTRR isn't present.
         */
        dev_priv->mm.gtt_mtrr = mtrr_add(dev->agp->base,
-                                        dev->agp->agp_info.aper_size *
-                                        1024 * 1024,
+                                        agp_size,
                                         MTRR_TYPE_WRCOMB, 1);
        if (dev_priv->mm.gtt_mtrr < 0) {
                DRM_INFO("MTRR allocation failed.  Graphics "
                         "performance may suffer.\n");
        }
 
-       dev_priv->mm.gtt = intel_gtt_get();
-       if (!dev_priv->mm.gtt) {
-               DRM_ERROR("Failed to initialize GTT\n");
-               ret = -ENODEV;
-               goto out_iomapfree;
-       }
-
-       prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT;
-       agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
-
        /* The i915 workqueue is primarily used for batched retirement of
         * requests (and thus managing bo) once the task has been completed
         * by the GPU. i915_gem_retire_requests() is called directly when we
@@ -1990,7 +1993,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
            drm_core_check_feature(dev, DRIVER_MODESET)) {
                DRM_ERROR("kernel modesetting requires GEM, disabling driver.\n");
                ret = -ENODEV;
-               goto out_iomapfree;
+               goto out_workqueue_free;
        }
 
        dev->driver->get_vblank_counter = i915_get_vblank_counter;
@@ -2013,8 +2016,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        /* Init HWS */
        if (!I915_NEED_GFX_HWS(dev)) {
                ret = i915_init_phys_hws(dev);
-               if (ret != 0)
-                       goto out_workqueue_free;
+               if (ret)
+                       goto out_gem_unload;
        }
 
        if (IS_PINEVIEW(dev))
@@ -2041,11 +2044,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        dev_priv->trace_irq_seqno = 0;
 
        ret = drm_vblank_init(dev, I915_NUM_PIPE);
-
-       if (ret) {
-               (void) i915_driver_unload(dev);
-               return ret;
-       }
+       if (ret)
+               goto out_gem_unload;
 
        /* Start out suspended */
        dev_priv->mm.suspended = 1;
@@ -2053,10 +2053,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        intel_detect_pch(dev);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
+               ret = i915_load_modeset_init(dev);
                if (ret < 0) {
                        DRM_ERROR("failed to init modeset\n");
-                       goto out_workqueue_free;
+                       goto out_gem_unload;
                }
        }
 
@@ -2074,12 +2074,18 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        return 0;
 
+out_gem_unload:
+       if (dev->pdev->msi_enabled)
+               pci_disable_msi(dev->pdev);
+
+       intel_teardown_gmbus(dev);
+       intel_teardown_mchbar(dev);
 out_workqueue_free:
        destroy_workqueue(dev_priv->wq);
 out_iomapfree:
        io_mapping_free(dev_priv->mm.gtt_mapping);
 out_rmmap:
-       iounmap(dev_priv->regs);
+       pci_iounmap(dev->pdev, dev_priv->regs);
 put_bridge:
        pci_dev_put(dev_priv->bridge_dev);
 free_priv:
@@ -2096,6 +2102,9 @@ int i915_driver_unload(struct drm_device *dev)
        i915_mch_dev = NULL;
        spin_unlock(&mchdev_lock);
 
+       if (dev_priv->mm.inactive_shrinker.shrink)
+               unregister_shrinker(&dev_priv->mm.inactive_shrinker);
+
        mutex_lock(&dev->struct_mutex);
        ret = i915_gpu_idle(dev);
        if (ret)
@@ -2162,7 +2171,7 @@ int i915_driver_unload(struct drm_device *dev)
        }
 
        if (dev_priv->regs != NULL)
-               iounmap(dev_priv->regs);
+               pci_iounmap(dev->pdev, dev_priv->regs);
 
        intel_teardown_gmbus(dev);
        intel_teardown_mchbar(dev);
index 80745f8..57e892d 100644 (file)
@@ -473,7 +473,7 @@ int i915_reset(struct drm_device *dev, u8 flags)
                        !dev_priv->mm.suspended) {
                struct intel_ring_buffer *ring = &dev_priv->render_ring;
                dev_priv->mm.suspended = 0;
-               ring->init(dev, ring);
+               ring->init(ring);
                mutex_unlock(&dev->struct_mutex);
                drm_irq_uninstall(dev);
                drm_irq_install(dev);
@@ -660,8 +660,6 @@ static int __init i915_init(void)
 
        driver.num_ioctls = i915_max_ioctl;
 
-       i915_gem_shrinker_init();
-
        /*
         * If CONFIG_DRM_I915_KMS is set, default to KMS unless
         * explicitly disabled with the module pararmeter.
@@ -693,7 +691,6 @@ static int __init i915_init(void)
 
 static void __exit i915_exit(void)
 {
-       i915_gem_shrinker_exit();
        drm_exit(&driver);
 }
 
index 409826d..73a41f7 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "i915_reg.h"
 #include "intel_bios.h"
+#include "i915_trace.h"
 #include "intel_ringbuffer.h"
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
@@ -148,6 +149,17 @@ struct drm_i915_error_state {
        u32 ipehr;
        u32 instdone;
        u32 acthd;
+       u32 error; /* gen6+ */
+       u32 bcs_acthd; /* gen6+ blt engine */
+       u32 bcs_ipehr;
+       u32 bcs_ipeir;
+       u32 bcs_instdone;
+       u32 bcs_seqno;
+       u32 vcs_acthd; /* gen6+ bsd engine */
+       u32 vcs_ipehr;
+       u32 vcs_ipeir;
+       u32 vcs_instdone;
+       u32 vcs_seqno;
        u32 instpm;
        u32 instps;
        u32 instdone1;
@@ -171,6 +183,7 @@ struct drm_i915_error_state {
                u32 tiling:2;
                u32 dirty:1;
                u32 purgeable:1;
+               u32 ring:4;
        } *active_bo;
        u32 active_bo_count;
        struct intel_overlay_error_state *overlay;
@@ -275,11 +288,7 @@ typedef struct drm_i915_private {
        int front_offset;
        int current_page;
        int page_flipping;
-#define I915_DEBUG_READ (1<<0)
-#define I915_DEBUG_WRITE (1<<1)
-       unsigned long debug_flags;
 
-       wait_queue_head_t irq_queue;
        atomic_t irq_received;
        /** Protects user_irq_refcount and irq_mask_reg */
        spinlock_t user_irq_lock;
@@ -535,18 +544,13 @@ typedef struct drm_i915_private {
                struct drm_mm vram;
                /** Memory allocator for GTT */
                struct drm_mm gtt_space;
+               /** End of mappable part of GTT */
+               unsigned long gtt_mappable_end;
 
                struct io_mapping *gtt_mapping;
                int gtt_mtrr;
 
-               /**
-                * Membership on list of all loaded devices, used to evict
-                * inactive buffers under memory pressure.
-                *
-                * Modifications should only be done whilst holding the
-                * shrink_list_lock spinlock.
-                */
-               struct list_head shrink_list;
+               struct shrinker inactive_shrinker;
 
                /**
                 * List of objects currently involved in rendering.
@@ -608,16 +612,6 @@ typedef struct drm_i915_private {
                 */
                struct delayed_work retire_work;
 
-               /**
-                * Waiting sequence number, if any
-                */
-               uint32_t waiting_gem_seqno;
-
-               /**
-                * Last seq seen at irq time
-                */
-               uint32_t irq_gem_seqno;
-
                /**
                 * Flag if the X Server, and thus DRM, is not currently in
                 * control of the device.
@@ -645,15 +639,17 @@ typedef struct drm_i915_private {
                /* storage for physical objects */
                struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
 
-               uint32_t flush_rings;
-
                /* accounting, useful for userland debugging */
                size_t object_memory;
                size_t pin_memory;
                size_t gtt_memory;
+               size_t gtt_mappable_memory;
+               size_t mappable_gtt_used;
+               size_t mappable_gtt_total;
                size_t gtt_total;
                u32 object_count;
                u32 pin_count;
+               u32 gtt_mappable_count;
                u32 gtt_count;
        } mm;
        struct sdvo_device_mapping sdvo_mappings[2];
@@ -757,15 +753,6 @@ struct drm_i915_gem_object {
         */
        unsigned int madv : 2;
 
-       /**
-        * Refcount for the pages array. With the current locking scheme, there
-        * are at most two concurrent users: Binding a bo to the gtt and
-        * pwrite/pread using physical addresses. So two bits for a maximum
-        * of two users are enough.
-        */
-       unsigned int pages_refcount : 2;
-#define DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT 0x3
-
        /**
         * Current tiling mode for the object.
         */
@@ -783,6 +770,20 @@ struct drm_i915_gem_object {
        unsigned int pin_count : 4;
 #define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
 
+       /**
+        * Is the object at the current location in the gtt mappable and
+        * fenceable? Used to avoid costly recalculations.
+        */
+       unsigned int map_and_fenceable : 1;
+
+       /**
+        * Whether the current gtt mapping needs to be mappable (and isn't just
+        * mappable by accident). Track pin and fault separate for a more
+        * accurate mappable working set.
+        */
+       unsigned int fault_mappable : 1;
+       unsigned int pin_mappable : 1;
+
        /** AGP memory structure for our GTT binding. */
        DRM_AGP_MEM *agp_mem;
 
@@ -798,11 +799,6 @@ struct drm_i915_gem_object {
        /* Which ring is refering to is this object */
        struct intel_ring_buffer *ring;
 
-       /**
-        * Fake offset for use by mmap(2)
-        */
-       uint64_t mmap_offset;
-
        /** Breadcrumb of last rendering to the buffer. */
        uint32_t last_rendering_seqno;
 
@@ -880,6 +876,67 @@ enum intel_chip_family {
        CHIP_I965 = 0x08,
 };
 
+#define INTEL_INFO(dev)        (((struct drm_i915_private *) (dev)->dev_private)->info)
+
+#define IS_I830(dev)           ((dev)->pci_device == 0x3577)
+#define IS_845G(dev)           ((dev)->pci_device == 0x2562)
+#define IS_I85X(dev)           (INTEL_INFO(dev)->is_i85x)
+#define IS_I865G(dev)          ((dev)->pci_device == 0x2572)
+#define IS_I915G(dev)          (INTEL_INFO(dev)->is_i915g)
+#define IS_I915GM(dev)         ((dev)->pci_device == 0x2592)
+#define IS_I945G(dev)          ((dev)->pci_device == 0x2772)
+#define IS_I945GM(dev)         (INTEL_INFO(dev)->is_i945gm)
+#define IS_BROADWATER(dev)     (INTEL_INFO(dev)->is_broadwater)
+#define IS_CRESTLINE(dev)      (INTEL_INFO(dev)->is_crestline)
+#define IS_GM45(dev)           ((dev)->pci_device == 0x2A42)
+#define IS_G4X(dev)            (INTEL_INFO(dev)->is_g4x)
+#define IS_PINEVIEW_G(dev)     ((dev)->pci_device == 0xa001)
+#define IS_PINEVIEW_M(dev)     ((dev)->pci_device == 0xa011)
+#define IS_PINEVIEW(dev)       (INTEL_INFO(dev)->is_pineview)
+#define IS_G33(dev)            (INTEL_INFO(dev)->is_g33)
+#define IS_IRONLAKE_D(dev)     ((dev)->pci_device == 0x0042)
+#define IS_IRONLAKE_M(dev)     ((dev)->pci_device == 0x0046)
+#define IS_MOBILE(dev)         (INTEL_INFO(dev)->is_mobile)
+
+#define IS_GEN2(dev)   (INTEL_INFO(dev)->gen == 2)
+#define IS_GEN3(dev)   (INTEL_INFO(dev)->gen == 3)
+#define IS_GEN4(dev)   (INTEL_INFO(dev)->gen == 4)
+#define IS_GEN5(dev)   (INTEL_INFO(dev)->gen == 5)
+#define IS_GEN6(dev)   (INTEL_INFO(dev)->gen == 6)
+
+#define HAS_BSD(dev)            (INTEL_INFO(dev)->has_bsd_ring)
+#define HAS_BLT(dev)            (INTEL_INFO(dev)->has_blt_ring)
+#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
+
+#define HAS_OVERLAY(dev)               (INTEL_INFO(dev)->has_overlay)
+#define OVERLAY_NEEDS_PHYSICAL(dev)    (INTEL_INFO(dev)->overlay_needs_physical)
+
+/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
+ * rows, which changed the alignment requirements and fence programming.
+ */
+#define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \
+                                                     IS_I915GM(dev)))
+#define SUPPORTS_DIGITAL_OUTPUTS(dev)  (!IS_GEN2(dev) && !IS_PINEVIEW(dev))
+#define SUPPORTS_INTEGRATED_HDMI(dev)  (IS_G4X(dev) || IS_GEN5(dev))
+#define SUPPORTS_INTEGRATED_DP(dev)    (IS_G4X(dev) || IS_GEN5(dev))
+#define SUPPORTS_EDP(dev)              (IS_IRONLAKE_M(dev))
+#define SUPPORTS_TV(dev)               (INTEL_INFO(dev)->supports_tv)
+#define I915_HAS_HOTPLUG(dev)           (INTEL_INFO(dev)->has_hotplug)
+/* dsparb controlled by hw only */
+#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev))
+
+#define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2)
+#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
+#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
+#define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6)
+
+#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev))
+#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev))
+
+#define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
+#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
+#define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX)
+
 extern struct drm_ioctl_desc i915_ioctls[];
 extern int i915_max_ioctl;
 extern unsigned int i915_fbpercrtc;
@@ -918,6 +975,7 @@ extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
 
 /* i915_irq.c */
 void i915_hangcheck_elapsed(unsigned long data);
+void i915_handle_error(struct drm_device *dev, bool wedged);
 extern int i915_irq_emit(struct drm_device *dev, void *data,
                         struct drm_file *file_priv);
 extern int i915_irq_wait(struct drm_device *dev, void *data,
@@ -1020,7 +1078,8 @@ int i915_gem_init_object(struct drm_gem_object *obj);
 struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
                                              size_t size);
 void i915_gem_free_object(struct drm_gem_object *obj);
-int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment);
+int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment,
+                       bool map_and_fenceable);
 void i915_gem_object_unpin(struct drm_gem_object *obj);
 int i915_gem_object_unbind(struct drm_gem_object *obj);
 void i915_gem_release_mmap(struct drm_gem_object *obj);
@@ -1050,13 +1109,13 @@ int i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
 int i915_gem_init_ringbuffer(struct drm_device *dev);
 void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
 int i915_gem_do_init(struct drm_device *dev, unsigned long start,
-                    unsigned long end);
+                    unsigned long mappable_end, unsigned long end);
 int i915_gpu_idle(struct drm_device *dev);
 int i915_gem_idle(struct drm_device *dev);
-uint32_t i915_add_request(struct drm_device *dev,
-                         struct drm_file *file_priv,
-                         struct drm_i915_gem_request *request,
-                         struct intel_ring_buffer *ring);
+int i915_add_request(struct drm_device *dev,
+                    struct drm_file *file_priv,
+                    struct drm_i915_gem_request *request,
+                    struct intel_ring_buffer *ring);
 int i915_do_wait_request(struct drm_device *dev,
                         uint32_t seqno,
                         bool interruptible,
@@ -1075,22 +1134,16 @@ void i915_gem_detach_phys_object(struct drm_device *dev,
 void i915_gem_free_all_phys_object(struct drm_device *dev);
 void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
 
-void i915_gem_shrinker_init(void);
-void i915_gem_shrinker_exit(void);
-
 /* i915_gem_evict.c */
-int i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment);
-int i915_gem_evict_everything(struct drm_device *dev);
-int i915_gem_evict_inactive(struct drm_device *dev);
+int i915_gem_evict_something(struct drm_device *dev, int min_size,
+                            unsigned alignment, bool mappable);
+int i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only);
+int i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only);
 
 /* i915_gem_tiling.c */
 void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
 void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj);
 void i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj);
-bool i915_tiling_ok(struct drm_device *dev, int stride, int size,
-                   int tiling_mode);
-bool i915_gem_object_fence_offset_ok(struct drm_gem_object *obj,
-                                    int tiling_mode);
 
 /* i915_gem_debug.c */
 void i915_gem_dump_object(struct drm_gem_object *obj, int len,
@@ -1184,64 +1237,92 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
                LOCK_TEST_WITH_RETURN(dev, file_priv);                  \
 } while (0)
 
-static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg)
-{
-       u32 val;
+#define I915_READ(reg)         i915_read(dev_priv, (reg), 4)
+#define I915_WRITE(reg, val)   i915_write(dev_priv, (reg), (val), 4)
+#define I915_READ16(reg)       i915_read(dev_priv, (reg), 2)
+#define I915_WRITE16(reg, val) i915_write(dev_priv, (reg), (val), 2)
+#define I915_READ8(reg)                i915_read(dev_priv, (reg), 1)
+#define I915_WRITE8(reg, val)  i915_write(dev_priv, (reg), (val), 1)
+#define I915_WRITE64(reg, val) i915_write(dev_priv, (reg), (val), 8)
+#define I915_READ64(reg)       i915_read(dev_priv, (reg), 8)
+
+#define I915_READ_NOTRACE(reg)         readl(dev_priv->regs + (reg))
+#define I915_WRITE_NOTRACE(reg, val)   writel(val, dev_priv->regs + (reg))
+#define I915_READ16_NOTRACE(reg)               readw(dev_priv->regs + (reg))
+#define I915_WRITE16_NOTRACE(reg, val) writew(val, dev_priv->regs + (reg))
 
-       val = readl(dev_priv->regs + reg);
-       if (dev_priv->debug_flags & I915_DEBUG_READ)
-               printk(KERN_ERR "read 0x%08x from 0x%08x\n", val, reg);
-       return val;
+#define POSTING_READ(reg)      (void)I915_READ_NOTRACE(reg)
+#define POSTING_READ16(reg)    (void)I915_READ16_NOTRACE(reg)
+
+static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg, int len)
+{
+       u64 val = 0;
+
+       switch (len) {
+       case 8:
+               val = readq(dev_priv->regs + reg);
+               break;
+       case 4:
+               val = readl(dev_priv->regs + reg);
+               break;
+       case 2:
+               val = readw(dev_priv->regs + reg);
+               break;
+       case 1:
+               val = readb(dev_priv->regs + reg);
+               break;
+       }
+       trace_i915_reg_rw('R', reg, val, len);
+
+       return val;
 }
 
-static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg,
-                             u32 val)
+/* On SNB platform, before reading ring registers forcewake bit
+ * must be set to prevent GT core from power down and stale values being
+ * returned.
+ */
+static inline u32 i915_safe_read(struct drm_i915_private *dev_priv, u32 reg)
 {
-       writel(val, dev_priv->regs + reg);
-       if (dev_priv->debug_flags & I915_DEBUG_WRITE)
-               printk(KERN_ERR "wrote 0x%08x to 0x%08x\n", val, reg);
+       if (IS_GEN6(dev_priv->dev)) {
+               I915_WRITE_NOTRACE(FORCEWAKE, 1);
+               POSTING_READ(FORCEWAKE);
+               /* XXX How long do we really need to wait here?
+                * Will different registers/engines require different periods?
+                */
+               udelay(100);
+       }
+       return I915_READ(reg);
 }
 
-#define I915_READ(reg)          i915_read(dev_priv, (reg))
-#define I915_WRITE(reg, val)    i915_write(dev_priv, (reg), (val))
-#define I915_READ16(reg)       readw(dev_priv->regs + (reg))
-#define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg))
-#define I915_READ8(reg)                readb(dev_priv->regs + (reg))
-#define I915_WRITE8(reg, val)  writeb(val, dev_priv->regs + (reg))
-#define I915_WRITE64(reg, val) writeq(val, dev_priv->regs + (reg))
-#define I915_READ64(reg)       readq(dev_priv->regs + (reg))
-#define POSTING_READ(reg)      (void)I915_READ(reg)
-#define POSTING_READ16(reg)    (void)I915_READ16(reg)
-
-#define I915_DEBUG_ENABLE_IO() (dev_priv->debug_flags |= I915_DEBUG_READ | \
-                               I915_DEBUG_WRITE)
-#define I915_DEBUG_DISABLE_IO() (dev_priv->debug_flags &= ~(I915_DEBUG_READ | \
-                                                           I915_DEBUG_WRITE))
-
-#define I915_VERBOSE 0
-
-#define BEGIN_LP_RING(n)  do { \
-       drm_i915_private_t *dev_priv__ = dev->dev_private;                \
-       if (I915_VERBOSE)                                               \
-               DRM_DEBUG("   BEGIN_LP_RING %x\n", (int)(n));           \
-       intel_ring_begin(dev, &dev_priv__->render_ring, (n));           \
-} while (0)
+static inline void
+i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len)
+{
+       /* Trace down the write operation before the real write */
+       trace_i915_reg_rw('W', reg, val, len);
+       switch (len) {
+       case 8:
+               writeq(val, dev_priv->regs + reg);
+               break;
+       case 4:
+               writel(val, dev_priv->regs + reg);
+               break;
+       case 2:
+               writew(val, dev_priv->regs + reg);
+               break;
+       case 1:
+               writeb(val, dev_priv->regs + reg);
+               break;
+       }
+}
 
+#define BEGIN_LP_RING(n) \
+       intel_ring_begin(&dev_priv->render_ring, (n))
 
-#define OUT_RING(x) do {                                               \
-       drm_i915_private_t *dev_priv__ = dev->dev_private;              \
-       if (I915_VERBOSE)                                               \
-               DRM_DEBUG("   OUT_RING %x\n", (int)(x));                \
-       intel_ring_emit(dev, &dev_priv__->render_ring, x);              \
-} while (0)
+#define OUT_RING(x) \
+       intel_ring_emit(&dev_priv->render_ring, x)
 
-#define ADVANCE_LP_RING() do {                                         \
-       drm_i915_private_t *dev_priv__ = dev->dev_private;                \
-       if (I915_VERBOSE)                                               \
-               DRM_DEBUG("ADVANCE_LP_RING %x\n",                       \
-                               dev_priv__->render_ring.tail);          \
-       intel_ring_advance(dev, &dev_priv__->render_ring);              \
-} while(0)
+#define ADVANCE_LP_RING() \
+       intel_ring_advance(&dev_priv->render_ring)
 
 /**
  * Reads a dword out of the status page, which is written to from the command
@@ -1264,67 +1345,4 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg,
 #define I915_GEM_HWS_INDEX             0x20
 #define I915_BREADCRUMB_INDEX          0x21
 
-#define INTEL_INFO(dev)        (((struct drm_i915_private *) (dev)->dev_private)->info)
-
-#define IS_I830(dev)           ((dev)->pci_device == 0x3577)
-#define IS_845G(dev)           ((dev)->pci_device == 0x2562)
-#define IS_I85X(dev)           (INTEL_INFO(dev)->is_i85x)
-#define IS_I865G(dev)          ((dev)->pci_device == 0x2572)
-#define IS_I915G(dev)          (INTEL_INFO(dev)->is_i915g)
-#define IS_I915GM(dev)         ((dev)->pci_device == 0x2592)
-#define IS_I945G(dev)          ((dev)->pci_device == 0x2772)
-#define IS_I945GM(dev)         (INTEL_INFO(dev)->is_i945gm)
-#define IS_BROADWATER(dev)     (INTEL_INFO(dev)->is_broadwater)
-#define IS_CRESTLINE(dev)      (INTEL_INFO(dev)->is_crestline)
-#define IS_GM45(dev)           ((dev)->pci_device == 0x2A42)
-#define IS_G4X(dev)            (INTEL_INFO(dev)->is_g4x)
-#define IS_PINEVIEW_G(dev)     ((dev)->pci_device == 0xa001)
-#define IS_PINEVIEW_M(dev)     ((dev)->pci_device == 0xa011)
-#define IS_PINEVIEW(dev)       (INTEL_INFO(dev)->is_pineview)
-#define IS_G33(dev)            (INTEL_INFO(dev)->is_g33)
-#define IS_IRONLAKE_D(dev)     ((dev)->pci_device == 0x0042)
-#define IS_IRONLAKE_M(dev)     ((dev)->pci_device == 0x0046)
-#define IS_MOBILE(dev)         (INTEL_INFO(dev)->is_mobile)
-
-#define IS_GEN2(dev)   (INTEL_INFO(dev)->gen == 2)
-#define IS_GEN3(dev)   (INTEL_INFO(dev)->gen == 3)
-#define IS_GEN4(dev)   (INTEL_INFO(dev)->gen == 4)
-#define IS_GEN5(dev)   (INTEL_INFO(dev)->gen == 5)
-#define IS_GEN6(dev)   (INTEL_INFO(dev)->gen == 6)
-
-#define HAS_BSD(dev)            (INTEL_INFO(dev)->has_bsd_ring)
-#define HAS_BLT(dev)            (INTEL_INFO(dev)->has_blt_ring)
-#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
-
-#define HAS_OVERLAY(dev)               (INTEL_INFO(dev)->has_overlay)
-#define OVERLAY_NEEDS_PHYSICAL(dev)    (INTEL_INFO(dev)->overlay_needs_physical)
-
-/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
- * rows, which changed the alignment requirements and fence programming.
- */
-#define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \
-                                                     IS_I915GM(dev)))
-#define SUPPORTS_DIGITAL_OUTPUTS(dev)  (!IS_GEN2(dev) && !IS_PINEVIEW(dev))
-#define SUPPORTS_INTEGRATED_HDMI(dev)  (IS_G4X(dev) || IS_GEN5(dev))
-#define SUPPORTS_INTEGRATED_DP(dev)    (IS_G4X(dev) || IS_GEN5(dev))
-#define SUPPORTS_EDP(dev)              (IS_IRONLAKE_M(dev))
-#define SUPPORTS_TV(dev)               (INTEL_INFO(dev)->supports_tv)
-#define I915_HAS_HOTPLUG(dev)           (INTEL_INFO(dev)->has_hotplug)
-/* dsparb controlled by hw only */
-#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev))
-
-#define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2)
-#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
-#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
-#define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6)
-
-#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev))
-#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev))
-
-#define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
-#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
-#define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX)
-
-#define PRIMARY_RINGBUFFER_SIZE         (128*1024)
-
 #endif
index 781c26c..54fc1e7 100644 (file)
 #include <linux/pci.h>
 #include <linux/intel-gtt.h>
 
-static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj);
+struct change_domains {
+       uint32_t invalidate_domains;
+       uint32_t flush_domains;
+       uint32_t flush_rings;
+};
+
+static uint32_t i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv);
+static uint32_t i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv);
 
 static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
                                                  bool pipelined);
@@ -51,22 +58,18 @@ static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *o
 static int i915_gem_object_wait_rendering(struct drm_gem_object *obj,
                                          bool interruptible);
 static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
-                                          unsigned alignment);
+                                      unsigned alignment,
+                                      bool map_and_fenceable);
 static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
 static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
                                struct drm_i915_gem_pwrite *args,
                                struct drm_file *file_priv);
 static void i915_gem_free_object_tail(struct drm_gem_object *obj);
 
-static int
-i915_gem_object_get_pages(struct drm_gem_object *obj,
-                         gfp_t gfpmask);
-
-static void
-i915_gem_object_put_pages(struct drm_gem_object *obj);
+static int i915_gem_inactive_shrink(struct shrinker *shrinker,
+                                   int nr_to_scan,
+                                   gfp_t gfp_mask);
 
-static LIST_HEAD(shrink_list);
-static DEFINE_SPINLOCK(shrink_list_lock);
 
 /* some bookkeeping */
 static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
@@ -84,31 +87,75 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv,
 }
 
 static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv,
-                                 size_t size)
+                                 struct drm_i915_gem_object *obj)
 {
        dev_priv->mm.gtt_count++;
-       dev_priv->mm.gtt_memory += size;
+       dev_priv->mm.gtt_memory += obj->gtt_space->size;
+       if (obj->gtt_offset < dev_priv->mm.gtt_mappable_end) {
+               dev_priv->mm.mappable_gtt_used +=
+                       min_t(size_t, obj->gtt_space->size,
+                             dev_priv->mm.gtt_mappable_end - obj->gtt_offset);
+       }
 }
 
 static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv,
-                                    size_t size)
+                                    struct drm_i915_gem_object *obj)
 {
        dev_priv->mm.gtt_count--;
-       dev_priv->mm.gtt_memory -= size;
+       dev_priv->mm.gtt_memory -= obj->gtt_space->size;
+       if (obj->gtt_offset < dev_priv->mm.gtt_mappable_end) {
+               dev_priv->mm.mappable_gtt_used -=
+                       min_t(size_t, obj->gtt_space->size,
+                             dev_priv->mm.gtt_mappable_end - obj->gtt_offset);
+       }
+}
+
+/**
+ * Update the mappable working set counters. Call _only_ when there is a change
+ * in one of (pin|fault)_mappable and update *_mappable _before_ calling.
+ * @mappable: new state the changed mappable flag (either pin_ or fault_).
+ */
+static void
+i915_gem_info_update_mappable(struct drm_i915_private *dev_priv,
+                             struct drm_i915_gem_object *obj,
+                             bool mappable)
+{
+       if (mappable) {
+               if (obj->pin_mappable && obj->fault_mappable)
+                       /* Combined state was already mappable. */
+                       return;
+               dev_priv->mm.gtt_mappable_count++;
+               dev_priv->mm.gtt_mappable_memory += obj->gtt_space->size;
+       } else {
+               if (obj->pin_mappable || obj->fault_mappable)
+                       /* Combined state still mappable. */
+                       return;
+               dev_priv->mm.gtt_mappable_count--;
+               dev_priv->mm.gtt_mappable_memory -= obj->gtt_space->size;
+       }
 }
 
 static void i915_gem_info_add_pin(struct drm_i915_private *dev_priv,
-                                 size_t size)
+                                 struct drm_i915_gem_object *obj,
+                                 bool mappable)
 {
        dev_priv->mm.pin_count++;
-       dev_priv->mm.pin_memory += size;
+       dev_priv->mm.pin_memory += obj->gtt_space->size;
+       if (mappable) {
+               obj->pin_mappable = true;
+               i915_gem_info_update_mappable(dev_priv, obj, true);
+       }
 }
 
 static void i915_gem_info_remove_pin(struct drm_i915_private *dev_priv,
-                                    size_t size)
+                                    struct drm_i915_gem_object *obj)
 {
        dev_priv->mm.pin_count--;
-       dev_priv->mm.pin_memory -= size;
+       dev_priv->mm.pin_memory -= obj->gtt_space->size;
+       if (obj->pin_mappable) {
+               obj->pin_mappable = false;
+               i915_gem_info_update_mappable(dev_priv, obj, false);
+       }
 }
 
 int
@@ -173,6 +220,7 @@ i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv)
 
 int i915_gem_do_init(struct drm_device *dev,
                     unsigned long start,
+                    unsigned long mappable_end,
                     unsigned long end)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -187,6 +235,8 @@ int i915_gem_do_init(struct drm_device *dev,
                    end - start);
 
        dev_priv->mm.gtt_total = end - start;
+       dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start;
+       dev_priv->mm.gtt_mappable_end = mappable_end;
 
        return 0;
 }
@@ -199,7 +249,7 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data,
        int ret;
 
        mutex_lock(&dev->struct_mutex);
-       ret = i915_gem_do_init(dev, args->gtt_start, args->gtt_end);
+       ret = i915_gem_do_init(dev, args->gtt_start, args->gtt_end, args->gtt_end);
        mutex_unlock(&dev->struct_mutex);
 
        return ret;
@@ -259,22 +309,6 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
        return 0;
 }
 
-static inline int
-fast_shmem_read(struct page **pages,
-               loff_t page_base, int page_offset,
-               char __user *data,
-               int length)
-{
-       char *vaddr;
-       int ret;
-
-       vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT]);
-       ret = __copy_to_user_inatomic(data, vaddr + page_offset, length);
-       kunmap_atomic(vaddr);
-
-       return ret;
-}
-
 static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj)
 {
        drm_i915_private_t *dev_priv = obj->dev->dev_private;
@@ -362,8 +396,9 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj,
                          struct drm_file *file_priv)
 {
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+       struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping;
        ssize_t remain;
-       loff_t offset, page_base;
+       loff_t offset;
        char __user *user_data;
        int page_offset, page_length;
 
@@ -374,21 +409,34 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj,
        offset = args->offset;
 
        while (remain > 0) {
+               struct page *page;
+               char *vaddr;
+               int ret;
+
                /* Operation in this page
                 *
-                * page_base = page offset within aperture
                 * page_offset = offset within page
                 * page_length = bytes to copy for this page
                 */
-               page_base = (offset & ~(PAGE_SIZE-1));
                page_offset = offset & (PAGE_SIZE-1);
                page_length = remain;
                if ((page_offset + remain) > PAGE_SIZE)
                        page_length = PAGE_SIZE - page_offset;
 
-               if (fast_shmem_read(obj_priv->pages,
-                                   page_base, page_offset,
-                                   user_data, page_length))
+               page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT,
+                                          GFP_HIGHUSER | __GFP_RECLAIMABLE);
+               if (IS_ERR(page))
+                       return PTR_ERR(page);
+
+               vaddr = kmap_atomic(page);
+               ret = __copy_to_user_inatomic(user_data,
+                                             vaddr + page_offset,
+                                             page_length);
+               kunmap_atomic(vaddr);
+
+               mark_page_accessed(page);
+               page_cache_release(page);
+               if (ret)
                        return -EFAULT;
 
                remain -= page_length;
@@ -399,30 +447,6 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj,
        return 0;
 }
 
-static int
-i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj)
-{
-       int ret;
-
-       ret = i915_gem_object_get_pages(obj, __GFP_NORETRY | __GFP_NOWARN);
-
-       /* If we've insufficient memory to map in the pages, attempt
-        * to make some space by throwing out some old buffers.
-        */
-       if (ret == -ENOMEM) {
-               struct drm_device *dev = obj->dev;
-
-               ret = i915_gem_evict_something(dev, obj->size,
-                                              i915_gem_get_gtt_alignment(obj));
-               if (ret)
-                       return ret;
-
-               ret = i915_gem_object_get_pages(obj, 0);
-       }
-
-       return ret;
-}
-
 /**
  * This is the fallback shmem pread path, which allocates temporary storage
  * in kernel space to copy_to_user into outside of the struct_mutex, so we
@@ -434,14 +458,15 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
                          struct drm_i915_gem_pread *args,
                          struct drm_file *file_priv)
 {
+       struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        struct mm_struct *mm = current->mm;
        struct page **user_pages;
        ssize_t remain;
        loff_t offset, pinned_pages, i;
        loff_t first_data_page, last_data_page, num_pages;
-       int shmem_page_index, shmem_page_offset;
-       int data_page_index,  data_page_offset;
+       int shmem_page_offset;
+       int data_page_index, data_page_offset;
        int page_length;
        int ret;
        uint64_t data_ptr = args->data_ptr;
@@ -484,15 +509,15 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
        offset = args->offset;
 
        while (remain > 0) {
+               struct page *page;
+
                /* Operation in this page
                 *
-                * shmem_page_index = page number within shmem file
                 * shmem_page_offset = offset within page in shmem file
                 * data_page_index = page number in get_user_pages return
                 * data_page_offset = offset with data_page_index page.
                 * page_length = bytes to copy for this page
                 */
-               shmem_page_index = offset / PAGE_SIZE;
                shmem_page_offset = offset & ~PAGE_MASK;
                data_page_index = data_ptr / PAGE_SIZE - first_data_page;
                data_page_offset = data_ptr & ~PAGE_MASK;
@@ -503,8 +528,13 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
                if ((data_page_offset + page_length) > PAGE_SIZE)
                        page_length = PAGE_SIZE - data_page_offset;
 
+               page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT,
+                                          GFP_HIGHUSER | __GFP_RECLAIMABLE);
+               if (IS_ERR(page))
+                       return PTR_ERR(page);
+
                if (do_bit17_swizzling) {
-                       slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index],
+                       slow_shmem_bit17_copy(page,
                                              shmem_page_offset,
                                              user_pages[data_page_index],
                                              data_page_offset,
@@ -513,11 +543,14 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
                } else {
                        slow_shmem_copy(user_pages[data_page_index],
                                        data_page_offset,
-                                       obj_priv->pages[shmem_page_index],
+                                       page,
                                        shmem_page_offset,
                                        page_length);
                }
 
+               mark_page_accessed(page);
+               page_cache_release(page);
+
                remain -= page_length;
                data_ptr += page_length;
                offset += page_length;
@@ -526,6 +559,7 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
 out:
        for (i = 0; i < pinned_pages; i++) {
                SetPageDirty(user_pages[i]);
+               mark_page_accessed(user_pages[i]);
                page_cache_release(user_pages[i]);
        }
        drm_free_large(user_pages);
@@ -581,15 +615,11 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
                goto out;
        }
 
-       ret = i915_gem_object_get_pages_or_evict(obj);
-       if (ret)
-               goto out;
-
        ret = i915_gem_object_set_cpu_read_domain_range(obj,
                                                        args->offset,
                                                        args->size);
        if (ret)
-               goto out_put;
+               goto out;
 
        ret = -EFAULT;
        if (!i915_gem_object_needs_bit17_swizzle(obj))
@@ -597,8 +627,6 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
        if (ret == -EFAULT)
                ret = i915_gem_shmem_pread_slow(dev, obj, args, file_priv);
 
-out_put:
-       i915_gem_object_put_pages(obj);
 out:
        drm_gem_object_unreference(obj);
 unlock:
@@ -650,22 +678,6 @@ slow_kernel_write(struct io_mapping *mapping,
        io_mapping_unmap(dst_vaddr);
 }
 
-static inline int
-fast_shmem_write(struct page **pages,
-                loff_t page_base, int page_offset,
-                char __user *data,
-                int length)
-{
-       char *vaddr;
-       int ret;
-
-       vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT]);
-       ret = __copy_from_user_inatomic(vaddr + page_offset, data, length);
-       kunmap_atomic(vaddr);
-
-       return ret;
-}
-
 /**
  * This is the fast pwrite path, where we copy the data directly from the
  * user into the GTT, uncached.
@@ -822,9 +834,10 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
                           struct drm_i915_gem_pwrite *args,
                           struct drm_file *file_priv)
 {
+       struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        ssize_t remain;
-       loff_t offset, page_base;
+       loff_t offset;
        char __user *user_data;
        int page_offset, page_length;
 
@@ -836,21 +849,40 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
        obj_priv->dirty = 1;
 
        while (remain > 0) {
+               struct page *page;
+               char *vaddr;
+               int ret;
+
                /* Operation in this page
                 *
-                * page_base = page offset within aperture
                 * page_offset = offset within page
                 * page_length = bytes to copy for this page
                 */
-               page_base = (offset & ~(PAGE_SIZE-1));
                page_offset = offset & (PAGE_SIZE-1);
                page_length = remain;
                if ((page_offset + remain) > PAGE_SIZE)
                        page_length = PAGE_SIZE - page_offset;
 
-               if (fast_shmem_write(obj_priv->pages,
-                                      page_base, page_offset,
-                                      user_data, page_length))
+               page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT,
+                                          GFP_HIGHUSER | __GFP_RECLAIMABLE);
+               if (IS_ERR(page))
+                       return PTR_ERR(page);
+
+               vaddr = kmap_atomic(page, KM_USER0);
+               ret = __copy_from_user_inatomic(vaddr + page_offset,
+                                               user_data,
+                                               page_length);
+               kunmap_atomic(vaddr, KM_USER0);
+
+               set_page_dirty(page);
+               mark_page_accessed(page);
+               page_cache_release(page);
+
+               /* If we get a fault while copying data, then (presumably) our
+                * source page isn't available.  Return the error and we'll
+                * retry in the slow path.
+                */
+               if (ret)
                        return -EFAULT;
 
                remain -= page_length;
@@ -873,13 +905,14 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
                           struct drm_i915_gem_pwrite *args,
                           struct drm_file *file_priv)
 {
+       struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        struct mm_struct *mm = current->mm;
        struct page **user_pages;
        ssize_t remain;
        loff_t offset, pinned_pages, i;
        loff_t first_data_page, last_data_page, num_pages;
-       int shmem_page_index, shmem_page_offset;
+       int shmem_page_offset;
        int data_page_index,  data_page_offset;
        int page_length;
        int ret;
@@ -922,15 +955,15 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
        obj_priv->dirty = 1;
 
        while (remain > 0) {
+               struct page *page;
+
                /* Operation in this page
                 *
-                * shmem_page_index = page number within shmem file
                 * shmem_page_offset = offset within page in shmem file
                 * data_page_index = page number in get_user_pages return
                 * data_page_offset = offset with data_page_index page.
                 * page_length = bytes to copy for this page
                 */
-               shmem_page_index = offset / PAGE_SIZE;
                shmem_page_offset = offset & ~PAGE_MASK;
                data_page_index = data_ptr / PAGE_SIZE - first_data_page;
                data_page_offset = data_ptr & ~PAGE_MASK;
@@ -941,21 +974,32 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
                if ((data_page_offset + page_length) > PAGE_SIZE)
                        page_length = PAGE_SIZE - data_page_offset;
 
+               page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT,
+                                          GFP_HIGHUSER | __GFP_RECLAIMABLE);
+               if (IS_ERR(page)) {
+                       ret = PTR_ERR(page);
+                       goto out;
+               }
+
                if (do_bit17_swizzling) {
-                       slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index],
+                       slow_shmem_bit17_copy(page,
                                              shmem_page_offset,
                                              user_pages[data_page_index],
                                              data_page_offset,
                                              page_length,
                                              0);
                } else {
-                       slow_shmem_copy(obj_priv->pages[shmem_page_index],
+                       slow_shmem_copy(page,
                                        shmem_page_offset,
                                        user_pages[data_page_index],
                                        data_page_offset,
                                        page_length);
                }
 
+               set_page_dirty(page);
+               mark_page_accessed(page);
+               page_cache_release(page);
+
                remain -= page_length;
                data_ptr += page_length;
                offset += page_length;
@@ -1029,7 +1073,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
        else if (obj_priv->tiling_mode == I915_TILING_NONE &&
                 obj_priv->gtt_space &&
                 obj->write_domain != I915_GEM_DOMAIN_CPU) {
-               ret = i915_gem_object_pin(obj, 0);
+               ret = i915_gem_object_pin(obj, 0, true);
                if (ret)
                        goto out;
 
@@ -1044,22 +1088,15 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
 out_unpin:
                i915_gem_object_unpin(obj);
        } else {
-               ret = i915_gem_object_get_pages_or_evict(obj);
-               if (ret)
-                       goto out;
-
                ret = i915_gem_object_set_to_cpu_domain(obj, 1);
                if (ret)
-                       goto out_put;
+                       goto out;
 
                ret = -EFAULT;
                if (!i915_gem_object_needs_bit17_swizzle(obj))
                        ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file);
                if (ret == -EFAULT)
                        ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file);
-
-out_put:
-               i915_gem_object_put_pages(obj);
        }
 
 out:
@@ -1192,6 +1229,7 @@ int
 i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
                   struct drm_file *file_priv)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_mmap *args = data;
        struct drm_gem_object *obj;
        loff_t offset;
@@ -1204,6 +1242,11 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
        if (obj == NULL)
                return -ENOENT;
 
+       if (obj->size > dev_priv->mm.gtt_mappable_end) {
+               drm_gem_object_unreference_unlocked(obj);
+               return -E2BIG;
+       }
+
        offset = args->offset;
 
        down_write(&current->mm->mmap_sem);
@@ -1253,14 +1296,29 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
        /* Now bind it into the GTT if needed */
        mutex_lock(&dev->struct_mutex);
+       BUG_ON(obj_priv->pin_count && !obj_priv->pin_mappable);
+
+       if (obj_priv->gtt_space) {
+               if (!obj_priv->map_and_fenceable) {
+                       ret = i915_gem_object_unbind(obj);
+                       if (ret)
+                               goto unlock;
+               }
+       }
+
        if (!obj_priv->gtt_space) {
-               ret = i915_gem_object_bind_to_gtt(obj, 0);
+               ret = i915_gem_object_bind_to_gtt(obj, 0, true);
                if (ret)
                        goto unlock;
+       }
 
-               ret = i915_gem_object_set_to_gtt_domain(obj, write);
-               if (ret)
-                       goto unlock;
+       ret = i915_gem_object_set_to_gtt_domain(obj, write);
+       if (ret)
+               goto unlock;
+
+       if (!obj_priv->fault_mappable) {
+               obj_priv->fault_mappable = true;
+               i915_gem_info_update_mappable(dev_priv, obj_priv, true);
        }
 
        /* Need a new fence register? */
@@ -1282,11 +1340,12 @@ unlock:
        mutex_unlock(&dev->struct_mutex);
 
        switch (ret) {
+       case -EAGAIN:
+               set_need_resched();
        case 0:
        case -ERESTARTSYS:
                return VM_FAULT_NOPAGE;
        case -ENOMEM:
-       case -EAGAIN:
                return VM_FAULT_OOM;
        default:
                return VM_FAULT_SIGBUS;
@@ -1309,7 +1368,6 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
        struct drm_gem_mm *mm = dev->mm_private;
-       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        struct drm_map_list *list;
        struct drm_local_map *map;
        int ret = 0;
@@ -1348,16 +1406,13 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
                goto out_free_mm;
        }
 
-       /* By now we should be all set, any drm_mmap request on the offset
-        * below will get to our mmap & fault handler */
-       obj_priv->mmap_offset = ((uint64_t) list->hash.key) << PAGE_SHIFT;
-
        return 0;
 
 out_free_mm:
        drm_mm_put_block(list->file_offset_node);
 out_free_list:
        kfree(list->map);
+       list->map = NULL;
 
        return ret;
 }
@@ -1380,35 +1435,31 @@ void
 i915_gem_release_mmap(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
-       if (dev->dev_mapping)
+       if (unlikely(obj->map_list.map && dev->dev_mapping))
                unmap_mapping_range(dev->dev_mapping,
-                                   obj_priv->mmap_offset, obj->size, 1);
+                                   (loff_t)obj->map_list.hash.key<<PAGE_SHIFT,
+                                   obj->size, 1);
+
+       if (obj_priv->fault_mappable) {
+               obj_priv->fault_mappable = false;
+               i915_gem_info_update_mappable(dev_priv, obj_priv, false);
+       }
 }
 
 static void
 i915_gem_free_mmap_offset(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
-       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        struct drm_gem_mm *mm = dev->mm_private;
-       struct drm_map_list *list;
+       struct drm_map_list *list = &obj->map_list;
 
-       list = &obj->map_list;
        drm_ht_remove_item(&mm->offset_hash, &list->hash);
-
-       if (list->file_offset_node) {
-               drm_mm_put_block(list->file_offset_node);
-               list->file_offset_node = NULL;
-       }
-
-       if (list->map) {
-               kfree(list->map);
-               list->map = NULL;
-       }
-
-       obj_priv->mmap_offset = 0;
+       drm_mm_put_block(list->file_offset_node);
+       kfree(list->map);
+       list->map = NULL;
 }
 
 /**
@@ -1416,35 +1467,89 @@ i915_gem_free_mmap_offset(struct drm_gem_object *obj)
  * @obj: object to check
  *
  * Return the required GTT alignment for an object, taking into account
- * potential fence register mapping if needed.
+ * potential fence register mapping.
  */
 static uint32_t
-i915_gem_get_gtt_alignment(struct drm_gem_object *obj)
+i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv)
 {
-       struct drm_device *dev = obj->dev;
-       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-       int start, i;
+       struct drm_device *dev = obj_priv->base.dev;
 
        /*
         * Minimum alignment is 4k (GTT page size), but might be greater
         * if a fence register is needed for the object.
         */
-       if (INTEL_INFO(dev)->gen >= 4 || obj_priv->tiling_mode == I915_TILING_NONE)
+       if (INTEL_INFO(dev)->gen >= 4 ||
+           obj_priv->tiling_mode == I915_TILING_NONE)
                return 4096;
 
+       /*
+        * Previous chips need to be aligned to the size of the smallest
+        * fence register that can contain the object.
+        */
+       return i915_gem_get_gtt_size(obj_priv);
+}
+
+/**
+ * i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an
+ *                                      unfenced object
+ * @obj: object to check
+ *
+ * Return the required GTT alignment for an object, only taking into account
+ * unfenced tiled surface requirements.
+ */
+static uint32_t
+i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj_priv)
+{
+       struct drm_device *dev = obj_priv->base.dev;
+       int tile_height;
+
+       /*
+        * Minimum alignment is 4k (GTT page size) for sane hw.
+        */
+       if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) ||
+           obj_priv->tiling_mode == I915_TILING_NONE)
+               return 4096;
+
+       /*
+        * Older chips need unfenced tiled buffers to be aligned to the left
+        * edge of an even tile row (where tile rows are counted as if the bo is
+        * placed in a fenced gtt region).
+        */
+       if (IS_GEN2(dev) ||
+           (obj_priv->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
+               tile_height = 32;
+       else
+               tile_height = 8;
+
+       return tile_height * obj_priv->stride * 2;
+}
+
+static uint32_t
+i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv)
+{
+       struct drm_device *dev = obj_priv->base.dev;
+       uint32_t size;
+
+       /*
+        * Minimum alignment is 4k (GTT page size), but might be greater
+        * if a fence register is needed for the object.
+        */
+       if (INTEL_INFO(dev)->gen >= 4)
+               return obj_priv->base.size;
+
        /*
         * Previous chips need to be aligned to the size of the smallest
         * fence register that can contain the object.
         */
        if (INTEL_INFO(dev)->gen == 3)
-               start = 1024*1024;
+               size = 1024*1024;
        else
-               start = 512*1024;
+               size = 512*1024;
 
-       for (i = start; i < obj->size; i <<= 1)
-               ;
+       while (size < obj_priv->base.size)
+               size <<= 1;
 
-       return i;
+       return size;
 }
 
 /**
@@ -1466,6 +1571,7 @@ int
 i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_mmap_gtt *args = data;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
@@ -1485,29 +1591,24 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
        }
        obj_priv = to_intel_bo(obj);
 
+       if (obj->size > dev_priv->mm.gtt_mappable_end) {
+               ret = -E2BIG;
+               goto unlock;
+       }
+
        if (obj_priv->madv != I915_MADV_WILLNEED) {
                DRM_ERROR("Attempting to mmap a purgeable buffer\n");
                ret = -EINVAL;
                goto out;
        }
 
-       if (!obj_priv->mmap_offset) {
+       if (!obj->map_list.map) {
                ret = i915_gem_create_mmap_offset(obj);
                if (ret)
                        goto out;
        }
 
-       args->offset = obj_priv->mmap_offset;
-
-       /*
-        * Pull it into the GTT so that we have a page list (makes the
-        * initial fault faster and any subsequent flushing possible).
-        */
-       if (!obj_priv->agp_mem) {
-               ret = i915_gem_object_bind_to_gtt(obj, 0);
-               if (ret)
-                       goto out;
-       }
+       args->offset = (u64)obj->map_list.hash.key << PAGE_SHIFT;
 
 out:
        drm_gem_object_unreference(obj);
@@ -1516,19 +1617,62 @@ unlock:
        return ret;
 }
 
+static int
+i915_gem_object_get_pages_gtt(struct drm_gem_object *obj,
+                             gfp_t gfpmask)
+{
+       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+       int page_count, i;
+       struct address_space *mapping;
+       struct inode *inode;
+       struct page *page;
+
+       /* Get the list of pages out of our struct file.  They'll be pinned
+        * at this point until we release them.
+        */
+       page_count = obj->size / PAGE_SIZE;
+       BUG_ON(obj_priv->pages != NULL);
+       obj_priv->pages = drm_malloc_ab(page_count, sizeof(struct page *));
+       if (obj_priv->pages == NULL)
+               return -ENOMEM;
+
+       inode = obj->filp->f_path.dentry->d_inode;
+       mapping = inode->i_mapping;
+       for (i = 0; i < page_count; i++) {
+               page = read_cache_page_gfp(mapping, i,
+                                          GFP_HIGHUSER |
+                                          __GFP_COLD |
+                                          __GFP_RECLAIMABLE |
+                                          gfpmask);
+               if (IS_ERR(page))
+                       goto err_pages;
+
+               obj_priv->pages[i] = page;
+       }
+
+       if (obj_priv->tiling_mode != I915_TILING_NONE)
+               i915_gem_object_do_bit_17_swizzle(obj);
+
+       return 0;
+
+err_pages:
+       while (i--)
+               page_cache_release(obj_priv->pages[i]);
+
+       drm_free_large(obj_priv->pages);
+       obj_priv->pages = NULL;
+       return PTR_ERR(page);
+}
+
 static void
-i915_gem_object_put_pages(struct drm_gem_object *obj)
+i915_gem_object_put_pages_gtt(struct drm_gem_object *obj)
 {
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        int page_count = obj->size / PAGE_SIZE;
        int i;
 
-       BUG_ON(obj_priv->pages_refcount == 0);
        BUG_ON(obj_priv->madv == __I915_MADV_PURGED);
 
-       if (--obj_priv->pages_refcount != 0)
-               return;
-
        if (obj_priv->tiling_mode != I915_TILING_NONE)
                i915_gem_object_save_bit_17_swizzle(obj);
 
@@ -1555,9 +1699,7 @@ i915_gem_next_request_seqno(struct drm_device *dev,
                            struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-
-       ring->outstanding_lazy_request = true;
-       return dev_priv->next_seqno;
+       return ring->outstanding_lazy_request = dev_priv->next_seqno;
 }
 
 static void
@@ -1683,7 +1825,7 @@ i915_gem_process_flushing_list(struct drm_device *dev,
        }
 }
 
-uint32_t
+int
 i915_add_request(struct drm_device *dev,
                 struct drm_file *file,
                 struct drm_i915_gem_request *request,
@@ -1693,17 +1835,17 @@ i915_add_request(struct drm_device *dev,
        struct drm_i915_file_private *file_priv = NULL;
        uint32_t seqno;
        int was_empty;
+       int ret;
+
+       BUG_ON(request == NULL);
 
        if (file != NULL)
                file_priv = file->driver_priv;
 
-       if (request == NULL) {
-               request = kzalloc(sizeof(*request), GFP_KERNEL);
-               if (request == NULL)
-                       return 0;
-       }
+       ret = ring->add_request(ring, &seqno);
+       if (ret)
+           return ret;
 
-       seqno = ring->add_request(dev, ring, 0);
        ring->outstanding_lazy_request = false;
 
        request->seqno = seqno;
@@ -1727,7 +1869,7 @@ i915_add_request(struct drm_device *dev,
                        queue_delayed_work(dev_priv->wq,
                                           &dev_priv->mm.retire_work, HZ);
        }
-       return seqno;
+       return 0;
 }
 
 /**
@@ -1745,8 +1887,7 @@ i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring)
        if (INTEL_INFO(dev)->gen >= 4)
                flush_domains |= I915_GEM_DOMAIN_SAMPLER;
 
-       ring->flush(dev, ring,
-                       I915_GEM_DOMAIN_COMMAND, flush_domains);
+       ring->flush(ring, I915_GEM_DOMAIN_COMMAND, flush_domains);
 }
 
 static inline void
@@ -1853,7 +1994,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
 
        WARN_ON(i915_verify_lists(dev));
 
-       seqno = ring->get_seqno(dev, ring);
+       seqno = ring->get_seqno(ring);
        while (!list_empty(&ring->request_list)) {
                struct drm_i915_gem_request *request;
 
@@ -1894,7 +2035,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
 
        if (unlikely (dev_priv->trace_irq_seqno &&
                      i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) {
-               ring->user_irq_put(dev, ring);
+               ring->user_irq_put(ring);
                dev_priv->trace_irq_seqno = 0;
        }
 
@@ -1964,14 +2105,23 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
        if (atomic_read(&dev_priv->mm.wedged))
                return -EAGAIN;
 
-       if (ring->outstanding_lazy_request) {
-               seqno = i915_add_request(dev, NULL, NULL, ring);
-               if (seqno == 0)
+       if (seqno == ring->outstanding_lazy_request) {
+               struct drm_i915_gem_request *request;
+
+               request = kzalloc(sizeof(*request), GFP_KERNEL);
+               if (request == NULL)
                        return -ENOMEM;
+
+               ret = i915_add_request(dev, NULL, request, ring);
+               if (ret) {
+                       kfree(request);
+                       return ret;
+               }
+
+               seqno = request->seqno;
        }
-       BUG_ON(seqno == dev_priv->next_seqno);
 
-       if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
+       if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) {
                if (HAS_PCH_SPLIT(dev))
                        ier = I915_READ(DEIER) | I915_READ(GTIER);
                else
@@ -1985,21 +2135,19 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
 
                trace_i915_gem_request_wait_begin(dev, seqno);
 
-               ring->waiting_gem_seqno = seqno;
-               ring->user_irq_get(dev, ring);
+               ring->waiting_seqno = seqno;
+               ring->user_irq_get(ring);
                if (interruptible)
                        ret = wait_event_interruptible(ring->irq_queue,
-                               i915_seqno_passed(
-                                       ring->get_seqno(dev, ring), seqno)
+                               i915_seqno_passed(ring->get_seqno(ring), seqno)
                                || atomic_read(&dev_priv->mm.wedged));
                else
                        wait_event(ring->irq_queue,
-                               i915_seqno_passed(
-                                       ring->get_seqno(dev, ring), seqno)
+                               i915_seqno_passed(ring->get_seqno(ring), seqno)
                                || atomic_read(&dev_priv->mm.wedged));
 
-               ring->user_irq_put(dev, ring);
-               ring->waiting_gem_seqno = 0;
+               ring->user_irq_put(ring);
+               ring->waiting_seqno = 0;
 
                trace_i915_gem_request_wait_end(dev, seqno);
        }
@@ -2008,7 +2156,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
 
        if (ret && ret != -ERESTARTSYS)
                DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n",
-                         __func__, ret, seqno, ring->get_seqno(dev, ring),
+                         __func__, ret, seqno, ring->get_seqno(ring),
                          dev_priv->next_seqno);
 
        /* Directly dispatch request retiring.  While we have the work queue
@@ -2040,7 +2188,7 @@ i915_gem_flush_ring(struct drm_device *dev,
                    uint32_t invalidate_domains,
                    uint32_t flush_domains)
 {
-       ring->flush(dev, ring, invalidate_domains, flush_domains);
+       ring->flush(ring, invalidate_domains, flush_domains);
        i915_gem_process_flushing_list(dev, flush_domains, ring);
 }
 
@@ -2151,11 +2299,12 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
        drm_unbind_agp(obj_priv->agp_mem);
        drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
 
-       i915_gem_object_put_pages(obj);
-       BUG_ON(obj_priv->pages_refcount);
+       i915_gem_object_put_pages_gtt(obj);
 
-       i915_gem_info_remove_gtt(dev_priv, obj->size);
+       i915_gem_info_remove_gtt(dev_priv, obj_priv);
        list_del_init(&obj_priv->mm_list);
+       /* Avoid an unnecessary call to unbind on rebind. */
+       obj_priv->map_and_fenceable = true;
 
        drm_mm_put_block(obj_priv->gtt_space);
        obj_priv->gtt_space = NULL;
@@ -2210,72 +2359,16 @@ i915_gpu_idle(struct drm_device *dev)
        return 0;
 }
 
-static int
-i915_gem_object_get_pages(struct drm_gem_object *obj,
-                         gfp_t gfpmask)
+static void sandybridge_write_fence_reg(struct drm_gem_object *obj)
 {
-       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-       int page_count, i;
-       struct address_space *mapping;
-       struct inode *inode;
-       struct page *page;
-
-       BUG_ON(obj_priv->pages_refcount
-                       == DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT);
-
-       if (obj_priv->pages_refcount++ != 0)
-               return 0;
-
-       /* Get the list of pages out of our struct file.  They'll be pinned
-        * at this point until we release them.
-        */
-       page_count = obj->size / PAGE_SIZE;
-       BUG_ON(obj_priv->pages != NULL);
-       obj_priv->pages = drm_calloc_large(page_count, sizeof(struct page *));
-       if (obj_priv->pages == NULL) {
-               obj_priv->pages_refcount--;
-               return -ENOMEM;
-       }
-
-       inode = obj->filp->f_path.dentry->d_inode;
-       mapping = inode->i_mapping;
-       for (i = 0; i < page_count; i++) {
-               page = read_cache_page_gfp(mapping, i,
-                                          GFP_HIGHUSER |
-                                          __GFP_COLD |
-                                          __GFP_RECLAIMABLE |
-                                          gfpmask);
-               if (IS_ERR(page))
-                       goto err_pages;
-
-               obj_priv->pages[i] = page;
-       }
-
-       if (obj_priv->tiling_mode != I915_TILING_NONE)
-               i915_gem_object_do_bit_17_swizzle(obj);
-
-       return 0;
-
-err_pages:
-       while (i--)
-               page_cache_release(obj_priv->pages[i]);
-
-       drm_free_large(obj_priv->pages);
-       obj_priv->pages = NULL;
-       obj_priv->pages_refcount--;
-       return PTR_ERR(page);
-}
-
-static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg)
-{
-       struct drm_gem_object *obj = reg->obj;
        struct drm_device *dev = obj->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+       u32 size = i915_gem_get_gtt_size(obj_priv);
        int regnum = obj_priv->fence_reg;
        uint64_t val;
 
-       val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) &
+       val = (uint64_t)((obj_priv->gtt_offset + size - 4096) &
                    0xfffff000) << 32;
        val |= obj_priv->gtt_offset & 0xfffff000;
        val |= (uint64_t)((obj_priv->stride / 128) - 1) <<
@@ -2288,16 +2381,16 @@ static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg)
        I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (regnum * 8), val);
 }
 
-static void i965_write_fence_reg(struct drm_i915_fence_reg *reg)
+static void i965_write_fence_reg(struct drm_gem_object *obj)
 {
-       struct drm_gem_object *obj = reg->obj;
        struct drm_device *dev = obj->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+       u32 size = i915_gem_get_gtt_size(obj_priv);
        int regnum = obj_priv->fence_reg;
        uint64_t val;
 
-       val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) &
+       val = (uint64_t)((obj_priv->gtt_offset + size - 4096) &
                    0xfffff000) << 32;
        val |= obj_priv->gtt_offset & 0xfffff000;
        val |= ((obj_priv->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT;
@@ -2308,21 +2401,20 @@ static void i965_write_fence_reg(struct drm_i915_fence_reg *reg)
        I915_WRITE64(FENCE_REG_965_0 + (regnum * 8), val);
 }
 
-static void i915_write_fence_reg(struct drm_i915_fence_reg *reg)
+static void i915_write_fence_reg(struct drm_gem_object *obj)
 {
-       struct drm_gem_object *obj = reg->obj;
        struct drm_device *dev = obj->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-       int regnum = obj_priv->fence_reg;
+       u32 size = i915_gem_get_gtt_size(obj_priv);
+       uint32_t fence_reg, val, pitch_val;
        int tile_width;
-       uint32_t fence_reg, val;
-       uint32_t pitch_val;
 
        if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) ||
-           (obj_priv->gtt_offset & (obj->size - 1))) {
-               WARN(1, "%s: object 0x%08x not 1M or size (0x%zx) aligned\n",
-                    __func__, obj_priv->gtt_offset, obj->size);
+           (obj_priv->gtt_offset & (size - 1))) {
+               WARN(1, "%s: object 0x%08x [fenceable? %d] not 1M or size (0x%08x) aligned [gtt_space offset=%lx, size=%lx]\n",
+                    __func__, obj_priv->gtt_offset, obj_priv->map_and_fenceable, size,
+                    obj_priv->gtt_space->start, obj_priv->gtt_space->size);
                return;
        }
 
@@ -2345,23 +2437,24 @@ static void i915_write_fence_reg(struct drm_i915_fence_reg *reg)
        val = obj_priv->gtt_offset;
        if (obj_priv->tiling_mode == I915_TILING_Y)
                val |= 1 << I830_FENCE_TILING_Y_SHIFT;
-       val |= I915_FENCE_SIZE_BITS(obj->size);
+       val |= I915_FENCE_SIZE_BITS(size);
        val |= pitch_val << I830_FENCE_PITCH_SHIFT;
        val |= I830_FENCE_REG_VALID;
 
-       if (regnum < 8)
-               fence_reg = FENCE_REG_830_0 + (regnum * 4);
+       fence_reg = obj_priv->fence_reg;
+       if (fence_reg < 8)
+               fence_reg = FENCE_REG_830_0 + fence_reg * 4;
        else
-               fence_reg = FENCE_REG_945_8 + ((regnum - 8) * 4);
+               fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4;
        I915_WRITE(fence_reg, val);
 }
 
-static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
+static void i830_write_fence_reg(struct drm_gem_object *obj)
 {
-       struct drm_gem_object *obj = reg->obj;
        struct drm_device *dev = obj->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+       u32 size = i915_gem_get_gtt_size(obj_priv);
        int regnum = obj_priv->fence_reg;
        uint32_t val;
        uint32_t pitch_val;
@@ -2381,7 +2474,7 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
        val = obj_priv->gtt_offset;
        if (obj_priv->tiling_mode == I915_TILING_Y)
                val |= 1 << I830_FENCE_TILING_Y_SHIFT;
-       fence_size_bits = I830_FENCE_SIZE_BITS(obj->size);
+       fence_size_bits = I830_FENCE_SIZE_BITS(size);
        WARN_ON(fence_size_bits & ~0x00000f00);
        val |= fence_size_bits;
        val |= pitch_val << I830_FENCE_PITCH_SHIFT;
@@ -2393,10 +2486,9 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
 static int i915_find_fence_reg(struct drm_device *dev,
                               bool interruptible)
 {
-       struct drm_i915_fence_reg *reg = NULL;
-       struct drm_i915_gem_object *obj_priv = NULL;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_gem_object *obj = NULL;
+       struct drm_i915_fence_reg *reg;
+       struct drm_i915_gem_object *obj_priv = NULL;
        int i, avail, ret;
 
        /* First try to find a free reg */
@@ -2415,33 +2507,31 @@ static int i915_find_fence_reg(struct drm_device *dev,
                return -ENOSPC;
 
        /* None available, try to steal one or wait for a user to finish */
-       i = I915_FENCE_REG_NONE;
+       avail = I915_FENCE_REG_NONE;
        list_for_each_entry(reg, &dev_priv->mm.fence_list,
                            lru_list) {
-               obj = reg->obj;
-               obj_priv = to_intel_bo(obj);
-
+               obj_priv = to_intel_bo(reg->obj);
                if (obj_priv->pin_count)
                        continue;
 
                /* found one! */
-               i = obj_priv->fence_reg;
+               avail = obj_priv->fence_reg;
                break;
        }
 
-       BUG_ON(i == I915_FENCE_REG_NONE);
+       BUG_ON(avail == I915_FENCE_REG_NONE);
 
        /* We only have a reference on obj from the active list. put_fence_reg
         * might drop that one, causing a use-after-free in it. So hold a
         * private reference to obj like the other callers of put_fence_reg
         * (set_tiling ioctl) do. */
-       drm_gem_object_reference(obj);
-       ret = i915_gem_object_put_fence_reg(obj, interruptible);
-       drm_gem_object_unreference(obj);
+       drm_gem_object_reference(&obj_priv->base);
+       ret = i915_gem_object_put_fence_reg(&obj_priv->base, interruptible);
+       drm_gem_object_unreference(&obj_priv->base);
        if (ret != 0)
                return ret;
 
-       return i;
+       return avail;
 }
 
 /**
@@ -2506,22 +2596,23 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
 
        switch (INTEL_INFO(dev)->gen) {
        case 6:
-               sandybridge_write_fence_reg(reg);
+               sandybridge_write_fence_reg(obj);
                break;
        case 5:
        case 4:
-               i965_write_fence_reg(reg);
+               i965_write_fence_reg(obj);
                break;
        case 3:
-               i915_write_fence_reg(reg);
+               i915_write_fence_reg(obj);
                break;
        case 2:
-               i830_write_fence_reg(reg);
+               i830_write_fence_reg(obj);
                break;
        }
 
-       trace_i915_gem_object_get_fence(obj, obj_priv->fence_reg,
-                       obj_priv->tiling_mode);
+       trace_i915_gem_object_get_fence(obj,
+                                       obj_priv->fence_reg,
+                                       obj_priv->tiling_mode);
 
        return 0;
 }
@@ -2624,13 +2715,17 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
  * Finds free space in the GTT aperture and binds the object there.
  */
 static int
-i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
+i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
+                           unsigned alignment,
+                           bool map_and_fenceable)
 {
        struct drm_device *dev = obj->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        struct drm_mm_node *free_space;
-       gfp_t gfpmask =  __GFP_NORETRY | __GFP_NOWARN;
+       gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN;
+       u32 size, fence_size, fence_alignment, unfenced_alignment;
+       bool mappable, fenceable;
        int ret;
 
        if (obj_priv->madv != I915_MADV_WILLNEED) {
@@ -2638,47 +2733,73 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
                return -EINVAL;
        }
 
+       fence_size = i915_gem_get_gtt_size(obj_priv);
+       fence_alignment = i915_gem_get_gtt_alignment(obj_priv);
+       unfenced_alignment = i915_gem_get_unfenced_gtt_alignment(obj_priv);
+
        if (alignment == 0)
-               alignment = i915_gem_get_gtt_alignment(obj);
-       if (alignment & (i915_gem_get_gtt_alignment(obj) - 1)) {
+               alignment = map_and_fenceable ? fence_alignment :
+                                               unfenced_alignment;
+       if (map_and_fenceable && alignment & (fence_alignment - 1)) {
                DRM_ERROR("Invalid object alignment requested %u\n", alignment);
                return -EINVAL;
        }
 
+       size = map_and_fenceable ? fence_size : obj->size;
+
        /* If the object is bigger than the entire aperture, reject it early
         * before evicting everything in a vain attempt to find space.
         */
-       if (obj->size > dev_priv->mm.gtt_total) {
+       if (obj->size >
+           (map_and_fenceable ? dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) {
                DRM_ERROR("Attempting to bind an object larger than the aperture\n");
                return -E2BIG;
        }
 
  search_free:
-       free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
-                                       obj->size, alignment, 0);
-       if (free_space != NULL)
-               obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size,
-                                                      alignment);
+       if (map_and_fenceable)
+               free_space =
+                       drm_mm_search_free_in_range(&dev_priv->mm.gtt_space,
+                                                   size, alignment, 0,
+                                                   dev_priv->mm.gtt_mappable_end,
+                                                   0);
+       else
+               free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
+                                               size, alignment, 0);
+
+       if (free_space != NULL) {
+               if (map_and_fenceable)
+                       obj_priv->gtt_space =
+                               drm_mm_get_block_range_generic(free_space,
+                                                              size, alignment, 0,
+                                                              dev_priv->mm.gtt_mappable_end,
+                                                              0);
+               else
+                       obj_priv->gtt_space =
+                               drm_mm_get_block(free_space, size, alignment);
+       }
        if (obj_priv->gtt_space == NULL) {
                /* If the gtt is empty and we're still having trouble
                 * fitting our object in, we're out of memory.
                 */
-               ret = i915_gem_evict_something(dev, obj->size, alignment);
+               ret = i915_gem_evict_something(dev, size, alignment,
+                                              map_and_fenceable);
                if (ret)
                        return ret;
 
                goto search_free;
        }
 
-       ret = i915_gem_object_get_pages(obj, gfpmask);
+       ret = i915_gem_object_get_pages_gtt(obj, gfpmask);
        if (ret) {
                drm_mm_put_block(obj_priv->gtt_space);
                obj_priv->gtt_space = NULL;
 
                if (ret == -ENOMEM) {
                        /* first try to clear up some space from the GTT */
-                       ret = i915_gem_evict_something(dev, obj->size,
-                                                      alignment);
+                       ret = i915_gem_evict_something(dev, size,
+                                                      alignment,
+                                                      map_and_fenceable);
                        if (ret) {
                                /* now try to shrink everyone else */
                                if (gfpmask) {
@@ -2704,20 +2825,23 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
                                               obj_priv->gtt_space->start,
                                               obj_priv->agp_type);
        if (obj_priv->agp_mem == NULL) {
-               i915_gem_object_put_pages(obj);
+               i915_gem_object_put_pages_gtt(obj);
                drm_mm_put_block(obj_priv->gtt_space);
                obj_priv->gtt_space = NULL;
 
-               ret = i915_gem_evict_something(dev, obj->size, alignment);
+               ret = i915_gem_evict_something(dev, size,
+                                              alignment, map_and_fenceable);
                if (ret)
                        return ret;
 
                goto search_free;
        }
 
+       obj_priv->gtt_offset = obj_priv->gtt_space->start;
+
        /* keep track of bounds object by adding it to the inactive list */
        list_add_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
-       i915_gem_info_add_gtt(dev_priv, obj->size);
+       i915_gem_info_add_gtt(dev_priv, obj_priv);
 
        /* Assert that the object is not currently in any GPU domain. As it
         * wasn't in the GTT, there shouldn't be any way it could have been in
@@ -2726,8 +2850,16 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
        BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS);
        BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS);
 
-       obj_priv->gtt_offset = obj_priv->gtt_space->start;
-       trace_i915_gem_object_bind(obj, obj_priv->gtt_offset);
+       trace_i915_gem_object_bind(obj, obj_priv->gtt_offset, map_and_fenceable);
+
+       fenceable =
+               obj_priv->gtt_space->size == fence_size &&
+               (obj_priv->gtt_space->start & (fence_alignment -1)) == 0;
+
+       mappable =
+               obj_priv->gtt_offset + obj->size <= dev_priv->mm.gtt_mappable_end;
+
+       obj_priv->map_and_fenceable = mappable && fenceable;
 
        return 0;
 }
@@ -2755,22 +2887,16 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
                                       bool pipelined)
 {
        struct drm_device *dev = obj->dev;
-       uint32_t old_write_domain;
 
        if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
                return 0;
 
        /* Queue the GPU write cache flushing we need. */
-       old_write_domain = obj->write_domain;
        i915_gem_flush_ring(dev, NULL,
                            to_intel_bo(obj)->ring,
                            0, obj->write_domain);
        BUG_ON(obj->write_domain);
 
-       trace_i915_gem_object_change_domain(obj,
-                                           obj->read_domains,
-                                           old_write_domain);
-
        if (pipelined)
                return 0;
 
@@ -2790,6 +2916,8 @@ i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj)
         * to it immediately go to main memory as far as we know, so there's
         * no chipset flush.  It also doesn't land in render cache.
         */
+       i915_gem_release_mmap(obj);
+
        old_write_domain = obj->write_domain;
        obj->write_domain = 0;
 
@@ -3093,16 +3221,12 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
  */
 static void
 i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
-                                 struct intel_ring_buffer *ring)
+                                 struct intel_ring_buffer *ring,
+                                 struct change_domains *cd)
 {
-       struct drm_device               *dev = obj->dev;
-       struct drm_i915_private         *dev_priv = dev->dev_private;
        struct drm_i915_gem_object      *obj_priv = to_intel_bo(obj);
        uint32_t                        invalidate_domains = 0;
        uint32_t                        flush_domains = 0;
-       uint32_t                        old_read_domains;
-
-       intel_mark_busy(dev, obj);
 
        /*
         * If the object isn't moving to a new write domain,
@@ -3110,8 +3234,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
         */
        if (obj->pending_write_domain == 0)
                obj->pending_read_domains |= obj->read_domains;
-       else
-               obj_priv->dirty = 1;
 
        /*
         * Flush the current write domain if
@@ -3134,7 +3256,9 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
        if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU)
                i915_gem_clflush_object(obj);
 
-       old_read_domains = obj->read_domains;
+       /* blow away mappings if mapped through GTT */
+       if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_GTT)
+               i915_gem_release_mmap(obj);
 
        /* The actual obj->write_domain will be updated with
         * pending_write_domain after we emit the accumulated flush for all
@@ -3144,18 +3268,13 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
         */
        if (flush_domains == 0 && obj->pending_write_domain == 0)
                obj->pending_write_domain = obj->write_domain;
-       obj->read_domains = obj->pending_read_domains;
 
-       dev->invalidate_domains |= invalidate_domains;
-       dev->flush_domains |= flush_domains;
+       cd->invalidate_domains |= invalidate_domains;
+       cd->flush_domains |= flush_domains;
        if (flush_domains & I915_GEM_GPU_DOMAINS)
-               dev_priv->mm.flush_rings |= obj_priv->ring->id;
+               cd->flush_rings |= obj_priv->ring->id;
        if (invalidate_domains & I915_GEM_GPU_DOMAINS)
-               dev_priv->mm.flush_rings |= ring->id;
-
-       trace_i915_gem_object_change_domain(obj,
-                                           old_read_domains,
-                                           obj->write_domain);
+               cd->flush_rings |= ring->id;
 }
 
 /**
@@ -3454,25 +3573,30 @@ i915_gem_execbuffer_pin(struct drm_device *dev,
        int ret, i, retry;
 
        /* attempt to pin all of the buffers into the GTT */
-       for (retry = 0; retry < 2; retry++) {
+       retry = 0;
+       do {
                ret = 0;
                for (i = 0; i < count; i++) {
                        struct drm_i915_gem_exec_object2 *entry = &exec_list[i];
-                       struct drm_i915_gem_object *obj= to_intel_bo(object_list[i]);
+                       struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]);
                        bool need_fence =
                                entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
                                obj->tiling_mode != I915_TILING_NONE;
 
+                       /* g33/pnv can't fence buffers in the unmappable part */
+                       bool need_mappable =
+                               entry->relocation_count ? true : need_fence;
+
                        /* Check fence reg constraints and rebind if necessary */
-                       if (need_fence &&
-                           !i915_gem_object_fence_offset_ok(&obj->base,
-                                                            obj->tiling_mode)) {
+                       if (need_mappable && !obj->map_and_fenceable) {
                                ret = i915_gem_object_unbind(&obj->base);
                                if (ret)
                                        break;
                        }
 
-                       ret = i915_gem_object_pin(&obj->base, entry->alignment);
+                       ret = i915_gem_object_pin(&obj->base,
+                                                 entry->alignment,
+                                                 need_mappable);
                        if (ret)
                                break;
 
@@ -3496,18 +3620,18 @@ i915_gem_execbuffer_pin(struct drm_device *dev,
                while (i--)
                        i915_gem_object_unpin(object_list[i]);
 
-               if (ret == 0)
-                       break;
-
-               if (ret != -ENOSPC || retry)
+               if (ret != -ENOSPC || retry > 1)
                        return ret;
 
-               ret = i915_gem_evict_everything(dev);
+               /* First attempt, just clear anything that is purgeable.
+                * Second attempt, clear the entire GTT.
+                */
+               ret = i915_gem_evict_everything(dev, retry == 0);
                if (ret)
                        return ret;
-       }
 
-       return 0;
+               retry++;
+       } while (1);
 }
 
 static int
@@ -3517,30 +3641,26 @@ i915_gem_execbuffer_move_to_gpu(struct drm_device *dev,
                                struct drm_gem_object **objects,
                                int count)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct change_domains cd;
        int ret, i;
 
-       /* Zero the global flush/invalidate flags. These
-        * will be modified as new domains are computed
-        * for each object
-        */
-       dev->invalidate_domains = 0;
-       dev->flush_domains = 0;
-       dev_priv->mm.flush_rings = 0;
+       cd.invalidate_domains = 0;
+       cd.flush_domains = 0;
+       cd.flush_rings = 0;
        for (i = 0; i < count; i++)
-               i915_gem_object_set_to_gpu_domain(objects[i], ring);
+               i915_gem_object_set_to_gpu_domain(objects[i], ring, &cd);
 
-       if (dev->invalidate_domains | dev->flush_domains) {
+       if (cd.invalidate_domains | cd.flush_domains) {
 #if WATCH_EXEC
                DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
                          __func__,
-                        dev->invalidate_domains,
-                        dev->flush_domains);
+                        cd.invalidate_domains,
+                        cd.flush_domains);
 #endif
                i915_gem_flush(dev, file,
-                              dev->invalidate_domains,
-                              dev->flush_domains,
-                              dev_priv->mm.flush_rings);
+                              cd.invalidate_domains,
+                              cd.flush_domains,
+                              cd.flush_rings);
        }
 
        for (i = 0; i < count; i++) {
@@ -3591,17 +3711,17 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
                return 0;
 
        ret = 0;
-       if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
+       if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) {
                /* And wait for the seqno passing without holding any locks and
                 * causing extra latency for others. This is safe as the irq
                 * generation is designed to be run atomically and so is
                 * lockless.
                 */
-               ring->user_irq_get(dev, ring);
+               ring->user_irq_get(ring);
                ret = wait_event_interruptible(ring->irq_queue,
-                                              i915_seqno_passed(ring->get_seqno(dev, ring), seqno)
+                                              i915_seqno_passed(ring->get_seqno(ring), seqno)
                                               || atomic_read(&dev_priv->mm.wedged));
-               ring->user_irq_put(dev, ring);
+               ring->user_irq_put(ring);
 
                if (ret == 0 && atomic_read(&dev_priv->mm.wedged))
                        ret = -EIO;
@@ -3664,7 +3784,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_gem_object **object_list = NULL;
        struct drm_gem_object *batch_obj;
-       struct drm_i915_gem_object *obj_priv;
        struct drm_clip_rect *cliprects = NULL;
        struct drm_i915_gem_request *request = NULL;
        int ret, i, flips;
@@ -3759,6 +3878,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 
        /* Look up object handles */
        for (i = 0; i < args->buffer_count; i++) {
+               struct drm_i915_gem_object *obj_priv;
+
                object_list[i] = drm_gem_object_lookup(dev, file,
                                                       exec_list[i].handle);
                if (object_list[i] == NULL) {
@@ -3821,15 +3942,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        if (ret)
                goto err;
 
-       for (i = 0; i < args->buffer_count; i++) {
-               struct drm_gem_object *obj = object_list[i];
-               uint32_t old_write_domain = obj->write_domain;
-               obj->write_domain = obj->pending_write_domain;
-               trace_i915_gem_object_change_domain(obj,
-                                                   obj->read_domains,
-                                                   old_write_domain);
-       }
-
 #if WATCH_COHERENCY
        for (i = 0; i < args->buffer_count; i++) {
                i915_gem_object_check_coherency(object_list[i],
@@ -3865,46 +3977,60 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                        else
                                flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
 
-                       intel_ring_begin(dev, ring, 2);
-                       intel_ring_emit(dev, ring,
-                                       MI_WAIT_FOR_EVENT | flip_mask);
-                       intel_ring_emit(dev, ring, MI_NOOP);
-                       intel_ring_advance(dev, ring);
+                       ret = intel_ring_begin(ring, 2);
+                       if (ret)
+                               goto err;
+
+                       intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask);
+                       intel_ring_emit(ring, MI_NOOP);
+                       intel_ring_advance(ring);
                }
        }
 
        /* Exec the batchbuffer */
-       ret = ring->dispatch_gem_execbuffer(dev, ring, args,
-                                           cliprects, exec_offset);
+       ret = ring->dispatch_execbuffer(ring, args, cliprects, exec_offset);
        if (ret) {
                DRM_ERROR("dispatch failed %d\n", ret);
                goto err;
        }
 
-       /*
-        * Ensure that the commands in the batch buffer are
-        * finished before the interrupt fires
-        */
-       i915_retire_commands(dev, ring);
-
        for (i = 0; i < args->buffer_count; i++) {
                struct drm_gem_object *obj = object_list[i];
 
+               obj->read_domains = obj->pending_read_domains;
+               obj->write_domain = obj->pending_write_domain;
+
                i915_gem_object_move_to_active(obj, ring);
-               if (obj->write_domain)
-                       list_move_tail(&to_intel_bo(obj)->gpu_write_list,
+               if (obj->write_domain) {
+                       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+                       obj_priv->dirty = 1;
+                       list_move_tail(&obj_priv->gpu_write_list,
                                       &ring->gpu_write_list);
+                       intel_mark_busy(dev, obj);
+               }
+
+               trace_i915_gem_object_change_domain(obj,
+                                                   obj->read_domains,
+                                                   obj->write_domain);
        }
 
-       i915_add_request(dev, file, request, ring);
-       request = NULL;
+       /*
+        * Ensure that the commands in the batch buffer are
+        * finished before the interrupt fires
+        */
+       i915_retire_commands(dev, ring);
+
+       if (i915_add_request(dev, file, request, ring))
+               i915_gem_next_request_seqno(dev, ring);
+       else
+               request = NULL;
 
 err:
        for (i = 0; i < args->buffer_count; i++) {
-               if (object_list[i]) {
-                       obj_priv = to_intel_bo(object_list[i]);
-                       obj_priv->in_execbuffer = false;
-               }
+               if (object_list[i] == NULL)
+                   break;
+
+               to_intel_bo(object_list[i])->in_execbuffer = false;
                drm_gem_object_unreference(object_list[i]);
        }
 
@@ -4064,7 +4190,8 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
 }
 
 int
-i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
+i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment,
+                   bool map_and_fenceable)
 {
        struct drm_device *dev = obj->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4072,15 +4199,19 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
        int ret;
 
        BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
+       BUG_ON(map_and_fenceable && !map_and_fenceable);
        WARN_ON(i915_verify_lists(dev));
 
        if (obj_priv->gtt_space != NULL) {
-               if (alignment == 0)
-                       alignment = i915_gem_get_gtt_alignment(obj);
-               if (obj_priv->gtt_offset & (alignment - 1)) {
+               if ((alignment && obj_priv->gtt_offset & (alignment - 1)) ||
+                   (map_and_fenceable && !obj_priv->map_and_fenceable)) {
                        WARN(obj_priv->pin_count,
-                            "bo is already pinned with incorrect alignment: offset=%x, req.alignment=%x\n",
-                            obj_priv->gtt_offset, alignment);
+                            "bo is already pinned with incorrect alignment:"
+                            " offset=%x, req.alignment=%x, req.map_and_fenceable=%d,"
+                            " obj->map_and_fenceable=%d\n",
+                            obj_priv->gtt_offset, alignment,
+                            map_and_fenceable,
+                            obj_priv->map_and_fenceable);
                        ret = i915_gem_object_unbind(obj);
                        if (ret)
                                return ret;
@@ -4088,22 +4219,19 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
        }
 
        if (obj_priv->gtt_space == NULL) {
-               ret = i915_gem_object_bind_to_gtt(obj, alignment);
+               ret = i915_gem_object_bind_to_gtt(obj, alignment,
+                                                 map_and_fenceable);
                if (ret)
                        return ret;
        }
 
-       obj_priv->pin_count++;
-
-       /* If the object is not active and not pending a flush,
-        * remove it from the inactive list
-        */
-       if (obj_priv->pin_count == 1) {
-               i915_gem_info_add_pin(dev_priv, obj->size);
+       if (obj_priv->pin_count++ == 0) {
+               i915_gem_info_add_pin(dev_priv, obj_priv, map_and_fenceable);
                if (!obj_priv->active)
                        list_move_tail(&obj_priv->mm_list,
                                       &dev_priv->mm.pinned_list);
        }
+       BUG_ON(!obj_priv->pin_mappable && map_and_fenceable);
 
        WARN_ON(i915_verify_lists(dev));
        return 0;
@@ -4117,19 +4245,14 @@ i915_gem_object_unpin(struct drm_gem_object *obj)
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
        WARN_ON(i915_verify_lists(dev));
-       obj_priv->pin_count--;
-       BUG_ON(obj_priv->pin_count < 0);
+       BUG_ON(obj_priv->pin_count == 0);
        BUG_ON(obj_priv->gtt_space == NULL);
 
-       /* If the object is no longer pinned, and is
-        * neither active nor being flushed, then stick it on
-        * the inactive list
-        */
-       if (obj_priv->pin_count == 0) {
+       if (--obj_priv->pin_count == 0) {
                if (!obj_priv->active)
                        list_move_tail(&obj_priv->mm_list,
                                       &dev_priv->mm.inactive_list);
-               i915_gem_info_remove_pin(dev_priv, obj->size);
+               i915_gem_info_remove_pin(dev_priv, obj_priv);
        }
        WARN_ON(i915_verify_lists(dev));
 }
@@ -4170,7 +4293,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
        obj_priv->user_pin_count++;
        obj_priv->pin_filp = file_priv;
        if (obj_priv->user_pin_count == 1) {
-               ret = i915_gem_object_pin(obj, args->alignment);
+               ret = i915_gem_object_pin(obj, args->alignment, true);
                if (ret)
                        goto out;
        }
@@ -4363,6 +4486,8 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
        INIT_LIST_HEAD(&obj->ring_list);
        INIT_LIST_HEAD(&obj->gpu_write_list);
        obj->madv = I915_MADV_WILLNEED;
+       /* Avoid an unnecessary call to unbind on the first bind. */
+       obj->map_and_fenceable = true;
 
        return &obj->base;
 }
@@ -4388,7 +4513,7 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj)
                return;
        }
 
-       if (obj_priv->mmap_offset)
+       if (obj->map_list.map)
                i915_gem_free_mmap_offset(obj);
 
        drm_gem_object_release(obj);
@@ -4436,7 +4561,7 @@ i915_gem_idle(struct drm_device *dev)
 
        /* Under UMS, be paranoid and evict. */
        if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
-               ret = i915_gem_evict_inactive(dev);
+               ret = i915_gem_evict_inactive(dev, false);
                if (ret) {
                        mutex_unlock(&dev->struct_mutex);
                        return ret;
@@ -4482,7 +4607,7 @@ i915_gem_init_pipe_control(struct drm_device *dev)
        obj_priv = to_intel_bo(obj);
        obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
 
-       ret = i915_gem_object_pin(obj, 4096);
+       ret = i915_gem_object_pin(obj, 4096, true);
        if (ret)
                goto err_unref;
 
@@ -4555,9 +4680,9 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
        return 0;
 
 cleanup_bsd_ring:
-       intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+       intel_cleanup_ring_buffer(&dev_priv->bsd_ring);
 cleanup_render_ring:
-       intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
+       intel_cleanup_ring_buffer(&dev_priv->render_ring);
 cleanup_pipe_control:
        if (HAS_PIPE_CONTROL(dev))
                i915_gem_cleanup_pipe_control(dev);
@@ -4569,9 +4694,9 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
 
-       intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
-       intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
-       intel_cleanup_ring_buffer(dev, &dev_priv->blt_ring);
+       intel_cleanup_ring_buffer(&dev_priv->render_ring);
+       intel_cleanup_ring_buffer(&dev_priv->bsd_ring);
+       intel_cleanup_ring_buffer(&dev_priv->blt_ring);
        if (HAS_PIPE_CONTROL(dev))
                i915_gem_cleanup_pipe_control(dev);
 }
@@ -4678,9 +4803,6 @@ i915_gem_load(struct drm_device *dev)
        INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
                          i915_gem_retire_work_handler);
        init_completion(&dev_priv->error_completion);
-       spin_lock(&shrink_list_lock);
-       list_add(&dev_priv->mm.shrink_list, &shrink_list);
-       spin_unlock(&shrink_list_lock);
 
        /* On GEN3 we really need to make sure the ARB C3 LP bit is set */
        if (IS_GEN3(dev)) {
@@ -4723,6 +4845,10 @@ i915_gem_load(struct drm_device *dev)
        }
        i915_gem_detect_bit_6_swizzle(dev);
        init_waitqueue_head(&dev_priv->pending_flip_queue);
+
+       dev_priv->mm.inactive_shrinker.shrink = i915_gem_inactive_shrink;
+       dev_priv->mm.inactive_shrinker.seeks = DEFAULT_SEEKS;
+       register_shrinker(&dev_priv->mm.inactive_shrinker);
 }
 
 /*
@@ -4794,33 +4920,35 @@ void i915_gem_free_all_phys_object(struct drm_device *dev)
 void i915_gem_detach_phys_object(struct drm_device *dev,
                                 struct drm_gem_object *obj)
 {
-       struct drm_i915_gem_object *obj_priv;
+       struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping;
+       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+       char *vaddr;
        int i;
-       int ret;
        int page_count;
 
-       obj_priv = to_intel_bo(obj);
        if (!obj_priv->phys_obj)
                return;
-
-       ret = i915_gem_object_get_pages(obj, 0);
-       if (ret)
-               goto out;
+       vaddr = obj_priv->phys_obj->handle->vaddr;
 
        page_count = obj->size / PAGE_SIZE;
 
        for (i = 0; i < page_count; i++) {
-               char *dst = kmap_atomic(obj_priv->pages[i]);
-               char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
-
-               memcpy(dst, src, PAGE_SIZE);
-               kunmap_atomic(dst);
+               struct page *page = read_cache_page_gfp(mapping, i,
+                                                       GFP_HIGHUSER | __GFP_RECLAIMABLE);
+               if (!IS_ERR(page)) {
+                       char *dst = kmap_atomic(page);
+                       memcpy(dst, vaddr + i*PAGE_SIZE, PAGE_SIZE);
+                       kunmap_atomic(dst);
+
+                       drm_clflush_pages(&page, 1);
+
+                       set_page_dirty(page);
+                       mark_page_accessed(page);
+                       page_cache_release(page);
+               }
        }
-       drm_clflush_pages(obj_priv->pages, page_count);
        drm_agp_chipset_flush(dev);
 
-       i915_gem_object_put_pages(obj);
-out:
        obj_priv->phys_obj->cur_obj = NULL;
        obj_priv->phys_obj = NULL;
 }
@@ -4831,6 +4959,7 @@ i915_gem_attach_phys_object(struct drm_device *dev,
                            int id,
                            int align)
 {
+       struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv;
        int ret = 0;
@@ -4854,7 +4983,7 @@ i915_gem_attach_phys_object(struct drm_device *dev,
                                                obj->size, align);
                if (ret) {
                        DRM_ERROR("failed to init phys object %d size: %zu\n", id, obj->size);
-                       goto out;
+                       return ret;
                }
        }
 
@@ -4862,27 +4991,27 @@ i915_gem_attach_phys_object(struct drm_device *dev,
        obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1];
        obj_priv->phys_obj->cur_obj = obj;
 
-       ret = i915_gem_object_get_pages(obj, 0);
-       if (ret) {
-               DRM_ERROR("failed to get page list\n");
-               goto out;
-       }
-
        page_count = obj->size / PAGE_SIZE;
 
        for (i = 0; i < page_count; i++) {
-               char *src = kmap_atomic(obj_priv->pages[i]);
-               char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
+               struct page *page;
+               char *dst, *src;
 
+               page = read_cache_page_gfp(mapping, i,
+                                          GFP_HIGHUSER | __GFP_RECLAIMABLE);
+               if (IS_ERR(page))
+                       return PTR_ERR(page);
+
+               src = kmap_atomic(page);
+               dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
                memcpy(dst, src, PAGE_SIZE);
                kunmap_atomic(src);
-       }
 
-       i915_gem_object_put_pages(obj);
+               mark_page_accessed(page);
+               page_cache_release(page);
+       }
 
        return 0;
-out:
-       return ret;
 }
 
 static int
@@ -4948,144 +5077,68 @@ i915_gpu_is_active(struct drm_device *dev)
 }
 
 static int
-i915_gem_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
+i915_gem_inactive_shrink(struct shrinker *shrinker,
+                        int nr_to_scan,
+                        gfp_t gfp_mask)
 {
-       drm_i915_private_t *dev_priv, *next_dev;
-       struct drm_i915_gem_object *obj_priv, *next_obj;
-       int cnt = 0;
-       int would_deadlock = 1;
+       struct drm_i915_private *dev_priv =
+               container_of(shrinker,
+                            struct drm_i915_private,
+                            mm.inactive_shrinker);
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_i915_gem_object *obj, *next;
+       int cnt;
+
+       if (!mutex_trylock(&dev->struct_mutex))
+               return 0;
 
        /* "fast-path" to count number of available objects */
        if (nr_to_scan == 0) {
-               spin_lock(&shrink_list_lock);
-               list_for_each_entry(dev_priv, &shrink_list, mm.shrink_list) {
-                       struct drm_device *dev = dev_priv->dev;
-
-                       if (mutex_trylock(&dev->struct_mutex)) {
-                               list_for_each_entry(obj_priv,
-                                                   &dev_priv->mm.inactive_list,
-                                                   mm_list)
-                                       cnt++;
-                               mutex_unlock(&dev->struct_mutex);
-                       }
-               }
-               spin_unlock(&shrink_list_lock);
-
-               return (cnt / 100) * sysctl_vfs_cache_pressure;
+               cnt = 0;
+               list_for_each_entry(obj,
+                                   &dev_priv->mm.inactive_list,
+                                   mm_list)
+                       cnt++;
+               mutex_unlock(&dev->struct_mutex);
+               return cnt / 100 * sysctl_vfs_cache_pressure;
        }
 
-       spin_lock(&shrink_list_lock);
-
 rescan:
        /* first scan for clean buffers */
-       list_for_each_entry_safe(dev_priv, next_dev,
-                                &shrink_list, mm.shrink_list) {
-               struct drm_device *dev = dev_priv->dev;
-
-               if (! mutex_trylock(&dev->struct_mutex))
-                       continue;
-
-               spin_unlock(&shrink_list_lock);
-               i915_gem_retire_requests(dev);
+       i915_gem_retire_requests(dev);
 
-               list_for_each_entry_safe(obj_priv, next_obj,
-                                        &dev_priv->mm.inactive_list,
-                                        mm_list) {
-                       if (i915_gem_object_is_purgeable(obj_priv)) {
-                               i915_gem_object_unbind(&obj_priv->base);
-                               if (--nr_to_scan <= 0)
-                                       break;
-                       }
+       list_for_each_entry_safe(obj, next,
+                                &dev_priv->mm.inactive_list,
+                                mm_list) {
+               if (i915_gem_object_is_purgeable(obj)) {
+                       i915_gem_object_unbind(&obj->base);
+                       if (--nr_to_scan == 0)
+                               break;
                }
-
-               spin_lock(&shrink_list_lock);
-               mutex_unlock(&dev->struct_mutex);
-
-               would_deadlock = 0;
-
-               if (nr_to_scan <= 0)
-                       break;
        }
 
        /* second pass, evict/count anything still on the inactive list */
-       list_for_each_entry_safe(dev_priv, next_dev,
-                                &shrink_list, mm.shrink_list) {
-               struct drm_device *dev = dev_priv->dev;
-
-               if (! mutex_trylock(&dev->struct_mutex))
-                       continue;
-
-               spin_unlock(&shrink_list_lock);
-
-               list_for_each_entry_safe(obj_priv, next_obj,
-                                        &dev_priv->mm.inactive_list,
-                                        mm_list) {
-                       if (nr_to_scan > 0) {
-                               i915_gem_object_unbind(&obj_priv->base);
-                               nr_to_scan--;
-                       } else
-                               cnt++;
-               }
-
-               spin_lock(&shrink_list_lock);
-               mutex_unlock(&dev->struct_mutex);
-
-               would_deadlock = 0;
-       }
-
-       if (nr_to_scan) {
-               int active = 0;
-
+       cnt = 0;
+       list_for_each_entry_safe(obj, next,
+                                &dev_priv->mm.inactive_list,
+                                mm_list) {
+               if (nr_to_scan) {
+                       i915_gem_object_unbind(&obj->base);
+                       nr_to_scan--;
+               } else
+                       cnt++;
+       }
+
+       if (nr_to_scan && i915_gpu_is_active(dev)) {
                /*
                 * We are desperate for pages, so as a last resort, wait
                 * for the GPU to finish and discard whatever we can.
                 * This has a dramatic impact to reduce the number of
                 * OOM-killer events whilst running the GPU aggressively.
                 */
-               list_for_each_entry(dev_priv, &shrink_list, mm.shrink_list) {
-                       struct drm_device *dev = dev_priv->dev;
-
-                       if (!mutex_trylock(&dev->struct_mutex))
-                               continue;
-
-                       spin_unlock(&shrink_list_lock);
-
-                       if (i915_gpu_is_active(dev)) {
-                               i915_gpu_idle(dev);
-                               active++;
-                       }
-
-                       spin_lock(&shrink_list_lock);
-                       mutex_unlock(&dev->struct_mutex);
-               }
-
-               if (active)
+               if (i915_gpu_idle(dev) == 0)
                        goto rescan;
        }
-
-       spin_unlock(&shrink_list_lock);
-
-       if (would_deadlock)
-               return -1;
-       else if (cnt > 0)
-               return (cnt / 100) * sysctl_vfs_cache_pressure;
-       else
-               return 0;
-}
-
-static struct shrinker shrinker = {
-       .shrink = i915_gem_shrink,
-       .seeks = DEFAULT_SEEKS,
-};
-
-__init void
-i915_gem_shrinker_init(void)
-{
-    register_shrinker(&shrinker);
-}
-
-__exit void
-i915_gem_shrinker_exit(void)
-{
-    unregister_shrinker(&shrinker);
+       mutex_unlock(&dev->struct_mutex);
+       return cnt / 100 * sysctl_vfs_cache_pressure;
 }
index d8ae7d1..3f6f336 100644 (file)
@@ -41,7 +41,8 @@ mark_free(struct drm_i915_gem_object *obj_priv,
 }
 
 int
-i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment)
+i915_gem_evict_something(struct drm_device *dev, int min_size,
+                        unsigned alignment, bool mappable)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct list_head eviction_list, unwind_list;
@@ -51,9 +52,17 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
        i915_gem_retire_requests(dev);
 
        /* Re-check for free space after retiring requests */
-       if (drm_mm_search_free(&dev_priv->mm.gtt_space,
-                              min_size, alignment, 0))
-               return 0;
+       if (mappable) {
+               if (drm_mm_search_free_in_range(&dev_priv->mm.gtt_space,
+                                               min_size, alignment, 0,
+                                               dev_priv->mm.gtt_mappable_end,
+                                               0))
+                       return 0;
+       } else {
+               if (drm_mm_search_free(&dev_priv->mm.gtt_space,
+                                      min_size, alignment, 0))
+                       return 0;
+       }
 
        /*
         * The goal is to evict objects and amalgamate space in LRU order.
@@ -79,7 +88,12 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
         */
 
        INIT_LIST_HEAD(&unwind_list);
-       drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment);
+       if (mappable)
+               drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space, min_size,
+                                           alignment, 0,
+                                           dev_priv->mm.gtt_mappable_end);
+       else
+               drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment);
 
        /* First see if there is a large enough contiguous idle region... */
        list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) {
@@ -157,7 +171,7 @@ found:
 }
 
 int
-i915_gem_evict_everything(struct drm_device *dev)
+i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        int ret;
@@ -176,36 +190,22 @@ i915_gem_evict_everything(struct drm_device *dev)
 
        BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
 
-       ret = i915_gem_evict_inactive(dev);
-       if (ret)
-               return ret;
-
-       lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
-                      list_empty(&dev_priv->mm.flushing_list) &&
-                      list_empty(&dev_priv->mm.active_list));
-       BUG_ON(!lists_empty);
-
-       return 0;
+       return i915_gem_evict_inactive(dev, purgeable_only);
 }
 
 /** Unbinds all inactive objects. */
 int
-i915_gem_evict_inactive(struct drm_device *dev)
+i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-
-       while (!list_empty(&dev_priv->mm.inactive_list)) {
-               struct drm_gem_object *obj;
-               int ret;
-
-               obj = &list_first_entry(&dev_priv->mm.inactive_list,
-                                       struct drm_i915_gem_object,
-                                       mm_list)->base;
-
-               ret = i915_gem_object_unbind(obj);
-               if (ret != 0) {
-                       DRM_ERROR("Error unbinding object: %d\n", ret);
-                       return ret;
+       struct drm_i915_gem_object *obj, *next;
+
+       list_for_each_entry_safe(obj, next,
+                                &dev_priv->mm.inactive_list, mm_list) {
+               if (!purgeable_only || obj->madv != I915_MADV_WILLNEED) {
+                       int ret = i915_gem_object_unbind(&obj->base);
+                       if (ret)
+                               return ret;
                }
        }
 
index af352de..a517b48 100644 (file)
@@ -181,7 +181,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
 }
 
 /* Check pitch constriants for all chips & tiling formats */
-bool
+static bool
 i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
 {
        int tile_width;
@@ -232,25 +232,23 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
        return true;
 }
 
-bool
-i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
+/* Is the current GTT allocation valid for the change in tiling? */
+static bool
+i915_gem_object_fence_ok(struct drm_gem_object *obj, int tiling_mode)
 {
-       struct drm_device *dev = obj->dev;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-
-       if (obj_priv->gtt_space == NULL)
-               return true;
+       u32 size;
 
        if (tiling_mode == I915_TILING_NONE)
                return true;
 
-       if (INTEL_INFO(dev)->gen >= 4)
+       if (INTEL_INFO(obj->dev)->gen >= 4)
                return true;
 
-       if (obj_priv->gtt_offset & (obj->size - 1))
-               return false;
+       if (!obj_priv->gtt_space)
+               return true;
 
-       if (IS_GEN3(dev)) {
+       if (INTEL_INFO(obj->dev)->gen == 3) {
                if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
                        return false;
        } else {
@@ -258,6 +256,24 @@ i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
                        return false;
        }
 
+       /*
+        * Previous chips need to be aligned to the size of the smallest
+        * fence register that can contain the object.
+        */
+       if (INTEL_INFO(obj->dev)->gen == 3)
+               size = 1024*1024;
+       else
+               size = 512*1024;
+
+       while (size < obj_priv->base.size)
+               size <<= 1;
+
+       if (obj_priv->gtt_space->size != size)
+               return false;
+
+       if (obj_priv->gtt_offset & (size - 1))
+               return false;
+
        return true;
 }
 
@@ -331,7 +347,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                 * tiling mode. Otherwise we can just leave it alone, but
                 * need to ensure that any fence register is cleared.
                 */
-               if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode))
+               if (!i915_gem_object_fence_ok(obj, args->tiling_mode))
                        ret = i915_gem_object_unbind(obj);
                else if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
                        ret = i915_gem_object_put_fence_reg(obj, true);
index 729fd0c..2103452 100644 (file)
@@ -297,8 +297,8 @@ static void notify_ring(struct drm_device *dev,
                        struct intel_ring_buffer *ring)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 seqno = ring->get_seqno(dev, ring);
-       ring->irq_gem_seqno = seqno;
+       u32 seqno = ring->get_seqno(ring);
+       ring->irq_seqno = seqno;
        trace_i915_gem_request_complete(dev, seqno);
        wake_up_all(&ring->irq_queue);
        dev_priv->hangcheck_count = 0;
@@ -520,30 +520,30 @@ i915_get_bbaddr(struct drm_device *dev, u32 *ring)
 }
 
 static u32
-i915_ringbuffer_last_batch(struct drm_device *dev)
+i915_ringbuffer_last_batch(struct drm_device *dev,
+                          struct intel_ring_buffer *ring)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 head, bbaddr;
-       u32 *ring;
+       u32 *val;
 
        /* Locate the current position in the ringbuffer and walk back
         * to find the most recently dispatched batch buffer.
         */
        bbaddr = 0;
-       head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
-       ring = (u32 *)(dev_priv->render_ring.virtual_start + head);
+       head = I915_READ_HEAD(ring) & HEAD_ADDR;
+       val = (u32 *)(ring->virtual_start + head);
 
-       while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) {
-               bbaddr = i915_get_bbaddr(dev, ring);
+       while (--val >= (u32 *)ring->virtual_start) {
+               bbaddr = i915_get_bbaddr(dev, val);
                if (bbaddr)
                        break;
        }
 
        if (bbaddr == 0) {
-               ring = (u32 *)(dev_priv->render_ring.virtual_start
-                               + dev_priv->render_ring.size);
-               while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) {
-                       bbaddr = i915_get_bbaddr(dev, ring);
+               val = (u32 *)(ring->virtual_start + ring->size);
+               while (--val >= (u32 *)ring->virtual_start) {
+                       bbaddr = i915_get_bbaddr(dev, val);
                        if (bbaddr)
                                break;
                }
@@ -586,19 +586,33 @@ static void i915_capture_error_state(struct drm_device *dev)
        DRM_DEBUG_DRIVER("generating error event\n");
 
        error->seqno =
-               dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring);
+               dev_priv->render_ring.get_seqno(&dev_priv->render_ring);
        error->eir = I915_READ(EIR);
        error->pgtbl_er = I915_READ(PGTBL_ER);
        error->pipeastat = I915_READ(PIPEASTAT);
        error->pipebstat = I915_READ(PIPEBSTAT);
        error->instpm = I915_READ(INSTPM);
-       if (INTEL_INFO(dev)->gen < 4) {
-               error->ipeir = I915_READ(IPEIR);
-               error->ipehr = I915_READ(IPEHR);
-               error->instdone = I915_READ(INSTDONE);
-               error->acthd = I915_READ(ACTHD);
-               error->bbaddr = 0;
-       } else {
+       error->error = 0;
+       if (INTEL_INFO(dev)->gen >= 6) {
+               error->error = I915_READ(ERROR_GEN6);
+
+               error->bcs_acthd = I915_READ(BCS_ACTHD);
+               error->bcs_ipehr = I915_READ(BCS_IPEHR);
+               error->bcs_ipeir = I915_READ(BCS_IPEIR);
+               error->bcs_instdone = I915_READ(BCS_INSTDONE);
+               error->bcs_seqno = 0;
+               if (dev_priv->blt_ring.get_seqno)
+                       error->bcs_seqno = dev_priv->blt_ring.get_seqno(&dev_priv->blt_ring);
+
+               error->vcs_acthd = I915_READ(VCS_ACTHD);
+               error->vcs_ipehr = I915_READ(VCS_IPEHR);
+               error->vcs_ipeir = I915_READ(VCS_IPEIR);
+               error->vcs_instdone = I915_READ(VCS_INSTDONE);
+               error->vcs_seqno = 0;
+               if (dev_priv->bsd_ring.get_seqno)
+                       error->vcs_seqno = dev_priv->bsd_ring.get_seqno(&dev_priv->bsd_ring);
+       }
+       if (INTEL_INFO(dev)->gen >= 4) {
                error->ipeir = I915_READ(IPEIR_I965);
                error->ipehr = I915_READ(IPEHR_I965);
                error->instdone = I915_READ(INSTDONE_I965);
@@ -606,9 +620,15 @@ static void i915_capture_error_state(struct drm_device *dev)
                error->instdone1 = I915_READ(INSTDONE1);
                error->acthd = I915_READ(ACTHD_I965);
                error->bbaddr = I915_READ64(BB_ADDR);
+       } else {
+               error->ipeir = I915_READ(IPEIR);
+               error->ipehr = I915_READ(IPEHR);
+               error->instdone = I915_READ(INSTDONE);
+               error->acthd = I915_READ(ACTHD);
+               error->bbaddr = 0;
        }
 
-       bbaddr = i915_ringbuffer_last_batch(dev);
+       bbaddr = i915_ringbuffer_last_batch(dev, &dev_priv->render_ring);
 
        /* Grab the current batchbuffer, most likely to have crashed. */
        batchbuffer[0] = NULL;
@@ -708,6 +728,7 @@ static void i915_capture_error_state(struct drm_device *dev)
                        error->active_bo[i].tiling = obj_priv->tiling_mode;
                        error->active_bo[i].dirty = obj_priv->dirty;
                        error->active_bo[i].purgeable = obj_priv->madv != I915_MADV_WILLNEED;
+                       error->active_bo[i].ring = obj_priv->ring->id;
 
                        if (++i == count)
                                break;
@@ -870,7 +891,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
  * so userspace knows something bad happened (should trigger collection
  * of a ring dump etc.).
  */
-static void i915_handle_error(struct drm_device *dev, bool wedged)
+void i915_handle_error(struct drm_device *dev, bool wedged)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -1101,12 +1122,13 @@ static int i915_emit_irq(struct drm_device * dev)
        if (master_priv->sarea_priv)
                master_priv->sarea_priv->last_enqueue = dev_priv->counter;
 
-       BEGIN_LP_RING(4);
-       OUT_RING(MI_STORE_DWORD_INDEX);
-       OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
-       OUT_RING(dev_priv->counter);
-       OUT_RING(MI_USER_INTERRUPT);
-       ADVANCE_LP_RING();
+       if (BEGIN_LP_RING(4) == 0) {
+               OUT_RING(MI_STORE_DWORD_INDEX);
+               OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+               OUT_RING(dev_priv->counter);
+               OUT_RING(MI_USER_INTERRUPT);
+               ADVANCE_LP_RING();
+       }
 
        return dev_priv->counter;
 }
@@ -1117,7 +1139,7 @@ void i915_trace_irq_get(struct drm_device *dev, u32 seqno)
        struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
 
        if (dev_priv->trace_irq_seqno == 0)
-               render_ring->user_irq_get(dev, render_ring);
+               render_ring->user_irq_get(render_ring);
 
        dev_priv->trace_irq_seqno = seqno;
 }
@@ -1141,10 +1163,10 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
        if (master_priv->sarea_priv)
                master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
 
-       render_ring->user_irq_get(dev, render_ring);
+       render_ring->user_irq_get(render_ring);
        DRM_WAIT_ON(ret, dev_priv->render_ring.irq_queue, 3 * DRM_HZ,
                    READ_BREADCRUMB(dev_priv) >= irq_nr);
-       render_ring->user_irq_put(dev, render_ring);
+       render_ring->user_irq_put(render_ring);
 
        if (ret == -EBUSY) {
                DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
@@ -1306,12 +1328,29 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
        return -EINVAL;
 }
 
-static struct drm_i915_gem_request *
-i915_get_tail_request(struct drm_device *dev)
+static u32
+ring_last_seqno(struct intel_ring_buffer *ring)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       return list_entry(dev_priv->render_ring.request_list.prev,
-                       struct drm_i915_gem_request, list);
+       return list_entry(ring->request_list.prev,
+                         struct drm_i915_gem_request, list)->seqno;
+}
+
+static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
+{
+       if (list_empty(&ring->request_list) ||
+           i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) {
+               /* Issue a wake-up to catch stuck h/w. */
+               if (ring->waiting_seqno && waitqueue_active(&ring->irq_queue)) {
+                       DRM_ERROR("Hangcheck timer elapsed... %s idle [waiting on %d, at %d], missed IRQ?\n",
+                                 ring->name,
+                                 ring->waiting_seqno,
+                                 ring->get_seqno(ring));
+                       wake_up_all(&ring->irq_queue);
+                       *err = true;
+               }
+               return true;
+       }
+       return false;
 }
 
 /**
@@ -1325,6 +1364,17 @@ 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, instdone, instdone1;
+       bool err = false;
+
+       /* If all work is done then ACTHD clearly hasn't advanced. */
+       if (i915_hangcheck_ring_idle(&dev_priv->render_ring, &err) &&
+           i915_hangcheck_ring_idle(&dev_priv->bsd_ring, &err) &&
+           i915_hangcheck_ring_idle(&dev_priv->blt_ring, &err)) {
+               dev_priv->hangcheck_count = 0;
+               if (err)
+                       goto repeat;
+               return;
+       }
 
        if (INTEL_INFO(dev)->gen < 4) {
                acthd = I915_READ(ACTHD);
@@ -1336,38 +1386,6 @@ void i915_hangcheck_elapsed(unsigned long data)
                instdone1 = I915_READ(INSTDONE1);
        }
 
-       /* If all work is done then ACTHD clearly hasn't advanced. */
-       if (list_empty(&dev_priv->render_ring.request_list) ||
-               i915_seqno_passed(dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring),
-                                 i915_get_tail_request(dev)->seqno)) {
-               bool missed_wakeup = false;
-
-               dev_priv->hangcheck_count = 0;
-
-               /* Issue a wake-up to catch stuck h/w. */
-               if (dev_priv->render_ring.waiting_gem_seqno &&
-                   waitqueue_active(&dev_priv->render_ring.irq_queue)) {
-                       wake_up_all(&dev_priv->render_ring.irq_queue);
-                       missed_wakeup = true;
-               }
-
-               if (dev_priv->bsd_ring.waiting_gem_seqno &&
-                   waitqueue_active(&dev_priv->bsd_ring.irq_queue)) {
-                       wake_up_all(&dev_priv->bsd_ring.irq_queue);
-                       missed_wakeup = true;
-               }
-
-               if (dev_priv->blt_ring.waiting_gem_seqno &&
-                   waitqueue_active(&dev_priv->blt_ring.irq_queue)) {
-                       wake_up_all(&dev_priv->blt_ring.irq_queue);
-                       missed_wakeup = true;
-               }
-
-               if (missed_wakeup)
-                       DRM_ERROR("Hangcheck timer elapsed... GPU idle, missed IRQ.\n");
-               return;
-       }
-
        if (dev_priv->last_acthd == acthd &&
            dev_priv->last_instdone == instdone &&
            dev_priv->last_instdone1 == instdone1) {
@@ -1380,11 +1398,11 @@ void i915_hangcheck_elapsed(unsigned long data)
                                 * and break the hang. This should work on
                                 * all but the second generation chipsets.
                                 */
-                               u32 tmp = I915_READ(PRB0_CTL);
+                               struct intel_ring_buffer *ring = &dev_priv->render_ring;
+                               u32 tmp = I915_READ_CTL(ring);
                                if (tmp & RING_WAIT) {
-                                       I915_WRITE(PRB0_CTL, tmp);
-                                       POSTING_READ(PRB0_CTL);
-                                       goto out;
+                                       I915_WRITE_CTL(ring, tmp);
+                                       goto repeat;
                                }
                        }
 
@@ -1399,7 +1417,7 @@ void i915_hangcheck_elapsed(unsigned long data)
                dev_priv->last_instdone1 = instdone1;
        }
 
-out:
+repeat:
        /* Reset timer case chip hangs without another request being added */
        mod_timer(&dev_priv->hangcheck_timer,
                  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
index 25ed911..886c0e0 100644 (file)
  * Instruction and interrupt control regs
  */
 #define PGTBL_ER       0x02024
-#define PRB0_TAIL      0x02030
-#define PRB0_HEAD      0x02034
-#define PRB0_START     0x02038
-#define PRB0_CTL       0x0203c
 #define RENDER_RING_BASE       0x02000
 #define BSD_RING_BASE          0x04000
 #define GEN6_BSD_RING_BASE     0x12000
 #define   RING_INVALID         0x00000000
 #define   RING_WAIT_I8XX       (1<<0) /* gen2, PRBx_HEAD */
 #define   RING_WAIT            (1<<11) /* gen3+, PRBx_CTL */
+#if 0
+#define PRB0_TAIL      0x02030
+#define PRB0_HEAD      0x02034
+#define PRB0_START     0x02038
+#define PRB0_CTL       0x0203c
 #define PRB1_TAIL      0x02040 /* 915+ only */
 #define PRB1_HEAD      0x02044 /* 915+ only */
 #define PRB1_START     0x02048 /* 915+ only */
 #define PRB1_CTL       0x0204c /* 915+ only */
+#endif
 #define IPEIR_I965     0x02064
 #define IPEHR_I965     0x02068
 #define INSTDONE_I965  0x0206c
 #define INSTDONE       0x02090
 #define NOPID          0x02094
 #define HWSTAM         0x02098
+#define VCS_INSTDONE   0x1206C
+#define VCS_IPEIR      0x12064
+#define VCS_IPEHR      0x12068
+#define VCS_ACTHD      0x12074
+#define BCS_INSTDONE   0x2206C
+#define BCS_IPEIR      0x22064
+#define BCS_IPEHR      0x22068
+#define BCS_ACTHD      0x22074
+
+#define ERROR_GEN6     0x040a0
+
+/* GM45+ chicken bits -- debug workaround bits that may be required
+ * for various sorts of correct behavior.  The top 16 bits of each are
+ * the enables for writing to the corresponding low bit.
+ */
+#define _3D_CHICKEN    0x02084
+#define _3D_CHICKEN2   0x0208c
+/* Disables pipelining of read flushes past the SF-WIZ interface.
+ * Required on all Ironlake steppings according to the B-Spec, but the
+ * particular danger of not doing so is not specified.
+ */
+# define _3D_CHICKEN2_WM_READ_PIPELINED                        (1 << 14)
+#define _3D_CHICKEN3   0x02090
 
 #define MI_MODE                0x0209c
 # define VS_TIMER_DISPATCH                             (1 << 6)
 #define GTIER   0x4401c
 
 #define ILK_DISPLAY_CHICKEN2   0x42004
+/* Required on all Ironlake and Sandybridge according to the B-Spec. */
+#define  ILK_ELPIN_409_SELECT  (1 << 25)
 #define  ILK_DPARB_GATE        (1<<22)
 #define  ILK_VSDPFD_FULL       (1<<21)
 #define ILK_DSPCLK_GATE                0x42020
 #define  EDP_LINK_TRAIN_800MV_0DB_SNB_B                (0x38<<22)
 #define  EDP_LINK_TRAIN_VOL_EMP_MASK_SNB       (0x3f<<22)
 
+#define  FORCEWAKE                             0xA18C
 #endif /* _I915_REG_H_ */
index fea97a2..34ef49f 100644 (file)
@@ -35,22 +35,25 @@ TRACE_EVENT(i915_gem_object_create,
 
 TRACE_EVENT(i915_gem_object_bind,
 
-           TP_PROTO(struct drm_gem_object *obj, u32 gtt_offset),
+           TP_PROTO(struct drm_gem_object *obj, u32 gtt_offset, bool mappable),
 
-           TP_ARGS(obj, gtt_offset),
+           TP_ARGS(obj, gtt_offset, mappable),
 
            TP_STRUCT__entry(
                             __field(struct drm_gem_object *, obj)
                             __field(u32, gtt_offset)
+                            __field(bool, mappable)
                             ),
 
            TP_fast_assign(
                           __entry->obj = obj;
                           __entry->gtt_offset = gtt_offset;
+                          __entry->mappable = mappable;
                           ),
 
-           TP_printk("obj=%p, gtt_offset=%08x",
-                     __entry->obj, __entry->gtt_offset)
+           TP_printk("obj=%p, gtt_offset=%08x%s",
+                     __entry->obj, __entry->gtt_offset,
+                     __entry->mappable ? ", mappable" : "")
 );
 
 TRACE_EVENT(i915_gem_object_change_domain,
@@ -298,6 +301,29 @@ TRACE_EVENT(i915_flip_complete,
            TP_printk("plane=%d, obj=%p", __entry->plane, __entry->obj)
 );
 
+TRACE_EVENT(i915_reg_rw,
+           TP_PROTO(int cmd, uint32_t reg, uint64_t val, int len),
+
+           TP_ARGS(cmd, reg, val, len),
+
+           TP_STRUCT__entry(
+                   __field(int, cmd)
+                   __field(uint32_t, reg)
+                   __field(uint64_t, val)
+                   __field(int, len)
+                   ),
+
+           TP_fast_assign(
+                   __entry->cmd = cmd;
+                   __entry->reg = reg;
+                   __entry->val = (uint64_t)val;
+                   __entry->len = len;
+                   ),
+
+           TP_printk("cmd=%c, reg=0x%x, val=0x%llx, len=%d",
+                     __entry->cmd, __entry->reg, __entry->val, __entry->len)
+);
+
 #endif /* _I915_TRACE_H_ */
 
 /* This part must be outside protection */
index bee24b1..3fa5aaa 100644 (file)
@@ -1461,7 +1461,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
                BUG();
        }
 
-       ret = i915_gem_object_pin(obj, alignment);
+       ret = i915_gem_object_pin(obj, alignment, true);
        if (ret)
                return ret;
 
@@ -1474,8 +1474,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
         * framebuffer compression.  For simplicity, we always install
         * a fence as the cost is not that onerous.
         */
-       if (obj_priv->fence_reg == I915_FENCE_REG_NONE &&
-           obj_priv->tiling_mode != I915_TILING_NONE) {
+       if (obj_priv->tiling_mode != I915_TILING_NONE) {
                ret = i915_gem_object_get_fence_reg(obj, false);
                if (ret)
                        goto err_unpin;
@@ -1996,17 +1995,17 @@ static void intel_flush_display_plane(struct drm_device *dev,
 static void intel_clear_scanline_wait(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
        u32 tmp;
 
        if (IS_GEN2(dev))
                /* Can't break the hang on i8xx */
                return;
 
-       tmp = I915_READ(PRB0_CTL);
-       if (tmp & RING_WAIT) {
-               I915_WRITE(PRB0_CTL, tmp);
-               POSTING_READ(PRB0_CTL);
-       }
+       ring = &dev_priv->render_ring;
+       tmp = I915_READ_CTL(ring);
+       if (tmp & RING_WAIT)
+               I915_WRITE_CTL(ring, tmp);
 }
 
 static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
@@ -4378,7 +4377,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        /* we only need to pin inside GTT if cursor is non-phy */
        mutex_lock(&dev->struct_mutex);
        if (!dev_priv->info->cursor_needs_physical) {
-               ret = i915_gem_object_pin(bo, PAGE_SIZE);
+               ret = i915_gem_object_pin(bo, PAGE_SIZE, true);
                if (ret) {
                        DRM_ERROR("failed to pin cursor bo\n");
                        goto fail_locked;
@@ -5115,22 +5114,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        if (ret)
                goto cleanup_objs;
 
-       /* Block clients from rendering to the new back buffer until
-        * the flip occurs and the object is no longer visible.
-        */
-       atomic_add(1 << intel_crtc->plane,
-                  &to_intel_bo(work->old_fb_obj)->pending_flip);
-
-       work->pending_flip_obj = obj;
-       obj_priv = to_intel_bo(obj);
-
        if (IS_GEN3(dev) || IS_GEN2(dev)) {
                u32 flip_mask;
 
                /* Can't queue multiple flips, so wait for the previous
                 * one to finish before executing the next.
                 */
-               BEGIN_LP_RING(2);
+               ret = BEGIN_LP_RING(2);
+               if (ret)
+                       goto cleanup_objs;
+
                if (intel_crtc->plane)
                        flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
                else
@@ -5140,13 +5133,25 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                ADVANCE_LP_RING();
        }
 
+       work->pending_flip_obj = obj;
+       obj_priv = to_intel_bo(obj);
+
        work->enable_stall_check = true;
 
        /* Offset into the new buffer for cases of shared fbs between CRTCs */
        offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8;
 
-       BEGIN_LP_RING(4);
-       switch(INTEL_INFO(dev)->gen) {
+       ret = BEGIN_LP_RING(4);
+       if (ret)
+               goto cleanup_objs;
+
+       /* Block clients from rendering to the new back buffer until
+        * the flip occurs and the object is no longer visible.
+        */
+       atomic_add(1 << intel_crtc->plane,
+                  &to_intel_bo(work->old_fb_obj)->pending_flip);
+
+       switch (INTEL_INFO(dev)->gen) {
        case 2:
                OUT_RING(MI_DISPLAY_FLIP |
                         MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
@@ -5536,7 +5541,7 @@ intel_alloc_context_page(struct drm_device *dev)
        }
 
        mutex_lock(&dev->struct_mutex);
-       ret = i915_gem_object_pin(ctx, 4096);
+       ret = i915_gem_object_pin(ctx, 4096, true);
        if (ret) {
                DRM_ERROR("failed to pin power context: %d\n", ret);
                goto err_unref;
@@ -5824,6 +5829,16 @@ void intel_init_clock_gating(struct drm_device *dev)
                                   ILK_DPFC_DIS2 |
                                   ILK_CLK_FBC);
                }
+
+               I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                          I915_READ(ILK_DISPLAY_CHICKEN2) |
+                          ILK_ELPIN_409_SELECT);
+
+               if (IS_GEN5(dev)) {
+                       I915_WRITE(_3D_CHICKEN2,
+                                  _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
+                                  _3D_CHICKEN2_WM_READ_PIPELINED);
+               }
                return;
        } else if (IS_G4X(dev)) {
                uint32_t dspclk_gate;
@@ -5874,16 +5889,17 @@ void intel_init_clock_gating(struct drm_device *dev)
                        struct drm_i915_gem_object *obj_priv;
                        obj_priv = to_intel_bo(dev_priv->renderctx);
                        if (obj_priv) {
-                               BEGIN_LP_RING(4);
-                               OUT_RING(MI_SET_CONTEXT);
-                               OUT_RING(obj_priv->gtt_offset |
-                                               MI_MM_SPACE_GTT |
-                                               MI_SAVE_EXT_STATE_EN |
-                                               MI_RESTORE_EXT_STATE_EN |
-                                               MI_RESTORE_INHIBIT);
-                               OUT_RING(MI_NOOP);
-                               OUT_RING(MI_FLUSH);
-                               ADVANCE_LP_RING();
+                               if (BEGIN_LP_RING(4) == 0) {
+                                       OUT_RING(MI_SET_CONTEXT);
+                                       OUT_RING(obj_priv->gtt_offset |
+                                                MI_MM_SPACE_GTT |
+                                                MI_SAVE_EXT_STATE_EN |
+                                                MI_RESTORE_EXT_STATE_EN |
+                                                MI_RESTORE_INHIBIT);
+                                       OUT_RING(MI_NOOP);
+                                       OUT_RING(MI_FLUSH);
+                                       ADVANCE_LP_RING();
+                               }
                        }
                } else
                        DRM_DEBUG_KMS("Failed to allocate render context."
index 3dba086..58040f6 100644 (file)
@@ -85,8 +85,9 @@ static u32 get_reserved(struct intel_gpio *gpio)
 
        /* On most chips, these bits must be preserved in software. */
        if (!IS_I830(dev) && !IS_845G(dev))
-               reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE |
-                                                  GPIO_CLOCK_PULLUP_DISABLE);
+               reserved = I915_READ_NOTRACE(gpio->reg) &
+                                            (GPIO_DATA_PULLUP_DISABLE |
+                                             GPIO_CLOCK_PULLUP_DISABLE);
 
        return reserved;
 }
@@ -96,9 +97,9 @@ static int get_clock(void *data)
        struct intel_gpio *gpio = data;
        struct drm_i915_private *dev_priv = gpio->dev_priv;
        u32 reserved = get_reserved(gpio);
-       I915_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK);
-       I915_WRITE(gpio->reg, reserved);
-       return (I915_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0;
+       I915_WRITE_NOTRACE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK);
+       I915_WRITE_NOTRACE(gpio->reg, reserved);
+       return (I915_READ_NOTRACE(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0;
 }
 
 static int get_data(void *data)
@@ -106,9 +107,9 @@ static int get_data(void *data)
        struct intel_gpio *gpio = data;
        struct drm_i915_private *dev_priv = gpio->dev_priv;
        u32 reserved = get_reserved(gpio);
-       I915_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK);
-       I915_WRITE(gpio->reg, reserved);
-       return (I915_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0;
+       I915_WRITE_NOTRACE(gpio->reg, reserved | GPIO_DATA_DIR_MASK);
+       I915_WRITE_NOTRACE(gpio->reg, reserved);
+       return (I915_READ_NOTRACE(gpio->reg) & GPIO_DATA_VAL_IN) != 0;
 }
 
 static void set_clock(void *data, int state_high)
@@ -124,7 +125,7 @@ static void set_clock(void *data, int state_high)
                clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
                        GPIO_CLOCK_VAL_MASK;
 
-       I915_WRITE(gpio->reg, reserved | clock_bits);
+       I915_WRITE_NOTRACE(gpio->reg, reserved | clock_bits);
        POSTING_READ(gpio->reg);
 }
 
@@ -141,7 +142,7 @@ static void set_data(void *data, int state_high)
                data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
                        GPIO_DATA_VAL_MASK;
 
-       I915_WRITE(gpio->reg, reserved | data_bits);
+       I915_WRITE_NOTRACE(gpio->reg, reserved | data_bits);
        POSTING_READ(gpio->reg);
 }
 
index 02ff0a4..ec8ffac 100644 (file)
@@ -221,11 +221,12 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
        int ret;
 
        BUG_ON(overlay->last_flip_req);
-       overlay->last_flip_req =
-               i915_add_request(dev, NULL, request, &dev_priv->render_ring);
-       if (overlay->last_flip_req == 0)
-               return -ENOMEM;
-
+       ret = i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+       if (ret) {
+           kfree(request);
+           return ret;
+       }
+       overlay->last_flip_req = request->seqno;
        overlay->flip_tail = tail;
        ret = i915_do_wait_request(dev,
                                   overlay->last_flip_req, true,
@@ -289,6 +290,7 @@ i830_deactivate_pipe_a(struct drm_device *dev)
 static int intel_overlay_on(struct intel_overlay *overlay)
 {
        struct drm_device *dev = overlay->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_request *request;
        int pipe_a_quirk = 0;
        int ret;
@@ -308,7 +310,12 @@ static int intel_overlay_on(struct intel_overlay *overlay)
                goto out;
        }
 
-       BEGIN_LP_RING(4);
+       ret = BEGIN_LP_RING(4);
+       if (ret) {
+               kfree(request);
+               goto out;
+       }
+
        OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
        OUT_RING(overlay->flip_addr | OFC_UPDATE);
        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
@@ -332,6 +339,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
        struct drm_i915_gem_request *request;
        u32 flip_addr = overlay->flip_addr;
        u32 tmp;
+       int ret;
 
        BUG_ON(!overlay->active);
 
@@ -347,13 +355,22 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
        if (tmp & (1 << 17))
                DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
 
-       BEGIN_LP_RING(2);
+       ret = BEGIN_LP_RING(2);
+       if (ret) {
+               kfree(request);
+               return ret;
+       }
        OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
        OUT_RING(flip_addr);
         ADVANCE_LP_RING();
 
-       overlay->last_flip_req =
-               i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+       ret = i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+       if (ret) {
+               kfree(request);
+               return ret;
+       }
+
+       overlay->last_flip_req = request->seqno;
        return 0;
 }
 
@@ -389,8 +406,10 @@ static int intel_overlay_off(struct intel_overlay *overlay,
                             bool interruptible)
 {
        struct drm_device *dev = overlay->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 flip_addr = overlay->flip_addr;
        struct drm_i915_gem_request *request;
+       int ret;
 
        BUG_ON(!overlay->active);
 
@@ -404,7 +423,11 @@ static int intel_overlay_off(struct intel_overlay *overlay,
         * of the hw. Do it in both cases */
        flip_addr |= OFC_UPDATE;
 
-       BEGIN_LP_RING(6);
+       ret = BEGIN_LP_RING(6);
+       if (ret) {
+               kfree(request);
+               return ret;
+       }
        /* wait for overlay to go idle */
        OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
        OUT_RING(flip_addr);
@@ -467,7 +490,12 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
                if (request == NULL)
                        return -ENOMEM;
 
-               BEGIN_LP_RING(2);
+               ret = BEGIN_LP_RING(2);
+               if (ret) {
+                       kfree(request);
+                       return ret;
+               }
+
                OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
                OUT_RING(MI_NOOP);
                ADVANCE_LP_RING();
@@ -753,7 +781,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
        if (ret != 0)
                return ret;
 
-       ret = i915_gem_object_pin(new_bo, PAGE_SIZE);
+       ret = i915_gem_object_pin(new_bo, PAGE_SIZE, true);
        if (ret != 0)
                return ret;
 
@@ -1397,7 +1425,7 @@ void intel_setup_overlay(struct drm_device *dev)
                 }
                overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
        } else {
-               ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
+               ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true);
                if (ret) {
                         DRM_ERROR("failed to pin overlay register bo\n");
                         goto out_free_bo;
index b83306f..1db860d 100644 (file)
@@ -49,11 +49,11 @@ static u32 i915_gem_get_seqno(struct drm_device *dev)
 }
 
 static void
-render_ring_flush(struct drm_device *dev,
-                 struct intel_ring_buffer *ring,
+render_ring_flush(struct intel_ring_buffer *ring,
                  u32   invalidate_domains,
                  u32   flush_domains)
 {
+       struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 cmd;
 
@@ -112,43 +112,40 @@ render_ring_flush(struct drm_device *dev,
 #if WATCH_EXEC
                DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd);
 #endif
-               intel_ring_begin(dev, ring, 2);
-               intel_ring_emit(dev, ring, cmd);
-               intel_ring_emit(dev, ring, MI_NOOP);
-               intel_ring_advance(dev, ring);
+               if (intel_ring_begin(ring, 2) == 0) {
+                       intel_ring_emit(ring, cmd);
+                       intel_ring_emit(ring, MI_NOOP);
+                       intel_ring_advance(ring);
+               }
        }
 }
 
-static void ring_write_tail(struct drm_device *dev,
-                           struct intel_ring_buffer *ring,
+static void ring_write_tail(struct intel_ring_buffer *ring,
                            u32 value)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_private_t *dev_priv = ring->dev->dev_private;
        I915_WRITE_TAIL(ring, value);
 }
 
-u32 intel_ring_get_active_head(struct drm_device *dev,
-                              struct intel_ring_buffer *ring)
+u32 intel_ring_get_active_head(struct intel_ring_buffer *ring)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       u32 acthd_reg = INTEL_INFO(dev)->gen >= 4 ?
+       drm_i915_private_t *dev_priv = ring->dev->dev_private;
+       u32 acthd_reg = INTEL_INFO(ring->dev)->gen >= 4 ?
                        RING_ACTHD(ring->mmio_base) : ACTHD;
 
        return I915_READ(acthd_reg);
 }
 
-static int init_ring_common(struct drm_device *dev,
-                           struct intel_ring_buffer *ring)
+static int init_ring_common(struct intel_ring_buffer *ring)
 {
+       drm_i915_private_t *dev_priv = ring->dev->dev_private;
+       struct drm_i915_gem_object *obj_priv = to_intel_bo(ring->gem_object);
        u32 head;
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_i915_gem_object *obj_priv;
-       obj_priv = to_intel_bo(ring->gem_object);
 
        /* Stop the ring if it's running. */
        I915_WRITE_CTL(ring, 0);
        I915_WRITE_HEAD(ring, 0);
-       ring->write_tail(dev, ring, 0);
+       ring->write_tail(ring, 0);
 
        /* Initialize the ring. */
        I915_WRITE_START(ring, obj_priv->gtt_offset);
@@ -176,12 +173,13 @@ static int init_ring_common(struct drm_device *dev,
        }
 
        I915_WRITE_CTL(ring,
-                       ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES)
+                       ((ring->size - PAGE_SIZE) & RING_NR_PAGES)
                        | RING_REPORT_64K | RING_VALID);
 
-       head = I915_READ_HEAD(ring) & HEAD_ADDR;
        /* If the head is still not zero, the ring is dead */
-       if (head != 0) {
+       if ((I915_READ_CTL(ring) & RING_VALID) == 0 ||
+           I915_READ_START(ring) != obj_priv->gtt_offset ||
+           (I915_READ_HEAD(ring) & HEAD_ADDR) != 0) {
                DRM_ERROR("%s initialization failed "
                                "ctl %08x head %08x tail %08x start %08x\n",
                                ring->name,
@@ -192,8 +190,8 @@ static int init_ring_common(struct drm_device *dev,
                return -EIO;
        }
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               i915_kernel_lost_context(dev);
+       if (!drm_core_check_feature(ring->dev, DRIVER_MODESET))
+               i915_kernel_lost_context(ring->dev);
        else {
                ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
                ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
@@ -204,29 +202,29 @@ static int init_ring_common(struct drm_device *dev,
        return 0;
 }
 
-static int init_render_ring(struct drm_device *dev,
-                           struct intel_ring_buffer *ring)
+static int init_render_ring(struct intel_ring_buffer *ring)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       int ret = init_ring_common(dev, ring);
-       int mode;
+       struct drm_device *dev = ring->dev;
+       int ret = init_ring_common(ring);
 
        if (INTEL_INFO(dev)->gen > 3) {
-               mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
+               drm_i915_private_t *dev_priv = dev->dev_private;
+               int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
                if (IS_GEN6(dev))
                        mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
                I915_WRITE(MI_MODE, mode);
        }
+
        return ret;
 }
 
-#define PIPE_CONTROL_FLUSH(addr)                                       \
+#define PIPE_CONTROL_FLUSH(ring__, addr__)                                     \
 do {                                                                   \
-       OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |          \
+       intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |           \
                 PIPE_CONTROL_DEPTH_STALL | 2);                         \
-       OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT);                       \
-       OUT_RING(0);                                                    \
-       OUT_RING(0);                                                    \
+       intel_ring_emit(ring__, (addr__) | PIPE_CONTROL_GLOBAL_GTT);                    \
+       intel_ring_emit(ring__, 0);                                                     \
+       intel_ring_emit(ring__, 0);                                                     \
 } while (0)
 
 /**
@@ -237,27 +235,28 @@ do {                                                                      \
  *
  * Returned sequence numbers are nonzero on success.
  */
-static u32
-render_ring_add_request(struct drm_device *dev,
-                       struct intel_ring_buffer *ring,
-                       u32 flush_domains)
+static int
+render_ring_add_request(struct intel_ring_buffer *ring,
+                       u32 *result)
 {
+       struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       u32 seqno;
-
-       seqno = i915_gem_get_seqno(dev);
+       u32 seqno = i915_gem_get_seqno(dev);
+       int ret;
 
        if (IS_GEN6(dev)) {
-               BEGIN_LP_RING(6);
-               OUT_RING(GFX_OP_PIPE_CONTROL | 3);
-               OUT_RING(PIPE_CONTROL_QW_WRITE |
-                        PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH |
-                        PIPE_CONTROL_NOTIFY);
-               OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
-               OUT_RING(seqno);
-               OUT_RING(0);
-               OUT_RING(0);
-               ADVANCE_LP_RING();
+               ret = intel_ring_begin(ring, 6);
+               if (ret)
+                   return ret;
+
+               intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | 3);
+               intel_ring_emit(ring, PIPE_CONTROL_QW_WRITE |
+                               PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH |
+                               PIPE_CONTROL_NOTIFY);
+               intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
+               intel_ring_emit(ring, seqno);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
        } else if (HAS_PIPE_CONTROL(dev)) {
                u32 scratch_addr = dev_priv->seqno_gfx_addr + 128;
 
@@ -266,46 +265,53 @@ render_ring_add_request(struct drm_device *dev,
                 * PIPE_NOTIFY buffers out to memory before requesting
                 * an interrupt.
                 */
-               BEGIN_LP_RING(32);
-               OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
-                        PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH);
-               OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
-               OUT_RING(seqno);
-               OUT_RING(0);
-               PIPE_CONTROL_FLUSH(scratch_addr);
+               ret = intel_ring_begin(ring, 32);
+               if (ret)
+                       return ret;
+
+               intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
+                               PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH);
+               intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
+               intel_ring_emit(ring, seqno);
+               intel_ring_emit(ring, 0);
+               PIPE_CONTROL_FLUSH(ring, scratch_addr);
                scratch_addr += 128; /* write to separate cachelines */
-               PIPE_CONTROL_FLUSH(scratch_addr);
+               PIPE_CONTROL_FLUSH(ring, scratch_addr);
                scratch_addr += 128;
-               PIPE_CONTROL_FLUSH(scratch_addr);
+               PIPE_CONTROL_FLUSH(ring, scratch_addr);
                scratch_addr += 128;
-               PIPE_CONTROL_FLUSH(scratch_addr);
+               PIPE_CONTROL_FLUSH(ring, scratch_addr);
                scratch_addr += 128;
-               PIPE_CONTROL_FLUSH(scratch_addr);
+               PIPE_CONTROL_FLUSH(ring, scratch_addr);
                scratch_addr += 128;
-               PIPE_CONTROL_FLUSH(scratch_addr);
-               OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
-                        PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH |
-                        PIPE_CONTROL_NOTIFY);
-               OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
-               OUT_RING(seqno);
-               OUT_RING(0);
-               ADVANCE_LP_RING();
+               PIPE_CONTROL_FLUSH(ring, scratch_addr);
+               intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
+                               PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH |
+                               PIPE_CONTROL_NOTIFY);
+               intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
+               intel_ring_emit(ring, seqno);
+               intel_ring_emit(ring, 0);
        } else {
-               BEGIN_LP_RING(4);
-               OUT_RING(MI_STORE_DWORD_INDEX);
-               OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
-               OUT_RING(seqno);
+               ret = intel_ring_begin(ring, 4);
+               if (ret)
+                   return ret;
+
+               intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
+               intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+               intel_ring_emit(ring, seqno);
 
-               OUT_RING(MI_USER_INTERRUPT);
-               ADVANCE_LP_RING();
+               intel_ring_emit(ring, MI_USER_INTERRUPT);
        }
-       return seqno;
+
+       intel_ring_advance(ring);
+       *result = seqno;
+       return 0;
 }
 
 static u32
-render_ring_get_seqno(struct drm_device *dev,
-                     struct intel_ring_buffer *ring)
+render_ring_get_seqno(struct intel_ring_buffer *ring)
 {
+       struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        if (HAS_PIPE_CONTROL(dev))
                return ((volatile u32 *)(dev_priv->seqno_page))[0];
@@ -314,9 +320,9 @@ render_ring_get_seqno(struct drm_device *dev,
 }
 
 static void
-render_ring_get_user_irq(struct drm_device *dev,
-                        struct intel_ring_buffer *ring)
+render_ring_get_user_irq(struct intel_ring_buffer *ring)
 {
+       struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
 
@@ -331,9 +337,9 @@ render_ring_get_user_irq(struct drm_device *dev,
 }
 
 static void
-render_ring_put_user_irq(struct drm_device *dev,
-                        struct intel_ring_buffer *ring)
+render_ring_put_user_irq(struct intel_ring_buffer *ring)
 {
+       struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
 
@@ -348,166 +354,166 @@ render_ring_put_user_irq(struct drm_device *dev,
        spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
-void intel_ring_setup_status_page(struct drm_device *dev,
-                                 struct intel_ring_buffer *ring)
+void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       if (IS_GEN6(dev)) {
-               I915_WRITE(RING_HWS_PGA_GEN6(ring->mmio_base),
-                          ring->status_page.gfx_addr);
-               I915_READ(RING_HWS_PGA_GEN6(ring->mmio_base)); /* posting read */
-       } else {
-               I915_WRITE(RING_HWS_PGA(ring->mmio_base),
-                          ring->status_page.gfx_addr);
-               I915_READ(RING_HWS_PGA(ring->mmio_base)); /* posting read */
-       }
-
+       drm_i915_private_t *dev_priv = ring->dev->dev_private;
+       u32 mmio = IS_GEN6(ring->dev) ?
+               RING_HWS_PGA_GEN6(ring->mmio_base) :
+               RING_HWS_PGA(ring->mmio_base);
+       I915_WRITE(mmio, (u32)ring->status_page.gfx_addr);
+       POSTING_READ(mmio);
 }
 
 static void
-bsd_ring_flush(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               u32     invalidate_domains,
-               u32     flush_domains)
-{
-       intel_ring_begin(dev, ring, 2);
-       intel_ring_emit(dev, ring, MI_FLUSH);
-       intel_ring_emit(dev, ring, MI_NOOP);
-       intel_ring_advance(dev, ring);
-}
-
-static int init_bsd_ring(struct drm_device *dev,
-                        struct intel_ring_buffer *ring)
+bsd_ring_flush(struct intel_ring_buffer *ring,
+              u32     invalidate_domains,
+              u32     flush_domains)
 {
-       return init_ring_common(dev, ring);
+       if (intel_ring_begin(ring, 2) == 0) {
+               intel_ring_emit(ring, MI_FLUSH);
+               intel_ring_emit(ring, MI_NOOP);
+               intel_ring_advance(ring);
+       }
 }
 
-static u32
-ring_add_request(struct drm_device *dev,
-                struct intel_ring_buffer *ring,
-                u32 flush_domains)
+static int
+ring_add_request(struct intel_ring_buffer *ring,
+                u32 *result)
 {
        u32 seqno;
+       int ret;
 
-       seqno = i915_gem_get_seqno(dev);
+       ret = intel_ring_begin(ring, 4);
+       if (ret)
+               return ret;
 
-       intel_ring_begin(dev, ring, 4);
-       intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX);
-       intel_ring_emit(dev, ring,
-                       I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
-       intel_ring_emit(dev, ring, seqno);
-       intel_ring_emit(dev, ring, MI_USER_INTERRUPT);
-       intel_ring_advance(dev, ring);
+       seqno = i915_gem_get_seqno(ring->dev);
 
-       DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno);
+       intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
+       intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+       intel_ring_emit(ring, seqno);
+       intel_ring_emit(ring, MI_USER_INTERRUPT);
+       intel_ring_advance(ring);
 
-       return seqno;
+       DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno);
+       *result = seqno;
+       return 0;
 }
 
 static void
-bsd_ring_get_user_irq(struct drm_device *dev,
-                     struct intel_ring_buffer *ring)
+bsd_ring_get_user_irq(struct intel_ring_buffer *ring)
 {
        /* do nothing */
 }
 static void
-bsd_ring_put_user_irq(struct drm_device *dev,
-                     struct intel_ring_buffer *ring)
+bsd_ring_put_user_irq(struct intel_ring_buffer *ring)
 {
        /* do nothing */
 }
 
 static u32
-ring_status_page_get_seqno(struct drm_device *dev,
-                          struct intel_ring_buffer *ring)
+ring_status_page_get_seqno(struct intel_ring_buffer *ring)
 {
        return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
 }
 
 static int
-ring_dispatch_gem_execbuffer(struct drm_device *dev,
-                            struct intel_ring_buffer *ring,
-                            struct drm_i915_gem_execbuffer2 *exec,
-                            struct drm_clip_rect *cliprects,
-                            uint64_t exec_offset)
+ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
+                        struct drm_i915_gem_execbuffer2 *exec,
+                        struct drm_clip_rect *cliprects,
+                        uint64_t exec_offset)
 {
        uint32_t exec_start;
+       int ret;
+
        exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
-       intel_ring_begin(dev, ring, 2);
-       intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START |
-                       (2 << 6) | MI_BATCH_NON_SECURE_I965);
-       intel_ring_emit(dev, ring, exec_start);
-       intel_ring_advance(dev, ring);
+
+       ret = intel_ring_begin(ring, 2);
+       if (ret)
+               return ret;
+
+       intel_ring_emit(ring,
+                       MI_BATCH_BUFFER_START |
+                       (2 << 6) |
+                       MI_BATCH_NON_SECURE_I965);
+       intel_ring_emit(ring, exec_start);
+       intel_ring_advance(ring);
+
        return 0;
 }
 
 static int
-render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
-                                   struct intel_ring_buffer *ring,
-                                   struct drm_i915_gem_execbuffer2 *exec,
-                                   struct drm_clip_rect *cliprects,
-                                   uint64_t exec_offset)
+render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
+                               struct drm_i915_gem_execbuffer2 *exec,
+                               struct drm_clip_rect *cliprects,
+                               uint64_t exec_offset)
 {
+       struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        int nbox = exec->num_cliprects;
-       int i = 0, count;
        uint32_t exec_start, exec_len;
+       int i, count, ret;
+
        exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
        exec_len = (uint32_t) exec->batch_len;
 
        trace_i915_gem_request_submit(dev, dev_priv->next_seqno + 1);
 
        count = nbox ? nbox : 1;
-
        for (i = 0; i < count; i++) {
                if (i < nbox) {
-                       int ret = i915_emit_box(dev, cliprects, i,
-                                               exec->DR1, exec->DR4);
+                       ret = i915_emit_box(dev, cliprects, i,
+                                           exec->DR1, exec->DR4);
                        if (ret)
                                return ret;
                }
 
                if (IS_I830(dev) || IS_845G(dev)) {
-                       intel_ring_begin(dev, ring, 4);
-                       intel_ring_emit(dev, ring, MI_BATCH_BUFFER);
-                       intel_ring_emit(dev, ring,
-                                       exec_start | MI_BATCH_NON_SECURE);
-                       intel_ring_emit(dev, ring, exec_start + exec_len - 4);
-                       intel_ring_emit(dev, ring, 0);
+                       ret = intel_ring_begin(ring, 4);
+                       if (ret)
+                               return ret;
+
+                       intel_ring_emit(ring, MI_BATCH_BUFFER);
+                       intel_ring_emit(ring, exec_start | MI_BATCH_NON_SECURE);
+                       intel_ring_emit(ring, exec_start + exec_len - 4);
+                       intel_ring_emit(ring, 0);
                } else {
-                       intel_ring_begin(dev, ring, 2);
+                       ret = intel_ring_begin(ring, 2);
+                       if (ret)
+                               return ret;
+
                        if (INTEL_INFO(dev)->gen >= 4) {
-                               intel_ring_emit(dev, ring,
+                               intel_ring_emit(ring,
                                                MI_BATCH_BUFFER_START | (2 << 6)
                                                | MI_BATCH_NON_SECURE_I965);
-                               intel_ring_emit(dev, ring, exec_start);
+                               intel_ring_emit(ring, exec_start);
                        } else {
-                               intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START
+                               intel_ring_emit(ring, MI_BATCH_BUFFER_START
                                                | (2 << 6));
-                               intel_ring_emit(dev, ring, exec_start |
+                               intel_ring_emit(ring, exec_start |
                                                MI_BATCH_NON_SECURE);
                        }
                }
-               intel_ring_advance(dev, ring);
+               intel_ring_advance(ring);
        }
 
        if (IS_G4X(dev) || IS_GEN5(dev)) {
-               intel_ring_begin(dev, ring, 2);
-               intel_ring_emit(dev, ring, MI_FLUSH |
-                               MI_NO_WRITE_FLUSH |
-                               MI_INVALIDATE_ISP );
-               intel_ring_emit(dev, ring, MI_NOOP);
-               intel_ring_advance(dev, ring);
+               if (intel_ring_begin(ring, 2) == 0) {
+                       intel_ring_emit(ring, MI_FLUSH |
+                                       MI_NO_WRITE_FLUSH |
+                                       MI_INVALIDATE_ISP );
+                       intel_ring_emit(ring, MI_NOOP);
+                       intel_ring_advance(ring);
+               }
        }
        /* XXX breadcrumb */
 
        return 0;
 }
 
-static void cleanup_status_page(struct drm_device *dev,
-                               struct intel_ring_buffer *ring)
+static void cleanup_status_page(struct intel_ring_buffer *ring)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_private_t *dev_priv = ring->dev->dev_private;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
 
@@ -524,9 +530,9 @@ static void cleanup_status_page(struct drm_device *dev,
        memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
 }
 
-static int init_status_page(struct drm_device *dev,
-                           struct intel_ring_buffer *ring)
+static int init_status_page(struct intel_ring_buffer *ring)
 {
+       struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
@@ -541,7 +547,7 @@ static int init_status_page(struct drm_device *dev,
        obj_priv = to_intel_bo(obj);
        obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
 
-       ret = i915_gem_object_pin(obj, 4096);
+       ret = i915_gem_object_pin(obj, 4096, true);
        if (ret != 0) {
                goto err_unref;
        }
@@ -555,7 +561,7 @@ static int init_status_page(struct drm_device *dev,
        ring->status_page.obj = obj;
        memset(ring->status_page.page_addr, 0, PAGE_SIZE);
 
-       intel_ring_setup_status_page(dev, ring);
+       intel_ring_setup_status_page(ring);
        DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
                        ring->name, ring->status_page.gfx_addr);
 
@@ -572,7 +578,6 @@ err:
 int intel_init_ring_buffer(struct drm_device *dev,
                           struct intel_ring_buffer *ring)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv;
        struct drm_gem_object *obj;
        int ret;
@@ -583,7 +588,7 @@ int intel_init_ring_buffer(struct drm_device *dev,
        INIT_LIST_HEAD(&ring->gpu_write_list);
 
        if (I915_NEED_GFX_HWS(dev)) {
-               ret = init_status_page(dev, ring);
+               ret = init_status_page(ring);
                if (ret)
                        return ret;
        }
@@ -597,7 +602,7 @@ int intel_init_ring_buffer(struct drm_device *dev,
 
        ring->gem_object = obj;
 
-       ret = i915_gem_object_pin(obj, PAGE_SIZE);
+       ret = i915_gem_object_pin(obj, PAGE_SIZE, true);
        if (ret)
                goto err_unref;
 
@@ -616,20 +621,11 @@ int intel_init_ring_buffer(struct drm_device *dev,
        }
 
        ring->virtual_start = ring->map.handle;
-       ret = ring->init(dev, ring);
+       ret = ring->init(ring);
        if (ret)
                goto err_unmap;
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               i915_kernel_lost_context(dev);
-       else {
-               ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
-               ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
-               ring->space = ring->head - (ring->tail + 8);
-               if (ring->space < 0)
-                       ring->space += ring->size;
-       }
-       return ret;
+       return 0;
 
 err_unmap:
        drm_core_ioremapfree(&ring->map, dev);
@@ -639,17 +635,24 @@ err_unref:
        drm_gem_object_unreference(obj);
        ring->gem_object = NULL;
 err_hws:
-       cleanup_status_page(dev, ring);
+       cleanup_status_page(ring);
        return ret;
 }
 
-void intel_cleanup_ring_buffer(struct drm_device *dev,
-                              struct intel_ring_buffer *ring)
+void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
 {
+       struct drm_i915_private *dev_priv;
+       int ret;
+
        if (ring->gem_object == NULL)
                return;
 
-       drm_core_ioremapfree(&ring->map, dev);
+       /* Disable the ring buffer. The ring must be idle at this point */
+       dev_priv = ring->dev->dev_private;
+       ret = intel_wait_ring_buffer(ring, ring->size - 8);
+       I915_WRITE_CTL(ring, 0);
+
+       drm_core_ioremapfree(&ring->map, ring->dev);
 
        i915_gem_object_unpin(ring->gem_object);
        drm_gem_object_unreference(ring->gem_object);
@@ -658,18 +661,17 @@ void intel_cleanup_ring_buffer(struct drm_device *dev,
        if (ring->cleanup)
                ring->cleanup(ring);
 
-       cleanup_status_page(dev, ring);
+       cleanup_status_page(ring);
 }
 
-static int intel_wrap_ring_buffer(struct drm_device *dev,
-                                 struct intel_ring_buffer *ring)
+static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring)
 {
        unsigned int *virt;
        int rem;
        rem = ring->size - ring->tail;
 
        if (ring->space < rem) {
-               int ret = intel_wait_ring_buffer(dev, ring, rem);
+               int ret = intel_wait_ring_buffer(ring, rem);
                if (ret)
                        return ret;
        }
@@ -687,11 +689,11 @@ static int intel_wrap_ring_buffer(struct drm_device *dev,
        return 0;
 }
 
-int intel_wait_ring_buffer(struct drm_device *dev,
-                          struct intel_ring_buffer *ring, int n)
+int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n)
 {
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long end;
-       drm_i915_private_t *dev_priv = dev->dev_private;
        u32 head;
 
        head = intel_read_status_page(ring, 4);
@@ -712,7 +714,7 @@ int intel_wait_ring_buffer(struct drm_device *dev,
                if (ring->space < 0)
                        ring->space += ring->size;
                if (ring->space >= n) {
-                       trace_i915_ring_wait_end (dev);
+                       trace_i915_ring_wait_end(dev);
                        return 0;
                }
 
@@ -723,29 +725,39 @@ int intel_wait_ring_buffer(struct drm_device *dev,
                }
 
                msleep(1);
+               if (atomic_read(&dev_priv->mm.wedged))
+                       return -EAGAIN;
        } while (!time_after(jiffies, end));
        trace_i915_ring_wait_end (dev);
        return -EBUSY;
 }
 
-void intel_ring_begin(struct drm_device *dev,
-                     struct intel_ring_buffer *ring,
-                     int num_dwords)
+int intel_ring_begin(struct intel_ring_buffer *ring,
+                    int num_dwords)
 {
        int n = 4*num_dwords;
-       if (unlikely(ring->tail + n > ring->size))
-               intel_wrap_ring_buffer(dev, ring);
-       if (unlikely(ring->space < n))
-               intel_wait_ring_buffer(dev, ring, n);
+       int ret;
+
+       if (unlikely(ring->tail + n > ring->size)) {
+               ret = intel_wrap_ring_buffer(ring);
+               if (unlikely(ret))
+                       return ret;
+       }
+
+       if (unlikely(ring->space < n)) {
+               ret = intel_wait_ring_buffer(ring, n);
+               if (unlikely(ret))
+                       return ret;
+       }
 
        ring->space -= n;
+       return 0;
 }
 
-void intel_ring_advance(struct drm_device *dev,
-                       struct intel_ring_buffer *ring)
+void intel_ring_advance(struct intel_ring_buffer *ring)
 {
        ring->tail &= ring->size - 1;
-       ring->write_tail(dev, ring, ring->tail);
+       ring->write_tail(ring, ring->tail);
 }
 
 static const struct intel_ring_buffer render_ring = {
@@ -760,7 +772,7 @@ static const struct intel_ring_buffer render_ring = {
        .get_seqno              = render_ring_get_seqno,
        .user_irq_get           = render_ring_get_user_irq,
        .user_irq_put           = render_ring_put_user_irq,
-       .dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer,
+       .dispatch_execbuffer    = render_ring_dispatch_execbuffer,
 };
 
 /* ring buffer for bit-stream decoder */
@@ -770,22 +782,21 @@ static const struct intel_ring_buffer bsd_ring = {
        .id                     = RING_BSD,
        .mmio_base              = BSD_RING_BASE,
        .size                   = 32 * PAGE_SIZE,
-       .init                   = init_bsd_ring,
+       .init                   = init_ring_common,
        .write_tail             = ring_write_tail,
        .flush                  = bsd_ring_flush,
        .add_request            = ring_add_request,
        .get_seqno              = ring_status_page_get_seqno,
        .user_irq_get           = bsd_ring_get_user_irq,
        .user_irq_put           = bsd_ring_put_user_irq,
-       .dispatch_gem_execbuffer = ring_dispatch_gem_execbuffer,
+       .dispatch_execbuffer    = ring_dispatch_execbuffer,
 };
 
 
-static void gen6_bsd_ring_write_tail(struct drm_device *dev,
-                                    struct intel_ring_buffer *ring,
+static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring,
                                     u32 value)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_private_t *dev_priv = ring->dev->dev_private;
 
        /* Every tail move must follow the sequence below */
        I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
@@ -804,36 +815,38 @@ static void gen6_bsd_ring_write_tail(struct drm_device *dev,
               GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE);
 }
 
-static void gen6_ring_flush(struct drm_device *dev,
-                           struct intel_ring_buffer *ring,
+static void gen6_ring_flush(struct intel_ring_buffer *ring,
                            u32 invalidate_domains,
                            u32 flush_domains)
 {
-       intel_ring_begin(dev, ring, 4);
-       intel_ring_emit(dev, ring, MI_FLUSH_DW);
-       intel_ring_emit(dev, ring, 0);
-       intel_ring_emit(dev, ring, 0);
-       intel_ring_emit(dev, ring, 0);
-       intel_ring_advance(dev, ring);
+       if (intel_ring_begin(ring, 4) == 0) {
+               intel_ring_emit(ring, MI_FLUSH_DW);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
+               intel_ring_advance(ring);
+       }
 }
 
 static int
-gen6_ring_dispatch_gem_execbuffer(struct drm_device *dev,
-                                 struct intel_ring_buffer *ring,
-                                 struct drm_i915_gem_execbuffer2 *exec,
-                                 struct drm_clip_rect *cliprects,
-                                 uint64_t exec_offset)
+gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
+                             struct drm_i915_gem_execbuffer2 *exec,
+                             struct drm_clip_rect *cliprects,
+                             uint64_t exec_offset)
 {
        uint32_t exec_start;
+       int ret;
 
        exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
 
-       intel_ring_begin(dev, ring, 2);
-       intel_ring_emit(dev, ring,
-                      MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965);
+       ret = intel_ring_begin(ring, 2);
+       if (ret)
+              return ret;
+
+       intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965);
        /* bit0-7 is the length on GEN6+ */
-       intel_ring_emit(dev, ring, exec_start);
-       intel_ring_advance(dev, ring);
+       intel_ring_emit(ring, exec_start);
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -844,27 +857,25 @@ static const struct intel_ring_buffer gen6_bsd_ring = {
        .id                     = RING_BSD,
        .mmio_base              = GEN6_BSD_RING_BASE,
        .size                   = 32 * PAGE_SIZE,
-       .init                   = init_bsd_ring,
+       .init                   = init_ring_common,
        .write_tail             = gen6_bsd_ring_write_tail,
        .flush                  = gen6_ring_flush,
        .add_request            = ring_add_request,
        .get_seqno              = ring_status_page_get_seqno,
        .user_irq_get           = bsd_ring_get_user_irq,
        .user_irq_put           = bsd_ring_put_user_irq,
-       .dispatch_gem_execbuffer        = gen6_ring_dispatch_gem_execbuffer,
+       .dispatch_execbuffer    = gen6_ring_dispatch_execbuffer,
 };
 
 /* Blitter support (SandyBridge+) */
 
 static void
-blt_ring_get_user_irq(struct drm_device *dev,
-                     struct intel_ring_buffer *ring)
+blt_ring_get_user_irq(struct intel_ring_buffer *ring)
 {
        /* do nothing */
 }
 static void
-blt_ring_put_user_irq(struct drm_device *dev,
-                     struct intel_ring_buffer *ring)
+blt_ring_put_user_irq(struct intel_ring_buffer *ring)
 {
        /* do nothing */
 }
@@ -884,27 +895,26 @@ to_blt_workaround(struct intel_ring_buffer *ring)
        return ring->private;
 }
 
-static int blt_ring_init(struct drm_device *dev,
-                        struct intel_ring_buffer *ring)
+static int blt_ring_init(struct intel_ring_buffer *ring)
 {
-       if (NEED_BLT_WORKAROUND(dev)) {
+       if (NEED_BLT_WORKAROUND(ring->dev)) {
                struct drm_i915_gem_object *obj;
-               u32 __iomem *ptr;
+               u32 *ptr;
                int ret;
 
-               obj = to_intel_bo(i915_gem_alloc_object(dev, 4096));
+               obj = to_intel_bo(i915_gem_alloc_object(ring->dev, 4096));
                if (obj == NULL)
                        return -ENOMEM;
 
-               ret = i915_gem_object_pin(&obj->base, 4096);
+               ret = i915_gem_object_pin(&obj->base, 4096, true);
                if (ret) {
                        drm_gem_object_unreference(&obj->base);
                        return ret;
                }
 
                ptr = kmap(obj->pages[0]);
-               iowrite32(MI_BATCH_BUFFER_END, ptr);
-               iowrite32(MI_NOOP, ptr+1);
+               *ptr++ = MI_BATCH_BUFFER_END;
+               *ptr++ = MI_NOOP;
                kunmap(obj->pages[0]);
 
                ret = i915_gem_object_set_to_gtt_domain(&obj->base, false);
@@ -917,51 +927,60 @@ static int blt_ring_init(struct drm_device *dev,
                ring->private = obj;
        }
 
-       return init_ring_common(dev, ring);
+       return init_ring_common(ring);
 }
 
-static void blt_ring_begin(struct drm_device *dev,
-                          struct intel_ring_buffer *ring,
+static int blt_ring_begin(struct intel_ring_buffer *ring,
                          int num_dwords)
 {
        if (ring->private) {
-               intel_ring_begin(dev, ring, num_dwords+2);
-               intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START);
-               intel_ring_emit(dev, ring, to_blt_workaround(ring)->gtt_offset);
+               int ret = intel_ring_begin(ring, num_dwords+2);
+               if (ret)
+                       return ret;
+
+               intel_ring_emit(ring, MI_BATCH_BUFFER_START);
+               intel_ring_emit(ring, to_blt_workaround(ring)->gtt_offset);
+
+               return 0;
        } else
-               intel_ring_begin(dev, ring, 4);
+               return intel_ring_begin(ring, 4);
 }
 
-static void blt_ring_flush(struct drm_device *dev,
-                          struct intel_ring_buffer *ring,
+static void blt_ring_flush(struct intel_ring_buffer *ring,
                           u32 invalidate_domains,
                           u32 flush_domains)
 {
-       blt_ring_begin(dev, ring, 4);
-       intel_ring_emit(dev, ring, MI_FLUSH_DW);
-       intel_ring_emit(dev, ring, 0);
-       intel_ring_emit(dev, ring, 0);
-       intel_ring_emit(dev, ring, 0);
-       intel_ring_advance(dev, ring);
+       if (blt_ring_begin(ring, 4) == 0) {
+               intel_ring_emit(ring, MI_FLUSH_DW);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
+               intel_ring_advance(ring);
+       }
 }
 
-static u32
-blt_ring_add_request(struct drm_device *dev,
-                    struct intel_ring_buffer *ring,
-                    u32 flush_domains)
+static int
+blt_ring_add_request(struct intel_ring_buffer *ring,
+                    u32 *result)
 {
-       u32 seqno = i915_gem_get_seqno(dev);
+       u32 seqno;
+       int ret;
+
+       ret = blt_ring_begin(ring, 4);
+       if (ret)
+               return ret;
 
-       blt_ring_begin(dev, ring, 4);
-       intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX);
-       intel_ring_emit(dev, ring,
-                       I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
-       intel_ring_emit(dev, ring, seqno);
-       intel_ring_emit(dev, ring, MI_USER_INTERRUPT);
-       intel_ring_advance(dev, ring);
+       seqno = i915_gem_get_seqno(ring->dev);
+
+       intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
+       intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+       intel_ring_emit(ring, seqno);
+       intel_ring_emit(ring, MI_USER_INTERRUPT);
+       intel_ring_advance(ring);
 
        DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno);
-       return seqno;
+       *result = seqno;
+       return 0;
 }
 
 static void blt_ring_cleanup(struct intel_ring_buffer *ring)
@@ -986,7 +1005,7 @@ static const struct intel_ring_buffer gen6_blt_ring = {
        .get_seqno              = ring_status_page_get_seqno,
        .user_irq_get           = blt_ring_get_user_irq,
        .user_irq_put           = blt_ring_put_user_irq,
-       .dispatch_gem_execbuffer        = gen6_ring_dispatch_gem_execbuffer,
+       .dispatch_execbuffer    = gen6_ring_dispatch_execbuffer,
        .cleanup                        = blt_ring_cleanup,
 };
 
index 3126c26..2565d65 100644 (file)
@@ -2,18 +2,23 @@
 #define _INTEL_RINGBUFFER_H_
 
 struct  intel_hw_status_page {
-       void            *page_addr;
+       u32     __iomem *page_addr;
        unsigned int    gfx_addr;
        struct          drm_gem_object *obj;
 };
 
-#define I915_READ_TAIL(ring) I915_READ(RING_TAIL(ring->mmio_base))
+#define I915_RING_READ(reg) i915_safe_read(dev_priv, reg)
+
+#define I915_READ_TAIL(ring) I915_RING_READ(RING_TAIL(ring->mmio_base))
 #define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL(ring->mmio_base), val)
-#define I915_READ_START(ring) I915_READ(RING_START(ring->mmio_base))
+
+#define I915_READ_START(ring) I915_RING_READ(RING_START(ring->mmio_base))
 #define I915_WRITE_START(ring, val) I915_WRITE(RING_START(ring->mmio_base), val)
-#define I915_READ_HEAD(ring) I915_READ(RING_HEAD(ring->mmio_base))
+
+#define I915_READ_HEAD(ring)  I915_RING_READ(RING_HEAD(ring->mmio_base))
 #define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD(ring->mmio_base), val)
-#define I915_READ_CTL(ring) I915_READ(RING_CTL(ring->mmio_base))
+
+#define I915_READ_CTL(ring) I915_RING_READ(RING_CTL(ring->mmio_base))
 #define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val)
 
 struct drm_i915_gem_execbuffer2;
@@ -25,7 +30,6 @@ struct  intel_ring_buffer {
                RING_BLT = 0x4,
        } id;
        u32             mmio_base;
-       unsigned long   size;
        void            *virtual_start;
        struct          drm_device *dev;
        struct          drm_gem_object *gem_object;
@@ -33,36 +37,29 @@ struct  intel_ring_buffer {
        unsigned int    head;
        unsigned int    tail;
        int             space;
+       int             size;
        struct intel_hw_status_page status_page;
 
-       u32             irq_gem_seqno;          /* last seq seem at irq time */
-       u32             waiting_gem_seqno;
+       u32             irq_seqno;              /* last seq seem at irq time */
+       u32             waiting_seqno;
        int             user_irq_refcount;
-       void            (*user_irq_get)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
-       void            (*user_irq_put)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
+       void            (*user_irq_get)(struct intel_ring_buffer *ring);
+       void            (*user_irq_put)(struct intel_ring_buffer *ring);
 
-       int             (*init)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
+       int             (*init)(struct intel_ring_buffer *ring);
 
-       void            (*write_tail)(struct drm_device *dev,
-                                     struct intel_ring_buffer *ring,
+       void            (*write_tail)(struct intel_ring_buffer *ring,
                                      u32 value);
-       void            (*flush)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring,
-                       u32     invalidate_domains,
-                       u32     flush_domains);
-       u32             (*add_request)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring,
-                       u32 flush_domains);
-       u32             (*get_seqno)(struct drm_device *dev,
-                                    struct intel_ring_buffer *ring);
-       int             (*dispatch_gem_execbuffer)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring,
-                       struct drm_i915_gem_execbuffer2 *exec,
-                       struct drm_clip_rect *cliprects,
-                       uint64_t exec_offset);
+       void            (*flush)(struct intel_ring_buffer *ring,
+                                u32    invalidate_domains,
+                                u32    flush_domains);
+       int             (*add_request)(struct intel_ring_buffer *ring,
+                                      u32 *seqno);
+       u32             (*get_seqno)(struct intel_ring_buffer *ring);
+       int             (*dispatch_execbuffer)(struct intel_ring_buffer *ring,
+                                              struct drm_i915_gem_execbuffer2 *exec,
+                                              struct drm_clip_rect *cliprects,
+                                              uint64_t exec_offset);
        void            (*cleanup)(struct intel_ring_buffer *ring);
 
        /**
@@ -95,7 +92,7 @@ struct  intel_ring_buffer {
        /**
         * Do we have some not yet emitted requests outstanding?
         */
-       bool outstanding_lazy_request;
+       u32 outstanding_lazy_request;
 
        wait_queue_head_t irq_queue;
        drm_local_map_t map;
@@ -105,43 +102,31 @@ struct  intel_ring_buffer {
 
 static inline u32
 intel_read_status_page(struct intel_ring_buffer *ring,
-               int reg)
+                      int reg)
 {
-       u32 *regs = ring->status_page.page_addr;
-       return regs[reg];
+       return ioread32(ring->status_page.page_addr + reg);
 }
 
-int intel_init_ring_buffer(struct drm_device *dev,
-                          struct intel_ring_buffer *ring);
-void intel_cleanup_ring_buffer(struct drm_device *dev,
-                              struct intel_ring_buffer *ring);
-int intel_wait_ring_buffer(struct drm_device *dev,
-                          struct intel_ring_buffer *ring, int n);
-void intel_ring_begin(struct drm_device *dev,
-                     struct intel_ring_buffer *ring, int n);
-
-static inline void intel_ring_emit(struct drm_device *dev,
-                                  struct intel_ring_buffer *ring,
-                                  unsigned int data)
+void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
+int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n);
+int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
+
+static inline void intel_ring_emit(struct intel_ring_buffer *ring,
+                                  u32 data)
 {
-       unsigned int *virt = ring->virtual_start + ring->tail;
-       *virt = data;
+       iowrite32(data, ring->virtual_start + ring->tail);
        ring->tail += 4;
 }
 
-void intel_ring_advance(struct drm_device *dev,
-               struct intel_ring_buffer *ring);
+void intel_ring_advance(struct intel_ring_buffer *ring);
 
-u32 intel_ring_get_seqno(struct drm_device *dev,
-               struct intel_ring_buffer *ring);
+u32 intel_ring_get_seqno(struct intel_ring_buffer *ring);
 
 int intel_init_render_ring_buffer(struct drm_device *dev);
 int intel_init_bsd_ring_buffer(struct drm_device *dev);
 int intel_init_blt_ring_buffer(struct drm_device *dev);
 
-u32 intel_ring_get_active_head(struct drm_device *dev,
-                              struct intel_ring_buffer *ring);
-void intel_ring_setup_status_page(struct drm_device *dev,
-                                 struct intel_ring_buffer *ring);
+u32 intel_ring_get_active_head(struct intel_ring_buffer *ring);
+void intel_ring_setup_status_page(struct intel_ring_buffer *ring);
 
 #endif /* _INTEL_RINGBUFFER_H_ */
index 274eaaa..d4bc0f5 100644 (file)
@@ -1041,8 +1041,6 @@ struct drm_device {
        /*@{ */
        spinlock_t object_name_lock;
        struct idr object_name_idr;
-       uint32_t invalidate_domains;    /* domains pending invalidation */
-       uint32_t flush_domains;         /* domains pending flush */
        /*@} */
 
 };
index bf01531..e391777 100644 (file)
@@ -62,11 +62,14 @@ struct drm_mm {
        struct list_head unused_nodes;
        int num_unused;
        spinlock_t unused_lock;
+       unsigned int scan_check_range : 1;
        unsigned scan_alignment;
        unsigned long scan_size;
        unsigned long scan_hit_start;
        unsigned scan_hit_size;
        unsigned scanned_blocks;
+       unsigned long scan_start;
+       unsigned long scan_end;
 };
 
 /*
@@ -145,6 +148,10 @@ static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)
 
 void drm_mm_init_scan(struct drm_mm *mm, unsigned long size,
                      unsigned alignment);
+void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size,
+                                unsigned alignment,
+                                unsigned long start,
+                                unsigned long end);
 int drm_mm_scan_add_block(struct drm_mm_node *node);
 int drm_mm_scan_remove_block(struct drm_mm_node *node);
 
index 8c641be..b20dbb2 100644 (file)
@@ -287,6 +287,7 @@ typedef struct drm_i915_irq_wait {
 #define I915_PARAM_HAS_EXECBUF2          9
 #define I915_PARAM_HAS_BSD              10
 #define I915_PARAM_HAS_BLT              11
+#define I915_PARAM_HAS_RELAXED_FENCING  12
 
 typedef struct drm_i915_getparam {
        int param;