69b00c47ee6097df230825da1ffe0636a58dffab
[open-ath9k-htc-firmware.git] / target_firmware / magpie_fw_dev / target / adf / adf_nbuf.c
1 /**
2  * (c) Copyright Atheros Communications Inc.,2002-2008
3  * All rights reserved
4  * 
5  * This file contains buffer Abstraction routines for FreeBSD
6  * the abstracted buffer called adf_nbuf is opaque to the
7  * user,hence these routines should be called to manipulate
8  * anything inside it.
9  * 
10  */
11 #include <adf_net.h>
12 #include <osapi.h>
13 #include "cmnos_api.h"
14 #include <Magpie_api.h>
15 #include <vbuf_api.h>
16
17 // #############################################################################
18 VDESC * __adf_nbuf_last(VBUF *buf);
19
20
21 // #############################################################################
22
23 /**
24  *  
25  * @brief allocate a new nbuf,
26  * 
27  * @param hdl (adf_net handle)
28  * @param size (size of the new buf)
29  * @param reserve (amount of space to reserve in the head)
30  * 
31  * @return newly allocated nbuf
32  */
33 __adf_nbuf_t 
34 __adf_nbuf_alloc(adf_os_size_t size, a_uint32_t reserve, 
35                  a_uint32_t align)
36 {
37     VBUF *buf = NULL;
38     VDESC *desc;
39     
40     buf = VBUF_alloc_vbuf();
41     if ( buf != NULL ) {
42         desc = VDESC_alloc_vdesc();
43         desc->buf_addr = (A_UINT8 *)A_ALLOCRAM(size);
44         desc->buf_size = size;
45         desc->next_desc = NULL;
46         desc->data_offset = reserve;
47         desc->data_size = 0;
48         desc->control = 0;    
49         
50         buf->desc_list = desc;
51         buf->buf_length = 0;    
52     }
53     
54     return buf;
55 }   
56   
57 /**
58  * @brief Free the nbuf
59  * function to be called in
60  * @param hdl
61  * @param adf_nbuf
62  * 
63  */
64 void __adf_nbuf_free(__adf_nbuf_t  buf)
65 {
66     adf_os_assert(0);
67 }
68
69 /**
70  * @brief reallocate the head space, call it only after the you
71  *        have called headroom
72  * 
73  * @param adf_nbuf
74  * @param headroom   
75  * 
76  * @return new nbuf
77  */
78 __adf_nbuf_t 
79 __adf_nbuf_realloc_headroom(__adf_nbuf_t buf, a_uint32_t headroom)
80 {
81     adf_os_assert(0);
82     return NULL;
83 }
84
85 /**
86  * @brief expand the tailroom, mostly by adding the new tail
87  *        buffer, also take care of the priv
88  * 
89  * @param buf
90  * @param tailroom
91  * 
92  * @return struct mbuf * (buffer with the new tailroom)
93  */
94 __adf_nbuf_t 
95 __adf_nbuf_realloc_tailroom(__adf_nbuf_t  buf, a_uint32_t tailroom)
96 {
97     adf_os_assert(0);
98     return NULL;
99 }
100
101 /**
102  * @brief expand the headroom or tailroom or both
103  * 
104  * @param buf
105  * @param headroom ( 0 if no headroom expansion req)
106  * @param tailroom ( 0 if no tailroom expansion req)
107  * 
108  * @return struct mbuf* (NULL if something goofed up)
109  */
110 __adf_nbuf_t 
111 __adf_nbuf_expand(__adf_nbuf_t buf, a_uint32_t headroom, a_uint32_t tailroom)
112 {
113     adf_os_assert(0);
114     return NULL;
115 }
116
117 /**
118  * @brief put data in the head
119  * 
120  * @param buf
121  * @param len (how much data to put)
122  * 
123  * @return new data pointer ,NULL if the len is more than the
124  *         space available in the head frag.
125  */
126 a_uint8_t *       
127 __adf_nbuf_push_head(__adf_nbuf_t buf, adf_os_size_t len)
128 {
129     a_uint8_t *ptr = NULL; 
130     VDESC *desc = buf->desc_list;
131     
132     desc->data_offset -= len;
133     desc->data_size += len;
134     buf->buf_length += len;
135     ptr = desc->buf_addr + desc->data_offset;
136     return(ptr);
137 }
138
139 /**
140  * 
141  * @brief add data in the end of tail
142  * 
143  * @param buf
144  * @param len (how much data to put)
145  * 
146  * @return previous tail (data+len),NULL if the len is more than
147  *         space available
148  */
149 a_uint8_t *
150 __adf_nbuf_put_tail(__adf_nbuf_t buf, adf_os_size_t len)
151 {
152     a_uint8_t *tail = NULL;
153     VDESC *last_desc = __adf_nbuf_last(buf);
154     
155     tail = last_desc->buf_addr + last_desc->data_offset + last_desc->data_size;
156     last_desc->data_size += len;
157     buf->buf_length += len;
158     
159     return tail;
160 }
161
162 /**
163  * @brief strip data from head
164  * 
165  * @param adf_nbuf
166  * @param len (how much data to rip)
167  * 
168  * @return new data pointer
169  */
170 a_uint8_t * 
171 __adf_nbuf_pull_head(__adf_nbuf_t buf, adf_os_size_t len)
172 {
173     a_uint8_t *ptr = NULL;
174     VDESC *desc = buf->desc_list;
175     
176     desc->data_offset += len;
177     desc->data_size -= len;
178     buf->buf_length -= len;
179     ptr = desc->buf_addr + desc->data_offset;
180     
181     return ptr;
182 }
183 /**
184  * @brief strip data from tail, priv safe
185  * 
186  * @param buf
187  * @param len (how much to strip down)
188  * 
189  */
190 void 
191 __adf_nbuf_trim_tail(__adf_nbuf_t buf, adf_os_size_t len)
192 {
193     VDESC *last_desc = __adf_nbuf_last(buf);
194     
195     adf_os_assert(buf != NULL);
196     last_desc->data_size -= len;
197     buf->buf_length -= len;
198     
199     //adf_os_assert(0);    //0820
200 }
201 /**
202  * @brief Copy assumes that we create a writeable copy of the
203  *        nbuf which is equivalent in FreeBSD as duping the
204  *        mbuf.
205  * 
206  * @param src
207  * 
208  * @return struct mbuf * (newly allocated buffer)
209  */
210 __adf_nbuf_t 
211 __adf_nbuf_copy(__adf_nbuf_t src)
212 {
213     __adf_nbuf_t buf = NULL; 
214
215     adf_os_assert(src != NULL);
216     
217     return buf;
218 }
219 /**
220  * @brief make the writable copy of the nbuf
221  * 
222  * @param adf_nbuf
223  * 
224  * @return new nbuf
225  */
226 __adf_nbuf_t 
227 __adf_nbuf_unshare(__adf_nbuf_t  src)
228 {
229     __adf_nbuf_t buf = NULL;
230
231     adf_os_assert(src != NULL);
232
233     return buf;
234 }
235
236 /**
237  * @brief return the frag data & len, where frag no. is
238  *        specified by the index
239  * 
240  * @param[in] buf
241  * @param[out] sg (scatter/gather list of all the frags)
242  * 
243  */
244 void  
245 __adf_nbuf_frag_info(__adf_nbuf_t buf, adf_os_sglist_t  *sg)
246 {
247     VDESC *desc = buf->desc_list;
248     int count = 0;
249     
250     while( desc != NULL ) {
251         sg->sg_segs[count].vaddr = desc->buf_addr + desc->data_offset;
252         sg->sg_segs[count].len   = desc->data_size;
253         
254         count++;        
255         desc = desc->next_desc;
256     }
257     
258     sg->nsegs = count;
259 }
260 /**
261  * @brief retrieve the priv space pointer from nbuf
262  * 
263  * @param buf (nbuf to attach the priv space)
264  * 
265  * @return uint8_t* ( pointer to the data )
266  */
267 a_uint8_t *
268 __adf_nbuf_get_priv(__adf_nbuf_t buf)
269 {
270     adf_os_assert(buf != NULL);
271
272     return buf->ctx;
273 }
274
275 /**
276  * 
277  * @brief append the nbuf to the queue
278  * 
279  * @param adf_qhead
280  * @param adf_nbuf
281  * 
282  */
283 void 
284 __adf_nbuf_queue_add(__adf_nbuf_qhead_t  *qhead, 
285                      __adf_nbuf_t  buf)
286 {
287     qhead->qlen++;
288
289     buf->next_buf = NULL;
290
291     if (qhead->head == NULL) {
292         qhead->head = buf;
293     }
294     else {
295         qhead->tail->next_buf = buf;
296     }
297     qhead->tail = buf;
298 }
299
300 /**
301  * @brief dequeue an nbuf
302  * 
303  * @param adf_qhead
304  * 
305  * @return the nbuf
306  */
307 __adf_nbuf_t   
308 __adf_nbuf_queue_remove(__adf_nbuf_qhead_t *qhead)
309 {
310     __adf_nbuf_t  b0 = NULL;
311
312     if (qhead->head) {
313         qhead->qlen--;
314         b0 = qhead->head;
315         if ( qhead->head == qhead->tail ) {
316             qhead->head = NULL;
317             qhead->tail = NULL;
318         } else {
319             qhead->head = qhead->head->next_buf;
320         }
321     
322         b0->next_buf = NULL;
323     }
324         return b0;
325 }
326
327 /**
328  * ****************DMA Routines Start Here*****************
329  */
330
331
332 /**
333  * @brief creates a streaming mapping (takes a pre allocated
334  *        global tag for 4K mbuf sizes)
335  * 
336  * @param hdl
337  * @param max_sz
338  * @param dmap
339  * 
340  * @return a_status_t
341  */
342 a_status_t 
343 __adf_nbuf_dmamap_create(__adf_os_device_t osdev, __adf_os_dma_map_t *dmap)
344 {
345     a_status_t retval = A_STATUS_OK;
346     
347     (*dmap) = A_ALLOCRAM(sizeof(struct __adf_dma_map));
348     if(*dmap == NULL)
349         return A_STATUS_ENOMEM;
350             
351     (*dmap)->buf = NULL;
352     return retval;
353 }
354
355
356 a_status_t 
357 __adf_nbuf_map(__adf_os_device_t osdev, __adf_os_dma_map_t bmap, 
358                           __adf_nbuf_t buf, adf_os_dma_dir_t dir)
359 {   
360     bmap->buf = buf;
361     
362     return A_STATUS_OK;
363 }
364
365 void 
366 __adf_nbuf_unmap(__adf_os_device_t osdev, __adf_os_dma_map_t bmap, 
367                             adf_os_dma_dir_t dir)
368 {
369     bmap->buf = NULL;
370     
371     return;
372 }
373
374 void
375 __adf_nbuf_dmamap_destroy(__adf_os_device_t osdev, 
376                           __adf_os_dma_map_t dmap)
377 {
378     //dmap->buf = NULL;
379     
380     // Should not be called in FW!
381     //return A_STATUS_OK;
382 }
383
384
385
386 /**
387  * @brief return the dma map info 
388  * 
389  * @param[in]  bmap
390  * @param[out] sg (map_info ptr)
391  */
392 void 
393 __adf_nbuf_dmamap_info(__adf_os_dma_map_t bmap, adf_os_dmamap_info_t *sg)
394 {
395     VDESC *desc = bmap->buf->desc_list;
396     int count = 0;
397     
398     while( desc != NULL ) {
399         sg->dma_segs[count].paddr = (adf_os_dma_addr_t)(desc->buf_addr + desc->data_offset);
400         sg->dma_segs[count].len   = desc->data_size;
401         
402         count++;        
403         desc = desc->next_desc;
404     }
405     
406     sg->nsegs = count;    
407 }
408
409 /**
410  * **************************Misc routines***************
411  */
412
413
414 /**
415  * @brief sets the cksum type & value for nbuf
416  * XXX: not fully implemented
417  * 
418  * @param buf
419  * @param cksum
420  */
421 void 
422 __adf_nbuf_set_rx_cksum(__adf_nbuf_t buf, adf_nbuf_rx_cksum_t *cksum)
423 {
424
425 }
426
427 a_status_t      
428 __adf_nbuf_get_vlan_info(adf_net_handle_t hdl, __adf_nbuf_t buf, 
429                          adf_net_vlanhdr_t *vlan)
430 {
431     return A_STATUS_OK;
432 }
433
434 __adf_nbuf_t
435 __adf_nbuf_create_frm_frag(__adf_nbuf_queue_t *qhead)
436 {
437     VBUF *buf_tmp, *buf_head = NULL;
438     VDESC *vdesc_prev = NULL, *vdesc_tmp = NULL;
439     a_uint32_t cnt = 0, len = __adf_nbuf_queue_len(qhead);
440     a_uint16_t total_len = 0;
441
442     buf_head = VBUF_alloc_vbuf();
443     buf_tmp = __adf_nbuf_queue_first(qhead);
444
445     __adf_os_assert(buf_head);
446     __adf_os_assert(buf_tmp);
447
448     buf_head->desc_list = buf_tmp->desc_list;
449
450     while ((buf_tmp = __adf_nbuf_queue_remove(qhead)) != NULL) {
451         cnt++;
452
453         //adf_os_print("merge buf: %x\n", buf_tmp->desc_list->buf_addr + buf_tmp->desc_list->data_offset);
454
455         total_len += buf_tmp->buf_length;
456
457         if (vdesc_prev) {
458             /* link "the last VDESC of previous VBUF" to "the 1st VDESC of this VBUF" */
459             vdesc_prev->next_desc = buf_tmp->desc_list;
460         }
461
462         /* traverse VDESC list in this VBUF to find out the last VDESC */
463         vdesc_tmp = buf_tmp->desc_list;
464         while (vdesc_tmp->next_desc) {
465             vdesc_tmp = vdesc_tmp->next_desc;
466         }
467         vdesc_prev = vdesc_tmp;
468
469         /* return VBUF to the pool */
470         buf_tmp->desc_list = NULL;
471         buf_tmp->buf_length = 0;
472         VBUF_free_vbuf(buf_tmp);
473     }
474
475     if (cnt != len) {
476         //adf_os_print("cnt: %x, len: %x, __adf_nbuf_queue_len: %x\n", cnt, len, 
477         //             __adf_nbuf_queue_len(qhead));
478         adf_os_assert(0);
479     }
480     //__adf_os_assert(cnt == len);
481
482     buf_head->buf_length = total_len;
483
484     return buf_head;
485 }
486
487 void
488 __adf_nbuf_split_to_frag(__adf_nbuf_t buf, __adf_nbuf_qhead_t *qhead)
489 {
490     VBUF *buf_tmp;
491     VDESC *desc_tmp = NULL;
492
493     __adf_nbuf_queue_init(qhead);
494     desc_tmp = buf->desc_list;
495
496     while (desc_tmp /*&& desc_tmp->buf_addr*/) {
497         buf_tmp = VBUF_alloc_vbuf();
498
499         __adf_os_assert(buf_tmp);
500
501         //desc_tmp->data_size = 0;
502         buf_tmp->desc_list = desc_tmp;
503         //buf_tmp->buf_length = desc_tmp->buf_size;
504         buf_tmp->buf_length = desc_tmp->data_size;
505         buf_tmp->next_buf = NULL;
506
507         //adf_os_print("split - buf: %x\n", buf_tmp->desc_list->buf_addr + buf_tmp->desc_list->data_offset);
508
509         __adf_nbuf_queue_add(qhead, buf_tmp);
510
511         desc_tmp = desc_tmp->next_desc;
512
513         buf_tmp->desc_list->next_desc = NULL;
514     }
515
516     buf->desc_list = NULL;
517     buf->buf_length = 0;
518     VBUF_free_vbuf(buf);
519     
520 }
521
522 /**
523  * @brief return the last mbuf
524  * 
525  * @param m0
526  * 
527  * @return struct mbuf*
528  */
529 VDESC * 
530 __adf_nbuf_last(VBUF *buf)
531 {
532     VDESC *desc = buf->desc_list;
533     
534     //for(; desc->next_desc != NULL; desc = desc->next_desc)
535     //    ;
536     while(desc->next_desc != NULL)
537     {
538         desc = desc->next_desc;
539     }
540     
541     return desc;
542 }
543
544 /**
545  * @brief num bytes in the head
546  * 
547  * @param adf_nbuf
548  * 
549  * @return num of bytes available
550  */
551 a_uint32_t
552 __adf_nbuf_headroom(__adf_nbuf_t  buf)
553 {
554     return buf->desc_list->data_offset;
555 }
556
557
558 /**
559  * @brief num of bytes available in the tail excluding the priv
560  *        portion
561  * 
562  * @param adf_nbuf
563  * 
564  * @return num of bytes
565  */
566
567 a_uint32_t 
568 __adf_nbuf_tailroom(__adf_nbuf_t  buf)
569 {
570     VDESC *last_desc = __adf_nbuf_last(buf);
571     
572     return last_desc->buf_size - last_desc->data_offset - last_desc->data_size;
573 }
574
575 /**
576  * @brief get the entire packet length
577  * 
578  * @param adf_nbuf
579  * 
580  * @return total length of packet (sum of all frag lengths)
581  */ 
582 a_uint32_t
583 __adf_nbuf_len(__adf_nbuf_t  buf)
584 {
585     return buf->buf_length; 
586 }
587
588 /**
589  * @brief Clone the nbuf (will not create writeable copies)
590  * 
591  * @param adf_nbuf
592  * 
593  * @return Read-only copy of the nbuf (including clusters)
594  */
595 __adf_nbuf_t 
596 __adf_nbuf_clone(__adf_nbuf_t  src)
597 {
598     __adf_nbuf_t buf = NULL;
599     
600     return buf;
601 }
602
603 void
604 __adf_nbuf_cat(__adf_nbuf_t dst, __adf_nbuf_t src)
605 {
606
607 }
608
609
610
611 /*
612  * @brief check if the mbuf is cloned or not
613  * 
614  * @param buf
615  * 
616  * @return a_bool_t
617  */
618 a_bool_t
619 __adf_nbuf_is_cloned(__adf_nbuf_t  buf)
620 {
621     return A_FALSE;
622 }
623 /**
624  * @brief This will return the header's addr & m_len
625  */
626 void
627 __adf_nbuf_peek_header(__adf_nbuf_t buf, a_uint8_t   **addr, 
628                        a_uint32_t       *len)
629 {
630     VDESC *desc = buf->desc_list;
631     
632     *addr = desc->buf_addr + desc->data_offset;
633     *len = desc->data_size; 
634 }
635 /**
636  * @brief init the queue
637  * @param qhead
638  */
639 void 
640 __adf_nbuf_queue_init(__adf_nbuf_qhead_t *qhead)
641 {
642     qhead->qlen = 0;
643     qhead->head = NULL;
644     qhead->tail = NULL;
645 }
646 /**
647  * @brief return the length of queue
648  * @param adf_qhead
649  * 
650  * @return length
651  * 
652  */
653 a_uint32_t  
654 __adf_nbuf_queue_len(__adf_nbuf_qhead_t *qhead)
655 {
656     return qhead->qlen;
657 }
658 /**
659  * @brief returns the first guy in the Q
660  * @param qhead
661  * 
662  * @return (NULL if the Q is empty)
663  */
664 __adf_nbuf_t   
665 __adf_nbuf_queue_first(__adf_nbuf_queue_t *qhead)
666 {
667     return qhead->head;
668 }
669 /**
670  * @brief return the next packet from packet chain
671  * 
672  * @param buf (packet)
673  * 
674  * @return (NULL if no packets are there)
675  */
676 __adf_nbuf_t   
677 __adf_nbuf_queue_next(__adf_nbuf_t  buf)
678 {
679     return buf->next_buf;
680 }
681 /**
682  * @brief check if the queue is empty or not
683  * 
684  * @param qhead
685  * 
686  * @return a_bool_t
687  */
688 a_bool_t  
689 __adf_nbuf_is_queue_empty(__adf_nbuf_qhead_t *qhead)
690 {
691     return ((qhead->qlen == 0));
692 }