RIFFA之LINUX驱动学习之二:riffa.c文件

因为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,同时在驱动里面自己写好这个驱动,就可以实现我们自己想要的功能了。

RIFFA之LINUX驱动学习之二:riffa.c文件_第1张图片

这里可以加上一个IOCTLS的控制,实际就顺序往下排号就行。

分析代码我们看到其实这些功能实现都是想组装一个IOCTRL结构,之后通过IOCTRL把这些参数传递给下层驱动进行控制。这些参数应该是在每次读写开始的时候都要写到FPGA里面进行设置的,其实我们可以考虑设置一个continued_write和continued_read,读和写都是使用之前上次的那些设置,就是再写一些新数据,再把新数据读上来。这里当然也牵扯一个读写的触发,我们之后要再底层的driver里面看是否可以隐含在某个操作里而不需要进行寄存器设置。

另外我们一定要看文件里面的注释,找出来我们可能需要关注的知识点:

RIFFA之LINUX驱动学习之二:riffa.c文件_第2张图片

 这里我们看到显然RIFFA驱动是支持多线程的。

这个riffa.c是编译成静态库文件,供大家调用的。其实使用的时候直接包含进来这个riffa.c的源文件也是可以。

最最关键的是riffa_drive.c文件,我们继续分析

你可能感兴趣的:(FPGA,嵌入式硬件,fpga开发,硬件工程)