Commit 437380ff authored by Steffen Vogel's avatar Steffen Vogel 🎅🏼

move more code to VILLAScommon repo

parent 4a05d63e
Subproject commit 1783a79c1a39f9f4f20f97a3c6adfb80b8cf760e
Subproject commit dd7d75d0aab3801d65f9ff757d82f47f705514af
/** Static server configuration
*
* This file contains some compiled-in settings.
* This settings are not part of the configuration file.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#pragma once
#ifndef V
#define V 2
#endif
/* Paths */
#define PLUGIN_PATH PREFIX "/share/villas/node/plugins"
#define WEB_PATH PREFIX "/share/villas/node/web"
#define SYSFS_PATH "/sys"
#define PROCFS_PATH "/proc"
/** Default number of values in a sample */
#define DEFAULT_SAMPLELEN 64
#define DEFAULT_QUEUELEN 1024
/** Number of hugepages which are requested from the the kernel.
* @see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt */
#define DEFAULT_NR_HUGEPAGES 100
/** Width of log output in characters */
#define LOG_WIDTH 80
#define LOG_HEIGHT 25
/** Socket priority */
#define SOCKET_PRIO 7
/* Protocol numbers */
#define IPPROTO_VILLAS 137
#define ETH_P_VILLAS 0xBABE
#define USER_AGENT "VILLASfpga (" BUILDID ")"
/* Required kernel version */
#define KERNEL_VERSION_MAJ 3
#define KERNEL_VERSION_MIN 6
/** PCIe BAR number of VILLASfpga registers */
#define FPGA_PCI_BAR 0
#define FPGA_PCI_VID_XILINX 0x10ee
#define FPGA_PCI_PID_VFPGA 0x7022
/** AXI Bus frequency for all components
* except RTDS AXI Stream bridge which runs at RTDS_HZ (100 Mhz) */
#define FPGA_AXI_HZ 125000000 // 125 MHz
......@@ -36,12 +36,12 @@
#include <jansson.h>
#include <villas/plugin.hpp>
#include <villas/config.h>
#include <villas/memory.hpp>
#include <villas/kernel/pci.h>
#include <villas/kernel/vfio.hpp>
#include <villas/fpga/config.h>
#include <villas/fpga/ip.hpp>
#define PCI_FILTER_DEFAULT_FPGA { \
......
/** Logging routines that depend on jansson.
/** Compile time configuration
*
* This file contains some compiled-in settings.
* This settings are not part of the configuration file.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
......@@ -23,15 +26,11 @@
#pragma once
struct log;
#include <jansson.h>
#include <villas/log.h>
/** Parse logging configuration. */
int log_parse(struct log *l, json_t *cfg);
/** PCIe BAR number of VILLASfpga registers */
#define FPGA_PCI_BAR 0
#define FPGA_PCI_VID_XILINX 0x10ee
#define FPGA_PCI_PID_VFPGA 0x7022
/** Print configuration error and exit. */
void jerror(json_error_t *err, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
/** AXI Bus frequency for all components
* except RTDS AXI Stream bridge which runs at RTDS_HZ (100 Mhz) */
#define FPGA_AXI_HZ 125000000 // 125 MHz
......@@ -32,8 +32,7 @@
#include <cstdint>
#include <xilinx/xtmrctr.h>
#include <villas/config.h>
#include <villas/fpga/config.h>
#include <villas/fpga/ip.hpp>
namespace villas {
......
/** Linux kernel related functions.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
/** @addtogroup fpga Kernel @{ */
#pragma once
#include <string.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Forward declarations */
struct version;
//#include <sys/capability.h>
/** Check if current process has capability \p cap.
*
* @retval 0 If capabilty is present.
* @retval <0 If capability is not present.
*/
//int kernel_check_cap(cap_value_t cap);
/** Get number of reserved hugepages. */
int kernel_get_nr_hugepages();
/** Set number of reserved hugepages. */
int kernel_set_nr_hugepages(int nr);
/** Get kernel cmdline parameter
*
* See https://www.kernel.org/doc/Documentation/kernel-parameters.txt
*
* @param param The cmdline parameter to look for.
* @param buf The string buffer to which the parameter value will be copied to.
* @param len The length of the buffer \p value
* @retval 0 Parameter \p key was found and value was copied to \p value
* @reval <>0 Kernel was not booted with parameter \p key
*/
int kernel_get_cmdline_param(const char *param, char *buf, size_t len);
/** Get the version of the kernel. */
int kernel_get_version(struct version *v);
/** Checks if a kernel module is loaded
*
* @param module the name of the module
* @retval 0 Module is loaded.
* @reval <>0 Module is not loaded.
*/
int kernel_module_loaded(const char *module);
/** Load kernel module via modprobe */
int kernel_module_load(const char *module);
/** Set parameter of loaded kernel module */
int kernel_module_set_param(const char *module, const char *param, const char *value);
/** Get cacheline size in bytes */
int kernel_get_cacheline_size();
/** Get the size of a standard page in bytes. */
int kernel_get_page_size();
/** Get the size of a huge page in bytes. */
int kernel_get_hugepage_size();
/** Set SMP affinity of IRQ */
int kernel_irq_setaffinity(unsigned irq, uintmax_t affinity, uintmax_t *old);
#ifdef __cplusplus
}
#endif
/** @} */
/** Linux PCI helpers
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2018, Steffen Vogel
**********************************************************************************/
/** @addtogroup fpga Kernel @{ */
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <villas/list.h>
#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
#define PCI_FUNC(devfn) ((devfn) & 0x07)
#ifdef __cplusplus
extern "C" {
#endif
struct pci_device {
struct {
int vendor;
int device;
int class_code;
} id;
struct {
int domain;
int bus;
int device;
int function;
} slot; /**< Bus, Device, Function (BDF) */
};
struct pci_region {
int num;
uintptr_t start;
uintptr_t end;
unsigned long long flags;
};
struct pci {
struct list devices; /**< List of available PCI devices in the system (struct pci_device) */
};
/** Initialize Linux PCI handle.
*
* This search for all available PCI devices under /sys/bus/pci
*
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
int pci_init(struct pci *p);
/** Destroy handle. */
int pci_destroy(struct pci *p);
int pci_device_parse_slot(struct pci_device *f, const char *str, const char **error);
int pci_device_parse_id(struct pci_device *f, const char *str, const char **error);
int pci_device_compare(const struct pci_device *d, const struct pci_device *f);
struct pci_device * pci_lookup_device(struct pci *p, struct pci_device *filter);
/** Get currently loaded driver for device */
int pci_get_driver(const struct pci_device *d, char *buf, size_t buflen);
/** Bind a new LKM to the PCI device */
int pci_attach_driver(const struct pci_device *d, const char *driver);
/** Return the IOMMU group of this PCI device or -1 if the device is not in a group. */
int pci_get_iommu_group(const struct pci_device *d);
size_t pci_get_regions(const struct pci_device *d, struct pci_region** regions);
#ifdef __cplusplus
}
#endif
/** @} */
/** Virtual Function IO wrapper around kernel API
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @author Daniel Krebs <github@daniel-krebs.net>
* @copyright 2017-2018, Steffen Vogel
* @copyright 2018, Daniel Krebs
*********************************************************************************/
/** @addtogroup fpga Kernel @{ */
#pragma once
#include <list>
#include <vector>
#include <memory>
#include <linux/vfio.h>
#include <sys/mman.h>
#define VFIO_PATH "/dev/vfio/"
#define VFIO_DEV VFIO_PATH "vfio"
/* Forward declarations */
struct pci_device;
namespace villas {
class VfioContainer;
class VfioGroup;
class VfioDevice {
friend class VfioContainer;
public:
VfioDevice(const std::string& name, VfioGroup& group) :
name(name), group(group) {}
~VfioDevice();
bool reset();
/** Map a device memory region to the application address space (e.g. PCI BARs) */
void* regionMap(size_t index);
/** munmap() a region which has been mapped by vfio_map_region() */
bool regionUnmap(size_t index);
/** Get the size of a device memory region */
size_t regionGetSize(size_t index);
/** Enable memory accesses and bus mastering for PCI device */
bool pciEnable();
bool pciHotReset();
int pciMsiInit(int efds[32]);
int pciMsiDeinit(int efds[32]);
bool pciMsiFind(int nos[32]);
bool isVfioPciDevice() const;
private:
/// Name of the device as listed under
/// /sys/kernel/iommu_groups/[vfio_group::index]/devices/
std::string name;
/// VFIO device file descriptor
int fd;
struct vfio_device_info info;
std::vector<struct vfio_irq_info> irqs;
std::vector<struct vfio_region_info> regions;
std::vector<void*> mappings;
/**< libpci handle of the device */
const struct pci_device *pci_device;
VfioGroup& group; /**< The VFIO group this device belongs to */
};
class VfioGroup {
friend class VfioContainer;
friend VfioDevice;
private:
VfioGroup(int index) : fd(-1), index(index) {}
public:
~VfioGroup();
static std::unique_ptr<VfioGroup>
attach(VfioContainer& container, int groupIndex);
private:
/// VFIO group file descriptor
int fd;
/// Index of the IOMMU group as listed under /sys/kernel/iommu_groups/
int index;
/// Status of group
struct vfio_group_status status;
/// All devices owned by this group
std::list<std::unique_ptr<VfioDevice>> devices;
VfioContainer* container; /**< The VFIO container to which this group is belonging */
};
class VfioContainer {
private:
VfioContainer();
public:
~VfioContainer();
static std::shared_ptr<VfioContainer>
create();
void dump();
VfioDevice& attachDevice(const char *name, int groupIndex);
VfioDevice& attachDevice(const struct pci_device *pdev);
/**
* @brief Map VM to an IOVA, which is accessible by devices in the container
* @param virt virtual address of memory
* @param phys IOVA where to map @p virt, -1 to use VFIO internal allocator
* @param length size of memory region in bytes
* @return IOVA address, UINTPTR_MAX on failure
*/
uintptr_t memoryMap(uintptr_t virt, uintptr_t phys, size_t length);
/** munmap() a region which has been mapped by vfio_map_region() */
bool memoryUnmap(uintptr_t phys, size_t length);
bool isIommuEnabled() const
{ return this->hasIommu; }
const int& getFd() const
{ return fd; }
private:
VfioGroup& getOrAttachGroup(int index);
private:
int fd;
int version;
int extensions;
uint64_t iova_next; /**< Next free IOVA address */
bool hasIommu;
/// All groups bound to this container
std::list<std::unique_ptr<VfioGroup>> groups;
};
/** @} */
} // namespace villas
/** A generic list implementation.
*
* This is a generic implementation of a list which can store void pointers to
* arbitrary data. The data itself is not stored or managed by the list.
*
* Internally, an array of pointers is used to store the pointers.
* If needed, this array will grow by realloc().
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC
*********************************************************************************/
#pragma once
#include <stdbool.h>
#include <pthread.h>
#include <villas/common.h>
#define LIST_CHUNKSIZE 16
/** Static list initialization */
#define LIST_INIT() { \
.array = NULL, \
.length = 0, \
.capacity = 0, \
.lock = PTHREAD_MUTEX_INITIALIZER, \
.state = STATE_INITIALIZED \
}
#define LIST_INIT_STATIC(l) \
__attribute__((constructor(105))) static void UNIQUE(__ctor)() {\
if ((l)->state == STATE_DESTROYED) \
list_init(l); \
} \
__attribute__((destructor(105))) static void UNIQUE(__dtor)() { \
list_destroy(l, NULL, false); \
}
#define list_length(list) ((list)->length)
#define list_at_safe(list, index) ((list)->length > index ? (list)->array[index] : NULL)
#define list_at(list, index) ((list)->array[index])
#define list_first(list) list_at(list, 0)
#define list_last(list) list_at(list, (list)->length-1)
#ifdef __cplusplus
extern "C" {
#endif
/** Callback to destroy list elements.
*
* @param data A pointer to the data which should be freed.
*/
typedef int (*dtor_cb_t)(void *);
/** Callback to search or sort a list. */
typedef int (*cmp_cb_t)(const void *, const void *);
/* The list data structure. */
struct list {
void **array; /**< Array of pointers to list elements */
size_t capacity; /**< Size of list::array in elements */
size_t length; /**< Number of elements of list::array which are in use */
pthread_mutex_t lock; /**< A mutex to allow thread-safe accesses */
enum state state; /**< The state of this list. */
};
/** Initialize a list.
*
* @param l A pointer to the list data structure.
*/
int list_init(struct list *l);
/** Destroy a list and call destructors for all list elements
*
* @param free free() all list members during when calling list_destroy()
* @param dtor A function pointer to a desctructor which will be called for every list item when the list is destroyed.
* @param l A pointer to the list data structure.
*/
int list_destroy(struct list *l, dtor_cb_t dtor, bool free);
/** Append an element to the end of the list */
void list_push(struct list *l, void *p);
/** Remove all occurences of a list item */
void list_remove(struct list *l, void *p);
/** Return the first list element which is identified by a string in its first member variable.
*
* List elements are pointers to structures of the following form:
*
* struct obj {
* char *name;
* // more members
* }
*
* @see Only possible because of §1424 of http://c0x.coding-guidelines.com/6.7.2.1.html
*/
void * list_lookup(struct list *l, const char *name);
/** Return the first element of the list for which cmp returns zero */
void * list_search(struct list *l, cmp_cb_t cmp, void *ctx);
/** Returns the number of occurences for which cmp returns zero when called on all list elements. */
int list_count(struct list *l, cmp_cb_t cmp, void *ctx);
/** Return 0 if list contains pointer p */
int list_contains(struct list *l, void *p);
/** Sort the list using the quicksort algorithm of libc */
void list_sort(struct list *l, cmp_cb_t cmp);
/** Set single element in list */
int list_set(struct list *l, int index, void *value);
#ifdef __cplusplus
}
#endif
/** Logging and debugging routines
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdarg.h>
#include <time.h>
#include <sys/ioctl.h>
#include <villas/common.h>
#include <villas/log_config.h>
#ifdef __GNUC__
#define INDENT int __attribute__ ((__cleanup__(log_outdent), unused)) _old_indent = log_indent(1);
#define NOINDENT int __attribute__ ((__cleanup__(log_outdent), unused)) _old_indent = log_noindent();
#else
#define INDENT ;
#define NOINDENT ;
#endif
/* The log level which is passed as first argument to print() */
#define LOG_LVL_DEBUG CLR_GRY("Debug")
#define LOG_LVL_INFO CLR_WHT("Info ")
#define LOG_LVL_WARN CLR_YEL("Warn ")
#define LOG_LVL_ERROR CLR_RED("Error")
#define LOG_LVL_STATS CLR_MAG("Stats")
/** Debug facilities.
*
* To be or-ed with the debug level
*/
enum log_facilities {
LOG_POOL = (1L << 8),
LOG_QUEUE = (1L << 9),
LOG_CONFIG = (1L << 10),
LOG_HOOK = (1L << 11),
LOG_PATH = (1L << 12),
LOG_NODE = (1L << 13),
LOG_MEM = (1L << 14),
LOG_WEB = (1L << 15),
LOG_API = (1L << 16),
LOG_LOG = (1L << 17),
LOG_VFIO = (1L << 18),
LOG_PCI = (1L << 19),
LOG_XIL = (1L << 20),
LOG_TC = (1L << 21),
LOG_IF = (1L << 22),
LOG_ADVIO = (1L << 23),
/* Node-types */
LOG_SOCKET = (1L << 24),
LOG_FILE = (1L << 25),
LOG_FPGA = (1L << 26),
LOG_NGSI = (1L << 27),
LOG_WEBSOCKET = (1L << 28),
LOG_OPAL = (1L << 30),
/* Classes */
LOG_NODES = LOG_NODE | LOG_SOCKET | LOG_FILE | LOG_FPGA | LOG_NGSI | LOG_WEBSOCKET | LOG_OPAL,
LOG_KERNEL = LOG_VFIO | LOG_PCI | LOG_TC | LOG_IF,
LOG_ALL = ~0xFF
};
struct log {
enum state state;
struct timespec epoch; /**< A global clock used to prefix the log messages. */
struct winsize window; /**< Size of the terminal window. */
int width; /**< The real usable log output width which fits into one line. */
/** Debug level used by the debug() macro.
* It defaults to V (defined by the Makefile) and can be
* overwritten by the 'debug' setting in the configuration file. */
int level;
long facilities; /**< Debug facilities used by the debug() macro. */
const char *path; /**< Path of the log file. */
char *prefix; /**< Prefix each line with this string. */
int syslog; /**< Whether or not to log to syslogd. */
FILE *file; /**< Send all log output to this file / stdout / stderr. */
};
/** The global log instance. */
extern struct log *global_log;
extern struct log default_log;
/** Initialize log object */
int log_init(struct log *l, int level, long faciltities);
int log_start(struct log *l);
int log_stop(struct log *l);
/** Destroy log object */
int log_destroy(struct log *l);
/** Change log indention for current thread.
*
* The argument level can be negative!
*/
int log_indent(int levels);
/** Disable log indention of current thread. */
int log_noindent();
/** A helper function the restore the previous log indention level.
*
* This function is usually called by a __cleanup__ handler (GCC C Extension).
* See INDENT macro.
*/
void log_outdent(int *);
/** Set logging facilities based on expression.
*
* Currently we support two types of expressions:
* 1. A comma seperated list of logging facilities
* 2. A comma seperated list of logging facilities which is prefixes with an exclamation mark '!'
*
* The first case enables only faciltities which are in the list.
* The second case enables all faciltities with exception of those which are in the list.
*
* @param expression The expression
* @return The new facilties mask (see enum log_faciltities)
*/
int log_set_facility_expression(struct log *l, const char *expression);
/** Logs variadic messages to stdout.
*
* @param lvl The log level