FreeCalypso > hg > fc-tourmaline
view src/nucleus/dms.c @ 303:f76436d19a7a default tip
!GPRS config: fix long-standing AT+COPS chance hanging bug
There has been a long-standing bug in FreeCalypso going back years:
sometimes in the AT command bring-up sequence of an ACI-only MS,
the AT+COPS command would produce only a power scan followed by
cessation of protocol stack activity (only L1 ADC traces), instead
of the expected network search sequence. This behaviour was seen
in different FC firmware versions going back to Citrine, and seemed
to follow some law of chance, not reliably repeatable.
This bug has been tracked down and found to be specific to !GPRS
configuration, stemming from our TCS2/TCS3 hybrid and reconstruction
of !GPRS support that was bitrotten in TCS3.2/LoCosto version.
ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3
version and had to be pulled from TCS2 - but as it turns out,
there is a new field in the MMR_REG_REQ primitive that needs to be
set correctly, and that psa_mms.c module is the place where this
initialization needed to be added.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 08 Jun 2023 08:23:37 +0000 |
parents | 4e78acac3d88 |
children |
line wrap: on
line source
/*************************************************************************/ /* */ /* Copyright Mentor Graphics Corporation 2002 */ /* All Rights Reserved. */ /* */ /* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS */ /* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS */ /* SUBJECT TO LICENSE TERMS. */ /* */ /*************************************************************************/ /*************************************************************************/ /* */ /* FILE NAME VERSION */ /* */ /* dms.c Nucleus PLUS 1.14 */ /* */ /* COMPONENT */ /* */ /* DM - Dynamic Memory Management */ /* */ /* DESCRIPTION */ /* */ /* This file contains the supplemental routines for the Dynamic */ /* Memory Management component. */ /* */ /* DATA STRUCTURES */ /* */ /* None */ /* */ /* FUNCTIONS */ /* */ /* DMS_Allocate_Aligned_Memory Allocate an aligned memory */ /* block from a dynamic */ /* memory pool */ /* DEPENDENCIES */ /* */ /* cs_extr.h Common Service functions */ /* tc_extr.h Thread Control functions */ /* dm_extr.h Partition functions */ /* hi_extr.h History functions */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 01-15-1999 Created initial revision */ /* 03-26-1999 Released 1.11m (new release */ /* numbering scheme) */ /* 04-17-2002 Released version 1.13m */ /* 11-07-2002 Released version 1.14 */ /*************************************************************************/ #define NU_SOURCE_FILE #include "cs_extr.h" /* Common service functions */ #include "tc_extr.h" /* Thread control functions */ #include "dm_extr.h" /* Dynamic memory functions */ #include "hi_extr.h" /* History functions */ #include "profiler.h" /* ProView interface */ /* Define external inner-component global data references. */ /* Define internal component function prototypes. */ VOID DMC_Cleanup(VOID *information); /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* DMS_Allocate_Aligned_Memory */ /* */ /* DESCRIPTION */ /* */ /* This function allocates memory from the specified dynamic memory */ /* pool. If dynamic memory is currently available, this function */ /* is completed immediately. Otherwise, if there is not enough */ /* memory currently available, task suspension is possible. */ /* */ /* CALLED BY */ /* */ /* Application */ /* */ /* CALLS */ /* */ /* CSC_Place_On_List Place on suspend list */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCC_Suspend_Task Suspend calling task */ /* TCC_Task_Priority Pickup task priority */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Current_Thread Pickup current thread pointer*/ /* TCT_Protect Protect memory pool */ /* TCT_Set_Suspend_Protect Save suspend protection */ /* TCT_System_Protect Protect system structures */ /* TCT_Unprotect Release protection */ /* TCT_Unprotect_Specific Release specific protection */ /* */ /* INPUTS */ /* */ /* pool_ptr Memory pool pointer */ /* return_pointer Pointer to the destination */ /* memory pointer */ /* size Number of bytes requested */ /* alignment Required alignment of */ /* destination memory pointer */ /* suspend Suspension option if full */ /* */ /* OUTPUTS */ /* */ /* NU_SUCCESS If service is successful */ /* NU_NO_MEMORY Memory not available */ /* NU_TIMEOUT If timeout on service */ /* NU_POOL_DELETED If memory pool deleted */ /* during suspension */ /* */ /* HISTORY */ /* */ /* NAME DATE REMARKS */ /* */ /* T. Larsen 01-15-1999 Created initial revision */ /* R. Baum 06-06-2002 Fixed problem with DM_OVERHEAD */ /* allocation. Added Proview */ /* support. */ /* */ /*************************************************************************/ STATUS DMS_Allocate_Aligned_Memory(NU_MEMORY_POOL *pool_ptr, VOID **return_pointer, UNSIGNED size, UNSIGNED alignment, UNSIGNED suspend) { R1 DM_PCB *pool; /* Pool control block ptr */ R2 DM_SUSPEND *suspend_ptr; /* Pointer to suspend block */ DM_SUSPEND suspend_block; /* Allocate suspension block */ R4 DM_HEADER *memory_ptr; /* Pointer to memory */ R3 DM_HEADER *new_ptr; /* New split block pointer */ UNSIGNED free_size; /* Size of block found */ TC_TCB *task; /* Task pointer */ STATUS status; /* Completion status */ UNSIGNED address; /* Address of start of block */ UNSIGNED split_size; /* Bytes for front split */ UNSIGNED next_aligned; /* Next aligned block addr */ NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Move input pool pointer into internal pointer. */ pool = (DM_PCB *) pool_ptr; #ifdef NU_ENABLE_STACK_CHECK /* Call stack checking function to check for an overflow condition. */ TCT_Check_Stack(); #endif #ifdef NU_ENABLE_HISTORY /* Make an entry that corresponds to this function in the system history log. */ HIC_Make_History_Entry(NU_ALLOCATE_ALIGNED_ID, (UNSIGNED) pool, (UNSIGNED) return_pointer, (UNSIGNED) size); #endif /* Initialize the status as successful. */ status = NU_SUCCESS; /* Adjust the request to a size evenly divisible by the number of bytes in an UNSIGNED data element. Also, check to make sure it is of the minimum size. */ if (size < pool -> dm_min_allocation) /* Change size to the minimum allocation. */ size = pool -> dm_min_allocation; else /* Insure that size is a multiple of the UNSIGNED size. */ size = ((size + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED); /* Adjust the requested alignment to one evenly divisible by the number of bytes in an UNSIGNED data element. */ alignment = ((alignment + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED); /* Protect against simultaneous access to the memory pool. */ TCT_Protect(&(pool -> dm_protect)); /* Search the memory list for the first available block of memory that satisfies the request. Note that blocks are merged during the deallocation function. */ memory_ptr = pool -> dm_search_ptr; do { /* Determine if the block is free and if it can satisfy the request. */ if (memory_ptr -> dm_memory_free) /* Calculate the free block size. */ free_size = (((BYTE_PTR) (memory_ptr -> dm_next_memory)) - ((BYTE_PTR) memory_ptr)) - DM_OVERHEAD; else /* There are no free bytes available. */ free_size = 0; /* Free block may be large enough, now check alignment */ if (free_size >= size) { address = ((UNSIGNED)(memory_ptr)) + DM_OVERHEAD; /* Is this free block, minus the overhead, already aligned? */ if (address % alignment != 0) { /* Not aligned, can the free block be split in front? */ next_aligned = address + (alignment - 1); next_aligned /= alignment; next_aligned *= alignment; split_size = next_aligned - address; /* Is space from start of block to aligned location large enough to contain 2 DM_OVERHEAD plus pool -> dm_min_allocation? */ if (split_size < ((2 * DM_OVERHEAD) + pool -> dm_min_allocation)) { /* No, so try to make space for overhead and dm_min_allocation */ next_aligned = address + (2 * DM_OVERHEAD) + (pool -> dm_min_allocation) + (alignment - 1); next_aligned /= alignment; next_aligned *= alignment; split_size = next_aligned - address; } /* Adjust free_size for result of front split */ if (free_size > split_size) free_size -= split_size; else /* Can't adjust block beginning, so keep searching */ free_size = 0; } } /* Determine if the search should continue. */ if (free_size < size) /* Large enough block has not been found. Move the search pointer to the next block. */ memory_ptr = memory_ptr -> dm_next_memory; } while((free_size < size) && (memory_ptr != pool -> dm_search_ptr)); /* Determine if the memory is available. */ if (free_size >= size) { /* A block that satisfies the request has been found. */ /* Is a front split required? The front split will represent the chunk of memory that goes from the last pointer to the aligned address. */ if(address % alignment != 0) { /* Not aligned, front split the block, leaving an allocated block. */ new_ptr = (DM_HEADER*)(((UNSIGNED)(memory_ptr)) + split_size); /* Mark the new block as free. */ new_ptr -> dm_memory_free = NU_TRUE; /* Put the pool pointer into the new block. */ new_ptr -> dm_memory_pool = pool; /* Build the necessary pointers. */ new_ptr -> dm_previous_memory = memory_ptr; new_ptr -> dm_next_memory = memory_ptr -> dm_next_memory; (new_ptr -> dm_next_memory) -> dm_previous_memory = new_ptr; memory_ptr -> dm_next_memory = new_ptr; /* Decrement the available byte count by one DM_OVERHEAD. */ pool -> dm_available = pool -> dm_available - DM_OVERHEAD; /* Point to new aligned free block. */ memory_ptr = new_ptr; } /* Determine if the remaining block needs to be tail split. */ if (free_size >= (size + DM_OVERHEAD + pool -> dm_min_allocation)) { /* Yes, split the block. */ new_ptr = (DM_HEADER *) (((BYTE_PTR) memory_ptr) + size + DM_OVERHEAD); /* Mark the new block as free. */ new_ptr -> dm_memory_free = NU_TRUE; /* Put the pool pointer into the new block. */ new_ptr -> dm_memory_pool = pool; /* Build the necessary pointers. */ new_ptr -> dm_previous_memory = memory_ptr; new_ptr -> dm_next_memory = memory_ptr -> dm_next_memory; (new_ptr -> dm_next_memory) -> dm_previous_memory = new_ptr; memory_ptr -> dm_next_memory = new_ptr; /* Decrement the available byte count. */ pool -> dm_available = pool -> dm_available - size - DM_OVERHEAD; } else /* Decrement the entire free size from the available bytes count. */ pool -> dm_available = pool -> dm_available - free_size; /* Mark the allocated block as not available. */ memory_ptr -> dm_memory_free = NU_FALSE; /* Should the search pointer be moved? */ if (pool -> dm_search_ptr == memory_ptr) /* Move the search pointer to the next free memory slot. */ pool -> dm_search_ptr = memory_ptr -> dm_next_memory; /* Return a memory address to the caller. */ *return_pointer = (VOID *) (((BYTE_PTR) memory_ptr) + DM_OVERHEAD); #ifdef INCLUDE_PROVIEW _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_OK); #endif /*INCLUDE_PROVIEW*/ } else { /* Enough dynamic memory is not available. Determine if suspension is required. */ if (suspend) { /* Suspension is selected. */ /* Increment the number of tasks waiting. */ pool -> dm_tasks_waiting++; #ifdef INCLUDE_PROVIEW _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_WAIT); #endif /*INCLUDE_PROVIEW*/ /* Setup the suspend block and suspend the calling task. */ suspend_ptr = &suspend_block; suspend_ptr -> dm_memory_pool = pool; suspend_ptr -> dm_request_size = size; suspend_ptr -> dm_suspend_link.cs_next = NU_NULL; suspend_ptr -> dm_suspend_link.cs_previous = NU_NULL; task = (TC_TCB *) TCT_Current_Thread(); suspend_ptr -> dm_suspended_task = task; /* Determine if priority or FIFO suspension is associated with the memory pool. */ if (pool -> dm_fifo_suspend) { /* FIFO suspension is required. Link the suspend block into the list of suspended tasks on this memory pool. */ CSC_Place_On_List((CS_NODE **) &(pool -> dm_suspension_list), &(suspend_ptr -> dm_suspend_link)); } else { /* Get the priority of the current thread so the suspend block can be placed in the appropriate place. */ suspend_ptr -> dm_suspend_link.cs_priority = TCC_Task_Priority(task); CSC_Priority_Place_On_List((CS_NODE **) &(pool -> dm_suspension_list), &(suspend_ptr -> dm_suspend_link)); } /* Protect against system access. */ TCT_System_Protect(); /* Save the list protection in preparation for suspension. */ TCT_Set_Suspend_Protect(&(pool -> dm_protect)); /* Release protection of dynamic memory pool. */ TCT_Unprotect_Specific(&(pool -> dm_protect)); /* Finally, suspend the calling task. Note that the suspension call automatically clears the system protection. */ TCC_Suspend_Task((NU_TASK *) task, NU_MEMORY_SUSPEND, DMC_Cleanup, suspend_ptr, suspend); /* Pickup the return status. */ status = suspend_ptr -> dm_return_status; *return_pointer = suspend_ptr -> dm_return_pointer; } else { /* No suspension requested. Simply return an error status. */ status = NU_NO_MEMORY; *return_pointer = NU_NULL; #ifdef INCLUDE_PROVIEW _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_FAIL); #endif /*INCLUDE_PROVIEW*/ } } /* Release protection of the memory pool. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); /* Return the completion status. */ return(status); }