summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/i915_gem_gtt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_gtt.c')
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c59
1 files changed, 51 insertions, 8 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index ea809b803885..5049cd0cf23e 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -716,6 +716,26 @@ static bool gen7_promote(struct i915_hw_ppgtt *ppgtt, struct i915_vma *vma)
return true;
}
+static struct i915_big_page *create_big_page(struct i915_vma *vma)
+{
+ struct i915_big_page *big = kzalloc(sizeof(*big), GFP_KERNEL);
+ if (!big)
+ return ERR_PTR(-ENOMEM);
+
+ kref_init(&big->ref);
+ vma->first_big_pfn = 0;
+ vma->num_big_pfns = vma->obj->base.size / GEN7_BIG_PAGE_SIZE;
+ bitmap_set(big->used_slots, 0, vma->num_big_pfns);
+ big->vma = vma;
+ return big;
+}
+
+static int find_first_slot(struct i915_hw_ppgtt *ppgtt, size_t size,
+ unsigned alignment)
+{
+ return -ENOENT;
+}
+
/*
* Try to merge a VMA into an existing big page allocation. There are
* essentially 3 return values:
@@ -727,7 +747,14 @@ static struct i915_big_page *gen7_big_page_merge(struct i915_hw_ppgtt *ppgtt,
struct i915_vma *vma,
unsigned alignment)
{
+ int which_pde;
+
BUG_ON(vma->big_page);
+
+ which_pde = find_first_slot(ppgtt, vma->obj->base.size, alignment);
+ if (which_pde < 0)
+ return create_big_page(vma);
+
return ERR_PTR(-ENOSPC);
}
@@ -762,10 +789,12 @@ struct i915_vma *gen7_merge_or_promote(struct i915_address_space *vm,
return NULL;
big_page = gen7_big_page_merge(ppgtt, vma, alignment);
- if (!IS_ERR(big_page))
- BUG(); /*Not support yet */
+ if (IS_ERR(big_page)) {
+ DRM_DEBUG_DRIVER("Failed to create big page\n");
+ return NULL;
+ }
- return NULL;
+ return big_page->vma;
}
static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
@@ -1536,9 +1565,6 @@ static void gen7_demote(struct i915_hw_ppgtt *ppgtt, struct i915_vma *vma)
(gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + ppgtt->pd_offset / sizeof(gen6_gtt_pte_t);
int i;
- if (!vma->big_page_promoted)
- return;
-
for (i = 0; i < num_pde; i++) {
u32 pd_entry = readl(pd_addr + first_pde + i);
writel(pd_entry & ~GEN7_PDE_BIG, pd_addr + first_pde + i);
@@ -1548,6 +1574,19 @@ static void gen7_demote(struct i915_hw_ppgtt *ppgtt, struct i915_vma *vma)
trace_i915_big_page_demote(vma);
}
+void big_page_release(struct kref *ref)
+{
+ struct i915_big_page *big_page =
+ container_of(ref, struct i915_big_page, ref);
+ struct i915_vma *vma = big_page->vma;
+ struct i915_hw_ppgtt *ppgtt =
+ container_of(vma->vm, struct i915_hw_ppgtt, base);
+
+ WARN_ON(bitmap_empty(big_page->used_slots, GEN7_BIG_PAGES_PER_PT) != 1);
+ ppgtt->demote(ppgtt, big_page->vma);
+ kfree(big_page);
+}
+
void i915_gem_vm_finish_vma(struct i915_vma *vma)
{
struct drm_i915_gem_object *obj = vma->obj;
@@ -1559,8 +1598,12 @@ void i915_gem_vm_finish_vma(struct i915_vma *vma)
if (!i915_is_ggtt(vma->vm))
ppgtt = vm_to_ppgtt_safe(vma->vm);
- if (ppgtt && ppgtt->demote)
- ppgtt->demote(ppgtt, vma);
+ if (vma->big_page) {
+ bitmap_clear(vma->big_page->used_slots,
+ vma->first_big_pfn,
+ vma->num_big_pfns);
+ kref_put(&vma->big_page->ref, big_page_release);
+ }
interruptible = do_idling(dev_priv);