Need help to understand WDFCOMMONBUFFER.

Hi,

I am developing PCI driver and I am using DMA for read write.
I am sending data from user application which is PCHAR value.
My question is how to use common buffer to send this buffer to DMA address?
How can I get Physical address of that buffer?

Help Appreciated.
Thank you.

>How can I get Physical address of that buffer?

Not to be overly pedantic, but you don’t WANT the “physical address” of that buffer… you want the LOGICAL address of that buffer. In Windows, we refer to the Logical Address in terms of DMA as the address that can be used to directly program a DMA device on a given device bus to perform a memory transfer. The MAY be a physical address, or it may be something else. What it actually consists of on a given platform is ultimately up to the HAL.

OK, having gotten THAT out of the way… You want to call WdfCommonBufferGetAlignedLogicalAddress.

I thought this was all pretty clearly explained on the doc page for WdfCommonBufferCreate… is there a specific, underlying, question that you have that’s causing you to be confused by the information on that page?

Peter
OSR
@OSRDrivers

Thank you Peter for quick response.

Yes I want logical address.I am sending PUCHAR buffer from application and copying that buffer to WriteCommonBufferBase .
WriteCommonBufferBase = WdfCommonBufferGetAlignedVirtualAddress(DevExt->WriteCommonBuffer);

My question is How I can get logical address so that I can pass it to DMA descriptor.
One more question is How I can identify that DMA transaction is successfully done or not. I am getting DMA interrupt after sending DMA descriptor.

I am getting logical address using
WriteCommonBufferBaseLA = WdfCommonBufferGetAlignedLogicalAddress(DevExt->WriteCommonBuffer);

How can I use this address to send user buffer data to DMA address and read it back on same way.

> How I can identify that DMA transaction is successfully done or not

The answer to this is hardware-specific. You check your hardware, typically from within your ISR.

How can I use this address to send user buffer data to DMA address

That’s also hardware specific. Program your hardware, based on the information in your hardware’s Data Sheet.

Peter
OSR
@OSRDrivers

On 06/20/2018 07:57 AM, xxxxx@gmail.com wrote:

I am getting logical address using
WriteCommonBufferBaseLA = WdfCommonBufferGetAlignedLogicalAddress(DevExt->WriteCommonBuffer);

How can I use this address to send user buffer data to DMA address and read it back on same way.

What, exactly, is your hardware?  Do you actually have a DMA engine in
your hardware?  Some people still think there is a generic “system DMA”
capability, but that’s simply not true.

If you do have a DMA engine, then the documentation for that engine will
tell you the registers you need to program.  You will have to write the
logical address and the length of the transfer, then write some other
register to start the transfer.  The hardware will presumably fire an
interrupt when the transfer is complete.

If your DMA engine has scatter/gather capability, as many engines do,
then you do not need a common buffer at all.  You can have the DMA
engine transfer directly from the user’s buffer.  For this, you would
want to use a WDFDMATRANSACTION.

So, tell us more about your hardware, and we can offer more useful advice.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Thank you Tim and Peter for Advice.

There is a an690 DMA controller.
We have only https://www.altera.com/en_US/pdfs/literature/an/an690.pdf file. No programmer manual for writing driver. But I have Linux reference code through which I am getting help from this.
This is 32bit DMA and I am writing driver for windows10 64bit.

It is accepting descriptor for write operation as follow.
read_address;
write_address = 0x10000;
bytes = size of transfer;
burst;
stride;
read_address_hi;
write_address_hi = 0x0;

From Linux sample code we identified below information.
To get logical address of user buffer

pcietxs_addr = (size_t)0x2000000000ll | (next_att_row * DMA_MAX_ATT_PAGE_SIZE) | (pPhysicalAddr & (PAGE_SIZE - 1));

where pPhysicalAddr = page_to_phys (next_page);
next_att_row = 0;
PAGE_SIZE = 1024;

