view src/cs/layer1/dyn_dwl_cfile/l1_dyn_dwl_func.c @ 220:0ed36de51973

ABB semaphore protection overhaul The ABB semaphone protection logic that came with TCS211 from TI was broken in several ways: * Some semaphore-protected functions were called from Application_Initialize() context. NU_Obtain_Semaphore() called with NU_SUSPEND fails with NU_INVALID_SUSPEND in this context, but the return value wasn't checked, and NU_Release_Semaphore() would be called unconditionally at the end. The latter call would increment the semaphore count past 1, making the semaphore no longer binary and thus no longer effective for resource protection. The fix is to check the return value from NU_Obtain_Semaphore() and skip the NU_Release_Semaphore() call if the semaphore wasn't properly obtained. * Some SPI hardware manipulation was being done before entering the semaphore- protected critical section. The fix is to reorder the code: first obtain the semaphore, then do everything else. * In the corner case of L1/DSP recovery, l1_abb_power_on() would call some non-semaphore-protected ABB & SPI init functions. The fix is to skip those calls in the case of recovery. * A few additional corner cases existed, all of which are fixed by making ABB semaphore protection 100% consistent for all ABB functions and code paths. There is still one remaining problem of priority inversion: suppose a low- priority task calls an ABB function, and some medium-priority task just happens to preempt right in the middle of that semaphore-protected ABB operation. Then the high-priority SPI task is locked out for a non-deterministic time until that medium-priority task finishes its work and goes back to sleep. This priority inversion problem remains outstanding for now.
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 26 Apr 2021 20:55:25 +0000
parents 4e78acac3d88
children
line wrap: on
line source

/************* Revision Controle System Header *************
 *                  GSM Layer 1 software
 * L1_DYN_DWL_FUNC.C
 *
 *        Filename l1_dyn_dwl_func.c
 *  Copyright 2004 (C) Texas Instruments
 *
 ************* Revision Controle System Header *************/

#include <stdio.h>
#include <string.h>
#include "l1_confg.h"
#include "l1_types.h"
#include "l1_const.h"        
#include "l1_signa.h"     
#include "sys_types.h"

#if(L1_DYN_DSP_DWNLD == 1)
#include "l1_dyn_dwl_const.h"
#include "l1_dyn_dwl_proto.h"
#include "l1_dyn_dwl_defty.h"
#endif
#if TESTMODE
  #include "l1tm_defty.h"
#endif
#if (AUDIO_TASK == 1)
  #include "l1audio_const.h"
  #include "l1audio_cust.h"
  #include "l1audio_defty.h"
#endif
#if (L1_GTT == 1)
  #include "l1gtt_const.h"
  #include "l1gtt_defty.h"
#endif
#if (L1_MP3 == 1)
  #include "l1mp3_defty.h"
#endif //L1_MP3
#if (L1_MIDI == 1)
  #include "l1midi_defty.h"
#endif

 #include "l1_defty.h"
 #include "l1_varex.h"
 #include "l1_macro.h"

#if (L1_DYN_DSP_DWNLD == 1)
  #ifndef NULL
#define NULL 0
  #endif

  extern T_DYN_DWNLD_MCU_DSP *dyn_dwl_ndb;
  #if (CODE_VERSION == SIMULATION)
    extern T_DYN_DWNLD_MCU_DSP dyn_dwl_ndb_sim;
  extern UWORD16 dwnld_area_array[SIZE_DWNLD_AREA_SIMU];
#endif // CODE_VERSION == SIMULATION


/*---------------------------------------------------------------------------- */
/* l1_initialize_patch_parameters                                              */
/*-------------------------------------------------------------------------    */
/*                                                                             */
/* Parameters :                                                                */
/*                                                                             */
/* Return     :    size of the patch                                           */
/*                                                                             */
/* Description :  Initialize patch parameters and returns the size of the patch*/
/*                                                                             */
/*                                                                             */
/*---------------------------------------------------------------------------- */
 
