From patchwork Fri Sep 13 09:30:52 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: tangchen X-Patchwork-Id: 2882341 Return-Path: X-Original-To: patchwork-linux-acpi@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 D708BBFF05 for ; Fri, 13 Sep 2013 09:29:48 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 1D2E42031A for ; Fri, 13 Sep 2013 09:29:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 461092048E for ; Fri, 13 Sep 2013 09:29:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755174Ab3IMJ3d (ORCPT ); Fri, 13 Sep 2013 05:29:33 -0400 Received: from cn.fujitsu.com ([222.73.24.84]:8115 "EHLO song.cn.fujitsu.com" rhost-flags-OK-FAIL-OK-OK) by vger.kernel.org with ESMTP id S1751901Ab3IMJ2n (ORCPT ); Fri, 13 Sep 2013 05:28:43 -0400 X-IronPort-AV: E=Sophos;i="4.90,897,1371052800"; d="scan'208";a="8515192" Received: from unknown (HELO tang.cn.fujitsu.com) ([10.167.250.3]) by song.cn.fujitsu.com with ESMTP; 13 Sep 2013 17:25:28 +0800 Received: from fnstmail02.fnst.cn.fujitsu.com (tang.cn.fujitsu.com [127.0.0.1]) by tang.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id r8D9SVTG017828; Fri, 13 Sep 2013 17:28:31 +0800 Received: from G08FNSTD090432.fnst.cn.fujitsu.com ([10.167.226.99]) by fnstmail02.fnst.cn.fujitsu.com (Lotus Domino Release 8.5.3) with ESMTP id 2013091317260794-1489958 ; Fri, 13 Sep 2013 17:26:07 +0800 From: Tang Chen To: rjw@sisk.pl, lenb@kernel.org, tglx@linutronix.de, mingo@elte.hu, hpa@zytor.com, akpm@linux-foundation.org, tj@kernel.org, toshi.kani@hp.com, zhangyanfei@cn.fujitsu.com, liwanp@linux.vnet.ibm.com, trenn@suse.de, yinghai@kernel.org, jiang.liu@huawei.com, wency@cn.fujitsu.com, laijs@cn.fujitsu.com, isimatu.yasuaki@jp.fujitsu.com, izumi.taku@jp.fujitsu.com, mgorman@suse.de, minchan@kernel.org, mina86@mina86.com, gong.chen@linux.intel.com, vasilis.liaskovitis@profitbricks.com, lwoodman@redhat.com, riel@redhat.com, jweiner@redhat.com, prarit@redhat.com Cc: x86@kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-acpi@vger.kernel.org Subject: [PATCH v3 2/5] memblock: Improve memblock to support allocation from lower address. Date: Fri, 13 Sep 2013 17:30:52 +0800 Message-Id: <1379064655-20874-3-git-send-email-tangchen@cn.fujitsu.com> X-Mailer: git-send-email 1.7.11.7 In-Reply-To: <1379064655-20874-1-git-send-email-tangchen@cn.fujitsu.com> References: <1379064655-20874-1-git-send-email-tangchen@cn.fujitsu.com> X-MIMETrack: Itemize by SMTP Server on mailserver/fnst(Release 8.5.3|September 15, 2011) at 2013/09/13 17:26:07, Serialize by Router on mailserver/fnst(Release 8.5.3|September 15, 2011) at 2013/09/13 17:26:15, Serialize complete at 2013/09/13 17:26:15 Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Spam-Status: No, score=-7.8 required=5.0 tests=BAYES_00,KHOP_BIG_TO_CC, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch modifies the memblock_find_in_range_node() to support two different allocation directions. After this patch, memblock will check memblock.current_direction, and decide in which direction to allocate memory. Now it supports two allocation directions: bottom up and top down. When direction is top down, it acts as before. When direction is bottom up, the start address should be greater than the end of the kernel image. Otherwise, it will be trimmed to kernel image end address. Signed-off-by: Tang Chen Reviewed-by: Zhang Yanfei --- mm/memblock.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 95 insertions(+), 12 deletions(-) diff --git a/mm/memblock.c b/mm/memblock.c index f24ca2e..87a7f04 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -20,6 +20,8 @@ #include #include +#include + static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock; static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock; @@ -84,8 +86,81 @@ static long __init_memblock memblock_overlaps_region(struct memblock_type *type, } /** + * __memblock_find_range - find free area utility + * @start: start of candidate range, can be %MEMBLOCK_ALLOC_ACCESSIBLE + * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE} + * @size: size of free area to find + * @align: alignment of free area to find + * @nid: nid of the free area to find, %MAX_NUMNODES for any node + * + * Utility called from memblock_find_in_range_node(), find free area from + * lower address to higher address. + * + * RETURNS: + * Found address on success, %0 on failure. + */ +static phys_addr_t __init_memblock +__memblock_find_range(phys_addr_t start, phys_addr_t end, + phys_addr_t size, phys_addr_t align, int nid) +{ + phys_addr_t this_start, this_end, cand; + u64 i; + + for_each_free_mem_range(i, nid, &this_start, &this_end, NULL) { + this_start = clamp(this_start, start, end); + this_end = clamp(this_end, start, end); + + cand = round_up(this_start, align); + if (cand < this_end && this_end - cand >= size) + return cand; + } + + return 0; +} + +/** + * __memblock_find_range_rev - find free area utility, in reverse order + * @start: start of candidate range, can be %MEMBLOCK_ALLOC_ACCESSIBLE + * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE} + * @size: size of free area to find + * @align: alignment of free area to find + * @nid: nid of the free area to find, %MAX_NUMNODES for any node + * + * Utility called from memblock_find_in_range_node(), find free area from + * higher address to lower address. + * + * RETURNS: + * Found address on success, %0 on failure. + */ +static phys_addr_t __init_memblock +__memblock_find_range_rev(phys_addr_t start, phys_addr_t end, + phys_addr_t size, phys_addr_t align, int nid) +{ + phys_addr_t this_start, this_end, cand; + u64 i; + + for_each_free_mem_range_reverse(i, nid, &this_start, &this_end, NULL) { + this_start = clamp(this_start, start, end); + this_end = clamp(this_end, start, end); + + /* + * Just in case that (this_end - size) underflows and cause + * (cand >= this_start) to be true incorrectly. + */ + if (this_end < size) + break; + + cand = round_down(this_end - size, align); + if (cand >= this_start) + return cand; + } + + return 0; +} + +/** * memblock_find_in_range_node - find free area in given range and node - * @start: start of candidate range + * @start: start of candidate range, can be %MEMBLOCK_ALLOC_ACCESSIBLE * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE} * @size: size of free area to find * @align: alignment of free area to find @@ -93,6 +168,11 @@ static long __init_memblock memblock_overlaps_region(struct memblock_type *type, * * Find @size free area aligned to @align in the specified range and node. * + * When allocation direction is from low to high, the @start should be greater + * than the end of the kernel image. Otherwise, it will be trimmed. And also, + * if allocation from low to high failed, will try to allocate memory from high + * to low again. + * * RETURNS: * Found address on success, %0 on failure. */ @@ -100,8 +180,7 @@ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align, int nid) { - phys_addr_t this_start, this_end, cand; - u64 i; + phys_addr_t ret; /* pump up @end */ if (end == MEMBLOCK_ALLOC_ACCESSIBLE) @@ -111,18 +190,22 @@ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t start, start = max_t(phys_addr_t, start, PAGE_SIZE); end = max(start, end); - for_each_free_mem_range_reverse(i, nid, &this_start, &this_end, NULL) { - this_start = clamp(this_start, start, end); - this_end = clamp(this_end, start, end); + if (memblock_direction_bottom_up()) { + /* + * MEMBLOCK_ALLOC_ACCESSIBLE is 0, which is less than the end + * of kernel image. So callers specify MEMBLOCK_ALLOC_ACCESSIBLE + * as @start is OK. + */ + start = max(start, __pa_symbol(_end)); /* End of kernel image. */ - if (this_end < size) - continue; + ret = __memblock_find_range(start, end, size, align, nid); + if (ret) + return ret; - cand = round_down(this_end - size, align); - if (cand >= this_start) - return cand; + pr_warn("memblock: Failed to allocate memory in bottom up direction. Now try top down direction.\n"); } - return 0; + + return __memblock_find_range_rev(start, end, size, align, nid); } /**