1. fix the exception of deinit/disable 2. debug mem leak of deinit, fix some memleak, but still something wrong. 3. debug men leak of disable. 4. add bluedroid memory debug
547 lines
16 KiB
C
547 lines
16 KiB
C
/******************************************************************************
|
|
*
|
|
* Copyright (C) 1999-2012 Broadcom Corporation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include "bt_trace.h"
|
|
#include "allocator.h"
|
|
#include "gki_int.h"
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function gki_init_free_queue
|
|
**
|
|
** Description Internal function called at startup to initialize a free
|
|
** queue. It is called once for each free queue.
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
static void gki_init_free_queue (UINT8 id, UINT16 size, UINT16 total, void *p_mem)
|
|
{
|
|
UINT16 i;
|
|
UINT16 act_size;
|
|
BUFFER_HDR_T *hdr;
|
|
BUFFER_HDR_T *hdr1 = NULL;
|
|
UINT32 *magic;
|
|
INT32 tempsize = size;
|
|
tGKI_COM_CB *p_cb = &gki_cb.com;
|
|
|
|
/* Ensure an even number of longwords */
|
|
tempsize = (INT32)ALIGN_POOL(size);
|
|
act_size = (UINT16)(tempsize + BUFFER_PADDING_SIZE);
|
|
|
|
/* Remember pool start and end addresses */
|
|
if (p_mem) {
|
|
p_cb->pool_start[id] = (UINT8 *)p_mem;
|
|
p_cb->pool_end[id] = (UINT8 *)p_mem + (act_size * total);
|
|
}
|
|
|
|
p_cb->pool_size[id] = act_size;
|
|
|
|
p_cb->freeq[id].size = (UINT16) tempsize;
|
|
p_cb->freeq[id].total = total;
|
|
p_cb->freeq[id].cur_cnt = 0;
|
|
p_cb->freeq[id].max_cnt = 0;
|
|
|
|
/* Initialize index table */
|
|
if (p_mem) {
|
|
hdr = (BUFFER_HDR_T *)p_mem;
|
|
p_cb->freeq[id]._p_first = hdr;
|
|
for (i = 0; i < total; i++) {
|
|
hdr->q_id = id;
|
|
hdr->status = BUF_STATUS_FREE;
|
|
magic = (UINT32 *)((UINT8 *)hdr + BUFFER_HDR_SIZE + tempsize);
|
|
*magic = MAGIC_NO;
|
|
hdr1 = hdr;
|
|
hdr = (BUFFER_HDR_T *)((UINT8 *)hdr + act_size);
|
|
hdr1->p_next = hdr;
|
|
}
|
|
hdr1->p_next = NULL;
|
|
p_cb->freeq[id]._p_last = hdr1;
|
|
}
|
|
}
|
|
|
|
void gki_buffer_cleanup(void)
|
|
{
|
|
UINT8 i;
|
|
tGKI_COM_CB *p_cb = &gki_cb.com;
|
|
|
|
for (i = 0; i < GKI_NUM_FIXED_BUF_POOLS; i++) {
|
|
if ( 0 < p_cb->freeq[i].max_cnt ) {
|
|
osi_free(p_cb->pool_start[i]);
|
|
|
|
p_cb->freeq[i].cur_cnt = 0;
|
|
p_cb->freeq[i].max_cnt = 0;
|
|
p_cb->freeq[i]._p_first = NULL;
|
|
p_cb->freeq[i]._p_last = NULL;
|
|
|
|
p_cb->pool_start[i] = NULL;
|
|
p_cb->pool_end[i] = NULL;
|
|
p_cb->pool_size[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function gki_buffer_init
|
|
**
|
|
** Description Called once internally by GKI at startup to initialize all
|
|
** buffers and free buffer pools.
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void gki_buffer_init(void)
|
|
{
|
|
static const struct {
|
|
uint16_t size;
|
|
uint16_t count;
|
|
} buffer_info[GKI_NUM_FIXED_BUF_POOLS] = {
|
|
{ GKI_BUF0_SIZE, GKI_BUF0_MAX },
|
|
{ GKI_BUF1_SIZE, GKI_BUF1_MAX },
|
|
{ GKI_BUF2_SIZE, GKI_BUF2_MAX },
|
|
{ GKI_BUF3_SIZE, GKI_BUF3_MAX },
|
|
{ GKI_BUF4_SIZE, GKI_BUF4_MAX },
|
|
{ GKI_BUF5_SIZE, GKI_BUF5_MAX },
|
|
{ GKI_BUF6_SIZE, GKI_BUF6_MAX },
|
|
{ GKI_BUF7_SIZE, GKI_BUF7_MAX },
|
|
{ GKI_BUF8_SIZE, GKI_BUF8_MAX },
|
|
{ GKI_BUF9_SIZE, GKI_BUF9_MAX },
|
|
};
|
|
|
|
tGKI_COM_CB *p_cb = &gki_cb.com;
|
|
|
|
for (int i = 0; i < GKI_NUM_TOTAL_BUF_POOLS; i++) {
|
|
p_cb->pool_start[i] = NULL;
|
|
p_cb->pool_end[i] = NULL;
|
|
p_cb->pool_size[i] = 0;
|
|
|
|
p_cb->freeq[i]._p_first = 0;
|
|
p_cb->freeq[i]._p_last = 0;
|
|
p_cb->freeq[i].size = 0;
|
|
p_cb->freeq[i].total = 0;
|
|
p_cb->freeq[i].cur_cnt = 0;
|
|
p_cb->freeq[i].max_cnt = 0;
|
|
}
|
|
|
|
/* Use default from target.h */
|
|
p_cb->pool_access_mask = GKI_DEF_BUFPOOL_PERM_MASK;
|
|
|
|
for (int i = 0; i < GKI_NUM_FIXED_BUF_POOLS; ++i) {
|
|
gki_init_free_queue(i, buffer_info[i].size, buffer_info[i].count, NULL);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_init_q
|
|
**
|
|
** Description Called by an application to initialize a buffer queue.
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void GKI_init_q (BUFFER_Q *p_q)
|
|
{
|
|
p_q->_p_first = p_q->_p_last = NULL;
|
|
p_q->_count = 0;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_getbuf_func
|
|
**
|
|
** Description Called by an application to get a free buffer which
|
|
** is of size greater or equal to the requested size.
|
|
**
|
|
** Note: This routine only takes buffers from public pools.
|
|
** It will not use any buffers from pools
|
|
** marked GKI_RESTRICTED_POOL.
|
|
**
|
|
** Parameters size - (input) number of bytes needed.
|
|
**
|
|
** Returns A pointer to the buffer, or NULL if none available
|
|
**
|
|
*******************************************************************************/
|
|
void *GKI_getbuf_func(UINT16 size)
|
|
{
|
|
BUFFER_HDR_T *header = osi_malloc(size + BUFFER_HDR_SIZE);
|
|
header->status = BUF_STATUS_UNLINKED;
|
|
header->p_next = NULL;
|
|
header->Type = 0;
|
|
header->size = size;
|
|
|
|
return header + 1;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_getpoolbuf_func
|
|
**
|
|
** Description Called by an application to get a free buffer from
|
|
** a specific buffer pool.
|
|
**
|
|
** Note: If there are no more buffers available from the pool,
|
|
** the public buffers are searched for an available buffer.
|
|
**
|
|
** Parameters pool_id - (input) pool ID to get a buffer out of.
|
|
**
|
|
** Returns A pointer to the buffer, or NULL if none available
|
|
**
|
|
*******************************************************************************/
|
|
void *GKI_getpoolbuf_func(UINT8 pool_id)
|
|
{
|
|
return GKI_getbuf_func(gki_cb.com.pool_size[pool_id]);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_freebuf
|
|
**
|
|
** Description Called by an application to return a buffer to the free pool.
|
|
**
|
|
** Parameters p_buf - (input) address of the beginning of a buffer.
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void GKI_freebuf (void *p_buf)
|
|
{
|
|
osi_free((BUFFER_HDR_T *)p_buf - 1);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_get_buf_size
|
|
**
|
|
** Description Called by an application to get the size of a buffer.
|
|
**
|
|
** Parameters p_buf - (input) address of the beginning of a buffer.
|
|
**
|
|
** Returns the size of the buffer
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 GKI_get_buf_size (void *p_buf)
|
|
{
|
|
BUFFER_HDR_T *header = (BUFFER_HDR_T *)p_buf - 1;
|
|
return header->size;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_enqueue
|
|
**
|
|
** Description Enqueue a buffer at the tail of the queue
|
|
**
|
|
** Parameters: p_q - (input) pointer to a queue.
|
|
** p_buf - (input) address of the buffer to enqueue
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void GKI_enqueue (BUFFER_Q *p_q, void *p_buf)
|
|
{
|
|
BUFFER_HDR_T *p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
|
|
assert(p_hdr->status == BUF_STATUS_UNLINKED);
|
|
|
|
GKI_disable();
|
|
|
|
/* Since the queue is exposed (C vs C++), keep the pointers in exposed format */
|
|
if (p_q->_p_last) {
|
|
BUFFER_HDR_T *_p_last_hdr = (BUFFER_HDR_T *)((UINT8 *)p_q->_p_last - BUFFER_HDR_SIZE);
|
|
_p_last_hdr->p_next = p_hdr;
|
|
} else {
|
|
p_q->_p_first = p_buf;
|
|
}
|
|
|
|
p_q->_p_last = p_buf;
|
|
p_q->_count++;
|
|
|
|
p_hdr->p_next = NULL;
|
|
p_hdr->status = BUF_STATUS_QUEUED;
|
|
|
|
GKI_enable();
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_dequeue
|
|
**
|
|
** Description Dequeues a buffer from the head of a queue
|
|
**
|
|
** Parameters: p_q - (input) pointer to a queue.
|
|
**
|
|
** Returns NULL if queue is empty, else buffer
|
|
**
|
|
*******************************************************************************/
|
|
void *GKI_dequeue (BUFFER_Q *p_q)
|
|
{
|
|
BUFFER_HDR_T *p_hdr;
|
|
|
|
GKI_disable();
|
|
|
|
if (!p_q || !p_q->_count) {
|
|
GKI_enable();
|
|
return (NULL);
|
|
}
|
|
|
|
p_hdr = (BUFFER_HDR_T *)((UINT8 *)p_q->_p_first - BUFFER_HDR_SIZE);
|
|
|
|
/* Keep buffers such that GKI header is invisible
|
|
*/
|
|
if (p_hdr->p_next) {
|
|
p_q->_p_first = ((UINT8 *)p_hdr->p_next + BUFFER_HDR_SIZE);
|
|
} else {
|
|
p_q->_p_first = NULL;
|
|
p_q->_p_last = NULL;
|
|
}
|
|
|
|
p_q->_count--;
|
|
|
|
p_hdr->p_next = NULL;
|
|
p_hdr->status = BUF_STATUS_UNLINKED;
|
|
|
|
GKI_enable();
|
|
|
|
return ((UINT8 *)p_hdr + BUFFER_HDR_SIZE);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_remove_from_queue
|
|
**
|
|
** Description Dequeue a buffer from the middle of the queue
|
|
**
|
|
** Parameters: p_q - (input) pointer to a queue.
|
|
** p_buf - (input) address of the buffer to enqueue
|
|
**
|
|
** Returns NULL if queue is empty, else buffer
|
|
**
|
|
*******************************************************************************/
|
|
void *GKI_remove_from_queue (BUFFER_Q *p_q, void *p_buf)
|
|
{
|
|
BUFFER_HDR_T *p_prev;
|
|
BUFFER_HDR_T *p_buf_hdr;
|
|
|
|
GKI_disable();
|
|
|
|
if (p_buf == p_q->_p_first) {
|
|
GKI_enable();
|
|
return (GKI_dequeue (p_q));
|
|
}
|
|
|
|
p_buf_hdr = (BUFFER_HDR_T *)((UINT8 *)p_buf - BUFFER_HDR_SIZE);
|
|
p_prev = (BUFFER_HDR_T *)((UINT8 *)p_q->_p_first - BUFFER_HDR_SIZE);
|
|
|
|
for ( ; p_prev; p_prev = p_prev->p_next) {
|
|
/* If the previous points to this one, move the pointers around */
|
|
if (p_prev->p_next == p_buf_hdr) {
|
|
p_prev->p_next = p_buf_hdr->p_next;
|
|
|
|
/* If we are removing the last guy in the queue, update _p_last */
|
|
if (p_buf == p_q->_p_last) {
|
|
p_q->_p_last = p_prev + 1;
|
|
}
|
|
|
|
/* One less in the queue */
|
|
p_q->_count--;
|
|
|
|
/* The buffer is now unlinked */
|
|
p_buf_hdr->p_next = NULL;
|
|
p_buf_hdr->status = BUF_STATUS_UNLINKED;
|
|
|
|
GKI_enable();
|
|
return (p_buf);
|
|
}
|
|
}
|
|
|
|
GKI_enable();
|
|
return (NULL);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_getfirst
|
|
**
|
|
** Description Return a pointer to the first buffer in a queue
|
|
**
|
|
** Parameters: p_q - (input) pointer to a queue.
|
|
**
|
|
** Returns NULL if queue is empty, else buffer address
|
|
**
|
|
*******************************************************************************/
|
|
void *GKI_getfirst (BUFFER_Q *p_q)
|
|
{
|
|
return (p_q->_p_first);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_getlast
|
|
**
|
|
** Description Return a pointer to the last buffer in a queue
|
|
**
|
|
** Parameters: p_q - (input) pointer to a queue.
|
|
**
|
|
** Returns NULL if queue is empty, else buffer address
|
|
**
|
|
*******************************************************************************/
|
|
void *GKI_getlast (BUFFER_Q *p_q)
|
|
{
|
|
return (p_q->_p_last);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_getnext
|
|
**
|
|
** Description Return a pointer to the next buffer in a queue
|
|
**
|
|
** Parameters: p_buf - (input) pointer to the buffer to find the next one from.
|
|
**
|
|
** Returns NULL if no more buffers in the queue, else next buffer address
|
|
**
|
|
*******************************************************************************/
|
|
void *GKI_getnext (void *p_buf)
|
|
{
|
|
BUFFER_HDR_T *p_hdr;
|
|
|
|
p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
|
|
|
|
if (p_hdr->p_next) {
|
|
return ((UINT8 *)p_hdr->p_next + BUFFER_HDR_SIZE);
|
|
} else {
|
|
return (NULL);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_queue_is_empty
|
|
**
|
|
** Description Check the status of a queue.
|
|
**
|
|
** Parameters: p_q - (input) pointer to a queue.
|
|
**
|
|
** Returns TRUE if queue is empty, else FALSE
|
|
**
|
|
*******************************************************************************/
|
|
BOOLEAN GKI_queue_is_empty(BUFFER_Q *p_q)
|
|
{
|
|
return ((BOOLEAN) (p_q->_count == 0));
|
|
}
|
|
|
|
UINT16 GKI_queue_length(BUFFER_Q *p_q)
|
|
{
|
|
return p_q->_count;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_poolcount
|
|
**
|
|
** Description Called by an application to get the total number of buffers
|
|
** in the specified buffer pool.
|
|
**
|
|
** Parameters pool_id - (input) pool ID to get the free count of.
|
|
**
|
|
** Returns the total number of buffers in the pool
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 GKI_poolcount (UINT8 pool_id)
|
|
{
|
|
if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) {
|
|
return (0);
|
|
}
|
|
|
|
return (gki_cb.com.freeq[pool_id].total);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_poolfreecount
|
|
**
|
|
** Description Called by an application to get the number of free buffers
|
|
** in the specified buffer pool.
|
|
**
|
|
** Parameters pool_id - (input) pool ID to get the free count of.
|
|
**
|
|
** Returns the number of free buffers in the pool
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 GKI_poolfreecount (UINT8 pool_id)
|
|
{
|
|
FREE_QUEUE_T *Q;
|
|
|
|
if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) {
|
|
return (0);
|
|
}
|
|
|
|
Q = &gki_cb.com.freeq[pool_id];
|
|
|
|
return ((UINT16)(Q->total - Q->cur_cnt));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_get_pool_bufsize
|
|
**
|
|
** Description Called by an application to get the size of buffers in a pool
|
|
**
|
|
** Parameters Pool ID.
|
|
**
|
|
** Returns the size of buffers in the pool
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 GKI_get_pool_bufsize (UINT8 pool_id)
|
|
{
|
|
if (pool_id < GKI_NUM_TOTAL_BUF_POOLS) {
|
|
return (gki_cb.com.freeq[pool_id].size);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function GKI_poolutilization
|
|
**
|
|
** Description Called by an application to get the buffer utilization
|
|
** in the specified buffer pool.
|
|
**
|
|
** Parameters pool_id - (input) pool ID to get the free count of.
|
|
**
|
|
** Returns % of buffers used from 0 to 100
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 GKI_poolutilization (UINT8 pool_id)
|
|
{
|
|
FREE_QUEUE_T *Q;
|
|
|
|
if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) {
|
|
return (100);
|
|
}
|
|
|
|
Q = &gki_cb.com.freeq[pool_id];
|
|
|
|
if (Q->total == 0) {
|
|
return (100);
|
|
}
|
|
|
|
return ((Q->cur_cnt * 100) / Q->total);
|
|
}
|