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.