xref: /titanic_52/usr/src/uts/common/io/igb/igb_buf.c (revision e5513923451d9bed546d16298b8bbb046bd602be)
1c869993eSxy150489 /*
2c869993eSxy150489  * CDDL HEADER START
3c869993eSxy150489  *
4c869993eSxy150489  * The contents of this file are subject to the terms of the
5c869993eSxy150489  * Common Development and Distribution License (the "License").
6c869993eSxy150489  * You may not use this file except in compliance with the License.
7c869993eSxy150489  *
869b2d733SGuoqing Zhu  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
969b2d733SGuoqing Zhu  * or http://www.opensolaris.org/os/licensing.
10c869993eSxy150489  * See the License for the specific language governing permissions
11c869993eSxy150489  * and limitations under the License.
12c869993eSxy150489  *
1369b2d733SGuoqing Zhu  * When distributing Covered Code, include this CDDL HEADER in each
1469b2d733SGuoqing Zhu  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c869993eSxy150489  * If applicable, add the following below this CDDL HEADER, with the
16c869993eSxy150489  * fields enclosed by brackets "[]" replaced with your own identifying
17c869993eSxy150489  * information: Portions Copyright [yyyy] [name of copyright owner]
18c869993eSxy150489  *
19c869993eSxy150489  * CDDL HEADER END
20c869993eSxy150489  */
21c869993eSxy150489 
22c869993eSxy150489 /*
2369b2d733SGuoqing Zhu  * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
2469b2d733SGuoqing Zhu  */
2569b2d733SGuoqing Zhu 
2669b2d733SGuoqing Zhu /*
2769b2d733SGuoqing Zhu  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28c869993eSxy150489  */
29c869993eSxy150489 
30c869993eSxy150489 #include "igb_sw.h"
31c869993eSxy150489 
32c869993eSxy150489 static int igb_alloc_tbd_ring(igb_tx_ring_t *);
33c869993eSxy150489 static void igb_free_tbd_ring(igb_tx_ring_t *);
34ac7f5757Schenlu chen - Sun Microsystems - Beijing China static int igb_alloc_rbd_ring(igb_rx_data_t *);
35ac7f5757Schenlu chen - Sun Microsystems - Beijing China static void igb_free_rbd_ring(igb_rx_data_t *);
36c869993eSxy150489 static int igb_alloc_dma_buffer(igb_t *, dma_buffer_t *, size_t);
37c869993eSxy150489 static int igb_alloc_tcb_lists(igb_tx_ring_t *);
38c869993eSxy150489 static void igb_free_tcb_lists(igb_tx_ring_t *);
39ac7f5757Schenlu chen - Sun Microsystems - Beijing China static int igb_alloc_rcb_lists(igb_rx_data_t *);
40ac7f5757Schenlu chen - Sun Microsystems - Beijing China static void igb_free_rcb_lists(igb_rx_data_t *);
41c869993eSxy150489 
42c869993eSxy150489 #ifdef __sparc
43c869993eSxy150489 #define	IGB_DMA_ALIGNMENT	0x0000000000002000ull
44c869993eSxy150489 #else
45c869993eSxy150489 #define	IGB_DMA_ALIGNMENT	0x0000000000001000ull
46c869993eSxy150489 #endif
47c869993eSxy150489 
48c869993eSxy150489 /*
49c869993eSxy150489  * DMA attributes for tx/rx descriptors
50c869993eSxy150489  */
51c869993eSxy150489 static ddi_dma_attr_t igb_desc_dma_attr = {
52c869993eSxy150489 	DMA_ATTR_V0,			/* version number */
53c869993eSxy150489 	0x0000000000000000ull,		/* low address */
54c869993eSxy150489 	0xFFFFFFFFFFFFFFFFull,		/* high address */
55c869993eSxy150489 	0x00000000FFFFFFFFull,		/* dma counter max */
56c869993eSxy150489 	IGB_DMA_ALIGNMENT,		/* alignment */
57c869993eSxy150489 	0x00000FFF,			/* burst sizes */
58c869993eSxy150489 	0x00000001,			/* minimum transfer size */
59c869993eSxy150489 	0x00000000FFFFFFFFull,		/* maximum transfer size */
60c869993eSxy150489 	0xFFFFFFFFFFFFFFFFull,		/* maximum segment size */
61c869993eSxy150489 	1,				/* scatter/gather list length */
62c869993eSxy150489 	0x00000001,			/* granularity */
638bb4b220Sgl147354 	DDI_DMA_FLAGERR,		/* DMA flags */
64c869993eSxy150489 };
65c869993eSxy150489 
66c869993eSxy150489 /*
67c869993eSxy150489  * DMA attributes for tx/rx buffers
68c869993eSxy150489  */
69c869993eSxy150489 static ddi_dma_attr_t igb_buf_dma_attr = {
70c869993eSxy150489 	DMA_ATTR_V0,			/* version number */
71c869993eSxy150489 	0x0000000000000000ull,		/* low address */
72c869993eSxy150489 	0xFFFFFFFFFFFFFFFFull,		/* high address */
73c869993eSxy150489 	0x00000000FFFFFFFFull,		/* dma counter max */
74c869993eSxy150489 	IGB_DMA_ALIGNMENT,		/* alignment */
75c869993eSxy150489 	0x00000FFF,			/* burst sizes */
76c869993eSxy150489 	0x00000001,			/* minimum transfer size */
77c869993eSxy150489 	0x00000000FFFFFFFFull,		/* maximum transfer size */
78c869993eSxy150489 	0xFFFFFFFFFFFFFFFFull,		/* maximum segment size	 */
79c869993eSxy150489 	1,				/* scatter/gather list length */
80c869993eSxy150489 	0x00000001,			/* granularity */
818bb4b220Sgl147354 	DDI_DMA_FLAGERR,		/* DMA flags */
82c869993eSxy150489 };
83c869993eSxy150489 
84c869993eSxy150489 /*
85c869993eSxy150489  * DMA attributes for transmit
86c869993eSxy150489  */
87c869993eSxy150489 static ddi_dma_attr_t igb_tx_dma_attr = {
88c869993eSxy150489 	DMA_ATTR_V0,			/* version number */
89c869993eSxy150489 	0x0000000000000000ull,		/* low address */
90c869993eSxy150489 	0xFFFFFFFFFFFFFFFFull,		/* high address */
91c869993eSxy150489 	0x00000000FFFFFFFFull,		/* dma counter max */
92c869993eSxy150489 	1,				/* alignment */
93c869993eSxy150489 	0x00000FFF,			/* burst sizes */
94c869993eSxy150489 	0x00000001,			/* minimum transfer size */
95c869993eSxy150489 	0x00000000FFFFFFFFull,		/* maximum transfer size */
96c869993eSxy150489 	0xFFFFFFFFFFFFFFFFull,		/* maximum segment size	 */
97c869993eSxy150489 	MAX_COOKIE,			/* scatter/gather list length */
98c869993eSxy150489 	0x00000001,			/* granularity */
998bb4b220Sgl147354 	DDI_DMA_FLAGERR,		/* DMA flags */
100c869993eSxy150489 };
101c869993eSxy150489 
102c869993eSxy150489 /*
103c869993eSxy150489  * DMA access attributes for descriptors.
104c869993eSxy150489  */
105c869993eSxy150489 static ddi_device_acc_attr_t igb_desc_acc_attr = {
106c869993eSxy150489 	DDI_DEVICE_ATTR_V0,
107c869993eSxy150489 	DDI_STRUCTURE_LE_ACC,
108837c1ac4SStephen Hanson 	DDI_STRICTORDER_ACC
109c869993eSxy150489 };
110c869993eSxy150489 
111c869993eSxy150489 /*
112c869993eSxy150489  * DMA access attributes for buffers.
113c869993eSxy150489  */
114c869993eSxy150489 static ddi_device_acc_attr_t igb_buf_acc_attr = {
115c869993eSxy150489 	DDI_DEVICE_ATTR_V0,
116c869993eSxy150489 	DDI_NEVERSWAP_ACC,
117c869993eSxy150489 	DDI_STRICTORDER_ACC
118c869993eSxy150489 };
119c869993eSxy150489 
120c869993eSxy150489 
121c869993eSxy150489 /*
122c869993eSxy150489  * igb_alloc_dma - Allocate DMA resources for all rx/tx rings
123c869993eSxy150489  */
124c869993eSxy150489 int
125c869993eSxy150489 igb_alloc_dma(igb_t *igb)
126c869993eSxy150489 {
127c869993eSxy150489 	igb_rx_ring_t *rx_ring;
128ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_rx_data_t *rx_data;
129c869993eSxy150489 	igb_tx_ring_t *tx_ring;
130c869993eSxy150489 	int i;
131c869993eSxy150489 
132c869993eSxy150489 	for (i = 0; i < igb->num_rx_rings; i++) {
133c869993eSxy150489 		/*
134c869993eSxy150489 		 * Allocate receive desciptor ring and control block lists
135c869993eSxy150489 		 */
136c869993eSxy150489 		rx_ring = &igb->rx_rings[i];
137ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data = rx_ring->rx_data;
138c869993eSxy150489 
139ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (igb_alloc_rbd_ring(rx_data) != IGB_SUCCESS)
140c869993eSxy150489 			goto alloc_dma_failure;
141c869993eSxy150489 
142ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (igb_alloc_rcb_lists(rx_data) != IGB_SUCCESS)
143c869993eSxy150489 			goto alloc_dma_failure;
144c869993eSxy150489 	}
145c869993eSxy150489 
146c869993eSxy150489 	for (i = 0; i < igb->num_tx_rings; i++) {
147c869993eSxy150489 		/*
148c869993eSxy150489 		 * Allocate transmit desciptor ring and control block lists
149c869993eSxy150489 		 */
150c869993eSxy150489 		tx_ring = &igb->tx_rings[i];
151c869993eSxy150489 
152c869993eSxy150489 		if (igb_alloc_tbd_ring(tx_ring) != IGB_SUCCESS)
153c869993eSxy150489 			goto alloc_dma_failure;
154c869993eSxy150489 
155c869993eSxy150489 		if (igb_alloc_tcb_lists(tx_ring) != IGB_SUCCESS)
156c869993eSxy150489 			goto alloc_dma_failure;
157c869993eSxy150489 	}
158c869993eSxy150489 
159c869993eSxy150489 	return (IGB_SUCCESS);
160c869993eSxy150489 
161c869993eSxy150489 alloc_dma_failure:
162c869993eSxy150489 	igb_free_dma(igb);
163c869993eSxy150489 
164c869993eSxy150489 	return (IGB_FAILURE);
165c869993eSxy150489 }
166c869993eSxy150489 
167c869993eSxy150489 
168c869993eSxy150489 /*
169c869993eSxy150489  * igb_free_dma - Free all the DMA resources of all rx/tx rings
170c869993eSxy150489  */
171c869993eSxy150489 void
172c869993eSxy150489 igb_free_dma(igb_t *igb)
173c869993eSxy150489 {
174c869993eSxy150489 	igb_rx_ring_t *rx_ring;
175ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_rx_data_t *rx_data;
176c869993eSxy150489 	igb_tx_ring_t *tx_ring;
177c869993eSxy150489 	int i;
178c869993eSxy150489 
179c869993eSxy150489 	/*
180c869993eSxy150489 	 * Free DMA resources of rx rings
181c869993eSxy150489 	 */
182c869993eSxy150489 	for (i = 0; i < igb->num_rx_rings; i++) {
183c869993eSxy150489 		rx_ring = &igb->rx_rings[i];
184ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data = rx_ring->rx_data;
185ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
186ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb_free_rbd_ring(rx_data);
187ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb_free_rcb_lists(rx_data);
188c869993eSxy150489 	}
189c869993eSxy150489 
190c869993eSxy150489 	/*
191c869993eSxy150489 	 * Free DMA resources of tx rings
192c869993eSxy150489 	 */
193c869993eSxy150489 	for (i = 0; i < igb->num_tx_rings; i++) {
194c869993eSxy150489 		tx_ring = &igb->tx_rings[i];
195c869993eSxy150489 		igb_free_tbd_ring(tx_ring);
196c869993eSxy150489 		igb_free_tcb_lists(tx_ring);
197c869993eSxy150489 	}
198c869993eSxy150489 }
199c869993eSxy150489 
200c869993eSxy150489 /*
201c869993eSxy150489  * igb_alloc_tbd_ring - Memory allocation for the tx descriptors of one ring.
202c869993eSxy150489  */
203c869993eSxy150489 static int
204c869993eSxy150489 igb_alloc_tbd_ring(igb_tx_ring_t *tx_ring)
205c869993eSxy150489 {
206c869993eSxy150489 	int ret;
207c869993eSxy150489 	size_t size;
208c869993eSxy150489 	size_t len;
209c869993eSxy150489 	uint_t cookie_num;
210c869993eSxy150489 	dev_info_t *devinfo;
211c869993eSxy150489 	ddi_dma_cookie_t cookie;
212c869993eSxy150489 	igb_t *igb = tx_ring->igb;
213c869993eSxy150489 
214c869993eSxy150489 	devinfo = igb->dip;
215c869993eSxy150489 	size = sizeof (union e1000_adv_tx_desc) * tx_ring->ring_size;
216c869993eSxy150489 
217c869993eSxy150489 	/*
218c869993eSxy150489 	 * If tx head write-back is enabled, an extra tbd is allocated
219c869993eSxy150489 	 * to save the head write-back value
220c869993eSxy150489 	 */
221c869993eSxy150489 	if (igb->tx_head_wb_enable) {
222c869993eSxy150489 		size += sizeof (union e1000_adv_tx_desc);
223c869993eSxy150489 	}
224c869993eSxy150489 
225c869993eSxy150489 	/*
226c869993eSxy150489 	 * Allocate a DMA handle for the transmit descriptor
227c869993eSxy150489 	 * memory area.
228c869993eSxy150489 	 */
229c869993eSxy150489 	ret = ddi_dma_alloc_handle(devinfo, &igb_desc_dma_attr,
230c869993eSxy150489 	    DDI_DMA_DONTWAIT, NULL,
231c869993eSxy150489 	    &tx_ring->tbd_area.dma_handle);
232c869993eSxy150489 
233c869993eSxy150489 	if (ret != DDI_SUCCESS) {
234*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
235c869993eSxy150489 		    "Could not allocate tbd dma handle: %x", ret);
236c869993eSxy150489 		tx_ring->tbd_area.dma_handle = NULL;
237c869993eSxy150489 
238c869993eSxy150489 		return (IGB_FAILURE);
239c869993eSxy150489 	}
240c869993eSxy150489 
241c869993eSxy150489 	/*
242c869993eSxy150489 	 * Allocate memory to DMA data to and from the transmit
243c869993eSxy150489 	 * descriptors.
244c869993eSxy150489 	 */
245c869993eSxy150489 	ret = ddi_dma_mem_alloc(tx_ring->tbd_area.dma_handle,
246c869993eSxy150489 	    size, &igb_desc_acc_attr, DDI_DMA_CONSISTENT,
247c869993eSxy150489 	    DDI_DMA_DONTWAIT, NULL,
248c869993eSxy150489 	    (caddr_t *)&tx_ring->tbd_area.address,
249c869993eSxy150489 	    &len, &tx_ring->tbd_area.acc_handle);
250c869993eSxy150489 
251c869993eSxy150489 	if (ret != DDI_SUCCESS) {
252*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
253c869993eSxy150489 		    "Could not allocate tbd dma memory: %x", ret);
254c869993eSxy150489 		tx_ring->tbd_area.acc_handle = NULL;
255c869993eSxy150489 		tx_ring->tbd_area.address = NULL;
256c869993eSxy150489 		if (tx_ring->tbd_area.dma_handle != NULL) {
257c869993eSxy150489 			ddi_dma_free_handle(&tx_ring->tbd_area.dma_handle);
258c869993eSxy150489 			tx_ring->tbd_area.dma_handle = NULL;
259c869993eSxy150489 		}
260c869993eSxy150489 		return (IGB_FAILURE);
261c869993eSxy150489 	}
262c869993eSxy150489 
263c869993eSxy150489 	/*
264c869993eSxy150489 	 * Initialize the entire transmit buffer descriptor area to zero
265c869993eSxy150489 	 */
266c869993eSxy150489 	bzero(tx_ring->tbd_area.address, len);
267c869993eSxy150489 
268c869993eSxy150489 	/*
269c869993eSxy150489 	 * Allocates DMA resources for the memory that was allocated by
270c869993eSxy150489 	 * the ddi_dma_mem_alloc call. The DMA resources then get bound to the
271c869993eSxy150489 	 * the memory address
272c869993eSxy150489 	 */
273c869993eSxy150489 	ret = ddi_dma_addr_bind_handle(tx_ring->tbd_area.dma_handle,
274c869993eSxy150489 	    NULL, (caddr_t)tx_ring->tbd_area.address,
275c869993eSxy150489 	    len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
276c869993eSxy150489 	    DDI_DMA_DONTWAIT, NULL, &cookie, &cookie_num);
277c869993eSxy150489 
278c869993eSxy150489 	if (ret != DDI_DMA_MAPPED) {
279*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
280c869993eSxy150489 		    "Could not bind tbd dma resource: %x", ret);
281c869993eSxy150489 		tx_ring->tbd_area.dma_address = NULL;
282c869993eSxy150489 		if (tx_ring->tbd_area.acc_handle != NULL) {
283c869993eSxy150489 			ddi_dma_mem_free(&tx_ring->tbd_area.acc_handle);
284c869993eSxy150489 			tx_ring->tbd_area.acc_handle = NULL;
285c869993eSxy150489 			tx_ring->tbd_area.address = NULL;
286c869993eSxy150489 		}
287c869993eSxy150489 		if (tx_ring->tbd_area.dma_handle != NULL) {
288c869993eSxy150489 			ddi_dma_free_handle(&tx_ring->tbd_area.dma_handle);
289c869993eSxy150489 			tx_ring->tbd_area.dma_handle = NULL;
290c869993eSxy150489 		}
291c869993eSxy150489 		return (IGB_FAILURE);
292c869993eSxy150489 	}
293c869993eSxy150489 
294c869993eSxy150489 	ASSERT(cookie_num == 1);
295c869993eSxy150489 
296c869993eSxy150489 	tx_ring->tbd_area.dma_address = cookie.dmac_laddress;
297c869993eSxy150489 	tx_ring->tbd_area.size = len;
298c869993eSxy150489 
299c869993eSxy150489 	tx_ring->tbd_ring = (union e1000_adv_tx_desc *)(uintptr_t)
300c869993eSxy150489 	    tx_ring->tbd_area.address;
301c869993eSxy150489 
302c869993eSxy150489 	return (IGB_SUCCESS);
303c869993eSxy150489 }
304c869993eSxy150489 
305c869993eSxy150489 /*
306c869993eSxy150489  * igb_free_tbd_ring - Free the tx descriptors of one ring.
307c869993eSxy150489  */
308c869993eSxy150489 static void
309c869993eSxy150489 igb_free_tbd_ring(igb_tx_ring_t *tx_ring)
310c869993eSxy150489 {
311c869993eSxy150489 	if (tx_ring->tbd_area.dma_handle != NULL) {
312c869993eSxy150489 		(void) ddi_dma_unbind_handle(tx_ring->tbd_area.dma_handle);
313c869993eSxy150489 	}
314c869993eSxy150489 	if (tx_ring->tbd_area.acc_handle != NULL) {
315c869993eSxy150489 		ddi_dma_mem_free(&tx_ring->tbd_area.acc_handle);
316c869993eSxy150489 		tx_ring->tbd_area.acc_handle = NULL;
317c869993eSxy150489 	}
318c869993eSxy150489 	if (tx_ring->tbd_area.dma_handle != NULL) {
319c869993eSxy150489 		ddi_dma_free_handle(&tx_ring->tbd_area.dma_handle);
320c869993eSxy150489 		tx_ring->tbd_area.dma_handle = NULL;
321c869993eSxy150489 	}
322c869993eSxy150489 	tx_ring->tbd_area.address = NULL;
323c869993eSxy150489 	tx_ring->tbd_area.dma_address = NULL;
324c869993eSxy150489 	tx_ring->tbd_area.size = 0;
325c869993eSxy150489 
326c869993eSxy150489 	tx_ring->tbd_ring = NULL;
327c869993eSxy150489 }
328c869993eSxy150489 
329ac7f5757Schenlu chen - Sun Microsystems - Beijing China int
330ac7f5757Schenlu chen - Sun Microsystems - Beijing China igb_alloc_rx_ring_data(igb_rx_ring_t *rx_ring)
331ac7f5757Schenlu chen - Sun Microsystems - Beijing China {
332ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_rx_data_t *rx_data;
333ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_t *igb = rx_ring->igb;
334ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	uint32_t rcb_count;
335ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
336ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	/*
337ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 * Allocate memory for software receive rings
338ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 */
339ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data = kmem_zalloc(sizeof (igb_rx_data_t), KM_NOSLEEP);
340ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
341ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (rx_data == NULL) {
342*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
343*e5513923SYuri Pankov 		    "Allocate software receive rings failed");
344ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		return (IGB_FAILURE);
345ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
346ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
347ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rx_ring = rx_ring;
348ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	mutex_init(&rx_data->recycle_lock, NULL,
349ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	    MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
350ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
351ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->ring_size = igb->rx_ring_size;
352ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->free_list_size = igb->rx_ring_size;
353ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
354ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rcb_head = 0;
355ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rcb_tail = 0;
356ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rcb_free = rx_data->free_list_size;
357ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
358ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	/*
359ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 * Allocate memory for the work list.
360ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 */
361ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->work_list = kmem_zalloc(sizeof (rx_control_block_t *) *
362ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	    rx_data->ring_size, KM_NOSLEEP);
363ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
364ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (rx_data->work_list == NULL) {
365*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
366ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		    "Could not allocate memory for rx work list");
367ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		goto alloc_rx_data_failure;
368ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
369ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
370ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	/*
371ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 * Allocate memory for the free list.
372ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 */
373ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->free_list = kmem_zalloc(sizeof (rx_control_block_t *) *
374ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	    rx_data->free_list_size, KM_NOSLEEP);
375ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
376ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (rx_data->free_list == NULL) {
377*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
378ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		    "Cound not allocate memory for rx free list");
379ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		goto alloc_rx_data_failure;
380ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
381ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
382ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	/*
383ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 * Allocate memory for the rx control blocks for work list and
384ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 * free list.
385ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 */
386ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rcb_count = rx_data->ring_size + rx_data->free_list_size;
387ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rcb_area =
388ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	    kmem_zalloc(sizeof (rx_control_block_t) * rcb_count,
389ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	    KM_NOSLEEP);
390ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
391ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (rx_data->rcb_area == NULL) {
392*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
393ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		    "Cound not allocate memory for rx control blocks");
394ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		goto alloc_rx_data_failure;
395ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
396ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
397ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_ring->rx_data = rx_data;
398ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	return (IGB_SUCCESS);
399ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
400ac7f5757Schenlu chen - Sun Microsystems - Beijing China alloc_rx_data_failure:
401ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_free_rx_ring_data(rx_data);
402ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	return (IGB_FAILURE);
403ac7f5757Schenlu chen - Sun Microsystems - Beijing China }
404ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
405ac7f5757Schenlu chen - Sun Microsystems - Beijing China void
406ac7f5757Schenlu chen - Sun Microsystems - Beijing China igb_free_rx_ring_data(igb_rx_data_t *rx_data)
407ac7f5757Schenlu chen - Sun Microsystems - Beijing China {
408ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	uint32_t rcb_count;
409ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
410ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (rx_data == NULL)
411ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		return;
412ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
413ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	ASSERT(rx_data->rcb_pending == 0);
414ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
415ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rcb_count = rx_data->ring_size + rx_data->free_list_size;
416ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (rx_data->rcb_area != NULL) {
417ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		kmem_free(rx_data->rcb_area,
418ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		    sizeof (rx_control_block_t) * rcb_count);
419ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data->rcb_area = NULL;
420ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
421ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
422ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (rx_data->work_list != NULL) {
423ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		kmem_free(rx_data->work_list,
424ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		    sizeof (rx_control_block_t *) * rx_data->ring_size);
425ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data->work_list = NULL;
426ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
427ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
428ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (rx_data->free_list != NULL) {
429ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		kmem_free(rx_data->free_list,
430ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		    sizeof (rx_control_block_t *) * rx_data->free_list_size);
431ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data->free_list = NULL;
432ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
433ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
434ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	mutex_destroy(&rx_data->recycle_lock);
435ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	kmem_free(rx_data, sizeof (igb_rx_data_t));
436ac7f5757Schenlu chen - Sun Microsystems - Beijing China }
437ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
438c869993eSxy150489 /*
439c869993eSxy150489  * igb_alloc_rbd_ring - Memory allocation for the rx descriptors of one ring.
440c869993eSxy150489  */
441c869993eSxy150489 static int
442ac7f5757Schenlu chen - Sun Microsystems - Beijing China igb_alloc_rbd_ring(igb_rx_data_t *rx_data)
443c869993eSxy150489 {
444c869993eSxy150489 	int ret;
445c869993eSxy150489 	size_t size;
446c869993eSxy150489 	size_t len;
447c869993eSxy150489 	uint_t cookie_num;
448c869993eSxy150489 	dev_info_t *devinfo;
449c869993eSxy150489 	ddi_dma_cookie_t cookie;
450ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_t *igb = rx_data->rx_ring->igb;
451c869993eSxy150489 
452c869993eSxy150489 	devinfo = igb->dip;
453ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	size = sizeof (union e1000_adv_rx_desc) * rx_data->ring_size;
454c869993eSxy150489 
455c869993eSxy150489 	/*
456c869993eSxy150489 	 * Allocate a new DMA handle for the receive descriptor
457c869993eSxy150489 	 * memory area.
458c869993eSxy150489 	 */
459c869993eSxy150489 	ret = ddi_dma_alloc_handle(devinfo, &igb_desc_dma_attr,
460c869993eSxy150489 	    DDI_DMA_DONTWAIT, NULL,
461ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	    &rx_data->rbd_area.dma_handle);
462c869993eSxy150489 
463c869993eSxy150489 	if (ret != DDI_SUCCESS) {
464*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
465c869993eSxy150489 		    "Could not allocate rbd dma handle: %x", ret);
466ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data->rbd_area.dma_handle = NULL;
467c869993eSxy150489 		return (IGB_FAILURE);
468c869993eSxy150489 	}
469c869993eSxy150489 
470c869993eSxy150489 	/*
471c869993eSxy150489 	 * Allocate memory to DMA data to and from the receive
472c869993eSxy150489 	 * descriptors.
473c869993eSxy150489 	 */
474ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	ret = ddi_dma_mem_alloc(rx_data->rbd_area.dma_handle,
475c869993eSxy150489 	    size, &igb_desc_acc_attr, DDI_DMA_CONSISTENT,
476c869993eSxy150489 	    DDI_DMA_DONTWAIT, NULL,
477ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	    (caddr_t *)&rx_data->rbd_area.address,
478ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	    &len, &rx_data->rbd_area.acc_handle);
479c869993eSxy150489 
480c869993eSxy150489 	if (ret != DDI_SUCCESS) {
481*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
482c869993eSxy150489 		    "Could not allocate rbd dma memory: %x", ret);
483ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data->rbd_area.acc_handle = NULL;
484ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data->rbd_area.address = NULL;
485ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (rx_data->rbd_area.dma_handle != NULL) {
486ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			ddi_dma_free_handle(&rx_data->rbd_area.dma_handle);
487ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			rx_data->rbd_area.dma_handle = NULL;
488c869993eSxy150489 		}
489c869993eSxy150489 		return (IGB_FAILURE);
490c869993eSxy150489 	}
491c869993eSxy150489 
492c869993eSxy150489 	/*
493c869993eSxy150489 	 * Initialize the entire transmit buffer descriptor area to zero
494c869993eSxy150489 	 */
495ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	bzero(rx_data->rbd_area.address, len);
496c869993eSxy150489 
497c869993eSxy150489 	/*
498c869993eSxy150489 	 * Allocates DMA resources for the memory that was allocated by
499c869993eSxy150489 	 * the ddi_dma_mem_alloc call.
500c869993eSxy150489 	 */
501ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	ret = ddi_dma_addr_bind_handle(rx_data->rbd_area.dma_handle,
502ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	    NULL, (caddr_t)rx_data->rbd_area.address,
503c869993eSxy150489 	    len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
504c869993eSxy150489 	    DDI_DMA_DONTWAIT, NULL, &cookie, &cookie_num);
505c869993eSxy150489 
506c869993eSxy150489 	if (ret != DDI_DMA_MAPPED) {
507*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
508c869993eSxy150489 		    "Could not bind rbd dma resource: %x", ret);
509ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data->rbd_area.dma_address = NULL;
510ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (rx_data->rbd_area.acc_handle != NULL) {
511ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			ddi_dma_mem_free(&rx_data->rbd_area.acc_handle);
512ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			rx_data->rbd_area.acc_handle = NULL;
513ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			rx_data->rbd_area.address = NULL;
514c869993eSxy150489 		}
515ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (rx_data->rbd_area.dma_handle != NULL) {
516ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			ddi_dma_free_handle(&rx_data->rbd_area.dma_handle);
517ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			rx_data->rbd_area.dma_handle = NULL;
518c869993eSxy150489 		}
519c869993eSxy150489 		return (IGB_FAILURE);
520c869993eSxy150489 	}
521c869993eSxy150489 
522c869993eSxy150489 	ASSERT(cookie_num == 1);
523c869993eSxy150489 
524ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rbd_area.dma_address = cookie.dmac_laddress;
525ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rbd_area.size = len;
526c869993eSxy150489 
527ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rbd_ring = (union e1000_adv_rx_desc *)(uintptr_t)
528ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	    rx_data->rbd_area.address;
529c869993eSxy150489 
530c869993eSxy150489 	return (IGB_SUCCESS);
531c869993eSxy150489 }
532c869993eSxy150489 
533c869993eSxy150489 /*
534c869993eSxy150489  * igb_free_rbd_ring - Free the rx descriptors of one ring.
535c869993eSxy150489  */
536c869993eSxy150489 static void
537ac7f5757Schenlu chen - Sun Microsystems - Beijing China igb_free_rbd_ring(igb_rx_data_t *rx_data)
538c869993eSxy150489 {
539ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (rx_data->rbd_area.dma_handle != NULL) {
540ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		(void) ddi_dma_unbind_handle(rx_data->rbd_area.dma_handle);
541c869993eSxy150489 	}
542ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (rx_data->rbd_area.acc_handle != NULL) {
543ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		ddi_dma_mem_free(&rx_data->rbd_area.acc_handle);
544ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data->rbd_area.acc_handle = NULL;
545c869993eSxy150489 	}
546ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (rx_data->rbd_area.dma_handle != NULL) {
547ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		ddi_dma_free_handle(&rx_data->rbd_area.dma_handle);
548ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data->rbd_area.dma_handle = NULL;
549c869993eSxy150489 	}
550ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rbd_area.address = NULL;
551ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rbd_area.dma_address = NULL;
552ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rbd_area.size = 0;
553c869993eSxy150489 
554ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rbd_ring = NULL;
555c869993eSxy150489 }
556c869993eSxy150489 
557c869993eSxy150489 
558c869993eSxy150489 /*
559c869993eSxy150489  * igb_alloc_dma_buffer - Allocate DMA resources for a DMA buffer
560c869993eSxy150489  */
561c869993eSxy150489 static int
562c869993eSxy150489 igb_alloc_dma_buffer(igb_t *igb,
563c869993eSxy150489     dma_buffer_t *buf, size_t size)
564c869993eSxy150489 {
565c869993eSxy150489 	int ret;
566c869993eSxy150489 	dev_info_t *devinfo = igb->dip;
567c869993eSxy150489 	ddi_dma_cookie_t cookie;
568c869993eSxy150489 	size_t len;
569c869993eSxy150489 	uint_t cookie_num;
570c869993eSxy150489 
571c869993eSxy150489 	ret = ddi_dma_alloc_handle(devinfo,
572c869993eSxy150489 	    &igb_buf_dma_attr, DDI_DMA_DONTWAIT,
573c869993eSxy150489 	    NULL, &buf->dma_handle);
574c869993eSxy150489 
575c869993eSxy150489 	if (ret != DDI_SUCCESS) {
576c869993eSxy150489 		buf->dma_handle = NULL;
577*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
578c869993eSxy150489 		    "Could not allocate dma buffer handle: %x", ret);
579c869993eSxy150489 		return (IGB_FAILURE);
580c869993eSxy150489 	}
581c869993eSxy150489 
582c869993eSxy150489 	ret = ddi_dma_mem_alloc(buf->dma_handle,
583c869993eSxy150489 	    size, &igb_buf_acc_attr, DDI_DMA_STREAMING,
584c869993eSxy150489 	    DDI_DMA_DONTWAIT, NULL, &buf->address,
585c869993eSxy150489 	    &len, &buf->acc_handle);
586c869993eSxy150489 
587c869993eSxy150489 	if (ret != DDI_SUCCESS) {
588c869993eSxy150489 		buf->acc_handle = NULL;
589c869993eSxy150489 		buf->address = NULL;
590c869993eSxy150489 		if (buf->dma_handle != NULL) {
591c869993eSxy150489 			ddi_dma_free_handle(&buf->dma_handle);
592c869993eSxy150489 			buf->dma_handle = NULL;
593c869993eSxy150489 		}
594*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
595c869993eSxy150489 		    "Could not allocate dma buffer memory: %x", ret);
596c869993eSxy150489 		return (IGB_FAILURE);
597c869993eSxy150489 	}
598c869993eSxy150489 
599c869993eSxy150489 	ret = ddi_dma_addr_bind_handle(buf->dma_handle, NULL,
600c869993eSxy150489 	    buf->address,
601c869993eSxy150489 	    len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
602c869993eSxy150489 	    DDI_DMA_DONTWAIT, NULL, &cookie, &cookie_num);
603c869993eSxy150489 
604c869993eSxy150489 	if (ret != DDI_DMA_MAPPED) {
605c869993eSxy150489 		buf->dma_address = NULL;
606c869993eSxy150489 		if (buf->acc_handle != NULL) {
607c869993eSxy150489 			ddi_dma_mem_free(&buf->acc_handle);
608c869993eSxy150489 			buf->acc_handle = NULL;
609c869993eSxy150489 			buf->address = NULL;
610c869993eSxy150489 		}
611c869993eSxy150489 		if (buf->dma_handle != NULL) {
612c869993eSxy150489 			ddi_dma_free_handle(&buf->dma_handle);
613c869993eSxy150489 			buf->dma_handle = NULL;
614c869993eSxy150489 		}
615*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
616c869993eSxy150489 		    "Could not bind dma buffer handle: %x", ret);
617c869993eSxy150489 		return (IGB_FAILURE);
618c869993eSxy150489 	}
619c869993eSxy150489 
620c869993eSxy150489 	ASSERT(cookie_num == 1);
621c869993eSxy150489 
622c869993eSxy150489 	buf->dma_address = cookie.dmac_laddress;
623c869993eSxy150489 	buf->size = len;
624c869993eSxy150489 	buf->len = 0;
625c869993eSxy150489 
626c869993eSxy150489 	return (IGB_SUCCESS);
627c869993eSxy150489 }
628c869993eSxy150489 
629c869993eSxy150489 /*
630c869993eSxy150489  * igb_free_dma_buffer - Free one allocated area of dma memory and handle
631c869993eSxy150489  */
632ac7f5757Schenlu chen - Sun Microsystems - Beijing China void
633c869993eSxy150489 igb_free_dma_buffer(dma_buffer_t *buf)
634c869993eSxy150489 {
635c869993eSxy150489 	if (buf->dma_handle != NULL) {
636c869993eSxy150489 		(void) ddi_dma_unbind_handle(buf->dma_handle);
637c869993eSxy150489 		buf->dma_address = NULL;
638c869993eSxy150489 	} else {
639c869993eSxy150489 		return;
640c869993eSxy150489 	}
641c869993eSxy150489 
642c869993eSxy150489 	if (buf->acc_handle != NULL) {
643c869993eSxy150489 		ddi_dma_mem_free(&buf->acc_handle);
644c869993eSxy150489 		buf->acc_handle = NULL;
645c869993eSxy150489 		buf->address = NULL;
646c869993eSxy150489 	}
647c869993eSxy150489 
648c869993eSxy150489 	if (buf->dma_handle != NULL) {
649c869993eSxy150489 		ddi_dma_free_handle(&buf->dma_handle);
650c869993eSxy150489 		buf->dma_handle = NULL;
651c869993eSxy150489 	}
652c869993eSxy150489 
653c869993eSxy150489 	buf->size = 0;
654c869993eSxy150489 	buf->len = 0;
655c869993eSxy150489 }
656c869993eSxy150489 
657c869993eSxy150489 /*
658c869993eSxy150489  * igb_alloc_tcb_lists - Memory allocation for the transmit control bolcks
659c869993eSxy150489  * of one ring.
660c869993eSxy150489  */
661c869993eSxy150489 static int
662c869993eSxy150489 igb_alloc_tcb_lists(igb_tx_ring_t *tx_ring)
663c869993eSxy150489 {
664c869993eSxy150489 	int i;
665c869993eSxy150489 	int ret;
666c869993eSxy150489 	tx_control_block_t *tcb;
667c869993eSxy150489 	dma_buffer_t *tx_buf;
668c869993eSxy150489 	igb_t *igb = tx_ring->igb;
669c869993eSxy150489 	dev_info_t *devinfo = igb->dip;
670c869993eSxy150489 
671c869993eSxy150489 	/*
672c869993eSxy150489 	 * Allocate memory for the work list.
673c869993eSxy150489 	 */
674c869993eSxy150489 	tx_ring->work_list = kmem_zalloc(sizeof (tx_control_block_t *) *
675c869993eSxy150489 	    tx_ring->ring_size, KM_NOSLEEP);
676c869993eSxy150489 
677c869993eSxy150489 	if (tx_ring->work_list == NULL) {
678*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
679c869993eSxy150489 		    "Cound not allocate memory for tx work list");
680c869993eSxy150489 		return (IGB_FAILURE);
681c869993eSxy150489 	}
682c869993eSxy150489 
683c869993eSxy150489 	/*
684c869993eSxy150489 	 * Allocate memory for the free list.
685c869993eSxy150489 	 */
686c869993eSxy150489 	tx_ring->free_list = kmem_zalloc(sizeof (tx_control_block_t *) *
687c869993eSxy150489 	    tx_ring->free_list_size, KM_NOSLEEP);
688c869993eSxy150489 
689c869993eSxy150489 	if (tx_ring->free_list == NULL) {
690c869993eSxy150489 		kmem_free(tx_ring->work_list,
691c869993eSxy150489 		    sizeof (tx_control_block_t *) * tx_ring->ring_size);
692c869993eSxy150489 		tx_ring->work_list = NULL;
693c869993eSxy150489 
694*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
695c869993eSxy150489 		    "Cound not allocate memory for tx free list");
696c869993eSxy150489 		return (IGB_FAILURE);
697c869993eSxy150489 	}
698c869993eSxy150489 
699c869993eSxy150489 	/*
700c869993eSxy150489 	 * Allocate memory for the tx control blocks of free list.
701c869993eSxy150489 	 */
702c869993eSxy150489 	tx_ring->tcb_area =
703c869993eSxy150489 	    kmem_zalloc(sizeof (tx_control_block_t) *
704c869993eSxy150489 	    tx_ring->free_list_size, KM_NOSLEEP);
705c869993eSxy150489 
706c869993eSxy150489 	if (tx_ring->tcb_area == NULL) {
707c869993eSxy150489 		kmem_free(tx_ring->work_list,
708c869993eSxy150489 		    sizeof (tx_control_block_t *) * tx_ring->ring_size);
709c869993eSxy150489 		tx_ring->work_list = NULL;
710c869993eSxy150489 
711c869993eSxy150489 		kmem_free(tx_ring->free_list,
712c869993eSxy150489 		    sizeof (tx_control_block_t *) * tx_ring->free_list_size);
713c869993eSxy150489 		tx_ring->free_list = NULL;
714c869993eSxy150489 
715*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
716c869993eSxy150489 		    "Cound not allocate memory for tx control blocks");
717c869993eSxy150489 		return (IGB_FAILURE);
718c869993eSxy150489 	}
719c869993eSxy150489 
720c869993eSxy150489 	/*
721c869993eSxy150489 	 * Allocate dma memory for the tx control block of free list.
722c869993eSxy150489 	 */
723c869993eSxy150489 	tcb = tx_ring->tcb_area;
724c869993eSxy150489 	for (i = 0; i < tx_ring->free_list_size; i++, tcb++) {
725c869993eSxy150489 		ASSERT(tcb != NULL);
726c869993eSxy150489 
727c869993eSxy150489 		tx_ring->free_list[i] = tcb;
728c869993eSxy150489 
729c869993eSxy150489 		/*
730c869993eSxy150489 		 * Pre-allocate dma handles for transmit. These dma handles
731c869993eSxy150489 		 * will be dynamically bound to the data buffers passed down
732c869993eSxy150489 		 * from the upper layers at the time of transmitting.
733c869993eSxy150489 		 */
734c869993eSxy150489 		ret = ddi_dma_alloc_handle(devinfo,
735c869993eSxy150489 		    &igb_tx_dma_attr,
736c869993eSxy150489 		    DDI_DMA_DONTWAIT, NULL,
737c869993eSxy150489 		    &tcb->tx_dma_handle);
738c869993eSxy150489 		if (ret != DDI_SUCCESS) {
739c869993eSxy150489 			tcb->tx_dma_handle = NULL;
740*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_ERROR,
741c869993eSxy150489 			    "Could not allocate tx dma handle: %x", ret);
742c869993eSxy150489 			goto alloc_tcb_lists_fail;
743c869993eSxy150489 		}
744c869993eSxy150489 
745c869993eSxy150489 		/*
746c869993eSxy150489 		 * Pre-allocate transmit buffers for packets that the
747c869993eSxy150489 		 * size is less than bcopy_thresh.
748c869993eSxy150489 		 */
749c869993eSxy150489 		tx_buf = &tcb->tx_buf;
750c869993eSxy150489 
751c869993eSxy150489 		ret = igb_alloc_dma_buffer(igb,
752c869993eSxy150489 		    tx_buf, igb->tx_buf_size);
753c869993eSxy150489 
754c869993eSxy150489 		if (ret != IGB_SUCCESS) {
755c869993eSxy150489 			ASSERT(tcb->tx_dma_handle != NULL);
756c869993eSxy150489 			ddi_dma_free_handle(&tcb->tx_dma_handle);
757c869993eSxy150489 			tcb->tx_dma_handle = NULL;
758*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_ERROR,
759*e5513923SYuri Pankov 			    "Allocate tx dma buffer failed");
760c869993eSxy150489 			goto alloc_tcb_lists_fail;
761c869993eSxy150489 		}
76269b2d733SGuoqing Zhu 		tcb->last_index = MAX_TX_RING_SIZE;
763c869993eSxy150489 	}
764c869993eSxy150489 
765c869993eSxy150489 	return (IGB_SUCCESS);
766c869993eSxy150489 
767c869993eSxy150489 alloc_tcb_lists_fail:
768c869993eSxy150489 	igb_free_tcb_lists(tx_ring);
769c869993eSxy150489 
770c869993eSxy150489 	return (IGB_FAILURE);
771c869993eSxy150489 }
772c869993eSxy150489 
773c869993eSxy150489 /*
774c869993eSxy150489  * igb_free_tcb_lists - Release the memory allocated for
775c869993eSxy150489  * the transmit control bolcks of one ring.
776c869993eSxy150489  */
777c869993eSxy150489 static void
778c869993eSxy150489 igb_free_tcb_lists(igb_tx_ring_t *tx_ring)
779c869993eSxy150489 {
780c869993eSxy150489 	int i;
781c869993eSxy150489 	tx_control_block_t *tcb;
782c869993eSxy150489 
783c869993eSxy150489 	tcb = tx_ring->tcb_area;
784c869993eSxy150489 	if (tcb == NULL)
785c869993eSxy150489 		return;
786c869993eSxy150489 
787c869993eSxy150489 	for (i = 0; i < tx_ring->free_list_size; i++, tcb++) {
788c869993eSxy150489 		ASSERT(tcb != NULL);
789c869993eSxy150489 
790c869993eSxy150489 		/* Free the tx dma handle for dynamical binding */
791c869993eSxy150489 		if (tcb->tx_dma_handle != NULL) {
792c869993eSxy150489 			ddi_dma_free_handle(&tcb->tx_dma_handle);
793c869993eSxy150489 			tcb->tx_dma_handle = NULL;
794c869993eSxy150489 		} else {
795c869993eSxy150489 			/*
796c869993eSxy150489 			 * If the dma handle is NULL, then we don't
797c869993eSxy150489 			 * have to check the remaining.
798c869993eSxy150489 			 */
799c869993eSxy150489 			break;
800c869993eSxy150489 		}
801c869993eSxy150489 
802c869993eSxy150489 		igb_free_dma_buffer(&tcb->tx_buf);
803c869993eSxy150489 	}
804c869993eSxy150489 
805c869993eSxy150489 	if (tx_ring->tcb_area != NULL) {
806c869993eSxy150489 		kmem_free(tx_ring->tcb_area,
807c869993eSxy150489 		    sizeof (tx_control_block_t) * tx_ring->free_list_size);
808c869993eSxy150489 		tx_ring->tcb_area = NULL;
809c869993eSxy150489 	}
810c869993eSxy150489 
811c869993eSxy150489 	if (tx_ring->work_list != NULL) {
812c869993eSxy150489 		kmem_free(tx_ring->work_list,
813c869993eSxy150489 		    sizeof (tx_control_block_t *) * tx_ring->ring_size);
814c869993eSxy150489 		tx_ring->work_list = NULL;
815c869993eSxy150489 	}
816c869993eSxy150489 
817c869993eSxy150489 	if (tx_ring->free_list != NULL) {
818c869993eSxy150489 		kmem_free(tx_ring->free_list,
819c869993eSxy150489 		    sizeof (tx_control_block_t *) * tx_ring->free_list_size);
820c869993eSxy150489 		tx_ring->free_list = NULL;
821c869993eSxy150489 	}
822c869993eSxy150489 }
823c869993eSxy150489 
824c869993eSxy150489 /*
825c869993eSxy150489  * igb_alloc_rcb_lists - Memory allocation for the receive control blocks
826c869993eSxy150489  * of one ring.
827c869993eSxy150489  */
828c869993eSxy150489 static int
829ac7f5757Schenlu chen - Sun Microsystems - Beijing China igb_alloc_rcb_lists(igb_rx_data_t *rx_data)
830c869993eSxy150489 {
831c869993eSxy150489 	int i;
832c869993eSxy150489 	int ret;
833c869993eSxy150489 	rx_control_block_t *rcb;
834ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_t *igb = rx_data->rx_ring->igb;
835c869993eSxy150489 	dma_buffer_t *rx_buf;
836c869993eSxy150489 	uint32_t rcb_count;
837c869993eSxy150489 
838c869993eSxy150489 	/*
839c869993eSxy150489 	 * Allocate memory for the rx control blocks for work list and
840c869993eSxy150489 	 * free list.
841c869993eSxy150489 	 */
842ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rcb_count = rx_data->ring_size + rx_data->free_list_size;
843ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rcb = rx_data->rcb_area;
844c869993eSxy150489 
845c869993eSxy150489 	for (i = 0; i < rcb_count; i++, rcb++) {
846c869993eSxy150489 		ASSERT(rcb != NULL);
847c869993eSxy150489 
848ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (i < rx_data->ring_size) {
849c869993eSxy150489 			/* Attach the rx control block to the work list */
850ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			rx_data->work_list[i] = rcb;
851c869993eSxy150489 		} else {
852c869993eSxy150489 			/* Attach the rx control block to the free list */
853ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			rx_data->free_list[i - rx_data->ring_size] = rcb;
854c869993eSxy150489 		}
855c869993eSxy150489 
856c869993eSxy150489 		rx_buf = &rcb->rx_buf;
857c869993eSxy150489 		ret = igb_alloc_dma_buffer(igb,
858c869993eSxy150489 		    rx_buf, igb->rx_buf_size);
859c869993eSxy150489 
860c869993eSxy150489 		if (ret != IGB_SUCCESS) {
861*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_ERROR,
862*e5513923SYuri Pankov 			    "Allocate rx dma buffer failed");
863c869993eSxy150489 			goto alloc_rcb_lists_fail;
864c869993eSxy150489 		}
865c869993eSxy150489 
866c869993eSxy150489 		rx_buf->size -= IPHDR_ALIGN_ROOM;
867c869993eSxy150489 		rx_buf->address += IPHDR_ALIGN_ROOM;
868c869993eSxy150489 		rx_buf->dma_address += IPHDR_ALIGN_ROOM;
869c869993eSxy150489 
870ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rcb->ref_cnt = 1;
871ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rcb->rx_data = (igb_rx_data_t *)rx_data;
872c869993eSxy150489 		rcb->free_rtn.free_func = igb_rx_recycle;
873c869993eSxy150489 		rcb->free_rtn.free_arg = (char *)rcb;
874c869993eSxy150489 
875c869993eSxy150489 		rcb->mp = desballoc((unsigned char *)
87680a11ad2Schenlu chen - Sun Microsystems - Beijing China 		    rx_buf->address,
87780a11ad2Schenlu chen - Sun Microsystems - Beijing China 		    rx_buf->size,
878c869993eSxy150489 		    0, &rcb->free_rtn);
879c869993eSxy150489 	}
880c869993eSxy150489 
881c869993eSxy150489 	return (IGB_SUCCESS);
882c869993eSxy150489 
883c869993eSxy150489 alloc_rcb_lists_fail:
884ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_free_rcb_lists(rx_data);
885c869993eSxy150489 
886c869993eSxy150489 	return (IGB_FAILURE);
887c869993eSxy150489 }
888c869993eSxy150489 
889c869993eSxy150489 /*
890c869993eSxy150489  * igb_free_rcb_lists - Free the receive control blocks of one ring.
891c869993eSxy150489  */
892c869993eSxy150489 static void
893ac7f5757Schenlu chen - Sun Microsystems - Beijing China igb_free_rcb_lists(igb_rx_data_t *rx_data)
894c869993eSxy150489 {
895ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_t *igb;
896c869993eSxy150489 	rx_control_block_t *rcb;
897c869993eSxy150489 	uint32_t rcb_count;
898ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	uint32_t ref_cnt;
899ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	int i;
900c869993eSxy150489 
901ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb = rx_data->rx_ring->igb;
902c869993eSxy150489 
903ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	mutex_enter(&igb->rx_pending_lock);
904ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
905ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rcb = rx_data->rcb_area;
906ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rcb_count = rx_data->ring_size + rx_data->free_list_size;
907ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
908c869993eSxy150489 	for (i = 0; i < rcb_count; i++, rcb++) {
909c869993eSxy150489 		ASSERT(rcb != NULL);
910c869993eSxy150489 
911ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		ref_cnt = atomic_dec_32_nv(&rcb->ref_cnt);
912ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (ref_cnt == 0) {
913c869993eSxy150489 			if (rcb->mp != NULL) {
914c869993eSxy150489 				freemsg(rcb->mp);
915c869993eSxy150489 				rcb->mp = NULL;
916c869993eSxy150489 			}
917c869993eSxy150489 			igb_free_dma_buffer(&rcb->rx_buf);
918ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		} else {
919ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			atomic_inc_32(&rx_data->rcb_pending);
920ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			atomic_inc_32(&igb->rcb_pending);
921ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		}
922c869993eSxy150489 	}
923c869993eSxy150489 
924ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	mutex_exit(&igb->rx_pending_lock);
925c869993eSxy150489 }
9268bb4b220Sgl147354 
9278bb4b220Sgl147354 void
928837c1ac4SStephen Hanson igb_set_fma_flags(int dma_flag)
9298bb4b220Sgl147354 {
9308bb4b220Sgl147354 	if (dma_flag) {
9318bb4b220Sgl147354 		igb_tx_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
9328bb4b220Sgl147354 		igb_buf_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
9338bb4b220Sgl147354 		igb_desc_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
9348bb4b220Sgl147354 	} else {
9358bb4b220Sgl147354 		igb_tx_dma_attr.dma_attr_flags = 0;
9368bb4b220Sgl147354 		igb_buf_dma_attr.dma_attr_flags = 0;
9378bb4b220Sgl147354 		igb_desc_dma_attr.dma_attr_flags = 0;
9388bb4b220Sgl147354 	}
9398bb4b220Sgl147354 }
940