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

this fixes that the wrong order of allocating and PciCard destruction causes an undefined state. Signed-off-by: Niklas Eiling <niklas.eiling@eonerc.rwth-aachen.de>
129 lines
3.5 KiB
C++
129 lines
3.5 KiB
C++
/** FPGA card
|
|
*
|
|
* This class represents a FPGA device.
|
|
*
|
|
* Author: Steffen Vogel <post@steffenvogel.de>
|
|
* Author: Daniel Krebs <github@daniel-krebs.net>
|
|
* SPDX-FileCopyrightText: 2017 Institute for Automation of Complex Power
|
|
* Systems, EONERC SPDX-License-Identifier: Apache-2.0
|
|
*********************************************************************************/
|
|
|
|
#include <villas/fpga/card.hpp>
|
|
|
|
using namespace villas;
|
|
using namespace villas::fpga;
|
|
|
|
Card::~Card()
|
|
{
|
|
// Ensure IP destructors are called before memory is unmapped
|
|
ips.clear();
|
|
|
|
auto &mm = MemoryManager::get();
|
|
|
|
// Unmap all memory blocks
|
|
for (auto &mappedMemoryBlock : memoryBlocksMapped) {
|
|
auto translation = mm.getTranslation(addrSpaceIdDeviceToHost, mappedMemoryBlock.first);
|
|
|
|
const uintptr_t iova = translation.getLocalAddr(0);
|
|
const size_t size = translation.getSize();
|
|
|
|
logger->debug("Unmap block {} at IOVA {:#x} of size {:#x}",
|
|
mappedMemoryBlock.first, iova, size);
|
|
vfioContainer->memoryUnmap(iova, size);
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<ip::Core> Card::lookupIp(const std::string &name) const
|
|
{
|
|
for(auto &ip : ips) {
|
|
if(*ip == name) {
|
|
return ip;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
std::shared_ptr<ip::Core> Card::lookupIp(const Vlnv &vlnv) const
|
|
{
|
|
for(auto &ip : ips) {
|
|
if(*ip == vlnv) {
|
|
return ip;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
std::shared_ptr<ip::Core> Card::lookupIp(const ip::IpIdentifier &id) const
|
|
{
|
|
for (auto &ip : ips) {
|
|
if (*ip == id) {
|
|
return ip;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool Card::unmapMemoryBlock(const MemoryBlock& block)
|
|
{
|
|
if (memoryBlocksMapped.find(block.getAddrSpaceId()) == memoryBlocksMapped.end()) {
|
|
throw std::runtime_error("Block " + std::to_string(block.getAddrSpaceId()) + " is not mapped but was requested to be unmapped.");
|
|
}
|
|
|
|
auto &mm = MemoryManager::get();
|
|
|
|
auto translation = mm.getTranslation(addrSpaceIdDeviceToHost, block.getAddrSpaceId());
|
|
|
|
const uintptr_t iova = translation.getLocalAddr(0);
|
|
const size_t size = translation.getSize();
|
|
|
|
logger->debug("Unmap block {} at IOVA {:#x} of size {:#x}",
|
|
block.getAddrSpaceId(), iova, size);
|
|
vfioContainer->memoryUnmap(iova, size);
|
|
|
|
memoryBlocksMapped.erase(block.getAddrSpaceId());
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Card::mapMemoryBlock(const std::shared_ptr<MemoryBlock> block)
|
|
{
|
|
if (not vfioContainer->isIommuEnabled()) {
|
|
logger->warn("VFIO mapping not supported without IOMMU");
|
|
return false;
|
|
}
|
|
|
|
auto &mm = MemoryManager::get();
|
|
const auto &addrSpaceId = block->getAddrSpaceId();
|
|
|
|
if (memoryBlocksMapped.find(addrSpaceId) != memoryBlocksMapped.end())
|
|
// Block already mapped
|
|
return true;
|
|
else
|
|
logger->debug("Create VFIO mapping for {}", addrSpaceId);
|
|
|
|
auto translationFromProcess = mm.getTranslationFromProcess(addrSpaceId);
|
|
uintptr_t processBaseAddr = translationFromProcess.getLocalAddr(0);
|
|
uintptr_t iovaAddr = vfioContainer->memoryMap(processBaseAddr,
|
|
UINTPTR_MAX,
|
|
block->getSize());
|
|
|
|
if (iovaAddr == UINTPTR_MAX) {
|
|
logger->error("Cannot map memory at {:#x} of size {:#x}",
|
|
processBaseAddr, block->getSize());
|
|
return false;
|
|
}
|
|
|
|
mm.createMapping(iovaAddr, 0, block->getSize(),
|
|
"VFIO-D2H",
|
|
this->addrSpaceIdDeviceToHost,
|
|
addrSpaceId);
|
|
|
|
// Remember that this block has already been mapped for later
|
|
memoryBlocksMapped.insert({addrSpaceId, block});
|
|
|
|
return true;
|
|
}
|