// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include #include #include #include #include "../pcie_driver/jfjoch_fpga.h" #include "../pcie_driver/jfjoch_ioctl.h" #include "JungfraujochDevice.h" JungfraujochDevice::JungfraujochDevice(const std::string &device_name, bool write_access) { fd = open(device_name.c_str(), write_access ? O_RDWR : O_RDONLY); if (fd == -1) { if (errno == EBUSY) throw std::runtime_error("Device already opened"); else if (errno == EACCES) throw std::runtime_error("Permission denied"); else throw std::runtime_error("Cannot open device"); } auto action_release = GetRevision(); if (action_release != JFJOCH_FPGA_REVISION) throw std::runtime_error("Mismatch of FPGA revision between driver and library"); } JungfraujochDevice::~JungfraujochDevice() { close(fd); } void JungfraujochDevice::Start() { if (ioctl(fd, IOCTL_JFJOCH_START) != 0) throw std::runtime_error("Failed starting action"); } void JungfraujochDevice::Cancel() { if (ioctl(fd, IOCTL_JFJOCH_CANCEL) != 0) throw std::runtime_error("Failed setting cancel bit"); } void JungfraujochDevice::End() { if (ioctl(fd, IOCTL_JFJOCH_END) != 0) throw std::runtime_error("Failed ending action"); } bool JungfraujochDevice::IsIdle() const { uint32_t tmp; if (ioctl(fd, IOCTL_JFJOCH_ISIDLE, &tmp) != 0) throw std::runtime_error("Failed checking if idle"); return tmp; } DataCollectionStatus JungfraujochDevice::GetDataCollectionStatus() const { DataCollectionStatus ret{}; if (ioctl(fd, IOCTL_JFJOCH_STATUS, &ret) != 0) throw std::runtime_error("Failed reading status"); return ret; } DataCollectionConfig JungfraujochDevice::GetConfig() const { DataCollectionConfig ret{}; if (ioctl(fd, IOCTL_JFJOCH_READ_CONFIG, &ret) != 0) throw std::runtime_error("Failed reading config"); return ret; } DeviceStatus JungfraujochDevice::GetDeviceStatus() const { DeviceStatus ret{}; if (ioctl(fd, IOCTL_JFJOCH_GET_DEV_STATUS, &ret) != 0) throw std::runtime_error("Failed reading env. data"); return ret; } void JungfraujochDevice::ClearNetworkCounters() { if (ioctl(fd, IOCTL_JFJOCH_CLR_CNTRS) != 0) throw std::runtime_error("Failed clearing network counters"); } void JungfraujochDevice::Reset() { } uint32_t JungfraujochDevice::GetNumaNode() const { int32_t tmp; if (ioctl(fd, IOCTL_JFJOCH_NUMA, &tmp) != 0) throw std::runtime_error("Failed reading NUMA node"); return tmp; } void JungfraujochDevice::SetConfig(const DataCollectionConfig &config) { if (config.nframes > MAX_FRAMES) throw std::runtime_error("Cannot handle this many frames"); if (ioctl(fd, IOCTL_JFJOCH_SET_CONFIG, &config) != 0) throw std::runtime_error("Failed writing config"); } bool JungfraujochDevice::ReadWorkCompletion(uint32_t *output) { int tmp = ioctl(fd, IOCTL_JFJOCH_READ_WC_MBOX, output); if (tmp != 0) { if ((errno == EAGAIN) || (errno == EINTR)) return false; throw std::runtime_error("Failed receiving work completion"); } return true; } bool JungfraujochDevice::SendWorkRequest(uint32_t id) { int tmp = ioctl(fd, IOCTL_JFJOCH_SEND_WR, &id); if (tmp != 0) { if (errno == EAGAIN) return false; throw std::runtime_error("Failed sending work request"); } return true; } uint32_t JungfraujochDevice::GetBufferCount() const { uint32_t tmp; if (ioctl(fd, IOCTL_JFJOCH_BUF_COUNT, &tmp) != 0) throw std::runtime_error("Failed getting buffer count"); return tmp; } uint64_t JungfraujochDevice::GetMACAddress(uint32_t interface) const { struct FPGAMacAddress tmp{.addr = UINT64_MAX, .if_number = interface}; if (ioctl(fd, IOCTL_JFJOCH_GET_MAC, &tmp) != 0) throw std::runtime_error("Failed getting MAC address"); return tmp.addr; } uint32_t JungfraujochDevice::GetIPv4Address(uint32_t interface) const { struct FPGAIPAddress tmp{.addr = UINT32_MAX, .if_number = interface}; if (ioctl(fd, IOCTL_JFJOCH_GET_IPV4, &tmp) != 0) throw std::runtime_error("Failed getting IPv4 address"); return tmp.addr; } void JungfraujochDevice::SetIPv4Address(uint32_t input, uint32_t interface) { struct FPGAIPAddress tmp{.addr = input, .if_number = interface}; if (ioctl(fd, IOCTL_JFJOCH_SET_IPV4, &tmp) != 0) throw std::runtime_error("Failed setting IPv4 address"); } void JungfraujochDevice::RunFrameGenerator(const FrameGeneratorConfig &config) { if (ioctl(fd, IOCTL_JFJOCH_RUN_FRAME_GEN, &config) != 0) throw std::runtime_error("Failed starting frame generator"); } uint32_t JungfraujochDevice::ReadRegister(uint32_t addr) const { RegisterConfig config; config.addr = addr; if (ioctl(fd, IOCTL_JFJOCH_READ_REGISTER, &config) != 0) throw std::runtime_error("Failed reading register"); return config.val; } void JungfraujochDevice::LoadCalibration(const LoadCalibrationConfig &config) { if (ioctl(fd, IOCTL_JFJOCH_LOAD_CALIB, &config) != 0) throw std::runtime_error("Failed uploading calibration"); } DeviceOutput *JungfraujochDevice::MapKernelBuffer(uint32_t id) { auto tmp = (DeviceOutput *) mmap(nullptr, FPGA_BUFFER_LOCATION_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, FPGA_BUFFER_LOCATION_SIZE * id); if (tmp == MAP_FAILED) throw std::runtime_error("Mmap of kernel buffer error"); return tmp; } void JungfraujochDevice::UnmapKernelBuffer(DeviceOutput *val) { munmap(val, FPGA_BUFFER_LOCATION_SIZE); } void JungfraujochDevice::SetSpotFinderParameters(const SpotFinderParameters& params) { if (ioctl(fd, IOCTL_JFJOCH_SET_SPOTFIN_PAR, ¶ms) != 0) throw std::runtime_error("Failed settings spot finder parameters"); } SpotFinderParameters JungfraujochDevice::GetSpotFinderParameters() { SpotFinderParameters ret{}; if (ioctl(fd, IOCTL_JFJOCH_GET_SPOTFIN_PAR, &ret) != 0) throw std::runtime_error("Failed fetching spot finder parameters"); return ret; } bool JungfraujochDevice::ReadWorkCompletion(JungfraujochDeviceCompletion &completion) { uint32_t tmp = 0; bool ret = ReadWorkCompletion(&tmp); completion.buffer_id = tmp & 0xFFFF; completion.data_collection_id = (tmp >> 16) & 0xFFFF; return ret; } uint32_t JungfraujochDevice::GetRevision() { uint32_t tmp = 0; if (ioctl(fd, IOCTL_JFJOCH_GET_REVISION, &tmp) != 0) throw std::runtime_error("Failed getting data source"); return tmp; } NetworkStatus JungfraujochDevice::GetNetworkStatus(uint32_t interface) { NetworkStatus status{}; status.jfjoch_net_magic = interface; if (ioctl(fd, IOCTL_JFJOCH_NET_STATUS, &status) != 0) throw std::runtime_error("Failed getting network status"); return status; } uint32_t JungfraujochDevice::GetNetworkMode(uint32_t interface) { struct FPGANetworkMode tmp{.mode = UINT32_MAX, .if_number = interface}; if (ioctl(fd, IOCTL_JFJOCH_GET_NET_MODE, &tmp) != 0) throw std::runtime_error("Failed getting network mode"); return tmp.mode; } void JungfraujochDevice::SetNetworkMode(uint32_t mode, uint32_t interface) { struct FPGANetworkMode tmp{.mode = mode, .if_number = interface}; if (ioctl(fd, IOCTL_JFJOCH_SET_NET_MODE, &tmp) != 0) throw std::runtime_error("Failed setting network mode"); } uint8_t JungfraujochDevice::ReadClockConfig(uint8_t addr) { I2COperation operation{ .dev_addr = 0xD0, .reg_addr = addr }; if (ioctl(fd, IOCTL_JFJOCH_I2C_CLK_READ, &operation) != 0) throw std::runtime_error("Failed reading I2C config"); return operation.content; } void JungfraujochDevice::WriteClockConfig(uint8_t addr, uint8_t val) { I2COperation operation{ .dev_addr = 0xD0, .reg_addr = addr, .content = val }; if (ioctl(fd, IOCTL_JFJOCH_I2C_CLK_WRITE, &operation) != 0) throw std::runtime_error("Failed writing I2C config"); }