From patchwork Tue Sep 4 20:03:10 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Wilson X-Patchwork-Id: 1403981 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork1.kernel.org (Postfix) with ESMTP id 393EF3FC71 for ; Tue, 4 Sep 2012 20:15:34 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id F29009EA03 for ; Tue, 4 Sep 2012 13:15:33 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from fireflyinternet.com (smtp.fireflyinternet.com [109.228.6.236]) by gabe.freedesktop.org (Postfix) with ESMTP id 12DDDA01FA for ; Tue, 4 Sep 2012 13:06:34 -0700 (PDT) X-Default-Received-SPF: pass (skip=forwardok (res=PASS)) x-ip-name=78.156.73.22; Received: from arrandale.alporthouse.com (unverified [78.156.73.22]) by fireflyinternet.com (Firefly Internet SMTP) with ESMTP id 121597524-1500050 for multiple; Tue, 04 Sep 2012 21:06:27 +0100 From: Chris Wilson To: intel-gfx@lists.freedesktop.org Date: Tue, 4 Sep 2012 21:03:10 +0100 Message-Id: <1346788996-19080-19-git-send-email-chris@chris-wilson.co.uk> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1346788996-19080-1-git-send-email-chris@chris-wilson.co.uk> References: <1346788996-19080-1-git-send-email-chris@chris-wilson.co.uk> X-Originating-IP: 78.156.73.22 Subject: [Intel-gfx] [PATCH 18/24] drm/i915: Handle stolen objects for pread X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org Errors-To: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 175 ++++++++++++++++++++++++++------------- 1 file changed, 116 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7946d73..070ddf2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -324,24 +324,21 @@ __copy_from_user_swizzled(char *gpu_vaddr, int gpu_offset, * Flushes invalid cachelines before reading the target if * needs_clflush is set. */ static int -shmem_pread_fast(struct page *page, int shmem_page_offset, int page_length, +shmem_pread_fast(char *vaddr, int shmem_page_offset, int page_length, char __user *user_data, bool page_do_bit17_swizzling, bool needs_clflush) { - char *vaddr; int ret; if (unlikely(page_do_bit17_swizzling)) return -EINVAL; - vaddr = kmap_atomic(page); if (needs_clflush) drm_clflush_virt_range(vaddr + shmem_page_offset, page_length); ret = __copy_to_user_inatomic(user_data, vaddr + shmem_page_offset, page_length); - kunmap_atomic(vaddr); return ret ? -EFAULT : 0; } @@ -371,14 +368,12 @@ shmem_clflush_swizzled_range(char *addr, unsigned long length, /* Only difference to the fast-path function is that this can handle bit17 * and uses non-atomic copy and kmap functions. */ static int -shmem_pread_slow(struct page *page, int shmem_page_offset, int page_length, +shmem_pread_slow(char *vaddr, int shmem_page_offset, int page_length, char __user *user_data, bool page_do_bit17_swizzling, bool needs_clflush) { - char *vaddr; int ret; - vaddr = kmap(page); if (needs_clflush) shmem_clflush_swizzled_range(vaddr + shmem_page_offset, page_length, @@ -392,7 +387,6 @@ shmem_pread_slow(struct page *page, int shmem_page_offset, int page_length, ret = __copy_to_user(user_data, vaddr + shmem_page_offset, page_length); - kunmap(page); return ret ? - EFAULT : 0; } @@ -403,6 +397,7 @@ i915_gem_shmem_pread(struct drm_device *dev, struct drm_i915_gem_pread *args, struct drm_file *file) { + struct drm_i915_private *dev_priv = dev->dev_private; char __user *user_data; ssize_t remain; loff_t offset; @@ -433,76 +428,138 @@ i915_gem_shmem_pread(struct drm_device *dev, } } - ret = i915_gem_object_get_pages(obj); - if (ret) - return ret; + offset = args->offset; - i915_gem_object_pin_pages(obj); + if (obj->stolen) { + char *vaddr; - offset = args->offset; + vaddr = (char *)dev_priv->mm.stolen_base; + vaddr += obj->stolen->start + offset; - for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) { - struct page *page; + shmem_page_offset = offset_in_page(offset); + while (remain > 0) { + /* Operation in this page + * + * shmem_page_offset = offset within page in shmem file + * page_length = bytes to copy for this page + */ + page_length = remain; + if ((shmem_page_offset + page_length) > PAGE_SIZE) + page_length = PAGE_SIZE - shmem_page_offset; - if (i < offset >> PAGE_SHIFT) - continue; + page_do_bit17_swizzling = obj_do_bit17_swizzling && + ((uintptr_t)vaddr & (1 << 17)) != 0; - if (remain <= 0) - break; + ret = shmem_pread_fast(vaddr, shmem_page_offset, page_length, + user_data, page_do_bit17_swizzling, + needs_clflush); + if (ret == 0) + goto next_stolen; - /* Operation in this page - * - * shmem_page_offset = offset within page in shmem file - * page_length = bytes to copy for this page - */ - shmem_page_offset = offset_in_page(offset); - page_length = remain; - if ((shmem_page_offset + page_length) > PAGE_SIZE) - page_length = PAGE_SIZE - shmem_page_offset; + hit_slowpath = 1; + mutex_unlock(&dev->struct_mutex); - page = sg_page(sg); - page_do_bit17_swizzling = obj_do_bit17_swizzling && - (page_to_phys(page) & (1 << 17)) != 0; + if (!prefaulted) { + ret = fault_in_multipages_writeable(user_data, remain); + /* Userspace is tricking us, but we've already clobbered + * its pages with the prefault and promised to write the + * data up to the first fault. Hence ignore any errors + * and just continue. */ + (void)ret; + prefaulted = 1; + } - ret = shmem_pread_fast(page, shmem_page_offset, page_length, - user_data, page_do_bit17_swizzling, - needs_clflush); - if (ret == 0) - goto next_page; + ret = shmem_pread_slow(vaddr, shmem_page_offset, page_length, + user_data, page_do_bit17_swizzling, + needs_clflush); - hit_slowpath = 1; - mutex_unlock(&dev->struct_mutex); + mutex_lock(&dev->struct_mutex); + if (ret) + goto out; - if (!prefaulted) { - ret = fault_in_multipages_writeable(user_data, remain); - /* Userspace is tricking us, but we've already clobbered - * its pages with the prefault and promised to write the - * data up to the first fault. Hence ignore any errors - * and just continue. */ - (void)ret; - prefaulted = 1; +next_stolen: + remain -= page_length; + user_data += page_length; + vaddr += page_length; + shmem_page_offset = 0; } + } else { + ret = i915_gem_object_get_pages(obj); + if (ret) + return ret; - ret = shmem_pread_slow(page, shmem_page_offset, page_length, - user_data, page_do_bit17_swizzling, - needs_clflush); + i915_gem_object_pin_pages(obj); - mutex_lock(&dev->struct_mutex); + for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) { + char *vaddr; + struct page *page; -next_page: - mark_page_accessed(page); + if (i < offset >> PAGE_SHIFT) + continue; - if (ret) - goto out; + if (remain <= 0) + break; - remain -= page_length; - user_data += page_length; - offset += page_length; + /* Operation in this page + * + * shmem_page_offset = offset within page in shmem file + * page_length = bytes to copy for this page + */ + shmem_page_offset = offset_in_page(offset); + page_length = remain; + if ((shmem_page_offset + page_length) > PAGE_SIZE) + page_length = PAGE_SIZE - shmem_page_offset; + + page = sg_page(sg); + mark_page_accessed(page); + + page_do_bit17_swizzling = obj_do_bit17_swizzling && + (page_to_phys(page) & (1 << 17)) != 0; + + vaddr = kmap_atomic(page); + ret = shmem_pread_fast(vaddr, shmem_page_offset, page_length, + user_data, page_do_bit17_swizzling, + needs_clflush); + kunmap_atomic(vaddr); + + if (ret == 0) + goto next_page; + + hit_slowpath = 1; + mutex_unlock(&dev->struct_mutex); + + if (!prefaulted) { + ret = fault_in_multipages_writeable(user_data, remain); + /* Userspace is tricking us, but we've already clobbered + * its pages with the prefault and promised to write the + * data up to the first fault. Hence ignore any errors + * and just continue. */ + (void)ret; + prefaulted = 1; + } + + vaddr = kmap(page); + ret = shmem_pread_slow(vaddr, shmem_page_offset, page_length, + user_data, page_do_bit17_swizzling, + needs_clflush); + kunmap(page); + + mutex_lock(&dev->struct_mutex); + + if (ret) + goto out_unpin; + +next_page: + remain -= page_length; + user_data += page_length; + offset += page_length; + } +out_unpin: + i915_gem_object_unpin_pages(obj); } -out: - i915_gem_object_unpin_pages(obj); +out: if (hit_slowpath) { /* Fixup: Kill any reinstated backing storage pages */ if (obj->madv == __I915_MADV_PURGED)