UWORD16 l1_initialize_patch_parameters(void)
{
  UWORD16 patch_size = 0;

  /* Initialize download patch parameters */
  l1_apihisr.dyn_dwnld.running_source_pointer = l1a_apihisr_com.dyn_dwnld.copy_parameters.start_MCU_copy_address[l1a_apihisr_com.dyn_dwnld.copy_parameters.num_of_elem-l1_apihisr.dyn_dwnld.patch_ids_counter];
  patch_size = l1a_apihisr_com.dyn_dwnld.copy_parameters.size_array[l1a_apihisr_com.dyn_dwnld.copy_parameters.num_of_elem-l1_apihisr.dyn_dwnld.patch_ids_counter];
  dyn_dwl_ndb->d_api_dwl_crc = 0x0; 
  return patch_size;
}

/*---------------------------------------------------------------------------- */
/* l1_set_uninstall_parameters                                                 */
/*-------------------------------------------------------------------------    */
/*                                                                             */
/* Parameters : void                                                           */
/*                                                                             */
/* Return     :    void                                                        */
/*                                                                             */
/* Description :  Set uninstall parameters                                     */
/*                                                                             */
/*                                                                             */
/*---------------------------------------------------------------------------- */
 
void l1_set_uninstall_parameters(void)
{
  /* Set next uninstall adress (pointer incremented) */
  dyn_dwl_ndb->d_api_dwl_function_address[0] = (API) (l1a_apihisr_com.dyn_dwnld.uninstall_parameters.address[l1a_apihisr_com.dyn_dwnld.uninstall_parameters.num_of_elem - l1_apihisr.dyn_dwnld.uninstall_counter] & 0x0000FFFF); 
  dyn_dwl_ndb->d_api_dwl_function_address[1] = (API) ((l1a_apihisr_com.dyn_dwnld.uninstall_parameters.address[l1a_apihisr_com.dyn_dwnld.uninstall_parameters.num_of_elem - l1_apihisr.dyn_dwnld.uninstall_counter] >> 16) & 0x0000FFFF); 

  /* Set uninstall command */
  dyn_dwl_ndb->d_api_dwl_download_ctrl = (API) C_DWL_DOWNLOAD_CTRL_UNINSTALL;   
}

/*---------------------------------------------------------------------------- */
/* l1_initialize_pointers_for_copy                                             */
/*-------------------------------------------------------------------------    */
/*                                                                             */
/* Parameters :   address of source and destination pointer                    */
/*                                                                             */
/* Return     :   source and destination address modified by reference         */
/*                                                                             */
/* Description :  Initialize the pointers for the copy                         */
/*                                                                             */
/*                                                                             */
/*---------------------------------------------------------------------------- */

void l1_initialize_pointers_for_copy(UWORD16 **pp_dest_mcu, UWORD16 **pp_src_mcu)
{
  /* BEGIN: Initialize download area parameters at start download area */
  dyn_dwl_ndb->d_api_dwl_write_pointer = l1a_apihisr_com.dyn_dwnld.copy_parameters.start_of_dwnld_area - 1; // correction
    
  /* Initialize pointers */
#if (CODE_VERSION == SIMULATION)
  *pp_dest_mcu = (UWORD16 *) dwnld_area_array;
#else
  *pp_dest_mcu = (UWORD16 *) API_address_dsp2mcu(l1a_apihisr_com.dyn_dwnld.copy_parameters.start_of_dwnld_area);
#endif // CODE_VERSION == SIMULATION

  *pp_src_mcu  = (UWORD16 *) l1_apihisr.dyn_dwnld.running_source_pointer;   
}

/*--------------------------------------------------------*/
/* l1_memcpy_16bit()                                      */
/*--------------------------------------------------------*/
/*                                                        */
/* Description:                                           */
/* ------------                                           */
/* This function is equivalemt of memcopy. Thid function  */
/* does only 8/16 bit accessed to both source and         */
/* destination                                            */
/*                                                        */
/* Input parameter:                                       */
/* ---------------                                        */
/* "src" - input pointer                                  */
/* "len" - number of bytes to copy                        */
/*                                                        */
/* Output parameter:                                      */
/* ----------------                                       */
/*  "dst" - output pointer                                */
/*                                                        */
/*--------------------------------------------------------*/
void l1_memcpy_16bit(void *dst,void* src,unsigned int len)
{
	unsigned int i;
	unsigned int tempLen;
	unsigned char *cdst,*csrc;
	unsigned short *ssrc,*sdst;

	cdst=dst;
	csrc=src;
	sdst=dst;
	ssrc=src;

  if(((unsigned int)src&0x01) || ((unsigned int)dst&0x01)){
  // if either source or destination is not 16-bit aligned do the entire memcopy
  // in 8-bit
    for(i=0;i<len;i++){
      *cdst++=*csrc++;
    }
  }
  else{
    // if both the source and destination are 16-bit aligned do the memcopy
    // in 16-bits
    tempLen = len>>1;
    for(i=0;i<tempLen;i++){
      *sdst++ = *ssrc++;
    }
    if(len & 0x1){
      // if the caller wanted to copy odd number of bytes do a last 8-bit copy
      cdst=(unsigned char*)sdst;
      csrc=(unsigned char*)ssrc;
      *cdst++ = *csrc++;
    }
  }
  return;
}

