WDF DMA 一些概念(一)

cache一致性

On machines or bus configurations inwhich the hardware does not ensure cache coherence for DMA operations—such ascertain Intel Itanium systems—the standard Windows DMA implementation does theprocess-specific
work that is necessary to ensure such coherency when the driver calls WdfDmaTransactionExecute.

The framework flushes this cache when the driver callsWdfDmaTransactionDmaCompleted.

Map寄存器

在系统地址空间和物理地址空间 翻译地址。类似于页表项和页目录项用于物理地址和虚拟地址之间的转换一样。每个map寄存器可以转换高达4KB的地址。Map寄存器是一种共享资源。系统根据创建DMA enable 对象时的最大传输长度reserves map寄存器。

框架会在执行transaction事务前立即分配map registers,在transaction完成后释放。一旦DMA设备的驱动程序从或者向系统内存拷贝数据,框架会动态分配 以及编程map registers.

Number of Required Map Registers =(Transfer Size / PAGE_SIZE) + 1

加1是针对一次传输的起始地址不是页对齐地址。map registers被分配在一个连续的块中。Windows操作系统将一块map registers (基地址和长度)给框架。其值 KMDF驱动无法获知。

举个例子:

PLX9x5x的驱动中在初始化设备扩展结构中有如下代码:

NTSTATUS
PLxInitializeDeviceExtension(
    IN PDEVICE_EXTENSION DevExt
    )
/*++
Routine Description:

    This routine is called by EvtDeviceAdd. Here the device context is
    initialized and all the software resources required by the device is
    allocated.

Arguments:

    DevExt     Pointer to the Device Extension

Return Value:

     NTSTATUS

--*/
{
    NTSTATUS    status;
    ULONG       dteCount;
    WDF_IO_QUEUE_CONFIG  queueConfig;

    PAGED_CODE();

    //
    // Set Maximum Transfer Length (which must be less than the SRAM size).
    //
    DevExt->MaximumTransferLength = PCI9656_MAXIMUM_TRANSFER_LENGTH;
    if(DevExt->MaximumTransferLength > PCI9656_SRAM_SIZE) {
        DevExt->MaximumTransferLength = PCI9656_SRAM_SIZE;
    }

	KdPrint((
                "MaximumTransferLength %d\n", DevExt->MaximumTransferLength));

    //
    // Calculate the number of DMA_TRANSFER_ELEMENTS + 1 needed to
    // support the MaximumTransferLength.
    //
    dteCount = BYTES_TO_PAGES((ULONG) ROUND_TO_PAGES(
        DevExt->MaximumTransferLength) + PAGE_SIZE);

    KdPrint((  "Number of DTEs %d\n", dteCount));

    //
    // Set the number of DMA_TRANSFER_ELEMENTs (DTE) to be available.
    //
    DevExt->WriteTransferElements = dteCount;
    DevExt->ReadTransferElements  = dteCount;
}

有用硬件实现的,也有用软件实现的。

什么时候用map registers? 满足下列任一项

1 设备不支持S/G

2 buffer已经超越了设备的寻址能力,如只支持32位传输,但是却要传到高4GB的物理地址空间,系统会使用map registers.

SG的实现

在初始化过程中,如果设备不支持硬件SG,Windows DMA 使用map registers.

1 Windows DMA分配足够连续的map registers,即low-memory 缓冲区,包含整个传输的数据;

2 对一个写操作来说,从系统内存到设备,数据从原有的数据缓冲区到map registers缓冲区。

3 WIndows DMA 给框架提供map registers的物理内存地址 作为 缓冲区在设备总线地址空间的地址。

然后 框架吧sg list的地址传送给驱动程序,当调用驱动的EvtProgramDma 回调函数时。

BOOLEAN
PLxEvtProgramWriteDma(
    IN  WDFDMATRANSACTION       Transaction,
    IN  WDFDEVICE               Device,
    IN  PVOID                   Context,
    IN  WDF_DMA_DIRECTION       Direction,
    IN  PSCATTER_GATHER_LIST    SgList
    )
