[Intel-gfx] [PATCH 26/33] drm/i915: Track pinned VMA
Chris Wilson
chris at chris-wilson.co.uk
Thu Aug 11 12:37:26 UTC 2016
On Thu, Aug 11, 2016 at 03:18:44PM +0300, Joonas Lahtinen wrote:
> On su, 2016-08-07 at 15:45 +0100, Chris Wilson wrote:
> > @@ -1616,7 +1618,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
> >
> > /**
> > * i915_gem_fault - fault a page into the GTT
> > - * @vma: VMA in question
> > + * @mm: VMA in question
>
> should be @vm or whatever the correct name.
>
> > * @vmf: fault info
> > *
> > * The fault handler is set up by drm_gem_mmap() when a object is GTT mapped
> > @@ -1630,20 +1632,21 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
> > * suffer if the GTT working set is large or there are few fence registers
> > * left.
> > */
> > -int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
> > +int i915_gem_fault(struct vm_area_struct *vm, struct vm_fault *vmf)
>
> 'vm' is used elsewhere for the address space, maybe 'kvma'? Or 'area'
> (used in linux/mm.h too occasionally)
I also was tempted by kvma. But area is better.
>
> > @@ -1722,13 +1726,13 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
> > } else {
> > if (!obj->fault_mappable) {
> > unsigned long size = min_t(unsigned long,
> > - vma->vm_end - vma->vm_start,
> > + vm->vm_end - vm->vm_start,
> > obj->base.size);
> > int i;
> >
> > for (i = 0; i < size >> PAGE_SHIFT; i++) {
> > - ret = vm_insert_pfn(vma,
> > - (unsigned long)vma->vm_start + i * PAGE_SIZE,
> > + ret = vm_insert_pfn(vm,
> > + (unsigned long)vm->vm_start + i * PAGE_SIZE,
>
> Hmm, vm->vm_start is already unsigned long, so cast could be
> eliminated.
>
> > pfn + i);
> > if (ret)
> > break;
> > @@ -1736,12 +1740,12 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
> >
> > obj->fault_mappable = true;
> > } else
> > - ret = vm_insert_pfn(vma,
> > + ret = vm_insert_pfn(vm,
> > (unsigned long)vmf->virtual_address,
> > pfn + page_offset);
> > }
> > err_unpin:
> > - i915_gem_object_ggtt_unpin_view(obj, &view);
> > + __i915_vma_unpin(vma);
> > err_unlock:
> > mutex_unlock(&dev->struct_mutex);
> > err_rpm:
> > @@ -3190,7 +3194,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
> > old_write_domain);
> >
> > /* And bump the LRU for this access */
> > - vma = i915_gem_obj_to_ggtt(obj);
> > + vma = i915_gem_object_to_ggtt(obj, NULL);
> > if (vma &&
> > drm_mm_node_allocated(&vma->node) &&
> > !i915_vma_is_active(vma))
> > @@ -3414,11 +3418,12 @@ rpm_put:
> > * Can be called from an uninterruptible phase (modesetting) and allows
> > * any flushes to be pipelined (for pageflips).
> > */
> > -int
> > +struct i915_vma *
> > i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
> > u32 alignment,
> > const struct i915_ggtt_view *view)
> > {
> > + struct i915_vma *vma;
> > u32 old_read_domains, old_write_domain;
> > int ret;
> >
> > @@ -3438,19 +3443,23 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
> > */
> > ret = i915_gem_object_set_cache_level(obj,
> > HAS_WT(obj->base.dev) ? I915_CACHE_WT : I915_CACHE_NONE);
> > - if (ret)
> > + if (ret) {
> > + vma = ERR_PTR(ret);
> > goto err_unpin_display;
> > + }
> >
> > /* As the user may map the buffer once pinned in the display plane
> > * (e.g. libkms for the bootup splash), we have to ensure that we
> > * always use map_and_fenceable for all scanout buffers.
> > */
> > - ret = i915_gem_object_ggtt_pin(obj, view, 0, alignment,
> > + vma = i915_gem_object_ggtt_pin(obj, view, 0, alignment,
> > view->type == I915_GGTT_VIEW_NORMAL ?
> > PIN_MAPPABLE : 0);
> > - if (ret)
> > + if (IS_ERR(vma))
> > goto err_unpin_display;
> >
> > + WARN_ON(obj->pin_display > i915_vma_pin_count(vma));
> > +
> > i915_gem_object_flush_cpu_write_domain(obj);
> >
> > old_write_domain = obj->base.write_domain;
> > @@ -3466,23 +3475,23 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
> > old_read_domains,
> > old_write_domain);
> >
> > - return 0;
> > + return vma;
> >
> > err_unpin_display:
> > obj->pin_display--;
> > - return ret;
> > + return vma;
> > }
> >
> > void
> > -i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj,
> > - const struct i915_ggtt_view *view)
> > +i915_gem_object_unpin_from_display_plane(struct i915_vma *vma)
> > {
> > - if (WARN_ON(obj->pin_display == 0))
> > + if (WARN_ON(vma->obj->pin_display == 0))
> > return;
> >
> > - i915_gem_object_ggtt_unpin_view(obj, view);
> > + vma->obj->pin_display--;
> >
> > - obj->pin_display--;
> > + i915_vma_unpin(vma);
> > + WARN_ON(vma->obj->pin_display > i915_vma_pin_count(vma));
> > }
> >
> > /**
> > @@ -3679,27 +3688,25 @@ err:
> > return ret;
> > }
> >
> > -int
> > +struct i915_vma *
> > i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
> > - const struct i915_ggtt_view *view,
> > + const struct i915_ggtt_view *ggtt_view,
>
> Hmm, why distinctive name compared to other places? This function has
> _ggtt_ in the name, so should be implicit.
>
> > u64 size,
> > u64 alignment,
> > u64 flags)
> > {
>
> <SNIP>
>
> > -/* All the new VM stuff */
>
> Oh noes, we destroy all the new stuff :P
>
> > @@ -349,30 +349,34 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
> > struct drm_i915_gem_relocation_entry *reloc,
> > uint64_t target_offset)
> > {
> > - struct drm_device *dev = obj->base.dev;
> > - struct drm_i915_private *dev_priv = to_i915(dev);
> > + struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
> > struct i915_ggtt *ggtt = &dev_priv->ggtt;
> > + struct i915_vma *vma;
> > uint64_t delta = relocation_target(reloc, target_offset);
> > uint64_t offset;
> > void __iomem *reloc_page;
> > int ret;
> >
> > + vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
> > + if (IS_ERR(vma))
> > + return PTR_ERR(vma);
> > +
> > ret = i915_gem_object_set_to_gtt_domain(obj, true);
> > if (ret)
> > - return ret;
> > + goto unpin;
> >
> > ret = i915_gem_object_put_fence(obj);
> > if (ret)
> > - return ret;
> > + goto unpin;
> >
> > /* Map the page containing the relocation we're going to perform. */
> > - offset = i915_gem_obj_ggtt_offset(obj);
> > + offset = vma->node.start;
> > offset += reloc->offset;
>
> Could concatenate to previous line now;
>
> offset = vma->node.start + reloc->offset;
>
> > -static struct i915_vma*
> > +static struct i915_vma *
> > i915_gem_execbuffer_parse(struct intel_engine_cs *engine,
> > struct drm_i915_gem_exec_object2 *shadow_exec_entry,
> > struct drm_i915_gem_object *batch_obj,
> > @@ -1305,31 +1311,30 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *engine,
> > batch_start_offset,
> > batch_len,
> > is_master);
> > - if (ret)
> > + if (ret) {
> > + if (ret == -EACCES) /* unhandled chained batch */
> > + vma = NULL;
> > + else
> > + vma = ERR_PTR(ret);
> > goto err;
> > + }
> >
> > - ret = i915_gem_object_ggtt_pin(shadow_batch_obj, NULL, 0, 0, 0);
> > - if (ret)
> > + vma = i915_gem_object_ggtt_pin(shadow_batch_obj, NULL, 0, 0, 0);
> > + if (IS_ERR(vma)) {
> > + ret = PTR_ERR(vma);
>
> Hmm, 'err' label no longer cares about ret, so this is redundant. Or
> should the ret-to-vma translation been kept at the end?
>
> > goto err;
> > -
> > - i915_gem_object_unpin_pages(shadow_batch_obj);
> > + }
> >
> > memset(shadow_exec_entry, 0, sizeof(*shadow_exec_entry));
> >
> > - vma = i915_gem_obj_to_ggtt(shadow_batch_obj);
> > vma->exec_entry = shadow_exec_entry;
> > vma->exec_entry->flags = __EXEC_OBJECT_HAS_PIN;
> > i915_gem_object_get(shadow_batch_obj);
> > list_add_tail(&vma->exec_list, &eb->vmas);
> >
> > - return vma;
> > -
> > err:
> > i915_gem_object_unpin_pages(shadow_batch_obj);
> > - if (ret == -EACCES) /* unhandled chained batch */
> > - return NULL;
> > - else
> > - return ERR_PTR(ret);
> > + return vma;
> > }
> >
>
> <SNIP>
>
> > @@ -432,13 +432,7 @@ bool
> > i915_gem_object_pin_fence(struct drm_i915_gem_object *obj)
> > {
> > if (obj->fence_reg != I915_FENCE_REG_NONE) {
> > - struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
> > - struct i915_vma *ggtt_vma = i915_gem_obj_to_ggtt(obj);
> > -
> > - WARN_ON(!ggtt_vma ||
> > - dev_priv->fence_regs[obj->fence_reg].pin_count >
> > - i915_vma_pin_count(ggtt_vma));
>
> Is this WARN_ON deliberately removed, not worthy GEM_BUG_ON?
The pin_count check is not strictly true for all futures, and the
ggtt_vma can just explode if NULL until it too is replaced in a few
patches time.
> > - dev_priv->fence_regs[obj->fence_reg].pin_count++;
> > + to_i915(obj->base.dev)->fence_regs[obj->fence_reg].pin_count++;
>
> This is not the most readable line of code one can imagine. dev_priv
> alias does make readability better occasionally.
This just makes another patch smaller. I've not qualms about this line
;)
> > @@ -3351,14 +3351,10 @@ __i915_gem_vma_create(struct drm_i915_gem_object *obj,
> >
> > GEM_BUG_ON(vm->closed);
> >
> > - if (WARN_ON(i915_is_ggtt(vm) != !!view))
> > - return ERR_PTR(-EINVAL);
> > -
> > vma = kmem_cache_zalloc(to_i915(obj->base.dev)->vmas, GFP_KERNEL);
> > if (vma == NULL)
> > return ERR_PTR(-ENOMEM);
> >
> > - INIT_LIST_HEAD(&vma->obj_link);
>
> This disappears completely?
It was never required.
> > @@ -3378,56 +3373,76 @@ __i915_gem_vma_create(struct drm_i915_gem_object *obj,
> > +static inline bool vma_matches(struct i915_vma *vma,
> > + struct i915_address_space *vm,
> > + const struct i915_ggtt_view *view)
>
> Function name is not clearest. But I can not suggest a better one off
> the top of my head.
>
> > static struct drm_i915_error_object *
> > i915_error_object_create(struct drm_i915_private *dev_priv,
> > - struct drm_i915_gem_object *src,
> > - struct i915_address_space *vm)
> > + struct i915_vma *vma)
> > {
> > struct i915_ggtt *ggtt = &dev_priv->ggtt;
> > + struct drm_i915_gem_object *src;
> > struct drm_i915_error_object *dst;
> > - struct i915_vma *vma = NULL;
> > int num_pages;
> > bool use_ggtt;
> > int i = 0;
> > u64 reloc_offset;
> >
> > - if (src == NULL || src->pages == NULL)
> > + if (!vma)
> > + return NULL;
> > +
> > + src = vma->obj;
> > + if (!src->pages)
> > return NULL;
> >
> > num_pages = src->base.size >> PAGE_SHIFT;
> >
> > dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC);
> > - if (dst == NULL)
> > + if (!dst)
> > return NULL;
> >
> > - if (i915_gem_obj_bound(src, vm))
> > - dst->gtt_offset = i915_gem_obj_offset(src, vm);
> > - else
> > - dst->gtt_offset = -1;
>
> What was the purpose of this line previously, the calculations would
> get majestically messed up?
No purpose. It would have taken quite a bit of abuse to be able to
trigger it, and certainly nothing relevant to the hang.
> > @@ -1035,11 +1029,8 @@ static void i915_gem_record_rings(struct drm_i915_private *dev_priv,
> > struct drm_i915_gem_request *request;
> > int i, count;
> >
> > - if (dev_priv->semaphore) {
> > - error->semaphore =
> > - i915_error_ggtt_object_create(dev_priv,
> > - dev_priv->semaphore->obj);
> > - }
> > + error->semaphore =
> > + i915_error_object_create(dev_priv, dev_priv->semaphore);
>
> Not sure if I like hiding the NULL tolerancy inside the function.
Otoh, it makes it a lot cleaner.
> > @@ -2291,7 +2293,8 @@ void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
> > if (view.type == I915_GGTT_VIEW_NORMAL)
> > i915_gem_object_unpin_fence(obj);
> >
> > - i915_gem_object_unpin_from_display_plane(obj, &view);
> > + vma = i915_gem_object_to_ggtt(obj, &view);
>
> GEM_BUG_ON(!vma)?
The goal and original patch passed in the vma to free. I gave up
tracking that patch through the ongoing atomic transition.
> This might be the only acceptable use of if () in teardown path.
>
> I hope there is an excellent revision listing in the next iteration.
> This was a pain to go through.
vN: Address some of Joonas's stylistic nitpicks.
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
More information about the Intel-gfx
mailing list