]> granicus.if.org Git - esp-idf/blob - components/bt/bluedroid/gki/gki_buffer.c
component/bt: Merge branch 'master' into feature/btdm_a2dp
[esp-idf] / components / bt / bluedroid / gki / gki_buffer.c
1 /******************************************************************************
2  *
3  *  Copyright (C) 1999-2012 Broadcom Corporation
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18
19 #include "bt_trace.h"
20 #include "allocator.h"
21 #include "gki_int.h"
22
23 /*******************************************************************************
24 **
25 ** Function         gki_init_free_queue
26 **
27 ** Description      Internal function called at startup to initialize a free
28 **                  queue. It is called once for each free queue.
29 **
30 ** Returns          void
31 **
32 *******************************************************************************/
33 static void gki_init_free_queue (UINT8 id, UINT16 size, UINT16 total, void *p_mem)
34 {
35     UINT16           i;
36     UINT16           act_size;
37     BUFFER_HDR_T    *hdr;
38     BUFFER_HDR_T    *hdr1 = NULL;
39     UINT32          *magic;
40     INT32            tempsize = size;
41     tGKI_COM_CB     *p_cb = &gki_cb.com;
42
43     /* Ensure an even number of longwords */
44     tempsize = (INT32)ALIGN_POOL(size);
45     act_size = (UINT16)(tempsize + BUFFER_PADDING_SIZE);
46
47     /* Remember pool start and end addresses */
48     if (p_mem) {
49         p_cb->pool_start[id] = (UINT8 *)p_mem;
50         p_cb->pool_end[id]   = (UINT8 *)p_mem + (act_size * total);
51     }
52
53     p_cb->pool_size[id]  = act_size;
54
55     p_cb->freeq[id].size      = (UINT16) tempsize;
56     p_cb->freeq[id].total     = total;
57     p_cb->freeq[id].cur_cnt   = 0;
58     p_cb->freeq[id].max_cnt   = 0;
59
60     /* Initialize  index table */
61     if (p_mem) {
62         hdr = (BUFFER_HDR_T *)p_mem;
63         p_cb->freeq[id]._p_first = hdr;
64         for (i = 0; i < total; i++) {
65             hdr->q_id    = id;
66             hdr->status  = BUF_STATUS_FREE;
67             magic        = (UINT32 *)((UINT8 *)hdr + BUFFER_HDR_SIZE + tempsize);
68             *magic       = MAGIC_NO;
69             hdr1         = hdr;
70             hdr          = (BUFFER_HDR_T *)((UINT8 *)hdr + act_size);
71             hdr1->p_next = hdr;
72         }
73         hdr1->p_next = NULL;
74         p_cb->freeq[id]._p_last = hdr1;
75     }
76 }
77
78 void gki_buffer_cleanup(void)
79 {
80     UINT8   i;
81     tGKI_COM_CB *p_cb = &gki_cb.com;
82
83     for (i = 0; i < GKI_NUM_FIXED_BUF_POOLS; i++) {
84         if ( 0 < p_cb->freeq[i].max_cnt ) {
85             osi_free(p_cb->pool_start[i]);
86
87             p_cb->freeq[i].cur_cnt   = 0;
88             p_cb->freeq[i].max_cnt   = 0;
89             p_cb->freeq[i]._p_first   = NULL;
90             p_cb->freeq[i]._p_last    = NULL;
91
92             p_cb->pool_start[i] = NULL;
93             p_cb->pool_end[i]   = NULL;
94             p_cb->pool_size[i]  = 0;
95         }
96     }
97 }
98
99 /*******************************************************************************
100 **
101 ** Function         gki_buffer_init
102 **
103 ** Description      Called once internally by GKI at startup to initialize all
104 **                  buffers and free buffer pools.
105 **
106 ** Returns          void
107 **
108 *******************************************************************************/
109 void gki_buffer_init(void)
110 {
111     static const struct {
112         uint16_t size;
113         uint16_t count;
114     } buffer_info[GKI_NUM_FIXED_BUF_POOLS] = {
115         { GKI_BUF0_SIZE, GKI_BUF0_MAX },
116         { GKI_BUF1_SIZE, GKI_BUF1_MAX },
117         { GKI_BUF2_SIZE, GKI_BUF2_MAX },
118         { GKI_BUF3_SIZE, GKI_BUF3_MAX },
119         { GKI_BUF4_SIZE, GKI_BUF4_MAX },
120         { GKI_BUF5_SIZE, GKI_BUF5_MAX },
121         { GKI_BUF6_SIZE, GKI_BUF6_MAX },
122         { GKI_BUF7_SIZE, GKI_BUF7_MAX },
123         { GKI_BUF8_SIZE, GKI_BUF8_MAX },
124         { GKI_BUF9_SIZE, GKI_BUF9_MAX },
125     };
126
127     tGKI_COM_CB *p_cb = &gki_cb.com;
128
129     for (int i = 0; i < GKI_NUM_TOTAL_BUF_POOLS; i++) {
130         p_cb->pool_start[i] = NULL;
131         p_cb->pool_end[i]   = NULL;
132         p_cb->pool_size[i]  = 0;
133
134         p_cb->freeq[i]._p_first = 0;
135         p_cb->freeq[i]._p_last  = 0;
136         p_cb->freeq[i].size    = 0;
137         p_cb->freeq[i].total   = 0;
138         p_cb->freeq[i].cur_cnt = 0;
139         p_cb->freeq[i].max_cnt = 0;
140     }
141
142     /* Use default from target.h */
143     p_cb->pool_access_mask = GKI_DEF_BUFPOOL_PERM_MASK;
144
145     for (int i = 0; i < GKI_NUM_FIXED_BUF_POOLS; ++i) {
146         gki_init_free_queue(i, buffer_info[i].size, buffer_info[i].count, NULL);
147     }
148 }
149
150 /*******************************************************************************
151 **
152 ** Function         GKI_init_q
153 **
154 ** Description      Called by an application to initialize a buffer queue.
155 **
156 ** Returns          void
157 **
158 *******************************************************************************/
159 void GKI_init_q (BUFFER_Q *p_q)
160 {
161     p_q->_p_first = p_q->_p_last = NULL;
162     p_q->_count = 0;
163 }
164
165 /*******************************************************************************
166 **
167 ** Function         GKI_getbuf_func
168 **
169 ** Description      Called by an application to get a free buffer which
170 **                  is of size greater or equal to the requested size.
171 **
172 **                  Note: This routine only takes buffers from public pools.
173 **                        It will not use any buffers from pools
174 **                        marked GKI_RESTRICTED_POOL.
175 **
176 ** Parameters       size - (input) number of bytes needed.
177 **
178 ** Returns          A pointer to the buffer, or NULL if none available
179 **
180 *******************************************************************************/
181 void *GKI_getbuf_func(UINT16 size)
182 {
183     BUFFER_HDR_T *header = osi_malloc(size + BUFFER_HDR_SIZE);
184     assert(header != NULL);
185     if (header != NULL) {
186         header->status  = BUF_STATUS_UNLINKED;
187         header->p_next  = NULL;
188         header->Type    = 0;
189         header->size = size;
190
191         return header + 1;
192     } else {
193         return NULL;
194     }
195 }
196
197 /*******************************************************************************
198 **
199 ** Function         GKI_getpoolbuf_func
200 **
201 ** Description      Called by an application to get a free buffer from
202 **                  a specific buffer pool.
203 **
204 **                  Note: If there are no more buffers available from the pool,
205 **                        the public buffers are searched for an available buffer.
206 **
207 ** Parameters       pool_id - (input) pool ID to get a buffer out of.
208 **
209 ** Returns          A pointer to the buffer, or NULL if none available
210 **
211 *******************************************************************************/
212 void *GKI_getpoolbuf_func(UINT8 pool_id)
213 {
214     return GKI_getbuf_func(gki_cb.com.pool_size[pool_id]);
215 }
216
217 /*******************************************************************************
218 **
219 ** Function         GKI_freebuf
220 **
221 ** Description      Called by an application to return a buffer to the free pool.
222 **
223 ** Parameters       p_buf - (input) address of the beginning of a buffer.
224 **
225 ** Returns          void
226 **
227 *******************************************************************************/
228 void GKI_freebuf (void *p_buf)
229 {
230     osi_free((BUFFER_HDR_T *)p_buf - 1);
231 }
232
233 /*******************************************************************************
234 **
235 ** Function         GKI_get_buf_size
236 **
237 ** Description      Called by an application to get the size of a buffer.
238 **
239 ** Parameters       p_buf - (input) address of the beginning of a buffer.
240 **
241 ** Returns          the size of the buffer
242 **
243 *******************************************************************************/
244 UINT16 GKI_get_buf_size (void *p_buf)
245 {
246     BUFFER_HDR_T *header = (BUFFER_HDR_T *)p_buf - 1;
247     return header->size;
248 }
249
250 /*******************************************************************************
251 **
252 ** Function         GKI_enqueue
253 **
254 ** Description      Enqueue a buffer at the tail of the queue
255 **
256 ** Parameters:      p_q  -  (input) pointer to a queue.
257 **                  p_buf - (input) address of the buffer to enqueue
258 **
259 ** Returns          void
260 **
261 *******************************************************************************/
262 void GKI_enqueue (BUFFER_Q *p_q, void *p_buf)
263 {
264     BUFFER_HDR_T *p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
265     assert(p_hdr->status == BUF_STATUS_UNLINKED);
266
267     GKI_disable();
268
269     /* Since the queue is exposed (C vs C++), keep the pointers in exposed format */
270     if (p_q->_p_last) {
271         BUFFER_HDR_T *_p_last_hdr = (BUFFER_HDR_T *)((UINT8 *)p_q->_p_last - BUFFER_HDR_SIZE);
272         _p_last_hdr->p_next = p_hdr;
273     } else {
274         p_q->_p_first = p_buf;
275     }
276
277     p_q->_p_last = p_buf;
278     p_q->_count++;
279
280     p_hdr->p_next = NULL;
281     p_hdr->status = BUF_STATUS_QUEUED;
282
283     GKI_enable();
284 }
285
286 /*******************************************************************************
287 **
288 ** Function         GKI_dequeue
289 **
290 ** Description      Dequeues a buffer from the head of a queue
291 **
292 ** Parameters:      p_q  - (input) pointer to a queue.
293 **
294 ** Returns          NULL if queue is empty, else buffer
295 **
296 *******************************************************************************/
297 void *GKI_dequeue (BUFFER_Q *p_q)
298 {
299     BUFFER_HDR_T    *p_hdr;
300
301     GKI_disable();
302
303     if (!p_q || !p_q->_count) {
304         GKI_enable();
305         return (NULL);
306     }
307
308     p_hdr = (BUFFER_HDR_T *)((UINT8 *)p_q->_p_first - BUFFER_HDR_SIZE);
309
310     /* Keep buffers such that GKI header is invisible
311     */
312     if (p_hdr->p_next) {
313         p_q->_p_first = ((UINT8 *)p_hdr->p_next + BUFFER_HDR_SIZE);
314     } else {
315         p_q->_p_first = NULL;
316         p_q->_p_last  = NULL;
317     }
318
319     p_q->_count--;
320
321     p_hdr->p_next = NULL;
322     p_hdr->status = BUF_STATUS_UNLINKED;
323
324     GKI_enable();
325
326     return ((UINT8 *)p_hdr + BUFFER_HDR_SIZE);
327 }
328
329 /*******************************************************************************
330 **
331 ** Function         GKI_remove_from_queue
332 **
333 ** Description      Dequeue a buffer from the middle of the queue
334 **
335 ** Parameters:      p_q  - (input) pointer to a queue.
336 **                  p_buf - (input) address of the buffer to enqueue
337 **
338 ** Returns          NULL if queue is empty, else buffer
339 **
340 *******************************************************************************/
341 void *GKI_remove_from_queue (BUFFER_Q *p_q, void *p_buf)
342 {
343     BUFFER_HDR_T    *p_prev;
344     BUFFER_HDR_T    *p_buf_hdr;
345
346     GKI_disable();
347
348     if (p_buf == p_q->_p_first) {
349         GKI_enable();
350         return (GKI_dequeue (p_q));
351     }
352
353     p_buf_hdr = (BUFFER_HDR_T *)((UINT8 *)p_buf - BUFFER_HDR_SIZE);
354     p_prev    = (BUFFER_HDR_T *)((UINT8 *)p_q->_p_first - BUFFER_HDR_SIZE);
355
356     for ( ; p_prev; p_prev = p_prev->p_next) {
357         /* If the previous points to this one, move the pointers around */
358         if (p_prev->p_next == p_buf_hdr) {
359             p_prev->p_next = p_buf_hdr->p_next;
360
361             /* If we are removing the last guy in the queue, update _p_last */
362             if (p_buf == p_q->_p_last) {
363                 p_q->_p_last = p_prev + 1;
364             }
365
366             /* One less in the queue */
367             p_q->_count--;
368
369             /* The buffer is now unlinked */
370             p_buf_hdr->p_next = NULL;
371             p_buf_hdr->status = BUF_STATUS_UNLINKED;
372
373             GKI_enable();
374             return (p_buf);
375         }
376     }
377
378     GKI_enable();
379     return (NULL);
380 }
381
382 /*******************************************************************************
383 **
384 ** Function         GKI_getfirst
385 **
386 ** Description      Return a pointer to the first buffer in a queue
387 **
388 ** Parameters:      p_q  - (input) pointer to a queue.
389 **
390 ** Returns          NULL if queue is empty, else buffer address
391 **
392 *******************************************************************************/
393 void *GKI_getfirst (BUFFER_Q *p_q)
394 {
395     return (p_q->_p_first);
396 }
397
398 /*******************************************************************************
399 **
400 ** Function         GKI_getlast
401 **
402 ** Description      Return a pointer to the last buffer in a queue
403 **
404 ** Parameters:      p_q  - (input) pointer to a queue.
405 **
406 ** Returns          NULL if queue is empty, else buffer address
407 **
408 *******************************************************************************/
409 void *GKI_getlast (BUFFER_Q *p_q)
410 {
411     return (p_q->_p_last);
412 }
413
414 /*******************************************************************************
415 **
416 ** Function         GKI_getnext
417 **
418 ** Description      Return a pointer to the next buffer in a queue
419 **
420 ** Parameters:      p_buf  - (input) pointer to the buffer to find the next one from.
421 **
422 ** Returns          NULL if no more buffers in the queue, else next buffer address
423 **
424 *******************************************************************************/
425 void *GKI_getnext (void *p_buf)
426 {
427     BUFFER_HDR_T    *p_hdr;
428
429     p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
430
431     if (p_hdr->p_next) {
432         return ((UINT8 *)p_hdr->p_next + BUFFER_HDR_SIZE);
433     } else {
434         return (NULL);
435     }
436 }
437
438 /*******************************************************************************
439 **
440 ** Function         GKI_queue_is_empty
441 **
442 ** Description      Check the status of a queue.
443 **
444 ** Parameters:      p_q  - (input) pointer to a queue.
445 **
446 ** Returns          TRUE if queue is empty, else FALSE
447 **
448 *******************************************************************************/
449 BOOLEAN GKI_queue_is_empty(BUFFER_Q *p_q)
450 {
451     return ((BOOLEAN) (p_q->_count == 0));
452 }
453
454 UINT16 GKI_queue_length(BUFFER_Q *p_q)
455 {
456     return p_q->_count;
457 }
458
459 /*******************************************************************************
460 **
461 ** Function         GKI_poolcount
462 **
463 ** Description      Called by an application to get the total number of buffers
464 **                  in the specified buffer pool.
465 **
466 ** Parameters       pool_id - (input) pool ID to get the free count of.
467 **
468 ** Returns          the total number of buffers in the pool
469 **
470 *******************************************************************************/
471 UINT16 GKI_poolcount (UINT8 pool_id)
472 {
473     if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) {
474         return (0);
475     }
476
477     return (gki_cb.com.freeq[pool_id].total);
478 }
479
480 /*******************************************************************************
481 **
482 ** Function         GKI_poolfreecount
483 **
484 ** Description      Called by an application to get the number of free buffers
485 **                  in the specified buffer pool.
486 **
487 ** Parameters       pool_id - (input) pool ID to get the free count of.
488 **
489 ** Returns          the number of free buffers in the pool
490 **
491 *******************************************************************************/
492 UINT16 GKI_poolfreecount (UINT8 pool_id)
493 {
494     FREE_QUEUE_T  *Q;
495
496     if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) {
497         return (0);
498     }
499
500     Q  = &gki_cb.com.freeq[pool_id];
501
502     return ((UINT16)(Q->total - Q->cur_cnt));
503 }
504
505 /*******************************************************************************
506 **
507 ** Function         GKI_get_pool_bufsize
508 **
509 ** Description      Called by an application to get the size of buffers in a pool
510 **
511 ** Parameters       Pool ID.
512 **
513 ** Returns          the size of buffers in the pool
514 **
515 *******************************************************************************/
516 UINT16 GKI_get_pool_bufsize (UINT8 pool_id)
517 {
518     if (pool_id < GKI_NUM_TOTAL_BUF_POOLS) {
519         return (gki_cb.com.freeq[pool_id].size);
520     }
521
522     return (0);
523 }
524
525 /*******************************************************************************
526 **
527 ** Function         GKI_poolutilization
528 **
529 ** Description      Called by an application to get the buffer utilization
530 **                  in the specified buffer pool.
531 **
532 ** Parameters       pool_id - (input) pool ID to get the free count of.
533 **
534 ** Returns          % of buffers used from 0 to 100
535 **
536 *******************************************************************************/
537 UINT16 GKI_poolutilization (UINT8 pool_id)
538 {
539     FREE_QUEUE_T  *Q;
540
541     if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) {
542         return (100);
543     }
544
545     Q  = &gki_cb.com.freeq[pool_id];
546
547     if (Q->total == 0) {
548         return (100);
549     }
550
551     return ((Q->cur_cnt * 100) / Q->total);
552 }