Home | History | Annotate | Download | only in parser
      1 #include "fw_pvt.h"
      2 #include "viddec_fw_parser_ipclib_config.h"
      3 #include "viddec_fw_common_defs.h"
      4 #include "viddec_pm_tags.h"
      5 #include "viddec_fw_parser.h"
      6 
      7 extern dmem_t _dmem;
      8 extern viddec_parser_ops_t parser_ops[MFD_STREAM_FORMAT_MAX];
      9 
     10 static void viddec_fw_parser_peekmessages(viddec_pm_cxt_t *pm, ipc_msg_data *wkld_cur, ipc_msg_data *wkld_next, int32_t *ret_cur, int32_t *ret_next, uint32_t stream_id)
     11 {
     12     FW_IPC_Handle *fwipc = GET_IPC_HANDLE(_dmem);
     13     wkld_cur->phys = wkld_next->phys = 0;
     14     /* read current and next workloads by peeking to free wkld queue.This would only give us a copy
     15        of message but won't actually pull it out of queue*/
     16 
     17     *ret_cur = FwIPC_PeekReadMessage(fwipc, &(fwipc->wkld_q[stream_id]), (char *)wkld_cur, sizeof(ipc_msg_data), 0);
     18     *ret_next = FwIPC_PeekReadMessage(fwipc, &(fwipc->wkld_q[stream_id]), (char *)wkld_next, sizeof(ipc_msg_data), 1);
     19     /* NOTE: I am passing length of current workload as size for next, since next workload might not exist. This is safe since in flush we always append to current workload */
     20     viddec_emit_update(&(pm->emitter), wkld_cur->phys, wkld_next->phys, wkld_cur->len, wkld_cur->len);
     21 }
     22 
     23 static void viddec_fw_parser_push_error_workload(viddec_pm_cxt_t *pm, ipc_msg_data *wkld_cur, uint32_t stream_id)
     24 {
     25     FW_IPC_Handle *fwipc = GET_IPC_HANDLE(_dmem);
     26     /* Push the current wkld */
     27     viddec_emit_set_workload_error(&(pm->emitter),
     28                                    (VIDDEC_FW_WORKLOAD_ERR_FLUSHED_FRAME | VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE),
     29                                    false);
     30     viddec_emit_flush_current_wkld(&(pm->emitter));
     31     FwIPC_SendMessage(fwipc, stream_id, (char *)wkld_cur, sizeof(ipc_msg_data));
     32     FwIPC_ReadMessage(fwipc, &(fwipc->wkld_q[stream_id]), (char *)wkld_cur, sizeof(ipc_msg_data));
     33 }
     34 
     35 int viddec_fw_parser_flush(unsigned int stream_id, unsigned int flush_type)
     36 {
     37     FW_IPC_Handle *fwipc = GET_IPC_HANDLE(_dmem);
     38     mfd_pk_strm_cxt *cxt;
     39     mfd_stream_info *cxt_swap;
     40     viddec_pm_cxt_t *pm;
     41     int32_t pos=0, ret = VIDDEC_FW_SUCCESS;/* success */
     42     uint32_t workloads_in_input_q = 0;
     43     cxt = (mfd_pk_strm_cxt *)&(_dmem.srm_cxt);
     44     cxt_swap = (mfd_stream_info *)&(_dmem.stream_info[stream_id]);
     45     pm = &(cxt->pm);
     46 
     47     workloads_in_input_q = ipc_mq_read_avail(&fwipc->wkld_q[stream_id].mq, (int32_t *)&pos);
     48     pos = 0;
     49     /* Check to see if output queue has space for next message */
     50     if(ipc_mq_write_avail(&fwipc->snd_q[stream_id].mq,&pos) >= workloads_in_input_q)
     51     {
     52         /* Check how many free workloads are available. Need at least 1 */
     53         if(workloads_in_input_q  >= CONFIG_IPC_MESSAGE_MAX_SIZE)
     54         {
     55             ipc_msg_data wkld_cur, wkld_next, cur_es;
     56             int32_t ret_cur=0,ret_next=0;
     57 
     58             {/* Swap context into local memory */
     59                 cp_using_dma(cxt_swap->ddr_cxt, (uint32_t) pm, sizeof(viddec_pm_cxt_t), false, false);
     60             }
     61 
     62             viddec_fw_parser_peekmessages(pm, &wkld_cur, &wkld_next, &ret_cur, &ret_next, stream_id);
     63             if(workloads_in_input_q >= (CONFIG_IPC_MESSAGE_MAX_SIZE << 1))
     64             {/* If we have more than 2 workloads, most likely current workload has partial data. To avoid overflow
     65                 lets push current and use next which is most likely empty .If there's only one workload it was
     66                 next for previous frame so most likely its empty in which case we don't do this logic*/
     67                 viddec_fw_parser_push_error_workload(pm, &wkld_cur, stream_id);
     68                 viddec_fw_parser_peekmessages(pm, &wkld_cur, &wkld_next, &ret_cur, &ret_next, stream_id);
     69             }
     70             /* Empty current es buffers in list */
     71             /* TODO(Assumption): we have to make sure that list flush is really succesful by checking return values.
     72                If our workload size is big enough to to accomadate buf done tags then its not necessary
     73                since we will guaranteed succesful writes for all es buffers */
     74             viddec_pm_generate_tags_for_unused_buffers_to_flush(pm);
     75             /* Check the number of ES buffers and append them to current wkld */
     76             while(FwIPC_ReadMessage(fwipc, &(fwipc->rcv_q[stream_id]), (char *)&cur_es, sizeof(ipc_msg_data)) != 0)
     77             {
     78                 /* NOTE(Assumption): Again we have to define workload size to be big enough to make sure we can fit
     79                    all the es buffers into current workload */
     80                 viddec_emit_contr_tag(&(pm->emitter), &cur_es, 0, false);
     81                 viddec_emit_assoc_tag(&(pm->emitter), cur_es.id, false);
     82             }
     83             viddec_fw_parser_push_error_workload(pm, &wkld_cur, stream_id);
     84             do
     85             {/* Read until no workloads left */
     86                 viddec_fw_parser_peekmessages(pm, &wkld_cur, &wkld_next, &ret_cur, &ret_next, stream_id);
     87                 if(ret_cur == 0)
     88                 {
     89                     break;
     90                 }
     91                 viddec_fw_parser_push_error_workload(pm, &wkld_cur, stream_id);
     92             }while(1);
     93             switch(flush_type)
     94             {
     95                 case VIDDEC_STREAM_FLUSH_DISCARD:
     96                 {
     97                     /* Reset pm_context */
     98                     viddec_fw_init_swap_memory(stream_id, 0, 1);
     99                 }
    100                 break;
    101                 case VIDDEC_STREAM_FLUSH_PRESERVE:
    102                 {
    103                         /* Reset just stream information */
    104                     viddec_fw_init_swap_memory(stream_id, 0, 0);
    105                 }
    106                 default:
    107                     break;
    108             }
    109             {/* swap context into DDR */
    110                 cp_using_dma(cxt_swap->ddr_cxt, (uint32_t) pm, sizeof(viddec_pm_cxt_t), true, false);
    111             }
    112         }
    113         else
    114         {
    115             pos = 0;
    116             /* check to see if I have any es buffers on input queue. If none are present we don't have to do anything */
    117             if(ipc_mq_read_avail(&fwipc->rcv_q[stream_id].mq, (int32_t *)&pos)  != 0)
    118                 ret = VIDDEC_FW_NEED_FREE_WKLD;
    119         }
    120     }
    121     else
    122     {
    123         /* data present in output queue. */
    124         ret =VIDDEC_FW_PORT_FULL;
    125     }
    126     return ret;
    127 }
    128