Line data Source code
1 : #include "decoder.hpp"
2 : #include "log.hpp"
3 : #include "publisher.hpp"
4 : #include "device.hpp"
5 : #include "tohost_monitor.hpp"
6 : #include <cstdint>
7 : #include <functional>
8 :
9 :
10 40 : Decoder::Decoder(const Elink &elink, Publisher &publisher, flx_tohost_format fmt,
11 40 : int l0id_decoder_fmt, unsigned int block_size, uint64_t buf_vaddr) :
12 40 : m_stats(elink.fid), m_elink(elink), m_publisher(publisher),
13 40 : m_buffer_vaddr(buf_vaddr), m_block_size(block_size)
14 : {
15 40 : switch (fmt) {
16 37 : case flx_tohost_format::TOHOST_SUBCHUNK_TRAILER:
17 586940999 : m_decode = [this](Block& b){return decode_subchunk_trailers(b);};
18 37 : break;
19 3 : case flx_tohost_format::TOHOST_SUBCHUNK_HEADER:
20 661 : m_decode = [this](Block& b){return decode_subchunk_headers(b);};
21 3 : break;
22 0 : default:
23 0 : LOG_ERR("ToHost data format %d not recognised. Assuming TOHOST_SUBCHUNK_TRAILER");
24 0 : m_decode = [this](Block& b){return decode_subchunk_trailers(b);};
25 : }
26 :
27 40 : if ( l0id_decoder_fmt > 0 ){
28 0 : if (elink.type == elink_type_t::TTC) {
29 0 : m_l0id_checker = std::make_unique<L0Decoder>(L0Decoder(elink.fid, 1));
30 : }
31 0 : else if (elink.type == elink_type_t::DAQ) {
32 0 : m_l0id_checker = std::make_unique<L0Decoder>(L0Decoder(elink.fid, l0id_decoder_fmt));
33 : }
34 : }
35 40 : }
36 :
37 :
38 579398971 : Publisher::Result Decoder::check_block_integrity(Block & block)
39 : {
40 : #if REGMAP_VERSION < 0x0500
41 : uint16_t* marker_word = (uint16_t*)(&block);
42 : if (block.marker != 0xABCD and marker_word[0] != marker_word[1])
43 : {
44 : LOG_ERR("Received invalid block header 0x%x. Block discarded.", block.marker);
45 : m_stats.increment_dropped_blocks();
46 : return Publisher::DECODING_ERROR;
47 : }
48 : #else
49 579398971 : unsigned bsize = (block.marker == 0xABCD) ? 1024 : ((block.marker >> 8) - 0xC0 + 1) * 1024;
50 579398971 : if (bsize != m_block_size) {
51 0 : LOG_ERR("received block header 0x%x with irregular block size %d, expected %d. Block discarded.",
52 : block.marker, bsize, m_block_size);
53 0 : m_stats.increment_dropped_blocks();
54 0 : return Publisher::DECODING_ERROR;
55 : }
56 : #endif
57 : //Sequence number check
58 579398971 : uint8_t expected_seqnr = (m_last_seqnr + 1) % 32;
59 579398971 : if(block.sequence_number != expected_seqnr)
60 : {
61 3706944 : if(!(m_seqnr_err++ % 100)){
62 43454 : LOG_DBG("received wrong sequence number: %d instead of %d (E-link: %d)",
63 : block.sequence_number, expected_seqnr, block.elink);
64 : }
65 : }
66 579398971 : m_last_seqnr = block.sequence_number;
67 579398971 : m_last_block = (reinterpret_cast<uint64_t>(&block) - m_buffer_vaddr) & 0xffffffff;
68 579398971 : return Publisher::Result::OK;
69 : }
70 :
71 586945130 : Publisher::Result Decoder::decode(Block & block)
72 : {
73 586945130 : return m_decode(block);
74 : }
75 :
76 :
77 658 : Publisher::Result Decoder::decode_subchunk_headers(Block & block)
78 : {
79 658 : using subchunk_header_t = subchunk_trailer_t;
80 :
81 658 : const bool first_time_decoding = (m_chunk_position == 0);
82 :
83 658 : if (first_time_decoding) {
84 658 : auto ret = check_block_integrity(block);
85 658 : if (ret == Publisher::Result::DECODING_ERROR) {
86 : return ret;
87 : }
88 : }
89 :
90 1590 : Publisher::Result r = Publisher::OK;
91 2522 : while (true) {
92 1590 : const auto chunk_header = *reinterpret_cast<subchunk_header_t*>(block.data + m_chunk_position);
93 :
94 1590 : uint16_t subchk_size = chunk_header.data.length;
95 1590 : uint16_t length = subchk_size + sizeof(subchunk_header_t) + (-subchk_size % sizeof(subchunk_header_t));
96 1590 : uint16_t next = m_chunk_position + length;
97 :
98 1590 : if (next > sizeof(block.data)) {
99 0 : LOG_ERR("Block 0x%lx of fid 0x%lx (elink 0x%x) discarded due to broken chunk length %u. Next position %u, header value 0x%x",
100 : &block, m_elink.fid, m_elink.lid, length, next, chunk_header.value);
101 0 : m_chunk_position = 0;
102 0 : m_stats.increment_processed_blocks();
103 0 : return Publisher::DECODING_ERROR;
104 : }
105 1590 : uint8_t fw_flags = (chunk_header.data.trunc) | (chunk_header.data.err << 2) | (chunk_header.data.crcerr << 3);
106 3180 : r = post_subchunk(block.data + m_chunk_position + sizeof(subchunk_header_t),
107 : subchk_size,
108 1590 : static_cast<Decoder::SubchunkType>(chunk_header.data.type),
109 : fw_flags);
110 :
111 1590 : if (r == Publisher::AGAIN or r == Publisher::PARTIAL) {
112 : return r;
113 : }
114 :
115 1590 : if (r == Publisher::DECODING_ERROR) {
116 0 : m_scratch.clear();
117 0 : break;
118 : }
119 :
120 1590 : if (r == Publisher::ERROR) {
121 0 : m_scratch.clear();
122 : }
123 :
124 1590 : if (next == sizeof(block.data)) {
125 658 : if(m_elink.type == elink_type_t::TTC){
126 655 : m_publisher.flush(m_elink.fid);
127 : }
128 : break;
129 : }
130 :
131 932 : m_chunk_position = next;
132 932 : }
133 :
134 658 : m_stats.increment_processed_blocks();
135 658 : m_chunk_position = 0;
136 658 : return r;
137 : }
138 :
139 :
140 586939001 : Publisher::Result Decoder::decode_subchunk_trailers(Block & block)
141 : {
142 : //No chunks already decoded waiting to be sent
143 586939001 : if (m_subchunks.empty()) {
144 :
145 579398918 : auto ret = check_block_integrity(block);
146 579395573 : if (ret != Publisher::Result::OK){
147 : return ret;
148 : }
149 :
150 : //Starting from the end of the block, save location of all subchunk trailers
151 579395573 : int pos = m_block_size - BLOCK_HEADER_SIZE;
152 579395573 : unsigned int trailer_size = sizeof(subchunk_trailer_t);
153 2315382635 : while (pos > 0) {
154 1735944136 : subchunk_trailer_t trailer = *(reinterpret_cast<subchunk_trailer_t*>(block.data + pos - trailer_size));
155 :
156 : #if REGMAP_VERSION < 0x0500
157 : // Check for FE BUSY
158 : if (trailer.value == 0xE05C) {
159 : pos -= sizeof(subchunk_trailer_t);
160 : trailer = *(reinterpret_cast<subchunk_trailer_t*>(block.data + pos - trailer_size));
161 : }
162 : #endif
163 1735944136 : uint32_t length = trailer.data.length;
164 : //padding: (-length % trailer_size)
165 1735944136 : pos -= length + trailer_size + (-length % trailer_size);
166 1735944136 : if (pos < 0) {
167 0 : LOG_ERR("Block 0x%lx of fid 0x%lx (elink 0x%x) discarded due to broken chunk length %u. Decoding position %u, trailer value 0x%x",
168 : block.data, m_elink.fid, m_elink.lid, length, pos, trailer.value);
169 0 : return Publisher::DECODING_ERROR;
170 : }
171 :
172 1735944136 : SubchunkType t = (SubchunkType)trailer.data.type;
173 :
174 1735944136 : if ((t == TIMEOUT and !trailer.data.trunc) or t == NIL or t == OOB) {
175 755432246 : continue;
176 : }
177 :
178 980511890 : uint16_t p = static_cast<uint16_t>(pos);
179 980511890 : m_subchunks.emplace_back(p, trailer.value);
180 : }
181 : }
182 :
183 : //Process and publish subchunks
184 1567436847 : while (not m_subchunks.empty()) {
185 988054018 : const auto & sc = m_subchunks[m_subchunks.size() - 1];
186 988054018 : subchunk_trailer_t tr;
187 988054018 : tr.value = sc.second;
188 988054018 : uint8_t fw_flags = (tr.data.trunc) | (tr.data.err << 2) | (tr.data.crcerr << 3);
189 988054018 : auto r = post_subchunk(block.data + sc.first, tr.data.length, (Decoder::SubchunkType)tr.data.type, fw_flags);
190 987998459 : if (r == Publisher::AGAIN) {
191 7547903 : return r;
192 : }
193 980450556 : if (r == Publisher::ERROR) {
194 0 : m_stats.increment_dropped_blocks();
195 0 : m_subchunks.clear();
196 0 : m_scratch.clear();
197 0 : return r;
198 : }
199 980450556 : m_subchunks.resize(m_subchunks.size() - 1);
200 980458265 : if(m_elink.type == elink_type_t::TTC && m_subchunks.empty()){
201 10831145 : m_publisher.flush(m_elink.fid);
202 : }
203 : }
204 :
205 579382829 : m_stats.increment_processed_blocks();
206 579382829 : return Publisher::OK;
207 : }
208 :
209 :
210 751646416 : void Decoder::on_successful_send()
211 : {
212 751646416 : m_stats.update_processed_chunk(m_scratch.get_status_byte(), m_scratch.byte_size());
213 751645953 : if (m_l0id_checker) {
214 0 : if ( m_l0id_checker->check_tohost_chunk(m_scratch.iov) ) {
215 0 : m_stats.increment_oosequence_l0id();
216 : }
217 : }
218 751645953 : if ( m_elink.has_streams ){ m_elink.fid &= 0xFFFFFFFFFFFFFF00; }
219 751645953 : m_scratch.clear();
220 751643342 : }
221 :
222 :
223 : /**
224 : * If this function returns AGAIN then it is guaranteed that
225 : * the current subchunk was not processed and must be submitted again
226 : */
227 988099408 : Publisher::Result Decoder::post_subchunk(
228 : uint8_t* data, uint32_t length, SubchunkType type, uint8_t fw_flags)
229 : {
230 : //First switch case mostly addresses error conditions
231 988099408 : switch(type) {
232 781877159 : case FIRST:
233 781877159 : case WHOLE:
234 781877159 : if (length == 0) {
235 0 : m_stats.increment_empty_chunks();
236 0 : return Publisher::OK;
237 : }
238 781877159 : if (not m_scratch.empty()) {
239 : //If scratch space not empty mark trucantion and publish leftover
240 31019773 : m_scratch.update_status_byte(SW_TRUNC);
241 31019773 : auto r = m_publisher.publish(m_elink.fid, m_scratch.iov_addr(), m_scratch.iov_len(), m_scratch.byte_size(), m_last_block, m_scratch.get_status_byte());
242 31019773 : if (Publisher::OK != r) {
243 : return r;
244 : } else {
245 1358899 : on_successful_send();
246 : }
247 : }
248 : break;
249 :
250 :
251 206221592 : case LAST:
252 206221592 : case MIDDLE:
253 206221592 : if (m_scratch.empty()) {
254 : //If the scratch empty mark truncation and add subschunk
255 8 : m_scratch.update_status_byte(SW_TRUNC);
256 : }
257 206221592 : m_scratch.update_status_byte(fw_flags);
258 206221592 : m_scratch.push_back(iovec{data, length});
259 206244060 : break;
260 :
261 655 : case TIMEOUT:
262 655 : if (fw_flags & FW_TRUNC) {
263 0 : return post_subchunk(data, length, m_scratch.empty() ? WHOLE : LAST, fw_flags);
264 : } else {
265 : //Discarded if no truncation flagged by firmware
266 : return Publisher::OK;
267 : }
268 :
269 : case NIL:
270 : case OOB:
271 : return Publisher::OK;
272 :
273 0 : default:
274 0 : LOG_ERR("invalid subchunk type=%d", type);
275 0 : return Publisher::DECODING_ERROR;
276 : }
277 :
278 : //Second switch case, no error conditions
279 958460345 : switch(type) {
280 :
281 62107029 : case FIRST:
282 62107029 : {
283 62107029 : m_scratch.update_status_byte(fw_flags);
284 62107029 : m_scratch.push_back(iovec{data, length});
285 62107029 : if ( m_elink.has_streams ){ m_elink.fid |= data[0]; }
286 : break;
287 : }
288 :
289 690131724 : case WHOLE:
290 690131724 : {
291 690131724 : m_scratch.update_status_byte(fw_flags);
292 690131724 : m_scratch.push_back(iovec{data, length});
293 690147441 : if ( m_elink.has_streams ){ m_elink.fid |= data[0]; }
294 690147441 : auto r = m_publisher.publish(m_elink.fid, m_scratch.iov_addr(), m_scratch.iov_len(), m_scratch.byte_size(), m_last_block, m_scratch.get_status_byte());
295 690149318 : if (Publisher::AGAIN == r) {
296 507269 : m_scratch.remove_last_entry();
297 : } else {
298 689642049 : on_successful_send();
299 : }
300 : return r;
301 : }
302 :
303 67786194 : case LAST:
304 67786194 : {
305 67786194 : auto r = m_publisher.publish(m_elink.fid, m_scratch.iov_addr(), m_scratch.iov_len(), m_scratch.byte_size(), m_last_block, m_scratch.get_status_byte());
306 67786194 : if (Publisher::AGAIN == r) {
307 7038070 : m_scratch.remove_last_entry();
308 : } else {
309 60748124 : on_successful_send();
310 : }
311 : return r;
312 : }
313 :
314 : default:
315 : break;
316 : }
317 :
318 : return Publisher::OK;
319 : }
320 :
321 :
322 293 : ToHostElinkStats Decoder::get_decoder_stats_increment(ToHostElinkStats & previous)
323 : {
324 293 : return m_stats.get_increment(previous);
325 : }
|