LCOV - code coverage report
Current view: top level - src - decoder.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 130 161 80.7 %
Date: 2025-11-14 15:45:10 Functions: 8 8 100.0 %

          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             : }

Generated by: LCOV version 1.0