From patchwork Tue Jun 4 10:37:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abdiel Janulgue X-Patchwork-Id: 10974695 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E07A113AD for ; Tue, 4 Jun 2019 10:45:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C5D3C2880F for ; Tue, 4 Jun 2019 10:45:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BA31A2880C; Tue, 4 Jun 2019 10:45:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 184F9287FE for ; Tue, 4 Jun 2019 10:45:03 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 8A9E6893EC; Tue, 4 Jun 2019 10:45:02 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by gabe.freedesktop.org (Postfix) with ESMTPS id BF406893EC for ; Tue, 4 Jun 2019 10:45:01 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 04 Jun 2019 03:45:00 -0700 X-ExtLoop1: 1 Received: from skylake-nuc.fi.intel.com ([10.237.72.185]) by fmsmga005.fm.intel.com with ESMTP; 04 Jun 2019 03:44:58 -0700 From: Abdiel Janulgue To: intel-gfx@lists.freedesktop.org Date: Tue, 4 Jun 2019 13:37:23 +0300 Message-Id: <20190604103723.23041-1-abdiel.janulgue@linux.intel.com> X-Mailer: git-send-email 2.19.1 MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH] drm/i915: Split out GTT fault handler to make it generic X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthew Auld Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP Allow reuse of the fault-handling code in preparation for having multiple fault handlers depending on the mmaping type and backing storage. Cc: Matthew Auld Cc: Chris Wilson Cc: Joonas Lahtinen Signed-off-by: Abdiel Janulgue --- drivers/gpu/drm/i915/gem/i915_gem_mman.c | 208 ++++++++++++++--------- 1 file changed, 132 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c index c7b9b34de01b..ed20fab66d2f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@ -197,6 +197,133 @@ compute_partial_view(const struct drm_i915_gem_object *obj, return view; } +struct gem_object_fault { + struct drm_i915_gem_object *obj; + pgoff_t page_offset; + intel_wakeref_t wakeref; + int srcu; + bool pin_vma; + vm_fault_t error_ret; +}; + +static vm_fault_t __vm_fault_from_error(struct drm_i915_private *i915, + int fault_ret) +{ + switch (fault_ret) { + case -EIO: + /* + * We eat errors when the gpu is terminally wedged to avoid + * userspace unduly crashing (gl has no provisions for mmaps to + * fail). But any other -EIO isn't ours (e.g. swap in failure) + * and so needs to be reported. + */ + if (!i915_terminally_wedged(i915)) + return VM_FAULT_SIGBUS; + /* else: fall through */ + case -EAGAIN: + /* + * EAGAIN means the gpu is hung and we'll wait for the error + * handler to reset everything when re-faulting in + * i915_mutex_lock_interruptible. + */ + case 0: + case -ERESTARTSYS: + case -EINTR: + case -EBUSY: + /* + * EBUSY is ok: this just means that another thread + * already did the job. + */ + return VM_FAULT_NOPAGE; + case -ENOMEM: + return VM_FAULT_OOM; + case -ENOSPC: + case -EFAULT: + return VM_FAULT_SIGBUS; + default: + WARN_ONCE(fault_ret, "unhandled error in %s: %i\n", __func__, + fault_ret); + return VM_FAULT_SIGBUS; + } +} + +static int __prepare_object_fault(struct vm_fault *vmf, + bool pin_vma, + struct gem_object_fault *f) +{ + struct vm_area_struct *area = vmf->vma; + struct drm_i915_gem_object *obj = to_intel_bo(area->vm_private_data); + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + bool write = area->vm_flags & VM_WRITE; + int ret; + + /* Sanity check that we allow writing into this object */ + if (i915_gem_object_is_readonly(obj) && write) { + f->error_ret = VM_FAULT_SIGBUS; + return -EACCES; + } + + f->obj = obj; + /* We don't use vmf->pgoff since that has the fake offset */ + f->page_offset = (vmf->address - area->vm_start) >> PAGE_SHIFT; + + trace_i915_gem_object_fault(obj, f->page_offset, true, write); + + ret = i915_gem_object_pin_pages(obj); + if (ret) + goto err; + + f->wakeref = intel_runtime_pm_get(dev_priv); + + f->srcu = i915_reset_trylock(dev_priv); + if (f->srcu < 0) { + ret = f->srcu; + goto err_rpm; + } + + f->pin_vma = pin_vma; + if (f->pin_vma) { + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto err_reset; + } + + /* Access to snoopable pages through the GTT is incoherent. */ + if (obj->cache_level != I915_CACHE_NONE && !HAS_LLC(dev_priv)) { + ret = -EFAULT; + goto err_unlock; + } + + return 0; + +err_unlock: + if (f->pin_vma) + mutex_unlock(&dev->struct_mutex); +err_reset: + i915_reset_unlock(dev_priv, f->srcu); +err_rpm: + intel_runtime_pm_put(dev_priv, f->wakeref); + i915_gem_object_unpin_pages(obj); +err: + f->error_ret = __vm_fault_from_error(dev_priv, ret); + return ret; +} + +static vm_fault_t __object_fault_fini(int fault_ret, struct gem_object_fault *f) +{ + struct drm_device *dev = f->obj->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + + if (f->pin_vma) + mutex_unlock(&dev->struct_mutex); + i915_reset_unlock(dev_priv, f->srcu); + intel_runtime_pm_put(dev_priv, f->wakeref); + i915_gem_object_unpin_pages(f->obj); + + return __vm_fault_from_error(dev_priv, fault_ret); +} + /** * i915_gem_fault - fault a page into the GTT * @vmf: fault info @@ -223,43 +350,13 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf) struct drm_device *dev = obj->base.dev; struct drm_i915_private *i915 = to_i915(dev); struct i915_ggtt *ggtt = &i915->ggtt; - bool write = area->vm_flags & VM_WRITE; - intel_wakeref_t wakeref; struct i915_vma *vma; pgoff_t page_offset; - int srcu; + struct gem_object_fault fault; int ret; - /* Sanity check that we allow writing into this object */ - if (i915_gem_object_is_readonly(obj) && write) - return VM_FAULT_SIGBUS; - - /* We don't use vmf->pgoff since that has the fake offset */ - page_offset = (vmf->address - area->vm_start) >> PAGE_SHIFT; - - trace_i915_gem_object_fault(obj, page_offset, true, write); - - ret = i915_gem_object_pin_pages(obj); - if (ret) - goto err; - - wakeref = intel_runtime_pm_get(i915); - - srcu = i915_reset_trylock(i915); - if (srcu < 0) { - ret = srcu; - goto err_rpm; - } - - ret = i915_mutex_lock_interruptible(dev); - if (ret) - goto err_reset; - - /* Access to snoopable pages through the GTT is incoherent. */ - if (obj->cache_level != I915_CACHE_NONE && !HAS_LLC(i915)) { - ret = -EFAULT; - goto err_unlock; - } + if (__prepare_object_fault(vmf, true, &fault)) + return fault.error_ret; /* Now pin it into the GTT as needed */ vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, @@ -291,7 +388,7 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf) } if (IS_ERR(vma)) { ret = PTR_ERR(vma); - goto err_unlock; + goto err; } ret = i915_vma_pin_fence(vma); @@ -322,49 +419,8 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf) i915_vma_unpin_fence(vma); err_unpin: __i915_vma_unpin(vma); -err_unlock: - mutex_unlock(&dev->struct_mutex); -err_reset: - i915_reset_unlock(i915, srcu); -err_rpm: - intel_runtime_pm_put(i915, wakeref); - i915_gem_object_unpin_pages(obj); err: - switch (ret) { - case -EIO: - /* - * We eat errors when the gpu is terminally wedged to avoid - * userspace unduly crashing (gl has no provisions for mmaps to - * fail). But any other -EIO isn't ours (e.g. swap in failure) - * and so needs to be reported. - */ - if (!i915_terminally_wedged(i915)) - return VM_FAULT_SIGBUS; - /* else: fall through */ - case -EAGAIN: - /* - * EAGAIN means the gpu is hung and we'll wait for the error - * handler to reset everything when re-faulting in - * i915_mutex_lock_interruptible. - */ - case 0: - case -ERESTARTSYS: - case -EINTR: - case -EBUSY: - /* - * EBUSY is ok: this just means that another thread - * already did the job. - */ - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - case -ENOSPC: - case -EFAULT: - return VM_FAULT_SIGBUS; - default: - WARN_ONCE(ret, "unhandled error in %s: %i\n", __func__, ret); - return VM_FAULT_SIGBUS; - } + return __object_fault_fini(ret, &fault); } void __i915_gem_object_release_mmap(struct drm_i915_gem_object *obj)