Message ID | 1341469459-29558-1-git-send-email-Barry.Song@csr.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Thursday 05 July 2012, Barry Song wrote: > From: Barry Song <Baohua.Song@csr.com> > > Any write request to /dev/cma_test will let the module to allocate memory from > CMA, for example: > > 1st time > $ echo 1024 > /dev/cma_test > will require cma_test to request 1MB(1024KB) > 2nd time > $ echo 2048 > /dev/cma_test > will require cma_test to request 2MB(2048KB) > > Any read request to /dev/cma_test will let the module to free the 1st valid > 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 > $ cat /dev/cma_test > will require cma_test to free the 2MB allocated in the second write request I missed the earlier times this was posted and read up on it now. > Signed-off-by: Barry Song <Baohua.Song@csr.com> > Reviewed-by: Michal Nazarewicz <mina86@mina86.com> > Cc: Marek Szyprowski <m.szyprowski@samsung.com> > Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> > --- > resend to Greg KH so that he can decide whether it should be placed at tools > or drivers/misc; > See the discussion thread: > [1] https://lkml.org/lkml/2012/7/3/80 > [2] https://lkml.org/lkml/2012/7/3/224 > [3] https://lkml.org/lkml/2012/7/4/87 I think it should be in mm/cma-test.c, along with kmemleak-test.c. It would be nice if you could add some code that just runs at boot time (or when the module is loaded) and allocates and frees memory using CMA. > +static struct device *cma_dev; Do you actually need this device? It's not connected to hardware so it doesn't actually do DMA and we might as well pass a NULL pointer into dma_alloc_*(). > +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 = misc_register(&cma_test_misc); A better place for this is really debugfs. The driver is not meant as a stable kernel interface that applications can rely on, it's purely a debugging help. Just make this ret = debugfs_create_file("cma-test", 0600, NULL, NULL, &cma_test_fops); Arnd
Hi Arnd, 2012/7/5 Arnd Bergmann <arnd@arndb.de>: > > I think it should be in mm/cma-test.c, along with kmemleak-test.c. It would be nice > if you could add some code that just runs at boot time (or when the module is > loaded) and allocates and frees memory using CMA. > >> +static struct device *cma_dev; > > Do you actually need this device? It's not connected to hardware so > it doesn't actually do DMA and we might as well pass a NULL pointer > into dma_alloc_*(). > >> +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 = misc_register(&cma_test_misc); > > A better place for this is really debugfs. The driver is not meant as a stable > kernel interface that applications can rely on, it's purely a debugging help. > > Just make this > > ret = debugfs_create_file("cma-test", 0600, NULL, NULL, &cma_test_fops); > we did have some discussions about this at: http://www.spinics.net/lists/arm-kernel/msg163548.html i'd say both are acceptable to me. > Arnd > -barry
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..7eb96db --- /dev/null +++ b/tools/cma/cma_test.c @@ -0,0 +1,140 @@ +/* + * kernel module helper for testing CMA + * + * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +struct cma_allocation { + struct list_head list; + size_t size; + dma_addr_t dma; + void *virt; +}; + +static struct device *cma_dev; +static LIST_HEAD(cma_allocations); +static DEFINE_SPINLOCK(cma_lock); + +/* + * any read request will free the 1st allocated 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) +{ + 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) + return -EIDRM; + + dma_free_coherent(cma_dev, alloc->size, alloc->virt, + alloc->dma); + + _dev_info(cma_dev, "free: CM virt: %p dma: %p size:%zuK\n", + alloc->virt, (void *)alloc->dma, alloc->size / SZ_1K); + kfree(alloc); + + return 0; +} + +/* + * any write request will alloc a new coherent memory, eg. + * echo 1024 > /dev/cma_test + * will request 1024KiB by CMA + */ +static ssize_t +cma_test_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + struct cma_allocation *alloc; + unsigned long size; + int ret; + + ret = kstrtoul_from_user(buf, count, 0, &size); + if (ret) + return ret; + + if (!size) + return -EINVAL; + + if (size > ~(size_t)0 / SZ_1K) + return -EOVERFLOW; + + alloc = kmalloc(sizeof *alloc, GFP_KERNEL); + if (!alloc) + return -ENOMEM; + + alloc->size = size * SZ_1K; + alloc->virt = dma_alloc_coherent(cma_dev, alloc->size, + &alloc->dma, GFP_KERNEL); + + if (alloc->virt) { + _dev_info(cma_dev, "alloc: virt: %p dma: %p size: %zuK\n", + alloc->virt, (void *)alloc->dma, alloc->size / SZ_1K); + + 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 = { + .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 = 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 0; +} +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 <Baohua.Song@csr.com>"); +MODULE_DESCRIPTION("kernel module to help the test of CMA"); +MODULE_ALIAS("cma_test");