/*---------------------------------------------------------------------------- */
/* l1_copy_till_the_end_of_the_patch_and_update_write_pointer                  */
/*---------------------------------------------------------------------------- */
/*                                                                             */
/* Parameters : size of the patch, source and destination pointer              */
/*                                                                             */
/* Return     : none                                                           */
/*                                                                             */
/* Description : Copy until the end of the patch is reached                    */
/*                                                                             */
/*                                                                             */
/*---------------------------------------------------------------------------- */

void l1_copy_till_the_end_of_the_patch_and_update_write_pointer(UWORD16 tmp_patch_size, UWORD16* p_dest_mcu, UWORD16* p_src_mcu)
{
  while (tmp_patch_size > NUM_WORDS_COPY_API)
  {
    l1_memcpy_16bit(p_dest_mcu,p_src_mcu, NUM_WORDS_COPY_API*sizeof(UWORD16));
    p_dest_mcu += NUM_WORDS_COPY_API;
    p_src_mcu  += NUM_WORDS_COPY_API;
    tmp_patch_size -= NUM_WORDS_COPY_API;
    dyn_dwl_ndb->d_api_dwl_write_pointer += NUM_WORDS_COPY_API;
  }
  if (tmp_patch_size != 0)
  {  
    l1_memcpy_16bit(p_dest_mcu,p_src_mcu, tmp_patch_size*sizeof(UWORD16));
    dyn_dwl_ndb->d_api_dwl_write_pointer += tmp_patch_size;
  }
}

/*---------------------------------------------------------------------------- */
/* l1_copy_till_end_of_dwnld_area_and_update_write_pointer                     */
/*---------------------------------------------------------------------------- */
/*                                                                             */
/* Parameters : address of size of the patch, size of download area,           */
/*              addresses of source pointer, destination pointer               */
/*                                                                             */
/* Return     : source pointer and size modified by reference                  */
/*                                                                             */
/* Description : Copy until the end of download area is reached                */
/*                                                                             */
/*                                                                             */
/*---------------------------------------------------------------------------- */

void l1_copy_till_end_of_dwnld_area_and_update_write_pointer(UWORD16 tmp_dwnld_area_size,UWORD16 *p_dest_mcu, UWORD16 *p_tmp_patch_size, UWORD16 **pp_src_mcu)
{
  UWORD16 tmp_patch_size = *p_tmp_patch_size;
  UWORD16 *p_src_mcu = (UWORD16 *)*pp_src_mcu;

  while (tmp_dwnld_area_size > NUM_WORDS_COPY_API)
  {
    l1_memcpy_16bit(p_dest_mcu,p_src_mcu, NUM_WORDS_COPY_API*sizeof(UWORD16));
    p_dest_mcu += NUM_WORDS_COPY_API;
    p_src_mcu  += NUM_WORDS_COPY_API;
    tmp_patch_size      -= NUM_WORDS_COPY_API;
    tmp_dwnld_area_size -= NUM_WORDS_COPY_API;
    dyn_dwl_ndb->d_api_dwl_write_pointer += NUM_WORDS_COPY_API;
  }

  if (tmp_dwnld_area_size > 0)
  {
    l1_memcpy_16bit(p_dest_mcu,p_src_mcu, tmp_dwnld_area_size*sizeof(UWORD16));
    p_src_mcu += tmp_dwnld_area_size;  
    tmp_patch_size -= tmp_dwnld_area_size;
    dyn_dwl_ndb->d_api_dwl_write_pointer += tmp_dwnld_area_size;
  }
  *pp_src_mcu = (UWORD16 *) p_src_mcu;
  *p_tmp_patch_size = tmp_patch_size;
}

