Skip to content

Commit bf1f6c1

Browse files
buttercutterintel-lab-lkp
authored andcommitted
Staging : Add RIFFA PCIe staging driver
This patch adds RIFFA PCIe linux driver for https://github.com/promach/riffa/tree/full_duplex/driver/linux This staging driver is modified from this upstream driver at https://github.com/KastnerRG/riffa/tree/master/driver/linux For further details, please refer to KastnerRG/riffa#31 Signed-off-by: Cheng Fei Phung <feiphung@hotmail.com>
1 parent d5d12ce commit bf1f6c1

9 files changed

Lines changed: 2344 additions & 0 deletions

File tree

drivers/staging/riffa/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
config RIFFA_PCIE
2+
tristate "a simple framework for communicating data from a host CPU to a FPGA via a PCI Express bus"
3+
depends on PCI
4+
---help---
5+
Transfers data with full duplex capability using PCIe protocol

drivers/staging/riffa/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
obj-$(CONFIG_RIFFA) += riffa.o circ_queue.o riffa_driver.o riffa_mod.o

drivers/staging/riffa/TODO

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
TODO:
2+
- optimize the driver code for further speed improvement although it can now achieve defined PCIe speed grade
3+
- solve all the coding style errors from scripts/checkpatch.pl
4+
- add vendor and device IDs for more supported devices after actual hardware testing
5+
6+
Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>
7+
and Cheng Fei Phung<feiphung@hotmail.com>