/*++

Routine Description:

Arguments:

Return Value:

--*/
{
    PDEVICE_EXTENSION        devExt;
    size_t                   offset;
    PDMA_TRANSFER_ELEMENT    dteVA;
    ULONG_PTR                dteLA;
    BOOLEAN                  errors;
    ULONG                    i;

    UNREFERENCED_PARAMETER( Context );
    UNREFERENCED_PARAMETER( Direction );

	KdPrint(("--> PLxEvtProgramWriteDma\n"))
                ;

    //
    // Initialize locals
    //
    devExt = PLxGetDeviceContext(Device);
    errors = FALSE;

    //
    // Get the number of bytes as the offset to the beginning of this
    // Dma operations transfer location in the buffer.
    //
    offset = WdfDmaTransactionGetBytesTransferred(Transaction);
	KdPrint(("offset is %d\n",offset));
    //
    // Setup the pointer to the next DMA_TRANSFER_ELEMENT
    // for both virtual and physical address references.
    //
    dteVA = (PDMA_TRANSFER_ELEMENT) devExt->WriteCommonBufferBase;
    dteLA = (devExt->WriteCommonBufferBaseLA.LowPart +
                        sizeof(DMA_TRANSFER_ELEMENT));

    //
    // Translate the System's SCATTER_GATHER_LIST elements
    // into the device's DMA_TRANSFER_ELEMENT elements.
    //
    for (i=0; i < SgList->NumberOfElements; i++) {

        //
        // Construct this DTE.
        //
        // NOTE: The LocalAddress is the offset into the SRAM from
        //       where this Write will start.
        //
        dteVA->PciAddressLow  = SgList->Elements[i].Address.LowPart;
        dteVA->PciAddressHigh = SgList->Elements[i].Address.HighPart;
        dteVA->TransferSize   = SgList->Elements[i].Length;

        dteVA->LocalAddress   = (ULONG) offset;

        dteVA->DescPtr.DescLocation  = DESC_PTR_DESC_LOCATION__PCI;
        dteVA->DescPtr.TermCountInt  = FALSE;
        dteVA->DescPtr.LastElement   = FALSE;
        dteVA->DescPtr.DirOfTransfer = DESC_PTR_DIRECTION__TO_DEVICE;
        dteVA->DescPtr.Address       = DESC_PTR_ADDR( dteLA );

        //
        // Increment the DmaTransaction length by this element length
        //
        offset += SgList->Elements[i].Length;

        //
        // If at end of SgList, then set LastElement bit in final NTE.
        //
        if (i == SgList->NumberOfElements - 1) {

            dteVA->DescPtr.LastElement = TRUE;
}
}

因为 缓冲区是物理连续的,所以SG表只有一个元素,基地址和长度。

驱动使用该长度和地址,其实不是真实的数据缓冲区片段的地址编程DMA。因为map register buffers 在低4GB 物理地址空间,所以该buffers可以被任何

总线主控DMA设备寻址到。

当驱动程序通知框架DMA传输已经完成,框架转而通知standard Windows DMA实现层,

map register可以使具有有限寻址能力的设备访问到任一内存位置。

时间: 2024-10-24 04:47:05

WDF DMA 一些概念(一)的相关文章

PCI/PCIe接口卡Windows驱动程序(2)-开发者需要了解的WDF中的一些重要的概念

本科毕业设计是这方面的工作,所以想开几篇博客来介绍使用WDF开发PCI/PCIe接口卡的驱动程序方法. 在上一篇简要介绍了WDF和开发环境搭建后,本篇将讲述几个WDF中的概念,对开发者了解WDF非常有帮助,属于“内功部分”: 本篇文章结构将没那么清晰,当句句都是作者通过看书.看论文.看MSDN提炼出来的,希望对读者能够有所帮助. 1.WinDBG是唯一的内核驱动调试利器,但是开发PCIe的WDF驱动可以采用“黑盒”方式,所以windbg不是必须的: 2.WDF比WDM好,别再用WDM了: 3.驱

Linux驱动开发(二)—DMA的使用(一)

1 DMA概念 DMA顾名思义就是指设备和内存之间.内存和外部存储设备之间进行直接的数据读写操作,而不需要CPU的参与. 2 DMA原理 DMA传输需要由DMA控制器DMAC进行,当需要进行DMA传输的时候,DMA控制器会发出占用总线的请求,当CPU响应DMA的请求时,暂时放弃对总线的控制权,当DMA传输结束的时候,DMAC会向I/O接口发出结束命令,并将总线控制权交还给CPU.一个完整的DMA传输过程必须经过DMA请求.DMA响应.DMA传输.DMA结束4个步骤. 3 DMA传输过程 4 DM

STM32 DMA使用详解

DMA部分我用到的相对简单,当然,可能这是新东西,我暂时还用不到它的复杂功能吧.下面用问答的形式表达我的思路. DMA有什么用? 直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输.无须CPU的干预,通过DMA数据可以快速地移动.这就节省了CPU的资源来做其他操作. 有多少个DMA资源? 有两个DMA控制器,DMA1有7个通道,DMA2有5个通道. 数据从什么地方送到什么地方? 外设到SRAM(I2C/UART等获取数据并送入SRAM): SRAM的两个区域之间: 外设

PCI总线 DMA burst 基本概念

转载地址:http://blog.csdn.net/sunjiajiang/article/details/7945057 DMA和burst不是一个概念. DMA传送不经过CPU的控制,假如硬盘的数据不能经过DMA控制器读到内存,那么每完成一次将硬盘的数据读出来,再存放到内存的操作,都要通过CPU运行几条读写指令来完成,这时CPU就做不了别的事了,如果有DMA控制器,则这个过程不需要CPU的参与,只需要占用总线就可以了.CPU还可以去完成别的运算. Burst操作还是要通过CPU的参与的,与单

DMA的基本概念

DMA允许外围设备和主内存之间直接传输 I/O 数据, DMA 依赖于系统.每一种体系结构DMA传输不同,编程接口也不同. 数据传输可以以两种方式触发:一种软件请求数据,另一种由硬件异步传输. 在第一种情况下,调用的步骤可以概括如下(以read为例): (1)在进程调用 read 时,驱动程序的方法分配一个 DMA 缓冲区,随后指示硬件传送它的数据.进程进入睡眠. (2)硬件将数据写入 DMA 缓冲区并在完成时产生一个中断. (3)中断处理程序获得输入数据,应答中断,最后唤醒进程,该进程现在可以

计算机基本概念

计算机基本概念 一.计算机系统 计算机系统的基本组成: 在计算机内部,数值.文字.声音.图形图像等各种信息都必须经过数字化编码后才能被传送.储存和处理:数值.文字和英文字母等都被认为是字符,任何字符进入计算机时,都必须转换成二进制表示形式,称为字符编码. 总线是连接多个设备的信息传送通道,实际上是一组信号线.广义地讲,任何连接两个以上电子元器件都可以称为总线,总线主要分为系统总线(内总线)和通信总线(外总线). 内总线:用于计算机各组成部分,CPU.内存和接口等的连接:PCI总线是目前微型机上广

多线程和进程的概念

1.耗时的操作使用线程,提高应用程序响应 2.并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求. 3.多CPU系统中,使用线程提高CPU利用率 4.改善程序结构.一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改. 使用多线程的理由之一是和进程相比,它是一种非常花销小,切换快,更"节俭"的多任务操作方式.在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段.堆栈段和数据段,这是

Java NIO 之一 I/O基本概念

缓冲区操作 缓冲区,以及缓冲区如何工作,是所有 I/O 的基础.所谓"输入/输出"讲的无非就是把数据移进或移出缓冲区.进程执行 I/O 操作,归结起来,也就是向操作系统发出请求,让它要么把缓冲区里的数据排干(写),要么用数据把缓冲区填满(读). 进程使用 read( )系统调用,要求其缓冲区被填满.内核随即向磁盘控制硬件发出命令,要求其从磁盘读取数据.磁盘控制器把数据直接写入内核内存缓冲区,这一步通过 DMA 完成,无需主 CPU 协助.一旦磁盘控制器把缓冲区装满,内核即把数据从内核空

基于WDF的PCI/PCIe接口卡Windows驱动程序(5)-如何为硬件移植驱动程序

原文地址:http://www.cnblogs.com/jacklu/p/6139347.html 正如前几篇博客所说,使用WDF开发PCIe驱动程序是我本科毕业设计的主要工作.在读研的两年,我也分别为所在课题组移植了自己编写的驱动程序,在Windows 32位和64位平台下的PXI.PXIe.PCI.PCIe板卡分别得到了验证. 这篇文章根据自己最新编写的驱动代码(源代码请找博主索取),主要讲述如何为自己的硬件板卡移植驱动程序,并简单讲述如何使用Altera系列FPGA配置PCI IP核,然后