From patchwork Thu Oct 13 09:03:58 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tvrtko Ursulin X-Patchwork-Id: 9374583 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 298D860839 for ; Thu, 13 Oct 2016 09:04:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1915629E72 for ; Thu, 13 Oct 2016 09:04:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0DF1A29E7D; Thu, 13 Oct 2016 09:04:37 +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=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID 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 5CA0029E72 for ; Thu, 13 Oct 2016 09:04:36 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id DB8616E3E3; Thu, 13 Oct 2016 09:04:35 +0000 (UTC) X-Original-To: Intel-gfx@lists.freedesktop.org Delivered-To: Intel-gfx@lists.freedesktop.org Received: from mail-lf0-x244.google.com (mail-lf0-x244.google.com [IPv6:2a00:1450:4010:c07::244]) by gabe.freedesktop.org (Postfix) with ESMTPS id B10E76E3E3 for ; Thu, 13 Oct 2016 09:04:16 +0000 (UTC) Received: by mail-lf0-x244.google.com with SMTP id b75so11439235lfg.3 for ; Thu, 13 Oct 2016 02:04:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ursulin-net.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=fKQPAlQ0pldQtUCX93/lDojh2RDaVtKLn7WASX8MyG0=; b=nWYHZ2FotAAY8qwp0l70S1M/KnKXTXddXxpRKDMQ7aTJwgnxh31le1yudXNKoqqj/o 0VCLDA5EVnr/p4m9jPgQ5VkOuTEHkHARycwiZgI6jLUfyf4N93ArDv4IU6RNkgHmNJAw mJ/9EM9KIB8V8sI4ozKrl305lV2QlEUq6KdxLgk6YG8AG8H2e2Z4RATmXFVwxv3MLqyP 7g3AxPEhSlAirkXREt8ygSJJ+W4gl6B1noKrAvx9jnM7bhmyc9cBkPXelaPkrn+XaJhu nxASA3Da2Uyu1wvpEzs/abUWtV270GonVi2GbTkec2uA2rNL/XTwyA4STJU7JIbeHB3w winA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=fKQPAlQ0pldQtUCX93/lDojh2RDaVtKLn7WASX8MyG0=; b=QMsgOhgqILTN1FstQt6ofE5XFmlOOJgFMbI9A3XkskiH+AIiQ1fJOh2F0MjgvXA4VT S5V3It9GxX2sPw3+Yl5qooRpnVHoEwCE50bMR5B6MNKedCmh/XdsAqRGmOGoH5EaTdU2 xsu51meQRi4St1jSlR7QSWj1aKweoelAtqVYa7kvCJ4czkidcsV0MA63AP8bMXwvvYFl iP1Pe5a0TAYb8gKQ7uFLhX1MiQqyv9vshccdeCfdlANf36Lb+aN54VzMF/xDfNQwIKX9 Ooiqusr66uvEdXVmGXf5bJYORYLeuM2gx/bhLENmo54INwtWVqQ4a6PCO4OiI4NjcRLz Z8+A== X-Gm-Message-State: AA6/9RnYnCklRmbbZFIouXmk9Ki14BRJVYhp3c4Vtczp/PKHHz7Xms422N9OdpUGrBRAkA== X-Received: by 10.28.152.78 with SMTP id a75mr1363493wme.56.1476349454744; Thu, 13 Oct 2016 02:04:14 -0700 (PDT) Received: from localhost.localdomain ([2a02:c7d:9b6d:e300:916a:6cab:ac67:71c2]) by smtp.gmail.com with ESMTPSA id y2sm20776894wjx.20.2016.10.13.02.04.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 13 Oct 2016 02:04:14 -0700 (PDT) From: Tvrtko Ursulin X-Google-Original-From: Tvrtko Ursulin To: Intel-gfx@lists.freedesktop.org Date: Thu, 13 Oct 2016 10:03:58 +0100 Message-Id: <1476349444-7331-2-git-send-email-tvrtko.ursulin@linux.intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1476349444-7331-1-git-send-email-tvrtko.ursulin@linux.intel.com> References: <1476349444-7331-1-git-send-email-tvrtko.ursulin@linux.intel.com> Subject: [Intel-gfx] [RFC 1/7] drm/i915: Extract sg creation into a helper X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 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 From: Tvrtko Ursulin In order to reuse the same logic in several places in the driver, extract the logic which adds pages to the sg list and does the potential coalescing, into separate functions. Code wanting to build the sg table needs to do the following: 1. Call i915_sg_create to create the state object for a given maximum number of pages. 2. Iterate using i915_sg_for_each_page 3. Call i915_sg_add_page to add all the pages in order 4. On success call i915_sg_complete, or on failure i915_sg_abort In this patch only i915_gem_object_get_pages_gtt gets converted to use the new functions. Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/i915_gem.c | 153 ++++++++++++++++++++++++++++------------ 1 file changed, 109 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index fdd496e6c081..93b047735e6b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2216,18 +2216,104 @@ static unsigned long swiotlb_max_size(void) #endif } +struct i915_sg_create_state { + struct sg_table *st; + struct scatterlist *sg; + unsigned int idx; + unsigned int page_count; + unsigned long max_segment; + unsigned long last_pfn; +}; + +static struct i915_sg_create_state * +i915_sg_create(unsigned int page_count) +{ + struct i915_sg_create_state *state; + struct sg_table *st; + + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return ERR_PTR(-ENOMEM); + + st = kmalloc(sizeof(*st), GFP_KERNEL); + if (!st) { + kfree(state); + return ERR_PTR(-ENOMEM); + } + + if (sg_alloc_table(st, page_count, GFP_KERNEL)) { + kfree(st); + kfree(state); + return ERR_PTR(-ENOMEM); + } + + st->nents = 0; + state->st = st; + state->sg = st->sgl; + state->page_count = page_count; + state->idx = 0; + state->max_segment = swiotlb_max_size(); + if (!state->max_segment) + state->max_segment = page_count * PAGE_SIZE; + state->last_pfn = 0; + + return state; +} + +static void +i915_sg_add_page(struct i915_sg_create_state *state, struct page *page) +{ + unsigned long pfn = page_to_pfn(page); + struct scatterlist *sg = state->sg; + + if (!state->idx || + sg->length >= state->max_segment || + pfn != state->last_pfn + 1) { + if (state->idx) + sg = sg_next(sg); + state->st->nents++; + sg_set_page(sg, page, PAGE_SIZE, 0); + } else { + sg->length += PAGE_SIZE; + } + + state->last_pfn = pfn; + state->sg = sg; + state->idx++; +} + +static struct sg_table * +i915_sg_complete(struct i915_sg_create_state *state) +{ + struct sg_table *st = state->st; + + if (state->sg) /* fewer sg entries written than max allocated */ + sg_mark_end(state->sg); + + kfree(state); + + return st; +} + +static void +i915_sg_abort(struct i915_sg_create_state *state) +{ + sg_free_table(state->st); + kfree(state->st); + kfree(state); +} + +#define i915_sg_for_each_page(state) \ + for( ; (state)->idx < (state)->page_count; ) + static int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv = to_i915(obj->base.dev); - int page_count, i; struct address_space *mapping; - struct sg_table *st; - struct scatterlist *sg; + struct i915_sg_create_state *state; struct sgt_iter sgt_iter; struct page *page; - unsigned long last_pfn = 0; /* suppress gcc warning */ - unsigned long max_segment; int ret; gfp_t gfp; @@ -2238,19 +2324,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS); BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS); - max_segment = swiotlb_max_size(); - if (!max_segment) - max_segment = obj->base.size; - - st = kmalloc(sizeof(*st), GFP_KERNEL); - if (st == NULL) - return -ENOMEM; - - page_count = obj->base.size / PAGE_SIZE; - if (sg_alloc_table(st, page_count, GFP_KERNEL)) { - kfree(st); - return -ENOMEM; - } + state = i915_sg_create(obj->base.size / PAGE_SIZE); + if (IS_ERR(state)) + return PTR_ERR(state); /* Get the list of pages out of our struct file. They'll be pinned * at this point until we release them. @@ -2260,47 +2336,37 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) mapping = obj->base.filp->f_mapping; gfp = mapping_gfp_constraint(mapping, ~(__GFP_IO | __GFP_RECLAIM)); gfp |= __GFP_NORETRY | __GFP_NOWARN; - sg = st->sgl; - st->nents = 0; - for (i = 0; i < page_count; i++) { - page = shmem_read_mapping_page_gfp(mapping, i, gfp); + i915_sg_for_each_page(state) { + page = shmem_read_mapping_page_gfp(mapping, state->idx, gfp); if (IS_ERR(page)) { i915_gem_shrink(dev_priv, - page_count, + state->page_count, I915_SHRINK_BOUND | I915_SHRINK_UNBOUND | I915_SHRINK_PURGEABLE); - page = shmem_read_mapping_page_gfp(mapping, i, gfp); + page = shmem_read_mapping_page_gfp(mapping, state->idx, + gfp); } if (IS_ERR(page)) { /* We've tried hard to allocate the memory by reaping * our own buffer, now let the real VM do its job and * go down in flames if truly OOM. */ - page = shmem_read_mapping_page(mapping, i); + page = shmem_read_mapping_page(mapping, state->idx); if (IS_ERR(page)) { ret = PTR_ERR(page); goto err_pages; } } - if (!i || - sg->length >= max_segment || - page_to_pfn(page) != last_pfn + 1) { - if (i) - sg = sg_next(sg); - st->nents++; - sg_set_page(sg, page, PAGE_SIZE, 0); - } else { - sg->length += PAGE_SIZE; - } - last_pfn = page_to_pfn(page); + + i915_sg_add_page(state, page); /* Check that the i965g/gm workaround works. */ - WARN_ON((gfp & __GFP_DMA32) && (last_pfn >= 0x00100000UL)); + WARN_ON((gfp & __GFP_DMA32) && + (state->last_pfn >= 0x00100000UL)); } - if (sg) /* loop terminated early; short sg table */ - sg_mark_end(sg); - obj->pages = st; + + obj->pages = i915_sg_complete(state); ret = i915_gem_gtt_prepare_object(obj); if (ret) @@ -2316,11 +2382,10 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) return 0; err_pages: - sg_mark_end(sg); - for_each_sgt_page(page, sgt_iter, st) + sg_mark_end(state->sg); + for_each_sgt_page(page, sgt_iter, state->st) put_page(page); - sg_free_table(st); - kfree(st); + i915_sg_abort(state); /* shmemfs first checks if there is enough memory to allocate the page * and reports ENOSPC should there be insufficient, along with the usual