drivers/staging/riffa/circ_queue.c

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
// ----------------------------------------------------------------------
2+
// Copyright (c) 2016, The Regents of the University of California All
3+
// rights reserved.
4+
//
5+
// Redistribution and use in source and binary forms, with or without
6+
// modification, are permitted provided that the following conditions are
7+
// met:
8+
//
9+
// * Redistributions of source code must retain the above copyright
10+
// notice, this list of conditions and the following disclaimer.
11+
//
12+
// * Redistributions in binary form must reproduce the above
13+
// copyright notice, this list of conditions and the following
14+
// disclaimer in the documentation and/or other materials provided
15+
// with the distribution.
16+
//
17+
// * Neither the name of The Regents of the University of California
18+
// nor the names of its contributors may be used to endorse or
19+
// promote products derived from this software without specific
20+
// prior written permission.
21+
//
22+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL REGENTS OF THE
26+
// UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY DIRECT, INDIRECT,
27+
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28+
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29+
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30+
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
31+
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
32+
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33+
// DAMAGE.
34+
// ----------------------------------------------------------------------
35+
36+
/*
37+
* Filename: circ_queue.c
38+
* Version: 1.0
39+
* Description: A lock-free single-producer circular queue implementation
40+
* modeled after the more elaborate C++ version from Faustino Frechilla at:
41+
* http://www.codeproject.com/Articles/153898/Yet-another-implementation-of-a-lock-free-circular
42+
* Author: Matthew Jacobsen
43+
* History: @mattj: Initial release. Version 1.0.
44+
*/
45+
46+
#include <linux/slab.h>
47+
#include "circ_queue.h"
48+
49+
circ_queue * init_circ_queue(int len)
50+
{
51+
int i;
52+
circ_queue * q;
53+
54+
q = kzalloc(sizeof(circ_queue), GFP_KERNEL);
55+
if (q == NULL) {
56+
printk(KERN_ERR "Not enough memory to allocate circ_queue");
57+
return NULL;
58+
}
59+
60+
atomic_set(&q->writeIndex, 0);
61+
atomic_set(&q->readIndex, 0);
62+
q->len = len;
63+
64+
q->vals = (unsigned int**) kzalloc(len*sizeof(unsigned int*), GFP_KERNEL);
65+
if (q->vals == NULL) {
66+
printk(KERN_ERR "Not enough memory to allocate circ_queue array");
67+
return NULL;
68+
}
69+
for (i = 0; i < len; i++) {
70+
q->vals[i] = (unsigned int*) kzalloc(2*sizeof(unsigned int), GFP_KERNEL);
71+
if (q->vals[i] == NULL) {
72+
printk(KERN_ERR "Not enough memory to allocate circ_queue array position");
73+
return NULL;
74+
}
75+
}
76+
77+
return q;
78+
}
79+
80+
/**
81+
* Internal function to help count. Returns the queue size normalized position.
82+
*/
83+
unsigned int queue_count_to_index(unsigned int count, unsigned int len)
84+
{
85+
return (count % len);
86+
}
87+
88+
int push_circ_queue(circ_queue * q, unsigned int val1, unsigned int val2)
89+
{
90+
unsigned int currReadIndex;
91+
unsigned int currWriteIndex;
92+
93+
currWriteIndex = atomic_read(&q->writeIndex);
94+
currReadIndex = atomic_read(&q->readIndex);
95+
if (queue_count_to_index(currWriteIndex+1, q->len) == queue_count_to_index(currReadIndex, q->len)) {
96+
// The queue is full
97+
return 1;
98+
}
99+
100+
// Save the data into the queue
101+
q->vals[queue_count_to_index(currWriteIndex, q->len)][0] = val1;
102+
q->vals[queue_count_to_index(currWriteIndex, q->len)][1] = val2;
103+
// Increment atomically write index. Now a consumer thread can read
104+
// the piece of data that was just stored.
105+
atomic_inc(&q->writeIndex);
106+
107+
return 0;
108+
}
109+
110+
int pop_circ_queue(circ_queue * q, unsigned int * val1, unsigned int * val2)
111+
{
112+
unsigned int currReadIndex;
113+
unsigned int currMaxReadIndex;
114+
115+
do
116+
{
117+
currReadIndex = atomic_read(&q->readIndex);
118+
currMaxReadIndex = atomic_read(&q->writeIndex);
119+
if (queue_count_to_index(currReadIndex, q->len) == queue_count_to_index(currMaxReadIndex, q->len)) {
120+
// The queue is empty or a producer thread has allocate space in the queue
121+
// but is waiting to commit the data into it
122+
return 1;
123+
}
124+
125+
// Retrieve the data from the queue
126+
*val1 = q->vals[queue_count_to_index(currReadIndex, q->len)][0];
127+
*val2 = q->vals[queue_count_to_index(currReadIndex, q->len)][1];
128+
129+
// Try to perfrom now the CAS operation on the read index. If we succeed
130+
// label & val already contain what q->readIndex pointed to before we
131+
// increased it.
132+
if (atomic_cmpxchg(&q->readIndex, currReadIndex, currReadIndex+1) == currReadIndex) {
133+
// The lable & val were retrieved from the queue. Note that the
134+
// data inside the label or value arrays are not deleted.
135+
return 0;
136+
}
137+
138+
// Failed to retrieve the elements off the queue. Someone else must
139+
// have read the element stored at countToIndex(currReadIndex)
140+
// before we could perform the CAS operation.
141+
} while(1); // keep looping to try again!
142+
143+
return 1;
144+
}
145+
146+
int circ_queue_empty(circ_queue * q)
147+
{
148+
unsigned int currReadIndex;
149+
unsigned int currMaxReadIndex;
150+
151+
currReadIndex = atomic_read(&q->readIndex);
152+
currMaxReadIndex = atomic_read(&q->writeIndex);
153+
if (queue_count_to_index(currReadIndex, q->len) == queue_count_to_index(currMaxReadIndex, q->len)) {
154+
// The queue is empty or a producer thread has allocate space in the queue
155+
// but is waiting to commit the data into it
156+
return 1;
157+
}
158+
return 0;
159+
}
160+
161+
int circ_queue_full(circ_queue * q)
162+
{
163+
unsigned int currReadIndex;
164+
unsigned int currWriteIndex;
165+
166+
currWriteIndex = atomic_read(&q->writeIndex);
167+
currReadIndex = atomic_read(&q->readIndex);
168+
if (queue_count_to_index(currWriteIndex+1, q->len) == queue_count_to_index(currReadIndex, q->len)) {
169+
// The queue is full
170+
return 1;
171+
}
172+
return 0;
173+
}
174+
175+
void free_circ_queue(circ_queue * q)
176+
{
177+
int i;
178+
179+
if (q == NULL)
180+
return;
181+
182+
for (i = 0; i < q->len; i++) {
183+
kfree(q->vals[i]);
184+
}
185+
kfree(q->vals);
186+
kfree(q);
187+
}
188+

drivers/staging/riffa/circ_queue.h

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// ----------------------------------------------------------------------
2+
// Copyright (c) 2016, The Regents of the University of California All
3+
// rights reserved.
4+
//
5+
// Redistribution and use in source and binary forms, with or without
6+
// modification, are permitted provided that the following conditions are
7+
// met:
8+
//
9+
// * Redistributions of source code must retain the above copyright
10+
// notice, this list of conditions and the following disclaimer.
11+
//
12+
// * Redistributions in binary form must reproduce the above
13+
// copyright notice, this list of conditions and the following
14+
// disclaimer in the documentation and/or other materials provided
15+
// with the distribution.
16+
//
17+
// * Neither the name of The Regents of the University of California
18+
// nor the names of its contributors may be used to endorse or
19+
// promote products derived from this software without specific
20+
// prior written permission.
21+
//
22+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL REGENTS OF THE
26+
// UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY DIRECT, INDIRECT,
27+
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28+
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29+
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30+
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
31+
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
32+
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33+
// DAMAGE.
34+
// ----------------------------------------------------------------------
35+
36+
/*
37+
* Filename: circ_queue.h
38+
* Version: 1.0
39+
* Description: A lock-free single-producer circular queue implementation
40+
* modeled after the more elaborate C++ version from Faustino Frechilla at:
41+
* http://www.codeproject.com/Articles/153898/Yet-another-implementation-of-a-lock-free-circular
42+
* Author: Matthew Jacobsen
43+
* History: @mattj: Initial release. Version 1.0.
44+
*/
45+
#ifndef CIRC_QUEUE_H
46+
#define CIRC_QUEUE_H
47+
48+
#include <asm/atomic.h>
49+
50+
/* Struct for the circular queue. */
51+
struct circ_queue {
52+
atomic_t writeIndex;
53+
atomic_t readIndex;
54+
unsigned int ** vals;
55+
unsigned int len;
56+
};
57+
typedef struct circ_queue circ_queue;
58+
59+
/**
60+
* Initializes a circ_queue with depth/length len. Returns non-NULL on success,
61+
* NULL if there was a problem creating the queue.
62+
*/
63+
circ_queue * init_circ_queue(int len);
64+
65+
/**
66+
* Pushes a pair of unsigned int values into the specified queue at the head.
67+
* Returns 0 on success, non-zero if there is no more space in the queue.
68+
*/
69+
int push_circ_queue(circ_queue * q, unsigned int val1, unsigned int val2);
70+
71+
/**
72+
* Pops a pair of unsigned int values out of the specified queue from the tail.
73+
* Returns 0 on success, non-zero if the queue is empty.
74+
*/
75+
int pop_circ_queue(circ_queue * q, unsigned int * val1, unsigned int * val2);
76+
77+
/**
78+
* Returns 1 if the circ_queue is empty, 0 otherwise. Note, this is not a
79+
* synchronized function. If another thread is accessing this circ_queue, the
80+
* return value may not be valid.
81+
*/
82+
int circ_queue_empty(circ_queue * q);
83+
84+
/**
85+
* Returns 1 if the circ_queue is full, 0 otherwise. Note, this is not a
86+
* synchronized function. If another thread is accessing this circ_queue, the
87+
* return value may not be valid.
88+
*/
89+
int circ_queue_full(circ_queue * q);
90+
91+
/**
92+
* Frees the resources associated with the specified circ_queue.
93+
*/
94+
void free_circ_queue(circ_queue * q);
95+
96+
#endif

0 commit comments

Comments
 (0)