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
44 #include "cmnos_api.h"
45 #include <Magpie_api.h>
48 // #############################################################################
49 VDESC * __adf_nbuf_last(VBUF *buf);
52 // #############################################################################
56 * @brief allocate a new nbuf,
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)
62 * @return newly allocated nbuf
65 __adf_nbuf_alloc(adf_os_size_t size, a_uint32_t reserve,
71 buf = VBUF_alloc_vbuf();
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;
81 buf->desc_list = desc;
89 * @brief Free the nbuf
90 * function to be called in
95 void __adf_nbuf_free(__adf_nbuf_t buf)
101 * @brief reallocate the head space, call it only after the you
102 * have called headroom
110 __adf_nbuf_realloc_headroom(__adf_nbuf_t buf, a_uint32_t headroom)
117 * @brief expand the tailroom, mostly by adding the new tail
118 * buffer, also take care of the priv
123 * @return struct mbuf * (buffer with the new tailroom)
126 __adf_nbuf_realloc_tailroom(__adf_nbuf_t buf, a_uint32_t tailroom)
133 * @brief expand the headroom or tailroom or both
136 * @param headroom ( 0 if no headroom expansion req)
137 * @param tailroom ( 0 if no tailroom expansion req)
139 * @return struct mbuf* (NULL if something goofed up)
142 __adf_nbuf_expand(__adf_nbuf_t buf, a_uint32_t headroom, a_uint32_t tailroom)
149 * @brief put data in the head
152 * @param len (how much data to put)
154 * @return new data pointer ,NULL if the len is more than the
155 * space available in the head frag.
158 __adf_nbuf_push_head(__adf_nbuf_t buf, adf_os_size_t len)
160 a_uint8_t *ptr = NULL;
161 VDESC *desc = buf->desc_list;
163 desc->data_offset -= len;
164 desc->data_size += len;
165 buf->buf_length += len;
166 ptr = desc->buf_addr + desc->data_offset;
172 * @brief add data in the end of tail
175 * @param len (how much data to put)
177 * @return previous tail (data+len),NULL if the len is more than
181 __adf_nbuf_put_tail(__adf_nbuf_t buf, adf_os_size_t len)
183 a_uint8_t *tail = NULL;
184 VDESC *last_desc = __adf_nbuf_last(buf);
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;
194 * @brief strip data from head
197 * @param len (how much data to rip)
199 * @return new data pointer
202 __adf_nbuf_pull_head(__adf_nbuf_t buf, adf_os_size_t len)
204 a_uint8_t *ptr = NULL;
205 VDESC *desc = buf->desc_list;
207 desc->data_offset += len;
208 desc->data_size -= len;
209 buf->buf_length -= len;
210 ptr = desc->buf_addr + desc->data_offset;
215 * @brief strip data from tail, priv safe
218 * @param len (how much to strip down)
222 __adf_nbuf_trim_tail(__adf_nbuf_t buf, adf_os_size_t len)
224 VDESC *last_desc = __adf_nbuf_last(buf);
226 adf_os_assert(buf != NULL);
227 last_desc->data_size -= len;
228 buf->buf_length -= len;
230 //adf_os_assert(0); //0820
233 * @brief Copy assumes that we create a writeable copy of the
234 * nbuf which is equivalent in FreeBSD as duping the
239 * @return struct mbuf * (newly allocated buffer)
242 __adf_nbuf_copy(__adf_nbuf_t src)
244 __adf_nbuf_t buf = NULL;
246 adf_os_assert(src != NULL);
251 * @brief make the writable copy of the nbuf
258 __adf_nbuf_unshare(__adf_nbuf_t src)
260 __adf_nbuf_t buf = NULL;
262 adf_os_assert(src != NULL);
268 * @brief return the frag data & len, where frag no. is
269 * specified by the index
272 * @param[out] sg (scatter/gather list of all the frags)
276 __adf_nbuf_frag_info(__adf_nbuf_t buf, adf_os_sglist_t *sg)
278 VDESC *desc = buf->desc_list;
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;
286 desc = desc->next_desc;
292 * @brief retrieve the priv space pointer from nbuf
294 * @param buf (nbuf to attach the priv space)
296 * @return uint8_t* ( pointer to the data )
299 __adf_nbuf_get_priv(__adf_nbuf_t buf)
301 adf_os_assert(buf != NULL);
308 * @brief append the nbuf to the queue
315 __adf_nbuf_queue_add(__adf_nbuf_qhead_t *qhead,
320 buf->next_buf = NULL;
322 if (qhead->head == NULL) {
326 qhead->tail->next_buf = buf;
332 * @brief dequeue an nbuf
339 __adf_nbuf_queue_remove(__adf_nbuf_qhead_t *qhead)
341 __adf_nbuf_t b0 = NULL;
346 if ( qhead->head == qhead->tail ) {
350 qhead->head = qhead->head->next_buf;
359 * ****************DMA Routines Start Here*****************
364 * @brief creates a streaming mapping (takes a pre allocated
365 * global tag for 4K mbuf sizes)
374 __adf_nbuf_dmamap_create(__adf_os_device_t osdev, __adf_os_dma_map_t *dmap)
376 a_status_t retval = A_STATUS_OK;
378 (*dmap) = A_ALLOCRAM(sizeof(struct __adf_dma_map));
380 return A_STATUS_ENOMEM;
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)
397 __adf_nbuf_unmap(__adf_os_device_t osdev, __adf_os_dma_map_t bmap,
398 adf_os_dma_dir_t dir)
406 __adf_nbuf_dmamap_destroy(__adf_os_device_t osdev,
407 __adf_os_dma_map_t dmap)
411 // Should not be called in FW!
412 //return A_STATUS_OK;
418 * @brief return the dma map info
421 * @param[out] sg (map_info ptr)
424 __adf_nbuf_dmamap_info(__adf_os_dma_map_t bmap, adf_os_dmamap_info_t *sg)
426 VDESC *desc = bmap->buf->desc_list;
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;
434 desc = desc->next_desc;
441 * **************************Misc routines***************
446 * @brief sets the cksum type & value for nbuf
447 * XXX: not fully implemented
453 __adf_nbuf_set_rx_cksum(__adf_nbuf_t buf, adf_nbuf_rx_cksum_t *cksum)
459 __adf_nbuf_get_vlan_info(adf_net_handle_t hdl, __adf_nbuf_t buf,
460 adf_net_vlanhdr_t *vlan)
466 __adf_nbuf_create_frm_frag(__adf_nbuf_queue_t *qhead)
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;
473 buf_head = VBUF_alloc_vbuf();
474 buf_tmp = __adf_nbuf_queue_first(qhead);
476 __adf_os_assert(buf_head);
477 __adf_os_assert(buf_tmp);
479 buf_head->desc_list = buf_tmp->desc_list;
481 while ((buf_tmp = __adf_nbuf_queue_remove(qhead)) != NULL) {
484 //adf_os_print("merge buf: %x\n", buf_tmp->desc_list->buf_addr + buf_tmp->desc_list->data_offset);
486 total_len += buf_tmp->buf_length;
489 /* link "the last VDESC of previous VBUF" to "the 1st VDESC of this VBUF" */
490 vdesc_prev->next_desc = buf_tmp->desc_list;
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;
498 vdesc_prev = vdesc_tmp;
500 /* return VBUF to the pool */
501 buf_tmp->desc_list = NULL;
502 buf_tmp->buf_length = 0;
503 VBUF_free_vbuf(buf_tmp);
507 //adf_os_print("cnt: %x, len: %x, __adf_nbuf_queue_len: %x\n", cnt, len,
508 // __adf_nbuf_queue_len(qhead));
511 //__adf_os_assert(cnt == len);
513 buf_head->buf_length = total_len;
519 __adf_nbuf_split_to_frag(__adf_nbuf_t buf, __adf_nbuf_qhead_t *qhead)
522 VDESC *desc_tmp = NULL;
524 __adf_nbuf_queue_init(qhead);
525 desc_tmp = buf->desc_list;
527 while (desc_tmp /*&& desc_tmp->buf_addr*/) {
528 buf_tmp = VBUF_alloc_vbuf();
530 __adf_os_assert(buf_tmp);
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;
538 //adf_os_print("split - buf: %x\n", buf_tmp->desc_list->buf_addr + buf_tmp->desc_list->data_offset);
540 __adf_nbuf_queue_add(qhead, buf_tmp);
542 desc_tmp = desc_tmp->next_desc;
544 buf_tmp->desc_list->next_desc = NULL;
547 buf->desc_list = NULL;
554 * @brief return the last mbuf
558 * @return struct mbuf*
561 __adf_nbuf_last(VBUF *buf)
563 VDESC *desc = buf->desc_list;
565 //for(; desc->next_desc != NULL; desc = desc->next_desc)
567 while(desc->next_desc != NULL)
569 desc = desc->next_desc;
576 * @brief num bytes in the head
580 * @return num of bytes available
583 __adf_nbuf_headroom(__adf_nbuf_t buf)
585 return buf->desc_list->data_offset;
590 * @brief num of bytes available in the tail excluding the priv
595 * @return num of bytes
599 __adf_nbuf_tailroom(__adf_nbuf_t buf)
601 VDESC *last_desc = __adf_nbuf_last(buf);
603 return last_desc->buf_size - last_desc->data_offset - last_desc->data_size;
607 * @brief get the entire packet length
611 * @return total length of packet (sum of all frag lengths)
614 __adf_nbuf_len(__adf_nbuf_t buf)
616 return buf->buf_length;
620 * @brief Clone the nbuf (will not create writeable copies)
624 * @return Read-only copy of the nbuf (including clusters)
627 __adf_nbuf_clone(__adf_nbuf_t src)
629 __adf_nbuf_t buf = NULL;
635 __adf_nbuf_cat(__adf_nbuf_t dst, __adf_nbuf_t src)
643 * @brief check if the mbuf is cloned or not
650 __adf_nbuf_is_cloned(__adf_nbuf_t buf)
655 * @brief This will return the header's addr & m_len
658 __adf_nbuf_peek_header(__adf_nbuf_t buf, a_uint8_t **addr,
661 VDESC *desc = buf->desc_list;
663 *addr = desc->buf_addr + desc->data_offset;
664 *len = desc->data_size;
667 * @brief init the queue
671 __adf_nbuf_queue_init(__adf_nbuf_qhead_t *qhead)
678 * @brief return the length of queue
685 __adf_nbuf_queue_len(__adf_nbuf_qhead_t *qhead)
690 * @brief returns the first guy in the Q
693 * @return (NULL if the Q is empty)
696 __adf_nbuf_queue_first(__adf_nbuf_queue_t *qhead)
701 * @brief return the next packet from packet chain
703 * @param buf (packet)
705 * @return (NULL if no packets are there)
708 __adf_nbuf_queue_next(__adf_nbuf_t buf)
710 return buf->next_buf;
713 * @brief check if the queue is empty or not
720 __adf_nbuf_is_queue_empty(__adf_nbuf_qhead_t *qhead)
722 return ((qhead->qlen == 0));