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