From patchwork Fri Mar 2 15:26:39 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Nazarewicz X-Patchwork-Id: 144274 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:4978:20e::2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id C647FB6ED0 for ; Sat, 3 Mar 2012 02:29:27 +1100 (EST) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1S3UNd-0004qS-6x; Fri, 02 Mar 2012 15:26:49 +0000 Received: from mail-ey0-f177.google.com ([209.85.215.177]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1S3UNY-0004pQ-G1 for linux-arm-kernel@lists.infradead.org; Fri, 02 Mar 2012 15:26:46 +0000 Received: by eaak13 with SMTP id k13so753843eaa.36 for ; Fri, 02 Mar 2012 07:26:41 -0800 (PST) Received-SPF: pass (google.com: domain of mnazarewicz@gmail.com designates 10.14.99.2 as permitted sender) client-ip=10.14.99.2; Authentication-Results: mr.google.com; spf=pass (google.com: domain of mnazarewicz@gmail.com designates 10.14.99.2 as permitted sender) smtp.mail=mnazarewicz@gmail.com; dkim=pass header.i=mnazarewicz@gmail.com Received: from mr.google.com ([10.14.99.2]) by 10.14.99.2 with SMTP id w2mr6264314eef.69.1330702001707 (num_hops = 1); Fri, 02 Mar 2012 07:26:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:content-type:to:cc:subject:references:date:mime-version :content-transfer-encoding:from:message-id:in-reply-to:user-agent; bh=5O/++xAAdsTg0fRKR+Ibx2o4dWDTzq2OOOX9iM3PY+Y=; b=HJmfwALHVXuVrE1GzqjhgfeIHJJdR7MRNGDyt4y1AiwxwXN8vSykTOs7GPCjofKYgd YhBMw8B+/W/eLRrrEr21LAre1qhHuKpZTAiV8K82BzN6fnhCW9pLbHMpERcB++SOvgfs gvhe8nJS8KIBevCV3ML7ABM84G7r0EI7raA65mWAg+i/iSaXY2psqp69hbfQuEN2G66C 0kalw64mOS1wkDK7DiCaZS1T5yG1Lx9Hwfu8IPNjlSggTjkXSgKv5W4sgi/gMMvez2P8 rhW5b4pjjt92r/IE4v8fYEs/rjHaIuLhfqEiTqKqsItm7u2j0r01E5d8AvHbzbQn3Gk5 KVVQ== Received: by 10.14.99.2 with SMTP id w2mr4830575eef.69.1330702001562; Fri, 02 Mar 2012 07:26:41 -0800 (PST) Received: from mpn-glaptop ([2620:0:105f:5:f2de:f1ff:fe35:1a72]) by mx.google.com with ESMTPS id v51sm21475074eef.2.2012.03.02.07.26.40 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 02 Mar 2012 07:26:41 -0800 (PST) To: m.szyprowski@samsung.com, "Barry Song" Subject: Re: [PATCH] MM: CMA: add a simple kernel module as the helper to test CMA References: <1330656742-5233-1-git-send-email-Barry.Song@csr.com> Date: Fri, 02 Mar 2012 16:26:39 +0100 MIME-Version: 1.0 From: "Michal Nazarewicz" Message-ID: In-Reply-To: <1330656742-5233-1-git-send-email-Barry.Song@csr.com> User-Agent: Opera Mail/11.61 (Linux) X-Spam-Note: CRM114 invocation failed X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (mnazarewicz[at]gmail.com) -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.215.177 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: workgroup.linux@csr.com, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Barry Song X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org On Fri, 02 Mar 2012 03:52:22 +0100, Barry Song wrote: > From: Barry Song > > Any write request to /dev/cma_test will let the module to allocate memory from > CMA, for example: > > 1st time > $ echo 0 > /dev/cma_test > will require cma_test to request 1MB > 2nd time > $ echo 0 > /dev/cma_test > will require cma_test to request 2MB > > Any read request to /dev/cma_test will let the module to free memory from CMA, > for example: > > 1st time > $ cat /dev/cma_test > will require cma_test to free the 1MB allocated in the first write request > 2nd time > $ echo 0 > /dev/cma_test > will require cma_test to free the 2MB allocated in the second write request Looks quite all right. It has a race condition but I guess for a test device it's not that big of a deal (I think the race cannot cause panic). Either way, would be nice if one could specify how much memory device should allocate. How about those changes: > Signed-off-by: Barry Song > --- > tools/cma/Makefile | 13 ++++++ > tools/cma/cma_test.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 121 insertions(+), 0 deletions(-) > create mode 100644 tools/cma/Makefile > create mode 100644 tools/cma/cma_test.c > > diff --git a/tools/cma/Makefile b/tools/cma/Makefile > new file mode 100644 > index 0000000..d15c2c0 > --- /dev/null > +++ b/tools/cma/Makefile > @@ -0,0 +1,13 @@ > +# Kernel modules > +# > +# To compile for ARM: > +# make ARCH=arm CC=arm-none-linux-gnueabi-gcc > +# > +obj-m += cma_test.o > + > +build: kernel_modules > + > +kernel_modules: > + ${MAKE} -C $(CURDIR)/../.. M=$(CURDIR) > +clean: > + ${MAKE} -C $(CURDIR)/../.. M=$(CURDIR) clean > diff --git a/tools/cma/cma_test.c b/tools/cma/cma_test.c > new file mode 100644 > index 0000000..3ee89f3 > --- /dev/null > +++ b/tools/cma/cma_test.c > @@ -0,0 +1,108 @@ > +/* > + * kernel module helper for testing CMA > + * > + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. > + * > + * Licensed under GPLv2 or later. > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#define CMA_NUM 10 > +static struct device *cma_dev; > +static dma_addr_t dma_phys[CMA_NUM]; > +static void *dma_virt[CMA_NUM]; > + > +/* any read request will free coherent memory, eg. > + * cat /dev/cma_test > + */ > +static ssize_t > +cma_test_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) > +{ > + int i; > + > + for (i = 0; i < CMA_NUM; i++) { > + if (dma_virt[i]) { > + dma_free_coherent(cma_dev, (i + 1) * SZ_1M, dma_virt[i], dma_phys[i]); > + _dev_info(cma_dev, "free virt: %p phys: %p\n", dma_virt[i], (void *)dma_phys[i]); > + dma_virt[i] = NULL; > + break; > + } > + } > + return 0; > +} > + > +/* > + * any write request will alloc coherent memory, eg. > + * echo 0 > /dev/cma_test > + */ > +static ssize_t > +cma_test_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) > +{ > + int i; > + int ret; > + > + for (i = 0; i < CMA_NUM; i++) { > + if (!dma_virt[i]) { > + dma_virt[i] = dma_alloc_coherent(cma_dev, (i + 1) * SZ_1M, &dma_phys[i], GFP_KERNEL); > + > + if (dma_virt[i]) { > + void *p; > + /* touch every page in the allocated memory */ > + for (p = dma_virt[i]; p < dma_virt[i] + (i + 1) * SZ_1M; p += PAGE_SIZE) > + *(u32 *)p = 0; > + > + _dev_info(cma_dev, "alloc virt: %p phys: %p\n", dma_virt[i], (void *)dma_phys[i]); > + } else { > + dev_err(cma_dev, "no mem in CMA area\n"); > + ret = -ENOMEM; > + } > + break; > + } > + } > + > + return count; > +} > + > +static const struct file_operations cma_test_fops = { > + .owner = THIS_MODULE, > + .read = cma_test_read, > + .write = cma_test_write, > +}; > + > +static struct miscdevice cma_test_misc = { > + .name = "cma_test", > + .fops = &cma_test_fops, > +}; > + > +static int __init cma_test_init(void) > +{ > + int ret = 0; > + > + ret = misc_register(&cma_test_misc); > + if (unlikely(ret)) { > + pr_err("failed to register cma test misc device!\n"); > + return ret; > + } > + cma_dev = cma_test_misc.this_device; > + cma_dev->coherent_dma_mask = ~0; > + _dev_info(cma_dev, "registered.\n"); > + > + return ret; > +} > +module_init(cma_test_init); > + > +static void __exit cma_test_exit(void) > +{ > + misc_deregister(&cma_test_misc); > +} > +module_exit(cma_test_exit); > + > +MODULE_LICENSE("GPL"); > +MODULE_AUTHOR("Barry Song "); > +MODULE_DESCRIPTION("kernel module to help the test of CMA"); > +MODULE_ALIAS("CMA test"); diff --git a/tools/cma/cma_test.c b/tools/cma/cma_test.c index 3ee89f3..3d3b074 100644 --- a/tools/cma/cma_test.c +++ b/tools/cma/cma_test.c @@ -6,66 +6,96 @@ * Licensed under GPLv2 or later. */ -#include #include +#include #include +#include #include -#include +#include +#include + +struct cma_allocation { + struct list_head list; + unsigned long size; + dma_addr_t dma; + void *virt; +}; -#define CMA_NUM 10 static struct device *cma_dev; -static dma_addr_t dma_phys[CMA_NUM]; -static void *dma_virt[CMA_NUM]; +static LIST_HEAD(cma_allocations); +static DEFINE_SPINLOCK(cma_lock); -/* any read request will free coherent memory, eg. +/* + * Any read request will free a single coherent memory, eg. * cat /dev/cma_test */ static ssize_t cma_test_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - int i; - - for (i = 0; i < CMA_NUM; i++) { - if (dma_virt[i]) { - dma_free_coherent(cma_dev, (i + 1) * SZ_1M, dma_virt[i], dma_phys[i]); - _dev_info(cma_dev, "free virt: %p phys: %p\n", dma_virt[i], (void *)dma_phys[i]); - dma_virt[i] = NULL; - break; - } + struct cma_allocation *alloc = NULL; + + spin_lock(&cma_lock); + if (!list_empty(&cma_allocations)) { + alloc = list_first_entry(&cma_allocations, + struct cma_allocation, list); + list_del(&alloc->list); } + spin_unlock(&cma_lock); + + if (alloc) { + dma_free_coherent(cma_dev, alloc->size, alloc->virt, + alloc->dma); + _dev_info(cma_dev, "free virt: %p phys: %p\n", + alloc->phys, (void *)alloc->dma); + kfree(alloc); + } + return 0; } /* - * any write request will alloc coherent memory, eg. - * echo 0 > /dev/cma_test + * Writes request specified number of pages, eg. + * echo 1024 > /dev/cma_test */ static ssize_t -cma_test_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +cma_test_write(struct file *file, const char __user *buf, size_t count, + loff_t *ppos) { - int i; + struct cma_allocation *alloc; int ret; - for (i = 0; i < CMA_NUM; i++) { - if (!dma_virt[i]) { - dma_virt[i] = dma_alloc_coherent(cma_dev, (i + 1) * SZ_1M, &dma_phys[i], GFP_KERNEL); - - if (dma_virt[i]) { - void *p; - /* touch every page in the allocated memory */ - for (p = dma_virt[i]; p < dma_virt[i] + (i + 1) * SZ_1M; p += PAGE_SIZE) - *(u32 *)p = 0; - - _dev_info(cma_dev, "alloc virt: %p phys: %p\n", dma_virt[i], (void *)dma_phys[i]); - } else { - dev_err(cma_dev, "no mem in CMA area\n"); - ret = -ENOMEM; - } - break; - } - } + alloc = kmalloc(sizeof *alloc, GFP_KERNEL); + if (!alloc) + return -ENOMEM; + + ret = kstrtouint_from_user(buf, count, 0, &alloc->size); + if (ret) + return ret; + + if (!alloc->size) + return -EINVAL; + + if (alloc->size > (ULONG_MAX << PAGE_SHIFT)) + return -EOVERFLOW; - return count; + alloc->size >>= PAGE_SHIFT; + alloc->virt = dma_alloc_coherent(cma_dev, alloc->size, + &alloc->dma, GFP_KERNEL); + + if (alloc->virt) { + _dev_info(cma_dev, "alloc virt: %p phys: %p\n", alloc->virt, + (void *)alloc->dma); + + spin_lock(&cma_lock); + list_add_tail(&alloc->list, &cma_allocations); + spin_unlock(&cma_lock); + + return count; + } else { + dev_err(cma_dev, "no mem in CMA area\n"); + kfree(alloc); + return -ENOSPC; + } } static const struct file_operations cma_test_fops = {