Skip to content

Commit

Permalink
drm/i915: Infrastructure for supporting different GGTT views per object
Browse files Browse the repository at this point in the history
Things like reliable GGTT mappings and mirrored 2d-on-3d display will need
to map objects into the same address space multiple times.

Added a GGTT view concept and linked it with the VMA to distinguish between
multiple instances per address space.

New objects and GEM functions which do not take this new view as a parameter
assume the default of zero (I915_GGTT_VIEW_NORMAL) which preserves the
previous behaviour.

This now means that objects can have multiple VMA entries so the code which
assumed there will only be one also had to be modified.

Alternative GGTT views are supposed to borrow DMA addresses from obj->pages
which is DMA mapped on first VMA instantiation and unmapped on the last one
going away.

v2:
    * Removed per view special casing in i915_gem_ggtt_prepare /
      finish_object in favour of creating and destroying DMA mappings
      on first VMA instantiation and last VMA destruction. (Daniel Vetter)
    * Simplified i915_vma_unbind which does not need to count the GGTT views.
      (Daniel Vetter)
    * Also moved obj->map_and_fenceable reset under the same check.
    * Checkpatch cleanups.

v3:
    * Only retire objects once the last VMA is unbound.

v4:
    * Keep scatter-gather table for alternative views persistent for the
      lifetime of the VMA.
    * Propagate binding errors to callers and handle appropriately.

v5:
    * Explicitly look for normal GGTT view in i915_gem_obj_bound to align
      usage in i915_gem_object_ggtt_unpin. (Michel Thierry)
    * Change to single if statement in i915_gem_obj_to_ggtt. (Michel Thierry)
    * Removed stray semi-colon in i915_gem_object_set_cache_level.

For: VIZ-4544
Signed-off-by: Tvrtko Ursulin <[email protected]>
Cc: Daniel Vetter <[email protected]>
Reviewed-by: Michel Thierry <[email protected]>
[danvet: Drop hunk from i915_gem_shrink since it's just prettification
but upsets a __must_check warning.]
Signed-off-by: Daniel Vetter <[email protected]>
  • Loading branch information
tursulin authored and danvet committed Dec 15, 2014
1 parent db5ff4a commit fe14d5f
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 70 deletions.
5 changes: 3 additions & 2 deletions drivers/gpu/drm/i915/i915_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
seq_puts(m, " (pp");
else
seq_puts(m, " (g");
seq_printf(m, "gtt offset: %08lx, size: %08lx)",
vma->node.start, vma->node.size);
seq_printf(m, "gtt offset: %08lx, size: %08lx, type: %u)",
vma->node.start, vma->node.size,
vma->ggtt_view.type);
}
if (obj->stolen)
seq_printf(m, " (stolen: %08lx)", obj->stolen->start);
Expand Down
56 changes: 51 additions & 5 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -2530,10 +2530,23 @@ void i915_gem_vma_destroy(struct i915_vma *vma);
#define PIN_GLOBAL 0x4
#define PIN_OFFSET_BIAS 0x8
#define PIN_OFFSET_MASK (~4095)
int __must_check i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
uint32_t alignment,
uint64_t flags,
const struct i915_ggtt_view *view);
static inline
int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
uint32_t alignment,
uint64_t flags);
uint64_t flags)
{
return i915_gem_object_pin_view(obj, vm, alignment, flags,
&i915_ggtt_view_normal);
}

int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
u32 flags);
int __must_check i915_vma_unbind(struct i915_vma *vma);
int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv);
Expand Down Expand Up @@ -2695,18 +2708,51 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev,

void i915_gem_restore_fences(struct drm_device *dev);

unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
struct i915_address_space *vm,
enum i915_ggtt_view_type view);
static inline
unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
struct i915_address_space *vm);
struct i915_address_space *vm)
{
return i915_gem_obj_offset_view(o, vm, I915_GGTT_VIEW_NORMAL);
}
bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o);
bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
struct i915_address_space *vm,
enum i915_ggtt_view_type view);
static inline
bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
struct i915_address_space *vm);
struct i915_address_space *vm)
{
return i915_gem_obj_bound_view(o, vm, I915_GGTT_VIEW_NORMAL);
}

unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
struct i915_address_space *vm);
struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
const struct i915_ggtt_view *view);
static inline
struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
struct i915_address_space *vm);
struct i915_address_space *vm)
{
return i915_gem_obj_to_vma_view(obj, vm, &i915_ggtt_view_normal);
}

struct i915_vma *
i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
const struct i915_ggtt_view *view);

static inline
struct i915_vma *
i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
struct i915_address_space *vm);
struct i915_address_space *vm)
{
return i915_gem_obj_lookup_or_create_vma_view(obj, vm,
&i915_ggtt_view_normal);
}

struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj);
static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) {
Expand Down
109 changes: 67 additions & 42 deletions drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -2297,17 +2297,14 @@ void i915_vma_move_to_active(struct i915_vma *vma,
static void
i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
struct i915_address_space *vm;
struct i915_vma *vma;

BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS);
BUG_ON(!obj->active);

list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
vma = i915_gem_obj_to_vma(obj, vm);
if (vma && !list_empty(&vma->mm_list))
list_move_tail(&vma->mm_list, &vm->inactive_list);
list_for_each_entry(vma, &obj->vma_list, vma_link) {
if (!list_empty(&vma->mm_list))
list_move_tail(&vma->mm_list, &vma->vm->inactive_list);
}

intel_fb_obj_flush(obj, true);
Expand Down Expand Up @@ -3062,10 +3059,8 @@ int i915_vma_unbind(struct i915_vma *vma)
* cause memory corruption through use-after-free.
*/

/* Throw away the active reference before moving to the unbound list */
i915_gem_object_retire(obj);

if (i915_is_ggtt(vma->vm)) {
if (i915_is_ggtt(vma->vm) &&
vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) {
i915_gem_object_finish_gtt(obj);

/* release the fence reg _after_ flushing */
Expand All @@ -3079,15 +3074,26 @@ int i915_vma_unbind(struct i915_vma *vma)
vma->unbind_vma(vma);

list_del_init(&vma->mm_list);
if (i915_is_ggtt(vma->vm))
obj->map_and_fenceable = false;
if (i915_is_ggtt(vma->vm)) {
if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) {
obj->map_and_fenceable = false;
} else if (vma->ggtt_view.pages) {
sg_free_table(vma->ggtt_view.pages);
kfree(vma->ggtt_view.pages);
vma->ggtt_view.pages = NULL;
}
}

drm_mm_remove_node(&vma->node);
i915_gem_vma_destroy(vma);

/* Since the unbound list is global, only move to that list if
* no more VMAs exist. */
if (list_empty(&obj->vma_list)) {
/* Throw away the active reference before
* moving to the unbound list. */
i915_gem_object_retire(obj);

i915_gem_gtt_finish_object(obj);
list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list);
}
Expand Down Expand Up @@ -3498,7 +3504,8 @@ static struct i915_vma *
i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
unsigned alignment,
uint64_t flags)
uint64_t flags,
const struct i915_ggtt_view *view)
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
Expand Down Expand Up @@ -3548,7 +3555,7 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,

i915_gem_object_pin_pages(obj);

vma = i915_gem_obj_lookup_or_create_vma(obj, vm);
vma = i915_gem_obj_lookup_or_create_vma_view(obj, vm, view);
if (IS_ERR(vma))
goto err_unpin;

Expand Down Expand Up @@ -3578,15 +3585,19 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
if (ret)
goto err_remove_node;

trace_i915_vma_bind(vma, flags);
ret = i915_vma_bind(vma, obj->cache_level,
flags & PIN_GLOBAL ? GLOBAL_BIND : 0);
if (ret)
goto err_finish_gtt;

list_move_tail(&obj->global_list, &dev_priv->mm.bound_list);
list_add_tail(&vma->mm_list, &vm->inactive_list);

trace_i915_vma_bind(vma, flags);
vma->bind_vma(vma, obj->cache_level,
flags & PIN_GLOBAL ? GLOBAL_BIND : 0);

return vma;

err_finish_gtt:
i915_gem_gtt_finish_object(obj);
err_remove_node:
drm_mm_remove_node(&vma->node);
err_free_vma:
Expand Down Expand Up @@ -3789,9 +3800,12 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
}

list_for_each_entry(vma, &obj->vma_list, vma_link)
if (drm_mm_node_allocated(&vma->node))
vma->bind_vma(vma, cache_level,
vma->bound & GLOBAL_BIND);
if (drm_mm_node_allocated(&vma->node)) {
ret = i915_vma_bind(vma, cache_level,
vma->bound & GLOBAL_BIND);
if (ret)
return ret;
}
}

list_for_each_entry(vma, &obj->vma_list, vma_link)
Expand Down Expand Up @@ -4144,10 +4158,11 @@ i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags)
}

