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