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 {
void *bar0;
void *bar4;
uint32_t vuart_base;
/*
* 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, found = 0;
int my_bus, my_devfn;
n = scandir("/sys/bus/pci/drivers/spec", &namelist, 0, 0);
if (n < 0)
{
perror("scandir");
exit(-1);
} else {
Tomasz Wlostowski
committed
{
if(!found && sscanf(namelist[n]->d_name,
"0000:%02x:%02x.0",
&my_bus, &my_devfn) == 2)
Tomasz Wlostowski
committed
{
if(*bus < 0) *bus = my_bus;
if(*devfn < 0) *devfn = my_devfn;
if(*bus == my_bus && *devfn == my_devfn)
found = 1;
}
free(namelist[n]);
Tomasz Wlostowski
committed
free(namelist);
}
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/drivers/spec"
"/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
if((int)ptr == -1)
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, strerror(errno));
free(buf);
return NULL;
}
*size = stbuf.st_size;
return buf;
}
int spec_load_bitstream(void *card, const char *filename)
{
struct spec_private *p = (struct spec_private *) card;
char *buf;
size_t size;
buf = load_binary_file(filename, &size);
if(!buf)
return -1;
int rv = loader_low_level(0, p->bar4, 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++)
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
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;
}