]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/i915/i915_gem_gtt.c
Merge remote-tracking branch 'drm-intel/for-linux-next'
[karo-tx-linux.git] / drivers / gpu / drm / i915 / i915_gem_gtt.c
index 650b06e015ad83acf4a9d809b1f9014604f405b4..0178bed3f55af1be51fbca81c4628db8db467135 100644 (file)
@@ -30,7 +30,8 @@
 #include "i915_trace.h"
 #include "intel_drv.h"
 
-static void gen8_setup_private_ppat(struct drm_i915_private *dev_priv);
+static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv);
+static void chv_setup_private_ppat(struct drm_i915_private *dev_priv);
 
 bool intel_enable_ppgtt(struct drm_device *dev, bool full)
 {
@@ -285,6 +286,8 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
                        num_entries--;
                }
 
+               if (!HAS_LLC(ppgtt->base.dev))
+                       drm_clflush_virt_range(pt_vaddr, PAGE_SIZE);
                kunmap_atomic(pt_vaddr);
 
                pte = 0;
@@ -321,6 +324,8 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
                        gen8_pte_encode(sg_page_iter_dma_address(&sg_iter),
                                        cache_level, true);
                if (++pte == GEN8_PTES_PER_PAGE) {
+                       if (!HAS_LLC(ppgtt->base.dev))
+                               drm_clflush_virt_range(pt_vaddr, PAGE_SIZE);
                        kunmap_atomic(pt_vaddr);
                        pt_vaddr = NULL;
                        if (++pde == GEN8_PDES_PER_PAGE) {
@@ -330,8 +335,11 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
                        pte = 0;
                }
        }
-       if (pt_vaddr)
+       if (pt_vaddr) {
+               if (!HAS_LLC(ppgtt->base.dev))
+                       drm_clflush_virt_range(pt_vaddr, PAGE_SIZE);
                kunmap_atomic(pt_vaddr);
+       }
 }
 
 static void gen8_free_page_tables(struct page **pt_pages)
@@ -594,6 +602,8 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
                        pd_vaddr[j] = gen8_pde_encode(ppgtt->base.dev, addr,
                                                      I915_CACHE_LLC);
                }
+               if (!HAS_LLC(ppgtt->base.dev))
+                       drm_clflush_virt_range(pd_vaddr, PAGE_SIZE);
                kunmap_atomic(pd_vaddr);
        }
 
@@ -1035,8 +1045,7 @@ alloc:
                                                  &ppgtt->node, GEN6_PD_SIZE,
                                                  GEN6_PD_ALIGN, 0,
                                                  0, dev_priv->gtt.base.total,
-                                                 DRM_MM_SEARCH_DEFAULT,
-                                                 DRM_MM_CREATE_DEFAULT);
+                                                 DRM_MM_TOPDOWN);
        if (ret == -ENOSPC && !retried) {
                ret = i915_gem_evict_something(dev, &dev_priv->gtt.base,
                                               GEN6_PD_SIZE, GEN6_PD_ALIGN,
@@ -1335,7 +1344,11 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 
 
        if (INTEL_INFO(dev)->gen >= 8) {
-               gen8_setup_private_ppat(dev_priv);
+               if (IS_CHERRYVIEW(dev))
+                       chv_setup_private_ppat(dev_priv);
+               else
+                       bdw_setup_private_ppat(dev_priv);
+
                return;
        }
 
@@ -1763,6 +1776,17 @@ static inline unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl)
        return bdw_gmch_ctl << 20;
 }
 
+static inline unsigned int chv_get_total_gtt_size(u16 gmch_ctrl)
+{
+       gmch_ctrl >>= SNB_GMCH_GGMS_SHIFT;
+       gmch_ctrl &= SNB_GMCH_GGMS_MASK;
+
+       if (gmch_ctrl)
+               return 1 << (20 + gmch_ctrl);
+
+       return 0;
+}
+
 static inline size_t gen6_get_stolen_size(u16 snb_gmch_ctl)
 {
        snb_gmch_ctl >>= SNB_GMCH_GMS_SHIFT;
@@ -1777,6 +1801,24 @@ static inline size_t gen8_get_stolen_size(u16 bdw_gmch_ctl)
        return bdw_gmch_ctl << 25; /* 32 MB units */
 }
 
