[转]windows驱动开发-基于WDF的Altera PCIe DMA驱动

本文详细解析了Altera PCIe AVM MDMA IP的寄存器配置与DMA控制器工作原理,包括读写描述符控制器寄存器的功能、描述符格式、Windows DMA编程流程等,深入探讨了DMA传输过程中的状态监测与中断处理机制。

版权声明:本文为优快云博主「黑客三遍猪」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/Zhu_Zhu_2009/article/details/80790252

Altera pcie-avmm dma IP寄存器
DMA Descriptor Controller Registers
DMA控制器读写均支持最多128个描述符,读写操作是以FPGA视角来看,读操作是从PCIe地址空间到FPGA Avalon-MM地址空间,写操作是从FPGA Avalon-MM地址空间到PCIe地址空间。
在DMA控制器寄存器里设置描述符表位于在PCIe地址空间里的地址和大小,DMA控制器用Read Data Mover首先将描述符复制到自己内部的FIFO中,然后在根据描述符来开始DMA传输。描述符在RC内的地址必须是32字节对齐的。
DMA控制器有寄存器指示读写描述符的完成状态,读和写分别有自己的状态寄存器表,每个表有128个连续的DWORD项,对应128个描述符。状态字占用512字节,位置在RC Read Status and Descriptor Base指定的地址偏移0处,而实际的描述符在0x200偏移处,DMA控制器项状态字的done位写1表示传输成功,DMA控制器在完成最后一个描述符后会发送一个MSI中断,在接收到中断之后,主机host软件可以轮询done位来判断描述符状态,但是DMA控制器不会设置done位或者发送MSI在每一个描述符完成的时候,它根据RD_DMA_LAST PTR和WR_DMA_LAST_PTR寄存器存储的描述符ID来操作,由于描述符支持PCIe完成包的乱序传输,所以done位置位的时候,描述符可能还没有传输完成。例如想在128个描述符的传输中间时刻和完成时候获得通知:

1、写入RD_DMA_LAST_PTR值63。
2、写入RD_DMA_LAST_PTR值127。
3、轮询第63个状态字。
4、轮询第127个状态字。

Read DMA Descriptor Controller Registers

地址偏移寄存器访问权限描述
0x00RC Read Status and Descriptor Base (Low)RW低32位,在设置高32位之后设置,地址必须32位对齐,在传输完成的时候才能改变这个寄存器
0x04RC Read Status and Descriptor Base (High)RW高32位
0x08EP Read Descriptor FIFO Base (Low)RW低32位,指定存储描述符的FIFO地址,在设置高32位之后设置
0x0CEP Read Descriptor FIFO Base (High)RW高32位
0x10RD_DMA_LAST_PTRRW读返回上次操作的描述符ID,如果没有DMA操作则返回0xFF,指定最后一个操作的描述符ID发起DMA,比如,读返回4,为了传输5个描述符,软件应该写入9
0x14RD_TABLE_SIZERW设置读描述符表的大小,值为描述符数量减1,默认为127
0x18RD_CONTROLRW高31位保留,第0位设置上报每一个描述符的done位,但MSI都不会每次上报,否则根据RD_DMA_LAST_PTR来上报

 

Write DMA Descriptor Controller Registers

和读一样,地址偏移在0x100。

Read DMA and Write DMA Descriptor Format

每个描述符32字节,Read/Write Status and Descriptor Base + 0x200处。

地址偏移寄存器描述
0x00RD_LOW_SRC_ADDR低32位,DMA源地址,PCIe地址空间
0x04RD_HIGH_SRC_ADDR高32位
0x08RD_CTRL_LOW_DEST_ADDR低32位,Avalon-MM地址空间
0x0CRD_CTRL_HIGH_DEST_ADDR高32位
0x10CONTROL

[31:25] Reserved,必须为0
[24:18] ID,描述符ID,0-127
[17:00] SIZE,传输大小,以DWORD单位,最大传输大小是1MB-4bytes,超过最大传输大小,按最大值传输,否则传输设置值,这个字段最大值为0x40000-0x1

0x14~0x1CReservedN/A

 

windows DMA编程

