免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4547 | 回复: 1
打印 上一主题 下一主题

使用DMA实现memcpy [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-11-10 22:06 |只看该作者 |倒序浏览
本帖最后由 mayjojo 于 2010-11-12 14:33 编辑

Hi, there

至于为什么有这样的需求,http://linux.chinaunix.net/bbs/thread-1173346-1-1.html 已经给出来说明。我是这个论坛的新人,也是kernel的新人。第一次在这里发帖提问,但是没有得到任何答案。于是在解决来问题之后,将自己的程序贴出来,希望大家提出改进意见。以下代码遵守GPL协议。

文件:dma_memcpy.c
  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/fs.h>
  4. #include <linux/mm_types.h>
  5. #include <linux/mm.h>
  6. #include <linux/sched.h>
  7. #include <linux/async_tx.h>
  8. #include <linux/slab.h>
  9. #include <linux/slub_def.h>
  10. #include <asm/page.h>
  11. #include <asm/uaccess.h>
  12. #include <asm/current.h>

  13. #include "dma_memcpy.h"

  14. MODULE_LICENSE("GPL");

  15. #define DMA_MEMCPY_DEVICE_NAME "dma_memcpy_device"

  16. static int major = 0;

  17. static int memcpy_ioctl(struct inode * inode, struct file * pfile, unsigned int cmd, unsigned long arg);

  18. static struct file_operations fops = { .ioctl = memcpy_ioctl };

  19. static int memcpy_init(void)
  20. {
  21.         major = register_chrdev(0, DMA_MEMCPY_DEVICE_NAME, &fops);
  22.         if (major < 0) {
  23.                 printk(KERN_ALERT "failed to register chrdev :%d\n", major);
  24.                 return major;
  25.         }
  26.         else {
  27.                 printk(KERN_ALERT "load dma_memcpy module : %d\n", major);
  28.                 return 0;
  29.         }
  30. }

  31. static void memcpy_exit(void)
  32. {
  33.         unregister_chrdev(major, DMA_MEMCPY_DEVICE_NAME);
  34.         printk(KERN_ALERT "exit dma_memcpy module\n");
  35. }

  36. static int memcpy_ioctl(struct inode * inode, struct file * pfile, unsigned int cmd, unsigned long arg)
  37. {
  38.         dma_memcpy_ioctr_t k_arg;
  39.         unsigned long count;
  40.         unsigned long nr_page;
  41.         unsigned long dest;
  42.         unsigned long src;
  43.         unsigned long i;
  44.         int nr_page_fetched;
  45.         int retval;

  46.         struct page ** dest_pages = NULL;
  47.         struct page ** src_pages = NULL;
  48.         struct async_submit_ctl * ctls = NULL;
  49.         struct dma_async_tx_descriptor ** desps = NULL;

  50.         printk(KERN_ALERT "file ioctl.\n");

  51.         if (!access_ok(VERIFY_READ, arg, sizeof(dma_memcpy_ioctr_t))) {
  52.                 printk(KERN_ALERT "invalid parameter of ioctl.\n");
  53.                 retval = -EFAULT;
  54.                 goto CLEAN;
  55.         }

  56.         if (copy_from_user((void *) &k_arg, (const void *) arg, sizeof(dma_memcpy_ioctr_t))) {
  57.                 printk(KERN_ALERT "can NOT copy data from user space.\n");
  58.                 retval = -EFAULT;
  59.                 goto CLEAN;
  60.         }

  61.         if (!access_ok(VERIFY_READ, k_arg.src, sizeof(k_arg.size))) {
  62.                 printk(KERN_ALERT "can NOT read data from src.\n");
  63.                 retval = -EFAULT;
  64.                 goto CLEAN;
  65.         }

  66.         if (!access_ok(VERIFY_WRITE, k_arg.dest, sizeof(k_arg.size))) {
  67.                 printk(KERN_ALERT "can NOT write data to dest.\n");
  68.                 retval = -EFAULT;
  69.                 goto CLEAN;
  70.         }

  71.         src = (unsigned long) k_arg.src;
  72.         dest = (unsigned long) k_arg.dest;

  73.         if (!(dest & PAGE_MASK && src & PAGE_MASK)) {
  74.                 printk(KERN_ALERT "src or dest is NOT aligned with PAGE.\n");
  75.                 retval = -EDOM;
  76.                 goto CLEAN;
  77.         }

  78.         count = k_arg.size;
  79.         retval = count;
  80.         nr_page = count / PAGE_SIZE;
  81.         printk(KERN_ALERT "to copy %ld page.\n", nr_page);

  82.         if (count % PAGE_SIZE != 0) {
  83.                 printk(KERN_ALERT "the size is NOT the multiple of PAGE.\n");
  84.                 retval = -EDOM;
  85.                 goto CLEAN;
  86.         }

  87.         dest_pages = (struct page **) kmalloc(nr_page * sizeof(struct page *), GFP_KERNEL);
  88.         src_pages = (struct page **) kmalloc(nr_page * sizeof(struct page *), GFP_KERNEL);
  89.         if (NULL == dest_pages || NULL == src_pages) {
  90.                 printk(KERN_ALERT "can NOT kmalloc memory.\n");
  91.                 retval = -ENOMEM;
  92.                 goto CLEAN;
  93.         }

  94.         if (nr_page != (nr_page_fetched = get_user_pages(current, current->mm, src, nr_page, 0, 0, src_pages, NULL))) {
  95.                 printk(KERN_ALERT "can NOT get user pages of virtual address 0x%lx\n", src);
  96.                 for (i = 0; i < nr_page_fetched; i++) {
  97.                         put_page(src_pages[i]);
  98.                 }
  99.                 goto CLEAN;
  100.         }

  101.         if (nr_page != (nr_page_fetched = get_user_pages(current, current->mm, dest, nr_page, 1, 0, dest_pages, NULL))) {
  102.                 printk(KERN_ALERT "can NOT get user pages of virtual address 0x%lx\n", dest);
  103.                 for (i = 0; i < nr_page_fetched; i++) {
  104.                         put_page(dest_pages[i]);
  105.                 }
  106.                 goto CLEAN;
  107.         }

  108.         ctls = (struct async_submit_ctl *) kmalloc(nr_page * sizeof(struct async_submit_ctl), GFP_KERNEL);
  109.         if (NULL == ctls) {
  110.                 printk(KERN_ALERT "can NOT kmalloc memory.\n");
  111.                 retval = -ENOMEM;
  112.                 goto CLEAN;
  113.         }

  114.         desps = (struct dma_async_tx_descriptor **) kmalloc(nr_page * sizeof(struct dma_async_tx_descriptor *), GFP_KERNEL);
  115.         if (NULL == desps) {
  116.                 printk(KERN_ALERT "can NOT kmalloc memory.\n");
  117.                 retval = -ENOMEM;
  118.                 goto CLEAN;
  119.         }

  120.         for (i = 0; i < nr_page; i++) {
  121.                 ctls[i].cb_fn = NULL;
  122.                 ctls[i].cb_param = NULL;
  123.                 ctls[i].depend_tx = NULL;
  124.                 ctls[i].flags = ASYNC_TX_ACK;
  125.                 ctls[i].scribble = NULL;
  126.         }

  127.         for (i = 0; i < nr_page; i++) {
  128.                 printk(KERN_ALERT "copy %ldth page.\n", i + 1);
  129.                 desps[i] = async_memcpy(dest_pages[i], src_pages[i], 0, 0, PAGE_SIZE, ctls + i);
  130.         }

  131.         for (i = 0; i < nr_page; i++) {
  132.                 printk(KERN_ALERT "finished copying %ldth page.\n", i + 1);
  133.                 if (NULL == desps) {
  134.                         printk(KERN_ALERT "do NOT use DMA to memcpy.\n");
  135.                 }
  136.                 else {
  137.                         dma_wait_for_async_tx(desps[i]);
  138.                 }
  139.         }
  140.         for (i = 0; i < nr_page_fetched; i++) {
  141.                 put_page(src_pages[i]);
  142.                 set_page_dirty(dest_pages[i]);
  143.                 put_page(dest_pages[i]);
  144.         }

  145. CLEAN :
  146.         kfree(dest_pages);
  147.         kfree(src_pages);
  148.         kfree(ctls);
  149.         kfree(desps);

  150.         printk(KERN_ALERT "complete.\n");
  151.         return retval;
  152. }
  153. module_init(memcpy_init);
  154. module_exit(memcpy_exit);

复制代码
文件:dma_memcpy.h
  1. #ifndef _DMA_MEMCPY_H_
  2. #define _DMA_MEMCPY_H_

  3. typedef struct dma_memcpy_ioctr {
  4.         void * dest;
  5.         void * src;
  6.         unsigned long size;
  7. } dma_memcpy_ioctr_t;

  8. #ifndef __KERNEL__
  9. #include <sys/ioctl.h>
  10. #include <unistd.h>
  11. #include <fcntl.h>

  12. #define DMA_MEMCPY_DEVICE_NAME "dma_memcpy_device"
  13. #define DMA_MEMCPY_DEVICE_PATH "/dev/dma_memcpy_device"

  14. const unsigned long PAGE_SIZE = (unsigned long)getpagesize();
  15. #define PAGE_MASK ( ~( PAGE_SIZE - 1 ))
  16. inline void * page_align_up(void * point) {
  17.         return (void *)(( ( unsigned long )(point) + PAGE_SIZE - 1 ) & PAGE_MASK );
  18. }

  19. static int dma_memcpy_device = 0;

  20. /**
  21. * @brief to open dma_memcpy_device
  22. *
  23. * @return return 1 if success, 0 otherwise.
  24. */
  25. inline int init_dma_memcpy() {
  26.         dma_memcpy_device = open(DMA_MEMCPY_DEVICE_PATH, O_RDONLY);
  27.         if (dma_memcpy_device <= 0) {
  28.                 return 0;
  29.         }
  30.         return 1;
  31. }

  32. /**
  33. * @brief to close dma_memcpy_device
  34. */
  35. inline void clean_dma_memcpy() {
  36.         close(dma_memcpy_device);
  37. }

  38. /**
  39. * @brief using dma to copy data in memory, dest and src are not overlapped.
  40. *
  41. * @param dest the destination point aligned with page size.
  42. * @param src the source point aligned with page size.
  43. * @param size the byte to be copied, must be the multiple of page size.
  44. *
  45. * @return the byte been copied. negative number on any error.
  46. */
  47. inline unsigned long dma_memcpy(void * dest, const void * src, unsigned long size) {
  48.         int retval;
  49.         dma_memcpy_ioctr_t ioctr;
  50.         ioctr.dest = dest;
  51.         ioctr.src = (void *)src;
  52.         ioctr.size = size;

  53.         retval = ioctl(dma_memcpy_device, 0, &ioctr);
  54.         return retval;
  55. }

  56. #endif

  57. #endif /*_DMA_MEMCPY_H_*/
复制代码
文件:Makefile
  1. ifneq (X$(KERNELRELEASE),X)
  2. obj-m := dma_memcpy.o

  3. else
  4. KERNELDIR := /lib/modules/$(shell uname -r)/build
  5. PWD := $(shell pwd)

  6. all:
  7.         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  8. endif

  9. clean:
  10.         @rm -f *.o *.mod.* *.ko *.symvers *.order .d*
  11.         @rm -rf .tmp_versions
  12.        
  13. install:
  14.         /bin/sh ./ins_memcpy_device.sh
  15.        
  16. .PHONY:all clean
复制代码
文件:ins_memcpy_device.sh
  1. #!/bin/sh
  2. module="dma_memcpy"
  3. device="dma_memcpy_device"
  4. mode="664"

  5. # invoke modprobe to install depended module.
  6. /sbin/modprobe async_memcpy

  7. # uninstall old module.
  8. /sbin/rmmod $module 2> /dev/null

  9. # invoke insmod with all arguments we got
  10. /sbin/insmod ./$module.ko $* || exit 1

  11. major=`awk '$2~/dma_memcpy_device/ {print $1}' /proc/devices`

  12. # remove stale node
  13. rm -f /dev/$device 2> /dev/null

  14. # make new
  15. mknod /dev/$device c $major 0

  16. # change owner
  17. chmod $mode /dev/$device
复制代码
文件:test.cpp
  1. #include <iostream>
  2. #include <cstring>
  3. #include <cassert>
  4. #include <cstdio>
  5. #include "dma_memcpy.h"

  6. using namespace std;

  7. int main()
  8. {
  9.         char * src, *dest;
  10.         char * align_src, *align_dest;

  11.         unsigned int nr_page = 10;

  12.         src = new char[PAGE_SIZE * (nr_page + 1)];
  13.         dest = new char[PAGE_SIZE * (nr_page + 1)];

  14.         align_src = (char *) page_align_up(src);
  15.         align_dest = (char *) page_align_up(dest);

  16.         memset(align_dest, 'B', nr_page * PAGE_SIZE);
  17.         memset(align_src, 'A', nr_page * PAGE_SIZE);

  18.         if (!init_dma_memcpy()) {
  19.                 perror("init_dma_memcpy");
  20.                 return -1;
  21.         }

  22.         if (nr_page * PAGE_SIZE != dma_memcpy(align_dest, align_src, nr_page * PAGE_SIZE)) {
  23.                 perror("dma_memcpy ");
  24.         }

  25.         assert(0 == memcmp(align_src, align_dest, nr_page * PAGE_SIZE));

  26.         clean_dma_memcpy();

  27.         cout << "All test is OK." << endl;

  28.         return 0;
  29. }
复制代码

论坛徽章:
3
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:58:11数据库技术版块每日发帖之星
日期:2015-08-30 06:20:00
2 [报告]
发表于 2010-11-12 15:29 |只看该作者
OMG ... 这样的效率已经低下到没有意义了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP