Newer
Older
* Trivial library function to return one of the spec memory addresses
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
Tomasz Wlostowski
committed
#include <stdlib.h>
#include <sys/mman.h>
Tomasz Wlostowski
committed
#include <sys/signal.h>
#include <arpa/inet.h>
#include <sys/stat.h>
Tomasz Wlostowski
committed
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include "speclib.h"
#include "wb_uart.h"
struct spec_private {
/* BAR0 maps the local bus (i.e. we can access FGPA register) */
/* BAR4 maps the local GN412x register */
void *bar4;
uint32_t vuart_base;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/*
* Check if the PCI device at bus/def_fn is a SPEC board.
* Return 1 if the device is a SPEC and 0 if it is not.
* If there is an error accessing the files, return -1
*/
static int spec_check_id(int bus, int dev)
{
unsigned int vendor, device;
char buf[128];
FILE *f;
// check device
snprintf(buf, sizeof buf,
"/sys/bus/pci/devices/0000:%02x:%02x.0/device",
bus, dev);
f=fopen(buf,"r");
if (f==NULL){
fprintf(stderr,"error accessing to file\n");
return -1;
}
fscanf(f, "%x", &device);
fclose(f);
// check vendor
snprintf(buf, sizeof buf,
"/sys/bus/pci/devices/0000:%02x:%02x.0/vendor",
bus, dev);
f=fopen(buf,"r");
if (f==NULL){
fprintf(stderr,"error accessing to file\n");
return -1;
}
fscanf(f, "%x", &vendor);
fclose(f);
if (device== PCI_DEVICE_ID_SPEC && vendor== PCI_VENDOR_ID_CERN)
return 1;
if (device== PCI_DEVICE_ID_GN4124 && vendor== PCI_VENDOR_ID_GENNUM)
return 1;
return 0;
}
/*
* Checks if there's a SPEC card at bus/def_fn.
* If one (or both) parameters are < 0, takes first available card
* and returns 0. If no cards have been detected, returns -1
*/
static int spec_scan(int *bus, int *devfn)
Tomasz Wlostowski
committed
struct dirent **namelist;
int n, i, found = 0, ret;
Tomasz Wlostowski
committed
int my_bus, my_devfn;
// Automatic search for the first availabe card
n = scandir("/sys/bus/pci/devices/", &namelist, 0, 0);
Tomasz Wlostowski
committed
if (n < 0)
{
perror("scandir");
exit(-1);
}
for (i = 0; i < n; i++)
{
ret = sscanf(namelist[i]->d_name, "0000:%02x:%02x.0",
&my_bus, &my_devfn);
if(!found && ret == 2)
Tomasz Wlostowski
committed
{
if (*bus >= 0)
my_bus = *bus;
if (*devfn >= 0)
my_devfn = *devfn;
if (spec_check_id(my_bus, my_devfn) > 0)
Tomasz Wlostowski
committed
{
*bus = my_bus;
*devfn = my_devfn;
found = 1;
Tomasz Wlostowski
committed
}
Tomasz Wlostowski
committed
}
Tomasz Wlostowski
committed
if(!found)
{
fprintf(stderr,"Can't detect any SPEC card :(\n");
return -1;
}
Tomasz Wlostowski
committed
return 0;
Tomasz Wlostowski
committed
}
/* Maps a particular BAR of given SPEC card and returns its virtual address
Tomasz Wlostowski
committed
(or NULL in case of failure) */
static void *spec_map_area(int bus, int dev, int bar, size_t size)
Tomasz Wlostowski
committed
{
char path[1024];
int fd;
void *ptr;
snprintf(path, sizeof(path), "/sys/bus/pci/devices/"
"/0000:%02x:%02x.0/resource%d", bus, dev, bar);
Tomasz Wlostowski
committed
fd = open(path, O_RDWR | O_SYNC);
if(fd <= 0)
return NULL;
ptr = mmap(NULL, size & ~(getpagesize()-1), PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
Tomasz Wlostowski
committed
return NULL;
Tomasz Wlostowski
committed
return ptr;
void *spec_open(int bus, int dev)
{
struct spec_private *card = malloc(sizeof(struct spec_private));
if(!card || spec_scan(&bus, &dev) < 0)
return NULL;
card->bar0 = spec_map_area(bus, dev, BASE_BAR0, 0x100000);
card->bar4 = spec_map_area(bus, dev, BASE_BAR4, 0x1000);
Grzegorz Daniluk
committed
if(!card->bar0 && !card->bar4)
{
free(card);
card = NULL;
}
return card;
}
void *spec_get_base(void *card, int basenr)
{
struct spec_private *p = card;
if (basenr == BASE_BAR0)
return p->bar0;
if (basenr == BASE_BAR4)
return p->bar4;
return NULL;
}
void spec_close(void *card)
{
struct spec_private *p = (struct spec_private *) card;
if(!card)
return;
munmap(p->bar0, 0x100000);
munmap(p->bar4, 0x1000);
free(card);
}
void spec_writel(void *card, uint32_t data, uint32_t addr)
{
struct spec_private *p = (struct spec_private *) card;
*(volatile uint32_t *) (p->bar0 + addr) = data;
}
uint32_t spec_readl(void *card, uint32_t addr)
{
struct spec_private *p = (struct spec_private *) card;
return *(volatile uint32_t *) (p->bar0 + addr);
}
static int vuart_rx(void *card)
{
struct spec_private *p = (struct spec_private *) card;
int rdr = spec_readl(card, p->vuart_base + UART_REG_HOST_RDR);
if(rdr & UART_HOST_RDR_RDY)
return UART_HOST_RDR_DATA_R(rdr);
else
return -1;
}
static void vuart_tx(void *card, int c)
{
struct spec_private *p = (struct spec_private *) card;
while( spec_readl(card, p->vuart_base + UART_REG_SR) & UART_SR_RX_RDY);
spec_writel(card, UART_HOST_TDR_DATA_W(c),
p->vuart_base + UART_REG_HOST_TDR);
}
static char *load_binary_file(const char *filename, size_t *size)
{
int i;
struct stat stbuf;
char *buf;
FILE *f;
f = fopen(filename, "r");
if (!f) {
fprintf(stderr, "%s: %s\n", filename, strerror(errno));
return NULL;
}
if (fstat(fileno(f), &stbuf) < 0) {
fprintf(stderr, "%s: %s\n", filename, strerror(errno));
fclose(f);
return NULL;
}
if (!S_ISREG(stbuf.st_mode)) {
fprintf(stderr, "%s: not a regular file\n", filename);
fclose(f);
return NULL;
}
buf = malloc(stbuf.st_size);
if (!buf) {
fprintf(stderr, "loading %s: %s\n", filename, strerror(errno));
fclose(f);
return NULL;
i = fread(buf, 1, stbuf.st_size, f);
fclose(f);
if (i < 0) {
fprintf(stderr, "reading %s: %s\n", filename, strerror(errno));
free(buf);
return NULL;
}
if (i != stbuf.st_size) {
fprintf(stderr, "%s: short read\n", filename);
free(buf);
return NULL;
}
*size = stbuf.st_size;
return buf;
}
int spec_load_bitstream_buffer(void *card, void *buf, size_t size)
struct spec_private *p = (struct spec_private *) card;
int rv;
rv = loader_low_level(0, p->bar4, buf, size);
waitdone_low_level(0, p->bar4);
gpiofix_low_level(0, p->bar4);
return rv;
}
int spec_load_bitstream(void *card, const char *filename)
{
char *buf;
size_t size;
buf = load_binary_file(filename, &size);
if(!buf)
return -1;
rv = spec_load_bitstream_buffer(card, buf, size);
free(buf);
return rv;
}
int spec_load_lm32(void *card, const char *filename, uint32_t base_addr)
{
char *buf;
uint32_t *ibuf;
size_t size;
int i;
buf = load_binary_file(filename, &size);
if(!buf)
return -1;
/* Phew... we are there, finally */
spec_writel(card, 0x1deadbee, base_addr + 0x20400);
while ( ! (spec_readl(card, base_addr + 0x20400) & (1<<28)) );
ibuf = (uint32_t *) buf;
for (i = 0; i < (size + 3) / 4; i++)
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
spec_writel(card, htonl(ibuf[i]), base_addr + i*4);
sync();
for (i = 0; i < (size + 3) / 4; i++) {
uint32_t r = spec_readl(card, base_addr + i * 4);
if (r != htonl(ibuf[i]))
{
fprintf(stderr, "programming error at %x "
"(expected %08x, found %08x)\n", i*4,
htonl(ibuf[i]), r);
return -1;
}
}
sync();
spec_writel(card, 0x0deadbee, base_addr + 0x20400);
return 0;
}
int spec_vuart_init(void *card, uint32_t base_addr)
{
struct spec_private *p = (struct spec_private *) card;
p->vuart_base = base_addr;
return 0;
}
size_t spec_vuart_rx(void *card, char *buffer, size_t size)
{
size_t s = size, n_rx = 0;
while(s--)
{
int c = vuart_rx(card);
if(c < 0)
return n_rx;
*buffer++ = c;
n_rx ++;
}
return n_rx;
}
size_t spec_vuart_tx(void *card, char *buffer, size_t size)
{
size_t s = size;
while(s--)
vuart_tx(card, *buffer++);
return size;
}