diff --git a/common/include/villas/kernel/devices/pci_device.hpp b/common/include/villas/kernel/devices/pci_device.hpp index 65794644b..8f6a10cf5 100644 --- a/common/include/villas/kernel/devices/pci_device.hpp +++ b/common/include/villas/kernel/devices/pci_device.hpp @@ -15,6 +15,8 @@ #include +#include + namespace villas { namespace kernel { namespace devices { @@ -58,7 +60,11 @@ struct Region { unsigned long long flags; }; -class PciDevice { +class PciDevice : public Device { +private: + static constexpr char PROBE_DEFAULT[] = "/sys/bus/pci/drivers_probe"; + static constexpr char OVERRIDE_DEFAULT[] = "driver_override"; + public: PciDevice(Id i, Slot s) : id(i), slot(s), log(Log::get("kernel:pci")) {} @@ -68,15 +74,17 @@ class PciDevice { bool operator==(const PciDevice &other); - // Get currently loaded driver for device - std::string getDriver() const; + // Implement device interface + std::optional> driver() const override; + std::optional iommu_group() const override; + std::string name() const override; + std::filesystem::path override_path() const override; + std::filesystem::path path() const override; + void probe() const override; // Bind a new LKM to the PCI device bool attachDriver(const std::string &driver) const; - // Return the IOMMU group of this PCI device or -1 if the device is not in a group - int getIommuGroup() const; - std::list getRegions() const; // Write 32-bit BAR value from to the PCI configuration space diff --git a/common/lib/kernel/devices/pci_device.cpp b/common/lib/kernel/devices/pci_device.cpp index ef8a8b5d0..2324c6013 100644 --- a/common/lib/kernel/devices/pci_device.cpp +++ b/common/lib/kernel/devices/pci_device.cpp @@ -18,10 +18,12 @@ #include #include +#include #include #include using namespace villas::kernel::devices; +using villas::utils::write_to_file; #define PCI_BASE_ADDRESS_N(n) (PCI_BASE_ADDRESS_0 + sizeof(uint32_t) * (n)) @@ -311,8 +313,7 @@ std::list PciDevice::getRegions() const { return regions; } - -std::string PciDevice::getDriver() const { +std::optional> PciDevice::driver() const { int ret; char sysfs[1024], syml[1024]; memset(syml, 0, sizeof(syml)); @@ -323,13 +324,15 @@ std::string PciDevice::getDriver() const { struct stat st; ret = stat(sysfs, &st); if (ret) - return ""; + return std::nullopt; ret = readlink(sysfs, syml, sizeof(syml)); if (ret < 0) throw SystemError("Failed to follow link: {}", sysfs); - return basename(syml); + auto driver = std::make_optional(std::make_unique( + "/sys/bus/pci/drivers/" + std::string(basename(syml)))); + return driver; } bool PciDevice::attachDriver(const std::string &driver) const { @@ -423,7 +426,7 @@ void PciDevice::writeBar(uint32_t addr, unsigned barNum) { file.write(reinterpret_cast(&addr), sizeof(addr)); } -int PciDevice::getIommuGroup() const { +std::optional PciDevice::iommu_group() const { int ret; char *group; @@ -437,11 +440,11 @@ int PciDevice::getIommuGroup() const { ret = readlink(sysfs, link, sizeof(link)); if (ret < 0) - return -1; + return std::nullopt; group = basename(link); - return atoi(group); + return std::make_optional(atoi(group)); } std::fstream PciDevice::openSysFs(const std::string &subPath, @@ -457,3 +460,33 @@ std::fstream PciDevice::openSysFs(const std::string &subPath, return file; } + +// TODO: test +std::string PciDevice::name() const { + char sysfs[1024]; + + snprintf(sysfs, sizeof(sysfs), "%04x:%02x:%02x.%x", slot.domain, slot.bus, + slot.device, slot.function); + + return std::string(sysfs); +} + +// TODO: test +std::filesystem::path PciDevice::path() const { + char sysfs[1024]; + + snprintf(sysfs, sizeof(sysfs), "%04x:%02x:%02x.%x", slot.domain, slot.bus, + slot.device, slot.function); + + return sysfs; +} + +// TODO: test +std::filesystem::path PciDevice::override_path() const { + + return this->path() / OVERRIDE_DEFAULT; +} + +void PciDevice::probe() const { + write_to_file(this->name(), this->PROBE_DEFAULT); +} diff --git a/common/lib/kernel/vfio_container.cpp b/common/lib/kernel/vfio_container.cpp index 76923aa08..595edf9fd 100644 --- a/common/lib/kernel/vfio_container.cpp +++ b/common/lib/kernel/vfio_container.cpp @@ -197,7 +197,7 @@ std::shared_ptr Container::attachDevice(devices::PciDevice &pdev) { throw RuntimeError("Failed to load kernel driver: vfio_pci"); // Bind PCI card to vfio-pci driver if not already bound - if (pdev.getDriver() != kernelDriver) { + if ( !(pdev.driver().has_value()) || pdev.driver().value()->name() != kernelDriver) { log->debug("Bind PCI card to kernel driver '{}'", kernelDriver); pdev.attachDriver(kernelDriver); } @@ -215,7 +215,7 @@ std::shared_ptr Container::attachDevice(devices::PciDevice &pdev) { } // Get IOMMU group of device - int index = isIommuEnabled() ? pdev.getIommuGroup() : 0; + int index = isIommuEnabled() ? pdev.iommu_group().value() : 0; if (index < 0) { ret = kernel::getCmdlineParam("intel_iommu", iommu_state, sizeof(iommu_state)); diff --git a/etc/examples/nodes/miob.conf b/etc/examples/nodes/miob.conf new file mode 100644 index 000000000..381052533 --- /dev/null +++ b/etc/examples/nodes/miob.conf @@ -0,0 +1,62 @@ +# SPDX-FileCopyrightText: 2025 Institute for Automation of Complex Power Systems, RWTH Aachen University +# SPDX-License-Identifier: Apache-2.0 + +logging = { + level = "info" +} + +fpgas = { + zcu106 = { + interface = "platform", + ips = "../../fpga/zcu106-dino/zcu106-dino.json", + #ignore_ips = ["dino_dinoif_dac_0", "dino_dinoif_fast_nologic_0"], # Optionally ignore IPs + polling = true, + } +} + +nodes = { + fpga_0 = { + type = "fpga", + card = "zcu106" + # connect = ["dino<->dma"] # Alternate HW Loopback + connect = ["0<->dma"] # Loopback + lowLatencyMode = false, + }, + + signal_gen_0 = { + type = "signal.v2", + realtime = true, + rate = 2, + in = { + signals = ( + { + name = "sine.v2", + signal = "sine", + frequency = 0.1, + amplitude = 10, + } + ) + }, + } +} + +paths = ( + { + in = "signal_gen_0" + out = "fpga_0" + hooks = ( + { + type = "print" + }) + + }, + { + in = "fpga_0" + hooks = ( + { + type = "print" + } + ) + } +) +