Skip to content

Commit 38a1429

Browse files
committed
fix(uio): consider "offset" from sysfs for unaligned UIO nodes
sometimes a UIO node is not aligned to mmap boundary (e.g. 0xA5005040), then sysfs will give an address (0xA5005000) and an offset (0x40). use the address for mmapping and consider the offset for accesses.
1 parent fc43bcc commit 38a1429

File tree

4 files changed

+60
-27
lines changed

4 files changed

+60
-27
lines changed

inc/udmaio/HwAccessor.hpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#pragma once
1313

14+
#include <cstddef>
1415
#include <filesystem>
1516
#include <fstream>
1617
#include <iostream>
@@ -117,7 +118,7 @@ class HwAccessor : public Logger, private boost::noncopyable {
117118
template <typename max_access_width_t>
118119
class HwAccessorMmap : public HwAccessor {
119120
public:
120-
HwAccessorMmap(std::string dev_path, UioRegion region, uintptr_t mmap_offs)
121+
HwAccessorMmap(std::string dev_path, UioRegion region, uintptr_t mmap_offs, size_t access_offs)
121122
: HwAccessor(), _region{region} {
122123
BOOST_LOG_SEV(HwAccessor::_lg, bls::debug) << "dev name = " << dev_path;
123124

@@ -128,28 +129,34 @@ class HwAccessorMmap : public HwAccessor {
128129
BOOST_LOG_SEV(HwAccessor::_lg, bls::trace) << "fd = " << _fd << ", size = " << _region.size;
129130

130131
// create memory mapping
131-
_mem = mmap(NULL, _region.size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, mmap_offs);
132+
_mmap_mem = mmap(NULL, _region.size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, mmap_offs);
133+
_access_mem = static_cast<void*>(static_cast<char*>(_mmap_mem) + access_offs);
134+
132135
BOOST_LOG_SEV(HwAccessor::_lg, bls::trace)
133-
<< "mmap = 0x" << std::hex << mmap_offs << " -> 0x" << _mem << std::dec;
136+
<< "mmap = 0x" << std::hex << mmap_offs << " -> 0x" << _mmap_mem << std::dec;
134137

135-
if (_mem == MAP_FAILED) {
136-
throw std::runtime_error("mmap failed for uio " + dev_path);
138+
if (_mmap_mem == MAP_FAILED) {
139+
throw std::runtime_error("mmap failed for uio " + dev_path + ": " + strerror(errno));
137140
}
141+
142+
BOOST_LOG_SEV(HwAccessor::_lg, bls::trace)
143+
<< "access offs = 0x" << std::hex << access_offs << " -> 0x" << _access_mem << std::dec;
138144
}
139145

140146
virtual ~HwAccessorMmap() {
141-
munmap(_mem, _region.size);
147+
munmap(_mmap_mem, _region.size);
142148
::close(_fd);
143149
}
144150

145151
protected:
146152
int _fd;
147-
void* _mem;
153+
void* _mmap_mem;
154+
void* _access_mem;
148155
const UioRegion _region;
149156

150157
template <typename access_width_t>
151158
inline volatile access_width_t* _mem_ptr(uint32_t offs) const {
152-
return reinterpret_cast<access_width_t*>(static_cast<uint8_t*>(_mem) +
159+
return reinterpret_cast<access_width_t*>(static_cast<uint8_t*>(_access_mem) +
153160
static_cast<ptrdiff_t>(offs));
154161
}
155162

@@ -217,8 +224,12 @@ class HwAccessorMmap : public HwAccessor {
217224
}
218225

219226
public:
220-
UioRegion get_phys_region() const final override { return _region; }
221-
void* get_virt_mem() const final override { return _mem; }
227+
UioRegion get_phys_region() const final override {
228+
const size_t access_offs =
229+
static_cast<uint8_t*>(_access_mem) - static_cast<uint8_t*>(_mmap_mem);
230+
return {_region.addr + access_offs, _region.size - access_offs};
231+
}
232+
void* get_virt_mem() const final override { return _access_mem; }
222233
};
223234

224235
// Hardware accessor for XDMA. Can support either 32 or 64 bit access
@@ -227,13 +238,15 @@ class HwAccessorXdma : public HwAccessorMmap<max_access_width_t> {
227238
int _fd_int;
228239

229240
public:
241+
// TODO: if we ever have to deal w/ unaligned mappings over XDMA (like on UIO), we'll have to pass an access_offs to HwAccessorMmap
230242
HwAccessorXdma(std::string xdma_path,
231243
std::string evt_dev,
232244
UioRegion region,
233245
uintptr_t pcie_offs)
234246
: HwAccessorMmap<max_access_width_t>(xdma_path + "/user",
235247
{region.addr | pcie_offs, region.size},
236-
region.addr) {
248+
region.addr,
249+
0) {
237250
if (!evt_dev.empty()) {
238251
const auto evt_path = xdma_path + "/" + evt_dev;
239252
_fd_int = ::open(evt_path.c_str(), O_RDWR);
@@ -259,7 +272,7 @@ class HwAccessorXdma : public HwAccessorMmap<max_access_width_t> {
259272
// Hardware accessor for AXI. Always supports 64 bit access
260273
class HwAccessorAxi : public HwAccessorMmap<uint64_t> {
261274
public:
262-
HwAccessorAxi(std::string dev_path, UioRegion region, uintptr_t mmap_offs);
275+
HwAccessorAxi(std::string dev_path, UioRegion region, uintptr_t mmap_offs, size_t access_offs);
263276
virtual ~HwAccessorAxi();
264277

265278
int get_fd_int() const final override { return _fd; }

inc/udmaio/UioConfig.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ class UioConfigBase {
8484
/// Creates HwAccessor from UioDeviceLocation (UIO version)
8585
class UioConfigUio : public UioConfigBase {
8686
static int _get_uio_number(std::string_view name);
87+
static unsigned long long _get_uio_val(const std::string path);
8788
static UioRegion _get_map_region(int uio_number, int map_index);
89+
static size_t _get_map_offset(int uio_number, int map_index);
8890

8991
public:
9092
DmaMode mode() override { return DmaMode::UIO; };

src/HwAccessor.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,11 @@ uint32_t HwAccessor::wait_for_interrupt() {
7575
return 0;
7676
}
7777

78-
HwAccessorAxi::HwAccessorAxi(std::string dev_path, UioRegion region, uintptr_t mmap_offs)
79-
: HwAccessorMmap<uint64_t>{dev_path, region, mmap_offs} {}
78+
HwAccessorAxi::HwAccessorAxi(std::string dev_path,
79+
UioRegion region,
80+
uintptr_t mmap_offs,
81+
size_t access_offs)
82+
: HwAccessorMmap<uint64_t>{dev_path, region, mmap_offs, access_offs} {}
8083

8184
HwAccessorAxi::~HwAccessorAxi() {}
8285

src/UioConfig.cpp

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,25 +84,39 @@ int UioConfigUio::_get_uio_number(std::string_view name) {
8484
return -1;
8585
}
8686

87+
unsigned long long UioConfigUio::_get_uio_val(const std::string path) {
88+
std::ifstream ifs{path};
89+
if (!ifs) {
90+
throw std::runtime_error("could not find " + path);
91+
}
92+
std::string size_str;
93+
ifs >> size_str;
94+
return std::stoull(size_str, nullptr, 0);
95+
}
96+
8797
/** @brief gets a region for an uio map */
8898
UioRegion UioConfigUio::_get_map_region(int uio_number, int map_index) {
8999
const std::string base_path{"/sys/class/uio/uio" + std::to_string(uio_number) + "/maps/map" +
90100
std::to_string(map_index) + "/"};
91101

92-
auto get_val = [](const std::string path) -> unsigned long long {
93-
std::ifstream ifs{path};
94-
if (!ifs) {
95-
throw std::runtime_error("could not find " + path);
96-
}
97-
std::string size_str;
98-
ifs >> size_str;
99-
return std::stoull(size_str, nullptr, 0);
102+
auto region = UioRegion{
103+
static_cast<uintptr_t>(_get_uio_val(base_path + "addr")),
104+
static_cast<size_t>(_get_uio_val(base_path + "size")),
100105
};
101106

102-
return {
103-
static_cast<uintptr_t>(get_val(base_path + "addr")),
104-
static_cast<size_t>(get_val(base_path + "size")),
105-
};
107+
std::cout << "UIoRegion is " << region.size << " bytes at 0x" << std::hex << region.addr
108+
<< std::endl;
109+
return region;
110+
}
111+
112+
size_t UioConfigUio::_get_map_offset(int uio_number, int map_index) {
113+
const std::string base_path{"/sys/class/uio/uio" + std::to_string(uio_number) + "/maps/map" +
114+
std::to_string(map_index) + "/"};
115+
116+
auto offset = static_cast<size_t>(_get_uio_val(base_path + "offset"));
117+
118+
std::cout << "UIoOffset is 0x" << std::hex << offset << std::endl;
119+
return offset;
106120
}
107121

108122
/** @brief gets device info (mem region, mmap offset, ...) from a uio name
@@ -154,7 +168,8 @@ HwAccessorPtr UioConfigUio::hw_acc(const UioDeviceLocation& dev_loc) const {
154168
}
155169
return std::make_shared<HwAccessorAxi>(std::string{"/dev/uio"} + std::to_string(uio_number),
156170
_get_map_region(uio_number, map_index),
157-
static_cast<uintptr_t>(map_index * getpagesize()));
171+
static_cast<uintptr_t>(map_index * getpagesize()),
172+
_get_map_offset(uio_number, map_index));
158173
}
159174

160175
UioConfigXdma::UioConfigXdma(std::string xdma_path, uintptr_t pcie_offs, bool x7_series_mode)

0 commit comments

Comments
 (0)