DMA Troubles

Hi,
I am trying to get DMA working with a PPC8245 processor, on a Sandpoint
PPC8245 eval system. I think I am doing all the right steps to get this
working, but apparently I am missing something. According to the PPC manual
(sect 8-5) I need to do the following:

page 8-5 in the MPC88245 Processor Users Manual
For DMA Direct Mode:

  1. Poll the DSR[CB] bit to ensure DMA channel is idle
  2. Init SAR, DAR, BCR registers
  3. Init the CTT bit in the CDAR to indicate transfer type
  4. Init the CTM bit in the DMR to indicate Direct Mode
  5. Clear and set the DMR[CS] bit to start the XFR

I think I am setting everything correctly, but I find that it always boils
down to operator error. So is there something else I need to do, or may be
the better question is what am I doing wrong?

I included my DMA setup/transfer code for reference, but from reading things
on the net I suspect that the problem does not lie in the setup of the DMA
(shown below), but actually lies in the placement of the information in the
buffers. The source and destination addresses for the buffers being passed
into the function below are just character buffers, they are not protected,
or DMA safe, or whatever they need to be.

There are a lot of articles on google groups referencing a document called
shmem.txt somewhere on the ftp.qnx.com site. Where exactly can I find this
document or example code on setting up DMA safe memory and how to actually
perform the DMA transfer.

Thanks in advance,
Mike

P.S. In case you could not tell, this is my first try at DMA transfers -
Thanks

The following function should setup and initiate a DMA transfer

//global variable this is mmap(ed)
//in another function to location 0x8000000
//of total length 0x1000
volatile unsigned int *DMAChannel;

int DoDMATransfer(unsigned char *sourceAddr, unsigned char *destAddr, int
xfrBytes)
{
//the DMA Base address (DMAChannel) is set to 0x80001000

printf(“The sourceAddr is %x\n”, sourceAddr);
printf(“The destAddr is %x\n”, destAddr);
printf(“The xfrBytes are %x\n”, xfrBytes);

/*
page 8-5 in the MPC88245 Processor Users Manual
For DMA Direct Mode:

  1. Poll the DSR[CB] bit to ensure DMA channel is idle
  2. Init SAR, DAR, BCR registers
  3. Init the CTT bit in the CDAR to indicate transfer type
  4. Init the CTM bit in the DMR to indicate Direct Mode
  5. Clear and set the DMR[CS] bit to start the XFR
    */

//1) Poll the DSR[CB] bit to ensure DMA channel is idle
if((DMAChannel[DMA0_DSR] & 0x4) == 0)
{
printf(“DmaChannel 0 is inactive and can be used\n”);

//set up the starting & ending transfer addresses
//and the data transfer size
//2) Init SAR, DAR, BCR registers
DMAChannel[DMA0_SAR] = (int) sourceAddr; //0x110 + base
DMAChannel[DMA0_DAR] = (int)destAddr; //0x118 + base
DMAChannel[DMA0_BCR] = xfrBytes; //0x120 + base
//re-read the stored data
printf(“The DMA0_SAR is %x\n”, DMAChannel[DMA0_SAR]);
printf(“The DMA0_DAR is %x\n”, DMAChannel[DMA0_DAR]);
printf(“The DMA0_BCR is %x\n”, DMAChannel[DMA0_BCR]);

//3) Init the CTT bit in the CDAR to indicate transfer type
//in this case we want a local memory transfer or bits 1 & 2 to == 0
DMAChannel[DMA0_CDAR] = DMAChannel[DMA0_CDAR] & 0xF9; //0x108 + base
printf(“The DMA0_CDAR is %x\n”, DMAChannel[DMA0_CDAR]);

//4) Init the CTM bit in the DMR to indicate Direct Mode
//see the current state of the DMR = 0
printf(“The DMA0_DMR is %d\n”, DMAChannel[DMA0_DMR]);
//turn on bit 2 (Chanel Transfer Mode) of the DMR indicate a direct mode
transfer
DMAChannel[DMA0_DMR] = DMAChannel[DMA0_DMR] | 0x4; //0x100 + base
//(DMR now = 4)
printf(“The DMA0_DMR was changed to %d\n”, DMAChannel[DMA0_DMR]);

//5) Clear and set the DMR[CS] bit to start the XFR
printf(“The DMA0_DMR is %d\n”,DMAChannel[DMA0_DMR]);
DMAChannel[DMA0_DMR] = DMAChannel[DMA0_DMR] & 0xFE;
//(DMR = 4)
printf(“The DMA0_DMR was changed to %d\n”, DMAChannel[DMA0_DMR]);

//set bit 0 (Chanel Start) of the the DMA regs
DMAChannel[DMA0_DMR] = DMAChannel[DMA0_DMR] | 0x01;
//(DMR now = 5)
printf(“The DMA0_DMR was changed to %d\n”, DMAChannel[DMA0_DMR]);

sleep(1);
//check the status register to see if any errors
//(none ever reported)
printf(“The DMA0_DSR is %x\n”, DMAChannel[DMA0_DSR]);
}
return(0);
}