I want to use this in windows. And I am using WDFCOMMONBUFFER in windows.

> If you do have a DMA engine, then the documentation for that engine will
tell you the registers you need to program.? You will have to write the
logical address and the length of the transfer, then write some other
register to start the transfer.? The hardware will presumably fire an
interrupt when the transfer is complete.

We have second register and length of transfer. We need only logical address. I am using logical address of common buffer which was allocated while DMA initialization.
With this address I am writing “0xAB”(some value) with this address and reading back I am getting “0x00”. So I am assuming that there is a problem while using this logical address.

Note : I am getting interrupt for both read and write.

Thanks,
Kishan Patel

On Jun 20, 2018, at 5:30 PM, xxxxx@gmail.com wrote:
>
> There is a an690 DMA controller.
> We have only https://www.altera.com/en_US/pdfs/literature/an/an690.pdf file. No programmer manual for writing driver. But I have Linux reference code through which I am getting help from this.

This is a reference design. Your company is, no doubt, creating a chip that uses the Intel IP block. It is the responsibility of the group designing the chip to create the programming manual. They are the ONLY people who know what registers to write and how the IP block is connected.

> This is 32bit DMA and I am writing driver for windows10 64bit.

Why do you think it is 32-bit DMA? Do you know what that means? The Intel documentation certainly doesn’t say anything about it. Your code example, however, contradicts this.

By the way, that DMA engine does do scatter/gather. It is not necessary for you to copy your data into a common buffer. You can lock down the buffer with a WDFDMATRANSACTION and have your DMA engine copy directly from that buffer.

> It is accepting descriptor for write operation as follow.
> read_address;
> write_address = 0x10000;
> bytes = size of transfer;
> burst;
> stride;
> read_address_hi;
> write_address_hi = 0x0;

The fact that there is a “read_address_hi” and “write_address_hi” tells me that it is 64-bit DMA.

> From Linux sample code we identified below information.
> To get logical address of user buffer
>
> pcietxs_addr = (size_t)0x2000000000ll | (next_att_row * DMA_MAX_ATT_PAGE_SIZE) | (pPhysicalAddr & (PAGE_SIZE - 1));
>
> where pPhysicalAddr = page_to_phys (next_page);
> next_att_row = 0;
> PAGE_SIZE = 1024;

PAGE_SIZE is not 1024. I guarantee it. PAGE_SIZE is 4096.

> I want to use this in windows.

Windows uses a different philosophy. WdfCommonBufferGetAlignedLogicalAddress already gives you the logical address. You don’t have to do any other machinations. You just need to write it into the device’s register.

>> We have second register and length of transfer. We need only logical address. I am using logical address of common buffer which was allocated while DMA initialization.
> With this address I am writing “0xAB”(some value) with this address and reading back I am getting “0x00”. So I am assuming that there is a problem while using this logical address.

Are you writing all 64-bits of the logical address?

Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

On Jun 20, 2018, at 5:30 PM, xxxxx@gmail.com wrote:
>
>
>> We have second register and length of transfer. We need only logical address. I am using logical address of common buffer which was allocated while DMA initialization.
> With this address I am writing “0xAB”(some value) with this address and reading back I am getting “0x00”.

How large is the buffer you are writing? Most DMA engines have a minimum size.

Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Hi Tom,

Please find inline response.

Why do you think it is 32-bit DMA? Do you know what that means? The Intel
documentation certainly doesn’t say anything about it. Your code example,
however, contradicts this.

On Linux reference code I found those comments. Which is working in linux code.
Due to hardware restrictions, can only do DMA for 32-byte aligned start addresses (on both host and device) AND 32-byte aligned lengths.
Also, need to use a separate descriptor for transfers that do NOT start or end on page boundary. DMA engine does NOT do DMA for these cases, so these transfers are very slow.

PAGE_SIZE is not 1024. I guarantee it. PAGE_SIZE is 4096.
Yes Page size is 4096.

