DMA buffer again

Jan Kiszka kiszka at rts.uni-hannover.de
Tue Jan 27 16:47:39 CET 2004


Rodrigo Amestica schrieb:

> if I use rt_malloc I cannot make the buffer available to user-land, or? 
> I did not say it before, but the buffer must be readable from user space.
> 

This makes things slightly more complicated...

> Looks like I cannot make a DMA contiguous buffer available to user land, 
> it looks like I will need to copy from the DMA buffer to a place where 
> user-land can read. I was trying to avoid this copying step.
> 

Hard real-time user land? Then don't forget to lock the memory!

It is not impossible. I just found some code remainder in our CVS. The 
skb header and data are in the same chunk of memory to which "skb" is 
pointing:

rtskb.h:
     /* sanity check */
     #if PAGE_SIZE < DEFAULT_MAX_RTSKB_SIZE
         #error The page size is smaller than the rtskb size. This may 
prevent
         #error DMA mapping of non-continuous rtskbs. You have to disable
         #error CONFIG_RTAI_MM_VMALLOC in RTAI to compile RTnet for the 
selected
         #error architecture.
     #endif

     /* This macro calculates the kernel virtual address which can be 
passed to
      * pci_map_single(). */
     #define RTSKB_KVA(skb, addr) \
         (void*)((unsigned long)skb->buf_page_addr | ((unsigned 
long)addr & (PAGE_SIZE-1)))

     /* The rtskb structure and its data buffer are allocated as one 
chunk. If
      * vmalloc'ed memory is used for rtskb's, the buffer has to fit into a
      * single page to allow DMA mapping. This macro extends the rtskb 
structure
      * size in order to be able to adjust the buffer start 
appropriately. */
     #define ALIGN_RTSKB_STRUCT_LEN      SKB_DATA_ALIGN(sizeof(struct 
rtskb)) + \
         SKB_DATA_ALIGN(DEFAULT_MAX_RTSKB_SIZE)

rtskb.c:
     /* align buffer start so that it fits into a single page */
     skb->buf_start = ((char *)skb) + ALIGN_RTSKB_BUF;
     if (((unsigned long)skb->buf_start & (PAGE_SIZE-1)) +
         DEFAULT_MAX_RTSKB_SIZE > PAGE_SIZE)
         skb->buf_start =
             (unsigned char*)(((unsigned long)skb->buf_start & 
~(PAGE_SIZE-1)) +
             PAGE_SIZE);

     /* calculate logical buffer page address */
     skb->buf_page_addr = page_address(vmalloc_to_page(skb->buf_start));


You can see, the approach was to pre-calculate the physical address in 
order to pass it fast to the hardware when needed.

Of course, copy_to/from_user is a bit easier :)

Jan




More information about the Rtai mailing list