rogue
Loading...
Searching...
No Matches
AxiStreamDma.cpp
Go to the documentation of this file.
1
17#include "rogue/Directives.h"
18
20
21#include <inttypes.h>
22#include <poll.h>
23
24#include <cstdio>
25#include <cstdlib>
26#include <map>
27#include <memory>
28#include <mutex>
29#include <string>
30
31#include "rogue/GeneralError.h"
32#include "rogue/GilRelease.h"
33#include "rogue/Helpers.h"
38
39namespace rha = rogue::hardware::axi;
41
42#ifndef NO_PYTHON
43 #include <boost/python.hpp>
44namespace bp = boost::python;
45#endif
46
47std::map<std::string, std::shared_ptr<rha::AxiStreamDmaShared> > rha::AxiStreamDma::sharedBuffers_;
48
49// Protect sharedBuffers_ against concurrent AxiStreamDma construction.
50static std::mutex sharedBuffersMtx;
51
52rha::AxiStreamDmaShared::AxiStreamDmaShared(std::string path) {
53 this->fd = -1;
54 this->path = path;
55 // Start at 0; openShared() is the single point that increments openCount
56 // for every caller (including the !zCopyEn early-return path), so a freshly
57 // constructed record must contribute zero to the refcount. Initializing to
58 // 1 here previously double-counted entries seeded by zeroCopyDisable() and
59 // was the root cause of openCount drifting negative on close.
60 this->openCount = 0;
61 this->rawBuff = NULL;
62 this->bCount = 0;
63 this->bSize = 0;
64 this->zCopyEn = true;
65}
66
68rha::AxiStreamDmaSharedPtr rha::AxiStreamDma::openShared(std::string path, rogue::LoggingPtr log) {
70 std::lock_guard<std::mutex> lock(sharedBuffersMtx);
71 std::map<std::string, rha::AxiStreamDmaSharedPtr>::iterator it;
73
74 // Entry already exists
75 if ((it = sharedBuffers_.find(path)) != sharedBuffers_.end()) {
76 ret = it->second;
77 log->debug("Reusing existing shared file descriptor for %s", path.c_str());
78
79 // Already opened by an earlier caller; just count the new user.
80 if (ret->fd != -1) {
81 ret->openCount++;
82 log->debug("Shared file descriptor already opened for %s", path.c_str());
83 return ret;
84 }
85
86 // Entry was seeded by zeroCopyDisable() (or fully closed and is being
87 // reopened with zCopyEn=false): no kernel fd will be held, but every
88 // AxiStreamDma sharing this path is still a refcount user. Without
89 // this branch, closeShared() would decrement an entry that never got
90 // counted, driving openCount negative.
91 if (!ret->zCopyEn) {
92 ret->openCount++;
93 log->debug("Zero copy is disabled. Not Mapping Buffers for %s", path.c_str());
94 return ret;
95 }
96
97 // Fall through to the open+map path; increment after success so a
98 // throw before insertion cannot leak openCount.
99
100 // Create new record
101 } else {
102 ret = std::make_shared<rha::AxiStreamDmaShared>(path);
103 log->debug("Opening new shared file descriptor for %s", path.c_str());
104 }
105
106 // We need to open device and create shared buffers
107 if ((ret->fd = ::open(path.c_str(), O_RDWR)) < 0)
108 throw(rogue::GeneralError::create("AxiStreamDma::openShared", "Failed to open device file: %s", path.c_str()));
109
110 // Check driver version ( ApiVersion 0x05 (or less) is the 32-bit address version)
111 //
112 // closeShared() leaves entries in sharedBuffers_ after openCount drops to
113 // 0 (only fd/bCount/bSize/rawBuff are reset), so an entry can be re-entered
114 // here via the "fd == -1, zCopyEn == true" fall-through. If we close the
115 // fd on error but leave ret->fd != -1, the persistent map entry will still
116 // hold the (now closed) descriptor, and the next openShared() caller would
117 // hit the "ret->fd != -1" fast-path and reuse a stale fd. Reset the
118 // shared record fd (ret->fd) to -1 (and clear any partial mapping state)
119 // on every error path before throwing. Note: ret->fd here is the shared
120 // AxiStreamDmaShared record field, distinct from the AxiStreamDma::fd_
121 // per-instance member.
122 if (dmaGetApiVersion(ret->fd) < 0x06) {
123 ::close(ret->fd);
124 ret->fd = -1;
125 throw(rogue::GeneralError("AxiStreamDma::openShared",
126 R"(Bad kernel driver version detected. Please re-compile kernel driver.
127 Note that aes-stream-driver (v5.15.2 or earlier) and rogue (v5.11.1 or earlier) are compatible with the 32-bit address API.
128 To use later versions (64-bit address API),, you will need to upgrade both rogue and aes-stream-driver at the same time to:
129 \t\taes-stream-driver = v5.16.0 (or later)
130 \t\trogue = v5.13.0 (or later))"));
131 }
132
133 // Check for mismatch in the rogue/loaded_driver API versions
134 if (dmaCheckVersion(ret->fd) < 0) {
135 ::close(ret->fd);
136 ret->fd = -1;
138 "AxiStreamDma::openShared",
139 "Rogue DmaDriver.h API Version (DMA_VERSION) does not match the aes-stream-driver API version"));
140 }
141
142 // Result may be that rawBuff = NULL
143 // Should this just be a warning?
144 ret->rawBuff = dmaMapDma(ret->fd, &(ret->bCount), &(ret->bSize));
145 if (ret->rawBuff == NULL) {
146 // dmaMapDma may have written to bCount/bSize even on failure; query
147 // the buffer count one more time for the user-facing error message,
148 // then scrub the shared record so a future openShared() on a
149 // re-entered entry starts clean.
150 uint32_t mapSize = dmaGetBuffCount(ret->fd) + 8192;
151
152 ::close(ret->fd);
153 ret->fd = -1;
154 ret->bCount = 0;
155 ret->bSize = 0;
156 ret->rawBuff = NULL;
158 "AxiStreamDma::openShared",
159 "Failed to map dma buffers. Increase vm map limit to : sudo sysctl -w vm.max_map_count=%i",
160 mapSize));
161 }
162 log->debug("Mapped buffers. bCount = %i, bSize=%i for %s", ret->bCount, ret->bSize, path.c_str());
163
164 // Open + map succeeded; count this caller and publish in the map.
165 ret->openCount++;
166 sharedBuffers_.insert(std::pair<std::string, rha::AxiStreamDmaSharedPtr>(path, ret));
167 return ret;
168}
169
171void rha::AxiStreamDma::closeShared(rha::AxiStreamDmaSharedPtr desc) {
172 rogue::GilRelease noGil;
173 std::lock_guard<std::mutex> lock(sharedBuffersMtx);
174 desc->openCount--;
175
176 if (desc->openCount == 0) {
177 if (desc->rawBuff != NULL) {
178 dmaUnMapDma(desc->fd, desc->rawBuff);
179 }
180
181 // Guard against close(-1). In the zeroCopyDisable() flow desc->fd is
182 // never opened, so calling ::close(desc->fd) here would issue a real
183 // syscall with fd=-1 and return EBADF. Skip the close when the fd
184 // was never held by this descriptor.
185 if (desc->fd != -1) {
186 ::close(desc->fd);
187 }
188 desc->fd = -1;
189 desc->bCount = 0;
190 desc->bSize = 0;
191 desc->rawBuff = NULL;
193}
194
196rha::AxiStreamDmaPtr rha::AxiStreamDma::create(std::string path, uint32_t dest, bool ssiEnable) {
197 rha::AxiStreamDmaPtr r = std::make_shared<rha::AxiStreamDma>(path, dest, ssiEnable);
198 return (r);
199}
200
201void rha::AxiStreamDma::zeroCopyDisable(std::string path) {
202 rogue::GilRelease noGil;
203 std::lock_guard<std::mutex> lock(sharedBuffersMtx);
204 std::map<std::string, rha::AxiStreamDmaSharedPtr>::iterator it;
205
206 // Entry already exists
207 if ((it = sharedBuffers_.find(path)) != sharedBuffers_.end())
208 throw(rogue::GeneralError("AxiStreamDma::zeroCopyDisable",
209 "zeroCopyDisable can't be called twice or after a device has been opened"));
210
211 // Create new record
212 rha::AxiStreamDmaSharedPtr ret = std::make_shared<rha::AxiStreamDmaShared>(path);
213 ret->zCopyEn = false;
214
215 sharedBuffers_.insert(std::pair<std::string, rha::AxiStreamDmaSharedPtr>(path, ret));
216}
217
219rha::AxiStreamDma::AxiStreamDma(std::string path, uint32_t dest, bool ssiEnable) {
220 uint8_t mask[DMA_MASK_SIZE];
221
222 dest_ = dest;
223 enSsi_ = ssiEnable;
224 retThold_ = 1;
225
226 // Create a shared pointer to use as a lock for runThread()
227 std::shared_ptr<int> scopePtr = std::make_shared<int>(0);
228
229 rogue::defaultTimeout(timeout_);
230
231 log_ = rogue::Logging::create("axi.AxiStreamDma");
232
233 rogue::GilRelease noGil;
234
235 // Attempt to open shared structure
236 desc_ = openShared(path, log_);
237
238 // Open non shared file descriptor
239 if ((fd_ = ::open(path.c_str(), O_RDWR)) < 0) {
240 closeShared(desc_);
241 throw(
242 rogue::GeneralError::create("AxiStreamDma::AxiStreamDma", "Failed to open device file: %s", path.c_str()));
243 }
244
245 // desc_->bCount and desc_->bSize live in the shared AxiStreamDmaShared
246 // instance returned by openShared(), which is also looked up under
247 // sharedBuffersMtx by other concurrent constructions on the same path.
248 // Two ctors racing here would otherwise both write the same fields
249 // without synchronisation - a data race even when the values written
250 // are identical. Take the same mutex that openShared / closeShared /
251 // zeroCopyDisable use, and BOTH read and write bCount under it (the
252 // earlier "read at function entry, write inside the conditional" form
253 // left the read racing with another ctor's write).
254 {
255 std::lock_guard<std::mutex> lock(sharedBuffersMtx);
256 if (desc_->rawBuff == NULL) {
257 desc_->bCount = dmaGetTxBuffCount(fd_) + dmaGetRxBuffCount(fd_);
258 desc_->bSize = dmaGetBuffSize(fd_);
259 }
260 if (desc_->bCount >= 1000) retThold_ = 80;
261 }
262
263 dmaInitMaskBytes(mask);
264 dmaAddMaskBytes(mask, dest_);
265
266 if (dmaSetMaskBytes(fd_, mask) < 0) {
267 closeShared(desc_);
268 ::close(fd_);
269 fd_ = -1;
270 throw(rogue::GeneralError::create("AxiStreamDma::AxiStreamDma",
271 "Failed to open device file %s with dest 0x%" PRIx32
272 "! Another process may already have it open!",
273 path.c_str(),
274 dest));
275 }
276
277 threadEn_ = true;
278 try {
279 thread_ = std::make_unique<std::thread>(&rha::AxiStreamDma::runThread, this, std::weak_ptr<int>(scopePtr));
280 } catch (...) {
281 threadEn_ = false;
282 closeShared(desc_);
283 ::close(fd_);
284 fd_ = -1;
285 throw;
286 }
287
288 // Set a thread name
289#ifndef __MACH__
290 pthread_setname_np(thread_->native_handle(), "AxiStreamDma");
291#endif
292}
293
295rha::AxiStreamDma::~AxiStreamDma() {
296 this->stop();
297}
298
299void rha::AxiStreamDma::stop() {
300 rogue::GilRelease noGil;
301
302 // Signal the worker to exit; idempotent so stop() can be called multiple
303 // times (user-initiated stop() followed by ~AxiStreamDma()).
304 threadEn_ = false;
305
306 // Join based on thread state, not threadEn_. runThread() can now exit on
307 // its own (e.g. the in-loop fd_ guard) by setting threadEn_ = false and
308 // returning, so gating cleanup on threadEn_ here would skip the join and
309 // ~unique_ptr<std::thread> on a still-joinable thread would call
310 // std::terminate(). Joining via joinable() handles both that early-exit
311 // path and the normal stop() path with the same code.
312 if (thread_ && thread_->joinable()) {
313 thread_->join();
314 }
315 thread_.reset();
316
317 // Release the shared descriptor exactly once even if stop() is called
318 // again (or runThread() self-exited and the user called stop() before
319 // ~AxiStreamDma()): clearing desc_ after closeShared() prevents a
320 // double-decrement of openCount.
321 if (desc_) {
322 closeShared(desc_);
323 desc_.reset();
324 }
325
326 // Close the per-instance fd exactly once.
327 if (fd_ >= 0) {
328 ::close(fd_);
329 fd_ = -1;
331}
332
334void rha::AxiStreamDma::setTimeout(uint32_t timeout) {
335 if (timeout > 0) {
336 div_t divResult = div(timeout, 1000000);
337 timeout_.tv_sec = divResult.quot;
338 timeout_.tv_usec = divResult.rem;
340}
341
343void rha::AxiStreamDma::setDriverDebug(uint32_t level) {
344 dmaSetDebug(fd_, level);
345}
346
348void rha::AxiStreamDma::dmaAck() {
349 if (fd_ >= 0) axisReadAck(fd_);
350}
351
353ris::FramePtr rha::AxiStreamDma::acceptReq(uint32_t size, bool zeroCopyEn) {
354 int32_t res;
355 struct pollfd pfd;
356 uint32_t alloc;
357 ris::BufferPtr buff;
358 ris::FramePtr frame;
359 uint32_t buffSize;
360
361 // Reject use after stop()/teardown. stop() resets the shared-descriptor
362 // shared_ptr to nullptr and closes the per-instance fd, so a post-stop
363 // call would otherwise segfault on the buffer-size read below instead
364 // of throwing a clean GeneralError.
365 if (!desc_ || fd_ < 0)
366 throw rogue::GeneralError("AxiStreamDma::acceptReq",
367 "instance has been stopped or did not finish construction");
368
370 if (size > desc_->bSize)
371 buffSize = desc_->bSize;
372 else
373 buffSize = size;
374
375 // Zero copy is disabled. Allocate from memory.
376 if (zeroCopyEn == false || desc_->rawBuff == NULL) {
377 frame = reqLocalFrame(size, false);
378
379 // Allocate zero copy buffers from driver
380 } else {
381 rogue::GilRelease noGil;
382
383 // Create empty frame
384 frame = ris::Frame::create();
385 alloc = 0;
386
387 // Request may be serviced with multiple buffers
388 while (alloc < size) {
389 // Keep trying since poll call can fire
390 // but getIndex fails because we did not win the buffer lock
391 do {
392 // Re-check fd validity: a concurrent stop() can toggle fd_ to -1.
393 // poll() imposes no FD_SETSIZE ceiling, so large fd values are fine.
394 if (fd_ < 0)
396 "AxiStreamDma::acceptReq",
397 "fd_=%d invalid; instance was stop()'d or never finished construction",
398 fd_);
399 pfd.fd = fd_;
400 pfd.events = POLLOUT;
401 pfd.revents = 0;
402
403 // Round up µs->ms so sub-ms timeouts do not collapse to a non-blocking poll().
404 int rc = poll(&pfd, 1, (timeout_.tv_sec * 1000) + ((timeout_.tv_usec + 999) / 1000));
405 // POLLERR/POLLHUP/POLLNVAL can be reported with POLLOUT also set on a fd in
406 // error state; surface that as a clear error instead of feeding a known-bad
407 // fd into dmaGetIndex() and looping on its return value.
408 if (rc > 0 && (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)))
410 "AxiStreamDma::acceptReq",
411 "poll() reported fd error revents=0x%x; fd may be closed or in error state",
412 pfd.revents);
413 if (rc <= 0 || !(pfd.revents & POLLOUT)) {
414 log_->critical("AxiStreamDma::acceptReq: Timeout waiting for outbound buffer after %" PRIuLEAST32
415 ".%" PRIuLEAST32 " seconds! May be caused by outbound back pressure.",
416 timeout_.tv_sec,
417 timeout_.tv_usec);
418 res = -1;
419 } else {
420 // Attempt to get index.
421 // return of less than 0 is a failure to get a buffer
422 res = dmaGetIndex(fd_);
423 }
424 } while (res < 0);
425
426 // Mark zero copy meta with bit 31 set, lower bits are index
427 buff = createBuffer(desc_->rawBuff[res], 0x80000000 | res, buffSize, desc_->bSize);
428 frame->appendBuffer(buff);
429 alloc += buffSize;
430 }
431 }
432 return (frame);
433}
434
436void rha::AxiStreamDma::acceptFrame(ris::FramePtr frame) {
437 int32_t res;
438 struct pollfd pfd;
439 uint32_t meta;
440 uint32_t fuser;
441 uint32_t luser;
442 uint32_t cont;
443 bool emptyFrame;
444
445 // Reject use after stop()/teardown. stop() releases the shared descriptor
446 // and closes fd_, so the inner-loop fd_ guard would still catch this, but
447 // that fires only after frame->lock() and buffer iteration have already
448 // run. Fail-fast at entry for a cleaner error path, mirroring acceptReq().
449 if (!desc_ || fd_ < 0)
450 throw rogue::GeneralError("AxiStreamDma::acceptFrame",
451 "instance has been stopped or did not finish construction");
452
453 rogue::GilRelease noGil;
454 ris::FrameLockPtr lock = frame->lock();
455 emptyFrame = false;
456
457 // Drop errored frames
458 if (frame->getError()) {
459 log_->warning("Dumping errored frame");
460 return;
461 }
462
463 // Go through each (*it)er in the frame
464 ris::Frame::BufferIterator it;
465 for (it = frame->beginBuffer(); it != frame->endBuffer(); ++it) {
466 (*it)->zeroHeader();
467
468 // First buffer
469 if (it == frame->beginBuffer()) {
470 fuser = frame->getFirstUser();
471 if (enSsi_) fuser |= 0x2;
472 } else {
473 fuser = 0;
474 }
475
476 // Last Buffer
477 if (it == (frame->endBuffer() - 1)) {
478 cont = 0;
479 luser = frame->getLastUser();
480
481 // Continue flag is set if this is not the last (*it)er
482 } else {
483 cont = 1;
484 luser = 0;
485 }
486
487 // Get (*it)er meta field
488 meta = (*it)->getMeta();
489
490 // Meta is zero copy as indicated by bit 31
491 if ((meta & 0x80000000) != 0) {
492 emptyFrame = true;
493
494 // Buffer is not already stale as indicates by bit 30
495 if ((meta & 0x40000000) == 0) {
496 // Write by passing (*it)er index to driver
497 if (dmaWriteIndex(fd_,
498 meta & 0x3FFFFFFF,
499 (*it)->getPayload(),
500 axisSetFlags(fuser, luser, cont),
501 dest_) <= 0) {
502 throw(rogue::GeneralError("AxiStreamDma::acceptFrame", "AXIS Write Call Failed"));
503 }
504
505 // Mark (*it)er as stale
506 meta |= 0x40000000;
507 (*it)->setMeta(meta);
508 }
509
510 // Write to pgp with (*it)er copy in driver
511 } else {
512 // Keep trying since poll call can fire
513 // but write fails because we did not win the (*it)er lock
514 do {
515 // Re-check fd validity: a concurrent stop() can toggle fd_ to -1.
516 // poll() imposes no FD_SETSIZE ceiling, so large fd values are fine.
517 if (fd_ < 0)
519 "AxiStreamDma::acceptFrame",
520 "fd_=%d invalid; instance was stop()'d or never finished construction",
521 fd_);
522 pfd.fd = fd_;
523 pfd.events = POLLOUT;
524 pfd.revents = 0;
525
526 // Round up µs->ms so sub-ms timeouts do not collapse to a non-blocking poll().
527 int rc = poll(&pfd, 1, (timeout_.tv_sec * 1000) + ((timeout_.tv_usec + 999) / 1000));
528 // POLLERR/POLLHUP/POLLNVAL can be reported with POLLOUT also set on a fd in
529 // error state; surface that as a clear error instead of feeding a known-bad
530 // fd into dmaWrite() and reporting a generic "AXIS Write Call Failed".
531 if (rc > 0 && (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)))
533 "AxiStreamDma::acceptFrame",
534 "poll() reported fd error revents=0x%x; fd may be closed or in error state",
535 pfd.revents);
536 if (rc <= 0 || !(pfd.revents & POLLOUT)) {
537 log_->critical("AxiStreamDma::acceptFrame: Timeout waiting for outbound write after %" PRIuLEAST32
538 ".%" PRIuLEAST32 " seconds! May be caused by outbound back pressure.",
539 timeout_.tv_sec,
540 timeout_.tv_usec);
541 res = 0;
542 } else {
543 // Write with (*it)er copy
544 if ((res =
545 dmaWrite(fd_, (*it)->begin(), (*it)->getPayload(), axisSetFlags(fuser, luser, 0), dest_)) <
546 0) {
547 throw(rogue::GeneralError("AxiStreamDma::acceptFrame", "AXIS Write Call Failed!!!!"));
548 }
549 }
550 } while (res == 0); // Exit out if return flag was set false
551 }
552 }
553
554 if (emptyFrame) frame->clear();
555}
556
558void rha::AxiStreamDma::retBuffer(uint8_t* data, uint32_t meta, uint32_t size) {
559 rogue::GilRelease noGil;
560 uint32_t ret[100];
561 uint32_t count;
562 uint32_t x;
563
564 // Buffer is zero copy as indicated by bit 31
565 if ((meta & 0x80000000) != 0) {
566 // Device is open and buffer is not stale
567 // Bit 30 indicates buffer has already been returned to hardware
568 if ((fd_ >= 0) && ((meta & 0x40000000) == 0)) {
569 if (dmaRetIndex(fd_, meta & 0x3FFFFFFF) < 0)
570 throw(rogue::GeneralError("AxiStreamDma::retBuffer", "AXIS Return Buffer Call Failed!!!!"));
571 }
572 decCounter(size);
573
574 // Buffer is allocated from Pool class
575 } else {
576 Pool::retBuffer(data, meta, size);
577 }
578}
579
581void rha::AxiStreamDma::runThread(std::weak_ptr<int> lockPtr) {
582 ris::BufferPtr buff[RxBufferCount];
583 uint32_t meta[RxBufferCount];
584 uint32_t rxFlags[RxBufferCount];
585 uint32_t rxError[RxBufferCount];
586 int32_t rxSize[RxBufferCount];
587 int32_t rxCount;
588 int32_t x;
589 ris::FramePtr frame;
590 struct pollfd pfd;
591 uint8_t error;
592 uint32_t fuser;
593 uint32_t luser;
594 uint32_t cont;
595
596 fuser = 0;
597 luser = 0;
598 cont = 0;
599
600 // Wait until constructor completes
601 while (!lockPtr.expired()) continue;
602
603 log_->logThreadId();
604
605 // Preallocate empty frame
606 frame = ris::Frame::create();
607
608 while (threadEn_) {
609 // runThread() has no top-level catch, so a throw here would call
610 // std::terminate. This in-loop check only fires if stop()/close()
611 // races with the worker and toggles fd_ to -1; log and exit the worker
612 // cleanly so stop() can complete instead of crashing the process.
613 // poll() imposes no FD_SETSIZE ceiling, so large fd values are fine.
614 if (fd_ < 0) {
615 log_->error("AxiStreamDma::runThread: fd_ value %d invalid; exiting worker", fd_);
616 threadEn_ = false;
617 break;
618 }
619 pfd.fd = fd_;
620 pfd.events = POLLIN;
621 pfd.revents = 0;
622
623 // poll returns with available buffer (1 ms timeout)
624 if (poll(&pfd, 1, 1) > 0) {
625 // poll() can report POLLERR/POLLHUP/POLLNVAL with POLLIN unset (e.g. closed-fd race).
626 // runThread() has no top-level catch, so falling through to dmaRead on an invalid fd
627 // would throw and call std::terminate. Log and exit the worker cleanly instead.
628 if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
629 log_->error("AxiStreamDma::runThread: poll reported fd error revents=0x%x; exiting worker",
630 pfd.revents);
631 threadEn_ = false;
632 break;
633 }
634 if (!(pfd.revents & POLLIN)) continue;
635 // Zero copy buffers were not allocated
636 if (desc_->rawBuff == NULL) {
637 // Allocate a buffer
638 buff[0] = allocBuffer(desc_->bSize, NULL);
639
640 // Attempt read, dest is not needed since only one lane/vc is open
641 rxSize[0] = dmaRead(fd_, buff[0]->begin(), buff[0]->getAvailable(), rxFlags, rxError, NULL);
642 if (rxSize[0] <= 0)
643 rxCount = rxSize[0];
644 else
645 rxCount = 1;
646
647 // Zero copy read
648 } else {
649 // Attempt read, dest is not needed since only one lane/vc is open
650 rxCount = dmaReadBulkIndex(fd_, RxBufferCount, rxSize, meta, rxFlags, rxError, NULL);
651
652 // Allocate a buffer, Mark zero copy meta with bit 31 set, lower bits are index
653 for (x = 0; x < rxCount; x++)
654 buff[x] = createBuffer(desc_->rawBuff[meta[x]], 0x80000000 | meta[x], desc_->bSize, desc_->bSize);
655 }
656
657 // Return of -1 is bad
658 if (rxCount < 0) throw(rogue::GeneralError("AxiStreamDma::runThread", "DMA Interface Failure!"));
659
660 // Read was successful
661 for (x = 0; x < rxCount; x++) {
662 fuser = axisGetFuser(rxFlags[x]);
663 luser = axisGetLuser(rxFlags[x]);
664 cont = axisGetCont(rxFlags[x]);
665
666 buff[x]->setPayload(rxSize[x]);
667
668 error = frame->getError();
669
670 // Receive error
671 error |= (rxError[x] & 0xFF);
672
673 // First buffer of frame
674 if (frame->isEmpty()) frame->setFirstUser(fuser & 0xFF);
675
676 // Last buffer of frame
677 if (cont == 0) {
678 frame->setLastUser(luser & 0xFF);
679 if (enSsi_ && ((luser & 0x1) != 0)) error |= 0x80;
680 }
681
682 frame->setError(error);
683 frame->appendBuffer(buff[x]);
684 buff[x].reset();
685
686 // If continue flag is not set, push frame and get a new empty frame
687 if (cont == 0) {
688 sendFrame(frame);
689 frame = ris::Frame::create();
690 }
691 }
692 }
694}
695
697std::string rha::AxiStreamDma::getGitVersion() {
698 return dmaGetGitVersion(fd_);
699}
700
702uint32_t rha::AxiStreamDma::getApiVersion() {
703 return dmaGetApiVersion(fd_);
704}
705
707uint32_t rha::AxiStreamDma::getBuffSize() {
708 return dmaGetBuffSize(fd_);
709}
710
712uint32_t rha::AxiStreamDma::getRxBuffCount() {
713 return dmaGetRxBuffCount(fd_);
714}
715
717uint32_t rha::AxiStreamDma::getRxBuffinUserCount() {
719}
720
722uint32_t rha::AxiStreamDma::getRxBuffinHwCount() {
724}
725
727uint32_t rha::AxiStreamDma::getRxBuffinPreHwQCount() {
729}
730
732uint32_t rha::AxiStreamDma::getRxBuffinSwQCount() {
734}
735
737uint32_t rha::AxiStreamDma::getRxBuffMissCount() {
739}
740
742uint32_t rha::AxiStreamDma::getTxBuffCount() {
743 return dmaGetTxBuffCount(fd_);
744}
745
747uint32_t rha::AxiStreamDma::getTxBuffinUserCount() {
749}
750
752uint32_t rha::AxiStreamDma::getTxBuffinHwCount() {
754}
755
757uint32_t rha::AxiStreamDma::getTxBuffinPreHwQCount() {
759}
760
762uint32_t rha::AxiStreamDma::getTxBuffinSwQCount() {
764}
765
767uint32_t rha::AxiStreamDma::getTxBuffMissCount() {
768 return dmaGetTxBuffMissCount(fd_);
769}
770
771void rha::AxiStreamDma::setup_python() {
772#ifndef NO_PYTHON
773
774 bp::class_<rha::AxiStreamDma, rha::AxiStreamDmaPtr, bp::bases<ris::Master, ris::Slave>, boost::noncopyable>(
775 "AxiStreamDma",
776 bp::init<std::string, uint32_t, bool>())
777 .def("setDriverDebug", &rha::AxiStreamDma::setDriverDebug)
778 .def("dmaAck", &rha::AxiStreamDma::dmaAck)
779 .def("setTimeout", &rha::AxiStreamDma::setTimeout)
780 .def("getGitVersion", &rha::AxiStreamDma::getGitVersion)
781 .def("getApiVersion", &rha::AxiStreamDma::getApiVersion)
782 .def("getBuffSize", &rha::AxiStreamDma::getBuffSize)
783 .def("getRxBuffCount", &rha::AxiStreamDma::getRxBuffCount)
784 .def("getRxBuffinUserCount", &rha::AxiStreamDma::getRxBuffinUserCount)
785 .def("getRxBuffinHwCount", &rha::AxiStreamDma::getRxBuffinHwCount)
786 .def("getRxBuffinPreHwQCount", &rha::AxiStreamDma::getRxBuffinPreHwQCount)
787 .def("getRxBuffinSwQCount", &rha::AxiStreamDma::getRxBuffinSwQCount)
788 .def("getRxBuffMissCount", &rha::AxiStreamDma::getRxBuffMissCount)
789 .def("getTxBuffCount", &rha::AxiStreamDma::getTxBuffCount)
790 .def("getTxBuffinUserCount", &rha::AxiStreamDma::getTxBuffinUserCount)
791 .def("getTxBuffinHwCount", &rha::AxiStreamDma::getTxBuffinHwCount)
792 .def("getTxBuffinPreHwQCount", &rha::AxiStreamDma::getTxBuffinPreHwQCount)
793 .def("getTxBuffinSwQCount", &rha::AxiStreamDma::getTxBuffinSwQCount)
794 .def("getTxBuffMissCount", &rha::AxiStreamDma::getTxBuffMissCount)
795 .def("zeroCopyDisable", &rha::AxiStreamDma::zeroCopyDisable);
796
797 bp::implicitly_convertible<rha::AxiStreamDmaPtr, ris::MasterPtr>();
798 bp::implicitly_convertible<rha::AxiStreamDmaPtr, ris::SlavePtr>();
799#endif
800}
static std::mutex sharedBuffersMtx
static uint32_t axisGetLuser(uint32_t flags)
Extracts last-user flag from packed AXIS flags.
Definition AxisDriver.h:80
static uint32_t axisSetFlags(uint32_t fuser, uint32_t luser, uint32_t cont)
Packs AXIS first-user, last-user, and continuation bits.
Definition AxisDriver.h:51
static uint32_t axisGetFuser(uint32_t flags)
Extracts first-user flag from packed AXIS flags.
Definition AxisDriver.h:69
static void axisReadAck(int32_t fd)
Issues AXIS read-acknowledge ioctl command.
Definition AxisDriver.h:104
static uint32_t axisGetCont(uint32_t flags)
Extracts continuation flag from packed AXIS flags.
Definition AxisDriver.h:91
static std::string dmaGetGitVersion(int32_t fd)
Get the DMA Driver's Git Version.
Definition DmaDriver.h:727
static ssize_t dmaGetTxBuffinPreHwQCount(int32_t fd)
Get the transmit buffer count in pre-hardware queue.
Definition DmaDriver.h:662
static ssize_t dmaGetTxBuffCount(int32_t fd)
Get the transmit buffer count.
Definition DmaDriver.h:623
static ssize_t dmaGetTxBuffMissCount(int32_t fd)
Get the transmit buffer missing count.
Definition DmaDriver.h:688
static ssize_t dmaGetRxBuffinHwCount(int32_t fd)
Get the receive buffer count in hardware.
Definition DmaDriver.h:571
static ssize_t dmaGetApiVersion(int32_t fd)
Get API version of the DMA driver.
Definition DmaDriver.h:930
static ssize_t dmaWriteIndex(int32_t fd, uint32_t index, size_t size, uint32_t flags, uint32_t dest)
Writes data to a DMA channel using an index.
Definition DmaDriver.h:246
static void dmaInitMaskBytes(uint8_t *mask)
Initialize DMA mask byte array.
Definition DmaDriver.h:867
static void dmaAddMaskBytes(uint8_t *mask, uint32_t dest)
Add a destination to the DMA mask byte array.
Definition DmaDriver.h:881
static ssize_t dmaReadBulkIndex(int32_t fd, uint32_t count, int32_t *ret, uint32_t *index, uint32_t *flags, uint32_t *error, uint32_t *dest)
Receive frame and access memory-mapped buffer.
Definition DmaDriver.h:449
#define DMA_MASK_SIZE
Definition DmaDriver.h:118
static ssize_t dmaSetMaskBytes(int32_t fd, uint8_t *mask)
Set mask byte array to the driver.
Definition DmaDriver.h:902
static ssize_t dmaGetRxBuffinUserCount(int32_t fd)
Get the receive buffer count in user.
Definition DmaDriver.h:558
static ssize_t dmaGetTxBuffinHwCount(int32_t fd)
Get the transmit buffer count in hardware.
Definition DmaDriver.h:649
static ssize_t dmaGetBuffSize(int32_t fd)
Get the buffer size.
Definition DmaDriver.h:701
static ssize_t dmaGetRxBuffinSwQCount(int32_t fd)
Get the receive buffer count in software queue.
Definition DmaDriver.h:597
static ssize_t dmaGetRxBuffCount(int32_t fd)
Get the receive buffer count.
Definition DmaDriver.h:545
static int32_t dmaGetIndex(int32_t fd)
Get the current write buffer index.
Definition DmaDriver.h:519
static ssize_t dmaGetRxBuffinPreHwQCount(int32_t fd)
Get the receive buffer count in pre-hardware queue.
Definition DmaDriver.h:584
static ssize_t dmaRetIndex(int32_t fd, uint32_t index)
Post an index back to the DMA.
Definition DmaDriver.h:486
static ssize_t dmaSetDebug(int32_t fd, uint32_t level)
Set debugging level for DMA operations.
Definition DmaDriver.h:816
static ssize_t dmaGetTxBuffinSwQCount(int32_t fd)
Get the transmit buffer count in software queue.
Definition DmaDriver.h:675
static ssize_t dmaGetBuffCount(int32_t fd)
Get the buffer count.
Definition DmaDriver.h:714
static ssize_t dmaCheckVersion(int32_t fd)
Check API version of the DMA driver.
Definition DmaDriver.h:915
static void ** dmaMapDma(int32_t fd, uint32_t *count, uint32_t *size)
Map user space to DMA buffers.
Definition DmaDriver.h:747
static ssize_t dmaUnMapDma(int32_t fd, void **buffer)
Unmap user space from DMA buffers.
Definition DmaDriver.h:791
static ssize_t dmaRead(int32_t fd, void *buf, size_t maxSize, uint32_t *flags, uint32_t *error, uint32_t *dest)
Receive Frame.
Definition DmaDriver.h:380
static ssize_t dmaGetTxBuffinUserCount(int32_t fd)
Get the transmit buffer count in user.
Definition DmaDriver.h:636
static ssize_t dmaWrite(int32_t fd, const void *buf, size_t size, uint32_t flags, uint32_t dest)
Writes data to a DMA channel.
Definition DmaDriver.h:218
static ssize_t dmaGetRxBuffMissCount(int32_t fd)
Get the receive buffer missing count.
Definition DmaDriver.h:610
Generic Rogue exception type.
static GeneralError create(std::string src, const char *fmt,...)
Creates a formatted error instance.
RAII helper that releases the Python GIL for a scope.
Definition GilRelease.h:36
static std::shared_ptr< rogue::Logging > create(const std::string &name, bool quiet=false)
Creates a logger instance.
Definition Logging.cpp:95
std::shared_ptr< rogue::hardware::axi::AxiStreamDma > AxiStreamDmaPtr
std::shared_ptr< rogue::hardware::axi::AxiStreamDmaShared > AxiStreamDmaSharedPtr
std::shared_ptr< rogue::interfaces::stream::Buffer > BufferPtr
Shared pointer alias for Buffer.
Definition Buffer.h:270
std::shared_ptr< rogue::interfaces::stream::Frame > FramePtr
Shared pointer alias for Frame.
Definition Frame.h:549
std::shared_ptr< rogue::interfaces::stream::FrameLock > FrameLockPtr
Shared pointer alias for FrameLock.
Definition FrameLock.h:110
std::shared_ptr< rogue::Logging > LoggingPtr
Shared pointer alias for Logging.
Definition Logging.h:205
void defaultTimeout(struct timeval &tout)
Returns Rogue default timeout as a timeval.
Definition Helpers.h:49