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