Line data Source code
1 : #include "fromhost_buffer.hpp" 2 : #include "log.hpp" 3 : #include <cstdint> 4 : 5 5 : FileFromHostBuffer::FileFromHostBuffer(std::shared_ptr<Device> d, std::string &filename, bool fifo) 6 : : FromHostBuffer(d), 7 5 : m_file(filename, m_encoder.get_block_size(), DiskIO::FWRITE, fifo), 8 5 : m_rd_odd(false), 9 15 : m_wr_odd(false){}; 10 : 11 5 : FileFromHostBuffer::~FileFromHostBuffer() 12 : { 13 5 : m_reader_thread.join(); 14 5 : LOG_INFO("Reader thread joined"); 15 5 : } 16 : 17 5 : void FileFromHostBuffer::allocate_buffer(size_t size, 18 : const std::string &name, 19 : bool vmem, bool free_previous_cmem) 20 : { 21 5 : m_size = size; 22 5 : if (vmem) 23 : { 24 5 : m_buffer = std::make_unique<VmemBuffer>(size); 25 : } 26 : else 27 : { 28 0 : m_buffer = std::make_unique<CmemBuffer>(size, name, free_previous_cmem); 29 : } 30 5 : uint8_t *vaddr = reinterpret_cast<uint8_t *>(m_buffer->vaddr); 31 5 : m_encoder.set_destination_parameters(vaddr, m_buffer->size); 32 5 : } 33 : 34 5 : void FileFromHostBuffer::dma_start_continuous() 35 : { 36 5 : m_buffer->pend = m_buffer->paddr + m_buffer->size; 37 5 : m_buffer->pc_ptr = m_buffer->paddr; 38 5 : m_buffer->emu_fw_ptr = m_buffer->paddr; 39 5 : LOG_INFO(" cmem buffer [0x%x,0x%x] %lu Blocks", m_buffer->paddr, m_buffer->pend, m_buffer->size/1024); 40 5 : LOG_INFO(" cmem virtual address 0x%x", m_buffer->vaddr); 41 5 : LOG_INFO(" fw_ptr 0x%x", m_buffer->emu_fw_ptr); 42 5 : LOG_INFO(" pc_ptr 0x%x", m_buffer->pc_ptr); 43 5 : LOG_INFO("Spawning buffer-to-file reader thread..."); 44 5 : m_reader_thread = std::thread(&FileFromHostBuffer::copy_from_dma_buffer_to_file, this); 45 5 : } 46 : 47 : /** Here I only need to update where to start reading, also known as the Firmware pointer emulator (emu_fw_ptr). 48 : The dimensions of the buffer (pend) do not change, also the pointer that tells until where in the buffer has been written (pc_ptr), 49 : is updated after writing with dma_set_write_offset()*/ 50 2 : void FileFromHostBuffer::dma_start_circular_trickle_buffer() 51 : { 52 2 : std::unique_lock<std::shared_mutex> lock(m_driver_mutex); 53 2 : m_buffer->emu_fw_ptr = m_buffer->paddr; 54 2 : m_buffer->pend = m_buffer->paddr + m_trickle_config_size; 55 2 : m_fw_reading_trickle.store(true); 56 2 : } 57 : 58 : 59 10025 : size_t FileFromHostBuffer::dma_free_bytes() 60 : { 61 10025 : std::shared_lock<std::shared_mutex> lock(m_driver_mutex); 62 10025 : bool even = (m_rd_odd == m_wr_odd); 63 20050 : return dma_compute_free_bytes(m_buffer->emu_fw_ptr, m_buffer->pc_ptr, even); 64 10025 : } 65 : 66 0 : bool FileFromHostBuffer::dma_is_full() 67 : { 68 0 : std::shared_lock<std::shared_mutex> lock(m_driver_mutex); 69 0 : return ((m_buffer->emu_fw_ptr == m_buffer->pc_ptr) and (m_rd_odd != m_wr_odd)); 70 0 : } 71 : 72 8586 : bool FileFromHostBuffer::dma_is_empty() 73 : { 74 8586 : std::shared_lock<std::shared_mutex> lock(m_driver_mutex); 75 15319 : return ((m_buffer->emu_fw_ptr == m_buffer->pc_ptr) and (m_rd_odd == m_wr_odd)); 76 8586 : } 77 : 78 : // offset read (fw emu) 79 0 : uint64_t FileFromHostBuffer::dma_get_read_offset() 80 : { 81 0 : std::shared_lock<std::shared_mutex> lock(m_driver_mutex); 82 0 : return (m_buffer->emu_fw_ptr - m_buffer->paddr); 83 0 : } 84 : 85 : // offset write (pc) 86 10002 : uint64_t FileFromHostBuffer::dma_get_write_offset() 87 : { 88 10002 : std::shared_lock<std::shared_mutex> lock(m_driver_mutex); 89 10002 : return (m_buffer->pc_ptr - m_buffer->paddr); 90 10002 : } 91 : 92 : // offset write (pc) 93 10004 : void FileFromHostBuffer::dma_set_write_offset(uint64_t offset) 94 : { 95 10004 : uint64_t p_addr = m_buffer->paddr + offset; 96 10004 : set_write_ptr_paddr(p_addr); 97 10004 : } 98 : 99 : // vaddr 100 0 : uint64_t FileFromHostBuffer::dma_get_write_ptr() 101 : { 102 0 : std::shared_lock<std::shared_mutex> lock(m_driver_mutex); 103 0 : return (m_buffer->pc_ptr - m_buffer->paddr + m_buffer->vaddr); 104 0 : } 105 : 106 0 : void FileFromHostBuffer::dma_advance_write_ptr(size_t bytes) 107 : { 108 0 : if (bytes == 0) 109 : { 110 0 : return; 111 : } 112 0 : std::scoped_lock<std::shared_mutex> lock(m_driver_mutex); 113 0 : m_buffer->emu_fw_ptr += bytes; 114 0 : if (m_buffer->emu_fw_ptr == m_buffer->pend) 115 : { 116 0 : m_buffer->emu_fw_ptr = m_buffer->paddr; 117 0 : m_wr_odd = !m_wr_odd; 118 : } 119 0 : } 120 : 121 10004 : void FileFromHostBuffer::set_write_ptr_paddr(uint64_t p_addr) 122 : { 123 : // write ptr := pc_ptr 124 10004 : std::scoped_lock<std::shared_mutex> lock(m_driver_mutex); 125 10004 : if (p_addr == m_buffer->pc_ptr) 126 : { 127 1 : return; 128 : } 129 : 130 10003 : if (p_addr < m_buffer->pc_ptr) 131 : { 132 1 : unsigned int diff = (p_addr - m_buffer->pc_ptr); 133 1 : if (diff > 0.1 * m_buffer->size) 134 : { 135 1 : m_wr_odd = !m_wr_odd; 136 : } 137 : } 138 10003 : m_buffer->pc_ptr = p_addr; 139 10003 : m_reader_cond.notify_one(); 140 10004 : } 141 : 142 5 : void FileFromHostBuffer::copy_from_dma_buffer_to_file() 143 : { 144 5 : LOG_INFO("read_from_dma_buffer thread started"); 145 5 : uint64_t data_offset; 146 5 : int blocks_to_copy(0), copied_blocks(0); 147 : 148 6783 : while (m_run_flag.load()) 149 : { 150 : 151 6773 : { 152 : // wait for data in the FromHost DMA buffer 153 6773 : std::unique_lock<std::mutex> lk(m_wake_reader_mutex); 154 6773 : using namespace std::chrono_literals; 155 15359 : m_reader_cond.wait_for(lk, 500ms, [&] { return !dma_is_empty(); }); 156 6773 : } 157 : 158 6773 : { 159 : // copy current addresses 160 6773 : std::shared_lock<std::shared_mutex> lock(m_driver_mutex); 161 6773 : bool even = (m_rd_odd == m_wr_odd); 162 6773 : data_offset = m_buffer->emu_fw_ptr - m_buffer->paddr; 163 13546 : blocks_to_copy = (m_buffer->size - dma_compute_free_bytes(m_buffer->emu_fw_ptr, m_buffer->pc_ptr, even)) / m_encoder.get_block_size(); 164 6773 : } 165 : 166 6773 : LOG_TRACE("Blocks to copy %lu", blocks_to_copy); 167 : 168 : // What it does: if there is no trickle mode, it works normally. All the blocks are copied and the read pointer is advanced. 169 : // If the trickle mode is active (m_fw_reading_trickle is TRUE), it emulates the firmware by reading the buffer a maximum of 100 times to avoid an endless loop. 170 6773 : int n_copies = 0; 171 7673 : do 172 : { 173 7673 : copied_blocks = 0; 174 14606 : while (blocks_to_copy > copied_blocks) 175 : { 176 6933 : uint64_t input = (data_offset + copied_blocks * m_encoder.get_block_size()) % m_buffer->size; 177 6933 : void *input_ptr = reinterpret_cast<void *>(input + m_buffer->vaddr); 178 6933 : size_t max_blocks = blocks_to_copy - copied_blocks; 179 6933 : LOG_DBG("input ptr 0x%lx, buffer start 0x%lx, end 0x%lx size 0%lu", input_ptr, m_buffer->vaddr, m_buffer->vaddr + m_buffer->size, m_buffer->size); 180 6933 : copied_blocks += m_file.block_write(input_ptr, max_blocks); 181 6933 : LOG_DBG("%lu blocks copied to disk", copied_blocks); 182 : } 183 : } 184 7682 : while (m_fw_reading_trickle.load() && n_copies++ < 100); 185 6773 : dma_advance_read_ptr(copied_blocks * m_encoder.get_block_size()); 186 : } 187 5 : } 188 : 189 6773 : void FileFromHostBuffer::dma_advance_read_ptr(size_t bytes) 190 : { 191 6773 : LOG_TRACE("Advancing of %lu bytes", bytes); 192 6773 : if (bytes == 0) 193 : { 194 6773 : return; 195 : } 196 6733 : std::scoped_lock<std::shared_mutex> lock(m_driver_mutex); 197 6733 : m_buffer->emu_fw_ptr += bytes; 198 6733 : if (m_buffer->emu_fw_ptr == m_buffer->pend) 199 : { 200 1 : m_buffer->emu_fw_ptr = m_buffer->paddr; 201 1 : m_rd_odd = !m_rd_odd; 202 : } 203 6733 : }