Skip to content

Commit 77d5322

Browse files
feat: vfio automask
Signed-off-by: Pascal Bauer <[email protected]>
1 parent 7f79208 commit 77d5322

File tree

4 files changed

+96
-25
lines changed

4 files changed

+96
-25
lines changed

common/include/villas/kernel/vfio_device.hpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ namespace vfio {
2828

2929
class Device {
3030
public:
31+
struct IrqVectorInfo {
32+
int eventFds[32];
33+
size_t numFds;
34+
bool automask;
35+
};
36+
3137
Device(const std::string &name, int groupFileDescriptor,
3238
const kernel::devices::PciDevice *pci_device = nullptr);
3339
~Device();
@@ -49,6 +55,8 @@ class Device {
4955
// Get the size of a device memory region
5056
size_t regionGetSize(size_t index);
5157

58+
std::vector<IrqVectorInfo> initEventFds();
59+
5260
// Enable memory accesses and bus mastering for PCI device
5361
bool pciEnable();
5462

@@ -86,7 +94,7 @@ class Device {
8694

8795
struct vfio_device_info info;
8896

89-
std::vector<struct vfio_irq_info> irqs;
97+
std::vector<struct vfio_irq_info> info_irq_vectors;
9098
std::vector<struct vfio_region_info> regions;
9199
std::vector<void *> mappings;
92100

common/lib/kernel/vfio_device.cpp

+51-6
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static const char *vfio_pci_irq_names[] = {
5555
Device::Device(const std::string &name, int groupFileDescriptor,
5656
const kernel::devices::PciDevice *pci_device)
5757
: name(name), fd(-1), attachedToGroup(false), groupFd(groupFileDescriptor),
58-
info(), irqs(), regions(), mappings(), pci_device(pci_device),
58+
info(), info_irq_vectors(), regions(), mappings(), pci_device(pci_device),
5959
log(Log::get("kernel:vfio:device")) {
6060
if (groupFileDescriptor < 0)
6161
throw RuntimeError("Invalid group file descriptor");
@@ -81,7 +81,7 @@ Device::Device(const std::string &name, int groupFileDescriptor,
8181
info.num_regions = pci_device != 0 ? VFIO_PCI_CONFIG_REGION_INDEX + 1 : 1;
8282

8383
// Reserve slots already so that we can use the []-operator for access
84-
irqs.resize(info.num_irqs);
84+
info_irq_vectors.resize(info.num_irqs);
8585
regions.resize(info.num_regions);
8686
mappings.resize(info.num_regions);
8787

@@ -120,7 +120,7 @@ Device::Device(const std::string &name, int groupFileDescriptor,
120120
log->debug("irq {} info: flags: 0x{:x}, count: {}", irq.index, irq.flags,
121121
irq.count);
122122

123-
irqs[i] = irq;
123+
info_irq_vectors[i] = irq;
124124
}
125125
}
126126

@@ -212,7 +212,7 @@ void Device::dump() {
212212
}
213213

214214
for (size_t i = 0; i < info.num_irqs; i++) {
215-
struct vfio_irq_info *irq = &irqs[i];
215+
struct vfio_irq_info *irq = &info_irq_vectors[i];
216216

217217
if (irq->count > 0) {
218218
log->info("IRQ {} {}: count={}, flags={}", irq->index,
@@ -247,12 +247,57 @@ bool Device::pciEnable() {
247247
return true;
248248
}
249249

250+
std::vector<Device::IrqVectorInfo> Device::initEventFds() {
251+
std::vector<Device::IrqVectorInfo> vectors;
252+
for (auto info_irq_vector : info_irq_vectors) {
253+
Device::IrqVectorInfo irq = {0};
254+
const size_t irqCount = info_irq_vector.count;
255+
const size_t irqSetSize =
256+
sizeof(struct vfio_irq_set) + sizeof(int) * irqCount;
257+
258+
auto *irqSetBuf = new char[irqSetSize];
259+
if (!irqSetBuf)
260+
throw MemoryAllocationError();
261+
auto *irqSet = reinterpret_cast<struct vfio_irq_set *>(irqSetBuf);
262+
263+
irqSet->argsz = irqSetSize;
264+
// DATA_EVENTFD binds the interrupt to the provided eventfd.
265+
// SET_ACTION_TRIGGER enables kernel->userspace signalling.
266+
irqSet->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
267+
irqSet->index = info_irq_vector.index;
268+
irqSet->start = 0;
269+
irqSet->count = irqCount;
270+
irq.automask = info_irq_vector.flags & VFIO_IRQ_INFO_AUTOMASKED;
271+
irq.numFds = irqCount;
272+
// Now set the new eventfds
273+
for (size_t i = 0; i < irqCount; i++) {
274+
irq.eventFds[i] = eventfd(0, 0);
275+
if (fd < 0) {
276+
delete[] irqSetBuf;
277+
throw std::runtime_error("Event FD could not be created.");
278+
}
279+
eventfdList.push_back(fd);
280+
}
281+
282+
memcpy(irqSet->data, irq.eventFds, sizeof(int) * irqCount);
283+
284+
if (ioctl(fd, VFIO_DEVICE_SET_IRQS, irqSet) != 0) {
285+
delete[] irqSetBuf;
286+
throw std::runtime_error("failed to set irqs");
287+
}
288+
delete[] irqSetBuf;
289+
vectors.push_back(irq);
290+
}
291+
292+
return vectors;
293+
}
294+
250295
int Device::pciMsiInit(int efds[]) {
251296
// Check if this is really a vfio-pci device
252297
if (not isVfioPciDevice())
253298
return -1;
254299

255-
const size_t irqCount = irqs[VFIO_PCI_MSI_IRQ_INDEX].count;
300+
const size_t irqCount = info_irq_vectors[VFIO_PCI_MSI_IRQ_INDEX].count;
256301
const size_t irqSetSize =
257302
sizeof(struct vfio_irq_set) + sizeof(int) * irqCount;
258303

@@ -299,7 +344,7 @@ int Device::pciMsiDeinit(int efds[]) {
299344
if (not isVfioPciDevice())
300345
return -1;
301346

302-
const size_t irqCount = irqs[VFIO_PCI_MSI_IRQ_INDEX].count;
347+
const size_t irqCount = info_irq_vectors[VFIO_PCI_MSI_IRQ_INDEX].count;
303348
const size_t irqSetSize =
304349
sizeof(struct vfio_irq_set) + sizeof(int) * irqCount;
305350

fpga/include/villas/fpga/ips/intc.hpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ class InterruptController : public Core {
5353
bool polling; // Polled or not
5454
};
5555

56-
int num_irqs; // Number of available MSI vectors
57-
int efds[maxIrqs];
56+
std::vector<kernel::vfio::Device::IrqVectorInfo> irq_vectors;
5857
int nos[maxIrqs];
5958
bool polling[maxIrqs];
6059
};

fpga/lib/ips/intc.cpp

+35-16
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
#include <errno.h>
9+
#include <sys/ioctl.h>
910
#include <unistd.h>
1011

1112
#include <villas/config.hpp>
@@ -22,28 +23,30 @@ using namespace villas::fpga::ip;
2223
InterruptController::~InterruptController() {}
2324

2425
bool InterruptController::stop() {
25-
return this->vfioDevice->pciMsiDeinit(this->efds) > 0;
26+
return this->vfioDevice->pciMsiDeinit(irq_vectors[0].eventFds) > 0;
2627
}
2728

2829
bool InterruptController::init() {
29-
const uintptr_t base = getBaseAddr(registerMemory);
30-
3130
PCIeCard *pciecard = dynamic_cast<PCIeCard *>(card);
3231
this->vfioDevice = pciecard->vfioDevice;
3332

34-
num_irqs = this->vfioDevice->pciMsiInit(efds);
35-
if (num_irqs < 0)
36-
return false;
37-
3833
if (not this->vfioDevice->pciMsiFind(nos)) {
3934
return false;
4035
}
4136

37+
const uintptr_t base = getBaseAddr(registerMemory);
38+
kernel::vfio::Device::IrqVectorInfo irq_vector = {0};
39+
irq_vector.numFds = this->vfioDevice->pciMsiInit(irq_vector.eventFds);
40+
irq_vector.automask = true;
41+
irq_vectors.push_back(irq_vector);
42+
43+
if (irq_vector.numFds < 0)
44+
return false;
45+
4246
// For each IRQ
43-
for (int i = 0; i < num_irqs; i++) {
47+
for (size_t i = 0; i < irq_vector.numFds; i++) {
4448

4549
// Try pinning to core
46-
PCIeCard *pciecard = dynamic_cast<PCIeCard *>(card);
4750
int ret = kernel::setIRQAffinity(nos[i], pciecard->affinity, nullptr);
4851

4952
switch (ret) {
@@ -89,7 +92,7 @@ bool InterruptController::enableInterrupt(InterruptController::IrqMaskType mask,
8992
// Clear pending IRQs
9093
XIntc_Out32(base + XIN_IAR_OFFSET, mask);
9194

92-
for (int i = 0; i < num_irqs; i++) {
95+
for (size_t i = 0; i < irq_vectors[0].numFds; i++) {
9396
if (mask & (1 << i))
9497
this->polling[i] = polling;
9598
}
@@ -120,6 +123,7 @@ bool InterruptController::disableInterrupt(
120123
return true;
121124
}
122125

126+
// Assuming only one interrupt vector
123127
ssize_t InterruptController::waitForInterrupt(int irq) {
124128
assert(irq < maxIrqs);
125129

@@ -144,22 +148,37 @@ ssize_t InterruptController::waitForInterrupt(int irq) {
144148
fd_set rfds;
145149
struct timeval tv = {.tv_sec = 1, .tv_usec = 0};
146150
FD_ZERO(&rfds);
147-
FD_SET(efds[irq], &rfds);
151+
FD_SET(irq_vectors[0].eventFds[irq], &rfds);
152+
logger->debug("Waiting for interrupt fd {}", irq_vectors[0].eventFds[irq]);
148153

149-
sret = select(efds[irq] + 1, &rfds, NULL, NULL, &tv);
154+
sret = select(irq_vectors[0].eventFds[irq] + 1, &rfds, NULL, NULL, &tv);
150155
if (sret == -1) {
151156
logger->error("select() failed: {}", strerror(errno));
152157
return -1;
153158
} else if (sret == 0) {
154159
logger->warn("timeout waiting for interrupt {}", irq);
155-
156160
return -1;
157161
}
158-
// Block until there has been an interrupt, read number of interrupts
159-
ssize_t ret = read(efds[irq], &count, sizeof(count));
162+
// Block until there has been an interrupt, read number of interruptsvfio_device
163+
ssize_t ret = read(irq_vectors[0].eventFds[irq], &count, sizeof(count));
160164
if (ret != sizeof(count)) {
161-
logger->error("Failed to read from eventfd: {}", strerror(errno));
165+
logger->error("Read failure on interrupt {}, {}", irq, ret);
162166
return -1;
167+
} else {
168+
logger->debug("Automask: {}", irq_vectors[0].automask);
169+
if (irq_vectors[0].automask) {
170+
struct vfio_irq_set irqSet = {0};
171+
irqSet.argsz = sizeof(struct vfio_irq_set);
172+
irqSet.flags = (VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK);
173+
irqSet.index = 0;
174+
irqSet.start = irq;
175+
irqSet.count = 1;
176+
int ret = ioctl(this->vfioDevice->getFileDescriptor(),
177+
VFIO_DEVICE_SET_IRQS, &irqSet);
178+
if (ret < 0) {
179+
logger->error("Failed to unmask IRQ {}", 0);
180+
}
181+
}
163182
}
164183

165184
return count;

0 commit comments

Comments
 (0)