aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_gem_gtt.c
diff options
context:
space:
mode:
authorBen Widawsky <ben@bwidawsk.net>2013-12-06 17:10:56 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-12-18 09:27:50 -0500
commit6f65e29acad7499920cf1e49b675fac7cde24166 (patch)
tree1eaaae1debf3f0be1e64c1db3ed5ff38ef079316 /drivers/gpu/drm/i915/i915_gem_gtt.c
parentd7f46fc4e7323887494db13f063a8e59861fefb0 (diff)
drm/i915: Create bind/unbind abstraction for VMAs
To sum up what goes on here, we abstract the vma binding, similarly to the previous object binding. This helps for distinguishing legacy binding, versus modern binding. To keep the code churn as minimal as possible, I am leaving in insert_entries(). It serves as the per platform pte writing basically. bind_vma and insert_entries do share a lot of similarities, and I did have designs to combine the two, but as mentioned already... too much churn in an already massive patchset. What follows are the 3 commits which existed discretely in the original submissions. Upon rebasing on Broadwell support, it became clear that separation was not good, and only made for more error prone code. Below are the 3 commit messages with all their history. drm/i915: Add bind/unbind object functions to VMA drm/i915: Use the new vm [un]bind functions drm/i915: reduce vm->insert_entries() usage drm/i915: Add bind/unbind object functions to VMA As we plumb the code with more VM information, it has become more obvious that the easiest way to deal with bind and unbind is to simply put the function pointers in the vm, and let those choose the correct way to handle the page table updates. This change allows many places in the code to simply be vm->bind, and not have to worry about distinguishing PPGTT vs GGTT. Notice that this patch has no impact on functionality. I've decided to save the actual change until the next patch because I think it's easier to review that way. I'm happy to squash the two, or let Daniel do it on merge. v2: Make ggtt handle the quirky aliasing ppgtt Add flags to bind object to support above Don't ever call bind/unbind directly for PPGTT until we have real, full PPGTT (use NULLs to assert this) Make sure we rebind the ggtt if there already is a ggtt binding. This happens on set cache levels. Use VMA for bind/unbind (Daniel, Ben) v3: Reorganize ggtt_vma_bind to be more concise and easier to read (Ville). Change logic in unbind to only unbind ggtt when there is a global mapping, and to remove a redundant check if the aliasing ppgtt exists. v4: Make the bind function a bit smarter about the cache levels to avoid unnecessary multiple remaps. "I accept it is a wart, I think unifying the pin_vma / bind_vma could be unified later" (Chris) Removed the git notes, and put version info here. (Daniel) v5: Update the comment to not suck (Chris) v6: Move bind/unbind to the VMA. It makes more sense in the VMA structure (always has, but I was previously lazy). With this change, it will allow us to keep a distinct insert_entries. Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Ben Widawsky <ben@bwidawsk.net> drm/i915: Use the new vm [un]bind functions Building on the last patch which created the new function pointers in the VM for bind/unbind, here we actually put those new function pointers to use. Split out as a separate patch to aid in review. I'm fine with squashing into the previous patch if people request it. v2: Updated to address the smart ggtt which can do aliasing as needed Make sure we bind to global gtt when mappable and fenceable. I thought we could get away without this initialy, but we cannot. v3: Make the global GTT binding explicitly use the ggtt VM for bind_vma(). While at it, use the new ggtt_vma helper (Chris) At this point the original mailing list thread diverges. ie. v4^: use target_obj instead of obj for gen6 relocate_entry vma->bind_vma() can be called safely during pin. So simply do that instead of the complicated conditionals. Don't restore PPGTT bound objects on resume path Bug fix in resume path for globally bound Bos Properly handle secure dispatch Rebased on vma bind/unbind conversion Signed-off-by: Ben Widawsky <ben@bwidawsk.net> drm/i915: reduce vm->insert_entries() usage FKA: drm/i915: eliminate vm->insert_entries() With bind/unbind function pointers in place, we no longer need insert_entries. We could, and want, to remove clear_range, however it's not totally easy at this point. Since it's used in a couple of place still that don't only deal in objects: setup, ppgtt init, and restore gtt mappings. v2: Don't actually remove insert_entries, just limit its usage. It will be useful when we introduce gen8. It will always be called from the vma bind/unbind. Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> (v1) Signed-off-by: Ben Widawsky <ben@bwidawsk.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_gtt.c')
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c192
1 files changed, 155 insertions, 37 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 056033791d24..73117ec333cc 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -68,6 +68,11 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
68#define PPAT_CACHED_INDEX _PAGE_PAT /* WB LLCeLLC */ 68#define PPAT_CACHED_INDEX _PAGE_PAT /* WB LLCeLLC */
69#define PPAT_DISPLAY_ELLC_INDEX _PAGE_PCD /* WT eLLC */ 69#define PPAT_DISPLAY_ELLC_INDEX _PAGE_PCD /* WT eLLC */
70 70
71static void ppgtt_bind_vma(struct i915_vma *vma,
72 enum i915_cache_level cache_level,
73 u32 flags);
74static void ppgtt_unbind_vma(struct i915_vma *vma);
75
71static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr, 76static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr,
72 enum i915_cache_level level, 77 enum i915_cache_level level,
73 bool valid) 78 bool valid)
@@ -746,22 +751,26 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
746 dev_priv->mm.aliasing_ppgtt = NULL; 751 dev_priv->mm.aliasing_ppgtt = NULL;
747} 752}
748 753
749void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, 754static void __always_unused
750 struct drm_i915_gem_object *obj, 755ppgtt_bind_vma(struct i915_vma *vma,
751 enum i915_cache_level cache_level) 756 enum i915_cache_level cache_level,
757 u32 flags)
752{ 758{
753 ppgtt->base.insert_entries(&ppgtt->base, obj->pages, 759 const unsigned long entry = vma->node.start >> PAGE_SHIFT;
754 i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT, 760
755 cache_level); 761 WARN_ON(flags);
762
763 vma->vm->insert_entries(vma->vm, vma->obj->pages, entry, cache_level);
756} 764}
757 765
758void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, 766static void __always_unused ppgtt_unbind_vma(struct i915_vma *vma)
759 struct drm_i915_gem_object *obj)
760{ 767{
761 ppgtt->base.clear_range(&ppgtt->base, 768 const unsigned long entry = vma->node.start >> PAGE_SHIFT;
762 i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT, 769
763 obj->base.size >> PAGE_SHIFT, 770 vma->vm->clear_range(vma->vm,
764 true); 771 entry,
772 vma->obj->base.size >> PAGE_SHIFT,
773 true);
765} 774}
766 775
767extern int intel_iommu_gfx_mapped; 776extern int intel_iommu_gfx_mapped;
@@ -863,8 +872,18 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
863 true); 872 true);
864 873
865 list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { 874 list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
875 struct i915_vma *vma = i915_gem_obj_to_vma(obj,
876 &dev_priv->gtt.base);
877 if (!vma)
878 continue;
879
866 i915_gem_clflush_object(obj, obj->pin_display); 880 i915_gem_clflush_object(obj, obj->pin_display);
867 i915_gem_gtt_bind_object(obj, obj->cache_level); 881 /* The bind_vma code tries to be smart about tracking mappings.
882 * Unfortunately above, we've just wiped out the mappings
883 * without telling our object about it. So we need to fake it.
884 */
885 obj->has_global_gtt_mapping = 0;
886 vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND);
868 } 887 }
869 888
870 i915_gem_chipset_flush(dev); 889 i915_gem_chipset_flush(dev);
@@ -1023,16 +1042,18 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
1023 readl(gtt_base); 1042 readl(gtt_base);
1024} 1043}
1025 1044
1026static void i915_ggtt_insert_entries(struct i915_address_space *vm, 1045
1027 struct sg_table *st, 1046static void i915_ggtt_bind_vma(struct i915_vma *vma,
1028 unsigned int pg_start, 1047 enum i915_cache_level cache_level,
1029 enum i915_cache_level cache_level) 1048 u32 unused)
1030{ 1049{
1050 const unsigned long entry = vma->node.start >> PAGE_SHIFT;
1031 unsigned int flags = (cache_level == I915_CACHE_NONE) ? 1051 unsigned int flags = (cache_level == I915_CACHE_NONE) ?
1032 AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; 1052 AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
1033 1053
1034 intel_gtt_insert_sg_entries(st, pg_start, flags); 1054 BUG_ON(!i915_is_ggtt(vma->vm));
1035 1055 intel_gtt_insert_sg_entries(vma->obj->pages, entry, flags);
1056 vma->obj->has_global_gtt_mapping = 1;
1036} 1057}
1037 1058
1038static void i915_ggtt_clear_range(struct i915_address_space *vm, 1059static void i915_ggtt_clear_range(struct i915_address_space *vm,
@@ -1043,33 +1064,77 @@ static void i915_ggtt_clear_range(struct i915_address_space *vm,
1043 intel_gtt_clear_range(first_entry, num_entries); 1064 intel_gtt_clear_range(first_entry, num_entries);
1044} 1065}
1045 1066
1067static void i915_ggtt_unbind_vma(struct i915_vma *vma)
1068{
1069 const unsigned int first = vma->node.start >> PAGE_SHIFT;
1070 const unsigned int size = vma->obj->base.size >> PAGE_SHIFT;
1046 1071
1047void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, 1072 BUG_ON(!i915_is_ggtt(vma->vm));
1048 enum i915_cache_level cache_level) 1073 vma->obj->has_global_gtt_mapping = 0;
1074 intel_gtt_clear_range(first, size);
1075}
1076
1077static void ggtt_bind_vma(struct i915_vma *vma,
1078 enum i915_cache_level cache_level,
1079 u32 flags)
1049{ 1080{
1050 struct drm_device *dev = obj->base.dev; 1081 struct drm_device *dev = vma->vm->dev;
1051 struct drm_i915_private *dev_priv = dev->dev_private; 1082 struct drm_i915_private *dev_priv = dev->dev_private;
1052 const unsigned long entry = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT; 1083 struct drm_i915_gem_object *obj = vma->obj;
1084 const unsigned long entry = vma->node.start >> PAGE_SHIFT;
1053 1085
1054 dev_priv->gtt.base.insert_entries(&dev_priv->gtt.base, obj->pages, 1086 /* If there is no aliasing PPGTT, or the caller needs a global mapping,
1055 entry, 1087 * or we have a global mapping already but the cacheability flags have
1056 cache_level); 1088 * changed, set the global PTEs.
1089 *
1090 * If there is an aliasing PPGTT it is anecdotally faster, so use that
1091 * instead if none of the above hold true.
1092 *
1093 * NB: A global mapping should only be needed for special regions like
1094 * "gtt mappable", SNB errata, or if specified via special execbuf
1095 * flags. At all other times, the GPU will use the aliasing PPGTT.
1096 */
1097 if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) {
1098 if (!obj->has_global_gtt_mapping ||
1099 (cache_level != obj->cache_level)) {
1100 vma->vm->insert_entries(vma->vm, obj->pages, entry,
1101 cache_level);
1102 obj->has_global_gtt_mapping = 1;
1103 }
1104 }
1057 1105
1058 obj->has_global_gtt_mapping = 1; 1106 if (dev_priv->mm.aliasing_ppgtt &&
1107 (!obj->has_aliasing_ppgtt_mapping ||
1108 (cache_level != obj->cache_level))) {
1109 struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
1110 appgtt->base.insert_entries(&appgtt->base,
1111 vma->obj->pages, entry, cache_level);
1112 vma->obj->has_aliasing_ppgtt_mapping = 1;
1113 }
1059} 1114}
1060 1115
1061void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) 1116static void ggtt_unbind_vma(struct i915_vma *vma)
1062{ 1117{
1063 struct drm_device *dev = obj->base.dev; 1118 struct drm_device *dev = vma->vm->dev;
1064 struct drm_i915_private *dev_priv = dev->dev_private; 1119 struct drm_i915_private *dev_priv = dev->dev_private;
1065 const unsigned long entry = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT; 1120 struct drm_i915_gem_object *obj = vma->obj;
1066 1121 const unsigned long entry = vma->node.start >> PAGE_SHIFT;
1067 dev_priv->gtt.base.clear_range(&dev_priv->gtt.base, 1122
1068 entry, 1123 if (obj->has_global_gtt_mapping) {
1069 obj->base.size >> PAGE_SHIFT, 1124 vma->vm->clear_range(vma->vm, entry,
1070 true); 1125 vma->obj->base.size >> PAGE_SHIFT,
1126 true);
1127 obj->has_global_gtt_mapping = 0;
1128 }
1071 1129
1072 obj->has_global_gtt_mapping = 0; 1130 if (obj->has_aliasing_ppgtt_mapping) {
1131 struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
1132 appgtt->base.clear_range(&appgtt->base,
1133 entry,
1134 obj->base.size >> PAGE_SHIFT,
1135 true);
1136 obj->has_aliasing_ppgtt_mapping = 0;
1137 }
1073} 1138}
1074 1139
1075void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj) 1140void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
@@ -1444,7 +1509,6 @@ static int i915_gmch_probe(struct drm_device *dev,
1444 1509
1445 dev_priv->gtt.do_idle_maps = needs_idle_maps(dev_priv->dev); 1510 dev_priv->gtt.do_idle_maps = needs_idle_maps(dev_priv->dev);
1446 dev_priv->gtt.base.clear_range = i915_ggtt_clear_range; 1511 dev_priv->gtt.base.clear_range = i915_ggtt_clear_range;
1447 dev_priv->gtt.base.insert_entries = i915_ggtt_insert_entries;
1448 1512
1449 return 0; 1513 return 0;
1450} 1514}
@@ -1496,3 +1560,57 @@ int i915_gem_gtt_init(struct drm_device *dev)
1496 1560
1497 return 0; 1561 return 0;
1498} 1562}
1563
1564static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
1565 struct i915_address_space *vm)
1566{
1567 struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
1568 if (vma == NULL)
1569 return ERR_PTR(-ENOMEM);
1570
1571 INIT_LIST_HEAD(&vma->vma_link);
1572 INIT_LIST_HEAD(&vma->mm_list);
1573 INIT_LIST_HEAD(&vma->exec_list);
1574 vma->vm = vm;
1575 vma->obj = obj;
1576
1577 switch (INTEL_INFO(vm->dev)->gen) {
1578 case 8:
1579 case 7:
1580 case 6:
1581 vma->unbind_vma = ggtt_unbind_vma;
1582 vma->bind_vma = ggtt_bind_vma;
1583 break;
1584 case 5:
1585 case 4:
1586 case 3:
1587 case 2:
1588 BUG_ON(!i915_is_ggtt(vm));
1589 vma->unbind_vma = i915_ggtt_unbind_vma;
1590 vma->bind_vma = i915_ggtt_bind_vma;
1591 break;
1592 default:
1593 BUG();
1594 }
1595
1596 /* Keep GGTT vmas first to make debug easier */
1597 if (i915_is_ggtt(vm))
1598 list_add(&vma->vma_link, &obj->vma_list);
1599 else
1600 list_add_tail(&vma->vma_link, &obj->vma_list);
1601
1602 return vma;
1603}
1604
1605struct i915_vma *
1606i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
1607 struct i915_address_space *vm)
1608{
1609 struct i915_vma *vma;
1610
1611 vma = i915_gem_obj_to_vma(obj, vm);
1612 if (!vma)
1613 vma = __i915_gem_vma_create(obj, vm);
1614
1615 return vma;
1616}