最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Zynq

旗下网站admin16浏览0评论

Zynq

Zynq

1、背景介绍

在使用pcie进行数据传输时,常常需要用到dma,由于dma传输多为异步传输方式,只需要告诉dma起始地址,数据大小,然后启动dma,cpu就可以去做其他事情。不过Dma传输需要有一个前提条件,分配一段连续的物理内存,在linux下,由于存在虚实物理地址转换,用户访问的都是虚地址,分配一段连续的物理内存比较困难。常见的做法是在操作系统启动时预留一段物理内存专门用于dma,缺点是操作系统无法管理这段空间,如果没有dma操作显然空间就浪费了。

2、cma概念

cma是linux中一种动态分配连续物理内存的方式,具体可以参看宋宝华的这篇博文:/21cnbao/article/details/7309757

这里在zynq中进行了一下cma的实践

3、内核配置

当前使用的内核是xilinx 2017.4版本,linux版本号为4.9。为了使用cma,需要在内核中进行如下配置

上图中设置了cma默认大小为256MB,同时指定了PAGE_SIZE最大值12,即cma区域的页大小为4MB,空间也按照4MB页进行对齐。

4、测试

当linux启动后能在串口中看到如下打印

从物理地址0x3000000开始的256MB为cma空间。测试时可以通过下面代码进行试验,参考:https://lwn/Articles/485193/

#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;unsigned long 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_tcma_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) {dma_free_coherent(cma_dev, alloc->size, alloc->virt,alloc->dma);_dev_info(cma_dev, "free CM at virtual address: 0x%p dma address: 0x%p size:%luKiB\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_tcma_test_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){struct cma_allocation *alloc;int ret;alloc = kmalloc(sizeof *alloc, GFP_KERNEL);if (!alloc)return -ENOMEM;ret = kstrtoul_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;alloc->size *= SZ_1K;alloc->virt = dma_alloc_coherent(cma_dev, alloc->size,&alloc->dma, GFP_KERNEL);if (alloc->virt) {_dev_info(cma_dev, "allocate CM at virtual address: 0x%p""address: 0x%p size:%luKiB\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 = 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 <Baohua.Song@csr>");MODULE_DESCRIPTION("kernel module to help the test of CMA");MODULE_ALIAS("CMA test");

这里将测试代码直接编入内核中

操作系统启动后执行echo 51200> /dev/cma_test即分配50MB连续物理内存空间,起始物理地址为0x31000000。

Zynq-Linux移植学习笔记之33-CMA连续物理内存配置

发布评论

评论列表(0)

  1. 暂无评论