Commit 634e2215 authored by Daniel Krebs's avatar Daniel Krebs

kernel/vfio: port to C++

This commit is 1/2 of a series of patches and not working on its own.
parent 72299cf2
......@@ -35,7 +35,7 @@
#include "common.h"
#include "kernel/pci.h"
#include "kernel/vfio.h"
#include "kernel/vfio.hpp"
#include <list>
#include <string>
......@@ -91,8 +91,11 @@ public:
struct pci *pci;
struct pci_device filter; /**< Filter for PCI device. */
::vfio_container *vfio_container;
struct vfio_device vfio_device; /**< VFIO device handle. */
/// The VFIO container that this card is part of
std::shared_ptr<VfioContainer> vfioContainer;
/// The VFIO device that represents this card
VfioDevice* vfioDevice;
/// Address space identifier of the master address space of this FPGA card.
/// This will be used for address resolution of all IPs on this card.
......@@ -116,7 +119,7 @@ public:
Plugin(Plugin::Type::FpgaCard, "FPGA Card plugin") {}
static CardList
make(json_t *json, struct pci* pci, ::vfio_container* vc);
make(json_t *json, struct pci* pci, std::shared_ptr<VfioContainer> vc);
static PCIeCard*
create();
......
/** Virtual Function IO wrapper around kernel API
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Steffen Vogel
*********************************************************************************/
/** @addtogroup fpga Kernel @{ */
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <sys/mman.h>
#include <linux/vfio.h>
#include <linux/pci_regs.h>
#include "list.h"
#define VFIO_DEV(x) "/dev/vfio/" x
#ifdef __cplusplus
extern "C" {
#endif
/* Forward declarations */
struct pci_device;
struct vfio_group {
int fd; /**< VFIO group file descriptor */
int index; /**< Index of the IOMMU group as listed under /sys/kernel/iommu_groups/ */
struct vfio_group_status status; /**< Status of group */
struct list devices;
struct vfio_container *container; /**< The VFIO container to which this group is belonging */
};
struct vfio_device {
char *name; /**< Name of the device as listed under /sys/kernel/iommu_groups/[vfio_group::index]/devices/ */
int fd; /**< VFIO device file descriptor */
struct vfio_device_info info;
struct vfio_irq_info *irqs;
struct vfio_region_info *regions;
void **mappings;
struct pci_device *pci_device; /**< libpci handle of the device */
struct vfio_group *group; /**< The VFIO group this device belongs to */
};
struct vfio_container {
int fd;
int version;
int extensions;
uint64_t iova_next; /**< Next free IOVA address */
struct list groups;
};
/** Initialize a new VFIO container. */
int vfio_init(struct vfio_container *c);
/** Initialize a VFIO group and attach it to an existing VFIO container. */
int vfio_group_attach(struct vfio_group *g, struct vfio_container *c, int index);
/** Initialize a VFIO device, lookup the VFIO group it belongs to, create the group if not already existing. */
int vfio_device_attach(struct vfio_device *d, struct vfio_container *c, const char *name, int index);
/** Initialie a VFIO-PCI device (uses vfio_device_attach() internally) */
int vfio_pci_attach(struct vfio_device *d, struct vfio_container *c, struct pci_device *pdev);
/** Hot resets a VFIO-PCI device */
int vfio_pci_reset(struct vfio_device *d);
int vfio_pci_msi_init(struct vfio_device *d, int efds[32]);
int vfio_pci_msi_deinit(struct vfio_device *d, int efds[32]);
int vfio_pci_msi_find(struct vfio_device *d, int nos[32]);
/** Enable memory accesses and bus mastering for PCI device */
int vfio_pci_enable(struct vfio_device *d);
/** Reset a VFIO device */
int vfio_device_reset(struct vfio_device *d);
/** Release memory and close container */
int vfio_destroy(struct vfio_container *c);
/** Release memory of group */
int vfio_group_destroy(struct vfio_group *g);
/** Release memory of device */
int vfio_device_destroy(struct vfio_device *g);
/** Print a dump of all attached groups and their devices including regions and IRQs */
void vfio_dump(struct vfio_container *c);
/** Map a device memory region to the application address space (e.g. PCI BARs) */
void * vfio_map_region(struct vfio_device *d, int idx);
/** Get the size of a device memory region */
size_t vfio_region_size(struct vfio_device *d, int idx);
/** Map VM to an IOVA, which is accessible by devices in the container */
int vfio_map_dma(struct vfio_container *c, uint64_t virt, uint64_t phys, size_t len);
/** Unmap DMA memory */
int vfio_unmap_dma(struct vfio_container *c, uint64_t virt, uint64_t phys, size_t len);
/** munmap() a region which has been mapped by vfio_map_region() */
int vfio_unmap_region(struct vfio_device *d, int idx);
#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, 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_DEV(x) "/dev/vfio/" x
/* 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(int containerFd, 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);
private:
VfioGroup& getOrAttachGroup(int index);
private:
int fd;
int version;
int extensions;
uint64_t iova_next; /**< Next free IOVA address */
/// All groups bound to this container
std::list<std::unique_ptr<VfioGroup>> groups;
};
/** @} */
} // namespace villas
set(SOURCES
ip.c
vlnv.c
card.c
vlnv.cpp
card.cpp
ip.cpp
ip_node.cpp
ips/timer.c
ips/model.c
ips/switch.c
ips/dft.c
ips/fifo.c
ips/dma.c
ips/intc.c
ips/gpio.c
ips/rtds_axis.c
ips/timer.cpp
ips/switch.cpp
ips/fifo.cpp
......@@ -26,9 +12,8 @@ set(SOURCES
kernel/kernel.c
kernel/pci.c
kernel/vfio.c
kernel/vfio.cpp
plugin.c
utils.c
list.c
log.c
......
......@@ -27,7 +27,7 @@
#include "log.hpp"
#include "kernel/pci.h"
#include "kernel/vfio.h"
#include "kernel/vfio.hpp"
#include "fpga/ip.hpp"
#include "fpga/card.hpp"
......@@ -38,9 +38,8 @@ namespace fpga {
// instantiate factory to register
static PCIeCardFactory PCIeCardFactory;
CardList
fpga::PCIeCardFactory::make(json_t *json, struct pci* pci, ::vfio_container* vc)
PCIeCardFactory::make(json_t *json, struct pci* pci, std::shared_ptr<VfioContainer> vc)
{
CardList cards;
auto logger = getStaticLogger();
......@@ -73,7 +72,7 @@ fpga::PCIeCardFactory::make(json_t *json, struct pci* pci, ::vfio_container* vc)
// populate generic properties
card->name = std::string(card_name);
card->pci = pci;
card->vfio_container = vc;
card->vfioContainer = std::move(vc);
card->affinity = affinity;
card->do_reset = do_reset != 0;
......@@ -158,19 +157,26 @@ fpga::PCIeCard::init()
}
/* Attach PCIe card to VFIO container */
ret = ::vfio_pci_attach(&vfio_device, vfio_container, pdev);
if (ret) {
logger->error("Failed to attach VFIO device");
VfioDevice& device = vfioContainer->attachDevice(pdev);
this->vfioDevice = &device;
/* Enable memory access and PCI bus mastering for DMA */
if (not device.pciEnable()) {
logger->error("Failed to enable PCI device");
return false;
}
/* Map PCIe BAR */
const void* bar0_mapped = vfio_map_region(&vfio_device, VFIO_PCI_BAR0_REGION_INDEX);
const void* bar0_mapped = vfioDevice->regionMap(VFIO_PCI_BAR0_REGION_INDEX);
if (bar0_mapped == MAP_FAILED) {
logger->error("Failed to mmap() BAR0");
return false;
}
// determine size of BAR0 region
const size_t bar0_size = vfioDevice->regionGetSize(VFIO_PCI_BAR0_REGION_INDEX);
/* Link mapped BAR0 to global memory graph */
......@@ -180,9 +186,6 @@ fpga::PCIeCard::init()
// create a new address space for this FPGA card
this->addrSpaceId = MemoryManager::get().getOrCreateAddressSpace(name);
// determine size of BAR0 region
const size_t bar0_size = vfio_region_size(&vfio_device,
VFIO_PCI_BAR0_REGION_INDEX);
// create a mapping from our address space to the FPGA card via vfio
MemoryManager::get().createMapping(reinterpret_cast<uintptr_t>(bar0_mapped),
......@@ -190,18 +193,11 @@ fpga::PCIeCard::init()
villasAddrSpace, this->addrSpaceId);
/* Enable memory access and PCI bus mastering for DMA */
ret = vfio_pci_enable(&vfio_device);
if (ret) {
logger->error("Failed to enable PCI device");
return false;
}
/* Reset system? */
if (do_reset) {
/* Reset / detect PCI device */
ret = vfio_pci_reset(&vfio_device);
if (ret) {
if(not vfioDevice->pciHotReset()) {
logger->error("Failed to reset PCI device");
return false;
}
......
......@@ -27,7 +27,7 @@
#include "log.h"
#include "plugin.hpp"
#include "kernel/vfio.h"
#include "kernel/vfio.hpp"
#include "kernel/kernel.h"
#include "fpga/card.hpp"
......@@ -43,7 +43,7 @@ static InterruptControllerFactory factory;
InterruptController::~InterruptController()
{
vfio_pci_msi_deinit(&card->vfio_device , this->efds);
card->vfioDevice->pciMsiDeinit(this->efds);
}
bool
......@@ -51,12 +51,13 @@ InterruptController::init()
{
const uintptr_t base = getBaseAddr(registerMemory);
num_irqs = vfio_pci_msi_init(&card->vfio_device, efds);
num_irqs = card->vfioDevice->pciMsiInit(efds);
if (num_irqs < 0)
return false;
if(vfio_pci_msi_find(&card->vfio_device, nos) != 0)
if(not card->vfioDevice->pciMsiFind(nos)) {
return false;
}
/* For each IRQ */
for (int i = 0; i < num_irqs; i++) {
......@@ -69,8 +70,8 @@ InterruptController::init()
// everything is fine
break;
case EACCES:
logger->warn("No permission to change affinity of VFIO-MSI interrupt. "
"This may degrade performance (increasing jitter)");
logger->warn("No permission to change affinity of VFIO-MSI interrupt, "
"performance may be degraded!");
break;
default:
logger->error("Failed to change affinity of VFIO-MSI interrupt");
......
This diff is collapsed.
This diff is collapsed.
......@@ -24,9 +24,9 @@
#include <criterion/criterion.h>
#include <villas/utils.h>
#include <villas/fpga/ip.h>
#include <villas/fpga/card.h>
#include <villas/fpga/vlnv.h>
#include <villas/fpga/ip.hpp>
#include <villas/fpga/card.hpp>
#include <villas/fpga/vlnv.hpp>
#include "global.hpp"
......@@ -40,7 +40,6 @@
#define FPGA_AXI_HZ 125000000
static struct pci pci;
static struct vfio_container vc;
FpgaState state;
......@@ -59,8 +58,7 @@ static void init()
ret = pci_init(&pci);
cr_assert_eq(ret, 0, "Failed to initialize PCI sub-system");
ret = vfio_init(&vc);
cr_assert_eq(ret, 0, "Failed to initiliaze VFIO sub-system");
auto vfioContainer = villas::VfioContainer::create();
/* Parse FPGA configuration */
f = fopen(TEST_CONFIG, "r");
......@@ -81,7 +79,7 @@ static void init()
villas::fpga::PCIeCardFactory* fpgaCardPlugin = dynamic_cast<villas::fpga::PCIeCardFactory*>(plugin);
// create all FPGA card instances using the corresponding plugin
state.cards = fpgaCardPlugin->make(fpgas, &pci, &vc);
state.cards = fpgaCardPlugin->make(fpgas, &pci, vfioContainer);
cr_assert(state.cards.size() != 0, "No FPGA cards found!");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment