uhd/host/lib/usrp/b300/b300_pcie_session_linux.cpp
Virendra Kakade 3716dd0884 b300: depend on installed nib310rio.h for Linux PCIe support
Remove the vendored copy of nib310rio.h from the inchworm tree and
replace it with a build-time dependency on the header installed by
the nib310rio-dev package:

    /usr/include/nib310rio/nib310rio.h

CMake now searches for this header before registering the B300
component. On Linux, if the header is absent, B300 support is
silently skipped with a status message pointing to the missing
package. If the user explicitly passes -DENABLE_B300=ON without
the header present, CMake fails with a clear error.

Update the two Linux-only include sites to use the system path:

    #include <nib310rio/nib310rio.h>

This makes the build-time dependency on the kernel driver explicit
and removes the risk of the vendored copy drifting out of sync with
the installed driver.

Signed-off-by: Virendra Kakade <virendra.kakade@ni.com>
2026-08-23 00:17:02 +02:00

212 lines
6.3 KiB
C++

// Copyright 2025 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
#include "./inchworm/user/libnifpga-usrp/src/DeviceFile.h"
#include "./inchworm/user/libnifpga-usrp/src/Exception.h"
#include "./inchworm/user/libnifpga-usrp/src/SysfsFile.h"
#include "./inchworm/user/libnifpga-usrp/src/Timer.h"
#include "b300_regs.hpp"
#include <uhd/config.h>
#include <uhd/exception.hpp>
#include <uhd/utils/log.hpp>
#include <uhdlib/usrp/b300/b300_pcie_fifo.hpp>
#include <uhdlib/usrp/b300/b300_pcie_session.hpp>
#include <fcntl.h>
#include <nib310rio/nib310rio.h>
#include <system_error>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <memory>
#include <mutex>
using namespace uhd::usrp::b300;
namespace {
// Error map for B300 PCIe session, similar to alreadyErrnoMap in Session.cpp
const class : public nirio::ErrnoMap
{
public:
void throwErrno(const int error) const final
{
// Add any B300-specific error handling here if needed
nirio::ErrnoMap::throwErrno(error);
}
} b300ErrnoMap;
// FIFO info structure
struct fifo_info_t
{
std::string name;
uint32_t number;
bool is_write;
};
// Define the available FIFOs (based on the kernel driver definition)
const std::vector<fifo_info_t> fifo_infos = {
{"input_rfnoc_control", 0, false},
{"input_streamer1", 1, false},
{"input_streamer2", 2, false},
{"input_streamer3", 3, false},
{"input_streamer4", 4, false},
{"output_rfnoc_control", 5, true},
{"output_streamer1", 6, true},
{"output_streamer2", 7, true},
{"output_streamer3", 8, true},
{"output_streamer4", 9, true},
};
} // namespace
class b300_pcie_session_impl : public b300_pcie_session
{
public:
b300_pcie_session_impl(const std::string& device)
: _device(device), _device_path(nirio::DeviceFile::getCdevPath(device))
{
_devfile = std::make_unique<nirio::DeviceFile>(
_device_path, nirio::DeviceFile::ReadWrite, b300ErrnoMap);
_devfile->mapMemory(B300_BAR0_MAP_SIZE);
}
~b300_pcie_session_impl()
{
close(false);
}
void close(bool UHD_UNUSED(reset_if_last_session) = false) final
{
std::lock_guard<std::mutex> lock(_mutex);
UHD_LOG_TRACE("B300", "Closing PCIe session");
_devfile.reset();
// Release all FIFOs
for (auto& fifo_pair : _fifos) {
try {
fifo_pair.second->stop();
} catch (const std::exception& ex) {
UHD_LOG_WARNING("B300",
"Error stopping FIFO " << fifo_pair.first << ": " << ex.what());
}
}
_fifos.clear();
}
b300_pcie_fifo::sptr create_rx_fifo(uint32_t fifo_num) final
{
return create_fifo(fifo_num, false);
}
b300_pcie_fifo::sptr create_tx_fifo(uint32_t fifo_num) final
{
return create_fifo(fifo_num, true);
}
std::string get_resource() const final
{
return _device_path;
}
std::vector<std::pair<uint32_t, std::pair<std::string, bool>>>
get_fifo_info() const final
{
std::vector<std::pair<uint32_t, std::pair<std::string, bool>>> result;
for (const auto& info : fifo_infos) {
result.push_back({info.number, {info.name, info.is_write}});
}
return result;
}
uint32_t peek32(uint32_t addr) final
{
struct ioctl_nib310rio_reg32 xfer = {addr, 0};
_devfile->ioctl(NIB310RIO_IOC_PEEK32, &xfer);
return xfer.value;
}
void poke32(uint32_t addr, uint32_t value) final
{
struct ioctl_nib310rio_reg32 xfer = {addr, value};
_devfile->ioctl(NIB310RIO_IOC_POKE32, &xfer);
}
uint64_t peek64(uint32_t addr) final
{
struct ioctl_nib310rio_reg64 xfer = {addr, 0};
_devfile->ioctl(NIB310RIO_IOC_PEEK64, &xfer);
return xfer.value;
}
void poke64(uint32_t addr, uint64_t value) final
{
struct ioctl_nib310rio_reg64 xfer = {addr, value};
_devfile->ioctl(NIB310RIO_IOC_POKE64, &xfer);
}
void fifo_ioctl(UHD_UNUSED(uint32_t control_code), UHD_UNUSED(void* buffer)) final
{
// Linux implementation stub - not used since Linux uses nirio::Fifo directly
UHD_LOG_WARNING(
"B300", "fifo_ioctl called on Linux - this is a Windows-only method");
}
uint32_t get_session_count() final
{
auto session_count = nirio::SysfsFile(_device, "session_count").readU32();
return session_count;
}
private:
b300_pcie_fifo::sptr create_fifo(uint32_t fifo_num, bool is_write)
{
std::lock_guard<std::mutex> lock(_mutex);
// Check if FIFO already exists
auto fifo_it = _fifos.find(fifo_num);
if (fifo_it != _fifos.end()) {
return fifo_it->second;
}
// Validate FIFO number and direction
bool found = false;
for (const auto& info : fifo_infos) {
if (info.number == fifo_num) {
if (info.is_write != is_write) {
UHD_LOG_THROW(uhd::runtime_error,
"B300",
"FIFO " + std::to_string(fifo_num)
+ " direction mismatch: requested " + (is_write ? "TX" : "RX")
+ " but FIFO is " + (info.is_write ? "TX" : "RX"));
}
found = true;
break;
}
}
if (!found) {
UHD_LOG_THROW(uhd::runtime_error,
"B300",
"Invalid FIFO number: " + std::to_string(fifo_num));
}
// Create the FIFO
try {
auto fifo = b300_pcie_fifo::make(fifo_num, _device, is_write);
_fifos[fifo_num] = fifo;
return fifo;
} catch (const std::exception& ex) {
UHD_LOG_THROW(uhd::runtime_error,
"B300",
std::string("Failed to create FIFO ") + std::to_string(fifo_num) + ": "
+ ex.what());
}
}
const std::string _device;
std::string _device_path;
std::unique_ptr<nirio::DeviceFile> _devfile;
std::unordered_map<uint32_t, b300_pcie_fifo::sptr> _fifos;
std::mutex _mutex;
};
b300_pcie_session::sptr b300_pcie_session::make(const std::string& device)
{
return std::make_shared<b300_pcie_session_impl>(device);
}