xref: /onnv-gate/usr/src/uts/common/io/igb/igb_buf.c (revision 12980:c2b4f6c2d38a)
15779Sxy150489 /*
25779Sxy150489  * CDDL HEADER START
35779Sxy150489  *
45779Sxy150489  * The contents of this file are subject to the terms of the
55779Sxy150489  * Common Development and Distribution License (the "License").
65779Sxy150489  * You may not use this file except in compliance with the License.
75779Sxy150489  *
8*12980SGuoqing.Zhu@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12980SGuoqing.Zhu@Sun.COM  * or http://www.opensolaris.org/os/licensing.
105779Sxy150489  * See the License for the specific language governing permissions
115779Sxy150489  * and limitations under the License.
125779Sxy150489  *
13*12980SGuoqing.Zhu@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*12980SGuoqing.Zhu@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155779Sxy150489  * If applicable, add the following below this CDDL HEADER, with the
165779Sxy150489  * fields enclosed by brackets "[]" replaced with your own identifying
175779Sxy150489  * information: Portions Copyright [yyyy] [name of copyright owner]
185779Sxy150489  *
195779Sxy150489  * CDDL HEADER END
205779Sxy150489  */
215779Sxy150489 
225779Sxy150489 /*
23*12980SGuoqing.Zhu@Sun.COM  * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
24*12980SGuoqing.Zhu@Sun.COM  */
25*12980SGuoqing.Zhu@Sun.COM 
26*12980SGuoqing.Zhu@Sun.COM /*
27*12980SGuoqing.Zhu@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
285779Sxy150489  */
295779Sxy150489 
305779Sxy150489 #include "igb_sw.h"
315779Sxy150489 
325779Sxy150489 static int igb_alloc_tbd_ring(igb_tx_ring_t *);
335779Sxy150489 static void igb_free_tbd_ring(igb_tx_ring_t *);
3411502SChenlu.Chen@Sun.COM static int igb_alloc_rbd_ring(igb_rx_data_t *);
3511502SChenlu.Chen@Sun.COM static void igb_free_rbd_ring(igb_rx_data_t *);
365779Sxy150489 static int igb_alloc_dma_buffer(igb_t *, dma_buffer_t *, size_t);
375779Sxy150489 static int igb_alloc_tcb_lists(igb_tx_ring_t *);
385779Sxy150489 static void igb_free_tcb_lists(igb_tx_ring_t *);
3911502SChenlu.Chen@Sun.COM static int igb_alloc_rcb_lists(igb_rx_data_t *);
4011502SChenlu.Chen@Sun.COM static void igb_free_rcb_lists(igb_rx_data_t *);
415779Sxy150489 
425779Sxy150489 #ifdef __sparc
435779Sxy150489 #define	IGB_DMA_ALIGNMENT	0x0000000000002000ull
445779Sxy150489 #else
455779Sxy150489 #define	IGB_DMA_ALIGNMENT	0x0000000000001000ull
465779Sxy150489 #endif
475779Sxy150489 
485779Sxy150489 /*
495779Sxy150489  * DMA attributes for tx/rx descriptors
505779Sxy150489  */
515779Sxy150489 static ddi_dma_attr_t igb_desc_dma_attr = {
525779Sxy150489 	DMA_ATTR_V0,			/* version number */
535779Sxy150489 	0x0000000000000000ull,		/* low address */
545779Sxy150489 	0xFFFFFFFFFFFFFFFFull,		/* high address */
555779Sxy150489 	0x00000000FFFFFFFFull,		/* dma counter max */
565779Sxy150489 	IGB_DMA_ALIGNMENT,		/* alignment */
575779Sxy150489 	0x00000FFF,			/* burst sizes */
585779Sxy150489 	0x00000001,			/* minimum transfer size */
595779Sxy150489 	0x00000000FFFFFFFFull,		/* maximum transfer size */
605779Sxy150489 	0xFFFFFFFFFFFFFFFFull,		/* maximum segment size */
615779Sxy150489 	1,				/* scatter/gather list length */
625779Sxy150489 	0x00000001,			/* granularity */
636624Sgl147354 	DDI_DMA_FLAGERR,		/* DMA flags */
645779Sxy150489 };
655779Sxy150489 
665779Sxy150489 /*
675779Sxy150489  * DMA attributes for tx/rx buffers
685779Sxy150489  */
695779Sxy150489 static ddi_dma_attr_t igb_buf_dma_attr = {
705779Sxy150489 	DMA_ATTR_V0,			/* version number */
715779Sxy150489 	0x0000000000000000ull,		/* low address */
725779Sxy150489 	0xFFFFFFFFFFFFFFFFull,		/* high address */
735779Sxy150489 	0x00000000FFFFFFFFull,		/* dma counter max */
745779Sxy150489 	IGB_DMA_ALIGNMENT,		/* alignment */
755779Sxy150489 	0x00000FFF,			/* burst sizes */
765779Sxy150489 	0x00000001,			/* minimum transfer size */
775779Sxy150489 	0x00000000FFFFFFFFull,		/* maximum transfer size */
785779Sxy150489 	0xFFFFFFFFFFFFFFFFull,		/* maximum segment size	 */
795779Sxy150489 	1,				/* scatter/gather list length */
805779Sxy150489 	0x00000001,			/* granularity */
816624Sgl147354 	DDI_DMA_FLAGERR,		/* DMA flags */
825779Sxy150489 };
835779Sxy150489 
845779Sxy150489 /*
855779Sxy150489  * DMA attributes for transmit
865779Sxy150489  */
875779Sxy150489 static ddi_dma_attr_t igb_tx_dma_attr = {
885779Sxy150489 	DMA_ATTR_V0,			/* version number */
895779Sxy150489 	0x0000000000000000ull,		/* low address */
905779Sxy150489 	0xFFFFFFFFFFFFFFFFull,		/* high address */
915779Sxy150489 	0x00000000FFFFFFFFull,		/* dma counter max */
925779Sxy150489 	1,				/* alignment */
935779Sxy150489 	0x00000FFF,			/* burst sizes */
945779Sxy150489 	0x00000001,			/* minimum transfer size */
955779Sxy150489 	0x00000000FFFFFFFFull,		/* maximum transfer size */
965779Sxy150489 	0xFFFFFFFFFFFFFFFFull,		/* maximum segment size	 */
975779Sxy150489 	MAX_COOKIE,			/* scatter/gather list length */
985779Sxy150489 	0x00000001,			/* granularity */
996624Sgl147354 	DDI_DMA_FLAGERR,		/* DMA flags */
1005779Sxy150489 };
1015779Sxy150489 
1025779Sxy150489 /*
1035779Sxy150489  * DMA access attributes for descriptors.
1045779Sxy150489  */
1055779Sxy150489 static ddi_device_acc_attr_t igb_desc_acc_attr = {
1065779Sxy150489 	DDI_DEVICE_ATTR_V0,
1075779Sxy150489 	DDI_STRUCTURE_LE_ACC,
10811236SStephen.Hanson@Sun.COM 	DDI_STRICTORDER_ACC
1095779Sxy150489 };
1105779Sxy150489 
1115779Sxy150489 /*
1125779Sxy150489  * DMA access attributes for buffers.
1135779Sxy150489  */
1145779Sxy150489 static ddi_device_acc_attr_t igb_buf_acc_attr = {
1155779Sxy150489 	DDI_DEVICE_ATTR_V0,
1165779Sxy150489 	DDI_NEVERSWAP_ACC,
1175779Sxy150489 	DDI_STRICTORDER_ACC
1185779Sxy150489 };
1195779Sxy150489 
1205779Sxy150489 
1215779Sxy150489 /*
1225779Sxy150489  * igb_alloc_dma - Allocate DMA resources for all rx/tx rings
1235779Sxy150489  */
1245779Sxy150489 int
igb_alloc_dma(igb_t * igb)1255779Sxy150489 igb_alloc_dma(igb_t *igb)
1265779Sxy150489 {
1275779Sxy150489 	igb_rx_ring_t *rx_ring;
12811502SChenlu.Chen@Sun.COM 	igb_rx_data_t *rx_data;
1295779Sxy150489 	igb_tx_ring_t *tx_ring;
1305779Sxy150489 	int i;
1315779Sxy150489 
1325779Sxy150489 	for (i = 0; i < igb->num_rx_rings; i++) {
1335779Sxy150489 		/*
1345779Sxy150489 		 * Allocate receive desciptor ring and control block lists
1355779Sxy150489 		 */
1365779Sxy150489 		rx_ring = &igb->rx_rings[i];
13711502SChenlu.Chen@Sun.COM 		rx_data = rx_ring->rx_data;
1385779Sxy150489 
13911502SChenlu.Chen@Sun.COM 		if (igb_alloc_rbd_ring(rx_data) != IGB_SUCCESS)
1405779Sxy150489 			goto alloc_dma_failure;
1415779Sxy150489 
14211502SChenlu.Chen@Sun.COM 		if (igb_alloc_rcb_lists(rx_data) != IGB_SUCCESS)
1435779Sxy150489 			goto alloc_dma_failure;
1445779Sxy150489 	}
1455779Sxy150489 
1465779Sxy150489 	for (i = 0; i < igb->num_tx_rings; i++) {
1475779Sxy150489 		/*
1485779Sxy150489 		 * Allocate transmit desciptor ring and control block lists
1495779Sxy150489 		 */
1505779Sxy150489 		tx_ring = &igb->tx_rings[i];
1515779Sxy150489 
1525779Sxy150489 		if (igb_alloc_tbd_ring(tx_ring) != IGB_SUCCESS)
1535779Sxy150489 			goto alloc_dma_failure;
1545779Sxy150489 
1555779Sxy150489 		if (igb_alloc_tcb_lists(tx_ring) != IGB_SUCCESS)
1565779Sxy150489 			goto alloc_dma_failure;
1575779Sxy150489 	}
1585779Sxy150489 
1595779Sxy150489 	return (IGB_SUCCESS);
1605779Sxy150489 
1615779Sxy150489 alloc_dma_failure:
1625779Sxy150489 	igb_free_dma(igb);
1635779Sxy150489 
1645779Sxy150489 	return (IGB_FAILURE);
1655779Sxy150489 }
1665779Sxy150489 
1675779Sxy150489 
1685779Sxy150489 /*
1695779Sxy150489  * igb_free_dma - Free all the DMA resources of all rx/tx rings
1705779Sxy150489  */
1715779Sxy150489 void
igb_free_dma(igb_t * igb)1725779Sxy150489 igb_free_dma(igb_t *igb)
1735779Sxy150489 {
1745779Sxy150489 	igb_rx_ring_t *rx_ring;
17511502SChenlu.Chen@Sun.COM 	igb_rx_data_t *rx_data;
1765779Sxy150489 	igb_tx_ring_t *tx_ring;
1775779Sxy150489 	int i;
1785779Sxy150489 
1795779Sxy150489 	/*
1805779Sxy150489 	 * Free DMA resources of rx rings
1815779Sxy150489 	 */
1825779Sxy150489 	for (i = 0; i < igb->num_rx_rings; i++) {
1835779Sxy150489 		rx_ring = &igb->rx_rings[i];
18411502SChenlu.Chen@Sun.COM 		rx_data = rx_ring->rx_data;
18511502SChenlu.Chen@Sun.COM 
18611502SChenlu.Chen@Sun.COM 		igb_free_rbd_ring(rx_data);
18711502SChenlu.Chen@Sun.COM 		igb_free_rcb_lists(rx_data);
1885779Sxy150489 	}
1895779Sxy150489 
1905779Sxy150489 	/*
1915779Sxy150489 	 * Free DMA resources of tx rings
1925779Sxy150489 	 */
1935779Sxy150489 	for (i = 0; i < igb->num_tx_rings; i++) {
1945779Sxy150489 		tx_ring = &igb->tx_rings[i];
1955779Sxy150489 		igb_free_tbd_ring(tx_ring);
1965779Sxy150489 		igb_free_tcb_lists(tx_ring);
1975779Sxy150489 	}
1985779Sxy150489 }
1995779Sxy150489 
2005779Sxy150489 /*
2015779Sxy150489  * igb_alloc_tbd_ring - Memory allocation for the tx descriptors of one ring.
2025779Sxy150489  */
2035779Sxy150489 static int
igb_alloc_tbd_ring(igb_tx_ring_t * tx_ring)2045779Sxy150489 igb_alloc_tbd_ring(igb_tx_ring_t *tx_ring)
2055779Sxy150489 {
2065779Sxy150489 	int ret;
2075779Sxy150489 	size_t size;
2085779Sxy150489 	size_t len;
2095779Sxy150489 	uint_t cookie_num;
2105779Sxy150489 	dev_info_t *devinfo;
2115779Sxy150489 	ddi_dma_cookie_t cookie;
2125779Sxy150489 	igb_t *igb = tx_ring->igb;
2135779Sxy150489 
2145779Sxy150489 	devinfo = igb->dip;
2155779Sxy150489 	size = sizeof (union e1000_adv_tx_desc) * tx_ring->ring_size;
2165779Sxy150489 
2175779Sxy150489 	/*
2185779Sxy150489 	 * If tx head write-back is enabled, an extra tbd is allocated
2195779Sxy150489 	 * to save the head write-back value
2205779Sxy150489 	 */
2215779Sxy150489 	if (igb->tx_head_wb_enable) {
2225779Sxy150489 		size += sizeof (union e1000_adv_tx_desc);
2235779Sxy150489 	}
2245779Sxy150489 
2255779Sxy150489 	/*
2265779Sxy150489 	 * Allocate a DMA handle for the transmit descriptor
2275779Sxy150489 	 * memory area.
2285779Sxy150489 	 */
2295779Sxy150489 	ret = ddi_dma_alloc_handle(devinfo, &igb_desc_dma_attr,
2305779Sxy150489 	    DDI_DMA_DONTWAIT, NULL,
2315779Sxy150489 	    &tx_ring->tbd_area.dma_handle);
2325779Sxy150489 
2335779Sxy150489 	if (ret != DDI_SUCCESS) {
2345779Sxy150489 		igb_error(igb,
2355779Sxy150489 		    "Could not allocate tbd dma handle: %x", ret);
2365779Sxy150489 		tx_ring->tbd_area.dma_handle = NULL;
2375779Sxy150489 
2385779Sxy150489 		return (IGB_FAILURE);
2395779Sxy150489 	}
2405779Sxy150489 
2415779Sxy150489 	/*
2425779Sxy150489 	 * Allocate memory to DMA data to and from the transmit
2435779Sxy150489 	 * descriptors.
2445779Sxy150489 	 */
2455779Sxy150489 	ret = ddi_dma_mem_alloc(tx_ring->tbd_area.dma_handle,
2465779Sxy150489 	    size, &igb_desc_acc_attr, DDI_DMA_CONSISTENT,
2475779Sxy150489 	    DDI_DMA_DONTWAIT, NULL,
2485779Sxy150489 	    (caddr_t *)&tx_ring->tbd_area.address,
2495779Sxy150489 	    &len, &tx_ring->tbd_area.acc_handle);
2505779Sxy150489 
2515779Sxy150489 	if (ret != DDI_SUCCESS) {
2525779Sxy150489 		igb_error(igb,
2535779Sxy150489 		    "Could not allocate tbd dma memory: %x", ret);
2545779Sxy150489 		tx_ring->tbd_area.acc_handle = NULL;
2555779Sxy150489 		tx_ring->tbd_area.address = NULL;
2565779Sxy150489 		if (tx_ring->tbd_area.dma_handle != NULL) {
2575779Sxy150489 			ddi_dma_free_handle(&tx_ring->tbd_area.dma_handle);
2585779Sxy150489 			tx_ring->tbd_area.dma_handle = NULL;
2595779Sxy150489 		}
2605779Sxy150489 		return (IGB_FAILURE);
2615779Sxy150489 	}
2625779Sxy150489 
2635779Sxy150489 	/*
2645779Sxy150489 	 * Initialize the entire transmit buffer descriptor area to zero
2655779Sxy150489 	 */
2665779Sxy150489 	bzero(tx_ring->tbd_area.address, len);
2675779Sxy150489 
2685779Sxy150489 	/*
2695779Sxy150489 	 * Allocates DMA resources for the memory that was allocated by
2705779Sxy150489 	 * the ddi_dma_mem_alloc call. The DMA resources then get bound to the
2715779Sxy150489 	 * the memory address
2725779Sxy150489 	 */
2735779Sxy150489 	ret = ddi_dma_addr_bind_handle(tx_ring->tbd_area.dma_handle,
2745779Sxy150489 	    NULL, (caddr_t)tx_ring->tbd_area.address,
2755779Sxy150489 	    len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2765779Sxy150489 	    DDI_DMA_DONTWAIT, NULL, &cookie, &cookie_num);
2775779Sxy150489 
2785779Sxy150489 	if (ret != DDI_DMA_MAPPED) {
2795779Sxy150489 		igb_error(igb,
2805779Sxy150489 		    "Could not bind tbd dma resource: %x", ret);
2815779Sxy150489 		tx_ring->tbd_area.dma_address = NULL;
2825779Sxy150489 		if (tx_ring->tbd_area.acc_handle != NULL) {
2835779Sxy150489 			ddi_dma_mem_free(&tx_ring->tbd_area.acc_handle);
2845779Sxy150489 			tx_ring->tbd_area.acc_handle = NULL;
2855779Sxy150489 			tx_ring->tbd_area.address = NULL;
2865779Sxy150489 		}
2875779Sxy150489 		if (tx_ring->tbd_area.dma_handle != NULL) {
2885779Sxy150489 			ddi_dma_free_handle(&tx_ring->tbd_area.dma_handle);
2895779Sxy150489 			tx_ring->tbd_area.dma_handle = NULL;
2905779Sxy150489 		}
2915779Sxy150489 		return (IGB_FAILURE);
2925779Sxy150489 	}
2935779Sxy150489 
2945779Sxy150489 	ASSERT(cookie_num == 1);
2955779Sxy150489 
2965779Sxy150489 	tx_ring->tbd_area.dma_address = cookie.dmac_laddress;
2975779Sxy150489 	tx_ring->tbd_area.size = len;
2985779Sxy150489 
2995779Sxy150489 	tx_ring->tbd_ring = (union e1000_adv_tx_desc *)(uintptr_t)
3005779Sxy150489 	    tx_ring->tbd_area.address;
3015779Sxy150489 
3025779Sxy150489 	return (IGB_SUCCESS);
3035779Sxy150489 }
3045779Sxy150489 
3055779Sxy150489 /*
3065779Sxy150489  * igb_free_tbd_ring - Free the tx descriptors of one ring.
3075779Sxy150489  */
3085779Sxy150489 static void
igb_free_tbd_ring(igb_tx_ring_t * tx_ring)3095779Sxy150489 igb_free_tbd_ring(igb_tx_ring_t *tx_ring)
3105779Sxy150489 {
3115779Sxy150489 	if (tx_ring->tbd_area.dma_handle != NULL) {
3125779Sxy150489 		(void) ddi_dma_unbind_handle(tx_ring->tbd_area.dma_handle);
3135779Sxy150489 	}
3145779Sxy150489 	if (tx_ring->tbd_area.acc_handle != NULL) {
3155779Sxy150489 		ddi_dma_mem_free(&tx_ring->tbd_area.acc_handle);
3165779Sxy150489 		tx_ring->tbd_area.acc_handle = NULL;
3175779Sxy150489 	}
3185779Sxy150489 	if (tx_ring->tbd_area.dma_handle != NULL) {
3195779Sxy150489 		ddi_dma_free_handle(&tx_ring->tbd_area.dma_handle);
3205779Sxy150489 		tx_ring->tbd_area.dma_handle = NULL;
3215779Sxy150489 	}
3225779Sxy150489 	tx_ring->tbd_area.address = NULL;
3235779Sxy150489 	tx_ring->tbd_area.dma_address = NULL;
3245779Sxy150489 	tx_ring->tbd_area.size = 0;
3255779Sxy150489 
3265779Sxy150489 	tx_ring->tbd_ring = NULL;
3275779Sxy150489 }
3285779Sxy150489 
32911502SChenlu.Chen@Sun.COM int
igb_alloc_rx_ring_data(igb_rx_ring_t * rx_ring)33011502SChenlu.Chen@Sun.COM igb_alloc_rx_ring_data(igb_rx_ring_t *rx_ring)
33111502SChenlu.Chen@Sun.COM {
33211502SChenlu.Chen@Sun.COM 	igb_rx_data_t *rx_data;
33311502SChenlu.Chen@Sun.COM 	igb_t *igb = rx_ring->igb;
33411502SChenlu.Chen@Sun.COM 	uint32_t rcb_count;
33511502SChenlu.Chen@Sun.COM 
33611502SChenlu.Chen@Sun.COM 	/*
33711502SChenlu.Chen@Sun.COM 	 * Allocate memory for software receive rings
33811502SChenlu.Chen@Sun.COM 	 */
33911502SChenlu.Chen@Sun.COM 	rx_data = kmem_zalloc(sizeof (igb_rx_data_t), KM_NOSLEEP);
34011502SChenlu.Chen@Sun.COM 
34111502SChenlu.Chen@Sun.COM 	if (rx_data == NULL) {
34211502SChenlu.Chen@Sun.COM 		igb_error(igb, "Allocate software receive rings failed");
34311502SChenlu.Chen@Sun.COM 		return (IGB_FAILURE);
34411502SChenlu.Chen@Sun.COM 	}
34511502SChenlu.Chen@Sun.COM 
34611502SChenlu.Chen@Sun.COM 	rx_data->rx_ring = rx_ring;
34711502SChenlu.Chen@Sun.COM 	mutex_init(&rx_data->recycle_lock, NULL,
34811502SChenlu.Chen@Sun.COM 	    MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
34911502SChenlu.Chen@Sun.COM 
35011502SChenlu.Chen@Sun.COM 	rx_data->ring_size = igb->rx_ring_size;
35111502SChenlu.Chen@Sun.COM 	rx_data->free_list_size = igb->rx_ring_size;
35211502SChenlu.Chen@Sun.COM 
35311502SChenlu.Chen@Sun.COM 	rx_data->rcb_head = 0;
35411502SChenlu.Chen@Sun.COM 	rx_data->rcb_tail = 0;
35511502SChenlu.Chen@Sun.COM 	rx_data->rcb_free = rx_data->free_list_size;
35611502SChenlu.Chen@Sun.COM 
35711502SChenlu.Chen@Sun.COM 	/*
35811502SChenlu.Chen@Sun.COM 	 * Allocate memory for the work list.
35911502SChenlu.Chen@Sun.COM 	 */
36011502SChenlu.Chen@Sun.COM 	rx_data->work_list = kmem_zalloc(sizeof (rx_control_block_t *) *
36111502SChenlu.Chen@Sun.COM 	    rx_data->ring_size, KM_NOSLEEP);
36211502SChenlu.Chen@Sun.COM 
36311502SChenlu.Chen@Sun.COM 	if (rx_data->work_list == NULL) {
36411502SChenlu.Chen@Sun.COM 		igb_error(igb,
36511502SChenlu.Chen@Sun.COM 		    "Could not allocate memory for rx work list");
36611502SChenlu.Chen@Sun.COM 		goto alloc_rx_data_failure;
36711502SChenlu.Chen@Sun.COM 	}
36811502SChenlu.Chen@Sun.COM 
36911502SChenlu.Chen@Sun.COM 	/*
37011502SChenlu.Chen@Sun.COM 	 * Allocate memory for the free list.
37111502SChenlu.Chen@Sun.COM 	 */
37211502SChenlu.Chen@Sun.COM 	rx_data->free_list = kmem_zalloc(sizeof (rx_control_block_t *) *
37311502SChenlu.Chen@Sun.COM 	    rx_data->free_list_size, KM_NOSLEEP);
37411502SChenlu.Chen@Sun.COM 
37511502SChenlu.Chen@Sun.COM 	if (rx_data->free_list == NULL) {
37611502SChenlu.Chen@Sun.COM 		igb_error(igb,
37711502SChenlu.Chen@Sun.COM 		    "Cound not allocate memory for rx free list");
37811502SChenlu.Chen@Sun.COM 		goto alloc_rx_data_failure;
37911502SChenlu.Chen@Sun.COM 	}
38011502SChenlu.Chen@Sun.COM 
38111502SChenlu.Chen@Sun.COM 	/*
38211502SChenlu.Chen@Sun.COM 	 * Allocate memory for the rx control blocks for work list and
38311502SChenlu.Chen@Sun.COM 	 * free list.
38411502SChenlu.Chen@Sun.COM 	 */
38511502SChenlu.Chen@Sun.COM 	rcb_count = rx_data->ring_size + rx_data->free_list_size;
38611502SChenlu.Chen@Sun.COM 	rx_data->rcb_area =
38711502SChenlu.Chen@Sun.COM 	    kmem_zalloc(sizeof (rx_control_block_t) * rcb_count,
38811502SChenlu.Chen@Sun.COM 	    KM_NOSLEEP);
38911502SChenlu.Chen@Sun.COM 
39011502SChenlu.Chen@Sun.COM 	if (rx_data->rcb_area == NULL) {
39111502SChenlu.Chen@Sun.COM 		igb_error(igb,
39211502SChenlu.Chen@Sun.COM 		    "Cound not allocate memory for rx control blocks");
39311502SChenlu.Chen@Sun.COM 		goto alloc_rx_data_failure;
39411502SChenlu.Chen@Sun.COM 	}
39511502SChenlu.Chen@Sun.COM 
39611502SChenlu.Chen@Sun.COM 	rx_ring->rx_data = rx_data;
39711502SChenlu.Chen@Sun.COM 	return (IGB_SUCCESS);
39811502SChenlu.Chen@Sun.COM 
39911502SChenlu.Chen@Sun.COM alloc_rx_data_failure:
40011502SChenlu.Chen@Sun.COM 	igb_free_rx_ring_data(rx_data);
40111502SChenlu.Chen@Sun.COM 	return (IGB_FAILURE);
40211502SChenlu.Chen@Sun.COM }
40311502SChenlu.Chen@Sun.COM 
40411502SChenlu.Chen@Sun.COM void
igb_free_rx_ring_data(igb_rx_data_t * rx_data)40511502SChenlu.Chen@Sun.COM igb_free_rx_ring_data(igb_rx_data_t *rx_data)
40611502SChenlu.Chen@Sun.COM {
40711502SChenlu.Chen@Sun.COM 	uint32_t rcb_count;
40811502SChenlu.Chen@Sun.COM 
40911502SChenlu.Chen@Sun.COM 	if (rx_data == NULL)
41011502SChenlu.Chen@Sun.COM 		return;
41111502SChenlu.Chen@Sun.COM 
41211502SChenlu.Chen@Sun.COM 	ASSERT(rx_data->rcb_pending == 0);
41311502SChenlu.Chen@Sun.COM 
41411502SChenlu.Chen@Sun.COM 	rcb_count = rx_data->ring_size + rx_data->free_list_size;
41511502SChenlu.Chen@Sun.COM 	if (rx_data->rcb_area != NULL) {
41611502SChenlu.Chen@Sun.COM 		kmem_free(rx_data->rcb_area,
41711502SChenlu.Chen@Sun.COM 		    sizeof (rx_control_block_t) * rcb_count);
41811502SChenlu.Chen@Sun.COM 		rx_data->rcb_area = NULL;
41911502SChenlu.Chen@Sun.COM 	}
42011502SChenlu.Chen@Sun.COM 
42111502SChenlu.Chen@Sun.COM 	if (rx_data->work_list != NULL) {
42211502SChenlu.Chen@Sun.COM 		kmem_free(rx_data->work_list,
42311502SChenlu.Chen@Sun.COM 		    sizeof (rx_control_block_t *) * rx_data->ring_size);
42411502SChenlu.Chen@Sun.COM 		rx_data->work_list = NULL;
42511502SChenlu.Chen@Sun.COM 	}
42611502SChenlu.Chen@Sun.COM 
42711502SChenlu.Chen@Sun.COM 	if (rx_data->free_list != NULL) {
42811502SChenlu.Chen@Sun.COM 		kmem_free(rx_data->free_list,
42911502SChenlu.Chen@Sun.COM 		    sizeof (rx_control_block_t *) * rx_data->free_list_size);
43011502SChenlu.Chen@Sun.COM 		rx_data->free_list = NULL;
43111502SChenlu.Chen@Sun.COM 	}
43211502SChenlu.Chen@Sun.COM 
43311502SChenlu.Chen@Sun.COM 	mutex_destroy(&rx_data->recycle_lock);
43411502SChenlu.Chen@Sun.COM 	kmem_free(rx_data, sizeof (igb_rx_data_t));
43511502SChenlu.Chen@Sun.COM }
43611502SChenlu.Chen@Sun.COM 
4375779Sxy150489 /*
4385779Sxy150489  * igb_alloc_rbd_ring - Memory allocation for the rx descriptors of one ring.
4395779Sxy150489  */
4405779Sxy150489 static int
igb_alloc_rbd_ring(igb_rx_data_t * rx_data)44111502SChenlu.Chen@Sun.COM igb_alloc_rbd_ring(igb_rx_data_t *rx_data)
4425779Sxy150489 {
4435779Sxy150489 	int ret;
4445779Sxy150489 	size_t size;
4455779Sxy150489 	size_t len;
4465779Sxy150489 	uint_t cookie_num;
4475779Sxy150489 	dev_info_t *devinfo;
4485779Sxy150489 	ddi_dma_cookie_t cookie;
44911502SChenlu.Chen@Sun.COM 	igb_t *igb = rx_data->rx_ring->igb;
4505779Sxy150489 
4515779Sxy150489 	devinfo = igb->dip;
45211502SChenlu.Chen@Sun.COM 	size = sizeof (union e1000_adv_rx_desc) * rx_data->ring_size;
4535779Sxy150489 
4545779Sxy150489 	/*
4555779Sxy150489 	 * Allocate a new DMA handle for the receive descriptor
4565779Sxy150489 	 * memory area.
4575779Sxy150489 	 */
4585779Sxy150489 	ret = ddi_dma_alloc_handle(devinfo, &igb_desc_dma_attr,
4595779Sxy150489 	    DDI_DMA_DONTWAIT, NULL,
46011502SChenlu.Chen@Sun.COM 	    &rx_data->rbd_area.dma_handle);
4615779Sxy150489 
4625779Sxy150489 	if (ret != DDI_SUCCESS) {
4635779Sxy150489 		igb_error(igb,
4645779Sxy150489 		    "Could not allocate rbd dma handle: %x", ret);
46511502SChenlu.Chen@Sun.COM 		rx_data->rbd_area.dma_handle = NULL;
4665779Sxy150489 		return (IGB_FAILURE);
4675779Sxy150489 	}
4685779Sxy150489 
4695779Sxy150489 	/*
4705779Sxy150489 	 * Allocate memory to DMA data to and from the receive
4715779Sxy150489 	 * descriptors.
4725779Sxy150489 	 */
47311502SChenlu.Chen@Sun.COM 	ret = ddi_dma_mem_alloc(rx_data->rbd_area.dma_handle,
4745779Sxy150489 	    size, &igb_desc_acc_attr, DDI_DMA_CONSISTENT,
4755779Sxy150489 	    DDI_DMA_DONTWAIT, NULL,
47611502SChenlu.Chen@Sun.COM 	    (caddr_t *)&rx_data->rbd_area.address,
47711502SChenlu.Chen@Sun.COM 	    &len, &rx_data->rbd_area.acc_handle);
4785779Sxy150489 
4795779Sxy150489 	if (ret != DDI_SUCCESS) {
4805779Sxy150489 		igb_error(igb,
4815779Sxy150489 		    "Could not allocate rbd dma memory: %x", ret);
48211502SChenlu.Chen@Sun.COM 		rx_data->rbd_area.acc_handle = NULL;
48311502SChenlu.Chen@Sun.COM 		rx_data->rbd_area.address = NULL;
48411502SChenlu.Chen@Sun.COM 		if (rx_data->rbd_area.dma_handle != NULL) {
48511502SChenlu.Chen@Sun.COM 			ddi_dma_free_handle(&rx_data->rbd_area.dma_handle);
48611502SChenlu.Chen@Sun.COM 			rx_data->rbd_area.dma_handle = NULL;
4875779Sxy150489 		}
4885779Sxy150489 		return (IGB_FAILURE);
4895779Sxy150489 	}
4905779Sxy150489 
4915779Sxy150489 	/*
4925779Sxy150489 	 * Initialize the entire transmit buffer descriptor area to zero
4935779Sxy150489 	 */
49411502SChenlu.Chen@Sun.COM 	bzero(rx_data->rbd_area.address, len);
4955779Sxy150489 
4965779Sxy150489 	/*
4975779Sxy150489 	 * Allocates DMA resources for the memory that was allocated by
4985779Sxy150489 	 * the ddi_dma_mem_alloc call.
4995779Sxy150489 	 */
50011502SChenlu.Chen@Sun.COM 	ret = ddi_dma_addr_bind_handle(rx_data->rbd_area.dma_handle,
50111502SChenlu.Chen@Sun.COM 	    NULL, (caddr_t)rx_data->rbd_area.address,
5025779Sxy150489 	    len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
5035779Sxy150489 	    DDI_DMA_DONTWAIT, NULL, &cookie, &cookie_num);
5045779Sxy150489 
5055779Sxy150489 	if (ret != DDI_DMA_MAPPED) {
5065779Sxy150489 		igb_error(igb,
5075779Sxy150489 		    "Could not bind rbd dma resource: %x", ret);
50811502SChenlu.Chen@Sun.COM 		rx_data->rbd_area.dma_address = NULL;
50911502SChenlu.Chen@Sun.COM 		if (rx_data->rbd_area.acc_handle != NULL) {
51011502SChenlu.Chen@Sun.COM 			ddi_dma_mem_free(&rx_data->rbd_area.acc_handle);
51111502SChenlu.Chen@Sun.COM 			rx_data->rbd_area.acc_handle = NULL;
51211502SChenlu.Chen@Sun.COM 			rx_data->rbd_area.address = NULL;
5135779Sxy150489 		}
51411502SChenlu.Chen@Sun.COM 		if (rx_data->rbd_area.dma_handle != NULL) {
51511502SChenlu.Chen@Sun.COM 			ddi_dma_free_handle(&rx_data->rbd_area.dma_handle);
51611502SChenlu.Chen@Sun.COM 			rx_data->rbd_area.dma_handle = NULL;
5175779Sxy150489 		}
5185779Sxy150489 		return (IGB_FAILURE);
5195779Sxy150489 	}
5205779Sxy150489 
5215779Sxy150489 	ASSERT(cookie_num == 1);
5225779Sxy150489 
52311502SChenlu.Chen@Sun.COM 	rx_data->rbd_area.dma_address = cookie.dmac_laddress;
52411502SChenlu.Chen@Sun.COM 	rx_data->rbd_area.size = len;
5255779Sxy150489 
52611502SChenlu.Chen@Sun.COM 	rx_data->rbd_ring = (union e1000_adv_rx_desc *)(uintptr_t)
52711502SChenlu.Chen@Sun.COM 	    rx_data->rbd_area.address;
5285779Sxy150489 
5295779Sxy150489 	return (IGB_SUCCESS);
5305779Sxy150489 }
5315779Sxy150489 
5325779Sxy150489 /*
5335779Sxy150489  * igb_free_rbd_ring - Free the rx descriptors of one ring.
5345779Sxy150489  */
5355779Sxy150489 static void
igb_free_rbd_ring(igb_rx_data_t * rx_data)53611502SChenlu.Chen@Sun.COM igb_free_rbd_ring(igb_rx_data_t *rx_data)
5375779Sxy150489 {
53811502SChenlu.Chen@Sun.COM 	if (rx_data->rbd_area.dma_handle != NULL) {
53911502SChenlu.Chen@Sun.COM 		(void) ddi_dma_unbind_handle(rx_data->rbd_area.dma_handle);
5405779Sxy150489 	}
54111502SChenlu.Chen@Sun.COM 	if (rx_data->rbd_area.acc_handle != NULL) {
54211502SChenlu.Chen@Sun.COM 		ddi_dma_mem_free(&rx_data->rbd_area.acc_handle);
54311502SChenlu.Chen@Sun.COM 		rx_data->rbd_area.acc_handle = NULL;
5445779Sxy150489 	}
54511502SChenlu.Chen@Sun.COM 	if (rx_data->rbd_area.dma_handle != NULL) {
54611502SChenlu.Chen@Sun.COM 		ddi_dma_free_handle(&rx_data->rbd_area.dma_handle);
54711502SChenlu.Chen@Sun.COM 		rx_data->rbd_area.dma_handle = NULL;
5485779Sxy150489 	}
54911502SChenlu.Chen@Sun.COM 	rx_data->rbd_area.address = NULL;
55011502SChenlu.Chen@Sun.COM 	rx_data->rbd_area.dma_address = NULL;
55111502SChenlu.Chen@Sun.COM 	rx_data->rbd_area.size = 0;
5525779Sxy150489 
55311502SChenlu.Chen@Sun.COM 	rx_data->rbd_ring = NULL;
5545779Sxy150489 }
5555779Sxy150489 
5565779Sxy150489 
5575779Sxy150489 /*
5585779Sxy150489  * igb_alloc_dma_buffer - Allocate DMA resources for a DMA buffer
5595779Sxy150489  */
5605779Sxy150489 static int
igb_alloc_dma_buffer(igb_t * igb,dma_buffer_t * buf,size_t size)5615779Sxy150489 igb_alloc_dma_buffer(igb_t *igb,
5625779Sxy150489     dma_buffer_t *buf, size_t size)
5635779Sxy150489 {
5645779Sxy150489 	int ret;
5655779Sxy150489 	dev_info_t *devinfo = igb->dip;
5665779Sxy150489 	ddi_dma_cookie_t cookie;
5675779Sxy150489 	size_t len;
5685779Sxy150489 	uint_t cookie_num;
5695779Sxy150489 
5705779Sxy150489 	ret = ddi_dma_alloc_handle(devinfo,
5715779Sxy150489 	    &igb_buf_dma_attr, DDI_DMA_DONTWAIT,
5725779Sxy150489 	    NULL, &buf->dma_handle);
5735779Sxy150489 
5745779Sxy150489 	if (ret != DDI_SUCCESS) {
5755779Sxy150489 		buf->dma_handle = NULL;
5765779Sxy150489 		igb_error(igb,
5775779Sxy150489 		    "Could not allocate dma buffer handle: %x", ret);
5785779Sxy150489 		return (IGB_FAILURE);
5795779Sxy150489 	}
5805779Sxy150489 
5815779Sxy150489 	ret = ddi_dma_mem_alloc(buf->dma_handle,
5825779Sxy150489 	    size, &igb_buf_acc_attr, DDI_DMA_STREAMING,
5835779Sxy150489 	    DDI_DMA_DONTWAIT, NULL, &buf->address,
5845779Sxy150489 	    &len, &buf->acc_handle);
5855779Sxy150489 
5865779Sxy150489 	if (ret != DDI_SUCCESS) {
5875779Sxy150489 		buf->acc_handle = NULL;
5885779Sxy150489 		buf->address = NULL;
5895779Sxy150489 		if (buf->dma_handle != NULL) {
5905779Sxy150489 			ddi_dma_free_handle(&buf->dma_handle);
5915779Sxy150489 			buf->dma_handle = NULL;
5925779Sxy150489 		}
5935779Sxy150489 		igb_error(igb,
5945779Sxy150489 		    "Could not allocate dma buffer memory: %x", ret);
5955779Sxy150489 		return (IGB_FAILURE);
5965779Sxy150489 	}
5975779Sxy150489 
5985779Sxy150489 	ret = ddi_dma_addr_bind_handle(buf->dma_handle, NULL,
5995779Sxy150489 	    buf->address,
6005779Sxy150489 	    len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
6015779Sxy150489 	    DDI_DMA_DONTWAIT, NULL, &cookie, &cookie_num);
6025779Sxy150489 
6035779Sxy150489 	if (ret != DDI_DMA_MAPPED) {
6045779Sxy150489 		buf->dma_address = NULL;
6055779Sxy150489 		if (buf->acc_handle != NULL) {
6065779Sxy150489 			ddi_dma_mem_free(&buf->acc_handle);
6075779Sxy150489 			buf->acc_handle = NULL;
6085779Sxy150489 			buf->address = NULL;
6095779Sxy150489 		}
6105779Sxy150489 		if (buf->dma_handle != NULL) {
6115779Sxy150489 			ddi_dma_free_handle(&buf->dma_handle);
6125779Sxy150489 			buf->dma_handle = NULL;
6135779Sxy150489 		}
6145779Sxy150489 		igb_error(igb,
6155779Sxy150489 		    "Could not bind dma buffer handle: %x", ret);
6165779Sxy150489 		return (IGB_FAILURE);
6175779Sxy150489 	}
6185779Sxy150489 
6195779Sxy150489 	ASSERT(cookie_num == 1);
6205779Sxy150489 
6215779Sxy150489 	buf->dma_address = cookie.dmac_laddress;
6225779Sxy150489 	buf->size = len;
6235779Sxy150489 	buf->len = 0;
6245779Sxy150489 
6255779Sxy150489 	return (IGB_SUCCESS);
6265779Sxy150489 }
6275779Sxy150489 
6285779Sxy150489 /*
6295779Sxy150489  * igb_free_dma_buffer - Free one allocated area of dma memory and handle
6305779Sxy150489  */
63111502SChenlu.Chen@Sun.COM void
igb_free_dma_buffer(dma_buffer_t * buf)6325779Sxy150489 igb_free_dma_buffer(dma_buffer_t *buf)
6335779Sxy150489 {
6345779Sxy150489 	if (buf->dma_handle != NULL) {
6355779Sxy150489 		(void) ddi_dma_unbind_handle(buf->dma_handle);
6365779Sxy150489 		buf->dma_address = NULL;
6375779Sxy150489 	} else {
6385779Sxy150489 		return;
6395779Sxy150489 	}
6405779Sxy150489 
6415779Sxy150489 	if (buf->acc_handle != NULL) {
6425779Sxy150489 		ddi_dma_mem_free(&buf->acc_handle);
6435779Sxy150489 		buf->acc_handle = NULL;
6445779Sxy150489 		buf->address = NULL;
6455779Sxy150489 	}
6465779Sxy150489 
6475779Sxy150489 	if (buf->dma_handle != NULL) {
6485779Sxy150489 		ddi_dma_free_handle(&buf->dma_handle);
6495779Sxy150489 		buf->dma_handle = NULL;
6505779Sxy150489 	}
6515779Sxy150489 
6525779Sxy150489 	buf->size = 0;
6535779Sxy150489 	buf->len = 0;
6545779Sxy150489 }
6555779Sxy150489 
6565779Sxy150489 /*
6575779Sxy150489  * igb_alloc_tcb_lists - Memory allocation for the transmit control bolcks
6585779Sxy150489  * of one ring.
6595779Sxy150489  */
6605779Sxy150489 static int
igb_alloc_tcb_lists(igb_tx_ring_t * tx_ring)6615779Sxy150489 igb_alloc_tcb_lists(igb_tx_ring_t *tx_ring)
6625779Sxy150489 {
6635779Sxy150489 	int i;
6645779Sxy150489 	int ret;
6655779Sxy150489 	tx_control_block_t *tcb;
6665779Sxy150489 	dma_buffer_t *tx_buf;
6675779Sxy150489 	igb_t *igb = tx_ring->igb;
6685779Sxy150489 	dev_info_t *devinfo = igb->dip;
6695779Sxy150489 
6705779Sxy150489 	/*
6715779Sxy150489 	 * Allocate memory for the work list.
6725779Sxy150489 	 */
6735779Sxy150489 	tx_ring->work_list = kmem_zalloc(sizeof (tx_control_block_t *) *
6745779Sxy150489 	    tx_ring->ring_size, KM_NOSLEEP);
6755779Sxy150489 
6765779Sxy150489 	if (tx_ring->work_list == NULL) {
6775779Sxy150489 		igb_error(igb,
6785779Sxy150489 		    "Cound not allocate memory for tx work list");
6795779Sxy150489 		return (IGB_FAILURE);
6805779Sxy150489 	}
6815779Sxy150489 
6825779Sxy150489 	/*
6835779Sxy150489 	 * Allocate memory for the free list.
6845779Sxy150489 	 */
6855779Sxy150489 	tx_ring->free_list = kmem_zalloc(sizeof (tx_control_block_t *) *
6865779Sxy150489 	    tx_ring->free_list_size, KM_NOSLEEP);
6875779Sxy150489 
6885779Sxy150489 	if (tx_ring->free_list == NULL) {
6895779Sxy150489 		kmem_free(tx_ring->work_list,
6905779Sxy150489 		    sizeof (tx_control_block_t *) * tx_ring->ring_size);
6915779Sxy150489 		tx_ring->work_list = NULL;
6925779Sxy150489 
6935779Sxy150489 		igb_error(igb,
6945779Sxy150489 		    "Cound not allocate memory for tx free list");
6955779Sxy150489 		return (IGB_FAILURE);
6965779Sxy150489 	}
6975779Sxy150489 
6985779Sxy150489 	/*
6995779Sxy150489 	 * Allocate memory for the tx control blocks of free list.
7005779Sxy150489 	 */
7015779Sxy150489 	tx_ring->tcb_area =
7025779Sxy150489 	    kmem_zalloc(sizeof (tx_control_block_t) *
7035779Sxy150489 	    tx_ring->free_list_size, KM_NOSLEEP);
7045779Sxy150489 
7055779Sxy150489 	if (tx_ring->tcb_area == NULL) {
7065779Sxy150489 		kmem_free(tx_ring->work_list,
7075779Sxy150489 		    sizeof (tx_control_block_t *) * tx_ring->ring_size);
7085779Sxy150489 		tx_ring->work_list = NULL;
7095779Sxy150489 
7105779Sxy150489 		kmem_free(tx_ring->free_list,
7115779Sxy150489 		    sizeof (tx_control_block_t *) * tx_ring->free_list_size);
7125779Sxy150489 		tx_ring->free_list = NULL;
7135779Sxy150489 
7145779Sxy150489 		igb_error(igb,
7155779Sxy150489 		    "Cound not allocate memory for tx control blocks");
7165779Sxy150489 		return (IGB_FAILURE);
7175779Sxy150489 	}
7185779Sxy150489 
7195779Sxy150489 	/*
7205779Sxy150489 	 * Allocate dma memory for the tx control block of free list.
7215779Sxy150489 	 */
7225779Sxy150489 	tcb = tx_ring->tcb_area;
7235779Sxy150489 	for (i = 0; i < tx_ring->free_list_size; i++, tcb++) {
7245779Sxy150489 		ASSERT(tcb != NULL);
7255779Sxy150489 
7265779Sxy150489 		tx_ring->free_list[i] = tcb;
7275779Sxy150489 
7285779Sxy150489 		/*
7295779Sxy150489 		 * Pre-allocate dma handles for transmit. These dma handles
7305779Sxy150489 		 * will be dynamically bound to the data buffers passed down
7315779Sxy150489 		 * from the upper layers at the time of transmitting.
7325779Sxy150489 		 */
7335779Sxy150489 		ret = ddi_dma_alloc_handle(devinfo,
7345779Sxy150489 		    &igb_tx_dma_attr,
7355779Sxy150489 		    DDI_DMA_DONTWAIT, NULL,
7365779Sxy150489 		    &tcb->tx_dma_handle);
7375779Sxy150489 		if (ret != DDI_SUCCESS) {
7385779Sxy150489 			tcb->tx_dma_handle = NULL;
7395779Sxy150489 			igb_error(igb,
7405779Sxy150489 			    "Could not allocate tx dma handle: %x", ret);
7415779Sxy150489 			goto alloc_tcb_lists_fail;
7425779Sxy150489 		}
7435779Sxy150489 
7445779Sxy150489 		/*
7455779Sxy150489 		 * Pre-allocate transmit buffers for packets that the
7465779Sxy150489 		 * size is less than bcopy_thresh.
7475779Sxy150489 		 */
7485779Sxy150489 		tx_buf = &tcb->tx_buf;
7495779Sxy150489 
7505779Sxy150489 		ret = igb_alloc_dma_buffer(igb,
7515779Sxy150489 		    tx_buf, igb->tx_buf_size);
7525779Sxy150489 
7535779Sxy150489 		if (ret != IGB_SUCCESS) {
7545779Sxy150489 			ASSERT(tcb->tx_dma_handle != NULL);
7555779Sxy150489 			ddi_dma_free_handle(&tcb->tx_dma_handle);
7565779Sxy150489 			tcb->tx_dma_handle = NULL;
7575779Sxy150489 			igb_error(igb, "Allocate tx dma buffer failed");
7585779Sxy150489 			goto alloc_tcb_lists_fail;
7595779Sxy150489 		}
760*12980SGuoqing.Zhu@Sun.COM 		tcb->last_index = MAX_TX_RING_SIZE;
7615779Sxy150489 	}
7625779Sxy150489 
7635779Sxy150489 	return (IGB_SUCCESS);
7645779Sxy150489 
7655779Sxy150489 alloc_tcb_lists_fail:
7665779Sxy150489 	igb_free_tcb_lists(tx_ring);
7675779Sxy150489 
7685779Sxy150489 	return (IGB_FAILURE);
7695779Sxy150489 }
7705779Sxy150489 
7715779Sxy150489 /*
7725779Sxy150489  * igb_free_tcb_lists - Release the memory allocated for
7735779Sxy150489  * the transmit control bolcks of one ring.
7745779Sxy150489  */
7755779Sxy150489 static void
igb_free_tcb_lists(igb_tx_ring_t * tx_ring)7765779Sxy150489 igb_free_tcb_lists(igb_tx_ring_t *tx_ring)
7775779Sxy150489 {
7785779Sxy150489 	int i;
7795779Sxy150489 	tx_control_block_t *tcb;
7805779Sxy150489 
7815779Sxy150489 	tcb = tx_ring->tcb_area;
7825779Sxy150489 	if (tcb == NULL)
7835779Sxy150489 		return;
7845779Sxy150489 
7855779Sxy150489 	for (i = 0; i < tx_ring->free_list_size; i++, tcb++) {
7865779Sxy150489 		ASSERT(tcb != NULL);
7875779Sxy150489 
7885779Sxy150489 		/* Free the tx dma handle for dynamical binding */
7895779Sxy150489 		if (tcb->tx_dma_handle != NULL) {
7905779Sxy150489 			ddi_dma_free_handle(&tcb->tx_dma_handle);
7915779Sxy150489 			tcb->tx_dma_handle = NULL;
7925779Sxy150489 		} else {
7935779Sxy150489 			/*
7945779Sxy150489 			 * If the dma handle is NULL, then we don't
7955779Sxy150489 			 * have to check the remaining.
7965779Sxy150489 			 */
7975779Sxy150489 			break;
7985779Sxy150489 		}
7995779Sxy150489 
8005779Sxy150489 		igb_free_dma_buffer(&tcb->tx_buf);
8015779Sxy150489 	}
8025779Sxy150489 
8035779Sxy150489 	if (tx_ring->tcb_area != NULL) {
8045779Sxy150489 		kmem_free(tx_ring->tcb_area,
8055779Sxy150489 		    sizeof (tx_control_block_t) * tx_ring->free_list_size);
8065779Sxy150489 		tx_ring->tcb_area = NULL;
8075779Sxy150489 	}
8085779Sxy150489 
8095779Sxy150489 	if (tx_ring->work_list != NULL) {
8105779Sxy150489 		kmem_free(tx_ring->work_list,
8115779Sxy150489 		    sizeof (tx_control_block_t *) * tx_ring->ring_size);
8125779Sxy150489 		tx_ring->work_list = NULL;
8135779Sxy150489 	}
8145779Sxy150489 
8155779Sxy150489 	if (tx_ring->free_list != NULL) {
8165779Sxy150489 		kmem_free(tx_ring->free_list,
8175779Sxy150489 		    sizeof (tx_control_block_t *) * tx_ring->free_list_size);
8185779Sxy150489 		tx_ring->free_list = NULL;
8195779Sxy150489 	}
8205779Sxy150489 }
8215779Sxy150489 
8225779Sxy150489 /*
8235779Sxy150489  * igb_alloc_rcb_lists - Memory allocation for the receive control blocks
8245779Sxy150489  * of one ring.
8255779Sxy150489  */
8265779Sxy150489 static int
igb_alloc_rcb_lists(igb_rx_data_t * rx_data)82711502SChenlu.Chen@Sun.COM igb_alloc_rcb_lists(igb_rx_data_t *rx_data)
8285779Sxy150489 {
8295779Sxy150489 	int i;
8305779Sxy150489 	int ret;
8315779Sxy150489 	rx_control_block_t *rcb;
83211502SChenlu.Chen@Sun.COM 	igb_t *igb = rx_data->rx_ring->igb;
8335779Sxy150489 	dma_buffer_t *rx_buf;
8345779Sxy150489 	uint32_t rcb_count;
8355779Sxy150489 
8365779Sxy150489 	/*
8375779Sxy150489 	 * Allocate memory for the rx control blocks for work list and
8385779Sxy150489 	 * free list.
8395779Sxy150489 	 */
84011502SChenlu.Chen@Sun.COM 	rcb_count = rx_data->ring_size + rx_data->free_list_size;
84111502SChenlu.Chen@Sun.COM 	rcb = rx_data->rcb_area;
8425779Sxy150489 
8435779Sxy150489 	for (i = 0; i < rcb_count; i++, rcb++) {
8445779Sxy150489 		ASSERT(rcb != NULL);
8455779Sxy150489 
84611502SChenlu.Chen@Sun.COM 		if (i < rx_data->ring_size) {
8475779Sxy150489 			/* Attach the rx control block to the work list */
84811502SChenlu.Chen@Sun.COM 			rx_data->work_list[i] = rcb;
8495779Sxy150489 		} else {
8505779Sxy150489 			/* Attach the rx control block to the free list */
85111502SChenlu.Chen@Sun.COM 			rx_data->free_list[i - rx_data->ring_size] = rcb;
8525779Sxy150489 		}
8535779Sxy150489 
8545779Sxy150489 		rx_buf = &rcb->rx_buf;
8555779Sxy150489 		ret = igb_alloc_dma_buffer(igb,
8565779Sxy150489 		    rx_buf, igb->rx_buf_size);
8575779Sxy150489 
8585779Sxy150489 		if (ret != IGB_SUCCESS) {
8595779Sxy150489 			igb_error(igb, "Allocate rx dma buffer failed");
8605779Sxy150489 			goto alloc_rcb_lists_fail;
8615779Sxy150489 		}
8625779Sxy150489 
8635779Sxy150489 		rx_buf->size -= IPHDR_ALIGN_ROOM;
8645779Sxy150489 		rx_buf->address += IPHDR_ALIGN_ROOM;
8655779Sxy150489 		rx_buf->dma_address += IPHDR_ALIGN_ROOM;
8665779Sxy150489 
86711502SChenlu.Chen@Sun.COM 		rcb->ref_cnt = 1;
86811502SChenlu.Chen@Sun.COM 		rcb->rx_data = (igb_rx_data_t *)rx_data;
8695779Sxy150489 		rcb->free_rtn.free_func = igb_rx_recycle;
8705779Sxy150489 		rcb->free_rtn.free_arg = (char *)rcb;
8715779Sxy150489 
8725779Sxy150489 		rcb->mp = desballoc((unsigned char *)
8738571SChenlu.Chen@Sun.COM 		    rx_buf->address,
8748571SChenlu.Chen@Sun.COM 		    rx_buf->size,
8755779Sxy150489 		    0, &rcb->free_rtn);
8765779Sxy150489 	}
8775779Sxy150489 
8785779Sxy150489 	return (IGB_SUCCESS);
8795779Sxy150489 
8805779Sxy150489 alloc_rcb_lists_fail:
88111502SChenlu.Chen@Sun.COM 	igb_free_rcb_lists(rx_data);
8825779Sxy150489 
8835779Sxy150489 	return (IGB_FAILURE);
8845779Sxy150489 }
8855779Sxy150489 
8865779Sxy150489 /*
8875779Sxy150489  * igb_free_rcb_lists - Free the receive control blocks of one ring.
8885779Sxy150489  */
8895779Sxy150489 static void
igb_free_rcb_lists(igb_rx_data_t * rx_data)89011502SChenlu.Chen@Sun.COM igb_free_rcb_lists(igb_rx_data_t *rx_data)
8915779Sxy150489 {
89211502SChenlu.Chen@Sun.COM 	igb_t *igb;
8935779Sxy150489 	rx_control_block_t *rcb;
8945779Sxy150489 	uint32_t rcb_count;
89511502SChenlu.Chen@Sun.COM 	uint32_t ref_cnt;
89611502SChenlu.Chen@Sun.COM 	int i;
8975779Sxy150489 
89811502SChenlu.Chen@Sun.COM 	igb = rx_data->rx_ring->igb;
89911502SChenlu.Chen@Sun.COM 
90011502SChenlu.Chen@Sun.COM 	mutex_enter(&igb->rx_pending_lock);
9015779Sxy150489 
90211502SChenlu.Chen@Sun.COM 	rcb = rx_data->rcb_area;
90311502SChenlu.Chen@Sun.COM 	rcb_count = rx_data->ring_size + rx_data->free_list_size;
90411502SChenlu.Chen@Sun.COM 
9055779Sxy150489 	for (i = 0; i < rcb_count; i++, rcb++) {
9065779Sxy150489 		ASSERT(rcb != NULL);
9075779Sxy150489 
90811502SChenlu.Chen@Sun.COM 		ref_cnt = atomic_dec_32_nv(&rcb->ref_cnt);
90911502SChenlu.Chen@Sun.COM 		if (ref_cnt == 0) {
91011502SChenlu.Chen@Sun.COM 			if (rcb->mp != NULL) {
91111502SChenlu.Chen@Sun.COM 				freemsg(rcb->mp);
91211502SChenlu.Chen@Sun.COM 				rcb->mp = NULL;
91311502SChenlu.Chen@Sun.COM 			}
91411502SChenlu.Chen@Sun.COM 			igb_free_dma_buffer(&rcb->rx_buf);
91511502SChenlu.Chen@Sun.COM 		} else {
91611502SChenlu.Chen@Sun.COM 			atomic_inc_32(&rx_data->rcb_pending);
91711502SChenlu.Chen@Sun.COM 			atomic_inc_32(&igb->rcb_pending);
9185779Sxy150489 		}
9195779Sxy150489 	}
9205779Sxy150489 
92111502SChenlu.Chen@Sun.COM 	mutex_exit(&igb->rx_pending_lock);
9225779Sxy150489 }
9236624Sgl147354 
9246624Sgl147354 void
igb_set_fma_flags(int dma_flag)92511236SStephen.Hanson@Sun.COM igb_set_fma_flags(int dma_flag)
9266624Sgl147354 {
9276624Sgl147354 	if (dma_flag) {
9286624Sgl147354 		igb_tx_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
9296624Sgl147354 		igb_buf_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
9306624Sgl147354 		igb_desc_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
9316624Sgl147354 	} else {
9326624Sgl147354 		igb_tx_dma_attr.dma_attr_flags = 0;
9336624Sgl147354 		igb_buf_dma_attr.dma_attr_flags = 0;
9346624Sgl147354 		igb_desc_dma_attr.dma_attr_flags = 0;
9356624Sgl147354 	}
9366624Sgl147354 }
937