2 * (c) Copyright Atheros Communications Inc.,2002-2008
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
13 #include "cmnos_api.h"
14 #include <Magpie_api.h>
17 // #############################################################################
18 VDESC * __adf_nbuf_last(VBUF *buf);
21 // #############################################################################
25 * @brief allocate a new nbuf,
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)
31 * @return newly allocated nbuf
34 __adf_nbuf_alloc(adf_os_size_t size, a_uint32_t reserve,
40 buf = VBUF_alloc_vbuf();
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;
50 buf->desc_list = desc;
58 * @brief Free the nbuf
59 * function to be called in
64 void __adf_nbuf_free(__adf_nbuf_t buf)
70 * @brief reallocate the head space, call it only after the you
71 * have called headroom
79 __adf_nbuf_realloc_headroom(__adf_nbuf_t buf, a_uint32_t headroom)
86 * @brief expand the tailroom, mostly by adding the new tail
87 * buffer, also take care of the priv
92 * @return struct mbuf * (buffer with the new tailroom)
95 __adf_nbuf_realloc_tailroom(__adf_nbuf_t buf, a_uint32_t tailroom)
102 * @brief expand the headroom or tailroom or both
105 * @param headroom ( 0 if no headroom expansion req)
106 * @param tailroom ( 0 if no tailroom expansion req)
108 * @return struct mbuf* (NULL if something goofed up)
111 __adf_nbuf_expand(__adf_nbuf_t buf, a_uint32_t headroom, a_uint32_t tailroom)
118 * @brief put data in the head
121 * @param len (how much data to put)
123 * @return new data pointer ,NULL if the len is more than the
124 * space available in the head frag.
127 __adf_nbuf_push_head(__adf_nbuf_t buf, adf_os_size_t len)
129 a_uint8_t *ptr = NULL;
130 VDESC *desc = buf->desc_list;
132 desc->data_offset -= len;
133 desc->data_size += len;
134 buf->buf_length += len;
135 ptr = desc->buf_addr + desc->data_offset;
141 * @brief add data in the end of tail
144 * @param len (how much data to put)
146 * @return previous tail (data+len),NULL if the len is more than
150 __adf_nbuf_put_tail(__adf_nbuf_t buf, adf_os_size_t len)
152 a_uint8_t *tail = NULL;
153 VDESC *last_desc = __adf_nbuf_last(buf);
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;
163 * @brief strip data from head
166 * @param len (how much data to rip)
168 * @return new data pointer
171 __adf_nbuf_pull_head(__adf_nbuf_t buf, adf_os_size_t len)
173 a_uint8_t *ptr = NULL;
174 VDESC *desc = buf->desc_list;
176 desc->data_offset += len;
177 desc->data_size -= len;
178 buf->buf_length -= len;
179 ptr = desc->buf_addr + desc->data_offset;
184 * @brief strip data from tail, priv safe
187 * @param len (how much to strip down)
191 __adf_nbuf_trim_tail(__adf_nbuf_t buf, adf_os_size_t len)
193 VDESC *last_desc = __adf_nbuf_last(buf);
195 adf_os_assert(buf != NULL);
196 last_desc->data_size -= len;
197 buf->buf_length -= len;
199 //adf_os_assert(0); //0820
202 * @brief Copy assumes that we create a writeable copy of the
203 * nbuf which is equivalent in FreeBSD as duping the
208 * @return struct mbuf * (newly allocated buffer)
211 __adf_nbuf_copy(__adf_nbuf_t src)
213 __adf_nbuf_t buf = NULL;
215 adf_os_assert(src != NULL);
220 * @brief make the writable copy of the nbuf
227 __adf_nbuf_unshare(__adf_nbuf_t src)
229 __adf_nbuf_t buf = NULL;
231 adf_os_assert(src != NULL);
237 * @brief return the frag data & len, where frag no. is
238 * specified by the index
241 * @param[out] sg (scatter/gather list of all the frags)
245 __adf_nbuf_frag_info(__adf_nbuf_t buf, adf_os_sglist_t *sg)
247 VDESC *desc = buf->desc_list;
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;
255 desc = desc->next_desc;
261 * @brief retrieve the priv space pointer from nbuf
263 * @param buf (nbuf to attach the priv space)
265 * @return uint8_t* ( pointer to the data )
268 __adf_nbuf_get_priv(__adf_nbuf_t buf)
270 adf_os_assert(buf != NULL);
277 * @brief append the nbuf to the queue
284 __adf_nbuf_queue_add(__adf_nbuf_qhead_t *qhead,
289 buf->next_buf = NULL;
291 if (qhead->head == NULL) {
295 qhead->tail->next_buf = buf;
301 * @brief dequeue an nbuf
308 __adf_nbuf_queue_remove(__adf_nbuf_qhead_t *qhead)
310 __adf_nbuf_t b0 = NULL;
315 if ( qhead->head == qhead->tail ) {
319 qhead->head = qhead->head->next_buf;
328 * ****************DMA Routines Start Here*****************
333 * @brief creates a streaming mapping (takes a pre allocated
334 * global tag for 4K mbuf sizes)
343 __adf_nbuf_dmamap_create(__adf_os_device_t osdev, __adf_os_dma_map_t *dmap)
345 a_status_t retval = A_STATUS_OK;
347 (*dmap) = A_ALLOCRAM(sizeof(struct __adf_dma_map));
349 return A_STATUS_ENOMEM;
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)
366 __adf_nbuf_unmap(__adf_os_device_t osdev, __adf_os_dma_map_t bmap,
367 adf_os_dma_dir_t dir)
375 __adf_nbuf_dmamap_destroy(__adf_os_device_t osdev,
376 __adf_os_dma_map_t dmap)
380 // Should not be called in FW!
381 //return A_STATUS_OK;
387 * @brief return the dma map info
390 * @param[out] sg (map_info ptr)
393 __adf_nbuf_dmamap_info(__adf_os_dma_map_t bmap, adf_os_dmamap_info_t *sg)
395 VDESC *desc = bmap->buf->desc_list;
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;
403 desc = desc->next_desc;
410 * **************************Misc routines***************
415 * @brief sets the cksum type & value for nbuf
416 * XXX: not fully implemented
422 __adf_nbuf_set_rx_cksum(__adf_nbuf_t buf, adf_nbuf_rx_cksum_t *cksum)
428 __adf_nbuf_get_vlan_info(adf_net_handle_t hdl, __adf_nbuf_t buf,
429 adf_net_vlanhdr_t *vlan)
435 __adf_nbuf_create_frm_frag(__adf_nbuf_queue_t *qhead)
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;
442 buf_head = VBUF_alloc_vbuf();
443 buf_tmp = __adf_nbuf_queue_first(qhead);
445 __adf_os_assert(buf_head);
446 __adf_os_assert(buf_tmp);
448 buf_head->desc_list = buf_tmp->desc_list;
450 while ((buf_tmp = __adf_nbuf_queue_remove(qhead)) != NULL) {
453 //adf_os_print("merge buf: %x\n", buf_tmp->desc_list->buf_addr + buf_tmp->desc_list->data_offset);
455 total_len += buf_tmp->buf_length;
458 /* link "the last VDESC of previous VBUF" to "the 1st VDESC of this VBUF" */
459 vdesc_prev->next_desc = buf_tmp->desc_list;
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;
467 vdesc_prev = vdesc_tmp;
469 /* return VBUF to the pool */
470 buf_tmp->desc_list = NULL;
471 buf_tmp->buf_length = 0;
472 VBUF_free_vbuf(buf_tmp);
476 //adf_os_print("cnt: %x, len: %x, __adf_nbuf_queue_len: %x\n", cnt, len,
477 // __adf_nbuf_queue_len(qhead));
480 //__adf_os_assert(cnt == len);
482 buf_head->buf_length = total_len;
488 __adf_nbuf_split_to_frag(__adf_nbuf_t buf, __adf_nbuf_qhead_t *qhead)
491 VDESC *desc_tmp = NULL;
493 __adf_nbuf_queue_init(qhead);
494 desc_tmp = buf->desc_list;
496 while (desc_tmp /*&& desc_tmp->buf_addr*/) {
497 buf_tmp = VBUF_alloc_vbuf();
499 __adf_os_assert(buf_tmp);
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;
507 //adf_os_print("split - buf: %x\n", buf_tmp->desc_list->buf_addr + buf_tmp->desc_list->data_offset);
509 __adf_nbuf_queue_add(qhead, buf_tmp);
511 desc_tmp = desc_tmp->next_desc;
513 buf_tmp->desc_list->next_desc = NULL;
516 buf->desc_list = NULL;
523 * @brief return the last mbuf
527 * @return struct mbuf*
530 __adf_nbuf_last(VBUF *buf)
532 VDESC *desc = buf->desc_list;
534 //for(; desc->next_desc != NULL; desc = desc->next_desc)
536 while(desc->next_desc != NULL)
538 desc = desc->next_desc;
545 * @brief num bytes in the head
549 * @return num of bytes available
552 __adf_nbuf_headroom(__adf_nbuf_t buf)
554 return buf->desc_list->data_offset;
559 * @brief num of bytes available in the tail excluding the priv
564 * @return num of bytes
568 __adf_nbuf_tailroom(__adf_nbuf_t buf)
570 VDESC *last_desc = __adf_nbuf_last(buf);
572 return last_desc->buf_size - last_desc->data_offset - last_desc->data_size;
576 * @brief get the entire packet length
580 * @return total length of packet (sum of all frag lengths)
583 __adf_nbuf_len(__adf_nbuf_t buf)
585 return buf->buf_length;
589 * @brief Clone the nbuf (will not create writeable copies)
593 * @return Read-only copy of the nbuf (including clusters)
596 __adf_nbuf_clone(__adf_nbuf_t src)
598 __adf_nbuf_t buf = NULL;
604 __adf_nbuf_cat(__adf_nbuf_t dst, __adf_nbuf_t src)
612 * @brief check if the mbuf is cloned or not
619 __adf_nbuf_is_cloned(__adf_nbuf_t buf)
624 * @brief This will return the header's addr & m_len
627 __adf_nbuf_peek_header(__adf_nbuf_t buf, a_uint8_t **addr,
630 VDESC *desc = buf->desc_list;
632 *addr = desc->buf_addr + desc->data_offset;
633 *len = desc->data_size;
636 * @brief init the queue
640 __adf_nbuf_queue_init(__adf_nbuf_qhead_t *qhead)
647 * @brief return the length of queue
654 __adf_nbuf_queue_len(__adf_nbuf_qhead_t *qhead)
659 * @brief returns the first guy in the Q
662 * @return (NULL if the Q is empty)
665 __adf_nbuf_queue_first(__adf_nbuf_queue_t *qhead)
670 * @brief return the next packet from packet chain
672 * @param buf (packet)
674 * @return (NULL if no packets are there)
677 __adf_nbuf_queue_next(__adf_nbuf_t buf)
679 return buf->next_buf;
682 * @brief check if the queue is empty or not
689 __adf_nbuf_is_queue_empty(__adf_nbuf_qhead_t *qhead)
691 return ((qhead->qlen == 0));