Mike Toreno <no.spam@address.com> wrote:

I included my DMA setup/transfer code for reference, but from reading things
on the net I suspect that the problem does not lie in the setup of the DMA
(shown below), but actually lies in the placement of the information in the
buffers. The source and destination addresses for the buffers being passed
into the function below are just character buffers, they are not protected,
or DMA safe, or whatever they need to be.

That sounds like the most likely problem.

From the docs to mmap:

/* Allocate a physically contiguous buffer */
addr = mmap( 0,
size_of_buf,
PROT_READ|PROT_WRITE|PROT_NOCACHE,
MAP_PHYS|MAP_ANON,
NOFD,
0 );

Is a sample of allocating DMA safe memory.

You would then want to use mem_offset() to get the physical address
of this buffer, and probably pass the physical address to the DMA
controller, rather than a virtual address.

There are a lot of articles on google groups referencing a document called
shmem.txt somewhere on the ftp.qnx.com site. Where exactly can I find this
document or example code on setting up DMA safe memory and how to actually
perform the DMA transfer.

shmem.txt was for QNX4.2x on x86, where doing things was far more arcane
than under QNX 6.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

Thanks Dave, I changed my buffers to a mmap(ed)/DMA safe buffers, and used
the mem_offset to get the address to pass to the PPC DMA engine. However I
am getting the same results as before. The destination buffer after the
“supposed” transfer is empty.

This leads me to believe that the DMA channel may not really be getting set
with the correct parameters,which leads me to another question of mmap VS
mmap_device_memory.

I am a bit confused, even after reading the docs, but let me give the
explanation a stab. mmap is used to map out a region of my local memory into
my local memory, such as for a DMA safe bufer. While mmap_device_memory is
used to map another devices memory/registers into my local memory. Is this
somewhat correct?

Currently I am using mmap to map the PPC DMA registers into memory, should I
be using mmap_device_memory?

Thanks,
Mike

Hi Mike,

“Mike Toreno” <no.spam@address.com> wrote in message
news:aa6p2e$k9l$1@nntp.qnx.com

Thanks Dave, I changed my buffers to a mmap(ed)/DMA safe buffers, and used
the mem_offset to get the address to pass to the PPC DMA engine. However
I
am getting the same results as before. The destination buffer after the
“supposed” transfer is empty.

The physical address of memory returned from mem_offset is not sufficient
for DMA to work on PPC. We couldn’t get our DMA working until we were told
that we needed to modify the physical address to turn it into a PCI address.

Add the CpuBmstrTranslation value from the pci_dev_info structure (in
hw/pci.h) to your physical address. That should give you the address that
you need.

This leads me to believe that the DMA channel may not really be getting
set
with the correct parameters,which leads me to another question of mmap VS
mmap_device_memory.

I am a bit confused, even after reading the docs, but let me give the
explanation a stab. mmap is used to map out a region of my local memory
into
my local memory, such as for a DMA safe bufer. While mmap_device_memory is
used to map another devices memory/registers into my local memory. Is this
somewhat correct?

Currently I am using mmap to map the PPC DMA registers into memory, should
I
be using mmap_device_memory?

Thanks,
Mike

Later,
Wayne

Wayne,

Thanks for the info, but I am not sure how to get the CpuBmstrTranslation
value from the pci_dev_info struc. The only way I see that this can be done
is by using the call pci_attach_device. Would I use the pci_attach_device
i.e.:
pci_attach_device(NULL, PCI_INIT_ALL, pindex, &pci_device_info_str)

Then use the value returned in the pci_device_info_str.CpuBmstrTranslation?
So the actual address would be EUMBBAR+0x1100+CpuBmstrTranslation?

Then would how would I access the DMA memory? Is it as simple as just
setting up a pointer with the above address?

Sorry for all the q’s but I am still trying to get the hang of this.

Thanks Much,
Mike

“Wayne Fisher” <wayne.fisher@avvidasystems.com> wrote in message
news:aaorat$20s$1@inn.qnx.com

Hi Mike,

