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
|