diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_gtt.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_gtt.c | 59 |
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); |