> Jonathan Haws wrote:
> > All,
> >
> > I have what may be an unconventional question:
> >
> > Our application consists of data being captured by an FPGA,
> processed, and transferred to SDRAM.  I simply give the FPGA an
> address of where I want it stored in SDRAM and it simply DMAs the
> data over and interrupts me when finished.  I then take that data
> and store it to disk.
> >
> > I have code in user space that handles all of the writing to disk
> nicely and fast enough for my application (I am capturing data at
> about 35-40 Mbytes/sec).
> >
> > My question is this:  is it possible to give a user-space pointer
> to the FPGA to DMA to?  It seems like I would have problems with
> alignment, address manipulation, and a whole slew of other issues.
> >
> > What would be the best way to accomplish something like that?  I
> want to handle all the disk access in user-space, but I do not want
> to have to copy 40 MB/s from kernel space to user-space either.
> >
> You can maintain a DMA buffer in kernel, then mmap to user space.
> And
> maybe you need some handshake between FPGA and the apps to balance
> input
> datas  with datas to disk.
> > I can maintain an allocated, DMA-safe buffer in kernel space if
> needed.  Can I simply get a user-space pointer to that buffer?  What
> calls are needed to translate addresses?
> >
> Use remap_pfn_range()  in your kernel DMA buffer manipulation driver
> .mmap() handler to export DMA  buffer address to user space.
> 

Can you provide an example for how to do that?  I have an mmap routine to map 
BARs that the FPGA maintains and I can access those, however when I try to map 
the DMA buffer and access what is in it, the system crashes.  Here is the mmap 
function I have right now:

/* fpga_mmap()
 *
 *  Description:
 *       The purpose of this function is to serve as a 'file_operation'
 *       which maps different PCI resources into the calling processes
 *       memory space.
 *
 *       NOTE:  The file offset are in page size; i.e.:
 *       offset 0 in process's mmap syscall -> BAR0
 *       offset 4096 in process's mmap syscall -> BAR1
 *       offset 8192 in process's mmap syscall -> BAR2
 *         offset 12288 -> Streaming DMA buffer
 *
 *  Arguments:
 *       struct file             *filp -- struct representing an open file
 *       struct vm_area_struct   *vma  -- struct representing memory 'segment'
 *
 *  Returns:
 *       int -- indication of success or failure
 *
 */