Are you writing all 64-bits of the logical address???
Yes , I am using logical address of common buffer and using following macro to get HI and LO address.

#define HI32(X) ((unsigned int)(((unsigned long long)X)>>32))
#define LO32(X) ((unsigned int)(((unsigned long long)X) & 0x0ffffffffllu))

and assigning values like
read_address = LO32(pcietxs_addr);
write_address = LO32(0x10000);
bytes = 0x400;
burst = 0;
stride = 0x00010001;
read_address_hi = HI32(pcietxs_addr);
write_address_hi = HI32(0x10000);

How large is the buffer you are writing? Most DMA engines have a minimum size.
???
I am writing 1024 bytes from Application and DMA can support upto 256K.

Thanks,
Kishan Patel

Sorry typing mistake. Tim

On Jun 20, 2018, at 11:09 PM, xxxxx@gmail.com wrote:
>
> On Linux reference code I found those comments. Which is working in linux code.
> Due to hardware restrictions, can only do DMA for 32-byte aligned start addresses (on both host and device) AND 32-byte aligned lengths.

That’s not unheard of, but I didn’t see that in the Intel documentation. Have you proven that this restriction is real?

> Also, need to use a separate descriptor for transfers that do NOT start or end on page boundary. DMA engine does NOT do DMA for these cases, so these transfers are very slow.

If the chip is doing the transfers, then it is doing DMA. The definition of PCI DMA is bus transfers being done by the device. There are no special “DMA cycles” in PCI.

>> Are you writing all 64-bits of the logical address???
> Yes , I am using logical address of common buffer and using following macro to get HI and LO address.
>
> #define HI32(X) ((unsigned int)(((unsigned long long)X)>>32))
> #define LO32(X) ((unsigned int)(((unsigned long long)X) & 0x0ffffffffllu))

You don’t have to do that macro/cast crap on Windows. WdfCommonBufferGetAlignedLogicalAddress returns a PHYSICAL_ADDRESS, which has LowPart and HighPart elements.

Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

>That’s not unheard of, but I didn’t see that in the Intel documentation. Have
you proven that this restriction is real?

No not proven, Same for me. I did not have document. I have reference of that code only which is running in Linux.

In write sequence what i am doing is,

//Getting user buffer and copy user buffer data to common buffer
virtualAddress = MmGetMdlVirtualAddress(mdl);
length = MmGetMdlByteCount(mdl);
RtlCopyBytes(WriteCommonBufferBase, virtualAddress, Length);

After this, Initialize DMA transaction using WdfDmaTransactionInitialize. In DMA transaction EvtProgramDmaFunction callback I am writing Logical address (LOW Part + High Part)to CRA register and sending descriptor as follows.

read_address = WriteCommonBufferBaseLA .LowPart;
write_address = LO32(0x10000);
bytes = 0x400;
burst = 0;
stride = 0x00010001;
read_address_hi = WriteCommonBufferBaseLA.HighPart;
write_address_hi = HI32(0x10000);

Is it correct method ?

On Jun 21, 2018, at 12:17 AM, xxxxx@gmail.com wrote:
>
> In write sequence what i am doing is,
>
> //Getting user buffer and copy user buffer data to common buffer
> virtualAddress = MmGetMdlVirtualAddress(mdl);
> length = MmGetMdlByteCount(mdl);
> RtlCopyBytes(WriteCommonBufferBase, virtualAddress, Length);
>
> After this, Initialize DMA transaction using WdfDmaTransactionInitialize. In DMA transaction EvtProgramDmaFunction callback I am writing Logical address (LOW Part + High Part)to CRA register and sending descriptor as follows.

If you are using a common buffer, you do not need a WDFDMATRANSACTION object at all. You already have the virtual and logical address. You don’t need any more mapping to be done.

