因为riffa.c包含进来了riffa.h和riffa_driver.h,我们分别贴出来这三个文件:
riffa_driver.h
// ----------------------------------------------------------------------
// Copyright (c) 2016, The Regents of the University of California All
// rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// * Neither the name of The Regents of the University of California
// nor the names of its contributors may be used to endorse or
// promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL REGENTS OF THE
// UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
// ----------------------------------------------------------------------
/*
* Filename: riffa_driver.h
* Version: 2.0
* Description: Linux PCIe device driver for RIFFA. Uses Linux kernel APIs in
* version 2.6.27+ (tested on version 2.6.32 - 3.3.0).
* Author: Matthew Jacobsen
* History: @mattj: Initial release. Version 2.0.
*/
#ifndef RIFFA_DRIVER_H
#define RIFFA_DRIVER_H
#include
#define DBUG 1
#ifdef DEBUG
#define DEBUG_MSG(...) printk(__VA_ARGS__)
#else
#define DEBUG_MSG(...)
#endif
// The major device number. We can't rely on dynamic registration because ioctls
// need to know it.
#define MAJOR_NUM 100
#define DEVICE_NAME "riffa"
#define VENDOR_ID0 0x10EE
#define VENDOR_ID1 0x1172
// Message events for readmsgs/writemsgs queues.
#define EVENT_TXN_LEN 1
#define EVENT_TXN_OFFLAST 2
#define EVENT_TXN_DONE 3
#define EVENT_SG_BUF_READ 4
// Constants and device offsets
#define NUM_FPGAS 5 // max # of FPGAs to support in a single PC
#define MAX_CHNLS 12 // max # of channels per FPGA
#define MAX_BUS_WIDTH_PARAM 4 // max bus width parameter
#define SG_BUF_SIZE (4*1024) // size of shared SG buffer
#define SG_ELEMS 200 // # of SG elements to transfer at a time
#define SPILL_BUF_SIZE (4*1024) // size of shared spill common buffer
#define RX_SG_LEN_REG_OFF 0x0 // config offset for RX SG buf length
#define RX_SG_ADDR_LO_REG_OFF 0x1 // config offset for RX SG buf low addr
#define RX_SG_ADDR_HI_REG_OFF 0x2 // config offset for RX SG buf high addr
#define RX_LEN_REG_OFF 0x3 // config offset for RX txn length
#define RX_OFFLAST_REG_OFF 0x4 // config offset for RX txn last/offset
#define RX_TNFR_LEN_REG_OFF 0xD // config offset for RX transfer length
#define TX_SG_LEN_REG_OFF 0x5 // config offset for TX SG buf length
#define TX_SG_ADDR_LO_REG_OFF 0x6 // config offset for TX SG buf low addr
#define TX_SG_ADDR_HI_REG_OFF 0x7 // config offset for TX SG buf high addr
#define TX_LEN_REG_OFF 0x8 // config offset for TX txn length
#define TX_OFFLAST_REG_OFF 0x9 // config offset for TX txn last/offset
#define TX_TNFR_LEN_REG_OFF 0xE // config offset for TX transfer length
#define INFO_REG_OFF 0xA // config offset for link info
#define IRQ_REG0_OFF 0xB // config offset for interrupt reg 0
#define IRQ_REG1_OFF 0xC // config offset for interrupt reg 1
// Structs
struct fpga_chnl_io
{
int id;
int chnl;
unsigned int len;
unsigned int offset;
unsigned int last;
unsigned long long timeout;
char * data;
};
typedef struct fpga_chnl_io fpga_chnl_io;
struct fpga_info_list
{
int num_fpgas;
int id[NUM_FPGAS];
int num_chnls[NUM_FPGAS];
char name[NUM_FPGAS][16];
int vendor_id[NUM_FPGAS];
int device_id[NUM_FPGAS];
};
typedef struct fpga_info_list fpga_info_list;
// IOCTLs
#define IOCTL_SEND _IOW(MAJOR_NUM, 1, fpga_chnl_io *)
#define IOCTL_RECV _IOR(MAJOR_NUM, 2, fpga_chnl_io *)
#define IOCTL_LIST _IOR(MAJOR_NUM, 3, fpga_info_list *)
#define IOCTL_RESET _IOW(MAJOR_NUM, 4, int)
#endif
riffa.h
// ----------------------------------------------------------------------
// Copyright (c) 2016, The Regents of the University of California All
// rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// * Neither the name of The Regents of the University of California
// nor the names of its contributors may be used to endorse or
// promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL REGENTS OF THE
// UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
// ----------------------------------------------------------------------
/*
* Filename: riffa.h
* Version: 2.0
* Description: Linux PCIe communications API for RIFFA.
* Author: Matthew Jacobsen
* History: @mattj: Initial release. Version 2.0.
*/
#ifndef RIFFA_H
#define RIFFA_H
#include "riffa_driver.h"
#ifdef __cplusplus
extern "C" {
#endif
struct fpga_t;
typedef struct fpga_t fpga_t;
/**
* Populates the fpga_info_list pointer with all FPGAs registered in the system.
* Returns 0 on success, a negative value on error.
*/
int fpga_list(fpga_info_list * list);
/**
* Initializes the FPGA specified by id. On success, returns a pointer to a
* fpga_t struct. On error, returns NULL. Each FPGA must be opened before any
* channels can be accessed. Once opened, any number of threads can use the
* fpga_t struct.
*/
fpga_t * fpga_open(int id);
/**
* Cleans up memory/resources for the FPGA specified by the fd descriptor.
*/
void fpga_close(fpga_t * fpga);
/**
* Sends len words (4 byte words) from data to FPGA channel chnl using the
* fpga_t struct. The FPGA channel will be sent len, destoff, and last. If last
* is 1, the channel should interpret the end of this send as the end of a
* transaction. If last is 0, the channel should wait for additional sends
* before the end of the transaction. If timeout is non-zero, this call will
* send data and wait up to timeout ms for the FPGA to respond (between
* packets) before timing out. If timeout is zero, this call may block
* indefinitely. Multiple threads sending on the same channel may result in
* corrupt data or error. This function is thread safe across channels.
* On success, returns the number of words sent. On error returns a negative
* value.
*/
int fpga_send(fpga_t * fpga, int chnl, void * data, int len, int destoff,
int last, long long timeout);
/**
* Receives data from the FPGA channel chnl to the data pointer, using the
* fpga_t struct. The FPGA channel can send any amount of data, so the data
* array should be large enough to accommodate. The len parameter specifies the
* actual size of the data buffer in words (4 byte words). The FPGA channel will
* specify an offset which will determine where in the data array the data will
* start being written. If the amount of data (plus offset) exceed the size of
* the data array (len), then that data will be discarded. If timeout is
* non-zero, this call will wait up to timeout ms for the FPGA to respond
* (between packets) before timing out. If timeout is zero, this call may block
* indefinitely. Multiple threads receiving on the same channel may result in
* corrupt data or error. This function is thread safe across channels.
* On success, returns the number of words written to the data array. On error
* returns a negative value.
*/
int fpga_recv(fpga_t * fpga, int chnl, void * data, int len, long long timeout);
/**
* Resets the state of the FPGA and all transfers across all channels. This is
* meant to be used as an alternative to rebooting if an error occurs while
* sending/receiving. Calling this function while other threads are sending or
* receiving will result in unexpected behavior.
*/
void fpga_reset(fpga_t * fpga);
#ifdef __cplusplus
}
#endif
#endif
riffa.c
// ----------------------------------------------------------------------
// Copyright (c) 2016, The Regents of the University of California All
// rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// * Neither the name of The Regents of the University of California
// nor the names of its contributors may be used to endorse or
// promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL REGENTS OF THE
// UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
// ----------------------------------------------------------------------
/*
* Filename: riffa.c
* Version: 2.0
* Description: Linux PCIe communications API for RIFFA.
* Author: Matthew Jacobsen
* History: @mattj: Initial release. Version 2.0.
*/
#include
#include
#include
#include
#include
#include "riffa.h"
struct fpga_t
{
int fd;
int id;
};
fpga_t * fpga_open(int id)
{
fpga_t * fpga;
// Allocate space for the fpga_dev
fpga = (fpga_t *)malloc(sizeof(fpga_t));
if (fpga == NULL)
return NULL;
fpga->id = id;
// Open the device file.
fpga->fd = open("/dev/" DEVICE_NAME, O_RDWR | O_SYNC);
if (fpga->fd < 0) {
free(fpga);
return NULL;
}
return fpga;
}
void fpga_close(fpga_t * fpga)
{
// Close the device file.
close(fpga->fd);
free(fpga);
}
int fpga_send(fpga_t * fpga, int chnl, void * data, int len, int destoff,
int last, long long timeout)
{
fpga_chnl_io io;
io.id = fpga->id;
io.chnl = chnl;
io.len = len;
io.offset = destoff;
io.last = last;
io.timeout = timeout;
io.data = (char *)data;
return ioctl(fpga->fd, IOCTL_SEND, &io);
}
int fpga_recv(fpga_t * fpga, int chnl, void * data, int len, long long timeout)
{
fpga_chnl_io io;
io.id = fpga->id;
io.chnl = chnl;
io.len = len;
io.timeout = timeout;
io.data = (char *)data;
return ioctl(fpga->fd, IOCTL_RECV, &io);
}
void fpga_reset(fpga_t * fpga)
{
ioctl(fpga->fd, IOCTL_RESET, fpga->id);
}
int fpga_list(fpga_info_list * list) {
int fd;
int rc;
fd = open("/dev/" DEVICE_NAME, O_RDWR | O_SYNC);
if (fd < 0)
return fd;
rc = ioctl(fd, IOCTL_LIST, list);
close(fd);
return rc;
}
其实我们可先从riffa.c开始看起:这定义了几个用户操作,打开,关闭,读,写,以及复位。其实都是通过IOCTRL实现的。我们在想其实我们可以自己加上某一个函数,调用一个指定编号的IOCTL,同时在驱动里面自己写好这个驱动,就可以实现我们自己想要的功能了。
这里可以加上一个IOCTLS的控制,实际就顺序往下排号就行。
分析代码我们看到其实这些功能实现都是想组装一个IOCTRL结构,之后通过IOCTRL把这些参数传递给下层驱动进行控制。这些参数应该是在每次读写开始的时候都要写到FPGA里面进行设置的,其实我们可以考虑设置一个continued_write和continued_read,读和写都是使用之前上次的那些设置,就是再写一些新数据,再把新数据读上来。这里当然也牵扯一个读写的触发,我们之后要再底层的driver里面看是否可以隐含在某个操作里而不需要进行寄存器设置。
另外我们一定要看文件里面的注释,找出来我们可能需要关注的知识点:
这里我们看到显然RIFFA驱动是支持多线程的。
这个riffa.c是编译成静态库文件,供大家调用的。其实使用的时候直接包含进来这个riffa.c的源文件也是可以。
最最关键的是riffa_drive.c文件,我们继续分析