int fpga_mmap(struct file *filp, struct vm_area_struct *vma)
{
        struct pci_dev *dev;
        unsigned long addressToMap;
        uint8_t mapType = 0; /* 0 = IO, 1 = memory */

        /* Get the PCI device */
        dev = (struct pci_dev*)(filp->private_data);

        /* Map in the appropriate BAR based on page offset */
        if (vma->vm_pgoff == FPGA_CONFIG_SPACE)
        {
                /* Map BAR1 (the CONFIG area) */
                printk(KERN_ALERT "FPGA: Mapping BAR1 (CONFIG BAR).\n");
                addressToMap = pci_resource_start(dev, FPGA_CONFIG_SPACE);
                printk(KERN_ALERT "FPGA: PCI BAR1 (CONFIG BAR) Size -> 
%#08x.\n",
                        pci_resource_len(dev, FPGA_CONFIG_SPACE));
                mapType = 0;
        }
        else if(vma->vm_pgoff == FPGA_TEST_SPACE)
        {
                /* Map BAR2 (the TEST area) */
                printk(KERN_ALERT "FPGA: Mapping BAR2 (TEST BAR).\n");
                addressToMap = (pci_resource_start(dev, FPGA_TEST_SPACE) +
                        pci_resource_len(dev, FPGA_TEST_SPACE)) - 
FPGA_TEST_LENGTH;
                printk(KERN_ALERT "FPGA: PCI BAR2 (TEST BAR) Size -> %#08x.\n",
                        pci_resource_len(dev, FPGA_TEST_SPACE));
                mapType = 0;
        }
        else if(vma->vm_pgoff == 3)
        {

                addressToMap = (unsigned long)&fpga_drv.strmData[0];
                mapType = 1;
        }
        else
        {
                printk(KERN_ALERT " FPGA: Invalid BAR mapping specified.\n");
                return ERROR;
        }

        /* Execute the mapping */
        vma->vm_flags |= VM_IO;
        vma->vm_flags |= VM_RESERVED;
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        printk(KERN_ALERT "FPGA: vmSize -> 0x%x.\n",
                        (unsigned int)(vma->vm_end - vma->vm_start));

        if( mapType == 0 )
        {
                if(io_remap_pfn_range(vma, vma->vm_start, addressToMap >> 
PAGE_SHIFT,
                                vma->vm_end - vma->vm_start, vma->vm_page_prot) 
!= 0)
                {
                        printk(KERN_ALERT "FPGA: Failed to map BAR PCI space to 
user space.\n");
                        return ERROR;
                }
        }
        else
        {
                printk(KERN_NOTICE "FPGA: Mapping stream ptr (%#08x) to user 
space\n",(uint32_t)&fpga_drv.strmData[0]);
                printk(KERN_NOTICE "FPGA: Setting strmData[0][0] to 0x37\n");
                fpga_drv.strmData[0][0] = 0x37;
                if(remap_pfn_range(vma, vma->vm_start, addressToMap >> 
PAGE_SHIFT,
                                vma->vm_end - vma->vm_start, vma->vm_page_prot) 
!= 0)
                {
                        printk(KERN_ALERT "FPGA: Failed to map BAR PCI space to 
user space.\n");
                        return ERROR;
                }
        }

        return OK;
}


And here is the failure:

~ # ./main
FPGA: vmSize -> 0x4000.
FPGA: Mapping stream ptr (0xd10613bc) to user space
FPGA: Setting strmData[0][0] to 0x37
Unable to handle kernel paging request for data at address 0x00000000
Faulting instruction address: 0xd105f5e0
Oops: Kernel access of bad area, sig: 11 [#1]
PREEMPT Kilauea
Modules linked in: fpgaDriver
NIP: d105f5e0 LR: d105f5d8 CTR: c003fff4
REGS: cf86dde0 TRAP: 0300   Not tainted  (2.6.30.3-wolverine-dirty)
MSR: 00029030 <EE,ME,CE,IR,DR>  CR: 24008022  XER: 0000005f
DEAR: 00000000, ESR: 00800000
TASK = cf873950[281] 'main' THREAD: cf86c000
GPR00: 00000037 cf86de90 cf873950 00000028 17d78400 c0302028 c0302068 00000000
GPR08: 00000000 00000000 00000003 c0300000 24008024 100e89c8 100d6590 100917d8
GPR16: 100d0000 100d0000 c0320000 cfaca07c 00000001 cf8c0230 00000003 000000fb
GPR24: 00000000 cf8a6840 cfaca07c 00000000 d10613bc d106128c 00000004 cfaca07c
NIP [d105f5e0] fpga_mmap+0x9c/0x214 [fpgaDriver]
LR [d105f5d8] fpga_mmap+0x94/0x214 [fpgaDriver]
Call Trace:
[cf86de90] [d105f5d8] fpga_mmap+0x94/0x214 [fpgaDriver] (unreliable)
[cf86deb0] [c00c1a4c] mmap_region+0x29c/0x408
[cf86df10] [c000377c] sys_mmap+0x78/0x100
[cf86df40] [c00103fc] ret_from_syscall+0x0/0x3c
Instruction dump:
386302a8 48000735 3b9d0130 3c60d106 7f84e378 386302c4 48000721 3c60d106
386302f8 48000715 813d0130 38000037 <98090000> 7fe3fb78 809f0004 80df0008
---[ end trace 4393e8cf23caef19 ]---


Where am I going wrong?

Using mmap() would work well for me.

Also, what about this:

1. I open /dev/mem and get a file descriptor
2. I use mmap to reserve some physical addresses for my buffers in user space.
3. I give that address to the FPGA for DMA use.
4. When I get the FPGA interrupt, I invalidate the data cache and write the 
data to disk

Does that sound like it would work?  Would the address I receive from mmap() 
and pass to the FPGA be the actual physical address, or would I need to send 
the physical address to the FPGA and use the mmap() address to access and write 
to disk?

Thanks for the help!

Jonathan


_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to