LCOV - code coverage report
Current view: top level - src - tohost_buffer.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 15 17 88.2 %
Date: 2025-09-09 12:09:29 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef TOHOST_BUFFER_H_
       2             : #define TOHOST_BUFFER_H_
       3             : 
       4             : #include <cstddef>
       5             : #include <cstdint>
       6             : #include <thread>
       7             : #include <span>
       8             : #include <mutex>
       9             : #include <shared_mutex>
      10             : #include <cstdio>
      11             : #include <condition_variable>
      12             : 
      13             : #include "device.hpp"
      14             : #include "cmem_buffer.hpp"
      15             : #include "block.hpp"
      16             : 
      17             : 
      18             : #if REGMAP_VERSION < 0x500
      19             :     #define IRQ_WRAP_AROUND_FROM_HOST 0
      20             :     #define IRQ_WRAP_AROUND_TO_HOST 1
      21             :     #define IRQ_DATA_AVAILABLE 2
      22             :     #define IRQ_FIFO_FULL_FROM_HOST 3
      23             :     #define IRQ_BUSY_CHANGE_TO_HOST 6
      24             :     #define IRQ_FIFO_FULL_TO_HOST 7
      25             : #else
      26             :     #define IRQ_DATA_AVAILABLE 0
      27             :     #define IRQ_XOFF_TO_HOST 5
      28             :     #define IRQ_BUSY_CHANGE_TO_HOST 6
      29             :     #define IRQ_FIFO_FULL_TO_HOST 7
      30             : #endif
      31             : 
      32             : #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
      33             : 
      34             : 
      35             : /**
      36             :  * Abstract class representing a ToHost DMA buffer.
      37             :  * The elinks enabled for the corresponding DMA buffers are read from the
      38             :  * device in the constructors.
      39             :  */
      40             : class ToHostBuffer
      41             : {
      42             :     public:
      43             :         ToHostBuffer(int dmaid, std::shared_ptr<Device> d);
      44             : 
      45             :         //Interrupts
      46             :         /**
      47             :          * \defgroup Interrupt handling
      48             :          * @{
      49             :          * Functions to enable/disable for MSI-X interrupts.
      50             :          */
      51             :         /**
      52             :          * @brief enable on_data interrupt for this DMA buffer.
      53             :          */
      54           0 :         void irq_data_enable() {m_device->irq_enable(m_irq_on_data);}
      55             : 
      56             :         /**
      57             :          * @brief disable on_data interrupt for this DMA buffer.
      58             :          */
      59             :         void irq_data_disable(){m_device->irq_disable(m_irq_on_data);}
      60             : 
      61             :         /**
      62             :          * @brief enable busy interrupt for this DMA buffer.
      63             :          */
      64             :         void irq_busy_enable() {m_device->irq_enable(IRQ_BUSY_CHANGE_TO_HOST);}
      65             : 
      66             :         /**
      67             :          * @brief disable busy interrupt for this DMA buffer.
      68             :          */
      69             :         void irq_busy_disable(){m_device->irq_disable(IRQ_BUSY_CHANGE_TO_HOST);}
      70             :         /**
      71             :          * @}
      72             :          */
      73             : 
      74             :         /**
      75             :          * @return a shared pointer to the device serving this DMA buffer.
      76             :          */ 
      77         120 :         std::shared_ptr<Device> get_device(){return m_device;}
      78             : 
      79             :         /**
      80             :          * @return identifying number of this DMA buffer.
      81             :          */ 
      82             :         int get_dmaid() const {return m_dmaid;}
      83             : 
      84             :         /**
      85             :          * @return read e-links enabled for this DMA buffer.
      86             :          */ 
      87             :         std::vector<Elink> get_elinks(){return m_device->read_enabled_elinks(m_dmaid);}
      88             : 
      89             :         /**
      90             :          * @return read e-links enabled for this DMA buffer of a given type.
      91             :          * @param t the e-link type, determined from the encoding.
      92             :          */
      93          66 :         std::vector<Elink> get_elinks_of_type(elink_type_t t){return m_device->get_enabled_elinks_of_type(m_dmaid, t);};
      94             : 
      95             :         /**
      96             :          * @return fraction of e-links enabled for this DMA buffer of a given type.
      97             :          * @param t the e-link type, determined from the encoding.
      98             :          */
      99             :         std::vector<std::vector<Elink>> split_elinks_of_type(elink_type_t t, size_t n);
     100             : 
     101             :         //DMA buffer operations
     102             :         /**
     103             :          * \defgroup DMA operations
     104             :          * @{
     105             :          * Functions to manage DMA read/write operations.
     106             :          */
     107             :         /**
     108             :          * @brief fraction of e-links enabled for this DMA buffer of a given type.
     109             :          * @param name of the buffers passed to the CMEM driver.
     110             :          * @param vmem if true, do not use CMEM but malloc a buffer in memory.
     111             :          * @param free_previous_cmem if true, re-claim a buffer with the same name if present and not locked.
     112             :          */
     113             :         virtual void allocate_buffer(size_t size,
     114             :                             const std::string& name,
     115             :                             bool vmem, bool free_previous_cmem=true) = 0;
     116             : 
     117             :         /**
     118             :          * @brief inform the FELIX card of the allocated buffer, to be used as a circular DMA buffer.
     119             :          */
     120             :         virtual void     dma_start_continuous()                  = 0; //start_circular_dma
     121             : 
     122             :         /**
     123             :          * @brief wait for an on-data MSI-X interrupt.
     124             :          */
     125             :         virtual void     dma_wait_for_data_irq()                 = 0; //wait_data_available
     126             : 
     127             :         /**
     128             :          * @return number of bytes written by firmware, to be read by software.
     129             :          */
     130             :         virtual size_t   dma_bytes_available()                   = 0; //bytes_available
     131             : 
     132             :         /**
     133             :          * @return number of bytes written by firmware up to the end of the buffer,
     134             :          * to be read by software. 
     135             :          */
     136             :         virtual size_t   dma_bytes_available_nowrap()            = 0; //bytes_available_to_read
     137             : 
     138             :         /**
     139             :          * @return true if the DMA buffer is full.
     140             :          */
     141             :         virtual bool     dma_is_full()                           = 0;
     142             : 
     143             :         /**
     144             :          * @return address in virtual memory of write pointer (moved by firmware).
     145             :          */
     146             :         virtual uint64_t dma_get_write_ptr()                     = 0;
     147             : 
     148             :         /**
     149             :          * @return address in virtual memory of read pointer (moved by software).
     150             :          */
     151             :         virtual uint64_t dma_get_read_ptr()                      = 0;
     152             : 
     153             :         /**
     154             :          * @brief set a new read pointer.
     155             :          * @details software uses the virtual addresses, firmware uses the physical ones.
     156             :          * @param v_addr virtual address of new read pointer.
     157             :          */
     158             :         virtual void     dma_set_read_ptr_vaddr(uint64_t v_addr) = 0;
     159             : 
     160             :         /**
     161             :          * @brief set a new read pointer.
     162             :          * @details software uses the virtual addresses, firmware uses the physical ones.
     163             :          * @param p_addr physical address of new read pointer.
     164             :          */
     165             :         virtual void     dma_set_read_ptr_paddr(uint64_t p_addr) = 0;
     166             : 
     167             :         /**
     168             :          * @return read pointer offset with respect to the start of buffer.
     169             :          */
     170             :         virtual uint64_t dma_get_read_offset()                   = 0;
     171             : 
     172             :         /**
     173             :          * @return write pointer offset with respect to the start of buffer.
     174             :          */
     175             :         virtual uint64_t dma_get_write_offset()                  = 0;
     176             : 
     177             :         /**
     178             :          * @brief advance read pointer.
     179             :          * @param bytes number of bytes processed by software.
     180             :          */
     181             :         virtual void     dma_advance_read_ptr(size_t bytes)      = 0;
     182             : 
     183             :         /**
     184             :          * @return virtual address of start of buffer.
     185             :          */
     186          36 :         uint64_t         dma_get_vaddr(){return m_buffer->vaddr;}
     187             : 
     188             :         /**
     189             :          * @return buffer size.
     190             :          */
     191       37025 :         size_t           dma_get_size(){return m_buffer->size;}
     192             :         /**
     193             :          * @}
     194             :          */
     195             : 
     196             :         /**
     197             :          * \defgroup Multi-reader functions
     198             :          * @{
     199             :          * Functions to manage readers' opearation
     200             :          */
     201             :         /**
     202             :          * @brief register a new reader to this DMA buffer.
     203             :          * @param zc_flag true if the reader uses zero-copy.
     204             :          * @return reader identifier.
     205             :          */
     206             :         uint32_t         reader_register(bool zc_flag);
     207             : 
     208             :         /**
     209             :          * @param reader_id reader identifier.
     210             :          * @return whether there are data in the DMA buffer for this reader to read.
     211             :          */
     212             :         bool             reader_is_data_available(uint32_t reader_id);
     213             : 
     214             :         /**
     215             :          * @param reader_id reader identifier.
     216             :          * @return bytes available for reading for the given reader.
     217             :          */
     218             :         size_t           reader_get_available_bytes(uint32_t reader_id);
     219             : 
     220             :         /**
     221             :          * @param reader_id reader identifier.
     222             :          * @return blocks to be read by the given reader.
     223             :          */
     224             :         std::span<Block> reader_get_available_blocks(uint32_t reader_id);
     225             : 
     226             :         /**
     227             :          * @brief advance the DMA buffer read pointer according to the readers' progress
     228             :          * @details single synchronisation point of the different ToHostReaders.
     229             :          * @param reader_id reader identifier.
     230             :          * @param read_bytes bytes read by the reader.
     231             :          * @param reader_id bytes sent by the reader (sent != read only in zero-copy mode).
     232             :          */
     233             :         void             reader_advance_read_ptr(uint32_t reader_id,  uint32_t read_bytes, uint32_t sent_bytes);
     234             :         /**
     235             :          * @}
     236             :          */
     237             : 
     238             :         /**
     239             :          * \defgroup Support for zero-copy module
     240             :          * @{
     241             :          * Functions to enable zero-copy flags.
     242             :          */
     243             :         /**
     244             :          * @return whether a zero-copy reader is present among those registered to this buffer.
     245             :          */
     246             :         bool             has_zero_copy_reader() const {return m_has_zero_copy_reader;}
     247             : 
     248             :         /**
     249             :          * @brief set flag for the presence of a zero-copy reader.
     250             :          */
     251          10 :         void             set_zero_copy_reader(){m_has_zero_copy_reader = true;}
     252             :         /**
     253             :          * @}
     254             :          */
     255             : 
     256             :         /**
     257             :          * @brief stop reading operations.
     258             :          */
     259          22 :         void             stop(){m_stop_flag = true;}
     260             : 
     261             :         /**
     262             :          * @return whether read operations have been stopped.
     263             :          */
     264     6940698 :         bool             is_stopped() const {return m_stop_flag;}
     265             : 
     266             :         /**
     267             :          * \defgroup Monitoring information
     268             :          * @{
     269             :          * Functions to manage readers' opearation
     270             :          */
     271             :         /**
     272             :          * @return free space in the buffer in MB.
     273             :          */
     274             :         uint32_t dma_get_free_MB();
     275             : 
     276             :         /**
     277             :          * @brief increase the on-data interrupt counter.
     278             :          */
     279           0 :         void dma_increase_irq_counter(){++m_irq_counter;}
     280             : 
     281             :         /**
     282             :          * @return the number of on-data interrupts.
     283             :          */
     284         177 :         uint64_t dma_get_irq_counter() const {return m_irq_counter;}
     285             :         /**
     286             :          * @}
     287             :          */
     288             : 
     289             :     protected:
     290             :         int m_dmaid;
     291             :         std::shared_ptr<Device> m_device;
     292             :         unsigned int m_block_size;
     293             :         int m_irq_on_data; //IRQ_DATA_AVAILABLE + m_dmaid;
     294             :         uint64_t m_irq_counter;
     295             :         size_t m_size;
     296             :         bool m_stop_flag; //stop flag for readers
     297             :         bool m_has_zero_copy_reader;
     298             :         size_t m_min_bytes_sent;
     299             : 
     300             :         std::mutex m_mutex;
     301             :         std::unique_ptr<DmaBuffer> m_buffer;
     302             : 
     303             :         //support for multiple ToHostBufferReader
     304             :         std::vector<uint64_t> m_bytes_read; //read from DMA buffer
     305             :         std::vector<uint64_t> m_bytes_sent; //different from read only for zc mode
     306             : 
     307             :         size_t dma_compute_bytes_to_read(uint64_t rd_ptr, uint64_t wr_ptr, bool even);
     308             : };
     309             : 
     310             : 
     311         177 : inline size_t ToHostBuffer::dma_compute_bytes_to_read(uint64_t rd_ptr, uint64_t wr_ptr, bool even)
     312             : {
     313         177 :     if( wr_ptr > rd_ptr ) {
     314          77 :         return wr_ptr - rd_ptr;
     315             :     }
     316         100 :     else if( wr_ptr < rd_ptr ) {
     317          40 :         return m_buffer->size + wr_ptr -rd_ptr;
     318             :     }
     319             :     else { // dma_ptr == buf->pc_ptr
     320          60 :         if( even ) {
     321             :             return 0;         // Buffer empty
     322             :         }
     323             :         else {
     324          49 :             return m_buffer->size; // Buffer full
     325             :         }
     326             :     }
     327             : }
     328             : 
     329             : 
     330             : /**
     331             :  * Reader of a Felix card ToHost DMA buffer. 
     332             :  * */
     333             : class FlxToHostBuffer : public ToHostBuffer {
     334             : 
     335             :     public:
     336             :         FlxToHostBuffer(int m_dmaid, std::shared_ptr<Device> d);
     337             :         ~FlxToHostBuffer();
     338             : 
     339             : 
     340             :         void allocate_buffer(size_t size,
     341             :                             const std::string& name,
     342             :                             bool vmem, bool free_previous_cmem=false) override;
     343             : 
     344             :         void     dma_start_continuous()                  override;
     345             :         void     dma_wait_for_data_irq()                 override;
     346             :         size_t   dma_bytes_available()                   override;
     347             :         //uint32_t dma_get_free_MB()                       override;
     348             :         size_t   dma_bytes_available_nowrap()            override;
     349             :         bool     dma_is_full()                           override;
     350             :         uint64_t dma_get_write_ptr()                     override;
     351             :         uint64_t dma_get_read_ptr()                      override;
     352             :         void     dma_set_read_ptr_vaddr(uint64_t v_addr) override;
     353             :         void     dma_set_read_ptr_paddr(uint64_t p_addr) override;
     354             :         uint64_t dma_get_read_offset()                   override;
     355             :         uint64_t dma_get_write_offset()                  override;
     356             :         void     dma_advance_read_ptr(size_t bytes)      override;
     357             : };
     358             : 
     359             : 
     360             : /**
     361             :  * Reader for the ToHost DMA buffer with hardware emulated in software.
     362             :  * A dedicated thread fills writes in the DMA buffer in stead of the FELIX card. 
     363             :  * */
     364             : class FileToHostBuffer : public ToHostBuffer {
     365             : 
     366             :     public:
     367             :         FileToHostBuffer(int m_dmaid, std::shared_ptr<Device> d,
     368             :             std::string& filename, unsigned int block_rate, bool repeat);
     369             :         ~FileToHostBuffer();
     370             :         void allocate_buffer(size_t size,
     371             :                             const std::string& name,
     372             :                             bool vmem, bool free_previous_cmem=true) override;
     373             : 
     374             :         void     dma_start_continuous()                  override;
     375             :         void     dma_wait_for_data_irq()                 override;
     376             :         size_t   dma_bytes_available()                   override;
     377             :         //uint32_t dma_get_free_MB()                       override;
     378             :         size_t   dma_bytes_available_nowrap()            override;
     379             :         bool     dma_is_full()                           override;
     380             :         uint64_t dma_get_write_ptr()                     override;
     381             :         uint64_t dma_get_read_ptr()                      override;
     382             :         void     dma_set_read_ptr_vaddr(uint64_t v_addr) override;
     383             :         void     dma_set_read_ptr_paddr(uint64_t p_addr) override;
     384             :         uint64_t dma_get_read_offset()                   override;
     385             :         uint64_t dma_get_write_offset()                  override;
     386             :         void     dma_advance_read_ptr(size_t bytes)      override;
     387             : 
     388             :     private:
     389             :         void    set_read_ptr_paddr(uint64_t p_addr);
     390             :         void    write_in_dma_buffer();
     391             :         size_t  limit_block_rate(size_t max_blocks);
     392             :         size_t  blocks_to_write(uint64_t rd_ptr, uint64_t wr_ptr, bool even);
     393             :         void    throttle_writer(const std::chrono::nanoseconds &elapsed, size_t count);
     394             :         void    writer_updates_fw_ptr(size_t written_blocks);
     395             :         bool    reset_file();
     396             : 
     397             :     private:
     398             :         //regulate the concurrent access to read and write pointers
     399             :         mutable std::shared_mutex m_driver_mutex;
     400             : 
     401             :         //emulate MSI-X on_data interrupts
     402             :         std::condition_variable m_irq_cond;
     403             :         mutable std::mutex m_irq_mutex;
     404             : 
     405             :         //suspend the card emulator thread when the DMA is full
     406             :         std::condition_variable m_writer_cond;
     407             :         mutable std::mutex m_stop_writer_mutex;
     408             : 
     409             :         unsigned int m_block_rate;
     410             :         bool m_repeat;     
     411             :         bool m_rd_odd;
     412             :         bool m_wr_odd;
     413             :         FILE*  m_fp;
     414             :         std::thread m_writer_thread;
     415             : };
     416             : 
     417             : #endif /* TOHOST_BUFFER_H_ */

Generated by: LCOV version 1.0