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