Because the hardware supports scatter/gather, you might consider copying directly from the user’s MDL instead of copying to a common buffer. For that, you would need a WDMDMATRANSACTION.

> read_address = WriteCommonBufferBaseLA .LowPart;
> write_address = LO32(0x10000);
> bytes = 0x400;
> burst = 0;
> stride = 0x00010001;
> read_address_hi = WriteCommonBufferBaseLA.HighPart;
> write_address_hi = HI32(0x10000);
>
> Is it correct method ?

That’s the correct way to set the read_address. I don’t know what “burst” and “stride” are doing. Note that, somewhere, you need to tell the hardware that you are reading from system memory and writing to onboard memory.

Is this setting up for a one-time transfer, or is this a descriptor you are loading another way? The documentation implied that all transfers were done through a descriptor list.

Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Hi Tim,

If you are using a common buffer, you do not need a WDFDMATRANSACTION object at
all. You already have the virtual and logical address. You don’t need any more
mapping to be done.

Ok, You means If I am not using scatter-gather method I simply can send descriptor without WDFDMATRANSACTION object.

Can you help me to understand following ?
1 )If I send data from application than how it will be filled in WriteCommonBufferBase?

If I print data without
virtualAddress = MmGetMdlVirtualAddress(mdl);
length = MmGetMdlByteCount(mdl);
RtlCopyBytes(WriteCommonBufferBase, virtualAddress, Length);

I am getting 0 value. If I fill this I believe logical address will send same data what I filled in WriteCommonBufferBase.

When I tried to read using same I am getting 0 value.

somewhere, you need to tell the hardware that you are reading from system memory and writing to onboard memory.

In read Method :
I am swapping address Like,
read_address = LO32(0x10000);
write_address = ReadCommonBufferBaseLA .LowPart;
bytes = 0x400;
burst = 0;
stride = 0x00010001;
read_address_hi = HI32(0x10000);
write_address_hi = ReadCommonBufferBaseLA.HighPart;

Query is that am I sending data in correct manner ? Or something needs to be done with Logical address.

Is this setting up for a one-time transfer, or is this a descriptor you are
loading another way?
One time transfer upto the buffer length. I am loading same way as I mensioned.

The documentation implied that all transfers were done
through a descriptor list.
In documentation I refered using descriptor method only.

xxxxx@gmail.com wrote:

Ok, You means If I am not using scatter-gather method I simply can send descriptor without WDFDMATRANSACTION object.

Yes.  The WDFDMATRANSACTION  serves two purposes: it serializes DMA
transactions, so you only do one at a time, and it hands you the logical
address of the buffer.  If you already have the logical address, as you
do with a common buffer, then you don’t need a transaction.

Can you help me to understand following ?
1 )If I send data from application than how it will be filled in WriteCommonBufferBase?

You would not use a common buffer.  You are getting a WDFREQUEST from
your user, correct?  You would use
WdfDmaTransactionInitializeUsingRequest.  That will do everything that
needs to be done.  It locks down the user’s buffer so it can’t be
deleted, it creates an MDL, and it maps that MDL into logical address
space, and it hands the scatter/gather list to your DMA callback.

If I print data without
virtualAddress = MmGetMdlVirtualAddress(mdl);
length = MmGetMdlByteCount(mdl);
RtlCopyBytes(WriteCommonBufferBase, virtualAddress, Length);

I am getting 0 value. If I fill this I believe logical address will send same data what I filled in WriteCommonBufferBase.
When I tried to read using same I am getting 0 value.

I can’t tell what you’re asking here.

> somewhere, you need to tell the hardware that you are reading from system memory and writing to onboard memory.
In read Method :
I am swapping address Like,
read_address = LO32(0x10000);
write_address = ReadCommonBufferBaseLA .LowPart;
bytes = 0x400;
burst = 0;
stride = 0x00010001;
read_address_hi = HI32(0x10000);
write_address_hi = ReadCommonBufferBaseLA.HighPart;

