--- drivers/dma/Kconfig | 5 + drivers/dma/Makefile | 1 + drivers/dma/dma_sram_rx_benchmark.c | 231 ++++++++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 drivers/dma/dma_sram_rx_benchmark.c
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 4f6956ebd4dc..807d5eb7088a 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -585,6 +585,11 @@ config DMA_COHERENT_RX_BENCHMARK help Simple benchmark for RX performance using coherent memory. +config DMA_SRAM_RX_BENCHMARK + tristate "DMA SRAM RX Benchmark" + help + Simple benchmark for RX performance using SRAM memory. + config DMA_ENGINE_RAID bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index d435b92a1a43..f9cb715cfc67 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_DMATEST) += dmatest.o # simple RX Benchmark obj-$(CONFIG_DMA_RX_BENCHMARK) += dma_rx_benchmark.o obj-$(CONFIG_DMA_COHERENT_RX_BENCHMARK) += dma_coherent_rx_benchmark.o +obj-$(CONFIG_DMA_SRAM_RX_BENCHMARK) += dma_sram_rx_benchmark.o #devices obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o diff --git a/drivers/dma/dma_sram_rx_benchmark.c b/drivers/dma/dma_sram_rx_benchmark.c new file mode 100644 index 000000000000..23a6e675fddf --- /dev/null +++ b/drivers/dma/dma_sram_rx_benchmark.c @@ -0,0 +1,231 @@ +/* DMA API benchmark + * Copyright(c) 2016 Andrew Lunn <and...@lunn.ch> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see <http://www.gnu.org/licenses/>. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/types.h> +#include <linux/dma-mapping.h> +#include <linux/genalloc.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <asm/page.h> + +#define MAX_BUFS 1024 + +struct device dev; +static void *bufs[MAX_BUFS]; +dma_addr_t dma_handles[MAX_BUFS]; + +static struct gen_pool *pool; + +static char discard[1500]; + +static int alloc_ring(struct device *dev, int num_bufs) +{ + struct platform_device *pdev; + struct device_node *node; + int ret; + int i; + + if (num_bufs > MAX_BUFS) + return -EINVAL; + + node = of_find_compatible_node(NULL, NULL, "mmio-sram"); + if (!node) { + dev_warn(dev, "failed to find sram node\n"); + return -ENODEV; + } + + pdev = of_find_device_by_node(node); + if (!pdev) { + dev_warn(dev, "failed to find sram device\n"); + ret = -ENODEV; + goto put_node; + } + + pool = gen_pool_get(&pdev->dev, NULL); + if (!pool) { + dev_warn(dev, "ocram pool unavailable\n"); + ret = -ENODEV; + goto put_node; + } + + for (i = 0; i < num_bufs; i++) { + bufs[i] = gen_pool_dma_alloc(pool, 2048, &dma_handles[i]); + dev_info(dev, "%p %x\n", bufs[i], dma_handles[i]); + if (!bufs[i]) { + dev_warn(dev, "Out of pool memory\n"); + ret = -ENOMEM; + goto put_node; + } + } + return 0; + +put_node: + of_node_put(node); + + return ret; +} + +static void free_ring(struct device *dev, int num_bufs) +{ + int i; + + for (i = 0; i < num_bufs; i++) + gen_pool_free(pool, (unsigned long)bufs[i], 2048); +} + +/* Give all but the first buffer to the device */ +static void prime_ring_sync(struct device *dev, int num_bufs) +{ + int i; + + for (i = 1; i < num_bufs - 1; i++) + dma_sync_single_range_for_device(dev, dma_handles[i], 0, + 2048, DMA_FROM_DEVICE); +} + +static void give_to_device(struct device *dev, int num_buf) +{ + dma_sync_single_range_for_device(dev, dma_handles[num_buf], + 0, 2048, DMA_FROM_DEVICE); +} + +static void take_from_device(struct device *dev, int num_buf) +{ + + dma_sync_single_range_for_cpu(dev, dma_handles[num_buf], + 0, 2048, DMA_FROM_DEVICE); + + memcpy(discard, (void *)bufs[num_buf], 1500); +} + + +static void run_ring_once(struct device *dev, int num_bufs) +{ + int i; + + for (i = 0; i < num_bufs - 1; i++) + memcpy(discard, bufs[i], 2048); +} + +static void run_ring(struct device *dev, int num_bufs) +{ + unsigned long elapsed; + unsigned long start; + unsigned long now; + int count = 0; + + start = jiffies; + + do { + run_ring_once(dev, num_bufs); + count += (num_bufs - 1); + now = jiffies; + elapsed = now - start; + } while (elapsed < (HZ * 2)); + + dev_info(dev, "%3d: %d\n", num_bufs, count); +} + +static void run_ring_sync_once(struct device *dev, int num_bufs) +{ + int i; + + for (i = 0; i < num_bufs - 1; i++) { + give_to_device(dev, i); + take_from_device(dev, i + 1); + } +} + +static void run_ring_sync(struct device *dev, int num_bufs) +{ + unsigned long elapsed; + unsigned long start; + unsigned long now; + int count = 0; + + start = jiffies; + + do { + run_ring_sync_once(dev, num_bufs); + count += num_bufs; + now = jiffies; + elapsed = now - start; + } while (elapsed < (HZ * 2)); + + dev_info(dev, "sync: %3d: %d\n", num_bufs, count); +} + +static __exit void rx_benchmark_release(struct device *dev) +{ +} + +static int __init rx_coherent_benchmark_init(void) +{ + int err; + int i; + + memset(&dev, 0, sizeof(dev)); + + dev_set_name(&dev, "rx_benchmark"); + dev.release = rx_benchmark_release; + dev.coherent_dma_mask = DMA_BIT_MASK(32); + + err = device_register(&dev); + if (err) + return err; + + for (i = 4; i <= 16; i += 2) { + err = alloc_ring(&dev, i); + if (err) + goto out_unregister; + + run_ring(&dev, i); + free_ring(&dev, i); + schedule(); + } + + for (i = 4; i <= 16; i += 2) { + err = alloc_ring(&dev, i); + if (err) + goto out_unregister; + + prime_ring_sync(&dev, i); + run_ring_sync(&dev, i); + free_ring(&dev, i); + schedule(); + } + +out_unregister: + return 0; +} + +static void __exit rx_coherent_benchmark_exit(void) +{ + device_unregister(&dev); +} + +module_init(rx_coherent_benchmark_init); +module_exit(rx_coherent_benchmark_exit); +MODULE_AUTHOR("Andrew Lunn (and...@lunn.ch)"); +MODULE_LICENSE("GPL v2"); -- 2.8.1