2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
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:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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
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.
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.
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
43 #include "cmnos_api.h"
44 #include <Magpie_api.h>
47 // #############################################################################
48 VDESC * __adf_nbuf_last(VBUF *buf);
51 // #############################################################################
55 * @brief allocate a new nbuf,
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)
61 * @return newly allocated nbuf
64 __adf_nbuf_alloc(adf_os_size_t size, a_uint32_t reserve,
70 buf = VBUF_alloc_vbuf();
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;
80 buf->desc_list = desc;
88 * @brief Free the nbuf
89 * function to be called in
94 void __adf_nbuf_free(__adf_nbuf_t buf)
100 * @brief reallocate the head space, call it only after the you
101 * have called headroom
109 __adf_nbuf_realloc_headroom(__adf_nbuf_t buf, a_uint32_t headroom)
116 * @brief expand the tailroom, mostly by adding the new tail
117 * buffer, also take care of the priv
122 * @return struct mbuf * (buffer with the new tailroom)
125 __adf_nbuf_realloc_tailroom(__adf_nbuf_t buf, a_uint32_t tailroom)
132 * @brief expand the headroom or tailroom or both
135 * @param headroom ( 0 if no headroom expansion req)
136 * @param tailroom ( 0 if no tailroom expansion req)
138 * @return struct mbuf* (NULL if something goofed up)
141 __adf_nbuf_expand(__adf_nbuf_t buf, a_uint32_t headroom, a_uint32_t tailroom)
148 * @brief put data in the head
151 * @param len (how much data to put)
153 * @return new data pointer ,NULL if the len is more than the
154 * space available in the head frag.
157 __adf_nbuf_push_head(__adf_nbuf_t buf, adf_os_size_t len)
159 a_uint8_t *ptr = NULL;
160 VDESC *desc = buf->desc_list;
162 desc->data_offset -= len;
163 desc->data_size += len;
164 buf->buf_length += len;
165 ptr = desc->buf_addr + desc->data_offset;
171 * @brief add data in the end of tail
174 * @param len (how much data to put)
176 * @return previous tail (data+len),NULL if the len is more than
180 __adf_nbuf_put_tail(__adf_nbuf_t buf, adf_os_size_t len)
182 a_uint8_t *tail = NULL;
183 VDESC *last_desc = __adf_nbuf_last(buf);
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;
193 * @brief strip data from head
196 * @param len (how much data to rip)
198 * @return new data pointer
201 __adf_nbuf_pull_head(__adf_nbuf_t buf, adf_os_size_t len)
203 a_uint8_t *ptr = NULL;
204 VDESC *desc = buf->desc_list;
206 desc->data_offset += len;
207 desc->data_size -= len;
208 buf->buf_length -= len;
209 ptr = desc->buf_addr + desc->data_offset;
214 * @brief strip data from tail, priv safe
217 * @param len (how much to strip down)
221 __adf_nbuf_trim_tail(__adf_nbuf_t buf, adf_os_size_t len)
223 VDESC *last_desc = __adf_nbuf_last(buf);
225 adf_os_assert(buf != NULL);
226 last_desc->data_size -= len;
227 buf->buf_length -= len;
229 //adf_os_assert(0); //0820
232 * @brief Copy assumes that we create a writeable copy of the
233 * nbuf which is equivalent in FreeBSD as duping the
238 * @return struct mbuf * (newly allocated buffer)
241 __adf_nbuf_copy(__adf_nbuf_t src)
243 __adf_nbuf_t buf = NULL;
245 adf_os_assert(src != NULL);
250 * @brief make the writable copy of the nbuf
257 __adf_nbuf_unshare(__adf_nbuf_t src)
259 __adf_nbuf_t buf = NULL;
261 adf_os_assert(src != NULL);
267 * @brief return the frag data & len, where frag no. is
268 * specified by the index
271 * @param[out] sg (scatter/gather list of all the frags)
275 __adf_nbuf_frag_info(__adf_nbuf_t buf, adf_os_sglist_t *sg)
277 VDESC *desc = buf->desc_list;
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;
285 desc = desc->next_desc;
291 * @brief retrieve the priv space pointer from nbuf
293 * @param buf (nbuf to attach the priv space)
295 * @return uint8_t* ( pointer to the data )
298 __adf_nbuf_get_priv(__adf_nbuf_t buf)
300 adf_os_assert(buf != NULL);
307 * @brief append the nbuf to the queue
314 __adf_nbuf_queue_add(__adf_nbuf_qhead_t *qhead,
319 buf->next_buf = NULL;
321 if (qhead->head == NULL) {
325 qhead->tail->next_buf = buf;
331 * @brief dequeue an nbuf
338 __adf_nbuf_queue_remove(__adf_nbuf_qhead_t *qhead)
340 __adf_nbuf_t b0 = NULL;
345 if ( qhead->head == qhead->tail ) {
349 qhead->head = qhead->head->next_buf;
358 * ****************DMA Routines Start Here*****************
363 * @brief creates a streaming mapping (takes a pre allocated
364 * global tag for 4K mbuf sizes)
373 __adf_nbuf_dmamap_create(__adf_os_device_t osdev, __adf_os_dma_map_t *dmap)
375 a_status_t retval = A_STATUS_OK;
377 (*dmap) = A_ALLOCRAM(sizeof(struct __adf_dma_map));
379 return A_STATUS_ENOMEM;
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)
396 __adf_nbuf_unmap(__adf_os_device_t osdev, __adf_os_dma_map_t bmap,
397 adf_os_dma_dir_t dir)
405 __adf_nbuf_dmamap_destroy(__adf_os_device_t osdev,
406 __adf_os_dma_map_t dmap)
410 // Should not be called in FW!
411 //return A_STATUS_OK;
417 * @brief return the dma map info
420 * @param[out] sg (map_info ptr)
423 __adf_nbuf_dmamap_info(__adf_os_dma_map_t bmap, adf_os_dmamap_info_t *sg)
425 VDESC *desc = bmap->buf->desc_list;
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;
433 desc = desc->next_desc;
440 * **************************Misc routines***************
445 * @brief sets the cksum type & value for nbuf
446 * XXX: not fully implemented
452 __adf_nbuf_set_rx_cksum(__adf_nbuf_t buf, adf_nbuf_rx_cksum_t *cksum)
458 __adf_nbuf_get_vlan_info(adf_net_handle_t hdl, __adf_nbuf_t buf,
459 adf_net_vlanhdr_t *vlan)
465 __adf_nbuf_create_frm_frag(__adf_nbuf_queue_t *qhead)
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;
472 buf_head = VBUF_alloc_vbuf();
473 buf_tmp = __adf_nbuf_queue_first(qhead);
475 __adf_os_assert(buf_head);
476 __adf_os_assert(buf_tmp);
478 buf_head->desc_list = buf_tmp->desc_list;
480 while ((buf_tmp = __adf_nbuf_queue_remove(qhead)) != NULL) {
483 //adf_os_print("merge buf: %x\n", buf_tmp->desc_list->buf_addr + buf_tmp->desc_list->data_offset);
485 total_len += buf_tmp->buf_length;
488 /* link "the last VDESC of previous VBUF" to "the 1st VDESC of this VBUF" */
489 vdesc_prev->next_desc = buf_tmp->desc_list;
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;
497 vdesc_prev = vdesc_tmp;
499 /* return VBUF to the pool */
500 buf_tmp->desc_list = NULL;
501 buf_tmp->buf_length = 0;
502 VBUF_free_vbuf(buf_tmp);
506 //adf_os_print("cnt: %x, len: %x, __adf_nbuf_queue_len: %x\n", cnt, len,
507 // __adf_nbuf_queue_len(qhead));
510 //__adf_os_assert(cnt == len);
512 buf_head->buf_length = total_len;
518 __adf_nbuf_split_to_frag(__adf_nbuf_t buf, __adf_nbuf_qhead_t *qhead)
521 VDESC *desc_tmp = NULL;
523 __adf_nbuf_queue_init(qhead);
524 desc_tmp = buf->desc_list;
526 while (desc_tmp /*&& desc_tmp->buf_addr*/) {
527 buf_tmp = VBUF_alloc_vbuf();
529 __adf_os_assert(buf_tmp);
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;
537 //adf_os_print("split - buf: %x\n", buf_tmp->desc_list->buf_addr + buf_tmp->desc_list->data_offset);
539 __adf_nbuf_queue_add(qhead, buf_tmp);
541 desc_tmp = desc_tmp->next_desc;
543 buf_tmp->desc_list->next_desc = NULL;
546 buf->desc_list = NULL;
553 * @brief return the last mbuf
557 * @return struct mbuf*
560 __adf_nbuf_last(VBUF *buf)
562 VDESC *desc = buf->desc_list;
564 //for(; desc->next_desc != NULL; desc = desc->next_desc)
566 while(desc->next_desc != NULL)
568 desc = desc->next_desc;
575 * @brief num bytes in the head
579 * @return num of bytes available
582 __adf_nbuf_headroom(__adf_nbuf_t buf)
584 return buf->desc_list->data_offset;
589 * @brief num of bytes available in the tail excluding the priv
594 * @return num of bytes
598 __adf_nbuf_tailroom(__adf_nbuf_t buf)
600 VDESC *last_desc = __adf_nbuf_last(buf);
602 return last_desc->buf_size - last_desc->data_offset - last_desc->data_size;
606 * @brief get the entire packet length
610 * @return total length of packet (sum of all frag lengths)
613 __adf_nbuf_len(__adf_nbuf_t buf)
615 return buf->buf_length;
619 * @brief Clone the nbuf (will not create writeable copies)
623 * @return Read-only copy of the nbuf (including clusters)
626 __adf_nbuf_clone(__adf_nbuf_t src)
628 __adf_nbuf_t buf = NULL;
634 __adf_nbuf_cat(__adf_nbuf_t dst, __adf_nbuf_t src)
642 * @brief check if the mbuf is cloned or not
649 __adf_nbuf_is_cloned(__adf_nbuf_t buf)
654 * @brief This will return the header's addr & m_len
657 __adf_nbuf_peek_header(__adf_nbuf_t buf, a_uint8_t **addr,
660 VDESC *desc = buf->desc_list;
662 *addr = desc->buf_addr + desc->data_offset;
663 *len = desc->data_size;
666 * @brief init the queue
670 __adf_nbuf_queue_init(__adf_nbuf_qhead_t *qhead)
677 * @brief return the length of queue
684 __adf_nbuf_queue_len(__adf_nbuf_qhead_t *qhead)
689 * @brief returns the first guy in the Q
692 * @return (NULL if the Q is empty)
695 __adf_nbuf_queue_first(__adf_nbuf_queue_t *qhead)
700 * @brief return the next packet from packet chain
702 * @param buf (packet)
704 * @return (NULL if no packets are there)
707 __adf_nbuf_queue_next(__adf_nbuf_t buf)
709 return buf->next_buf;
712 * @brief check if the queue is empty or not
719 __adf_nbuf_is_queue_empty(__adf_nbuf_qhead_t *qhead)
721 return ((qhead->qlen == 0));