But that’s not enough.  Given that information, how can I (or the
hardware) possibly know which of those two addresses is a system memory
address, and which is an onboard memory address?  Somehow, you have to
tell the hardware whether this is a “system-to-board” transfer or a
“board-to-system” transfer

In documentation I refered using descriptor method only.

So, in the pseudo-code you show above, you are actually creating a
descriptor.  Somehow, you then have to tell the hardware where to find
the descriptors.  That, also, has to be a logical/physical address.  Are
you putting these descriptors in your common buffer as well?  Otherwise,
how do you get the logical address of the descriptor?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Hi Tim,

Please find attached document.
http://www.i6.in.tum.de/pub/Main/Hub/Communication.pdf
On Page 23-24 mentioned how to create DMA descriptor and DMA operation. We are following same. I am in doubt How we can use it in our case.

pcietxs_addr = (size_t) ACL_PCIE_TX_PORT
| (att_row * ACL_PCIE_DMA_MAX_ATT_PAGE_SIZE)
| (physical_addr & (ACL_PCIE_DMA_MAX_ATT_PAGE_SIZE - 1));

in Linux they implemented physical_addr as follow.

=>To send descriptor they are using

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Prepare Descriptor

#define HI32(X) ((unsigned int)(((unsigned long long)X)>>32))
#define LO32(X) ((unsigned int)(((unsigned long long)X) & 0x0ffffffffllu))
size_t pcietxs_addr = (size_t)ACL_PCIE_TX_PORT | (d->m_next_att_row * ACL_PCIE_DMA_MAX_ATT_PAGE_SIZE) | (pPhysicalAddr & (PAGE_SIZE - 1));
size_t gmem_addr = (size_t)d->m_device_addr + d->m_bytes_sent;

d->m_active_descriptor.read_address = d->m_read ? LO32(gmem_addr) : LO32(pcietxs_addr);
d->m_active_descriptor.write_address = d->m_read ? LO32(pcietxs_addr) : LO32(gmem_addr);
d->m_active_descriptor.bytes = 0; // Updated below
d->m_active_descriptor.burst = 0;
d->m_active_descriptor.stride = 0x00010001;
d->m_active_descriptor.read_address_hi = d->m_read ? HI32(gmem_addr) : HI32(pcietxs_addr);
d->m_active_descriptor.write_address_hi = d->m_read ? HI32(pcietxs_addr) : HI32(gmem_addr);
d->m_active_descriptor_size = 0;
d->m_active_descriptor_valid = true;
#undef HI32
#undef LO32
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

Write Descriptor

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
writel(u.desc.read_address, dev_addr);
writel(u.desc.write_address, dev_addr + sizeof(u32));
writel(u.desc.bytes, dev_addr + 2*sizeof(u32));
writew((u16) u.desc.burst, dev_addr + 3*sizeof(u32));
writeb((u8)(u.desc.burst >> 16), dev_addr + 3*sizeof(u32) + sizeof(u16));
writeb((u8)(u.desc.burst >> 24), dev_addr + 3*sizeof(u32) + sizeof(u16) + sizeof(u8));
writew((u16) u.desc.stride, dev_addr + 4*sizeof(u32));
writew((u16)(u.desc.stride >> 16), dev_addr + 4*sizeof(u32) + sizeof(u16));
writel(u.desc.read_address_hi, dev_addr + 5*sizeof(u32));
writel(u.desc.write_address_hi, dev_addr + 6*sizeof(u32));
writel(u.desc.control, dev_addr + 7*sizeof(u32));
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

In WIndows :

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
In our case I am using WDF common buffer’s logical address.

pcietxs_addr = (size_t) ACL_PCIE_TX_PORT | ((buffer.LowPart | buffer.HighPart) & (PAGE_SIZE -1))
gmem_addr = 0x10000
read_address = LO32(pcietxs_addr);
write_address = LO32(gmem_addr);
bytes = 0x400;
burst = 0;
stride = 0x00010001;
read_address_hi = HI32(pcietxs_addr);
write_address_hi = HI32(gmem_addr);