int
i915_gem_object_pin(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
uint32_t alignment,
uint64_t flags)
i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
uint32_t alignment,
uint64_t flags,
const struct i915_ggtt_view *view)
{
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
struct i915_vma *vma;
Expand All @@ -4163,7 +4178,7 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
if (WARN_ON((flags & (PIN_MAPPABLE | PIN_GLOBAL)) == PIN_MAPPABLE))
return -EINVAL;

vma = i915_gem_obj_to_vma(obj, vm);
vma = i915_gem_obj_to_vma_view(obj, vm, view);
if (vma) {
if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
return -EBUSY;
Expand All @@ -4173,7 +4188,8 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
"bo is already pinned with incorrect alignment:"
" offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
" obj->map_and_fenceable=%d\n",
i915_gem_obj_offset(obj, vm), alignment,
i915_gem_obj_offset_view(obj, vm, view->type),
alignment,
!!(flags & PIN_MAPPABLE),
obj->map_and_fenceable);
ret = i915_vma_unbind(vma);
Expand All @@ -4186,13 +4202,17 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,

bound = vma ? vma->bound : 0;
if (vma == NULL || !drm_mm_node_allocated(&vma->node)) {
vma = i915_gem_object_bind_to_vm(obj, vm, alignment, flags);
vma = i915_gem_object_bind_to_vm(obj, vm, alignment,
flags, view);
if (IS_ERR(vma))
return PTR_ERR(vma);
}

if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND))
vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND);
if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND)) {
ret = i915_vma_bind(vma, obj->cache_level, GLOBAL_BIND);
if (ret)
return ret;
}

if ((bound ^ vma->bound) & GLOBAL_BIND) {
bool mappable, fenceable;
Expand Down Expand Up @@ -4528,12 +4548,13 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
intel_runtime_pm_put(dev_priv);
}

struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
struct i915_address_space *vm)
struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
const struct i915_ggtt_view *view)
{
struct i915_vma *vma;
list_for_each_entry(vma, &obj->vma_list, vma_link)
if (vma->vm == vm)
if (vma->vm == vm && vma->ggtt_view.type == view->type)
return vma;

return NULL;
Expand Down Expand Up @@ -5145,16 +5166,17 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
}

/* All the new VM stuff */
unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
struct i915_address_space *vm)
unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
struct i915_address_space *vm,
enum i915_ggtt_view_type view)
{
struct drm_i915_private *dev_priv = o->base.dev->dev_private;
struct i915_vma *vma;

WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);

list_for_each_entry(vma, &o->vma_list, vma_link) {
if (vma->vm == vm)
if (vma->vm == vm && vma->ggtt_view.type == view)
return vma->node.start;

}
Expand All @@ -5163,13 +5185,16 @@ unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
return -1;
}

bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
struct i915_address_space *vm)
bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
struct i915_address_space *vm,
enum i915_ggtt_view_type view)
{
struct i915_vma *vma;

list_for_each_entry(vma, &o->vma_list, vma_link)
if (vma->vm == vm && drm_mm_node_allocated(&vma->node))
if (vma->vm == vm &&
vma->ggtt_view.type == view &&
drm_mm_node_allocated(&vma->node))
return true;

return false;
Expand Down Expand Up @@ -5304,10 +5329,10 @@ struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
struct i915_address_space *ggtt = i915_obj_to_ggtt(obj);
struct i915_vma *vma;

list_for_each_entry(vma, &obj->vma_list, vma_link) {
if (vma->vm == ggtt)
list_for_each_entry(vma, &obj->vma_list, vma_link)
if (vma->vm == ggtt &&
vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
return vma;
}

return NULL;
}
11 changes: 8 additions & 3 deletions drivers/gpu/drm/i915/i915_gem_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -590,9 +590,14 @@ static int do_switch(struct intel_engine_cs *ring,
goto unpin_out;

vma = i915_gem_obj_to_ggtt(to->legacy_hw_ctx.rcs_state);
if (!(vma->bound & GLOBAL_BIND))
vma->bind_vma(vma, to->legacy_hw_ctx.rcs_state->cache_level,
GLOBAL_BIND);
if (!(vma->bound & GLOBAL_BIND)) {
ret = i915_vma_bind(vma,
to->legacy_hw_ctx.rcs_state->cache_level,
GLOBAL_BIND);
/* This shouldn't ever fail. */
if (WARN_ONCE(ret, "GGTT context bind failed!"))
goto unpin_out;
}

if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to))
hw_flags |= MI_RESTORE_INHIBIT;
Expand Down
9 changes: 6 additions & 3 deletions drivers/gpu/drm/i915/i915_gem_execbuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,12 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
* through the ppgtt for non_secure batchbuffers. */
if (unlikely(IS_GEN6(dev) &&
reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
!(target_vma->bound & GLOBAL_BIND)))
target_vma->bind_vma(target_vma, target_i915_obj->cache_level,
GLOBAL_BIND);
!(target_vma->bound & GLOBAL_BIND))) {
ret = i915_vma_bind(target_vma, target_i915_obj->cache_level,
GLOBAL_BIND);
if (WARN_ONCE(ret, "Unexpected failure to bind target VMA!"))
return ret;
}

/* Validate that the target is in a valid r/w GPU domain */
if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) {
Expand Down
Loading

0 comments on commit fe14d5f

Please sign in to comment.