From patchwork Sat May 10 03:59:51 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Widawsky X-Patchwork-Id: 4146531 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 0EBBBC0ACC for ; Sat, 10 May 2014 04:03:19 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 22E06201F7 for ; Sat, 10 May 2014 04:03:18 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 12235201DE for ; Sat, 10 May 2014 04:03:17 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 727C86F0B2; Fri, 9 May 2014 21:03:16 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mail.bwidawsk.net (bwidawsk.net [166.78.191.112]) by gabe.freedesktop.org (Postfix) with ESMTP id 133A86F0B2 for ; Fri, 9 May 2014 21:03:16 -0700 (PDT) Received: by mail.bwidawsk.net (Postfix, from userid 5001) id 1A0095809D; Fri, 9 May 2014 21:03:15 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from ironside.intel.com (c-24-21-100-90.hsd1.or.comcast.net [24.21.100.90]) by mail.bwidawsk.net (Postfix) with ESMTPSA id D438C580A3; Fri, 9 May 2014 21:00:34 -0700 (PDT) From: Ben Widawsky To: Intel GFX Date: Fri, 9 May 2014 20:59:51 -0700 Message-Id: <1399694391-3935-57-git-send-email-benjamin.widawsky@intel.com> X-Mailer: git-send-email 1.9.2 In-Reply-To: <1399694391-3935-1-git-send-email-benjamin.widawsky@intel.com> References: <1399694391-3935-1-git-send-email-benjamin.widawsky@intel.com> Cc: Ben Widawsky , Ben Widawsky Subject: [Intel-gfx] [PATCH 56/56] drm/i915/userptr: Mirror GPU addr at ioctl (HACK/POC) X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP This is needed for the proof of concept work that will allow mirrored GPU addressing via the existing userptr interface. Part of the hack involves passing the context ID to the ioctl in order to get a VM. Signed-off-by: Ben Widawsky --- drivers/gpu/drm/i915/i915_gem_userptr.c | 120 +++++++++++++++++++++++++------- include/uapi/drm/i915_drm.h | 7 +- 2 files changed, 98 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index 5da37cc..795ea3e 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -224,10 +224,6 @@ i915_mmu_notifier_add(struct i915_mmu_notifier *mmu, * remove the objects from the interval tree) before we do * the check for overlapping objects. */ - ret = i915_mutex_lock_interruptible(mmu->dev); - if (ret) - return ret; - i915_gem_retire_requests(mmu->dev); /* Disallow overlapping userptr objects */ @@ -253,7 +249,6 @@ i915_mmu_notifier_add(struct i915_mmu_notifier *mmu, ret = 0; } spin_unlock(&mmu->lock); - mutex_unlock(&mmu->dev->struct_mutex); return ret; } @@ -283,19 +278,12 @@ i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj, return capable(CAP_SYS_ADMIN) ? 0 : -EPERM; down_write(&obj->userptr.mm->mmap_sem); - ret = i915_mutex_lock_interruptible(obj->base.dev); - if (ret == 0) { - mmu = i915_mmu_notifier_get(obj->base.dev, obj->userptr.mm); - if (!IS_ERR(mmu)) - mmu->count++; /* preemptive add to act as a refcount */ - else - ret = PTR_ERR(mmu); - mutex_unlock(&obj->base.dev->struct_mutex); - } + mmu = i915_mmu_notifier_get(obj->base.dev, obj->userptr.mm); + if (!IS_ERR(mmu)) + mmu->count++; /* preemptive add to act as a refcount */ + else + ret = PTR_ERR(mmu); up_write(&obj->userptr.mm->mmap_sem); - if (ret) - return ret; - mn = kzalloc(sizeof(*mn), GFP_KERNEL); if (mn == NULL) { ret = -ENOMEM; @@ -588,6 +576,52 @@ i915_gem_userptr_release(struct drm_i915_gem_object *obj) } } +/* Carve out the address space for later use */ +static int i915_gem_userptr_reserve_vma(struct drm_i915_gem_object *obj, + struct i915_address_space *vm, + uint64_t offset, + uint64_t size) +{ + struct i915_vma *vma; + int ret; + + vma = i915_gem_obj_to_vma(obj, vm); + if (vma) + return -ENXIO; + + vma = i915_gem_obj_lookup_or_create_vma(obj, vm); + if (!vma) + return PTR_ERR(vma); + + BUG_ON(!drm_mm_initialized(&vm->mm)); + + if (vma->uptr) { + DRM_INFO("Already had a userptr\n"); + return 0; + } + if (vma->node.allocated) { + DRM_INFO("Node was previously allocated\n"); + return -EBUSY; + } + + vma->node.start = offset; + vma->node.size = size; + vma->node.color = 0; + ret = drm_mm_reserve_node(&vm->mm, &vma->node); + if (ret) { + /* There are two reasons this can fail. + * 1. The user is using a mix of relocs and userptr, and a reloc + * won. + * TODO: handle better. + */ + return ret; + } + + vma->uptr = 1; + + return 0; +} + static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = { .get_pages = i915_gem_userptr_get_pages, .put_pages = i915_gem_userptr_put_pages, @@ -630,37 +664,62 @@ static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = { int i915_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_file_private *file_priv = file->driver_priv; struct drm_i915_gem_userptr *args = data; struct drm_i915_gem_object *obj; + struct i915_hw_context *ctx; + struct i915_address_space *vm; int ret; u32 handle; + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + +#define goto_err(__err) do { \ + ret = (__err); \ + goto out; \ +} while (0) + + ctx = i915_gem_context_get(file_priv, args->ctx_id); + if (IS_ERR(ctx)) + goto_err(PTR_ERR(ctx)); + + /* i915_gem_context_reference(ctx); */ + if (args->flags & ~(I915_USERPTR_READ_ONLY | + I915_USERPTR_GPU_MIRROR | I915_USERPTR_UNSYNCHRONIZED)) - return -EINVAL; + goto_err(-EINVAL); if (offset_in_page(args->user_ptr | args->user_size)) - return -EINVAL; - - if (args->user_size > dev_priv->gtt.base.total) - return -E2BIG; + goto_err(-EINVAL); if (!access_ok(args->flags & I915_USERPTR_READ_ONLY ? VERIFY_READ : VERIFY_WRITE, (char __user *)(unsigned long)args->user_ptr, args->user_size)) - return -EFAULT; + goto_err(-EFAULT); if (args->flags & I915_USERPTR_READ_ONLY) { /* On almost all of the current hw, we cannot tell the GPU that a * page is readonly, so this is just a placeholder in the uAPI. */ - return -ENODEV; + goto_err(-ENODEV); + } + + vm = ctx->vm; + if (args->user_size > vm->total) + goto_err(-E2BIG); + + if (args->flags & I915_USERPTR_GPU_MIRROR) { + if (!HAS_48B_PPGTT(dev)) + goto_err(-ENODEV); } /* Allocate the new object */ obj = i915_gem_object_alloc(dev); if (obj == NULL) - return -ENOMEM; + goto_err(-ENOMEM); +#undef goto_err drm_gem_private_object_init(dev, &obj->base, args->user_size); i915_gem_object_init(obj, &i915_gem_userptr_ops); @@ -680,9 +739,16 @@ i915_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file ret = i915_gem_userptr_init__mmu_notifier(obj, args->flags); if (ret == 0) ret = drm_gem_handle_create(file, &obj->base, &handle); + if (ret == 0 && args->flags & I915_USERPTR_GPU_MIRROR) { + ret = i915_gem_userptr_reserve_vma(obj, vm, args->user_ptr, args->user_size); + if (ret) + DRM_DEBUG_DRIVER("Failed to reserve GPU mirror %d\n", ret); + } /* drop reference from allocate - handle holds it now */ - drm_gem_object_unreference_unlocked(&obj->base); + drm_gem_object_unreference(&obj->base); +out: + mutex_unlock(&dev->struct_mutex); if (ret) return ret; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index dd98463..addab22 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -1056,15 +1056,18 @@ struct drm_i915_reset_stats { struct drm_i915_gem_userptr { __u64 user_ptr; __u64 user_size; + __u32 ctx_id; __u32 flags; -#define I915_USERPTR_READ_ONLY 0x1 -#define I915_USERPTR_UNSYNCHRONIZED 0x80000000 +#define I915_USERPTR_READ_ONLY (1<<0) +#define I915_USERPTR_GPU_MIRROR (1<<1) +#define I915_USERPTR_UNSYNCHRONIZED (1<<31) /** * Returned handle for the object. * * Object handles are nonzero. */ __u32 handle; + __u32 pad; }; #endif /* _UAPI_I915_DRM_H_ */