WRITE_REGISTER_ULONG(dev_add, read_address);

//Write to wadd
PVOID write_add = (PUCHAR)dev_add + sizeof(ULONG);
WRITE_REGISTER_ULONG(write_add, (ULONG)write_address);

//Write Bytes
PVOID byteadd = (PUCHAR)dev_add + (2 * sizeof(ULONG));
WRITE_REGISTER_ULONG(byteadd, bytes);

//Write burst
PVOID burstadd = (PUCHAR)dev_add + (3 * sizeof(ULONG));
WRITE_REGISTER_USHORT(burstadd, (USHORT)burst);
PVOID burstadd1 = (PUCHAR)dev_add + (3 * sizeof(ULONG)) + sizeof(USHORT);
WRITE_REGISTER_UCHAR(burstadd1, (UCHAR)(burst >> 16));
PVOID burstadd2 = (PUCHAR)dev_add + (3 * sizeof(ULONG)) + sizeof(USHORT) + sizeof(UCHAR);
WRITE_REGISTER_UCHAR(burstadd2, (UCHAR)(burst >> 24));

//Write Stride
PVOID stadd = (PUCHAR)dev_add + 4 * sizeof(ULONG);
WRITE_REGISTER_USHORT(stadd, (USHORT)stride);
PVOID stadd1 = (PUCHAR)dev_add + 4 * sizeof(ULONG) + sizeof(USHORT);
WRITE_REGISTER_USHORT(stadd1, (stride >> 16));

//Write readadd_hi
PVOID rhI = (PUCHAR)dev_add + 5 * sizeof(ULONG);
WRITE_REGISTER_ULONG(rhI, read_address_hi);

//Write Add hi
PVOID whI = (PUCHAR)dev_add + 6 * sizeof(ULONG);
WRITE_REGISTER_ULONG(whI, write_address_hi);

//COntrol
PVOID cntlreg = (PUCHAR)dev_add + 7 * sizeof(ULONG);
WRITE_REGISTER_ULONG(cntlreg, control);

Am i doing anything wrong in that?

xxxxx@gmail.com wrote:

Please find attached document.
http://www.i6.in.tum.de/pub/Main/Hub/Communication.pdf
On Page 23-24 mentioned how to create DMA descriptor and DMA operation. We are following same. I am in doubt How we can use it in our case.

This is NOT the PCIe core you talked about earlier.  This is an Altera
PCIe core (and a strange one, at that).  Earlier, you said you were
using an Intel PCIe core.

You need to tell us exactly what you are doing.  What is the hardware? 
What are you building?  Which FPGA, and which PCIe core?  Who is doing
the FPGA work?

pcietxs_addr = (size_t) ACL_PCIE_TX_PORT
| (att_row * ACL_PCIE_DMA_MAX_ATT_PAGE_SIZE)
| (physical_addr & (ACL_PCIE_DMA_MAX_ATT_PAGE_SIZE - 1));

You omitted a very important line in this quote: this variable is
declared as “unsigned long”.  This is why it is so dangerous to try to
port code from another operating system without understanding the
differences.  In a 64-bit Linux system, “unsigned long” is a 64-bit
type.  In Windows, “unsigned long” is always a 32-bit type. 
ACL_PCIE_TX_PORT is 0x200000000, which is larger than 32-bits, so that
value is going to be truncated.  Without the high-order bits, the engine
will never access system memory.

And did you read the description of this DMA engine?  They don’t use the
actual physical addresses here.  This PCIe core has an “address
translation table,” where you store all of the physical addresses you
will be using.  The “att_row” value there is the entry number within
that translation table. You must previously have written the matching
physical address into the ATT.

In WIndows :
In our case I am using WDF common buffer’s logical address.