/*---------------------------------------------------------------------------- */
/* l1_copy_first_N_words                                                       */
/*---------------------------------------------------------------------------- */
/*                                                                             */
/* Parameters : address of size of the patch, address of size of download area,*/
/*              addresses of source pointer, address of destination pointer    */
/*                                                                             */
/* Return     : source and  destination  pointer modified by reference         */
/*              size of download area and patch area modified by reference     */
/*                                                                             */
/* Description : Copy the min(N, remaining size of the patch) at the beginning */
/*               download area                                                 */
/*                                                                             */
/*                                                                             */
/*---------------------------------------------------------------------------- */

BOOL l1_copy_first_N_words (UWORD16 *dwnld_area_size_p, UWORD16 *patch_area_size_p, UWORD16 **pp_dest_mcu, UWORD16 **pp_src_mcu)
{
  BOOL    return_flag;
  UWORD16 num_words_interrupt;
  UWORD16 tmp_patch_size = *patch_area_size_p;
  UWORD16 tmp_dwnld_area_size = *dwnld_area_size_p;
  UWORD16 *p_dest_mcu =(UWORD16 *)*pp_dest_mcu;
  UWORD16 *p_src_mcu = (UWORD16 *)*pp_src_mcu;

  /* Copy first N words and generate API interrupt*/
  if (tmp_patch_size > NUM_WORDS_COPY_API)
  {  
    num_words_interrupt = NUM_WORDS_COPY_API;
    return_flag = TRUE;
  }
  else
  {
    num_words_interrupt = tmp_patch_size;
    return_flag = FALSE;
  }

  l1_memcpy_16bit(p_dest_mcu,p_src_mcu, num_words_interrupt*sizeof(UWORD16));

  p_dest_mcu += num_words_interrupt;
  p_src_mcu  += num_words_interrupt;

  tmp_patch_size      -= num_words_interrupt;
  tmp_dwnld_area_size -= num_words_interrupt;
  
  dyn_dwl_ndb->d_api_dwl_write_pointer+=num_words_interrupt;
  
  *patch_area_size_p = tmp_patch_size;
  *dwnld_area_size_p = tmp_dwnld_area_size;
  *pp_dest_mcu       = (UWORD16 *)p_dest_mcu;
  *pp_src_mcu        = (UWORD16 *)p_src_mcu ;
  
  return return_flag;
}

/*---------------------------------------------------------------------------- */
/* l1_initialize_download_area_parameters                                      */
/*---------------------------------------------------------------------------- */
/*                                                                             */
/* Parameters : none                                                           */
/*                                                                             */
/*                                                                             */
/* Return     : download area size                                             */
/*                                                                             */
/* Description : Initialize download area: all the parameters                  */
/*                                                                             */
/*                                                                             */
/*---------------------------------------------------------------------------- */

UWORD16 l1_initialize_download_area_parameters(void)
{
  UWORD16 dwnld_area_size = 0;

  /* Set download address and size in API-DSP com */
  dyn_dwl_ndb->d_api_dwl_function_address[0] = l1a_apihisr_com.dyn_dwnld.copy_parameters.start_of_dwnld_area;
  dyn_dwl_ndb->d_api_dwl_function_address[1] = 0x0;      

#if (CODE_VERSION == SIMULATION)
  dyn_dwl_ndb->d_api_dwl_size = SIZE_DWNLD_AREA_SIMU;
#else
  dyn_dwl_ndb->d_api_dwl_size = l1a_apihisr_com.dyn_dwnld.copy_parameters.size_of_dwnld_area;
#endif  // CODE_VERSION == SIMULATION

  dwnld_area_size = l1a_apihisr_com.dyn_dwnld.copy_parameters.size_of_dwnld_area;
  return dwnld_area_size;
}