分配Descriptor内存,

 1     NTSTATUS status = WdfCommonBufferCreate(engine->parentDevice->dmaEnabler, bufferSize,
 2                                             WDF_NO_OBJECT_ATTRIBUTES, &engine->descBuffer);
 3     if (!NT_SUCCESS(status)) {
 4         TraceError(DBG_INIT, "WdfCommonBufferCreate failed: %!STATUS!", status);
 5         return status;
 6     }
 7 
 8     PHYSICAL_ADDRESS descBufferLA = WdfCommonBufferGetAlignedLogicalAddress(engine->descBuffer);
 9     PUCHAR descBufferVA = (PUCHAR)WdfCommonBufferGetAlignedVirtualAddress(engine->descBuffer);
10     RtlZeroMemory(descBufferVA, bufferSize);

 

申请MSI/MSI-X中断,

1     NTSTATUS status = WdfInterruptCreate(xdma->wdfDevice, &config, &attribs,
2                                          &(xdma->channelInterrupts[index]));
3     if (!NT_SUCCESS(status)) {
4         TraceError(DBG_INIT, "WdfInterruptCreate failed: %!STATUS!", status);
5     }

 

申请DMA,这里设置了ADMA_MAX_TRANSFER_SIZE,

1     WdfDeviceSetAlignmentRequirement(adma->wdfDevice, FILE_32_BYTE_ALIGNMENT); //add by zhuce 
2     WDF_DMA_ENABLER_CONFIG dmaConfig;
3     WDF_DMA_ENABLER_CONFIG_INIT(&dmaConfig, WdfDmaProfileScatterGather64Duplex, ADMA_MAX_TRANSFER_SIZE);
4     status = WdfDmaEnablerCreate(adma->wdfDevice, &dmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &adma->dmaEnabler);
5     if (!NT_SUCCESS(status)) {
6         TraceError(DBG_INIT, " WdfDmaEnablerCreate() failed: %!STATUS!", status);
7         return status;
8     }

 

申请读/写队列,

 1     WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchSequential);
 2     config.EvtIoWrite = EvtIoWriteDma;
 3     //config.EvtIoRead = EvtIoReadDma;
 4     WDF_OBJECT_ATTRIBUTES_INIT(&attribs);
 5     attribs.SynchronizationScope = WdfSynchronizationScopeQueue;
 6     WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attribs, QUEUE_CONTEXT);
 7     status = WdfIoQueueCreate(device, &config, &attribs, queue);
 8     if (!NT_SUCCESS(status)) {
 9         TraceError(DBG_INIT, "WdfIoQueueCreate failed %d", status);
10         return status;
11     }

 

发起DMA,ADMA_EngineProgramDma作为回调函数,超过ADMA_MAX_TRANSFER_SIZE,传输会被分多次,WDF为我们做了很多工作,这些我们都是看不到的。

 1     status = WdfDmaTransactionInitializeUsingRequest(queue->engine->dmaTransaction, Request,
 2                                                      ADMA_EngineProgramDma,
 3                                                      WdfDmaDirectionReadFromDevice);
 4     if (!NT_SUCCESS(status)) {
 5         TraceError(DBG_IO, "WdfDmaTransactionInitializeUsingRequest failed: %!STATUS!",
 6                    status);
 7         goto ErrExit;
 8     }
 9     status = WdfDmaTransactionExecute(queue->engine->dmaTransaction, queue->engine);
10     if (!NT_SUCCESS(status)) {
11         TraceError(DBG_IO, "WdfDmaTransactionExecute failed: %!STATUS!", status);
12         goto ErrExit;
13     }

 

回调函数,填入描述符表。

 1     for (ULONG i = 0; i < SgList->NumberOfElements; i++) {
 2         descriptor[i].control = XDMA_DESC_MAGIC;
 3         descriptor[i].numBytes = SgList->Elements[i].Length;
 4         ULONG hostAddrLo = SgList->Elements[i].Address.LowPart;
 5         LONG hostAddrHi = SgList->Elements[i].Address.HighPart;
 6         if (Direction == WdfDmaDirectionWriteToDevice) {
 7             // source is host memory
 8             descriptor[i].srcAddrLo = hostAddrLo;
 9             descriptor[i].srcAddrHi = hostAddrHi;
10             descriptor[i].dstAddrLo = LIMIT_TO_32(deviceOffset);
11             descriptor[i].dstAddrHi = LIMIT_TO_32(deviceOffset >> 32);
12         } else {
13             // destination is host memory
14             descriptor[i].srcAddrLo = LIMIT_TO_32(deviceOffset);
15             descriptor[i].srcAddrHi = LIMIT_TO_32(deviceOffset >> 32);
16             descriptor[i].dstAddrLo = hostAddrLo;
17             descriptor[i].dstAddrHi = hostAddrHi;
18         }
19     }

 

