214 lines
7.4 KiB
C++
214 lines
7.4 KiB
C++
// Copyright (2019-2022) Paul Scherrer Institute
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include "PCIExpressDevice.h"
|
|
#include "../../common/JFJochException.h"
|
|
#include "../pcie_driver/jfjoch_ioctl.h"
|
|
#include <thread>
|
|
#include "../../common/NetworkAddressConvert.h"
|
|
|
|
PCIExpressDevice::PCIExpressDevice(uint16_t data_stream, uint16_t pci_slot) :
|
|
PCIExpressDevice("/dev/jfjoch" + std::to_string(pci_slot), data_stream) {
|
|
|
|
}
|
|
PCIExpressDevice::PCIExpressDevice(uint16_t data_stream) :
|
|
PCIExpressDevice("/dev/jfjoch" + std::to_string(data_stream), data_stream) {}
|
|
|
|
PCIExpressDevice::PCIExpressDevice(const std::string &device_name, uint16_t data_stream)
|
|
: AcquisitionDevice(data_stream) {
|
|
fd = open(device_name.c_str(), O_RDWR);
|
|
if (fd == -1)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Cannot open device");
|
|
|
|
ActionStatus status{};
|
|
GetStatus_Internal(&status);
|
|
max_modules = status.max_modules;
|
|
if (max_modules == 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Max modules cannot be zero");
|
|
|
|
uint32_t num_buf = GetNumKernelBuffers();
|
|
|
|
if (num_buf < max_modules * (3 + 3 * 16) + 2)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Need to increase number of host-device buffers");
|
|
|
|
buffer_device.resize(num_buf, nullptr);
|
|
try {
|
|
for (int i = 0; i < num_buf; i++)
|
|
buffer_device[i] = MapKernelBuffer(i);
|
|
} catch (JFJochException &e) {
|
|
UnmapBuffers();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
PCIExpressDevice::~PCIExpressDevice() {
|
|
close(fd);
|
|
}
|
|
|
|
uint16_t *PCIExpressDevice::MapKernelBuffer(uint32_t n_buf) {
|
|
auto tmp = (uint16_t *) mmap(nullptr, FPGA_BUFFER_LOCATION_SIZE,
|
|
PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
fd, FPGA_BUFFER_LOCATION_SIZE * n_buf);
|
|
|
|
if (tmp == nullptr)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Mmap of kernel buffer error: "
|
|
+ std::string(strerror(errno)));
|
|
|
|
return tmp;
|
|
}
|
|
|
|
bool PCIExpressDevice::HW_ReadMailbox(uint32_t *values) {
|
|
int tmp = ioctl(fd, IOCTL_JFJOCH_READ_WC_MBOX, values);
|
|
|
|
if (tmp != 0) {
|
|
if (errno == EAGAIN)
|
|
return false;
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed receiving work completion", errno);
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
Completion PCIExpressDevice::ReadCompletion() {
|
|
uint32_t values[12];
|
|
while (!HW_ReadMailbox(values)) {
|
|
// The receive FIFO level is less than or equal to the RIT threshold
|
|
std::this_thread::sleep_for(std::chrono::microseconds(10));
|
|
}
|
|
return parse_hw_completion(values);
|
|
}
|
|
|
|
void PCIExpressDevice::HW_SetCancelDataCollectionBit() {
|
|
if (ioctl(fd, IOCTL_JFJOCH_CANCEL) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed setting cancel bit", errno);
|
|
}
|
|
|
|
bool PCIExpressDevice::HW_SendWorkRequest(uint32_t handle) {
|
|
int tmp = ioctl(fd, IOCTL_JFJOCH_SEND_WR, &handle);
|
|
if (tmp != 0) {
|
|
if (errno == EAGAIN)
|
|
return false;
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed sending work request", errno);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void PCIExpressDevice::HW_StartAction() {
|
|
if (ioctl(fd, IOCTL_JFJOCH_START) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed starting action", errno);
|
|
}
|
|
|
|
void PCIExpressDevice::HW_EndAction() {
|
|
if (ioctl(fd, IOCTL_JFJOCH_END) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed ending action", errno);
|
|
}
|
|
|
|
bool PCIExpressDevice::HW_IsIdle() const {
|
|
uint32_t tmp;
|
|
if (ioctl(fd, IOCTL_JFJOCH_ISIDLE, &tmp) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed checking if idle", errno);
|
|
return tmp;
|
|
}
|
|
|
|
void PCIExpressDevice::HW_WriteActionRegister(const ActionConfig *config) {
|
|
if (ioctl(fd, IOCTL_JFJOCH_SET_CONFIG, config) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed writing config", errno);
|
|
}
|
|
|
|
void PCIExpressDevice::HW_ReadActionRegister(ActionConfig *config) {
|
|
if (ioctl(fd, IOCTL_JFJOCH_READ_CONFIG, config) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed reading config", errno);
|
|
}
|
|
|
|
uint64_t PCIExpressDevice::HW_GetMACAddress() const {
|
|
uint64_t tmp;
|
|
if (ioctl(fd, IOCTL_JFJOCH_GET_MAC, &tmp) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed getting MAC address", errno);
|
|
return tmp;
|
|
}
|
|
|
|
void PCIExpressDevice::SetMACAddress(uint64_t mac_addr_network_order) {
|
|
if (ioctl(fd, IOCTL_JFJOCH_SET_MAC, &mac_addr_network_order) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed setting MAC address", errno);
|
|
}
|
|
|
|
void PCIExpressDevice::HW_GetStatus(ActionStatus *status) const {
|
|
GetStatus_Internal(status);
|
|
}
|
|
|
|
void PCIExpressDevice::GetStatus_Internal(ActionStatus *status) const {
|
|
if (ioctl(fd, IOCTL_JFJOCH_STATUS, status) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed reading status", errno);
|
|
}
|
|
|
|
void PCIExpressDevice::HW_GetEnvParams(ActionEnvParams *status) const {
|
|
if (ioctl(fd, IOCTL_JFJOCH_GET_ENV_DATA, status) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed reading env. data", errno);
|
|
}
|
|
|
|
uint32_t PCIExpressDevice::GetNumKernelBuffers() const {
|
|
uint32_t tmp;
|
|
if (ioctl(fd, IOCTL_JFJOCH_BUF_COUNT, &tmp) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed reading env. data", errno);
|
|
return tmp;
|
|
}
|
|
|
|
void PCIExpressDevice::Reset() {
|
|
if (ioctl(fd, IOCTL_JFJOCH_RESET) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed reset", errno);
|
|
}
|
|
|
|
int32_t PCIExpressDevice::GetNUMANode() const {
|
|
int32_t tmp;
|
|
if (ioctl(fd, IOCTL_JFJOCH_NUMA, &tmp) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed reading NUMA node", errno);
|
|
return tmp;
|
|
}
|
|
|
|
void PCIExpressDevice::ClearNetworkCounters() {
|
|
if (ioctl(fd, IOCTL_JFJOCH_CLR_CNTRS) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed clearing network counters", errno);
|
|
}
|
|
|
|
void PCIExpressDevice::SetDefaultMAC() const {
|
|
if (ioctl(fd, IOCTL_JFJOCH_DEFAULT_MAC) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed setting default MAC", errno);
|
|
}
|
|
|
|
void PCIExpressDevice::SetIPv4Address(uint32_t ipv4_addr_network_order) {
|
|
if (ioctl(fd, IOCTL_JFJOCH_SET_IPV4, &ipv4_addr_network_order) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed setting IPv4 address", errno);
|
|
}
|
|
|
|
uint32_t PCIExpressDevice::HW_GetIPv4Address() const {
|
|
uint32_t tmp;
|
|
if (ioctl(fd, IOCTL_JFJOCH_GET_IPV4, &tmp) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError,
|
|
"Failed getting MAC address", errno);
|
|
return tmp;
|
|
}
|