pcietxs_addr = (size_t) ACL_PCIE_TX_PORT | ((buffer.LowPart | buffer.HighPart) & (PAGE_SIZE -1))

For gosh sakes, you can’t just “or” the LowPart and HighPart together! 
What did you think that was going to do?  Do you not understand how the
PHYSICAL_ADDRESS structure works?  To make a physical address, the
HighPart has to be shifted up by 32 bits.  If you need to refer to the
whole 64-bit address, you use buffer.QuadPart.  However, in this case,
you don’t need to do that, because you’re only keeping the low-order 12
bits.  Just use LowPart.

However, this is missing the “address translation table” row number. 
Did you write the physical address into the ATT?

How did you define pcietxs_addr?  It has to be large enough to hold a
64-bit value.  Note that this code will not work in a 32-bit system,
because “size_t” is a 32-bit type in that case, and ACL_PCIE_TX_PORT is
larger than 32 bits.

gmem_addr = 0x10000
read_address = LO32(pcietxs_addr);
write_address = LO32(gmem_addr);
bytes = 0x400;
burst = 0;
stride = 0x00010001;
read_address_hi = HI32(pcietxs_addr);
write_address_hi = HI32(gmem_addr);

WRITE_REGISTER_ULONG(dev_add, read_address);

//Write to wadd
PVOID write_add = (PUCHAR)dev_add + sizeof(ULONG);
WRITE_REGISTER_ULONG(write_add, (ULONG)write_address);

//Write Bytes
PVOID byteadd = (PUCHAR)dev_add + (2 * sizeof(ULONG));
WRITE_REGISTER_ULONG(byteadd, bytes);

//Write burst
PVOID burstadd = (PUCHAR)dev_add + (3 * sizeof(ULONG));
WRITE_REGISTER_USHORT(burstadd, (USHORT)burst);
PVOID burstadd1 = (PUCHAR)dev_add + (3 * sizeof(ULONG)) + sizeof(USHORT);
WRITE_REGISTER_UCHAR(burstadd1, (UCHAR)(burst >> 16));
PVOID burstadd2 = (PUCHAR)dev_add + (3 * sizeof(ULONG)) + sizeof(USHORT) + sizeof(UCHAR);
WRITE_REGISTER_UCHAR(burstadd2, (UCHAR)(burst >> 24));

//Write Stride
PVOID stadd = (PUCHAR)dev_add + 4 * sizeof(ULONG);
WRITE_REGISTER_USHORT(stadd, (USHORT)stride);
PVOID stadd1 = (PUCHAR)dev_add + 4 * sizeof(ULONG) + sizeof(USHORT);
WRITE_REGISTER_USHORT(stadd1, (stride >> 16));

//Write readadd_hi
PVOID rhI = (PUCHAR)dev_add + 5 * sizeof(ULONG);
WRITE_REGISTER_ULONG(rhI, read_address_hi);

//Write Add hi
PVOID whI = (PUCHAR)dev_add + 6 * sizeof(ULONG);
WRITE_REGISTER_ULONG(whI, write_address_hi);

//COntrol
PVOID cntlreg = (PUCHAR)dev_add + 7 * sizeof(ULONG);
WRITE_REGISTER_ULONG(cntlreg, control);

Am i doing anything wrong in that?

Many things.  You don’t need to create a new variable for each address
computation.  You don’t need to write the shorts and bytes individually;
that’s just silly and error-prone.  Further, you shouldn’t really be
doing the address computations like that anyway; just declare a
structure that matches the hardware, and then you can use
WRITE_REGISTER_BUFFER_ULONG to copy the whole thing.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Thank you tim it helped me a lot. Now I am able to get data using common buffer. I changed pcietxs_addr to ULONG64 and used lower part of common buffer to get/set data and added lowerpart entry in ATT. and it worked fine for me. Thanks a lot for your great support.

Br,
Kishan Patel,