/*---------------------------------------------------------------------------- */
/* l1_init_pointers_and_copy_first_block_of_data                               */
/*---------------------------------------------------------------------------- */
/*                                                                             */
/* Parameters : address of size of the patch, address of size of download area,*/
/*              addresses of source pointer, address of destination pointer    */
/*              new patch flag                                                 */
/* Return     : TRUE if N< size of patch, FALSE otherwise                      */
/*              source and  destination  pointer modified by reference         */
/*              size of download area and patch area modified by reference,    */
/*                                                                             */
/* Description : Initialize pointers and starts the copy.                      */
/*                                                                             */
/*                                                                             */
/*                                                                             */
/*---------------------------------------------------------------------------- */

BOOL l1_init_pointers_and_copy_first_block_of_data(UWORD16 *dwnld_area_size_p, UWORD16 *patch_size_p, UWORD16 **pp_dest_mcu, UWORD16 **pp_src_mcu, BOOL new_patch)
{
  BOOL return_flag;

  /* Initialize download area*/
  *dwnld_area_size_p = l1_initialize_download_area_parameters();

  /* In case this is a new patch, initialize patch parameters*/
  if (new_patch == TRUE)
    *patch_size_p = l1_initialize_patch_parameters();

  /* Initialize pointers for the copy*/
  l1_initialize_pointers_for_copy(pp_dest_mcu, pp_src_mcu);

  /* If this is a new patch, the header of the patch must be taken off from the copy*/
  if (new_patch == TRUE)
  {
    /* Take the initial header off */
    *pp_src_mcu= (*pp_src_mcu)+HEADER_PATCH_SIZE;
    *patch_size_p= (*patch_size_p)-HEADER_PATCH_SIZE;
  }
    
  /* Copy first N words; if remaining size of the patch is smaller than N copy until the end of the patch */
  /* In this case, return FALSE as there are no more words to be copied*/
  return_flag = l1_copy_first_N_words (dwnld_area_size_p, patch_size_p, pp_dest_mcu, pp_src_mcu);
    
  return return_flag;
}


/*---------------------------------------------------------------------------- */
/* l1_set_dyn_dwnld_install_vect                                               */
/*---------------------------------------------------------------------------- */
/*                                                                             */
/* Parameters : size vector, destination address vector, crc vector            */
/*              patch code vector, identifier i of the patch                   */
/*              new patch flag                                                 */
/* Return     : TRUE operation is successful, FALSE otherwise                  */
/*                                                                             */
/* Description : Compute address, size and crc of i-th patch                   */
/*                                                                             */
/*---------------------------------------------------------------------------- */

BOOL l1_set_dyn_dwnld_install_vect(UWORD16* size_p, UWORD32* dest_addr, UWORD16* crc_vect, const UWORD8 *patch_array_code, UWORD16 i)
{
  UWORD16 full_size_32_bit, size, size_ext, dsp_addr, dsp_addr_ext, crc_value;
  UWORD16 *codePtr;
  UWORD16 size_total = 0;
  BOOL status_flag = FALSE;
  codePtr = (UWORD16 *) patch_array_code;
  
  if ( (0 == *codePtr++) && (0 == *codePtr++)) 
  {  // NULL TAG detection
    if ( (3 == *codePtr++) && (0 == *codePtr++)) 
    {   // coff2c version number detection
      size = *codePtr++;
      size_ext        = *codePtr++; 
   
      // first header:4
      size_total+=HEADER_PATCH_SIZE; 
      while(size != 0 || size_ext != 0)
      {    
        full_size_32_bit = (size_ext << 16) + size;
        // reconstruction of the total 32-bit size of the section
        size_total+=HEADER_PATCH_SIZE+full_size_32_bit+1;
        // Header + size_block + cntrl_word(0xDEAD):1
        codePtr+=full_size_32_bit+2+1; 
        // Two words for address and one for the cntrl word 0xDEAD
        size = *codePtr++;
        size_ext = *codePtr++;
      }
      size_total+=HEADER_PATCH_SIZE;
      // Last header to consider

      dsp_addr = *codePtr++;
      dsp_addr_ext = *codePtr++;
      crc_value = *codePtr++;
      dest_addr[i] = (dsp_addr_ext << 16)+dsp_addr;
      crc_vect[i] = crc_value;
      size_p[i] = size_total;
      status_flag = TRUE;
    }
  }
  return status_flag;
}
#endif //L1_DYN_DSP_DWNLD == 1