LCOV - code coverage report
Current view: top level - flxlibs/src - CardWrapper.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 200 0
Test Date: 2025-12-21 13:07:08 Functions: 0.0 % 50 0

            Line data    Source code
       1              : /**
       2              :  * @file CardWrapper.cpp FELIX's FlxCard library wrapper implementation
       3              :  *
       4              :  * This is part of the DUNE DAQ , copyright 2020.
       5              :  * Licensing/copyright details are in the COPYING file that you should have
       6              :  * received with this code.
       7              :  */
       8              : // From Module
       9              : #include "CardWrapper.hpp"
      10              : #include "FelixDefinitions.hpp"
      11              : #include "FelixIssues.hpp"
      12              : 
      13              : #include "logging/Logging.hpp"
      14              : 
      15              : #include "flxcard/FlxException.h"
      16              : #include "packetformat/block_format.hpp"
      17              : 
      18              : // From STD
      19              : #include <chrono>
      20              : #include <memory>
      21              : #include <string>
      22              : 
      23              : /**
      24              :  * @brief TRACE debug levels used in this source file
      25              :  */
      26              : enum
      27              : {
      28              :   TLVL_ENTER_EXIT_METHODS = 5,
      29              :   TLVL_WORK_STEPS = 10,
      30              :   TLVL_BOOKKEEPING = 15
      31              : };
      32              : 
      33              : namespace dunedaq {
      34              : namespace flxlibs {
      35              : 
      36            0 : CardWrapper::CardWrapper(const appmodel::FelixInterface * cfg, std::vector<unsigned int> enabled_links)
      37            0 :   : m_run_marker{ false }
      38            0 :   , m_card_id(cfg->get_card())
      39            0 :   , m_logical_unit(cfg->get_slr())
      40            0 :   , m_dma_id(cfg->get_dma_id())
      41            0 :   , m_margin_blocks(cfg->get_dma_margin_blocks())
      42            0 :   , m_block_threshold(cfg->get_dma_block_threshold())
      43            0 :   , m_interrupt_mode(cfg->get_interrupt_mode())
      44            0 :   , m_poll_time(cfg->get_poll_time())
      45            0 :   , m_numa_id(cfg->get_numa_id())
      46            0 :   , m_info_str("")
      47            0 :   , m_run_lock{ false }
      48            0 :   , m_dma_processor(0)
      49            0 :   , m_handle_block_addr(nullptr)
      50            0 :   , m_links_enabled(enabled_links)
      51              : {
      52            0 :   m_dma_memory_size = cfg->get_dma_memory_size_gb() * 1024 * 1024 * 1024UL;
      53              : 
      54            0 :   std::ostringstream tnoss;
      55            0 :   tnoss << m_dma_processor_name << "-" << std::to_string(m_card_id); // append physical card id
      56            0 :   m_dma_processor.set_name(tnoss.str(), m_logical_unit); // set_name appends logical unit id
      57              : 
      58            0 :   std::ostringstream cardoss;
      59            0 :   cardoss << "[id:" << std::to_string(m_card_id) << " slr:" << std::to_string(m_logical_unit) << "]";
      60            0 :   m_card_id_str = cardoss.str();
      61              : 
      62            0 :   m_flx_card = std::make_unique<FlxCard>();
      63            0 :   if (m_flx_card == nullptr) {
      64            0 :     throw flxlibs::CardError(ERS_HERE, "Couldn't create FlxCard object.");
      65              :   }
      66            0 : }
      67              : 
      68            0 : CardWrapper::~CardWrapper()
      69              : {
      70            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "CardWrapper destructor called. First stop check, then closing card.";
      71            0 :   graceful_stop();
      72            0 :   close_card();
      73            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "CardWrapper destroyed.";
      74            0 : }
      75              : 
      76              : 
      77              : void
      78            0 : CardWrapper::configure()
      79              : {
      80            0 :   if (m_configured) {
      81            0 :     TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "Card is already configured! Won't touch it.";
      82              :   } else {
      83            0 :     TLOG_DEBUG(TLVL_WORK_STEPS) << "Configuring CardWrapper of card " << m_card_id_str;
      84              :     // Open card
      85            0 :     open_card();
      86            0 :     TLOG_DEBUG(TLVL_WORK_STEPS) << "Card[" << m_card_id_str << "] opened.";
      87              :     // Allocate CMEM
      88            0 :     m_cmem_handle = allocate_CMEM(m_numa_id, m_dma_memory_size, &m_phys_addr, &m_virt_addr);
      89            0 :     TLOG_DEBUG(TLVL_WORK_STEPS) << "Card[" << m_card_id_str << "] CMEM memory allocated with "
      90            0 :                                 << std::to_string(m_dma_memory_size) << " Bytes.";
      91              :     // Stop currently running DMA
      92            0 :     stop_DMA();
      93            0 :     TLOG_DEBUG(TLVL_WORK_STEPS) << "Card[" << m_card_id_str << "] DMA interactions force stopped.";
      94              :     // Init DMA between software and card
      95            0 :     init_DMA();
      96            0 :     TLOG_DEBUG(TLVL_WORK_STEPS) << "Card[" << m_card_id_str << "] DMA access initialized.";
      97              :     // The rest was some CPU pinning.
      98            0 :     TLOG_DEBUG(TLVL_WORK_STEPS) << m_card_id_str << "] is configured for datataking.";
      99            0 :     m_configured = true;
     100              :   }
     101            0 : }
     102              : 
     103              : void
     104            0 : CardWrapper::start()
     105              : {
     106            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "Starting CardWrapper of card " << m_card_id_str << "...";
     107            0 :   if (!m_run_marker.load()) {
     108            0 :     if (!m_block_addr_handler_available) {
     109            0 :       TLOG() << "Block Address handler is not set! Is it intentional?";
     110              :     }
     111            0 :     start_DMA();
     112            0 :     set_running(true);
     113            0 :     m_dma_processor.set_work(&CardWrapper::process_DMA, this);
     114            0 :     TLOG() << "Started CardWrapper of card " << m_card_id_str << "...";
     115              :   } else {
     116            0 :     TLOG() << "CardWrapper of card " << m_card_id_str << " is already running!";
     117              :   }
     118            0 : }
     119              : 
     120              : void
     121            0 : CardWrapper::graceful_stop()
     122              : {
     123            0 :   TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "Stopping CardWrapper of card " << m_card_id_str << "...";
     124            0 :   if (m_run_marker.load()) {
     125            0 :     set_running(false);
     126            0 :     while (!m_dma_processor.get_readiness()) {
     127            0 :       std::this_thread::sleep_for(std::chrono::milliseconds(10));
     128              :     }
     129            0 :     stop_DMA();
     130            0 :     init_DMA();
     131            0 :     TLOG() << "Stopped CardWrapper of card " << m_card_id_str << "!";
     132              :   } else {
     133            0 :     TLOG() << "CardWrapper of card " << m_card_id_str << " is already stopped!";
     134              :   }
     135            0 : }
     136              : 
     137              : void
     138            0 : CardWrapper::stop()
     139              : {
     140            0 :   graceful_stop();
     141            0 : }
     142              : 
     143              : void
     144            0 : CardWrapper::set_running(bool should_run)
     145              : {
     146            0 :   bool was_running = m_run_marker.exchange(should_run);
     147            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "Active state was toggled from " << was_running << " to " << should_run;
     148            0 : }
     149              : 
     150              : void
     151            0 : CardWrapper::open_card()
     152              : {
     153            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "Opening FELIX card (with DMA lock mask)" << m_card_id_str;
     154            0 :   try {
     155            0 :     m_card_mutex.lock();
     156            0 :     auto absolute_card_id = m_card_id + m_logical_unit;
     157            0 :     u_int current_lock_mask = m_flx_card->get_lock_mask(absolute_card_id);
     158            0 :     TLOG_DEBUG(TLVL_WORK_STEPS) << "Current lock mask for FELIX card " << m_card_id_str << " mask:" << int(current_lock_mask);
     159            0 :     u_int to_lock_mask = u_int(m_dma_id+1);
     160            0 :     if (current_lock_mask & to_lock_mask) { // LOCK_NONE=0, LOCK_DMA0=1, LOCK_DMA1=2 from FlxCard.h
     161            0 :       ers::fatal(flxlibs::CardError(ERS_HERE, "FELIX card's DMA is locked by another process!"));
     162            0 :       exit(EXIT_FAILURE);
     163              :     }
     164            0 :     m_flx_card->card_open(static_cast<int>(absolute_card_id), to_lock_mask); // FlxCard.h
     165            0 :     m_card_mutex.unlock();
     166            0 :   } catch (FlxException& ex) {
     167            0 :     ers::error(flxlibs::CardError(ERS_HERE, ex.what()));
     168            0 :     exit(EXIT_FAILURE);
     169            0 :   }
     170            0 : }
     171              : 
     172              : void
     173            0 : CardWrapper::close_card()
     174              : {
     175            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "Closing FELIX card " << m_card_id_str;
     176            0 :   try {
     177            0 :     m_card_mutex.lock();
     178            0 :     m_flx_card->card_close();
     179            0 :     m_card_mutex.unlock();
     180            0 :   } catch (FlxException& ex) {
     181            0 :     ers::error(flxlibs::CardError(ERS_HERE, ex.what()));
     182            0 :     exit(EXIT_FAILURE);
     183            0 :   }
     184            0 : }
     185              : 
     186              : int
     187            0 : CardWrapper::allocate_CMEM(uint8_t numa, u_long bsize, u_long* paddr, u_long* vaddr) // NOLINT
     188              : {
     189            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "Allocating CMEM buffer " << m_card_id_str << " dma id:" << std::to_string(m_dma_id);
     190            0 :   int handle;
     191            0 :   unsigned ret = CMEM_Open(); // cmem_rcc.h
     192            0 :   if (!ret) {
     193            0 :     ret = CMEM_NumaSegmentAllocate(bsize, numa, const_cast<char*>(m_card_id_str.c_str()), &handle); // NUMA aware
     194              :     // ret = CMEM_GFPBPASegmentAllocate(bsize, const_cast<char*>(m_card_id_str.c_str()), &handle); // non NUMA aware
     195              :   }
     196            0 :   if (!ret) {
     197            0 :     ret = CMEM_SegmentPhysicalAddress(handle, paddr);
     198              :   }
     199            0 :   if (!ret) {
     200            0 :     ret = CMEM_SegmentVirtualAddress(handle, vaddr);
     201              :   }
     202            0 :   if (ret) {
     203              :     // rcc_error_print(stdout, ret);
     204            0 :     m_card_mutex.lock();
     205            0 :     m_flx_card->card_close();
     206            0 :     m_card_mutex.unlock();
     207            0 :     ers::fatal(
     208            0 :       flxlibs::CardError(ERS_HERE,
     209              :                          "Not enough CMEM memory allocated or the application demands too much CMEM memory.\n"
     210            0 :                          "Fix the CMEM memory reservation in the driver or change the module's configuration."));
     211            0 :     exit(EXIT_FAILURE);
     212              :   }
     213            0 :   return handle;
     214              : }
     215              : 
     216              : void
     217            0 : CardWrapper::init_DMA()
     218              : {
     219            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "InitDMA issued...";
     220            0 :   m_card_mutex.lock();
     221            0 :   m_flx_card->dma_reset();
     222            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "flxCard.dma_reset issued.";
     223            0 :   m_flx_card->soft_reset();
     224            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "flxCard.soft_reset issued.";
     225            0 :   m_flx_card->irq_reset_counters();
     226            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "flxCard.irq_reset_counters issued.";
     227              :   // interrupted or polled DMA processing
     228            0 :   if (m_interrupt_mode) {
     229              : #if REGMAP_VERSION < 0x500
     230            0 :     m_flx_card->irq_enable(IRQ_DATA_AVAILABLE);
     231              : #else
     232              :     m_flx_card->irq_enable(IRQ_DATA_AVAILABLE + m_dma_id);
     233              : #endif
     234            0 :     TLOG_DEBUG(TLVL_WORK_STEPS) << "flxCard.irq_enable issued.";
     235              :   } else {
     236            0 :     m_flx_card->irq_disable();
     237            0 :     TLOG_DEBUG(TLVL_WORK_STEPS) << "flxCard.irq_disable issued.";
     238              :   }
     239            0 :   m_card_mutex.unlock();
     240            0 :   m_current_addr = m_phys_addr;
     241            0 :   m_destination = m_phys_addr;
     242            0 :   m_read_index = 0;
     243            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "flxCard initDMA done card[" << m_card_id_str << "]";
     244            0 : }
     245              : 
     246              : void
     247            0 : CardWrapper::start_DMA()
     248              : {
     249            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "Issuing flxCard.dma_to_host for card " << m_card_id_str
     250            0 :                               << " dma id:" << std::to_string(m_dma_id);
     251            0 :   m_card_mutex.lock();
     252            0 :   m_flx_card->dma_to_host(m_dma_id, m_phys_addr, m_dma_memory_size, m_dma_wraparound); // FlxCard.h
     253            0 :   m_card_mutex.unlock();
     254            0 : }
     255              : 
     256              : void
     257            0 : CardWrapper::stop_DMA()
     258              : {
     259            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "Issuing flxCard.dma_stop for card " << m_card_id_str
     260            0 :                               << " dma id:" << std::to_string(m_dma_id);
     261            0 :   m_card_mutex.lock();
     262            0 :   m_flx_card->dma_stop(m_dma_id);
     263            0 :   m_card_mutex.unlock();
     264            0 : }
     265              : 
     266              : inline uint64_t // NOLINT
     267            0 : CardWrapper::bytes_available()
     268              : {
     269            0 :   return (m_current_addr - ((m_read_index * m_block_size) + m_phys_addr) + m_dma_memory_size) % m_dma_memory_size;
     270              : }
     271              : 
     272              : void
     273            0 : CardWrapper::read_current_address()
     274              : {
     275            0 :   m_card_mutex.lock();
     276            0 :   m_current_addr = m_flx_card->m_bar0->DMA_DESC_STATUS[m_dma_id].current_address;
     277            0 :   m_card_mutex.unlock();
     278            0 : }
     279              : 
     280              : void
     281            0 : CardWrapper::process_DMA()
     282              : {
     283            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "CardWrapper starts processing blocks...";
     284            0 :   while (m_run_marker.load()) {
     285              : 
     286              :     // First fix us poll until read address makes sense
     287            0 :     while ((m_current_addr < m_phys_addr) || (m_phys_addr + m_dma_memory_size < m_current_addr)) {
     288            0 :       if (m_run_marker.load()) {
     289            0 :         read_current_address();
     290            0 :         std::this_thread::sleep_for(std::chrono::microseconds(5000)); // fix 5ms initial poll
     291              :       } else {
     292            0 :         TLOG_DEBUG(TLVL_WORK_STEPS) << "Stop issued during poll! Returning...";
     293            0 :         return;
     294              :       }
     295              :     }
     296              : 
     297              :     // Loop or wait for interrupt while there are not enough data
     298            0 :     while (bytes_available() < m_block_threshold * m_block_size) {
     299            0 :       if (m_run_marker.load()) {
     300            0 :         if (m_interrupt_mode) {
     301            0 :           m_card_mutex.lock();
     302              : #if REGMAP_VERSION < 0x500
     303            0 :           m_flx_card->irq_wait(IRQ_DATA_AVAILABLE);
     304              : #else
     305              :           m_flx_card->irq_wait(IRQ_DATA_AVAILABLE + m_dma_id);
     306              : #endif // REGMAP_VERSION
     307            0 :           m_card_mutex.unlock();
     308              :         } else { // poll mode
     309            0 :           std::this_thread::sleep_for(std::chrono::microseconds(m_poll_time));
     310              :         }
     311            0 :         read_current_address();
     312              :       } else {
     313            0 :         TLOG_DEBUG(TLVL_WORK_STEPS) << "Stop issued during waiting for data! Returning...";
     314            0 :         return;
     315              :       }
     316              :     }
     317              : 
     318              :     // Set write index and start DMA advancing
     319            0 :     u_long write_index = (m_current_addr - m_phys_addr) / m_block_size;
     320            0 :     uint64_t bytes = 0; // NOLINT
     321            0 :     while (m_read_index != write_index) {
     322            0 :       uint64_t from_address = m_virt_addr + (m_read_index * m_block_size); // NOLINT
     323              : 
     324              :       // Handle block address
     325            0 :       if (m_block_addr_handler_available) {
     326            0 :         m_handle_block_addr(from_address);
     327              :       }
     328              : 
     329              :       // Advance
     330            0 :       m_read_index = (m_read_index + 1) % (m_dma_memory_size / m_block_size);
     331            0 :       bytes += m_block_size;
     332              :     }
     333              : 
     334              :     // here check if we can move the read pointer in the circular buffer
     335            0 :     m_destination = m_phys_addr + (write_index * m_block_size) - (m_margin_blocks * m_block_size);
     336            0 :     if (m_destination < m_phys_addr) {
     337            0 :       m_destination += m_dma_memory_size;
     338              :     }
     339              : 
     340              :     // Finally, set new pointer
     341            0 :     m_card_mutex.lock();
     342            0 :     m_flx_card->dma_set_ptr(m_dma_id, m_destination);
     343            0 :     m_card_mutex.unlock();
     344              :   }
     345            0 :   TLOG_DEBUG(TLVL_WORK_STEPS) << "CardWrapper processor thread finished.";
     346              : }
     347              : 
     348              : } // namespace flxlibs
     349              : } // namespace dunedaq
        

Generated by: LCOV version 2.0-1