]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/gpu/drm/i915/i915_gem_gtt.c
drm/i915: Provide the quantization range in the AVI infoframe
[mirror_ubuntu-artful-kernel.git] / drivers / gpu / drm / i915 / i915_gem_gtt.c
index 2c150dee78a70468f96a87295cd29595cfa46a68..0f0db02c1e56d090ef3d0d53dca7ea99a31e10b2 100644 (file)
@@ -282,7 +282,7 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
        uint32_t pd_offset;
        struct intel_ring_buffer *ring;
        struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
-       uint32_t __iomem *pd_addr;
+       gtt_pte_t __iomem *pd_addr;
        uint32_t pd_entry;
        int i;
 
@@ -290,7 +290,7 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
                return;
 
 
-       pd_addr = dev_priv->mm.gtt->gtt + ppgtt->pd_offset/sizeof(uint32_t);
+       pd_addr = (gtt_pte_t __iomem*)dev_priv->gtt.gsm + ppgtt->pd_offset/sizeof(gtt_pte_t);
        for (i = 0; i < ppgtt->num_pd_entries; i++) {
                dma_addr_t pt_addr;
 
@@ -367,7 +367,7 @@ static void i915_ggtt_clear_range(struct drm_device *dev,
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        gtt_pte_t scratch_pte;
-       gtt_pte_t __iomem *gtt_base = dev_priv->mm.gtt->gtt + first_entry;
+       gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
        const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry;
        int i;
 
@@ -393,8 +393,8 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
        struct drm_i915_gem_object *obj;
 
        /* First fill our portion of the GTT with scratch pages */
-       i915_ggtt_clear_range(dev, dev_priv->mm.gtt_start / PAGE_SIZE,
-                             (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
+       i915_ggtt_clear_range(dev, dev_priv->gtt.start / PAGE_SIZE,
+                             dev_priv->gtt.total / PAGE_SIZE);
 
        list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
                i915_gem_clflush_object(obj);
@@ -432,7 +432,8 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj,
        struct scatterlist *sg = st->sgl;
        const int first_entry = obj->gtt_space->start >> PAGE_SHIFT;
        const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry;
-       gtt_pte_t __iomem *gtt_entries = dev_priv->mm.gtt->gtt + first_entry;
+       gtt_pte_t __iomem *gtt_entries =
+               (gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
        int unused, i = 0;
        unsigned int len, m = 0;
        dma_addr_t addr;
@@ -525,26 +526,102 @@ static void i915_gtt_color_adjust(struct drm_mm_node *node,
        }
 }
 
-void i915_gem_init_global_gtt(struct drm_device *dev,
-                             unsigned long start,
-                             unsigned long mappable_end,
-                             unsigned long end)
+void i915_gem_setup_global_gtt(struct drm_device *dev,
+                              unsigned long start,
+                              unsigned long mappable_end,
+                              unsigned long end)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_mm_node *entry;
+       struct drm_i915_gem_object *obj;
+       unsigned long hole_start, hole_end;
+
+       BUG_ON(mappable_end > end);
 
-       /* Substract the guard page ... */
+       /* Subtract the guard page ... */
        drm_mm_init(&dev_priv->mm.gtt_space, start, end - start - PAGE_SIZE);
        if (!HAS_LLC(dev))
                dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust;
 
-       dev_priv->mm.gtt_start = start;
-       dev_priv->mm.gtt_mappable_end = mappable_end;
-       dev_priv->mm.gtt_end = end;
-       dev_priv->mm.gtt_total = end - start;
-       dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start;
+       /* Mark any preallocated objects as occupied */
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+               DRM_DEBUG_KMS("reserving preallocated space: %x + %zx\n",
+                             obj->gtt_offset, obj->base.size);
+
+               BUG_ON(obj->gtt_space != I915_GTT_RESERVED);
+               obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space,
+                                                    obj->gtt_offset,
+                                                    obj->base.size,
+                                                    false);
+               obj->has_global_gtt_mapping = 1;
+       }
+
+       dev_priv->gtt.start = start;
+       dev_priv->gtt.total = end - start;
+
+       /* Clear any non-preallocated blocks */
+       drm_mm_for_each_hole(entry, &dev_priv->mm.gtt_space,
+                            hole_start, hole_end) {
+               DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n",
+                             hole_start, hole_end);
+               i915_ggtt_clear_range(dev,
+                                     hole_start / PAGE_SIZE,
+                                     (hole_end-hole_start) / PAGE_SIZE);
+       }
+
+       /* And finally clear the reserved guard page */
+       i915_ggtt_clear_range(dev, end / PAGE_SIZE - 1, 1);
+}
+
+static bool
+intel_enable_ppgtt(struct drm_device *dev)
+{
+       if (i915_enable_ppgtt >= 0)
+               return i915_enable_ppgtt;
+
+#ifdef CONFIG_INTEL_IOMMU
+       /* Disable ppgtt on SNB if VT-d is on. */
+       if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped)
+               return false;
+#endif
+
+       return true;
+}
+
+void i915_gem_init_global_gtt(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long gtt_size, mappable_size;
+       int ret;
+
+       gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT;
+       mappable_size = dev_priv->gtt.mappable_end;
 
-       /* ... but ensure that we clear the entire range. */
-       i915_ggtt_clear_range(dev, start / PAGE_SIZE, (end-start) / PAGE_SIZE);
+       if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) {
+               /* PPGTT pdes are stolen from global gtt ptes, so shrink the
+                * aperture accordingly when using aliasing ppgtt. */
+               gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
+
+               i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
+
+               ret = i915_gem_init_aliasing_ppgtt(dev);
+               if (ret) {
+                       mutex_unlock(&dev->struct_mutex);
+                       return;
+               }
+       } else {
+               /* Let GEM Manage all of the aperture.
+                *
+                * However, leave one page at the end still bound to the scratch
+                * page.  There are a number of places where the hardware
+                * apparently prefetches past the end of the object, and we've
+                * seen multiple hangs with the GPU head pointer stuck in a
+                * batchbuffer bound at the last page of the aperture.  One page
+                * should be enough to keep any prefetching inside of the
+                * aperture.
+                */
+               i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
+       }
 }
 
 static int setup_scratch_page(struct drm_device *dev)
