1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00
VILLASnode/fpga/lib/ips/pcie.cpp
Steffen Vogel 3d73c759ea Reformat all code with clang-format
Signed-off-by: Steffen Vogel <post@steffenvogel.de>
2024-02-29 19:34:27 +01:00

141 lines
4.7 KiB
C++

/* AXI PCIe bridge
*
* Author: Daniel Krebs <github@daniel-krebs.net>
* SPDX-FileCopyrightText: 2018 Institute for Automation of Complex Power Systems, RWTH Aachen University
* SPDX-License-Identifier: Apache-2.0
*/
#include <jansson.h>
#include <limits>
#include <villas/exceptions.hpp>
#include <villas/memory.hpp>
#include <villas/fpga/card.hpp>
#include <villas/fpga/ips/pcie.hpp>
#include <villas/fpga/pcie_card.hpp>
using namespace villas::fpga::ip;
bool AxiPciExpressBridge::init() {
auto &mm = MemoryManager::get();
// Throw an exception if the is no bus master interface and thus no
// address space we can use for translation -> error
card->addrSpaceIdHostToDevice = busMasterInterfaces.at(axiInterface);
// Map PCIe BAR0 via VFIO
const void *bar0_mapped =
card->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 =
card->vfioDevice->regionGetSize(VFIO_PCI_BAR0_REGION_INDEX);
// Create a mapping from process address space to the FPGA card via vfio
mm.createMapping(reinterpret_cast<uintptr_t>(bar0_mapped), 0, bar0_size,
"vfio-h2d", mm.getProcessAddressSpace(),
card->addrSpaceIdHostToDevice);
// Make PCIe (IOVA) address space available to FPGA via BAR0
// IPs that can access this address space will know it via their memory view
const auto addrSpaceNameDeviceToHost =
mm.getSlaveAddrSpaceName(getInstanceName(), pcieMemory);
// Save ID in card so we can create mappings later when needed (e.g. when
// allocating DMA memory in host RAM)
card->addrSpaceIdDeviceToHost =
mm.getOrCreateAddressSpace(addrSpaceNameDeviceToHost);
auto pciAddrSpaceId = mm.getPciAddressSpace();
auto regions = dynamic_cast<PCIeCard *>(card)->pdev->getRegions();
int i = 0;
for (auto region : regions) {
const size_t region_size = region.end - region.start + 1;
char barName[] = "BARx";
barName[3] = '0' + region.num;
auto pciBar = pcieToAxiTranslations.at(barName);
logger->info("PCI-BAR{}: bus addr={:#x} size={:#x}", region.num,
region.start, region_size);
logger->info("PCI-BAR{}: AXI translation offset {:#x}", i,
pciBar.translation);
mm.createMapping(region.start, pciBar.translation, region_size,
std::string("PCI-") + barName, pciAddrSpaceId,
card->addrSpaceIdHostToDevice);
}
for (auto &[barName, axiBar] : axiToPcieTranslations) {
logger->info("AXI-{}: bus addr={:#x} size={:#x}", barName, axiBar.base,
axiBar.size);
logger->info("AXI-{}: PCI translation offset: {:#x}", barName,
axiBar.translation);
auto barXAddrSpaceName =
mm.getSlaveAddrSpaceName(getInstanceName(), barName);
auto barXAddrSpaceId = mm.getOrCreateAddressSpace(barXAddrSpaceName);
// Base is already incorporated into mapping of each IP by Vivado, so
// the mapping src has to be 0
mm.createMapping(0, axiBar.translation, axiBar.size,
std::string("AXI-") + barName, barXAddrSpaceId,
pciAddrSpaceId);
i++;
}
return true;
}
void AxiPciExpressBridgeFactory::parse(Core &ip, json_t *cfg) {
CoreFactory::parse(ip, cfg);
auto logger = getLogger();
auto &pcie = dynamic_cast<AxiPciExpressBridge &>(ip);
for (auto barType : std::list<std::string>{"axi_bars", "pcie_bars"}) {
json_t *json_bars = json_object_get(cfg, barType.c_str());
if (not json_is_object(json_bars))
throw ConfigError(cfg, "", "Missing BAR config: {}", barType);
json_t *json_bar;
const char *bar_name;
json_object_foreach(json_bars, bar_name, json_bar) {
unsigned int translation;
json_error_t err;
int ret = json_unpack_ex(json_bar, &err, 0, "{ s: i }", "translation",
&translation);
if (ret != 0)
throw ConfigError(json_bar, err, "", "Cannot parse {}/{}", barType,
bar_name);
if (barType == "axi_bars") {
json_int_t base, high, size;
int ret =
json_unpack_ex(json_bar, &err, 0, "{ s: I, s: I, s: I }",
"baseaddr", &base, "highaddr", &high, "size", &size);
if (ret != 0)
throw ConfigError(json_bar, err, "", "Cannot parse {}/{}", barType,
bar_name);
pcie.axiToPcieTranslations[bar_name] = {
.base = static_cast<uintptr_t>(base),
.size = static_cast<size_t>(size),
.translation = translation};
} else
pcie.pcieToAxiTranslations[bar_name] = {.translation = translation};
}
}
}
static AxiPciExpressBridgeFactory p;