From patchwork Thu Feb 14 12:45:27 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 14797 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 390B123F72 for ; Thu, 14 Feb 2013 12:46:02 +0000 (UTC) Received: from mail-vc0-f171.google.com (mail-vc0-f171.google.com [209.85.220.171]) by fiordland.canonical.com (Postfix) with ESMTP id B3C2BA1840D for ; Thu, 14 Feb 2013 12:46:01 +0000 (UTC) Received: by mail-vc0-f171.google.com with SMTP id p1so1470529vcq.30 for ; Thu, 14 Feb 2013 04:46:01 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:x-forwarded-to:x-forwarded-for:delivered-to:x-received :received-spf:x-auditid:from:to:date:message-id:x-mailer:in-reply-to :references:x-brightmail-tracker:cc:subject:x-beenthere :x-mailman-version:precedence:list-id:list-unsubscribe:list-archive :list-post:list-help:list-subscribe:mime-version:content-type :content-transfer-encoding:sender:errors-to:x-gm-message-state; bh=Q2GCerBVliTRLQ5DYyo1GQSgRs2KC8wccRlsi4TnVu8=; b=Qf0LGX/lVkBq+ZvwrS35NVxQzOBk8fSC0adnDg57lUUDeSUebJND3jgYRKy1GcxsFh Cxu5BabPQUvpiZ7tHFuRgbVvwxQ45S+GFS+6xpP2EYKEbw8j52xS+sJcnbTGic8BFA2w Xe8JbAx1fO2LnjOyvAe0okM9KOzMFnrBahxeK+DuVOYODpCEJVeU6a1H1Iwkjn6vf1TF z6b1sxEq3YZafTebm4F2WZPBcWqpObSQGXNjf2BJLT1B3prgkqwb1OeZMY+HPoB18d6r GvzfNXpbalbbV9b3yuLbL3VlXgvcqNTbdsMLwsCabPRzPu98Np2cBkPe8PBVwOEOCVJK Lfjg== X-Received: by 10.220.220.134 with SMTP id hy6mr647639vcb.2.1360845961110; Thu, 14 Feb 2013 04:46:01 -0800 (PST) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.221.4.5 with SMTP id oa5csp258288vcb; Thu, 14 Feb 2013 04:46:00 -0800 (PST) X-Received: by 10.14.207.200 with SMTP id n48mr17248308eeo.4.1360845957982; Thu, 14 Feb 2013 04:45:57 -0800 (PST) Received: from mombin.canonical.com (mombin.canonical.com. [91.189.95.16]) by mx.google.com with ESMTP id f9si10351253eep.189.2013.02.14.04.45.57; Thu, 14 Feb 2013 04:45:57 -0800 (PST) Received-SPF: neutral (google.com: 91.189.95.16 is neither permitted nor denied by best guess record for domain of linaro-mm-sig-bounces@lists.linaro.org) client-ip=91.189.95.16; Authentication-Results: mx.google.com; spf=neutral (google.com: 91.189.95.16 is neither permitted nor denied by best guess record for domain of linaro-mm-sig-bounces@lists.linaro.org) smtp.mail=linaro-mm-sig-bounces@lists.linaro.org Received: from localhost ([127.0.0.1] helo=mombin.canonical.com) by mombin.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1U5yCI-0004hn-Jp; Thu, 14 Feb 2013 12:45:54 +0000 Received: from mailout4.samsung.com ([203.254.224.34]) by mombin.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1U5yCG-0004ha-GG for linaro-mm-sig@lists.linaro.org; Thu, 14 Feb 2013 12:45:53 +0000 Received: from epcpsbgm1.samsung.com (epcpsbgm1 [203.254.230.26]) by mailout4.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MI7004BGNGBTA60@mailout4.samsung.com> for linaro-mm-sig@lists.linaro.org; Thu, 14 Feb 2013 21:45:52 +0900 (KST) X-AuditID: cbfee61a-b7f7d6d000000f4e-e5-511cdc7ffbeb Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 34.4E.03918.F7CDC115; Thu, 14 Feb 2013 21:45:52 +0900 (KST) Received: from localhost.localdomain ([106.116.147.30]) by mmp2.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MI7002HQNG3EJ20@mmp2.samsung.com> for linaro-mm-sig@lists.linaro.org; Thu, 14 Feb 2013 21:45:51 +0900 (KST) From: Marek Szyprowski To: linux-arm-kernel@lists.infradead.org, linaro-mm-sig@lists.linaro.org, devicetree-discuss@lists.ozlabs.org Date: Thu, 14 Feb 2013 13:45:27 +0100 Message-id: <1360845928-8107-2-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1360845928-8107-1-git-send-email-m.szyprowski@samsung.com> References: <1360845928-8107-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrEJMWRmVeSWpSXmKPExsVy+t9jQd2GOzKBBuf/Mll8ufKQyYHR4/a/ x8wBjFFcNimpOZllqUX6dglcGQe+PGAvuJxU8bdpCksD46WALkZODgkBE4n5E++xQthiEhfu rWfrYuTiEBKYzigx8exKZghnFZNE85l5zCBVbAKGEl1vu4CqODhEBPIlVs/iBalhFvjEKLF+ xip2kBphgViJte/esYHYLAKqEr++HmMEsXkF3CVOzb7KDNIrIaAgMWeSDUiYU8BDYmXTWRYQ Wwio5OaEDcwTGHkXMDKsYhRNLUguKE5KzzXUK07MLS7NS9dLzs/dxAj2+TOpHYwrGywOMQpw MCrx8Cr+kg4UYk0sK67MPcQowcGsJML7MlAmUIg3JbGyKrUoP76oNCe1+BCjNAeLkjgv46kn AUIC6YklqdmpqQWpRTBZJg5OqQZG16lVM5tF/V7NtP7sbPvFdbX/95e3TDf9cjkVN9P5rCC7 18fszQ+vrPjPvTd3/Q91lqk/im/uLJCdwMxw+OFS681vziSL3zuQ0OgX2b/cqvzhlzPXNOvW l2vNWtXy5fPkyglHWK8LdPkGhChtPr3r/uzJfaoit5bUvLzev7M2wdgkMZjjZeWxeUosxRmJ hlrMRcWJAC7nFgr1AQAA Cc: Arnd Bergmann , Tomasz Figa , Michal Nazarewicz , Grant Likely , Kyungmin Park Subject: [Linaro-mm-sig] [PATCH 1/2] drivers: dma-contiguous: clean source code and prepare for device tree X-BeenThere: linaro-mm-sig@lists.linaro.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: "Unified memory management interest group." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linaro-mm-sig-bounces@lists.linaro.org Errors-To: linaro-mm-sig-bounces@lists.linaro.org X-Gm-Message-State: ALoCoQnaP3Ym96ojLmW85YuZAL6WPQ9ojZFJdI0vJuAQE7qG1PQiKM+km+V/ZUQXr7lDTugR8FAa This patch cleans the initialization of dma contiguous framework. The all-in-one dma_declare_contiguous() function is now separated into dma_contiguous_reserve_area() which only steals the the memory from memblock allocator and dma_contiguous_add_device() function, which assigns given device to the specified reserved memory area. This improves the flexibility in defining contiguous memory areas and assigning device to them, because now it is possible to assign more than one device to the given contiguous memory area. This split in initialization is also required for upcoming device tree support. Signed-off-by: Marek Szyprowski Acked-by: Kyungmin Park --- drivers/base/dma-contiguous.c | 210 +++++++++++++++++++++------------- include/asm-generic/dma-contiguous.h | 4 +- include/linux/dma-contiguous.h | 32 +++++- 3 files changed, 161 insertions(+), 85 deletions(-) diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 0ca5442..085389c 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -39,7 +39,33 @@ struct cma { unsigned long *bitmap; }; -struct cma *dma_contiguous_default_area; +static DEFINE_MUTEX(cma_mutex); + +struct cma *dma_contiguous_def_area; +phys_addr_t dma_contiguous_def_base; + +static struct cma_area { + phys_addr_t base; + unsigned long size; + struct cma *cma; +} cma_areas[MAX_CMA_AREAS] __initdata; +static unsigned cma_area_count __initdata; + + +static struct cma_map { + phys_addr_t base; + struct device *dev; +} cma_maps[MAX_CMA_AREAS] __initdata; +static unsigned cma_map_count __initdata; + +static struct cma *cma_get_area(phys_addr_t base) +{ + int i; + for (i = 0; i < cma_area_count; i++) + if (cma_areas[i].base == base) + return cma_areas[i].cma; + return NULL; +} #ifdef CONFIG_CMA_SIZE_MBYTES #define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES @@ -95,45 +121,6 @@ static inline __maybe_unused phys_addr_t cma_early_percent_memory(void) #endif -/** - * dma_contiguous_reserve() - reserve area for contiguous memory handling - * @limit: End address of the reserved memory (optional, 0 for any). - * - * This function reserves memory from early allocator. It should be - * called by arch specific code once the early allocator (memblock or bootmem) - * has been activated and all other subsystems have already allocated/reserved - * memory. - */ -void __init dma_contiguous_reserve(phys_addr_t limit) -{ - phys_addr_t selected_size = 0; - - pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit); - - if (size_cmdline != -1) { - selected_size = size_cmdline; - } else { -#ifdef CONFIG_CMA_SIZE_SEL_MBYTES - selected_size = size_bytes; -#elif defined(CONFIG_CMA_SIZE_SEL_PERCENTAGE) - selected_size = cma_early_percent_memory(); -#elif defined(CONFIG_CMA_SIZE_SEL_MIN) - selected_size = min(size_bytes, cma_early_percent_memory()); -#elif defined(CONFIG_CMA_SIZE_SEL_MAX) - selected_size = max(size_bytes, cma_early_percent_memory()); -#endif - } - - if (selected_size) { - pr_debug("%s: reserving %ld MiB for global area\n", __func__, - (unsigned long)selected_size / SZ_1M); - - dma_declare_contiguous(NULL, selected_size, 0, limit); - } -}; - -static DEFINE_MUTEX(cma_mutex); - static __init int cma_activate_area(unsigned long base_pfn, unsigned long count) { unsigned long pfn = base_pfn; @@ -190,55 +177,73 @@ no_mem: return ERR_PTR(ret); } -static struct cma_reserved { - phys_addr_t start; - unsigned long size; - struct device *dev; -} cma_reserved[MAX_CMA_AREAS] __initdata; -static unsigned cma_reserved_count __initdata; - -static int __init cma_init_reserved_areas(void) +/** + * dma_contiguous_reserve() - reserve area for contiguous memory handling + * @limit: End address of the reserved memory (optional, 0 for any). + * + * This function reserves memory from early allocator. It should be + * called by arch specific code once the early allocator (memblock or bootmem) + * has been activated and all other subsystems have already allocated/reserved + * memory. It reserves contiguous areas for global, device independent + * allocations and (optionally) all areas defined in device tree structures. + */ +void __init dma_contiguous_reserve(phys_addr_t limit) { - struct cma_reserved *r = cma_reserved; - unsigned i = cma_reserved_count; + phys_addr_t sel_size = 0; - pr_debug("%s()\n", __func__); + pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit); - for (; i; --i, ++r) { - struct cma *cma; - cma = cma_create_area(PFN_DOWN(r->start), - r->size >> PAGE_SHIFT); - if (!IS_ERR(cma)) - dev_set_cma_area(r->dev, cma); + if (size_cmdline != -1) { + sel_size = size_cmdline; + } else { +#ifdef CONFIG_CMA_SIZE_SEL_MBYTES + sel_size = size_bytes; +#elif defined(CONFIG_CMA_SIZE_SEL_PERCENTAGE) + sel_size = cma_early_percent_memory(); +#elif defined(CONFIG_CMA_SIZE_SEL_MIN) + sel_size = min(size_bytes, cma_early_percent_memory()); +#elif defined(CONFIG_CMA_SIZE_SEL_MAX) + sel_size = max(size_bytes, cma_early_percent_memory()); +#endif } - return 0; -} -core_initcall(cma_init_reserved_areas); + + if (sel_size) { + phys_addr_t base = 0; + pr_debug("%s: reserving %ld MiB for global area\n", __func__, + (unsigned long)sel_size / SZ_1M); + + if (dma_contiguous_reserve_area(sel_size, &base, limit) == 0) + dma_contiguous_def_base = base; + } +}; /** - * dma_declare_contiguous() - reserve area for contiguous memory handling - * for particular device - * @dev: Pointer to device structure. - * @size: Size of the reserved memory. - * @base: Start address of the reserved memory (optional, 0 for any). + * dma_contiguous_reserve_area() - reserve custom contiguous area + * @size: Size of the reserved area (in bytes), + * @base: Pointer to the base address of the reserved area, also used to return + * base address of the actually reserved area, optional, use pointer to + * 0 for any * @limit: End address of the reserved memory (optional, 0 for any). * - * This function reserves memory for specified device. It should be - * called by board specific code when early allocator (memblock or bootmem) - * is still activate. + * This function reserves memory from early allocator. It should be + * called by arch specific code once the early allocator (memblock or bootmem) + * has been activated and all other subsystems have already allocated/reserved + * memory. This function allows to create custom reserved areas for specific + * devices. */ -int __init dma_declare_contiguous(struct device *dev, phys_addr_t size, - phys_addr_t base, phys_addr_t limit) +int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base, + phys_addr_t limit) { - struct cma_reserved *r = &cma_reserved[cma_reserved_count]; + phys_addr_t base = *res_base; phys_addr_t alignment; + int ret = 0; pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__, (unsigned long)size, (unsigned long)base, (unsigned long)limit); /* Sanity checks */ - if (cma_reserved_count == ARRAY_SIZE(cma_reserved)) { + if (cma_area_count == ARRAY_SIZE(cma_areas)) { pr_err("Not enough slots for CMA reserved regions!\n"); return -ENOSPC; } @@ -256,7 +261,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size, if (base) { if (memblock_is_region_reserved(base, size) || memblock_reserve(base, size) < 0) { - base = -EBUSY; + ret = -EBUSY; goto err; } } else { @@ -266,7 +271,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size, */ phys_addr_t addr = __memblock_alloc_base(size, alignment, limit); if (!addr) { - base = -ENOMEM; + ret = -ENOMEM; goto err; } else { base = addr; @@ -277,10 +282,11 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size, * Each reserved area must be initialised later, when more kernel * subsystems (like slab allocator) are available. */ - r->start = base; - r->size = size; - r->dev = dev; - cma_reserved_count++; + cma_areas[cma_area_count].base = base; + cma_areas[cma_area_count].size = size; + cma_area_count++; + *res_base = base; + pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M, (unsigned long)base); @@ -289,9 +295,55 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size, return 0; err: pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M); - return base; + return ret; +} + +/** + * dma_contiguous_add_device() - add device to custom contiguous reserved area + * @dev: Pointer to device structure. + * @base: Pointer to the base address of the reserved area returned by + * dma_contiguous_reserve_area() function, also used to return + * + * This function assigns the given device to the contiguous memory area + * reserved earlier by dma_contiguous_reserve_area() function. + */ +int __init dma_contiguous_add_device(struct device *dev, phys_addr_t base) +{ + if (cma_map_count == ARRAY_SIZE(cma_maps)) { + pr_err("Not enough slots for CMA reserved regions!\n"); + return -ENOSPC; + } + cma_maps[cma_map_count].dev = dev; + cma_maps[cma_map_count].base = base; + cma_map_count++; + return 0; } +static int __init cma_init_reserved_areas(void) +{ + struct cma *cma; + int i; + + for (i = 0; i < cma_area_count; i++) { + phys_addr_t base = PFN_DOWN(cma_areas[i].base); + unsigned int count = cma_areas[i].size >> PAGE_SHIFT; + + cma = cma_create_area(base, count); + if (!IS_ERR(cma)) + cma_areas[i].cma = cma; + } + + dma_contiguous_def_area = cma_get_area(dma_contiguous_def_base); + + for (i = 0; i < cma_map_count; i++) { + cma = cma_get_area(cma_maps[i].base); + dev_set_cma_area(cma_maps[i].dev, cma); + } + + return 0; +} +core_initcall(cma_init_reserved_areas); + /** * dma_alloc_from_contiguous() - allocate pages from contiguous area * @dev: Pointer to device for which the allocation is performed. diff --git a/include/asm-generic/dma-contiguous.h b/include/asm-generic/dma-contiguous.h index 294b1e7..9071ef1 100644 --- a/include/asm-generic/dma-contiguous.h +++ b/include/asm-generic/dma-contiguous.h @@ -11,15 +11,13 @@ static inline struct cma *dev_get_cma_area(struct device *dev) { if (dev && dev->cma_area) return dev->cma_area; - return dma_contiguous_default_area; + return dma_contiguous_def_area; } static inline void dev_set_cma_area(struct device *dev, struct cma *cma) { if (dev) dev->cma_area = cma; - if (!dev && !dma_contiguous_default_area) - dma_contiguous_default_area = cma; } #endif diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h index 01b5c84..285b593 100644 --- a/include/linux/dma-contiguous.h +++ b/include/linux/dma-contiguous.h @@ -65,11 +65,37 @@ struct device; */ #define MAX_CMA_AREAS (1 + CONFIG_CMA_AREAS) -extern struct cma *dma_contiguous_default_area; +extern struct cma *dma_contiguous_def_area; void dma_contiguous_reserve(phys_addr_t addr_limit); -int dma_declare_contiguous(struct device *dev, phys_addr_t size, - phys_addr_t base, phys_addr_t limit); + +int dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base, + phys_addr_t limit); + +int dma_contiguous_add_device(struct device *dev, phys_addr_t base); + +/** + * dma_declare_contiguous() - reserve area for contiguous memory handling + * for particular device + * @dev: Pointer to device structure. + * @size: Size of the reserved memory. + * @base: Start address of the reserved memory (optional, 0 for any). + * @limit: End address of the reserved memory (optional, 0 for any). + * + * This function reserves memory for specified device. It should be + * called by board specific code when early allocator (memblock or bootmem) + * is still activate. + */ + +static inline int dma_declare_contiguous(struct device *dev, phys_addr_t size, + phys_addr_t base, phys_addr_t limit) +{ + int ret; + ret = dma_contiguous_reserve_area(size, &base, limit); + if (ret == 0) + ret = dma_contiguous_add_device(dev, base); + return ret; +} struct page *dma_alloc_from_contiguous(struct device *dev, int count, unsigned int order);