+static size_t chv_get_stolen_size(u16 gmch_ctrl)
+{
+       gmch_ctrl >>= SNB_GMCH_GMS_SHIFT;
+       gmch_ctrl &= SNB_GMCH_GMS_MASK;
+
+       /*
+        * 0x0  to 0x10: 32MB increments starting at 0MB
+        * 0x11 to 0x16: 4MB increments starting at 8MB
+        * 0x17 to 0x1d: 4MB increments start at 36MB
+        */
+       if (gmch_ctrl < 0x11)
+               return gmch_ctrl << 25;
+       else if (gmch_ctrl < 0x17)
+               return (gmch_ctrl - 0x11 + 2) << 22;
+       else
+               return (gmch_ctrl - 0x17 + 9) << 22;
+}
+
 static int ggtt_probe_common(struct drm_device *dev,
                             size_t gtt_size)
 {
@@ -1807,7 +1849,7 @@ static int ggtt_probe_common(struct drm_device *dev,
 /* The GGTT and PPGTT need a private PPAT setup in order to handle cacheability
  * bits. When using advanced contexts each context stores its own PAT, but
  * writing this data shouldn't be harmful even in those cases. */
-static void gen8_setup_private_ppat(struct drm_i915_private *dev_priv)
+static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv)
 {
        uint64_t pat;
 
@@ -1826,6 +1868,33 @@ static void gen8_setup_private_ppat(struct drm_i915_private *dev_priv)
        I915_WRITE(GEN8_PRIVATE_PAT + 4, pat >> 32);
 }
 
+static void chv_setup_private_ppat(struct drm_i915_private *dev_priv)
+{
+       uint64_t pat;
+
+       /*
+        * Map WB on BDW to snooped on CHV.
+        *
+        * Only the snoop bit has meaning for CHV, the rest is
+        * ignored.
+        *
+        * Note that the harware enforces snooping for all page
+        * table accesses. The snoop bit is actually ignored for
+        * PDEs.
+        */
+       pat = GEN8_PPAT(0, CHV_PPAT_SNOOP) |
+             GEN8_PPAT(1, 0) |
+             GEN8_PPAT(2, 0) |
+             GEN8_PPAT(3, 0) |
+             GEN8_PPAT(4, CHV_PPAT_SNOOP) |
+             GEN8_PPAT(5, CHV_PPAT_SNOOP) |
+             GEN8_PPAT(6, CHV_PPAT_SNOOP) |
+             GEN8_PPAT(7, CHV_PPAT_SNOOP);
+
+       I915_WRITE(GEN8_PRIVATE_PAT, pat);
+       I915_WRITE(GEN8_PRIVATE_PAT + 4, pat >> 32);
+}
+
 static int gen8_gmch_probe(struct drm_device *dev,
                           size_t *gtt_total,
                           size_t *stolen,
@@ -1846,12 +1915,20 @@ static int gen8_gmch_probe(struct drm_device *dev,
 
        pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
 
-       *stolen = gen8_get_stolen_size(snb_gmch_ctl);
+       if (IS_CHERRYVIEW(dev)) {
+               *stolen = chv_get_stolen_size(snb_gmch_ctl);
+               gtt_size = chv_get_total_gtt_size(snb_gmch_ctl);
+       } else {
+               *stolen = gen8_get_stolen_size(snb_gmch_ctl);
+               gtt_size = gen8_get_total_gtt_size(snb_gmch_ctl);
+       }
 
-       gtt_size = gen8_get_total_gtt_size(snb_gmch_ctl);
        *gtt_total = (gtt_size / sizeof(gen8_gtt_pte_t)) << PAGE_SHIFT;
 
-       gen8_setup_private_ppat(dev_priv);
+       if (IS_CHERRYVIEW(dev))
+               chv_setup_private_ppat(dev_priv);
+       else
+               bdw_setup_private_ppat(dev_priv);
 
        ret = ggtt_probe_common(dev, gtt_size);