@@ -613,6 +690,9 @@ int i915_gem_gtt_init(struct drm_device *dev)
        u16 snb_gmch_ctl;
        int ret;
 
+       dev_priv->gtt.mappable_base = pci_resource_start(dev->pdev, 2);
+       dev_priv->gtt.mappable_end = pci_resource_len(dev->pdev, 2);
+
        /* On modern platforms we need not worry ourself with the legacy
         * hostbridge query stuff. Skip it entirely
         */
@@ -645,7 +725,6 @@ int i915_gem_gtt_init(struct drm_device *dev)
 
        /* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */
        gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20);
-       dev_priv->mm.gtt->gma_bus_addr = pci_resource_start(dev->pdev, 2);
 
        /* i9xx_setup */
        pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
@@ -656,14 +735,13 @@ int i915_gem_gtt_init(struct drm_device *dev)
        else
                dev_priv->mm.gtt->stolen_size = gen7_get_stolen_size(snb_gmch_ctl);
 
-       dev_priv->mm.gtt->gtt_mappable_entries = pci_resource_len(dev->pdev, 2) >> PAGE_SHIFT;
        /* 64/512MB is the current min/max we actually know of, but this is just a
         * coarse sanity check.
         */
-       if ((dev_priv->mm.gtt->gtt_mappable_entries >> 8) < 64 ||
-           dev_priv->mm.gtt->gtt_mappable_entries > dev_priv->mm.gtt->gtt_total_entries) {
-               DRM_ERROR("Unknown GMADR entries (%d)\n",
-                         dev_priv->mm.gtt->gtt_mappable_entries);
+       if ((dev_priv->gtt.mappable_end < (64<<20) ||
+           (dev_priv->gtt.mappable_end > (512<<20)))) {
+               DRM_ERROR("Unknown GMADR size (%lx)\n",
+                         dev_priv->gtt.mappable_end);
                ret = -ENXIO;
                goto err_out;
        }
@@ -674,9 +752,9 @@ int i915_gem_gtt_init(struct drm_device *dev)
                goto err_out;
        }
 
-       dev_priv->mm.gtt->gtt = ioremap_wc(gtt_bus_addr,
-                                          dev_priv->mm.gtt->gtt_total_entries * sizeof(gtt_pte_t));
-       if (!dev_priv->mm.gtt->gtt) {
+       dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr,
+                                      dev_priv->mm.gtt->gtt_total_entries * sizeof(gtt_pte_t));
+       if (!dev_priv->gtt.gsm) {
                DRM_ERROR("Failed to map the gtt page table\n");
                teardown_scratch_page(dev);
                ret = -ENOMEM;
@@ -685,7 +763,7 @@ int i915_gem_gtt_init(struct drm_device *dev)
 
        /* GMADR is the PCI aperture used by SW to access tiled GFX surfaces in a linear fashion. */
        DRM_INFO("Memory usable by graphics device = %dM\n", dev_priv->mm.gtt->gtt_total_entries >> 8);
-       DRM_DEBUG_DRIVER("GMADR size = %dM\n", dev_priv->mm.gtt->gtt_mappable_entries >> 8);
+       DRM_DEBUG_DRIVER("GMADR size = %ldM\n", dev_priv->gtt.mappable_end >> 20);
        DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", dev_priv->mm.gtt->stolen_size >> 20);
 
        return 0;
@@ -700,7 +778,7 @@ err_out:
 void i915_gem_gtt_fini(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       iounmap(dev_priv->mm.gtt->gtt);
+       iounmap(dev_priv->gtt.gsm);
        teardown_scratch_page(dev);
        if (INTEL_INFO(dev)->gen < 6)
                intel_gmch_remove();