日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux dmaengine编程

發(fā)布時間:2023/12/15 linux 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux dmaengine编程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

開發(fā)板:A33,運(yùn)行l(wèi)inux-3.4.39

主機(jī):Ubuntu 14.04

----------------------------------------------

?

DMA是Direct Memory Access的縮寫,顧名思義,就是繞開CPU直接訪問memory的意思。在計(jì)算機(jī)中,相比CPU,memory和外設(shè)的速度是非常慢的,因而在memory和memory(或者memory和設(shè)備)之間搬運(yùn)數(shù)據(jù),非常浪費(fèi)CPU的時間,造成CPU無法及時處理一些實(shí)時事件。因此,工程師們就設(shè)計(jì)出來一種專門用來搬運(yùn)數(shù)據(jù)的器件----DMA控制器,協(xié)助CPU進(jìn)行數(shù)據(jù)搬運(yùn)。

DMA傳輸可以是內(nèi)存到內(nèi)存、內(nèi)存到外設(shè)和外設(shè)到內(nèi)存。這里的代碼通過dma驅(qū)動實(shí)現(xiàn)了內(nèi)存到內(nèi)存的數(shù)據(jù)傳輸。linux實(shí)現(xiàn)了DMA框架,叫做DMA Engine,內(nèi)核驅(qū)動開發(fā)者必須按照固定的流程編碼才能正確的使用DMA。

?

1. DMA用法包括以下的步驟:?

1)分配一個DMA通道;?

dma_request_channel()

2)設(shè)置controller特定的參數(shù);?

none

3)獲取一個傳輸描述符;

device_prep_dma_memcpy()?

4)提交傳輸描述符;?

tx_submit();

5)dma_async_issue_pending()

?

2. 測試:

1)交叉編譯成ko模塊,下載到A33開發(fā)板

2)加載模塊:insmod dma.ko

3)執(zhí)行:cat /dev/dma_test

執(zhí)行此操作會產(chǎn)生一次DMA請求,將src內(nèi)存數(shù)據(jù)復(fù)制到dst內(nèi)存區(qū)域,復(fù)制完后會調(diào)用回調(diào)函數(shù),復(fù)制過程中不需要CPU的參與。

注:在Ubuntu下dma_request_channel()失敗,原因未知,所以轉(zhuǎn)到A33下測試。

?

3. 其它

申請DMA緩沖區(qū):

void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, int flag);

該函數(shù)實(shí)際獲得兩個地址,?

1、函數(shù)的返回值是一個 void *,代表緩沖區(qū)的內(nèi)核虛擬地址?

2、相關(guān)的總線地址(物理地址),保存在dma_handle中

物理地址和虛擬地址存在映射關(guān)系。DMA傳輸使用物理地址,而CPU操作的是虛擬地址。

如在tx = dev->device_prep_dma_memcpy(chan, dma_dst, dma_src, 512, flags);使用了物理地址

在dma_callback_func()中使用了虛擬地址。

使用DMA傳輸數(shù)據(jù)必須要基于DMA緩沖區(qū),不能使用其他的內(nèi)存區(qū)域,如kmalloc開辟的內(nèi)存。

?

4. 源碼dma.c

/* Function description:When we call dmatest_read(),it will transmit src memory data to dst memory,then print dst memory data by dma_callback_func(void) function. */ #include<linux/module.h> #include<linux/init.h> #include<linux/fs.h> #include<linux/sched.h>#include<linux/device.h> #include<linux/string.h> #include<linux/errno.h>#include<linux/types.h> #include<linux/slab.h> #include<linux/dmaengine.h> #include<linux/dma-mapping.h>#include<asm/uaccess.h>#define DEVICE_NAME "dma_test"unsigned char dmatest_major; static struct class *dmatest_class;struct dma_chan *chan;//bus address dma_addr_t dma_src; dma_addr_t dma_dst; //virtual address char *src = NULL; char *dst = NULL ; struct dma_device *dev; struct dma_async_tx_descriptor *tx = NULL; enum dma_ctrl_flags flags; dma_cookie_t cookie;//When dma transfer finished,this function will be called. void dma_callback_func(void) {int i;printk("dma transfer ok.\n");for (i = 0; i < 512; ){printk("dst[%d]:%c ", i, dst[i]);i += 10;}printk("\n"); }int dmatest_open(struct inode *inode, struct file *filp) {return 0; }int dmatest_release(struct inode *inode, struct file *filp) {return 0; }static ssize_t dmatest_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) {int ret = 0;//alloc a desc,and set dst_addr,src_addr,data_size.tx = dev->device_prep_dma_memcpy(chan, dma_dst, dma_src, 512, flags);if (!tx){printk("Failed to prepare DMA memcpy");}tx->callback = dma_callback_func;//set call back functiontx->callback_param = NULL;cookie = tx->tx_submit(tx); //submit the descif (dma_submit_error(cookie)){printk("Failed to do DMA tx_submit");}printk("begin dma transfer.\n"); dma_async_issue_pending(chan); //begin dma transferreturn ret; }static ssize_t dmatest_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos) {int ret = 0;return ret; }static const struct file_operations dmatest_fops = {.owner = THIS_MODULE,.read = dmatest_read,.write = dmatest_write,.open = dmatest_open,.release = dmatest_release, };int dmatest_init(void) {int i;dma_cap_mask_t mask;//the first parameter 0 means allocate major device number automaticallydmatest_major = register_chrdev(0, DEVICE_NAME, &dmatest_fops);if (dmatest_major < 0) return dmatest_major;//create a dmatest classdmatest_class = class_create(THIS_MODULE,DEVICE_NAME);if (IS_ERR(dmatest_class))return -1;//create a dmatest device from this classdevice_create(dmatest_class,NULL,MKDEV(dmatest_major,0),NULL,DEVICE_NAME);printk("device node create ok.\n");//alloc 512B src memory and dst memorysrc = dma_alloc_coherent(NULL, 512, &dma_src, GFP_KERNEL);printk("src = 0x%x, dma_src = 0x%x\n",src, dma_src);dst = dma_alloc_coherent(NULL, 512, &dma_dst, GFP_KERNEL);printk("dst = 0x%x, dma_dst = 0x%x\n",dst, dma_dst);for (i = 0; i < 512; i++){*(src + i) = 'a';}dma_cap_zero(mask);dma_cap_set(DMA_MEMCPY, mask); //direction:memory to memorychan = dma_request_channel(mask,NULL,NULL); //request a dma channelif(chan)printk("dma channel id = %d\n",chan->chan_id);else{printk("dma_request_channel faild.\n");return -1;}flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;dev = chan->device;return 0; }void dmatest_exit(void) {unregister_chrdev(dmatest_major,DEVICE_NAME);//release major device numberdevice_destroy(dmatest_class,MKDEV(dmatest_major,0));//destroy globalmem deviceclass_destroy(dmatest_class);//destroy globalmem class//free memory and dma channeldma_free_coherent(NULL, 512, src, &dma_src);dma_free_coherent(NULL, 512, dst, &dma_dst);dma_release_channel(chan); }module_init(dmatest_init); module_exit(dmatest_exit);MODULE_LICENSE("GPL");

?

?

?

?

總結(jié)

以上是生活随笔為你收集整理的linux dmaengine编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。