1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-16 00:00:02 +01:00
VILLASnode/server/src/gtfpga.c

276 lines
6.3 KiB
C
Raw Normal View History

/** Node type: GTFPGA (Xilinx ML507)
*
* This file implements the gtfpga subtype for nodes.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
2015-06-02 21:53:04 +02:00
* @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC
* This file is part of S2SS. All Rights Reserved. Proprietary and confidential.
2015-08-07 01:11:43 +02:00
* Unauthorized copying of this file, via any medium is strictly prohibited.
2015-06-02 21:53:04 +02:00
*********************************************************************************/
2015-05-07 13:04:06 +02:00
2015-06-03 10:13:35 +02:00
#include <stdio.h>
2015-05-07 13:04:06 +02:00
#include <inttypes.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
2015-06-02 21:53:04 +02:00
#include "gtfpga.h"
#include "utils.h"
#include "timing.h"
#define SYSFS_PATH "/sys/bus/pci"
2015-05-07 13:04:06 +02:00
static struct pci_access *pacc;
static void gtfpga_debug(char *msg, ...) {
va_list ap;
va_start(ap, msg);
log_vprint(DEBUG, msg, ap);
va_end(ap);
}
2015-05-07 13:04:06 +02:00
int gtfpga_init(int argc, char * argv[], struct settings *set)
{
pacc = pci_alloc(); /* Get the pci_access structure */
2015-08-22 17:42:38 +02:00
if (!pacc)
error("Failed to allocate PCI access structure");
pci_init(pacc); /* Initialize the PCI library */
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
pacc->error = (log_cb_t) error; /* Replace logging and debug functions */
pacc->warning = (log_cb_t) warn;
pacc->debug = gtfpga_debug;
2015-08-07 01:11:43 +02:00
pci_scan_bus(pacc); /* We want to get the list of devices */
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
return 0;
}
int gtfpga_deinit()
{
pci_cleanup(pacc);
2015-05-07 13:04:06 +02:00
return 0;
}
int gtfpga_parse(config_setting_t *cfg, struct node *n)
{
struct gtfpga *g = alloc(sizeof(struct gtfpga));
2015-05-07 13:04:06 +02:00
const char *slot, *id, *err;
config_setting_t *cfg_slot, *cfg_id;
2015-08-07 01:11:43 +02:00
/* Checks */
if (n->combine != 1) {
config_setting_t *cfg_combine = config_setting_get_member(cfg, "combine");
cerror(cfg_combine, "The GTFPGA node type does not support combining!");
}
pci_filter_init(NULL, &g->filter);
2015-05-07 13:04:06 +02:00
cfg_slot = config_setting_get_member(cfg, "slot");
if (cfg_slot) {
slot = config_setting_get_string(cfg_slot);
if (slot) {
err = pci_filter_parse_slot(&g->filter, (char*) slot);
if (err)
cerror(cfg_slot, "%s", err);
}
else
cerror(cfg_slot, "Invalid slot format");
}
2015-05-07 13:04:06 +02:00
cfg_id = config_setting_get_member(cfg, "id");
if (cfg_id) {
id = config_setting_get_string(cfg_id);
if (id) {
err = pci_filter_parse_id(&g->filter, (char*) id);
if (err)
cerror(cfg_id, "%s", err);
}
else
cerror(cfg_slot, "Invalid id format");
}
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
if (!config_setting_lookup_float(cfg, "rate", &g->rate))
g->rate = 0;
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
n->gtfpga = g;
return 0;
}
int gtfpga_print(struct node *n, char *buf, int len)
{
2015-05-07 13:04:06 +02:00
struct gtfpga *g = n->gtfpga;
if (g->dev) {
return snprintf(buf, len, "rate=%.1f slot=%04"PRIx16":%02"PRIx8":%02"PRIx8".%"PRIx8
" id=%04"PRIx16":%04"PRIx16" class=%04"PRIx16" irq=%d (%s)", g->rate,
g->dev->domain, g->dev->bus, g->dev->dev, g->dev->func, g->dev->vendor_id, g->dev->device_id,
g->dev->device_class, g->dev->irq, g->name);
}
else {
return snprintf(buf, len, "rate=%.1f slot=%02"PRIx8":%02"PRIx8".%"PRIx8" id=%04"PRIx16":%04"PRIx16, g->rate,
g->filter.bus, g->filter.device, g->filter.func,
g->filter.vendor, g->filter.device);
}
}
static int gtfpga_load_driver(struct pci_dev *d)
{
FILE *f;
char slot[16];
int ret;
2015-08-07 01:11:43 +02:00
/* Prepare slot identifier */
snprintf(slot, sizeof(slot), "%04x:%02x:%02x.%x",
2015-05-07 13:04:06 +02:00
d->domain, d->bus, d->dev, d->func);
2015-08-07 01:11:43 +02:00
/* Load uio_pci_generic module */
ret = system2("modprobe uio_pci_generic");
if (ret)
serror("Failed to load module");
2015-08-07 01:11:43 +02:00
/* Add new ID to uio_pci_generic */
f = fopen(SYSFS_PATH "/drivers/uio_pci_generic/new_id", "w");
if (!f)
serror("Failed to add PCI id to uio_pci_generic driver");
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
debug(5, "Adding ID to uio_pci_generic module: %04x %04x", d->vendor_id, d->device_id);
fprintf(f, "%04x %04x", d->vendor_id, d->device_id);
fclose(f);
2015-08-07 01:11:43 +02:00
/* Bind to uio_pci_generic */
f = fopen(SYSFS_PATH "/drivers/uio_pci_generic/bind", "w");
if (!f)
serror("Failed to add PCI id to uio_pci_generic driver");
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
debug(5, "Bind slot to uio_pci_generic module: %s", slot);
fprintf(f, "%s\n", slot);
fclose(f);
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
return 0;
}
static struct pci_dev * gtfpga_find_device(struct pci_filter *f)
{
struct pci_dev *d;
/* Iterate over all devices */
for (d = pacc->devices; d; d = d->next) {
2015-05-07 13:04:06 +02:00
if (pci_filter_match(f, d))
return d;
}
return NULL;
}
2015-05-07 13:04:06 +02:00
static int gtfpga_mmap(struct gtfpga *g)
{
int fd = open("/dev/mem", O_RDWR | O_SYNC);
if (!fd)
serror("Failed open()");
long int addr = g->dev->base_addr[GTFPGA_BAR] & ~0xfff;
int size = g->dev->size[GTFPGA_BAR];
/* mmap() first BAR */
2015-05-07 13:04:06 +02:00
debug(5, "Setup mapping: mmap(NULL, %#x, PROT_READ | PROT_WRITE, MAP_SHARED, %u, %#lx)", size, fd, addr);
void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr);
if (map == MAP_FAILED)
serror("Failed mmap()");
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
return 0;
}
int gtfpga_open(struct node *n)
{
struct gtfpga *g = n->gtfpga;
struct pci_dev *dev;
int ret;
2015-05-07 13:04:06 +02:00
dev = gtfpga_find_device(&g->filter);
if (!dev)
2015-05-07 13:04:06 +02:00
error("No GTFPGA card found");
g->dev = dev;
2015-05-07 13:04:06 +02:00
g->name = alloc(512);
2015-05-07 13:04:06 +02:00
gtfpga_load_driver(dev);
gtfpga_mmap(g);
/* Show some debug infos */
pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); /* Fill in header info we need */
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
g->name = pci_lookup_name(pacc, g->name, 512, PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id);
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
/* Setup timer */
if (g->rate) {
g->fd_irq = timerfd_create(CLOCK_MONOTONIC, 0);
if (g->fd_irq < 0)
serror("Failed to create timer");
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
struct itimerspec its = {
.it_interval = time_from_double(1 / g->rate),
2015-05-07 13:04:06 +02:00
.it_value = { 1, 0 }
};
ret = timerfd_settime(g->fd_irq, 0, &its, NULL);
if (ret)
serror("Failed to start timer");
}
else
/** @todo implement UIO interrupts */
error("UIO irq not implemented yet. Use 'rate' setting");
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
char buf[1024];
gtfpga_print(n, buf, sizeof(buf));
debug(5, "Found GTFPGA card: %s", buf);
2015-08-07 01:11:43 +02:00
return 0;
}
int gtfpga_close(struct node *n)
{
struct gtfpga *g = n->gtfpga;
if (g->map)
munmap(g->map, g->dev->size[GTFPGA_BAR]);
close(g->fd_mmap);
2015-05-07 13:04:06 +02:00
close(g->fd_irq);
free(g->name);
return 0;
}
/** @todo implement */
2015-05-07 13:04:06 +02:00
int gtfpga_read(struct node *n, struct msg *pool, int poolsize, int first, int cnt)
{
struct gtfpga *g = n->gtfpga;
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
struct msg *m = &pool[first % poolsize];
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
uint64_t runs;
read(g->fd_irq, &runs, sizeof(runs));
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
static int seq;
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
m->sequence = seq++;
return 0;
}
/** @todo implement */
2015-05-07 13:04:06 +02:00
int gtfpga_write(struct node *n, struct msg *pool, int poolsize, int first, int cnt)
{
2015-05-07 13:04:06 +02:00
// struct gtfpga *g = n->gtfpga;
2015-08-07 01:11:43 +02:00
2015-05-07 13:04:06 +02:00
// struct msg *m = &pool[first % poolsize];
return 0;
}