转载于:https://www.cnblogs.com/tubujia/p/11430213.html

├─reference_design │ ├─vhdl │ │ │ stratix_enh_pll.vhd │ │ │ stratix_top.vhd │ │ │ vhdl_components.vhd │ │ │ │ │ ├─001 ddr_cntrl │ │ │ ddr_top.vhd │ │ │ │ │ ├─004 pci_local │ │ │ backend.vhd │ │ │ cnten.vhd │ │ │ datapath_fifo.vhd │ │ │ dma.vhd │ │ │ dma_reg.vhd │ │ │ dma_sm.vhd │ │ │ fifo_128x32.vhd │ │ │ fifo_128x4.vhd │ │ │ fifo_128x64.vhd │ │ │ last_gen.vhd │ │ │ mstr_cntrl.vhd │ │ │ mstr_fifo_cntrl.vhd │ │ │ mstr_perf.vhd │ │ │ targ_cntrl.vhd │ │ │ targ_fifo_cntrl.vhd │ │ │ targ_perf.vhd │ │ │ │ │ ├─002 ddr_intf │ │ │ adr_gen.vhd │ │ │ clk_sync.vhd │ │ │ cntrl_intf.vhd │ │ │ ddr_intf.vhd │ │ │ mr_sm.vhd │ │ │ mw_sm.vhd │ │ │ tr_sm.vhd │ │ │ tw_sm.vhd │ │ │ │ │ ├─003 flash_cntrl │ │ │ erase_sm.vhd │ │ │ flash_mem_cntrl.vhd │ │ │ read_sm.vhd │ │ │ write_sm.vhd │ │ │ │ │ └─005 pci_mt64 │ │ pci_top.vhd │ │ │ ├─001 sim │ │ │ modelsim.ini │ │ │ sim.do │ │ │ stratix_pci2ddr.mpf │ │ │ stratix_pci2ddr_tb.vhd │ │ │ trgt_tranx_mem_init.dat │ │ │ wave_stratix_pciddr.do │ │ │ │ │ ├─001 altera_lib │ │ │ altera_mf.vhd │ │ │ │ │ ├─002 ddr_dimm │ │ │ ddr_dimm_model.vhd │ │ │ mt46v32m8.vhd │ │ │ │ │ └─003 pci_bfm │ │ arbiter.vhd │ │ clk_gen.vhd │ │ log.vhd │ │ monitor.vhd │ │ mstr_pkg.vhd │ │ mstr_tranx.vhd │ │ pull_up.vhd │ │ trgt_tranx.vhd │ │ │ └─002 syn_1s25 │ stratix_top.csf │ stratix_top.esf │ stratix_top.psf │ stratix_top.quartus │ stratix_top.rbf │ stratix_top.sof │ ├─001 bin │ altera.inf │ megaicon.ico │ StratixPCI.exe │ STRATIX_KIT_APP_HELP.HLP │ wdreg.exe │ windrvr6.inf │ windrvr6.sys │ ├─002 constraints │ mt32_23_ep1s25f1020c5_66_03_04.tcl │ mt64_23_ep1s25f1020c5_66_03_04.tcl │ Stratix_PCI_Board_DDR_settings.tcl │ t32_23_ep1s25f1020c5_66_03_04.tcl │ ├─003 doc │ an223.pdf │ banner.jpg │ ds_StratixPciBd.pdf │ readmeStratixPciKit.htm │ StratixPciKitDocContents.pdf │ ug_StratixPciKit.pdf │ ├─004 max_config │ max_stratix_config.pof │ └─006 software ├─001 driver │ altera_lib.c │ altera_lib.h │ └─002 gui altera.aps altera.clw altera.cpp altera.dsp altera.dsw altera.h altera.ncb altera.odl altera.opt altera.plg altera.rc Altera.rgs alteraDlg.cpp alteraDlg.h alteralogo.bmp CBox.cpp CBox.h Ioctl.h megaicon.ico Meter.cpp Meter.h MonWnd.cpp MonWnd.h resource.h resource.hm StdAfx.cpp StdAfx.h
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值