- 论坛徽章:
- 0
|
本帖最后由 mayjojo 于 2010-11-12 14:33 编辑
Hi, there
至于为什么有这样的需求,http://linux.chinaunix.net/bbs/thread-1173346-1-1.html 已经给出来说明。我是这个论坛的新人,也是kernel的新人。第一次在这里发帖提问,但是没有得到任何答案。于是在解决来问题之后,将自己的程序贴出来,希望大家提出改进意见。以下代码遵守GPL协议。
文件:dma_memcpy.c- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <linux/mm_types.h>
- #include <linux/mm.h>
- #include <linux/sched.h>
- #include <linux/async_tx.h>
- #include <linux/slab.h>
- #include <linux/slub_def.h>
- #include <asm/page.h>
- #include <asm/uaccess.h>
- #include <asm/current.h>
- #include "dma_memcpy.h"
- MODULE_LICENSE("GPL");
- #define DMA_MEMCPY_DEVICE_NAME "dma_memcpy_device"
- static int major = 0;
- static int memcpy_ioctl(struct inode * inode, struct file * pfile, unsigned int cmd, unsigned long arg);
- static struct file_operations fops = { .ioctl = memcpy_ioctl };
- static int memcpy_init(void)
- {
- major = register_chrdev(0, DMA_MEMCPY_DEVICE_NAME, &fops);
- if (major < 0) {
- printk(KERN_ALERT "failed to register chrdev :%d\n", major);
- return major;
- }
- else {
- printk(KERN_ALERT "load dma_memcpy module : %d\n", major);
- return 0;
- }
- }
- static void memcpy_exit(void)
- {
- unregister_chrdev(major, DMA_MEMCPY_DEVICE_NAME);
- printk(KERN_ALERT "exit dma_memcpy module\n");
- }
- static int memcpy_ioctl(struct inode * inode, struct file * pfile, unsigned int cmd, unsigned long arg)
- {
- dma_memcpy_ioctr_t k_arg;
- unsigned long count;
- unsigned long nr_page;
- unsigned long dest;
- unsigned long src;
- unsigned long i;
- int nr_page_fetched;
- int retval;
- struct page ** dest_pages = NULL;
- struct page ** src_pages = NULL;
- struct async_submit_ctl * ctls = NULL;
- struct dma_async_tx_descriptor ** desps = NULL;
- printk(KERN_ALERT "file ioctl.\n");
- if (!access_ok(VERIFY_READ, arg, sizeof(dma_memcpy_ioctr_t))) {
- printk(KERN_ALERT "invalid parameter of ioctl.\n");
- retval = -EFAULT;
- goto CLEAN;
- }
- if (copy_from_user((void *) &k_arg, (const void *) arg, sizeof(dma_memcpy_ioctr_t))) {
- printk(KERN_ALERT "can NOT copy data from user space.\n");
- retval = -EFAULT;
- goto CLEAN;
- }
- if (!access_ok(VERIFY_READ, k_arg.src, sizeof(k_arg.size))) {
- printk(KERN_ALERT "can NOT read data from src.\n");
- retval = -EFAULT;
- goto CLEAN;
- }
- if (!access_ok(VERIFY_WRITE, k_arg.dest, sizeof(k_arg.size))) {
- printk(KERN_ALERT "can NOT write data to dest.\n");
- retval = -EFAULT;
- goto CLEAN;
- }
- src = (unsigned long) k_arg.src;
- dest = (unsigned long) k_arg.dest;
- if (!(dest & PAGE_MASK && src & PAGE_MASK)) {
- printk(KERN_ALERT "src or dest is NOT aligned with PAGE.\n");
- retval = -EDOM;
- goto CLEAN;
- }
- count = k_arg.size;
- retval = count;
- nr_page = count / PAGE_SIZE;
- printk(KERN_ALERT "to copy %ld page.\n", nr_page);
- if (count % PAGE_SIZE != 0) {
- printk(KERN_ALERT "the size is NOT the multiple of PAGE.\n");
- retval = -EDOM;
- goto CLEAN;
- }
- dest_pages = (struct page **) kmalloc(nr_page * sizeof(struct page *), GFP_KERNEL);
- src_pages = (struct page **) kmalloc(nr_page * sizeof(struct page *), GFP_KERNEL);
- if (NULL == dest_pages || NULL == src_pages) {
- printk(KERN_ALERT "can NOT kmalloc memory.\n");
- retval = -ENOMEM;
- goto CLEAN;
- }
- if (nr_page != (nr_page_fetched = get_user_pages(current, current->mm, src, nr_page, 0, 0, src_pages, NULL))) {
- printk(KERN_ALERT "can NOT get user pages of virtual address 0x%lx\n", src);
- for (i = 0; i < nr_page_fetched; i++) {
- put_page(src_pages[i]);
- }
- goto CLEAN;
- }
- if (nr_page != (nr_page_fetched = get_user_pages(current, current->mm, dest, nr_page, 1, 0, dest_pages, NULL))) {
- printk(KERN_ALERT "can NOT get user pages of virtual address 0x%lx\n", dest);
- for (i = 0; i < nr_page_fetched; i++) {
- put_page(dest_pages[i]);
- }
- goto CLEAN;
- }
- ctls = (struct async_submit_ctl *) kmalloc(nr_page * sizeof(struct async_submit_ctl), GFP_KERNEL);
- if (NULL == ctls) {
- printk(KERN_ALERT "can NOT kmalloc memory.\n");
- retval = -ENOMEM;
- goto CLEAN;
- }
- desps = (struct dma_async_tx_descriptor **) kmalloc(nr_page * sizeof(struct dma_async_tx_descriptor *), GFP_KERNEL);
- if (NULL == desps) {
- printk(KERN_ALERT "can NOT kmalloc memory.\n");
- retval = -ENOMEM;
- goto CLEAN;
- }
- for (i = 0; i < nr_page; i++) {
- ctls[i].cb_fn = NULL;
- ctls[i].cb_param = NULL;
- ctls[i].depend_tx = NULL;
- ctls[i].flags = ASYNC_TX_ACK;
- ctls[i].scribble = NULL;
- }
- for (i = 0; i < nr_page; i++) {
- printk(KERN_ALERT "copy %ldth page.\n", i + 1);
- desps[i] = async_memcpy(dest_pages[i], src_pages[i], 0, 0, PAGE_SIZE, ctls + i);
- }
- for (i = 0; i < nr_page; i++) {
- printk(KERN_ALERT "finished copying %ldth page.\n", i + 1);
- if (NULL == desps) {
- printk(KERN_ALERT "do NOT use DMA to memcpy.\n");
- }
- else {
- dma_wait_for_async_tx(desps[i]);
- }
- }
- for (i = 0; i < nr_page_fetched; i++) {
- put_page(src_pages[i]);
- set_page_dirty(dest_pages[i]);
- put_page(dest_pages[i]);
- }
- CLEAN :
- kfree(dest_pages);
- kfree(src_pages);
- kfree(ctls);
- kfree(desps);
- printk(KERN_ALERT "complete.\n");
- return retval;
- }
- module_init(memcpy_init);
- module_exit(memcpy_exit);
复制代码 文件:dma_memcpy.h- #ifndef _DMA_MEMCPY_H_
- #define _DMA_MEMCPY_H_
- typedef struct dma_memcpy_ioctr {
- void * dest;
- void * src;
- unsigned long size;
- } dma_memcpy_ioctr_t;
- #ifndef __KERNEL__
- #include <sys/ioctl.h>
- #include <unistd.h>
- #include <fcntl.h>
- #define DMA_MEMCPY_DEVICE_NAME "dma_memcpy_device"
- #define DMA_MEMCPY_DEVICE_PATH "/dev/dma_memcpy_device"
- const unsigned long PAGE_SIZE = (unsigned long)getpagesize();
- #define PAGE_MASK ( ~( PAGE_SIZE - 1 ))
- inline void * page_align_up(void * point) {
- return (void *)(( ( unsigned long )(point) + PAGE_SIZE - 1 ) & PAGE_MASK );
- }
- static int dma_memcpy_device = 0;
- /**
- * @brief to open dma_memcpy_device
- *
- * @return return 1 if success, 0 otherwise.
- */
- inline int init_dma_memcpy() {
- dma_memcpy_device = open(DMA_MEMCPY_DEVICE_PATH, O_RDONLY);
- if (dma_memcpy_device <= 0) {
- return 0;
- }
- return 1;
- }
- /**
- * @brief to close dma_memcpy_device
- */
- inline void clean_dma_memcpy() {
- close(dma_memcpy_device);
- }
- /**
- * @brief using dma to copy data in memory, dest and src are not overlapped.
- *
- * @param dest the destination point aligned with page size.
- * @param src the source point aligned with page size.
- * @param size the byte to be copied, must be the multiple of page size.
- *
- * @return the byte been copied. negative number on any error.
- */
- inline unsigned long dma_memcpy(void * dest, const void * src, unsigned long size) {
- int retval;
- dma_memcpy_ioctr_t ioctr;
- ioctr.dest = dest;
- ioctr.src = (void *)src;
- ioctr.size = size;
- retval = ioctl(dma_memcpy_device, 0, &ioctr);
- return retval;
- }
- #endif
- #endif /*_DMA_MEMCPY_H_*/
复制代码 文件:Makefile- ifneq (X$(KERNELRELEASE),X)
- obj-m := dma_memcpy.o
- else
- KERNELDIR := /lib/modules/$(shell uname -r)/build
- PWD := $(shell pwd)
- all:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
- endif
- clean:
- @rm -f *.o *.mod.* *.ko *.symvers *.order .d*
- @rm -rf .tmp_versions
-
- install:
- /bin/sh ./ins_memcpy_device.sh
-
- .PHONY:all clean
复制代码 文件:ins_memcpy_device.sh- #!/bin/sh
- module="dma_memcpy"
- device="dma_memcpy_device"
- mode="664"
- # invoke modprobe to install depended module.
- /sbin/modprobe async_memcpy
- # uninstall old module.
- /sbin/rmmod $module 2> /dev/null
- # invoke insmod with all arguments we got
- /sbin/insmod ./$module.ko $* || exit 1
- major=`awk '$2~/dma_memcpy_device/ {print $1}' /proc/devices`
- # remove stale node
- rm -f /dev/$device 2> /dev/null
- # make new
- mknod /dev/$device c $major 0
- # change owner
- chmod $mode /dev/$device
复制代码 文件:test.cpp- #include <iostream>
- #include <cstring>
- #include <cassert>
- #include <cstdio>
- #include "dma_memcpy.h"
- using namespace std;
- int main()
- {
- char * src, *dest;
- char * align_src, *align_dest;
- unsigned int nr_page = 10;
- src = new char[PAGE_SIZE * (nr_page + 1)];
- dest = new char[PAGE_SIZE * (nr_page + 1)];
- align_src = (char *) page_align_up(src);
- align_dest = (char *) page_align_up(dest);
- memset(align_dest, 'B', nr_page * PAGE_SIZE);
- memset(align_src, 'A', nr_page * PAGE_SIZE);
- if (!init_dma_memcpy()) {
- perror("init_dma_memcpy");
- return -1;
- }
- if (nr_page * PAGE_SIZE != dma_memcpy(align_dest, align_src, nr_page * PAGE_SIZE)) {
- perror("dma_memcpy ");
- }
- assert(0 == memcmp(align_src, align_dest, nr_page * PAGE_SIZE));
- clean_dma_memcpy();
- cout << "All test is OK." << endl;
- return 0;
- }
复制代码 |
|