[vortex] User level DMA
Ricardo Luis Kulzer
kulzer@inf.ufsm.br
Mon, 18 Dec 2000 20:19:03 -0200 (BRST)
I would like to write a driver for a specifica apllication using
Vortex chip. In my case, I want to allocate a buffer in the driver (kernel
segment), map this buffer to user process memory using mmap and
remap_page_range, and send the buffer to NIC using ioctl. Does anybody
have already write anything in this way?
I am trying, but I have not many experience, and I have some basics
doubts. I dont achieve success in remaping a skbuffer->data to a user
process. I wrote for example, the code below for the driver, user process
and testing. I load the driver, alloc a sk_buff, and put a initial string
"_INITIAL:__STRCPY TO SBUFFER_DATA______". I use a user process to map a
user process variable, str, to skbuffer->data, and copy "______TEST:STRCPY
TO STR______" to str (I think to skbuffer->data, because str is mapped in
skbuffer->data).
At clanup_module, I print skbuffer->data, but it didn't change the
initial data, "_INITIAL:__STRCPY TO SBUFFER_DATA______".
Whats wrong? Can I do user level DMA in this way?
Thanks?
R. Kulzer
/*########################################################################*/
/*############### mmaptest.c: the module ##################################*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/fs.h>
#include <linux/wrapper.h>
#include <asm/io.h>
#include <linux/skbuff.h>
#define MMT_BUF_SIZE 8024
static struct sk_buff *sbuffer;
static int mmaptest_mmap(struct file *filp, struct vm_area_struct *vma){
unsigned long page,pos;
unsigned long start = (unsigned long)vma->vm_start;
unsigned long size = (unsigned long)(vma->vm_end-vma->vm_start);
if (size>MMT_BUF_SIZE)
return -EINVAL;
pos=(unsigned long) sbuffer->data;
printk("\n<1>FROM KERNEL - Remaping str to buffer\n");
while (size > 0) {
page = virt_to_phys((void *)pos);
if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
return -EAGAIN;
start+=PAGE_SIZE;
pos+=PAGE_SIZE;
size-=PAGE_SIZE;
}
return 0;
}
void cleanup_module(void){
printk("\n<1>CLEANUP FROM KERNEL - sbuffer->data:%s\n",sbuffer->data);
kfree_skb(sbuffer);
unregister_chrdev(187,"mmaptest");
return;
}
static int mmaptest_open(struct inode *inode, struct file *filp){
MOD_INC_USE_COUNT;
return 0;
}
static int mmaptest_release(struct inode *inode, struct file *filp){
MOD_DEC_USE_COUNT;
return 0;
}
static struct file_operations mmaptest_fops = {
mmap: mmaptest_mmap,
open: mmaptest_open,
release: mmaptest_release,
};
int init_module(void) {
struct page *page;
int i;
char *s="_INITIAL:__STRCPY TO SBUFFER_DATA______";
register_chrdev(187,"mmaptest",&mmaptest_fops);
sbuffer=alloc_skb(MMT_BUF_SIZE,GFP_KERNEL);
skb_reserve(sbuffer, 2);
skb_put(sbuffer,strlen(s)+1);
strcpy(sbuffer->data,s);
return 0;
}
/*########################################################################*/
/*############### mmapdriver.c: the user process #####################*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
int main (int argc, char *argv[])
{
char *str;
int fd;
system("rm -f /dev/mmaptest0");
system("mknod /dev/mmaptest0 c 187 0");
fd = open("/dev/mmaptest0",O_RDONLY);
str = (char *)mmap(NULL,1024,PROT_WRITE,MAP_PRIVATE,fd,0);
if (str==MAP_FAILED) {
puts("Error!");
return 1;
};
strcpy(str,"______TEST:STRCPY TO STR______");
printf("\nFROM PROCESS: Coping <%s> to STR\n",str);
munmap(str, 4096);
close(fd);
return 0;
}
/*########################################################################*/
/*############### Makefile #####################*/
all: mmaptest.o mmapdriver
KCFLAGS=-D__KERNEL__ -w -Wstrict-prototypes -O2 -DMODULE
CFLAGS= -Wstrict-prototypes -w -O2 -pipe
mmaptest.o: mmaptest.c
gcc $(KCFLAGS) -c -o $@ $<
mmapdriver: mmapdriver.c
gcc $(CFLAGS) -o $@ $<
test:
insmod ./mmaptest.o
./mmapdriver /dev/mmaptest0
rmmod mmaptest
clean:
rm -f mmapdriver mmaptest.o core
rmmod mmaptest