“Mike Toreno” <> no.spam@address.com> > wrote in message
news:aa6p2e$k9l$> 1@nntp.qnx.com> …
Thanks Dave, I changed my buffers to a mmap(ed)/DMA safe buffers, and
used
the mem_offset to get the address to pass to the PPC DMA engine.
However
I
am getting the same results as before. The destination buffer after the
“supposed” transfer is empty.

The physical address of memory returned from mem_offset is not sufficient
for DMA to work on PPC. We couldn’t get our DMA working until we were told
that we needed to modify the physical address to turn it into a PCI
address.

Add the CpuBmstrTranslation value from the pci_dev_info structure (in
hw/pci.h) to your physical address. That should give you the address that
you need.

This leads me to believe that the DMA channel may not really be getting
set
with the correct parameters,which leads me to another question of mmap
VS
mmap_device_memory.

I am a bit confused, even after reading the docs, but let me give the
explanation a stab. mmap is used to map out a region of my local memory
into
my local memory, such as for a DMA safe bufer. While mmap_device_memory
is
used to map another devices memory/registers into my local memory. Is
this
somewhat correct?

Currently I am using mmap to map the PPC DMA registers into memory,
should
I
be using mmap_device_memory?

Thanks,
Mike

Later,
Wayne

Hi Mike,

I went back and re-read your original post and your environment is different
than ours. So, best I can do is draw upon the similarities between them. For
our DMA, we are using a DMA controller on a cPCI card and not on the
processor itself.

Depending on your current point of view, there are 3 different views or
mappings of the same memory location.

First is the physical address of it - the CPU’s point of view.
Then there is the virtual address of it - the process’ point of view. (after
mmap()).
And finally, the PCI address of it - a PCI card’s point of view.

You might picture is as follows:

virutal address <–> physical address <–> PCI address.

To map between them, you use either mem_offset() or mmap_device_memory() to
go between the virtual and physical addresses. You use CpuBmstrTranslation
to go between physical and PCI addresses. (As a side note,
CpuBmstrTranslation is 0 on x86 platforms so physical == PCI there).

So, whenever your DMA controller wants a PCI address, give it the PCI
address and see if it works. I don’t know the correct way to get the
CpuBmstrTranslation when your device is on the processor itself, but, I
think that it should be the same as that returned from any other PCI
device.

Hope this helps,

Wayne


“Mike Toreno” <no.spam@address.com> wrote in message
news:aaudgf$p3u$1@nntp.qnx.com

Wayne,

Thanks for the info, but I am not sure how to get the CpuBmstrTranslation
value from the pci_dev_info struc. The only way I see that this can be
done
is by using the call pci_attach_device. Would I use the pci_attach_device
i.e.:
pci_attach_device(NULL, PCI_INIT_ALL, pindex, &pci_device_info_str)

Then use the value returned in the
pci_device_info_str.CpuBmstrTranslation?
So the actual address would be EUMBBAR+0x1100+CpuBmstrTranslation?

Then would how would I access the DMA memory? Is it as simple as just
setting up a pointer with the above address?

Sorry for all the q’s but I am still trying to get the hang of this.

Thanks Much,
Mike

“Wayne Fisher” <> wayne.fisher@avvidasystems.com> > wrote in message
news:aaorat$20s$> 1@inn.qnx.com> …
Hi Mike,

“Mike Toreno” <> no.spam@address.com> > wrote in message
news:aa6p2e$k9l$> 1@nntp.qnx.com> …
Thanks Dave, I changed my buffers to a mmap(ed)/DMA safe buffers, and
used
the mem_offset to get the address to pass to the PPC DMA engine.
However
I
am getting the same results as before. The destination buffer after
the
“supposed” transfer is empty.

The physical address of memory returned from mem_offset is not
sufficient
for DMA to work on PPC. We couldn’t get our DMA working until we were
told
that we needed to modify the physical address to turn it into a PCI
address.

Add the CpuBmstrTranslation value from the pci_dev_info structure (in
hw/pci.h) to your physical address. That should give you the address
that
you need.

This leads me to believe that the DMA channel may not really be
getting
set
with the correct parameters,which leads me to another question of mmap
VS
mmap_device_memory.

I am a bit confused, even after reading the docs, but let me give the
explanation a stab. mmap is used to map out a region of my local
memory
into
my local memory, such as for a DMA safe bufer. While
mmap_device_memory
is
used to map another devices memory/registers into my local memory. Is
this
somewhat correct?

Currently I am using mmap to map the PPC DMA registers into memory,
should
I
be using mmap_device_memory?

Thanks,
Mike

Later,
Wayne