43 #include <boost/python.hpp>
44namespace bp = boost::python;
47std::map<std::string, std::shared_ptr<rha::AxiStreamDmaShared> > rha::AxiStreamDma::sharedBuffers_;
52rha::AxiStreamDmaShared::AxiStreamDmaShared(std::string path) {
71 std::map<std::string, rha::AxiStreamDmaSharedPtr>::iterator it;
75 if ((it = sharedBuffers_.find(path)) != sharedBuffers_.end()) {
77 log->debug(
"Reusing existing shared file descriptor for %s", path.c_str());
82 log->debug(
"Shared file descriptor already opened for %s", path.c_str());
93 log->debug(
"Zero copy is disabled. Not Mapping Buffers for %s", path.c_str());
102 ret = std::make_shared<rha::AxiStreamDmaShared>(path);
103 log->debug(
"Opening new shared file descriptor for %s", path.c_str());
107 if ((ret->fd = ::open(path.c_str(), O_RDWR)) < 0)
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))"));
138 "AxiStreamDma::openShared",
139 "Rogue DmaDriver.h API Version (DMA_VERSION) does not match the aes-stream-driver API version"));
144 ret->rawBuff =
dmaMapDma(ret->fd, &(ret->bCount), &(ret->bSize));
145 if (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",
162 log->debug(
"Mapped buffers. bCount = %i, bSize=%i for %s", ret->bCount, ret->bSize, path.c_str());
166 sharedBuffers_.insert(std::pair<std::string, rha::AxiStreamDmaSharedPtr>(path, ret));
176 if (desc->openCount == 0) {
177 if (desc->rawBuff != NULL) {
185 if (desc->fd != -1) {
191 desc->rawBuff = NULL;
196rha::AxiStreamDmaPtr rha::AxiStreamDma::create(std::string path, uint32_t dest,
bool ssiEnable) {
201void rha::AxiStreamDma::zeroCopyDisable(std::string path) {
204 std::map<std::string, rha::AxiStreamDmaSharedPtr>::iterator it;
207 if ((it = sharedBuffers_.find(path)) != sharedBuffers_.end())
209 "zeroCopyDisable can't be called twice or after a device has been opened"));
213 ret->zCopyEn =
false;
215 sharedBuffers_.insert(std::pair<std::string, rha::AxiStreamDmaSharedPtr>(path, ret));
219rha::AxiStreamDma::AxiStreamDma(std::string path, uint32_t dest,
bool ssiEnable) {
227 std::shared_ptr<int> scopePtr = std::make_shared<int>(0);
236 desc_ = openShared(path, log_);
239 if ((fd_ = ::open(path.c_str(), O_RDWR)) < 0) {
256 if (desc_->rawBuff == NULL) {
260 if (desc_->bCount >= 1000) retThold_ = 80;
271 "Failed to open device file %s with dest 0x%" PRIx32
272 "! Another process may already have it open!",
279 thread_ = std::make_unique<std::thread>(&rha::AxiStreamDma::runThread,
this, std::weak_ptr<int>(scopePtr));
290 pthread_setname_np(thread_->native_handle(),
"AxiStreamDma");
295rha::AxiStreamDma::~AxiStreamDma() {
299void rha::AxiStreamDma::stop() {
312 if (thread_ && thread_->joinable()) {
334void rha::AxiStreamDma::setTimeout(uint32_t timeout) {
336 div_t divResult = div(timeout, 1000000);
337 timeout_.tv_sec = divResult.quot;
338 timeout_.tv_usec = divResult.rem;
343void rha::AxiStreamDma::setDriverDebug(uint32_t level) {
348void rha::AxiStreamDma::dmaAck() {
353ris::FramePtr rha::AxiStreamDma::acceptReq(uint32_t size,
bool zeroCopyEn) {
365 if (!desc_ || fd_ < 0)
367 "instance has been stopped or did not finish construction");
370 if (size > desc_->bSize)
371 buffSize = desc_->bSize;
376 if (zeroCopyEn ==
false || desc_->rawBuff == NULL) {
377 frame = reqLocalFrame(size,
false);
384 frame = ris::Frame::create();
388 while (alloc < size) {
396 "AxiStreamDma::acceptReq",
397 "fd_=%d invalid; instance was stop()'d or never finished construction",
400 pfd.events = POLLOUT;
404 int rc = poll(&pfd, 1, (timeout_.tv_sec * 1000) + ((timeout_.tv_usec + 999) / 1000));
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",
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.",
427 buff = createBuffer(desc_->rawBuff[res], 0x80000000 | res, buffSize, desc_->bSize);
428 frame->appendBuffer(buff);
449 if (!desc_ || fd_ < 0)
451 "instance has been stopped or did not finish construction");
458 if (frame->getError()) {
459 log_->warning(
"Dumping errored frame");
464 ris::Frame::BufferIterator it;
465 for (it = frame->beginBuffer(); it != frame->endBuffer(); ++it) {
469 if (it == frame->beginBuffer()) {
470 fuser = frame->getFirstUser();
471 if (enSsi_) fuser |= 0x2;
477 if (it == (frame->endBuffer() - 1)) {
479 luser = frame->getLastUser();
488 meta = (*it)->getMeta();
491 if ((meta & 0x80000000) != 0) {
495 if ((meta & 0x40000000) == 0) {
507 (*it)->setMeta(meta);
519 "AxiStreamDma::acceptFrame",
520 "fd_=%d invalid; instance was stop()'d or never finished construction",
523 pfd.events = POLLOUT;
527 int rc = poll(&pfd, 1, (timeout_.tv_sec * 1000) + ((timeout_.tv_usec + 999) / 1000));
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",
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.",
554 if (emptyFrame) frame->clear();
558void rha::AxiStreamDma::retBuffer(uint8_t* data, uint32_t meta, uint32_t size) {
565 if ((meta & 0x80000000) != 0) {
568 if ((fd_ >= 0) && ((meta & 0x40000000) == 0)) {
570 throw(
rogue::GeneralError(
"AxiStreamDma::retBuffer",
"AXIS Return Buffer Call Failed!!!!"));
576 Pool::retBuffer(data, meta, size);
581void rha::AxiStreamDma::runThread(std::weak_ptr<int> lockPtr) {
583 uint32_t meta[RxBufferCount];
584 uint32_t rxFlags[RxBufferCount];
585 uint32_t rxError[RxBufferCount];
586 int32_t rxSize[RxBufferCount];
601 while (!lockPtr.expired())
continue;
606 frame = ris::Frame::create();
615 log_->error(
"AxiStreamDma::runThread: fd_ value %d invalid; exiting worker", fd_);
624 if (poll(&pfd, 1, 1) > 0) {
628 if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
629 log_->error(
"AxiStreamDma::runThread: poll reported fd error revents=0x%x; exiting worker",
634 if (!(pfd.revents & POLLIN))
continue;
636 if (desc_->rawBuff == NULL) {
638 buff[0] = allocBuffer(desc_->bSize, NULL);
641 rxSize[0] =
dmaRead(fd_, buff[0]->begin(), buff[0]->getAvailable(), rxFlags, rxError, NULL);
650 rxCount =
dmaReadBulkIndex(fd_, RxBufferCount, rxSize, meta, rxFlags, rxError, NULL);
653 for (x = 0; x < rxCount; x++)
654 buff[x] = createBuffer(desc_->rawBuff[meta[x]], 0x80000000 | meta[x], desc_->bSize, desc_->bSize);
658 if (rxCount < 0)
throw(
rogue::GeneralError(
"AxiStreamDma::runThread",
"DMA Interface Failure!"));
661 for (x = 0; x < rxCount; x++) {
666 buff[x]->setPayload(rxSize[x]);
668 error = frame->getError();
671 error |= (rxError[x] & 0xFF);
674 if (frame->isEmpty()) frame->setFirstUser(fuser & 0xFF);
678 frame->setLastUser(luser & 0xFF);
679 if (enSsi_ && ((luser & 0x1) != 0)) error |= 0x80;
682 frame->setError(error);
683 frame->appendBuffer(buff[x]);
689 frame = ris::Frame::create();
697std::string rha::AxiStreamDma::getGitVersion() {
702uint32_t rha::AxiStreamDma::getApiVersion() {
707uint32_t rha::AxiStreamDma::getBuffSize() {
712uint32_t rha::AxiStreamDma::getRxBuffCount() {
717uint32_t rha::AxiStreamDma::getRxBuffinUserCount() {
722uint32_t rha::AxiStreamDma::getRxBuffinHwCount() {
727uint32_t rha::AxiStreamDma::getRxBuffinPreHwQCount() {
732uint32_t rha::AxiStreamDma::getRxBuffinSwQCount() {
737uint32_t rha::AxiStreamDma::getRxBuffMissCount() {
742uint32_t rha::AxiStreamDma::getTxBuffCount() {
747uint32_t rha::AxiStreamDma::getTxBuffinUserCount() {
752uint32_t rha::AxiStreamDma::getTxBuffinHwCount() {
757uint32_t rha::AxiStreamDma::getTxBuffinPreHwQCount() {
762uint32_t rha::AxiStreamDma::getTxBuffinSwQCount() {
767uint32_t rha::AxiStreamDma::getTxBuffMissCount() {
771void rha::AxiStreamDma::setup_python() {
774 bp::class_<rha::AxiStreamDma, rha::AxiStreamDmaPtr, bp::bases<ris::Master, ris::Slave>, boost::noncopyable>(
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);
797 bp::implicitly_convertible<rha::AxiStreamDmaPtr, ris::MasterPtr>();
798 bp::implicitly_convertible<rha::AxiStreamDmaPtr, ris::SlavePtr>();
static std::mutex sharedBuffersMtx
static uint32_t axisGetLuser(uint32_t flags)
Extracts last-user flag from packed AXIS flags.
static uint32_t axisSetFlags(uint32_t fuser, uint32_t luser, uint32_t cont)
Packs AXIS first-user, last-user, and continuation bits.
static uint32_t axisGetFuser(uint32_t flags)
Extracts first-user flag from packed AXIS flags.
static void axisReadAck(int32_t fd)
Issues AXIS read-acknowledge ioctl command.
static uint32_t axisGetCont(uint32_t flags)
Extracts continuation flag from packed AXIS flags.
static std::string dmaGetGitVersion(int32_t fd)
Get the DMA Driver's Git Version.
static ssize_t dmaGetTxBuffinPreHwQCount(int32_t fd)
Get the transmit buffer count in pre-hardware queue.
static ssize_t dmaGetTxBuffCount(int32_t fd)
Get the transmit buffer count.
static ssize_t dmaGetTxBuffMissCount(int32_t fd)
Get the transmit buffer missing count.
static ssize_t dmaGetRxBuffinHwCount(int32_t fd)
Get the receive buffer count in hardware.
static ssize_t dmaGetApiVersion(int32_t fd)
Get API version of the DMA driver.
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.
static void dmaInitMaskBytes(uint8_t *mask)
Initialize DMA mask byte array.
static void dmaAddMaskBytes(uint8_t *mask, uint32_t dest)
Add a destination to the DMA mask byte array.
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.
static ssize_t dmaSetMaskBytes(int32_t fd, uint8_t *mask)
Set mask byte array to the driver.
static ssize_t dmaGetRxBuffinUserCount(int32_t fd)
Get the receive buffer count in user.
static ssize_t dmaGetTxBuffinHwCount(int32_t fd)
Get the transmit buffer count in hardware.
static ssize_t dmaGetBuffSize(int32_t fd)
Get the buffer size.
static ssize_t dmaGetRxBuffinSwQCount(int32_t fd)
Get the receive buffer count in software queue.
static ssize_t dmaGetRxBuffCount(int32_t fd)
Get the receive buffer count.
static int32_t dmaGetIndex(int32_t fd)
Get the current write buffer index.
static ssize_t dmaGetRxBuffinPreHwQCount(int32_t fd)
Get the receive buffer count in pre-hardware queue.
static ssize_t dmaRetIndex(int32_t fd, uint32_t index)
Post an index back to the DMA.
static ssize_t dmaSetDebug(int32_t fd, uint32_t level)
Set debugging level for DMA operations.
static ssize_t dmaGetTxBuffinSwQCount(int32_t fd)
Get the transmit buffer count in software queue.
static ssize_t dmaGetBuffCount(int32_t fd)
Get the buffer count.
static ssize_t dmaCheckVersion(int32_t fd)
Check API version of the DMA driver.
static void ** dmaMapDma(int32_t fd, uint32_t *count, uint32_t *size)
Map user space to DMA buffers.
static ssize_t dmaUnMapDma(int32_t fd, void **buffer)
Unmap user space from DMA buffers.
static ssize_t dmaRead(int32_t fd, void *buf, size_t maxSize, uint32_t *flags, uint32_t *error, uint32_t *dest)
Receive Frame.
static ssize_t dmaGetTxBuffinUserCount(int32_t fd)
Get the transmit buffer count in user.
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.
static ssize_t dmaGetRxBuffMissCount(int32_t fd)
Get the receive buffer missing count.
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.
static std::shared_ptr< rogue::Logging > create(const std::string &name, bool quiet=false)
Creates a logger instance.
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.
std::shared_ptr< rogue::interfaces::stream::Frame > FramePtr
Shared pointer alias for Frame.
std::shared_ptr< rogue::interfaces::stream::FrameLock > FrameLockPtr
Shared pointer alias for FrameLock.
std::shared_ptr< rogue::Logging > LoggingPtr
Shared pointer alias for Logging.
void defaultTimeout(struct timeval &tout)
Returns Rogue default timeout as a timeval.