PCIe driver: Clean-up + add intermediate library between driver and AcquisitionDevice

This commit is contained in:
2023-10-16 18:50:23 +02:00
parent 2fd8d38782
commit faca7a3f15
27 changed files with 545 additions and 440 deletions
+34 -170
View File
@@ -1,29 +1,19 @@
// Copyright (2019-2023) Paul Scherrer Institute
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <thread>
#include "PCIExpressDevice.h"
#include "../fpga/pcie_driver/jfjoch_ioctl.h"
#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("/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)
: FPGAAcquisitionDevice(data_stream) {
fd = open(device_name.c_str(), O_RDWR);
if (fd == -1)
throw JFJochException(JFJochExceptionCategory::PCIeError, "Cannot open device");
: FPGAAcquisitionDevice(data_stream), dev(device_name, true) {
DataCollectionStatus status = dev.GetDataCollectionStatus();
ActionStatus status{};
GetStatus_Internal(&status);
max_modules = status.max_modules;
if (max_modules == 0)
throw JFJochException(JFJochExceptionCategory::PCIeError, "Max modules cannot be zero");
@@ -37,229 +27,103 @@ PCIExpressDevice::PCIExpressDevice(const std::string &device_name, uint16_t data
buffer_device.resize(num_buf, nullptr);
try {
for (int i = 0; i < num_buf; i++)
buffer_device[i] = MapKernelBuffer(i);
buffer_device[i] = dev.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;
return dev.ReadWorkCompletion(values);
}
void PCIExpressDevice::Cancel() {
if (ioctl(fd, IOCTL_JFJOCH_CANCEL) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError,
"Failed setting cancel bit", errno);
dev.Cancel();
}
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;
return dev.SendWorkRequest(handle);
}
void PCIExpressDevice::FPGA_StartAction(const DiffractionExperiment &experiment) {
if (ioctl(fd, IOCTL_JFJOCH_START) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed starting action", errno);
dev.Start();
if (experiment.IsUsingInternalPacketGen()) {
FrameGeneratorConfig config{};
config.frames = experiment.GetFrameNum() + DELAY_FRAMES_STOP_AND_QUIT + 1;
config.modules = experiment.GetModulesNum(data_stream);
if (ioctl(fd, IOCTL_JFJOCH_GET_MAC, &config.dest_mac_addr) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError,
"Failed getting MAC address", errno);
if (ioctl(fd, IOCTL_JFJOCH_GET_IPV4, &config.dest_ipv4_addr) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError,
"Failed getting MAC address", errno);
if (ioctl(fd, IOCTL_JFJOCH_RUN_FRAME_GEN, &config) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed starting frame generator", errno);
config.dest_mac_addr = dev.GetMACAddress();
config.dest_ipv4_addr = dev.GetIPv4Address();
dev.RunFrameGenerator(config);
}
}
void PCIExpressDevice::FPGA_EndAction() {
if (ioctl(fd, IOCTL_JFJOCH_END) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError,
"Failed ending action", errno);
dev.End();
}
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;
return dev.IsIdle();
}
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_WriteActionRegister(const DataCollectionConfig *config) {
dev.SetConfig(*config);
}
void PCIExpressDevice::HW_ReadActionRegister(ActionConfig *config) {
if (ioctl(fd, IOCTL_JFJOCH_READ_CONFIG, config) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError,
"Failed reading config", errno);
void PCIExpressDevice::HW_ReadActionRegister(DataCollectionConfig *config) {
*config = dev.GetConfig();
}
std::string PCIExpressDevice::GetMACAddress() const {
uint64_t tmp;
if (ioctl(fd, IOCTL_JFJOCH_GET_MAC, &tmp) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError,
"Failed getting MAC address", errno);
return MacAddressToStr(tmp);
return MacAddressToStr(dev.GetMACAddress());
}
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);
dev.SetMACAddress(mac_addr_network_order);
}
void PCIExpressDevice::HW_GetStatus(ActionStatus *status) const {
GetStatus_Internal(status);
void PCIExpressDevice::HW_GetStatus(DataCollectionStatus *status) const {
*status = dev.GetDataCollectionStatus();
}
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);
void PCIExpressDevice::HW_GetEnvParams(DeviceStatus *status) const {
*status = dev.GetDeviceStatus();
}
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);
return dev.GetBufferCount();
}
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;
return dev.GetNumaNode();
}
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::SetDefaultMAC() {
dev.SetDefaultMACAddress();
}
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);
dev.SetIPv4Address(ipv4_addr_network_order);
}
std::string PCIExpressDevice::GetIPv4Address() const {
uint32_t tmp;
if (ioctl(fd, IOCTL_JFJOCH_GET_IPV4, &tmp) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError,
"Failed getting MAC address", errno);
return IPv4AddressToStr(tmp);
return IPv4AddressToStr(dev.GetIPv4Address());
}
void PCIExpressDevice::HW_LoadCalibration(uint32_t in_modules, uint32_t in_storage_cells) {
ActionConfig config{
.nmodules = in_modules,
.nstorage_cells = in_storage_cells
};
if (ioctl(fd, IOCTL_JFJOCH_LOAD_CALIB, &config) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed uploading calibration", errno);
dev.LoadCalibration(in_modules, in_storage_cells);
}
void PCIExpressDevice::HW_LoadIntegrationMap(uint32_t in_modules) {
ActionConfig config{
.nmodules = in_modules,
};
if (ioctl(fd, IOCTL_JFJOCH_LOAD_INT_MAP, &config) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed uploading integration map", errno);
dev.LoadIntegrationMap(in_modules);
}
uint32_t PCIExpressDevice::GetCompletedDescriptors() const {
uint32_t ret = 0;
if (ioctl(fd, IOCTL_JFJOCH_C2H_DMA_DESC, &ret) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed geting C2H completed descriptor count", errno);
return ret;
}
uint32_t PCIExpressDevice::ReadRegister(uint32_t addr) const {
RegisterConfig config;
config.addr = addr;
if (ioctl(fd, IOCTL_JFJOCH_READ_REGISTER, &config) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed reading register", errno);
return config.val;
}
void PCIExpressDevice::WriteRegister(uint32_t addr, uint32_t val) {
RegisterConfig config{.addr = addr, .val = val};
if (ioctl(fd, IOCTL_JFJOCH_WRITE_REGISTER, &config) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed writing to register", errno);
return dev.GetCompletedDescriptors();
}
void PCIExpressDevice::HW_LoadInternalGeneratorFrame(uint32_t in_modules) {
ActionConfig config{
.nmodules = in_modules
};
if (ioctl(fd, IOCTL_JFJOCH_LOAD_INT_GEN, &config) != 0)
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed uploading internal generator frame", errno);
dev.LoadInternalGeneratorFrame(in_modules);
}