mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-23 00:00:01 +01:00

This edits the headers in every file so the copyright notice mentions RWTH Aachen University. We also update some copyright years and fix various comments so the header is the same across all of VILLASframework. * Harmonize comment and code-style Signed-off-by: Steffen Vogel <steffen.vogel@opal-rt.com> * Harmonize comment and code-style Signed-off-by: Steffen Vogel <steffen.vogel@opal-rt.com> --------- Signed-off-by: Steffen Vogel <steffen.vogel@opal-rt.com>
150 lines
4.5 KiB
C++
150 lines
4.5 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 <limits>
|
|
#include <jansson.h>
|
|
|
|
#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;
|