1、驱动链接
XDMA驱动源码官网下载地址为:https://github.com/Xilinx/dma_ip_drivers
下载最新版本的XDMA驱动源码,即master版本,否则其驱动用不了(xdma ip核版本为4.1)。
2、驱动
此部分来源于博客:xdma驱动编译(给arm使用)
2.1、修改驱动的Makefile
修改dma_ip_drivers-master/XDMA/linux-kernel/xdma/Makefile
# ifneq ($(KERNELRELEASE),)
# $(TARGET_MODULE)-objs := libxdma.o xdma_cdev.o cdev_ctrl.o cdev_events.o cdev_sgdma.o cdev_xvc.o cdev_bypass.o xdma_mod.o xdma_thread.o
# obj-m := $(TARGET_MODULE).o
# else
# BUILDSYSTEM_DIR:=/lib/modules/$(shell uname -r)/build
# PWD:=$(shell pwd)
找到上面的并注释掉(最后一行还有一个 endif 也注释掉),紧挨着就添加下面的:
$(TARGET_MODULE)-objs := libxdma.o xdma_cdev.o cdev_ctrl.o cdev_events.o cdev_sgdma.o cdev_xvc.o cdev_bypass.o xdma_mod.o xdma_thread.o
obj-m := $(TARGET_MODULE).o
BUILDSYSTEM_DIR:=/home/debian/Desktop/xiaguangbo/project/rk3588/project/kernel # linux 源码目录
PWD:=$(shell pwd)
2.2、编译
export ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
make
3、测试工具
3.1、修改测试工具Makefile
修改 dma_ip_drivers-master/XDMA/linux-kernel/tools/Makefile
# CC ?= gcc
CC = aarch64-linux-gnu-gcc
3.2、编译
make
编译之后用file xxx查看文件是否是属于aarch64架构的,如果不是查看Makefile对不对
4、xdma中断检测上位机
4.1、代码
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdarg.h>
#include <syslog.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/sysinfo.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
/* ltoh: little to host */
/* htol: big to host */
#if __BYTE_ORDER == __LITTLE_ENDIAN
# define ltohl(x) (x)
# define ltohs(x) (x)
# define htoll(x) (x)
# define htols(x) (x)
#elif __BYTE_ORDER == __BIG_ENDIAN
# define ltohl(x) __bswap_32(x)
# define ltohs(x) __bswap_16(x)
# define htoll(x) __bswap_32(x)
# define htols(x) __bswap_16(x)
#endif
#define MAP_SIZE (1024*1024UL)
#define MAP_MASK (MAP_SIZE - 1)
static void * user_base;
static int start_en;
unsigned int user_irq_ack;
static void *mmap_control(int fd,long mapsize)
{
void *vir_addr;
vir_addr = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
return vir_addr;
}
static void user_write(unsigned int address,unsigned int val)
{
unsigned int writeval = htoll(val);
*((unsigned int *)(user_base+address)) = writeval;
}
static unsigned int user_read(unsigned int address)
{
unsigned int read_result = *((unsigned int *)(user_base+address));
read_result = ltohl(read_result);
return read_result;
}
void *event0_process()
{
int val;
int h_event0;
h_event0 = open("/dev/xdma0_events_0", O_RDWR | O_SYNC);
if(h_event0 < 0)
{
printf("open event0 error\n");
}
else
{
printf("open event0\n");
while (1)
{
if (start_en) {
read(h_event0,&val,4);
if (val == 1)
printf("event_0 done!\n");
else
printf("event_0 timeout!\n");
}
usleep(1);
}
close(h_event0);
}
}
void *event1_process()
{
int val;
int h_event1;
h_event1 = open("/dev/xdma0_events_1", O_RDWR | O_SYNC);
if(h_event1 < 0)
{
printf("open event1 error\n");
}
else
{
printf("open event1\n");
while (1)
{
if (start_en) {
read(h_event1,&val,4);
if (val == 1)
printf("event_1 done!\n");
else
printf("event_1 timeout!\n");
}
usleep(1);
}
close(h_event1);
}
}
void *event2_process()
{
int val;
int h_event2;
h_event2 = open("/dev/xdma0_events_2", O_RDWR | O_SYNC);
if(h_event2 < 0)
{
printf("open event2 error\n");
}
else
{
printf("open event2\n");
while (1)
{
if (start_en) {
read(h_event2,&val,4);
if (val == 1)
printf("event_2 done!\n");
else
printf("event_2 timeout!\n");
}
usleep(1);
}
close(h_event2);
}
}
void *event3_process()
{
int val;
int h_event3;
h_event3 = open("/dev/xdma0_events_3", O_RDWR | O_SYNC);
if(h_event3 < 0)
{
printf("open event3 error\n");
}
else
{
printf("open event3\n");
while (1)
{
if (start_en) {
read(h_event3,&val,4);
if (val == 1)
printf("event_3 done!\n");
else
printf("event_3 timeout!\n");
}
usleep(1);
}
close(h_event3);
}
}
int main(int argc, char* argv[])
{
static int h_c2h0;
static int h_h2c0;
static int h_user;
pthread_t t_event0;
pthread_t t_event1;
pthread_t t_event2;
pthread_t t_event3;
char* user_name = "/dev/xdma0_user";
char* c2h0_name = "/dev/xdma0_c2h_0";
char* h2c0_name = "/dev/xdma0_h2c_0";
start_en = 0;
h_c2h0 = open(c2h0_name,O_RDWR | O_NONBLOCK);
if(h_c2h0 < 0) { printf("open c2h0 error\n"); };
h_h2c0 = open(h2c0_name,O_RDWR);
if(h_h2c0 < 0) { printf("open h2c0 error\n"); };
h_user = open(user_name, O_RDWR | O_SYNC);
if(h_user < 0) { printf("open user error\n"); };
user_base = mmap_control(h_user,MAP_SIZE);
user_write(0x00000, 0xf);
pthread_create(&t_event0, NULL, event0_process, NULL);
pthread_create(&t_event1, NULL, event1_process, NULL);
pthread_create(&t_event2, NULL, event2_process, NULL);
pthread_create(&t_event3, NULL, event3_process, NULL);
usleep(100);
user_irq_ack = 0xffff0000;
user_write(0x00004, user_irq_ack);//start irq
start_en = 1;
printf("start\n");
pthread_join(t_event0,NULL);
pthread_join(t_event1,NULL);
pthread_join(t_event2,NULL);
pthread_join(t_event3,NULL);
user_irq_ack = 0x00000000;
user_write(0x00004, user_irq_ack);//stop irq
close(h_c2h0);
close(h_h2c0);
close(h_user);
close(t_event0);
close(t_event1);
close(t_event2);
close(t_event3);
}
4.2编译中断测试程序
aarch64-linux-gnu-gcc pcie_irq.c -o pcie_irq -static -lpthread