xref: /titanic_51/usr/src/uts/common/io/e1000g/e1000g_alloc.c (revision bcfab0594401266bd287f71573312d8af05de184)
108057504Sxy150489 /*
208057504Sxy150489  * This file is provided under a CDDLv1 license.  When using or
308057504Sxy150489  * redistributing this file, you may do so under this license.
408057504Sxy150489  * In redistributing this file this license must be included
508057504Sxy150489  * and no other modification of this header file is permitted.
608057504Sxy150489  *
708057504Sxy150489  * CDDL LICENSE SUMMARY
808057504Sxy150489  *
954e0d7a5SMiles Xu, Sun Microsystems  * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
1008057504Sxy150489  *
1108057504Sxy150489  * The contents of this file are subject to the terms of Version
1208057504Sxy150489  * 1.0 of the Common Development and Distribution License (the "License").
1308057504Sxy150489  *
1408057504Sxy150489  * You should have received a copy of the License with this software.
1508057504Sxy150489  * You can obtain a copy of the License at
1608057504Sxy150489  *	http://www.opensolaris.org/os/licensing.
1708057504Sxy150489  * See the License for the specific language governing permissions
1808057504Sxy150489  * and limitations under the License.
1908057504Sxy150489  */
2008057504Sxy150489 
2108057504Sxy150489 /*
223fb4efefSchangqing li - Sun Microsystems - Beijing China  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2308057504Sxy150489  */
2408057504Sxy150489 
2508057504Sxy150489 /*
2608057504Sxy150489  * **********************************************************************
2708057504Sxy150489  * Module Name:								*
2825f2d433Sxy150489  *   e1000g_alloc.c							*
2908057504Sxy150489  *									*
3008057504Sxy150489  * Abstract:								*
3125f2d433Sxy150489  *   This file contains some routines that take care of			*
3225f2d433Sxy150489  *   memory allocation for descriptors and buffers.			*
3308057504Sxy150489  *									*
3408057504Sxy150489  * **********************************************************************
3508057504Sxy150489  */
3608057504Sxy150489 
3708057504Sxy150489 #include "e1000g_sw.h"
3808057504Sxy150489 #include "e1000g_debug.h"
3908057504Sxy150489 
4008057504Sxy150489 #define	TX_SW_PKT_AREA_SZ \
4125f2d433Sxy150489 	(sizeof (tx_sw_packet_t) * Adapter->tx_freelist_num)
4208057504Sxy150489 
4308057504Sxy150489 static int e1000g_alloc_tx_descriptors(e1000g_tx_ring_t *);
4454e0d7a5SMiles Xu, Sun Microsystems static int e1000g_alloc_rx_descriptors(e1000g_rx_data_t *);
4508057504Sxy150489 static void e1000g_free_tx_descriptors(e1000g_tx_ring_t *);
4654e0d7a5SMiles Xu, Sun Microsystems static void e1000g_free_rx_descriptors(e1000g_rx_data_t *);
4708057504Sxy150489 static int e1000g_alloc_tx_packets(e1000g_tx_ring_t *);
4854e0d7a5SMiles Xu, Sun Microsystems static int e1000g_alloc_rx_packets(e1000g_rx_data_t *);
4908057504Sxy150489 static void e1000g_free_tx_packets(e1000g_tx_ring_t *);
503fb4efefSchangqing li - Sun Microsystems - Beijing China static void e1000g_free_rx_packets(e1000g_rx_data_t *, boolean_t);
5125f2d433Sxy150489 static int e1000g_alloc_dma_buffer(struct e1000g *,
5225f2d433Sxy150489     dma_buffer_t *, size_t, ddi_dma_attr_t *p_dma_attr);
53ede5269eSchenlu chen - Sun Microsystems - Beijing China 
54ede5269eSchenlu chen - Sun Microsystems - Beijing China /*
55ede5269eSchenlu chen - Sun Microsystems - Beijing China  * In order to avoid address error crossing 64KB boundary
56ede5269eSchenlu chen - Sun Microsystems - Beijing China  * during PCI-X packets receving, e1000g_alloc_dma_buffer_82546
57ede5269eSchenlu chen - Sun Microsystems - Beijing China  * is used by some necessary adapter types.
58ede5269eSchenlu chen - Sun Microsystems - Beijing China  */
59ede5269eSchenlu chen - Sun Microsystems - Beijing China static int e1000g_alloc_dma_buffer_82546(struct e1000g *,
60ede5269eSchenlu chen - Sun Microsystems - Beijing China     dma_buffer_t *, size_t, ddi_dma_attr_t *p_dma_attr);
61ede5269eSchenlu chen - Sun Microsystems - Beijing China static int e1000g_dma_mem_alloc_82546(dma_buffer_t *buf,
62ede5269eSchenlu chen - Sun Microsystems - Beijing China     size_t size, size_t *len);
63ede5269eSchenlu chen - Sun Microsystems - Beijing China static boolean_t e1000g_cross_64k_bound(void *, uintptr_t);
64ede5269eSchenlu chen - Sun Microsystems - Beijing China 
6508057504Sxy150489 static void e1000g_free_dma_buffer(dma_buffer_t *);
6608057504Sxy150489 #ifdef __sparc
6708057504Sxy150489 static int e1000g_alloc_dvma_buffer(struct e1000g *, dma_buffer_t *, size_t);
6808057504Sxy150489 static void e1000g_free_dvma_buffer(dma_buffer_t *);
6908057504Sxy150489 #endif
7008057504Sxy150489 static int e1000g_alloc_descriptors(struct e1000g *Adapter);
7125f2d433Sxy150489 static void e1000g_free_descriptors(struct e1000g *Adapter);
7208057504Sxy150489 static int e1000g_alloc_packets(struct e1000g *Adapter);
7325f2d433Sxy150489 static void e1000g_free_packets(struct e1000g *Adapter);
7454e0d7a5SMiles Xu, Sun Microsystems static p_rx_sw_packet_t e1000g_alloc_rx_sw_packet(e1000g_rx_data_t *,
7525f2d433Sxy150489     ddi_dma_attr_t *p_dma_attr);
7625f2d433Sxy150489 
7725f2d433Sxy150489 /* DMA access attributes for descriptors <Little Endian> */
7825f2d433Sxy150489 static ddi_device_acc_attr_t e1000g_desc_acc_attr = {
7925f2d433Sxy150489 	DDI_DEVICE_ATTR_V0,
8025f2d433Sxy150489 	DDI_STRUCTURE_LE_ACC,
81837c1ac4SStephen Hanson 	DDI_STRICTORDER_ACC
8225f2d433Sxy150489 };
8325f2d433Sxy150489 
8425f2d433Sxy150489 /* DMA access attributes for DMA buffers */
8525f2d433Sxy150489 #ifdef __sparc
8625f2d433Sxy150489 static ddi_device_acc_attr_t e1000g_buf_acc_attr = {
8725f2d433Sxy150489 	DDI_DEVICE_ATTR_V0,
8825f2d433Sxy150489 	DDI_STRUCTURE_BE_ACC,
8925f2d433Sxy150489 	DDI_STRICTORDER_ACC,
9025f2d433Sxy150489 };
9125f2d433Sxy150489 #else
9225f2d433Sxy150489 static ddi_device_acc_attr_t e1000g_buf_acc_attr = {
9325f2d433Sxy150489 	DDI_DEVICE_ATTR_V0,
9425f2d433Sxy150489 	DDI_STRUCTURE_LE_ACC,
9525f2d433Sxy150489 	DDI_STRICTORDER_ACC,
9625f2d433Sxy150489 };
9725f2d433Sxy150489 #endif
9825f2d433Sxy150489 
9925f2d433Sxy150489 /* DMA attributes for tx mblk buffers */
10025f2d433Sxy150489 static ddi_dma_attr_t e1000g_tx_dma_attr = {
10125f2d433Sxy150489 	DMA_ATTR_V0,		/* version of this structure */
10225f2d433Sxy150489 	0,			/* lowest usable address */
10325f2d433Sxy150489 	0xffffffffffffffffULL,	/* highest usable address */
10425f2d433Sxy150489 	0x7fffffff,		/* maximum DMAable byte count */
10525f2d433Sxy150489 	1,			/* alignment in bytes */
10625f2d433Sxy150489 	0x7ff,			/* burst sizes (any?) */
10725f2d433Sxy150489 	1,			/* minimum transfer */
10825f2d433Sxy150489 	0xffffffffU,		/* maximum transfer */
10925f2d433Sxy150489 	0xffffffffffffffffULL,	/* maximum segment length */
1104d737963Sxiangtao you - Sun Microsystems - Beijing China 	MAX_COOKIES,		/* maximum number of segments */
11125f2d433Sxy150489 	1,			/* granularity */
1129b6541b3Sgl147354 	DDI_DMA_FLAGERR,	/* dma_attr_flags */
11325f2d433Sxy150489 };
11425f2d433Sxy150489 
11525f2d433Sxy150489 /* DMA attributes for pre-allocated rx/tx buffers */
11625f2d433Sxy150489 static ddi_dma_attr_t e1000g_buf_dma_attr = {
11725f2d433Sxy150489 	DMA_ATTR_V0,		/* version of this structure */
11825f2d433Sxy150489 	0,			/* lowest usable address */
11925f2d433Sxy150489 	0xffffffffffffffffULL,	/* highest usable address */
12025f2d433Sxy150489 	0x7fffffff,		/* maximum DMAable byte count */
12125f2d433Sxy150489 	1,			/* alignment in bytes */
12225f2d433Sxy150489 	0x7ff,			/* burst sizes (any?) */
12325f2d433Sxy150489 	1,			/* minimum transfer */
12425f2d433Sxy150489 	0xffffffffU,		/* maximum transfer */
12525f2d433Sxy150489 	0xffffffffffffffffULL,	/* maximum segment length */
12625f2d433Sxy150489 	1,			/* maximum number of segments */
12725f2d433Sxy150489 	1,			/* granularity */
1289b6541b3Sgl147354 	DDI_DMA_FLAGERR,	/* dma_attr_flags */
12925f2d433Sxy150489 };
13025f2d433Sxy150489 
13125f2d433Sxy150489 /* DMA attributes for rx/tx descriptors */
13225f2d433Sxy150489 static ddi_dma_attr_t e1000g_desc_dma_attr = {
13325f2d433Sxy150489 	DMA_ATTR_V0,		/* version of this structure */
13425f2d433Sxy150489 	0,			/* lowest usable address */
13525f2d433Sxy150489 	0xffffffffffffffffULL,	/* highest usable address */
13625f2d433Sxy150489 	0x7fffffff,		/* maximum DMAable byte count */
137ede5269eSchenlu chen - Sun Microsystems - Beijing China 	E1000_MDALIGN,		/* default alignment is 4k but can be changed */
13825f2d433Sxy150489 	0x7ff,			/* burst sizes (any?) */
13925f2d433Sxy150489 	1,			/* minimum transfer */
14025f2d433Sxy150489 	0xffffffffU,		/* maximum transfer */
14125f2d433Sxy150489 	0xffffffffffffffffULL,	/* maximum segment length */
14225f2d433Sxy150489 	1,			/* maximum number of segments */
14325f2d433Sxy150489 	1,			/* granularity */
1449b6541b3Sgl147354 	DDI_DMA_FLAGERR,	/* dma_attr_flags */
14525f2d433Sxy150489 };
14608057504Sxy150489 
14708057504Sxy150489 #ifdef __sparc
14808057504Sxy150489 static ddi_dma_lim_t e1000g_dma_limits = {
14908057504Sxy150489 	(uint_t)0,		/* dlim_addr_lo */
15008057504Sxy150489 	(uint_t)0xffffffff,	/* dlim_addr_hi */
15108057504Sxy150489 	(uint_t)0xffffffff,	/* dlim_cntr_max */
15208057504Sxy150489 	(uint_t)0xfc00fc,	/* dlim_burstsizes for 32 and 64 bit xfers */
15308057504Sxy150489 	0x1,			/* dlim_minxfer */
15408057504Sxy150489 	1024			/* dlim_speed */
15508057504Sxy150489 };
15608057504Sxy150489 #endif
15708057504Sxy150489 
15808057504Sxy150489 #ifdef __sparc
15908057504Sxy150489 static dma_type_t e1000g_dma_type = USE_DVMA;
16008057504Sxy150489 #else
16108057504Sxy150489 static dma_type_t e1000g_dma_type = USE_DMA;
16208057504Sxy150489 #endif
16308057504Sxy150489 
16408057504Sxy150489 extern krwlock_t e1000g_dma_type_lock;
16508057504Sxy150489 
16625f2d433Sxy150489 
16708057504Sxy150489 int
16808057504Sxy150489 e1000g_alloc_dma_resources(struct e1000g *Adapter)
16908057504Sxy150489 {
17025f2d433Sxy150489 	int result;
17108057504Sxy150489 
17225f2d433Sxy150489 	result = DDI_FAILURE;
17308057504Sxy150489 
17425f2d433Sxy150489 	while ((result != DDI_SUCCESS) &&
17525f2d433Sxy150489 	    (Adapter->tx_desc_num >= MIN_NUM_TX_DESCRIPTOR) &&
17625f2d433Sxy150489 	    (Adapter->rx_desc_num >= MIN_NUM_RX_DESCRIPTOR) &&
1773fb4efefSchangqing li - Sun Microsystems - Beijing China 	    (Adapter->tx_freelist_num >= MIN_NUM_TX_FREELIST)) {
17808057504Sxy150489 
17925f2d433Sxy150489 		result = e1000g_alloc_descriptors(Adapter);
18008057504Sxy150489 
18125f2d433Sxy150489 		if (result == DDI_SUCCESS) {
18225f2d433Sxy150489 			result = e1000g_alloc_packets(Adapter);
18325f2d433Sxy150489 
18425f2d433Sxy150489 			if (result != DDI_SUCCESS)
18525f2d433Sxy150489 				e1000g_free_descriptors(Adapter);
18608057504Sxy150489 		}
18708057504Sxy150489 
18808057504Sxy150489 		/*
18925f2d433Sxy150489 		 * If the allocation fails due to resource shortage,
19025f2d433Sxy150489 		 * we'll reduce the numbers of descriptors/buffers by
19125f2d433Sxy150489 		 * half, and try the allocation again.
19225f2d433Sxy150489 		 */
19325f2d433Sxy150489 		if (result != DDI_SUCCESS) {
19425f2d433Sxy150489 			/*
19525f2d433Sxy150489 			 * We must ensure the number of descriptors
19625f2d433Sxy150489 			 * is always a multiple of 8.
19725f2d433Sxy150489 			 */
19825f2d433Sxy150489 			Adapter->tx_desc_num =
19925f2d433Sxy150489 			    (Adapter->tx_desc_num >> 4) << 3;
20025f2d433Sxy150489 			Adapter->rx_desc_num =
20125f2d433Sxy150489 			    (Adapter->rx_desc_num >> 4) << 3;
20225f2d433Sxy150489 
20325f2d433Sxy150489 			Adapter->tx_freelist_num >>= 1;
20425f2d433Sxy150489 		}
20525f2d433Sxy150489 	}
20625f2d433Sxy150489 
20725f2d433Sxy150489 	return (result);
20825f2d433Sxy150489 }
20925f2d433Sxy150489 
21025f2d433Sxy150489 /*
21125f2d433Sxy150489  * e1000g_alloc_descriptors - allocate DMA buffers for descriptors
21225f2d433Sxy150489  *
21325f2d433Sxy150489  * This routine allocates neccesary DMA buffers for
21425f2d433Sxy150489  *	Transmit Descriptor Area
21525f2d433Sxy150489  *	Receive Descrpitor Area
21608057504Sxy150489  */
21708057504Sxy150489 static int
21808057504Sxy150489 e1000g_alloc_descriptors(struct e1000g *Adapter)
21908057504Sxy150489 {
22008057504Sxy150489 	int result;
22108057504Sxy150489 	e1000g_tx_ring_t *tx_ring;
22254e0d7a5SMiles Xu, Sun Microsystems 	e1000g_rx_data_t *rx_data;
22308057504Sxy150489 
2243d15c084Schenlu chen - Sun Microsystems - Beijing China 	if (Adapter->mem_workaround_82546 &&
2253d15c084Schenlu chen - Sun Microsystems - Beijing China 	    ((Adapter->shared.mac.type == e1000_82545) ||
226ede5269eSchenlu chen - Sun Microsystems - Beijing China 	    (Adapter->shared.mac.type == e1000_82546) ||
2273d15c084Schenlu chen - Sun Microsystems - Beijing China 	    (Adapter->shared.mac.type == e1000_82546_rev_3))) {
228ede5269eSchenlu chen - Sun Microsystems - Beijing China 		/* Align on a 64k boundary for these adapter types */
229ede5269eSchenlu chen - Sun Microsystems - Beijing China 		Adapter->desc_align = E1000_MDALIGN_82546;
230ede5269eSchenlu chen - Sun Microsystems - Beijing China 	} else {
231ede5269eSchenlu chen - Sun Microsystems - Beijing China 		/* Align on a 4k boundary for all other adapter types */
232ede5269eSchenlu chen - Sun Microsystems - Beijing China 		Adapter->desc_align = E1000_MDALIGN;
233ede5269eSchenlu chen - Sun Microsystems - Beijing China 	}
234ede5269eSchenlu chen - Sun Microsystems - Beijing China 
23508057504Sxy150489 	tx_ring = Adapter->tx_ring;
23608057504Sxy150489 
23708057504Sxy150489 	result = e1000g_alloc_tx_descriptors(tx_ring);
23808057504Sxy150489 	if (result != DDI_SUCCESS)
23908057504Sxy150489 		return (DDI_FAILURE);
24008057504Sxy150489 
24154e0d7a5SMiles Xu, Sun Microsystems 	rx_data = Adapter->rx_ring->rx_data;
24208057504Sxy150489 
24354e0d7a5SMiles Xu, Sun Microsystems 	result = e1000g_alloc_rx_descriptors(rx_data);
24408057504Sxy150489 	if (result != DDI_SUCCESS) {
24508057504Sxy150489 		e1000g_free_tx_descriptors(tx_ring);
24608057504Sxy150489 		return (DDI_FAILURE);
24708057504Sxy150489 	}
24808057504Sxy150489 
24908057504Sxy150489 	return (DDI_SUCCESS);
25008057504Sxy150489 }
25108057504Sxy150489 
25225f2d433Sxy150489 static void
25325f2d433Sxy150489 e1000g_free_descriptors(struct e1000g *Adapter)
25425f2d433Sxy150489 {
25525f2d433Sxy150489 	e1000g_tx_ring_t *tx_ring;
25654e0d7a5SMiles Xu, Sun Microsystems 	e1000g_rx_data_t *rx_data;
25725f2d433Sxy150489 
25825f2d433Sxy150489 	tx_ring = Adapter->tx_ring;
25954e0d7a5SMiles Xu, Sun Microsystems 	rx_data = Adapter->rx_ring->rx_data;
26025f2d433Sxy150489 
26125f2d433Sxy150489 	e1000g_free_tx_descriptors(tx_ring);
26254e0d7a5SMiles Xu, Sun Microsystems 	e1000g_free_rx_descriptors(rx_data);
26325f2d433Sxy150489 }
26425f2d433Sxy150489 
26508057504Sxy150489 static int
26608057504Sxy150489 e1000g_alloc_tx_descriptors(e1000g_tx_ring_t *tx_ring)
26708057504Sxy150489 {
26808057504Sxy150489 	int mystat;
26908057504Sxy150489 	boolean_t alloc_flag;
27008057504Sxy150489 	size_t size;
27108057504Sxy150489 	size_t len;
27208057504Sxy150489 	uintptr_t templong;
27308057504Sxy150489 	uint_t cookie_count;
27408057504Sxy150489 	dev_info_t *devinfo;
27508057504Sxy150489 	ddi_dma_cookie_t cookie;
27608057504Sxy150489 	struct e1000g *Adapter;
27725f2d433Sxy150489 	ddi_dma_attr_t dma_attr;
27808057504Sxy150489 
27908057504Sxy150489 	Adapter = tx_ring->adapter;
28025f2d433Sxy150489 	devinfo = Adapter->dip;
28108057504Sxy150489 
28208057504Sxy150489 	alloc_flag = B_FALSE;
28325f2d433Sxy150489 	dma_attr = e1000g_desc_dma_attr;
28408057504Sxy150489 
28508057504Sxy150489 	/*
28608057504Sxy150489 	 * Solaris 7 has a problem with allocating physically contiguous memory
28708057504Sxy150489 	 * that is aligned on a 4K boundary. The transmit and rx descriptors
28808057504Sxy150489 	 * need to aligned on a 4kbyte boundary. We first try to allocate the
28908057504Sxy150489 	 * memory with DMA attributes set to 4K alignment and also no scatter/
29008057504Sxy150489 	 * gather mechanism specified. In most cases, this does not allocate
29108057504Sxy150489 	 * memory aligned at a 4Kbyte boundary. We then try asking for memory
29208057504Sxy150489 	 * aligned on 4K boundary with scatter/gather set to 2. This works when
29308057504Sxy150489 	 * the amount of memory is less than 4k i.e a page size. If neither of
29408057504Sxy150489 	 * these options work or if the number of descriptors is greater than
29508057504Sxy150489 	 * 4K, ie more than 256 descriptors, we allocate 4k extra memory and
29608057504Sxy150489 	 * and then align the memory at a 4k boundary.
29708057504Sxy150489 	 */
29825f2d433Sxy150489 	size = sizeof (struct e1000_tx_desc) * Adapter->tx_desc_num;
29908057504Sxy150489 
30008057504Sxy150489 	/*
30108057504Sxy150489 	 * Memory allocation for the transmit buffer descriptors.
30208057504Sxy150489 	 */
30325f2d433Sxy150489 	dma_attr.dma_attr_sgllen = 1;
304ede5269eSchenlu chen - Sun Microsystems - Beijing China 	dma_attr.dma_attr_align = Adapter->desc_align;
30508057504Sxy150489 
30608057504Sxy150489 	/*
30708057504Sxy150489 	 * Allocate a new DMA handle for the transmit descriptor
30808057504Sxy150489 	 * memory area.
30908057504Sxy150489 	 */
31025f2d433Sxy150489 	mystat = ddi_dma_alloc_handle(devinfo, &dma_attr,
31108057504Sxy150489 	    DDI_DMA_DONTWAIT, 0,
31208057504Sxy150489 	    &tx_ring->tbd_dma_handle);
31308057504Sxy150489 
31408057504Sxy150489 	if (mystat != DDI_SUCCESS) {
31525f2d433Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
31608057504Sxy150489 		    "Could not allocate tbd dma handle: %d", mystat);
31708057504Sxy150489 		tx_ring->tbd_dma_handle = NULL;
31808057504Sxy150489 		return (DDI_FAILURE);
31908057504Sxy150489 	}
32008057504Sxy150489 
32108057504Sxy150489 	/*
32208057504Sxy150489 	 * Allocate memory to DMA data to and from the transmit
32308057504Sxy150489 	 * descriptors.
32408057504Sxy150489 	 */
32508057504Sxy150489 	mystat = ddi_dma_mem_alloc(tx_ring->tbd_dma_handle,
32608057504Sxy150489 	    size,
32725f2d433Sxy150489 	    &e1000g_desc_acc_attr, DDI_DMA_CONSISTENT,
32808057504Sxy150489 	    DDI_DMA_DONTWAIT, 0,
32908057504Sxy150489 	    (caddr_t *)&tx_ring->tbd_area,
33008057504Sxy150489 	    &len, &tx_ring->tbd_acc_handle);
33108057504Sxy150489 
33208057504Sxy150489 	if ((mystat != DDI_SUCCESS) ||
333ede5269eSchenlu chen - Sun Microsystems - Beijing China 	    ((uintptr_t)tx_ring->tbd_area & (Adapter->desc_align - 1))) {
33408057504Sxy150489 		if (mystat == DDI_SUCCESS) {
33508057504Sxy150489 			ddi_dma_mem_free(&tx_ring->tbd_acc_handle);
33608057504Sxy150489 			tx_ring->tbd_acc_handle = NULL;
33708057504Sxy150489 			tx_ring->tbd_area = NULL;
33808057504Sxy150489 		}
33908057504Sxy150489 		if (tx_ring->tbd_dma_handle != NULL) {
34008057504Sxy150489 			ddi_dma_free_handle(&tx_ring->tbd_dma_handle);
34108057504Sxy150489 			tx_ring->tbd_dma_handle = NULL;
34208057504Sxy150489 		}
34308057504Sxy150489 		alloc_flag = B_FALSE;
34408057504Sxy150489 	} else
34508057504Sxy150489 		alloc_flag = B_TRUE;
34608057504Sxy150489 
34708057504Sxy150489 	/*
34808057504Sxy150489 	 * Initialize the entire transmit buffer descriptor area to zero
34908057504Sxy150489 	 */
35008057504Sxy150489 	if (alloc_flag)
35108057504Sxy150489 		bzero(tx_ring->tbd_area, len);
35208057504Sxy150489 
35308057504Sxy150489 	/*
35408057504Sxy150489 	 * If the previous DMA attributes setting could not give us contiguous
35508057504Sxy150489 	 * memory or the number of descriptors is greater than the page size,
356ede5269eSchenlu chen - Sun Microsystems - Beijing China 	 * we allocate extra memory and then align it at appropriate boundary.
35708057504Sxy150489 	 */
35808057504Sxy150489 	if (!alloc_flag) {
359ede5269eSchenlu chen - Sun Microsystems - Beijing China 		size = size + Adapter->desc_align;
36008057504Sxy150489 
36108057504Sxy150489 		/*
36208057504Sxy150489 		 * DMA attributes set to no scatter/gather and 16 bit alignment
36308057504Sxy150489 		 */
36425f2d433Sxy150489 		dma_attr.dma_attr_align = 1;
36525f2d433Sxy150489 		dma_attr.dma_attr_sgllen = 1;
36608057504Sxy150489 
36708057504Sxy150489 		/*
36808057504Sxy150489 		 * Allocate a new DMA handle for the transmit descriptor memory
36908057504Sxy150489 		 * area.
37008057504Sxy150489 		 */
37125f2d433Sxy150489 		mystat = ddi_dma_alloc_handle(devinfo, &dma_attr,
37208057504Sxy150489 		    DDI_DMA_DONTWAIT, 0,
37308057504Sxy150489 		    &tx_ring->tbd_dma_handle);
37408057504Sxy150489 
37508057504Sxy150489 		if (mystat != DDI_SUCCESS) {
37625f2d433Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
37708057504Sxy150489 			    "Could not re-allocate tbd dma handle: %d", mystat);
37808057504Sxy150489 			tx_ring->tbd_dma_handle = NULL;
37908057504Sxy150489 			return (DDI_FAILURE);
38008057504Sxy150489 		}
38108057504Sxy150489 
38208057504Sxy150489 		/*
38308057504Sxy150489 		 * Allocate memory to DMA data to and from the transmit
38408057504Sxy150489 		 * descriptors.
38508057504Sxy150489 		 */
38608057504Sxy150489 		mystat = ddi_dma_mem_alloc(tx_ring->tbd_dma_handle,
38708057504Sxy150489 		    size,
38825f2d433Sxy150489 		    &e1000g_desc_acc_attr, DDI_DMA_CONSISTENT,
38908057504Sxy150489 		    DDI_DMA_DONTWAIT, 0,
39008057504Sxy150489 		    (caddr_t *)&tx_ring->tbd_area,
39108057504Sxy150489 		    &len, &tx_ring->tbd_acc_handle);
39208057504Sxy150489 
39308057504Sxy150489 		if (mystat != DDI_SUCCESS) {
39425f2d433Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
39508057504Sxy150489 			    "Could not allocate tbd dma memory: %d", mystat);
39608057504Sxy150489 			tx_ring->tbd_acc_handle = NULL;
39708057504Sxy150489 			tx_ring->tbd_area = NULL;
39808057504Sxy150489 			if (tx_ring->tbd_dma_handle != NULL) {
39908057504Sxy150489 				ddi_dma_free_handle(&tx_ring->tbd_dma_handle);
40008057504Sxy150489 				tx_ring->tbd_dma_handle = NULL;
40108057504Sxy150489 			}
40208057504Sxy150489 			return (DDI_FAILURE);
40308057504Sxy150489 		} else
40408057504Sxy150489 			alloc_flag = B_TRUE;
40508057504Sxy150489 
40608057504Sxy150489 		/*
40708057504Sxy150489 		 * Initialize the entire transmit buffer descriptor area to zero
40808057504Sxy150489 		 */
40908057504Sxy150489 		bzero(tx_ring->tbd_area, len);
41008057504Sxy150489 		/*
41108057504Sxy150489 		 * Memory has been allocated with the ddi_dma_mem_alloc call,
412ede5269eSchenlu chen - Sun Microsystems - Beijing China 		 * but has not been aligned.
413ede5269eSchenlu chen - Sun Microsystems - Beijing China 		 * We now align it on the appropriate boundary.
41408057504Sxy150489 		 */
415ede5269eSchenlu chen - Sun Microsystems - Beijing China 		templong = P2NPHASE((uintptr_t)tx_ring->tbd_area,
416ede5269eSchenlu chen - Sun Microsystems - Beijing China 		    Adapter->desc_align);
41708057504Sxy150489 		len = size - templong;
41808057504Sxy150489 		templong += (uintptr_t)tx_ring->tbd_area;
41908057504Sxy150489 		tx_ring->tbd_area = (struct e1000_tx_desc *)templong;
42008057504Sxy150489 	}	/* alignment workaround */
42108057504Sxy150489 
42208057504Sxy150489 	/*
42308057504Sxy150489 	 * Transmit buffer descriptor memory allocation succeeded
42408057504Sxy150489 	 */
42508057504Sxy150489 	ASSERT(alloc_flag);
42608057504Sxy150489 
42708057504Sxy150489 	/*
42808057504Sxy150489 	 * Allocates DMA resources for the memory that was allocated by
42908057504Sxy150489 	 * the ddi_dma_mem_alloc call. The DMA resources then get bound to the
43008057504Sxy150489 	 * the memory address
43108057504Sxy150489 	 */
43208057504Sxy150489 	mystat = ddi_dma_addr_bind_handle(tx_ring->tbd_dma_handle,
43308057504Sxy150489 	    (struct as *)NULL, (caddr_t)tx_ring->tbd_area,
43408057504Sxy150489 	    len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
43525f2d433Sxy150489 	    DDI_DMA_DONTWAIT, 0, &cookie, &cookie_count);
43608057504Sxy150489 
43708057504Sxy150489 	if (mystat != DDI_SUCCESS) {
43825f2d433Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
43908057504Sxy150489 		    "Could not bind tbd dma resource: %d", mystat);
44008057504Sxy150489 		if (tx_ring->tbd_acc_handle != NULL) {
44108057504Sxy150489 			ddi_dma_mem_free(&tx_ring->tbd_acc_handle);
44208057504Sxy150489 			tx_ring->tbd_acc_handle = NULL;
44308057504Sxy150489 			tx_ring->tbd_area = NULL;
44408057504Sxy150489 		}
44508057504Sxy150489 		if (tx_ring->tbd_dma_handle != NULL) {
44608057504Sxy150489 			ddi_dma_free_handle(&tx_ring->tbd_dma_handle);
44708057504Sxy150489 			tx_ring->tbd_dma_handle = NULL;
44808057504Sxy150489 		}
44908057504Sxy150489 		return (DDI_FAILURE);
45008057504Sxy150489 	}
45108057504Sxy150489 
45208057504Sxy150489 	ASSERT(cookie_count == 1);	/* 1 cookie */
45308057504Sxy150489 
45408057504Sxy150489 	if (cookie_count != 1) {
45525f2d433Sxy150489 		E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL,
45608057504Sxy150489 		    "Could not bind tbd dma resource in a single frag. "
45708057504Sxy150489 		    "Count - %d Len - %d", cookie_count, len);
45808057504Sxy150489 		e1000g_free_tx_descriptors(tx_ring);
45908057504Sxy150489 		return (DDI_FAILURE);
46008057504Sxy150489 	}
46108057504Sxy150489 
46208057504Sxy150489 	tx_ring->tbd_dma_addr = cookie.dmac_laddress;
46308057504Sxy150489 	tx_ring->tbd_first = tx_ring->tbd_area;
46408057504Sxy150489 	tx_ring->tbd_last = tx_ring->tbd_first +
46525f2d433Sxy150489 	    (Adapter->tx_desc_num - 1);
46608057504Sxy150489 
46708057504Sxy150489 	return (DDI_SUCCESS);
46808057504Sxy150489 }
46908057504Sxy150489 
47008057504Sxy150489 static int
47154e0d7a5SMiles Xu, Sun Microsystems e1000g_alloc_rx_descriptors(e1000g_rx_data_t *rx_data)
47208057504Sxy150489 {
47308057504Sxy150489 	int mystat;
47408057504Sxy150489 	boolean_t alloc_flag;
47508057504Sxy150489 	size_t size;
47608057504Sxy150489 	size_t len;
47708057504Sxy150489 	uintptr_t templong;
47808057504Sxy150489 	uint_t cookie_count;
47908057504Sxy150489 	dev_info_t *devinfo;
48008057504Sxy150489 	ddi_dma_cookie_t cookie;
48108057504Sxy150489 	struct e1000g *Adapter;
48225f2d433Sxy150489 	ddi_dma_attr_t dma_attr;
48308057504Sxy150489 
48454e0d7a5SMiles Xu, Sun Microsystems 	Adapter = rx_data->rx_ring->adapter;
48525f2d433Sxy150489 	devinfo = Adapter->dip;
48608057504Sxy150489 
48708057504Sxy150489 	alloc_flag = B_FALSE;
48825f2d433Sxy150489 	dma_attr = e1000g_desc_dma_attr;
48908057504Sxy150489 
49008057504Sxy150489 	/*
49108057504Sxy150489 	 * Memory allocation for the receive buffer descriptors.
49208057504Sxy150489 	 */
49325f2d433Sxy150489 	size = (sizeof (struct e1000_rx_desc)) * Adapter->rx_desc_num;
49408057504Sxy150489 
49508057504Sxy150489 	/*
496ede5269eSchenlu chen - Sun Microsystems - Beijing China 	 * Asking for aligned memory with DMA attributes set for suitable value
49708057504Sxy150489 	 */
49825f2d433Sxy150489 	dma_attr.dma_attr_sgllen = 1;
499ede5269eSchenlu chen - Sun Microsystems - Beijing China 	dma_attr.dma_attr_align = Adapter->desc_align;
50008057504Sxy150489 
50108057504Sxy150489 	/*
50225f2d433Sxy150489 	 * Allocate a new DMA handle for the receive descriptors
50308057504Sxy150489 	 */
50425f2d433Sxy150489 	mystat = ddi_dma_alloc_handle(devinfo, &dma_attr,
50508057504Sxy150489 	    DDI_DMA_DONTWAIT, 0,
50654e0d7a5SMiles Xu, Sun Microsystems 	    &rx_data->rbd_dma_handle);
50708057504Sxy150489 
50808057504Sxy150489 	if (mystat != DDI_SUCCESS) {
50925f2d433Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
51008057504Sxy150489 		    "Could not allocate rbd dma handle: %d", mystat);
51154e0d7a5SMiles Xu, Sun Microsystems 		rx_data->rbd_dma_handle = NULL;
51208057504Sxy150489 		return (DDI_FAILURE);
51308057504Sxy150489 	}
51408057504Sxy150489 	/*
51508057504Sxy150489 	 * Allocate memory to DMA data to and from the receive
51608057504Sxy150489 	 * descriptors.
51708057504Sxy150489 	 */
51854e0d7a5SMiles Xu, Sun Microsystems 	mystat = ddi_dma_mem_alloc(rx_data->rbd_dma_handle,
51908057504Sxy150489 	    size,
52025f2d433Sxy150489 	    &e1000g_desc_acc_attr, DDI_DMA_CONSISTENT,
52108057504Sxy150489 	    DDI_DMA_DONTWAIT, 0,
52254e0d7a5SMiles Xu, Sun Microsystems 	    (caddr_t *)&rx_data->rbd_area,
52354e0d7a5SMiles Xu, Sun Microsystems 	    &len, &rx_data->rbd_acc_handle);
52408057504Sxy150489 
52508057504Sxy150489 	/*
52608057504Sxy150489 	 * Check if memory allocation succeeded and also if the
52708057504Sxy150489 	 * allocated memory is aligned correctly.
52808057504Sxy150489 	 */
52908057504Sxy150489 	if ((mystat != DDI_SUCCESS) ||
53054e0d7a5SMiles Xu, Sun Microsystems 	    ((uintptr_t)rx_data->rbd_area & (Adapter->desc_align - 1))) {
53108057504Sxy150489 		if (mystat == DDI_SUCCESS) {
53254e0d7a5SMiles Xu, Sun Microsystems 			ddi_dma_mem_free(&rx_data->rbd_acc_handle);
53354e0d7a5SMiles Xu, Sun Microsystems 			rx_data->rbd_acc_handle = NULL;
53454e0d7a5SMiles Xu, Sun Microsystems 			rx_data->rbd_area = NULL;
53508057504Sxy150489 		}
53654e0d7a5SMiles Xu, Sun Microsystems 		if (rx_data->rbd_dma_handle != NULL) {
53754e0d7a5SMiles Xu, Sun Microsystems 			ddi_dma_free_handle(&rx_data->rbd_dma_handle);
53854e0d7a5SMiles Xu, Sun Microsystems 			rx_data->rbd_dma_handle = NULL;
53908057504Sxy150489 		}
54008057504Sxy150489 		alloc_flag = B_FALSE;
54108057504Sxy150489 	} else
54208057504Sxy150489 		alloc_flag = B_TRUE;
54308057504Sxy150489 
54408057504Sxy150489 	/*
54508057504Sxy150489 	 * Initialize the allocated receive descriptor memory to zero.
54608057504Sxy150489 	 */
54708057504Sxy150489 	if (alloc_flag)
54854e0d7a5SMiles Xu, Sun Microsystems 		bzero((caddr_t)rx_data->rbd_area, len);
54908057504Sxy150489 
55008057504Sxy150489 	/*
55125f2d433Sxy150489 	 * If memory allocation did not succeed, do the alignment ourselves
55208057504Sxy150489 	 */
55308057504Sxy150489 	if (!alloc_flag) {
55425f2d433Sxy150489 		dma_attr.dma_attr_align = 1;
55525f2d433Sxy150489 		dma_attr.dma_attr_sgllen = 1;
556ede5269eSchenlu chen - Sun Microsystems - Beijing China 		size = size + Adapter->desc_align;
55708057504Sxy150489 		/*
55825f2d433Sxy150489 		 * Allocate a new DMA handle for the receive descriptor.
55908057504Sxy150489 		 */
56025f2d433Sxy150489 		mystat = ddi_dma_alloc_handle(devinfo, &dma_attr,
56108057504Sxy150489 		    DDI_DMA_DONTWAIT, 0,
56254e0d7a5SMiles Xu, Sun Microsystems 		    &rx_data->rbd_dma_handle);
56308057504Sxy150489 
56408057504Sxy150489 		if (mystat != DDI_SUCCESS) {
56525f2d433Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
56608057504Sxy150489 			    "Could not re-allocate rbd dma handle: %d", mystat);
56754e0d7a5SMiles Xu, Sun Microsystems 			rx_data->rbd_dma_handle = NULL;
56808057504Sxy150489 			return (DDI_FAILURE);
56908057504Sxy150489 		}
57008057504Sxy150489 		/*
57108057504Sxy150489 		 * Allocate memory to DMA data to and from the receive
57208057504Sxy150489 		 * descriptors.
57308057504Sxy150489 		 */
57454e0d7a5SMiles Xu, Sun Microsystems 		mystat = ddi_dma_mem_alloc(rx_data->rbd_dma_handle,
57508057504Sxy150489 		    size,
57625f2d433Sxy150489 		    &e1000g_desc_acc_attr, DDI_DMA_CONSISTENT,
57708057504Sxy150489 		    DDI_DMA_DONTWAIT, 0,
57854e0d7a5SMiles Xu, Sun Microsystems 		    (caddr_t *)&rx_data->rbd_area,
57954e0d7a5SMiles Xu, Sun Microsystems 		    &len, &rx_data->rbd_acc_handle);
58008057504Sxy150489 
58108057504Sxy150489 		if (mystat != DDI_SUCCESS) {
58225f2d433Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
58308057504Sxy150489 			    "Could not allocate rbd dma memory: %d", mystat);
58454e0d7a5SMiles Xu, Sun Microsystems 			rx_data->rbd_acc_handle = NULL;
58554e0d7a5SMiles Xu, Sun Microsystems 			rx_data->rbd_area = NULL;
58654e0d7a5SMiles Xu, Sun Microsystems 			if (rx_data->rbd_dma_handle != NULL) {
58754e0d7a5SMiles Xu, Sun Microsystems 				ddi_dma_free_handle(&rx_data->rbd_dma_handle);
58854e0d7a5SMiles Xu, Sun Microsystems 				rx_data->rbd_dma_handle = NULL;
58908057504Sxy150489 			}
59008057504Sxy150489 			return (DDI_FAILURE);
59108057504Sxy150489 		} else
59208057504Sxy150489 			alloc_flag = B_TRUE;
59308057504Sxy150489 
59408057504Sxy150489 		/*
59508057504Sxy150489 		 * Initialize the allocated receive descriptor memory to zero.
59608057504Sxy150489 		 */
59754e0d7a5SMiles Xu, Sun Microsystems 		bzero((caddr_t)rx_data->rbd_area, len);
59854e0d7a5SMiles Xu, Sun Microsystems 		templong = P2NPHASE((uintptr_t)rx_data->rbd_area,
599ede5269eSchenlu chen - Sun Microsystems - Beijing China 		    Adapter->desc_align);
60008057504Sxy150489 		len = size - templong;
60154e0d7a5SMiles Xu, Sun Microsystems 		templong += (uintptr_t)rx_data->rbd_area;
60254e0d7a5SMiles Xu, Sun Microsystems 		rx_data->rbd_area = (struct e1000_rx_desc *)templong;
60308057504Sxy150489 	}	/* alignment workaround */
60408057504Sxy150489 
60508057504Sxy150489 	/*
60608057504Sxy150489 	 * The memory allocation of the receive descriptors succeeded
60708057504Sxy150489 	 */
60808057504Sxy150489 	ASSERT(alloc_flag);
60908057504Sxy150489 
61008057504Sxy150489 	/*
61108057504Sxy150489 	 * Allocates DMA resources for the memory that was allocated by
61208057504Sxy150489 	 * the ddi_dma_mem_alloc call.
61308057504Sxy150489 	 */
61454e0d7a5SMiles Xu, Sun Microsystems 	mystat = ddi_dma_addr_bind_handle(rx_data->rbd_dma_handle,
61554e0d7a5SMiles Xu, Sun Microsystems 	    (struct as *)NULL, (caddr_t)rx_data->rbd_area,
61608057504Sxy150489 	    len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
61725f2d433Sxy150489 	    DDI_DMA_DONTWAIT, 0, &cookie, &cookie_count);
61808057504Sxy150489 
61908057504Sxy150489 	if (mystat != DDI_SUCCESS) {
62025f2d433Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
62108057504Sxy150489 		    "Could not bind rbd dma resource: %d", mystat);
62254e0d7a5SMiles Xu, Sun Microsystems 		if (rx_data->rbd_acc_handle != NULL) {
62354e0d7a5SMiles Xu, Sun Microsystems 			ddi_dma_mem_free(&rx_data->rbd_acc_handle);
62454e0d7a5SMiles Xu, Sun Microsystems 			rx_data->rbd_acc_handle = NULL;
62554e0d7a5SMiles Xu, Sun Microsystems 			rx_data->rbd_area = NULL;
62608057504Sxy150489 		}
62754e0d7a5SMiles Xu, Sun Microsystems 		if (rx_data->rbd_dma_handle != NULL) {
62854e0d7a5SMiles Xu, Sun Microsystems 			ddi_dma_free_handle(&rx_data->rbd_dma_handle);
62954e0d7a5SMiles Xu, Sun Microsystems 			rx_data->rbd_dma_handle = NULL;
63008057504Sxy150489 		}
63108057504Sxy150489 		return (DDI_FAILURE);
63208057504Sxy150489 	}
63308057504Sxy150489 
63408057504Sxy150489 	ASSERT(cookie_count == 1);
63508057504Sxy150489 	if (cookie_count != 1) {
63625f2d433Sxy150489 		E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL,
63708057504Sxy150489 		    "Could not bind rbd dma resource in a single frag. "
63808057504Sxy150489 		    "Count - %d Len - %d", cookie_count, len);
63954e0d7a5SMiles Xu, Sun Microsystems 		e1000g_free_rx_descriptors(rx_data);
64008057504Sxy150489 		return (DDI_FAILURE);
64108057504Sxy150489 	}
64225f2d433Sxy150489 
64354e0d7a5SMiles Xu, Sun Microsystems 	rx_data->rbd_dma_addr = cookie.dmac_laddress;
64454e0d7a5SMiles Xu, Sun Microsystems 	rx_data->rbd_first = rx_data->rbd_area;
64554e0d7a5SMiles Xu, Sun Microsystems 	rx_data->rbd_last = rx_data->rbd_first +
64625f2d433Sxy150489 	    (Adapter->rx_desc_num - 1);
64708057504Sxy150489 
64808057504Sxy150489 	return (DDI_SUCCESS);
64908057504Sxy150489 }
65008057504Sxy150489 
65108057504Sxy150489 static void
65254e0d7a5SMiles Xu, Sun Microsystems e1000g_free_rx_descriptors(e1000g_rx_data_t *rx_data)
65308057504Sxy150489 {
65454e0d7a5SMiles Xu, Sun Microsystems 	if (rx_data->rbd_dma_handle != NULL) {
65554e0d7a5SMiles Xu, Sun Microsystems 		(void) ddi_dma_unbind_handle(rx_data->rbd_dma_handle);
65608057504Sxy150489 	}
65754e0d7a5SMiles Xu, Sun Microsystems 	if (rx_data->rbd_acc_handle != NULL) {
65854e0d7a5SMiles Xu, Sun Microsystems 		ddi_dma_mem_free(&rx_data->rbd_acc_handle);
65954e0d7a5SMiles Xu, Sun Microsystems 		rx_data->rbd_acc_handle = NULL;
66054e0d7a5SMiles Xu, Sun Microsystems 		rx_data->rbd_area = NULL;
66108057504Sxy150489 	}
66254e0d7a5SMiles Xu, Sun Microsystems 	if (rx_data->rbd_dma_handle != NULL) {
66354e0d7a5SMiles Xu, Sun Microsystems 		ddi_dma_free_handle(&rx_data->rbd_dma_handle);
66454e0d7a5SMiles Xu, Sun Microsystems 		rx_data->rbd_dma_handle = NULL;
66508057504Sxy150489 	}
66654e0d7a5SMiles Xu, Sun Microsystems 	rx_data->rbd_dma_addr = NULL;
66754e0d7a5SMiles Xu, Sun Microsystems 	rx_data->rbd_first = NULL;
66854e0d7a5SMiles Xu, Sun Microsystems 	rx_data->rbd_last = NULL;
66908057504Sxy150489 }
67008057504Sxy150489 
67108057504Sxy150489 static void
67208057504Sxy150489 e1000g_free_tx_descriptors(e1000g_tx_ring_t *tx_ring)
67308057504Sxy150489 {
67408057504Sxy150489 	if (tx_ring->tbd_dma_handle != NULL) {
675fe62dec3SChen-Liang Xu 		(void) ddi_dma_unbind_handle(tx_ring->tbd_dma_handle);
67608057504Sxy150489 	}
67708057504Sxy150489 	if (tx_ring->tbd_acc_handle != NULL) {
67808057504Sxy150489 		ddi_dma_mem_free(&tx_ring->tbd_acc_handle);
67908057504Sxy150489 		tx_ring->tbd_acc_handle = NULL;
68008057504Sxy150489 		tx_ring->tbd_area = NULL;
68108057504Sxy150489 	}
68208057504Sxy150489 	if (tx_ring->tbd_dma_handle != NULL) {
68308057504Sxy150489 		ddi_dma_free_handle(&tx_ring->tbd_dma_handle);
68408057504Sxy150489 		tx_ring->tbd_dma_handle = NULL;
68508057504Sxy150489 	}
68608057504Sxy150489 	tx_ring->tbd_dma_addr = NULL;
68708057504Sxy150489 	tx_ring->tbd_first = NULL;
68808057504Sxy150489 	tx_ring->tbd_last = NULL;
68908057504Sxy150489 }
69008057504Sxy150489 
69108057504Sxy150489 
69208057504Sxy150489 /*
69325f2d433Sxy150489  * e1000g_alloc_packets - allocate DMA buffers for rx/tx
69425f2d433Sxy150489  *
69525f2d433Sxy150489  * This routine allocates neccesary buffers for
69625f2d433Sxy150489  *	 Transmit sw packet structure
69725f2d433Sxy150489  *	 DMA handle for Transmit
69825f2d433Sxy150489  *	 DMA buffer for Transmit
69925f2d433Sxy150489  *	 Receive sw packet structure
70025f2d433Sxy150489  *	 DMA buffer for Receive
70108057504Sxy150489  */
70208057504Sxy150489 static int
70308057504Sxy150489 e1000g_alloc_packets(struct e1000g *Adapter)
70408057504Sxy150489 {
70508057504Sxy150489 	int result;
70608057504Sxy150489 	e1000g_tx_ring_t *tx_ring;
70754e0d7a5SMiles Xu, Sun Microsystems 	e1000g_rx_data_t *rx_data;
70808057504Sxy150489 
70908057504Sxy150489 	tx_ring = Adapter->tx_ring;
71054e0d7a5SMiles Xu, Sun Microsystems 	rx_data = Adapter->rx_ring->rx_data;
71108057504Sxy150489 
71208057504Sxy150489 again:
71308057504Sxy150489 	rw_enter(&e1000g_dma_type_lock, RW_READER);
71408057504Sxy150489 
71508057504Sxy150489 	result = e1000g_alloc_tx_packets(tx_ring);
71608057504Sxy150489 	if (result != DDI_SUCCESS) {
71708057504Sxy150489 		if (e1000g_dma_type == USE_DVMA) {
71808057504Sxy150489 			rw_exit(&e1000g_dma_type_lock);
71908057504Sxy150489 
72008057504Sxy150489 			rw_enter(&e1000g_dma_type_lock, RW_WRITER);
72108057504Sxy150489 			e1000g_dma_type = USE_DMA;
72208057504Sxy150489 			rw_exit(&e1000g_dma_type_lock);
72308057504Sxy150489 
72425f2d433Sxy150489 			E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
72508057504Sxy150489 			    "No enough dvma resource for Tx packets, "
72608057504Sxy150489 			    "trying to allocate dma buffers...\n");
72708057504Sxy150489 			goto again;
72808057504Sxy150489 		}
72908057504Sxy150489 		rw_exit(&e1000g_dma_type_lock);
73008057504Sxy150489 
73125f2d433Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
73208057504Sxy150489 		    "Failed to allocate dma buffers for Tx packets\n");
73308057504Sxy150489 		return (DDI_FAILURE);
73408057504Sxy150489 	}
73508057504Sxy150489 
73654e0d7a5SMiles Xu, Sun Microsystems 	result = e1000g_alloc_rx_packets(rx_data);
73708057504Sxy150489 	if (result != DDI_SUCCESS) {
73808057504Sxy150489 		e1000g_free_tx_packets(tx_ring);
73908057504Sxy150489 		if (e1000g_dma_type == USE_DVMA) {
74008057504Sxy150489 			rw_exit(&e1000g_dma_type_lock);
74108057504Sxy150489 
74208057504Sxy150489 			rw_enter(&e1000g_dma_type_lock, RW_WRITER);
74308057504Sxy150489 			e1000g_dma_type = USE_DMA;
74408057504Sxy150489 			rw_exit(&e1000g_dma_type_lock);
74508057504Sxy150489 
74625f2d433Sxy150489 			E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
74708057504Sxy150489 			    "No enough dvma resource for Rx packets, "
74808057504Sxy150489 			    "trying to allocate dma buffers...\n");
74908057504Sxy150489 			goto again;
75008057504Sxy150489 		}
75108057504Sxy150489 		rw_exit(&e1000g_dma_type_lock);
75208057504Sxy150489 
75325f2d433Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
75408057504Sxy150489 		    "Failed to allocate dma buffers for Rx packets\n");
75508057504Sxy150489 		return (DDI_FAILURE);
75608057504Sxy150489 	}
75708057504Sxy150489 
75808057504Sxy150489 	rw_exit(&e1000g_dma_type_lock);
75908057504Sxy150489 
76008057504Sxy150489 	return (DDI_SUCCESS);
76108057504Sxy150489 }
76208057504Sxy150489 
76325f2d433Sxy150489 static void
76425f2d433Sxy150489 e1000g_free_packets(struct e1000g *Adapter)
76525f2d433Sxy150489 {
76625f2d433Sxy150489 	e1000g_tx_ring_t *tx_ring;
76754e0d7a5SMiles Xu, Sun Microsystems 	e1000g_rx_data_t *rx_data;
76825f2d433Sxy150489 
76925f2d433Sxy150489 	tx_ring = Adapter->tx_ring;
77054e0d7a5SMiles Xu, Sun Microsystems 	rx_data = Adapter->rx_ring->rx_data;
77125f2d433Sxy150489 
77225f2d433Sxy150489 	e1000g_free_tx_packets(tx_ring);
7733fb4efefSchangqing li - Sun Microsystems - Beijing China 	e1000g_free_rx_packets(rx_data, B_FALSE);
77425f2d433Sxy150489 }
77525f2d433Sxy150489 
77608057504Sxy150489 #ifdef __sparc
77708057504Sxy150489 static int
77808057504Sxy150489 e1000g_alloc_dvma_buffer(struct e1000g *Adapter,
77908057504Sxy150489     dma_buffer_t *buf, size_t size)
78008057504Sxy150489 {
78108057504Sxy150489 	int mystat;
78208057504Sxy150489 	dev_info_t *devinfo;
78308057504Sxy150489 	ddi_dma_cookie_t cookie;
78408057504Sxy150489 
7850f70fbf8Sxy150489 	if (e1000g_force_detach)
7860f70fbf8Sxy150489 		devinfo = Adapter->priv_dip;
7870f70fbf8Sxy150489 	else
78808057504Sxy150489 		devinfo = Adapter->dip;
78908057504Sxy150489 
79008057504Sxy150489 	mystat = dvma_reserve(devinfo,
79108057504Sxy150489 	    &e1000g_dma_limits,
79208057504Sxy150489 	    Adapter->dvma_page_num,
79308057504Sxy150489 	    &buf->dma_handle);
79408057504Sxy150489 
79508057504Sxy150489 	if (mystat != DDI_SUCCESS) {
79608057504Sxy150489 		buf->dma_handle = NULL;
79725f2d433Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
79808057504Sxy150489 		    "Could not allocate dvma buffer handle: %d\n", mystat);
79908057504Sxy150489 		return (DDI_FAILURE);
80008057504Sxy150489 	}
80108057504Sxy150489 
80208057504Sxy150489 	buf->address = kmem_alloc(size, KM_NOSLEEP);
80308057504Sxy150489 
80408057504Sxy150489 	if (buf->address == NULL) {
80508057504Sxy150489 		if (buf->dma_handle != NULL) {
80608057504Sxy150489 			dvma_release(buf->dma_handle);
80708057504Sxy150489 			buf->dma_handle = NULL;
80808057504Sxy150489 		}
80925f2d433Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
81008057504Sxy150489 		    "Could not allocate dvma buffer memory\n");
81108057504Sxy150489 		return (DDI_FAILURE);
81208057504Sxy150489 	}
81308057504Sxy150489 
81408057504Sxy150489 	dvma_kaddr_load(buf->dma_handle,
81508057504Sxy150489 	    buf->address, size, 0, &cookie);
81608057504Sxy150489 
81708057504Sxy150489 	buf->dma_address = cookie.dmac_laddress;
81808057504Sxy150489 	buf->size = size;
81908057504Sxy150489 	buf->len = 0;
82008057504Sxy150489 
82108057504Sxy150489 	return (DDI_SUCCESS);
82208057504Sxy150489 }
82308057504Sxy150489 
82408057504Sxy150489 static void
82508057504Sxy150489 e1000g_free_dvma_buffer(dma_buffer_t *buf)
82608057504Sxy150489 {
82708057504Sxy150489 	if (buf->dma_handle != NULL) {
82808057504Sxy150489 		dvma_unload(buf->dma_handle, 0, -1);
82908057504Sxy150489 	} else {
83008057504Sxy150489 		return;
83108057504Sxy150489 	}
83208057504Sxy150489 
83308057504Sxy150489 	buf->dma_address = NULL;
83408057504Sxy150489 
83508057504Sxy150489 	if (buf->address != NULL) {
83608057504Sxy150489 		kmem_free(buf->address, buf->size);
83708057504Sxy150489 		buf->address = NULL;
83808057504Sxy150489 	}
83908057504Sxy150489 
84008057504Sxy150489 	if (buf->dma_handle != NULL) {
84108057504Sxy150489 		dvma_release(buf->dma_handle);
84208057504Sxy150489 		buf->dma_handle = NULL;
84308057504Sxy150489 	}
84408057504Sxy150489 
84508057504Sxy150489 	buf->size = 0;
84608057504Sxy150489 	buf->len = 0;
84708057504Sxy150489 }
84808057504Sxy150489 #endif
84908057504Sxy150489 
85008057504Sxy150489 static int
85108057504Sxy150489 e1000g_alloc_dma_buffer(struct e1000g *Adapter,
85225f2d433Sxy150489     dma_buffer_t *buf, size_t size, ddi_dma_attr_t *p_dma_attr)
85308057504Sxy150489 {
85408057504Sxy150489 	int mystat;
85508057504Sxy150489 	dev_info_t *devinfo;
85608057504Sxy150489 	ddi_dma_cookie_t cookie;
85708057504Sxy150489 	size_t len;
85808057504Sxy150489 	uint_t count;
85908057504Sxy150489 
8600f70fbf8Sxy150489 	if (e1000g_force_detach)
8610f70fbf8Sxy150489 		devinfo = Adapter->priv_dip;
8620f70fbf8Sxy150489 	else
86308057504Sxy150489 		devinfo = Adapter->dip;
86408057504Sxy150489 
86508057504Sxy150489 	mystat = ddi_dma_alloc_handle(devinfo,
86625f2d433Sxy150489 	    p_dma_attr,
86708057504Sxy150489 	    DDI_DMA_DONTWAIT, 0,
86808057504Sxy150489 	    &buf->dma_handle);
86908057504Sxy150489 
87008057504Sxy150489 	if (mystat != DDI_SUCCESS) {
87108057504Sxy150489 		buf->dma_handle = NULL;
87225f2d433Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
87308057504Sxy150489 		    "Could not allocate dma buffer handle: %d\n", mystat);
87408057504Sxy150489 		return (DDI_FAILURE);
87508057504Sxy150489 	}
87608057504Sxy150489 
87708057504Sxy150489 	mystat = ddi_dma_mem_alloc(buf->dma_handle,
87825f2d433Sxy150489 	    size, &e1000g_buf_acc_attr, DDI_DMA_STREAMING,
87908057504Sxy150489 	    DDI_DMA_DONTWAIT, 0,
88008057504Sxy150489 	    &buf->address,
88108057504Sxy150489 	    &len, &buf->acc_handle);
88208057504Sxy150489 
88308057504Sxy150489 	if (mystat != DDI_SUCCESS) {
88408057504Sxy150489 		buf->acc_handle = NULL;
88508057504Sxy150489 		buf->address = NULL;
88608057504Sxy150489 		if (buf->dma_handle != NULL) {
88708057504Sxy150489 			ddi_dma_free_handle(&buf->dma_handle);
88808057504Sxy150489 			buf->dma_handle = NULL;
88908057504Sxy150489 		}
89025f2d433Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
89108057504Sxy150489 		    "Could not allocate dma buffer memory: %d\n", mystat);
89208057504Sxy150489 		return (DDI_FAILURE);
89308057504Sxy150489 	}
89408057504Sxy150489 
89508057504Sxy150489 	mystat = ddi_dma_addr_bind_handle(buf->dma_handle,
89608057504Sxy150489 	    (struct as *)NULL,
89708057504Sxy150489 	    buf->address,
8980c35404fSchangqing li - Sun Microsystems - Beijing China 	    len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
89925f2d433Sxy150489 	    DDI_DMA_DONTWAIT, 0, &cookie, &count);
90008057504Sxy150489 
90108057504Sxy150489 	if (mystat != DDI_SUCCESS) {
90208057504Sxy150489 		if (buf->acc_handle != NULL) {
90308057504Sxy150489 			ddi_dma_mem_free(&buf->acc_handle);
90408057504Sxy150489 			buf->acc_handle = NULL;
90508057504Sxy150489 			buf->address = NULL;
90608057504Sxy150489 		}
90708057504Sxy150489 		if (buf->dma_handle != NULL) {
90808057504Sxy150489 			ddi_dma_free_handle(&buf->dma_handle);
90908057504Sxy150489 			buf->dma_handle = NULL;
91008057504Sxy150489 		}
91125f2d433Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
91208057504Sxy150489 		    "Could not bind buffer dma handle: %d\n", mystat);
91308057504Sxy150489 		return (DDI_FAILURE);
91408057504Sxy150489 	}
91508057504Sxy150489 
91608057504Sxy150489 	ASSERT(count == 1);
91708057504Sxy150489 	if (count != 1) {
91808057504Sxy150489 		if (buf->dma_handle != NULL) {
919fe62dec3SChen-Liang Xu 			(void) ddi_dma_unbind_handle(buf->dma_handle);
92008057504Sxy150489 		}
92108057504Sxy150489 		if (buf->acc_handle != NULL) {
92208057504Sxy150489 			ddi_dma_mem_free(&buf->acc_handle);
92308057504Sxy150489 			buf->acc_handle = NULL;
92408057504Sxy150489 			buf->address = NULL;
92508057504Sxy150489 		}
92608057504Sxy150489 		if (buf->dma_handle != NULL) {
92708057504Sxy150489 			ddi_dma_free_handle(&buf->dma_handle);
92808057504Sxy150489 			buf->dma_handle = NULL;
92908057504Sxy150489 		}
93025f2d433Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
93108057504Sxy150489 		    "Could not bind buffer as a single frag. "
93208057504Sxy150489 		    "Count = %d\n", count);
93308057504Sxy150489 		return (DDI_FAILURE);
93408057504Sxy150489 	}
93508057504Sxy150489 
93608057504Sxy150489 	buf->dma_address = cookie.dmac_laddress;
93708057504Sxy150489 	buf->size = len;
93808057504Sxy150489 	buf->len = 0;
93908057504Sxy150489 
94008057504Sxy150489 	return (DDI_SUCCESS);
94108057504Sxy150489 }
94208057504Sxy150489 
943ede5269eSchenlu chen - Sun Microsystems - Beijing China /*
944ede5269eSchenlu chen - Sun Microsystems - Beijing China  * e1000g_alloc_dma_buffer_82546 - allocate a dma buffer along with all
945ede5269eSchenlu chen - Sun Microsystems - Beijing China  * necessary handles.  Same as e1000g_alloc_dma_buffer() except ensure
946ede5269eSchenlu chen - Sun Microsystems - Beijing China  * that buffer that doesn't cross a 64k boundary.
947ede5269eSchenlu chen - Sun Microsystems - Beijing China  */
948ede5269eSchenlu chen - Sun Microsystems - Beijing China static int
949ede5269eSchenlu chen - Sun Microsystems - Beijing China e1000g_alloc_dma_buffer_82546(struct e1000g *Adapter,
950ede5269eSchenlu chen - Sun Microsystems - Beijing China     dma_buffer_t *buf, size_t size, ddi_dma_attr_t *p_dma_attr)
951ede5269eSchenlu chen - Sun Microsystems - Beijing China {
952ede5269eSchenlu chen - Sun Microsystems - Beijing China 	int mystat;
953ede5269eSchenlu chen - Sun Microsystems - Beijing China 	dev_info_t *devinfo;
954ede5269eSchenlu chen - Sun Microsystems - Beijing China 	ddi_dma_cookie_t cookie;
955ede5269eSchenlu chen - Sun Microsystems - Beijing China 	size_t len;
956ede5269eSchenlu chen - Sun Microsystems - Beijing China 	uint_t count;
957ede5269eSchenlu chen - Sun Microsystems - Beijing China 
958ede5269eSchenlu chen - Sun Microsystems - Beijing China 	if (e1000g_force_detach)
959ede5269eSchenlu chen - Sun Microsystems - Beijing China 		devinfo = Adapter->priv_dip;
960ede5269eSchenlu chen - Sun Microsystems - Beijing China 	else
961ede5269eSchenlu chen - Sun Microsystems - Beijing China 		devinfo = Adapter->dip;
962ede5269eSchenlu chen - Sun Microsystems - Beijing China 
963ede5269eSchenlu chen - Sun Microsystems - Beijing China 	mystat = ddi_dma_alloc_handle(devinfo,
964ede5269eSchenlu chen - Sun Microsystems - Beijing China 	    p_dma_attr,
965ede5269eSchenlu chen - Sun Microsystems - Beijing China 	    DDI_DMA_DONTWAIT, 0,
966ede5269eSchenlu chen - Sun Microsystems - Beijing China 	    &buf->dma_handle);
967ede5269eSchenlu chen - Sun Microsystems - Beijing China 
968ede5269eSchenlu chen - Sun Microsystems - Beijing China 	if (mystat != DDI_SUCCESS) {
969ede5269eSchenlu chen - Sun Microsystems - Beijing China 		buf->dma_handle = NULL;
970ede5269eSchenlu chen - Sun Microsystems - Beijing China 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
971ede5269eSchenlu chen - Sun Microsystems - Beijing China 		    "Could not allocate dma buffer handle: %d\n", mystat);
972ede5269eSchenlu chen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
973ede5269eSchenlu chen - Sun Microsystems - Beijing China 	}
974ede5269eSchenlu chen - Sun Microsystems - Beijing China 
975ede5269eSchenlu chen - Sun Microsystems - Beijing China 	mystat = e1000g_dma_mem_alloc_82546(buf, size, &len);
976ede5269eSchenlu chen - Sun Microsystems - Beijing China 	if (mystat != DDI_SUCCESS) {
977ede5269eSchenlu chen - Sun Microsystems - Beijing China 		buf->acc_handle = NULL;
978ede5269eSchenlu chen - Sun Microsystems - Beijing China 		buf->address = NULL;
979ede5269eSchenlu chen - Sun Microsystems - Beijing China 		if (buf->dma_handle != NULL) {
980ede5269eSchenlu chen - Sun Microsystems - Beijing China 			ddi_dma_free_handle(&buf->dma_handle);
981ede5269eSchenlu chen - Sun Microsystems - Beijing China 			buf->dma_handle = NULL;
982ede5269eSchenlu chen - Sun Microsystems - Beijing China 		}
983ede5269eSchenlu chen - Sun Microsystems - Beijing China 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
984ede5269eSchenlu chen - Sun Microsystems - Beijing China 		    "Could not allocate dma buffer memory: %d\n", mystat);
985ede5269eSchenlu chen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
986ede5269eSchenlu chen - Sun Microsystems - Beijing China 	}
987ede5269eSchenlu chen - Sun Microsystems - Beijing China 
988ede5269eSchenlu chen - Sun Microsystems - Beijing China 	mystat = ddi_dma_addr_bind_handle(buf->dma_handle,
989ede5269eSchenlu chen - Sun Microsystems - Beijing China 	    (struct as *)NULL,
990ede5269eSchenlu chen - Sun Microsystems - Beijing China 	    buf->address,
991ede5269eSchenlu chen - Sun Microsystems - Beijing China 	    len, DDI_DMA_READ | DDI_DMA_STREAMING,
992ede5269eSchenlu chen - Sun Microsystems - Beijing China 	    DDI_DMA_DONTWAIT, 0, &cookie, &count);
993ede5269eSchenlu chen - Sun Microsystems - Beijing China 
994ede5269eSchenlu chen - Sun Microsystems - Beijing China 	if (mystat != DDI_SUCCESS) {
995ede5269eSchenlu chen - Sun Microsystems - Beijing China 		if (buf->acc_handle != NULL) {
996ede5269eSchenlu chen - Sun Microsystems - Beijing China 			ddi_dma_mem_free(&buf->acc_handle);
997ede5269eSchenlu chen - Sun Microsystems - Beijing China 			buf->acc_handle = NULL;
998ede5269eSchenlu chen - Sun Microsystems - Beijing China 			buf->address = NULL;
999ede5269eSchenlu chen - Sun Microsystems - Beijing China 		}
1000ede5269eSchenlu chen - Sun Microsystems - Beijing China 		if (buf->dma_handle != NULL) {
1001ede5269eSchenlu chen - Sun Microsystems - Beijing China 			ddi_dma_free_handle(&buf->dma_handle);
1002ede5269eSchenlu chen - Sun Microsystems - Beijing China 			buf->dma_handle = NULL;
1003ede5269eSchenlu chen - Sun Microsystems - Beijing China 		}
1004ede5269eSchenlu chen - Sun Microsystems - Beijing China 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
1005ede5269eSchenlu chen - Sun Microsystems - Beijing China 		    "Could not bind buffer dma handle: %d\n", mystat);
1006ede5269eSchenlu chen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
1007ede5269eSchenlu chen - Sun Microsystems - Beijing China 	}
1008ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1009ede5269eSchenlu chen - Sun Microsystems - Beijing China 	ASSERT(count == 1);
1010ede5269eSchenlu chen - Sun Microsystems - Beijing China 	if (count != 1) {
1011ede5269eSchenlu chen - Sun Microsystems - Beijing China 		if (buf->dma_handle != NULL) {
101257ef6f69Sguoqing zhu - Sun Microsystems - Beijing China 			(void) ddi_dma_unbind_handle(buf->dma_handle);
1013ede5269eSchenlu chen - Sun Microsystems - Beijing China 		}
1014ede5269eSchenlu chen - Sun Microsystems - Beijing China 		if (buf->acc_handle != NULL) {
1015ede5269eSchenlu chen - Sun Microsystems - Beijing China 			ddi_dma_mem_free(&buf->acc_handle);
1016ede5269eSchenlu chen - Sun Microsystems - Beijing China 			buf->acc_handle = NULL;
1017ede5269eSchenlu chen - Sun Microsystems - Beijing China 			buf->address = NULL;
1018ede5269eSchenlu chen - Sun Microsystems - Beijing China 		}
1019ede5269eSchenlu chen - Sun Microsystems - Beijing China 		if (buf->dma_handle != NULL) {
1020ede5269eSchenlu chen - Sun Microsystems - Beijing China 			ddi_dma_free_handle(&buf->dma_handle);
1021ede5269eSchenlu chen - Sun Microsystems - Beijing China 			buf->dma_handle = NULL;
1022ede5269eSchenlu chen - Sun Microsystems - Beijing China 		}
1023ede5269eSchenlu chen - Sun Microsystems - Beijing China 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
1024ede5269eSchenlu chen - Sun Microsystems - Beijing China 		    "Could not bind buffer as a single frag. "
1025ede5269eSchenlu chen - Sun Microsystems - Beijing China 		    "Count = %d\n", count);
1026ede5269eSchenlu chen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
1027ede5269eSchenlu chen - Sun Microsystems - Beijing China 	}
1028ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1029ede5269eSchenlu chen - Sun Microsystems - Beijing China 	buf->dma_address = cookie.dmac_laddress;
1030ede5269eSchenlu chen - Sun Microsystems - Beijing China 	buf->size = len;
1031ede5269eSchenlu chen - Sun Microsystems - Beijing China 	buf->len = 0;
1032ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1033ede5269eSchenlu chen - Sun Microsystems - Beijing China 	return (DDI_SUCCESS);
1034ede5269eSchenlu chen - Sun Microsystems - Beijing China }
1035ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1036ede5269eSchenlu chen - Sun Microsystems - Beijing China /*
1037ede5269eSchenlu chen - Sun Microsystems - Beijing China  * e1000g_dma_mem_alloc_82546 - allocate a dma buffer, making up to
1038ede5269eSchenlu chen - Sun Microsystems - Beijing China  * ALLOC_RETRY attempts to get a buffer that doesn't cross a 64k boundary.
1039ede5269eSchenlu chen - Sun Microsystems - Beijing China  */
1040ede5269eSchenlu chen - Sun Microsystems - Beijing China static int
1041ede5269eSchenlu chen - Sun Microsystems - Beijing China e1000g_dma_mem_alloc_82546(dma_buffer_t *buf, size_t size, size_t *len)
1042ede5269eSchenlu chen - Sun Microsystems - Beijing China {
1043ede5269eSchenlu chen - Sun Microsystems - Beijing China #define	ALLOC_RETRY	10
1044ede5269eSchenlu chen - Sun Microsystems - Beijing China 	int stat;
1045ede5269eSchenlu chen - Sun Microsystems - Beijing China 	int cnt = 0;
1046ede5269eSchenlu chen - Sun Microsystems - Beijing China 	ddi_acc_handle_t hold[ALLOC_RETRY];
1047ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1048ede5269eSchenlu chen - Sun Microsystems - Beijing China 	while (cnt < ALLOC_RETRY) {
1049ede5269eSchenlu chen - Sun Microsystems - Beijing China 		hold[cnt] = NULL;
1050ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1051ede5269eSchenlu chen - Sun Microsystems - Beijing China 		/* allocate memory */
1052ede5269eSchenlu chen - Sun Microsystems - Beijing China 		stat = ddi_dma_mem_alloc(buf->dma_handle, size,
1053ede5269eSchenlu chen - Sun Microsystems - Beijing China 		    &e1000g_buf_acc_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT,
1054ede5269eSchenlu chen - Sun Microsystems - Beijing China 		    0, &buf->address, len, &buf->acc_handle);
1055ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1056ede5269eSchenlu chen - Sun Microsystems - Beijing China 		if (stat != DDI_SUCCESS) {
1057ede5269eSchenlu chen - Sun Microsystems - Beijing China 			break;
1058ede5269eSchenlu chen - Sun Microsystems - Beijing China 		}
1059ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1060ede5269eSchenlu chen - Sun Microsystems - Beijing China 		/*
1061ede5269eSchenlu chen - Sun Microsystems - Beijing China 		 * Check 64k bounday:
1062ede5269eSchenlu chen - Sun Microsystems - Beijing China 		 * if it is bad, hold it and retry
1063ede5269eSchenlu chen - Sun Microsystems - Beijing China 		 * if it is good, exit loop
1064ede5269eSchenlu chen - Sun Microsystems - Beijing China 		 */
1065ede5269eSchenlu chen - Sun Microsystems - Beijing China 		if (e1000g_cross_64k_bound(buf->address, *len)) {
1066ede5269eSchenlu chen - Sun Microsystems - Beijing China 			hold[cnt] = buf->acc_handle;
1067ede5269eSchenlu chen - Sun Microsystems - Beijing China 			stat = DDI_FAILURE;
1068ede5269eSchenlu chen - Sun Microsystems - Beijing China 		} else {
1069ede5269eSchenlu chen - Sun Microsystems - Beijing China 			break;
1070ede5269eSchenlu chen - Sun Microsystems - Beijing China 		}
1071ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1072ede5269eSchenlu chen - Sun Microsystems - Beijing China 		cnt++;
1073ede5269eSchenlu chen - Sun Microsystems - Beijing China 	}
1074ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1075ede5269eSchenlu chen - Sun Microsystems - Beijing China 	/* Release any held buffers crossing 64k bounday */
1076ede5269eSchenlu chen - Sun Microsystems - Beijing China 	for (--cnt; cnt >= 0; cnt--) {
1077ede5269eSchenlu chen - Sun Microsystems - Beijing China 		if (hold[cnt])
1078ede5269eSchenlu chen - Sun Microsystems - Beijing China 			ddi_dma_mem_free(&hold[cnt]);
1079ede5269eSchenlu chen - Sun Microsystems - Beijing China 	}
1080ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1081ede5269eSchenlu chen - Sun Microsystems - Beijing China 	return (stat);
1082ede5269eSchenlu chen - Sun Microsystems - Beijing China }
1083ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1084ede5269eSchenlu chen - Sun Microsystems - Beijing China /*
1085ede5269eSchenlu chen - Sun Microsystems - Beijing China  * e1000g_cross_64k_bound - If starting and ending address cross a 64k boundary
1086ede5269eSchenlu chen - Sun Microsystems - Beijing China  * return true; otherwise return false
1087ede5269eSchenlu chen - Sun Microsystems - Beijing China  */
1088ede5269eSchenlu chen - Sun Microsystems - Beijing China static boolean_t
1089ede5269eSchenlu chen - Sun Microsystems - Beijing China e1000g_cross_64k_bound(void *addr, uintptr_t len)
1090ede5269eSchenlu chen - Sun Microsystems - Beijing China {
1091ede5269eSchenlu chen - Sun Microsystems - Beijing China 	uintptr_t start = (uintptr_t)addr;
1092ede5269eSchenlu chen - Sun Microsystems - Beijing China 	uintptr_t end = start + len - 1;
1093ede5269eSchenlu chen - Sun Microsystems - Beijing China 
1094ede5269eSchenlu chen - Sun Microsystems - Beijing China 	return (((start ^ end) >> 16) == 0 ? B_FALSE : B_TRUE);
1095ede5269eSchenlu chen - Sun Microsystems - Beijing China }
1096ede5269eSchenlu chen - Sun Microsystems - Beijing China 
109708057504Sxy150489 static void
109808057504Sxy150489 e1000g_free_dma_buffer(dma_buffer_t *buf)
109908057504Sxy150489 {
110008057504Sxy150489 	if (buf->dma_handle != NULL) {
1101fe62dec3SChen-Liang Xu 		(void) ddi_dma_unbind_handle(buf->dma_handle);
110208057504Sxy150489 	} else {
110308057504Sxy150489 		return;
110408057504Sxy150489 	}
110508057504Sxy150489 
110608057504Sxy150489 	buf->dma_address = NULL;
110708057504Sxy150489 
110808057504Sxy150489 	if (buf->acc_handle != NULL) {
110908057504Sxy150489 		ddi_dma_mem_free(&buf->acc_handle);
111008057504Sxy150489 		buf->acc_handle = NULL;
111108057504Sxy150489 		buf->address = NULL;
111208057504Sxy150489 	}
111308057504Sxy150489 
111408057504Sxy150489 	if (buf->dma_handle != NULL) {
111508057504Sxy150489 		ddi_dma_free_handle(&buf->dma_handle);
111608057504Sxy150489 		buf->dma_handle = NULL;
111708057504Sxy150489 	}
111808057504Sxy150489 
111908057504Sxy150489 	buf->size = 0;
112008057504Sxy150489 	buf->len = 0;
112108057504Sxy150489 }
112208057504Sxy150489 
112308057504Sxy150489 static int
112408057504Sxy150489 e1000g_alloc_tx_packets(e1000g_tx_ring_t *tx_ring)
112508057504Sxy150489 {
112608057504Sxy150489 	int j;
112725f2d433Sxy150489 	p_tx_sw_packet_t packet;
112808057504Sxy150489 	int mystat;
112908057504Sxy150489 	dma_buffer_t *tx_buf;
113025f2d433Sxy150489 	struct e1000g *Adapter;
113125f2d433Sxy150489 	dev_info_t *devinfo;
113225f2d433Sxy150489 	ddi_dma_attr_t dma_attr;
113325f2d433Sxy150489 
113425f2d433Sxy150489 	Adapter = tx_ring->adapter;
113525f2d433Sxy150489 	devinfo = Adapter->dip;
113625f2d433Sxy150489 	dma_attr = e1000g_buf_dma_attr;
113708057504Sxy150489 
113808057504Sxy150489 	/*
113908057504Sxy150489 	 * Memory allocation for the Transmit software structure, the transmit
114008057504Sxy150489 	 * software packet. This structure stores all the relevant information
114108057504Sxy150489 	 * for transmitting a single packet.
114208057504Sxy150489 	 */
114308057504Sxy150489 	tx_ring->packet_area =
114408057504Sxy150489 	    kmem_zalloc(TX_SW_PKT_AREA_SZ, KM_NOSLEEP);
114508057504Sxy150489 
114608057504Sxy150489 	if (tx_ring->packet_area == NULL)
114708057504Sxy150489 		return (DDI_FAILURE);
114808057504Sxy150489 
114908057504Sxy150489 	for (j = 0, packet = tx_ring->packet_area;
115025f2d433Sxy150489 	    j < Adapter->tx_freelist_num; j++, packet++) {
115108057504Sxy150489 
115208057504Sxy150489 		ASSERT(packet != NULL);
115308057504Sxy150489 
115408057504Sxy150489 		/*
115508057504Sxy150489 		 * Pre-allocate dma handles for transmit. These dma handles
115608057504Sxy150489 		 * will be dynamically bound to the data buffers passed down
115708057504Sxy150489 		 * from the upper layers at the time of transmitting. The
115808057504Sxy150489 		 * dynamic binding only applies for the packets that are larger
115908057504Sxy150489 		 * than the tx_bcopy_thresh.
116008057504Sxy150489 		 */
116108057504Sxy150489 		switch (e1000g_dma_type) {
116208057504Sxy150489 #ifdef __sparc
116308057504Sxy150489 		case USE_DVMA:
116408057504Sxy150489 			mystat = dvma_reserve(devinfo,
116508057504Sxy150489 			    &e1000g_dma_limits,
116608057504Sxy150489 			    Adapter->dvma_page_num,
116708057504Sxy150489 			    &packet->tx_dma_handle);
116808057504Sxy150489 			break;
116908057504Sxy150489 #endif
117008057504Sxy150489 		case USE_DMA:
117108057504Sxy150489 			mystat = ddi_dma_alloc_handle(devinfo,
117225f2d433Sxy150489 			    &e1000g_tx_dma_attr,
117308057504Sxy150489 			    DDI_DMA_DONTWAIT, 0,
117408057504Sxy150489 			    &packet->tx_dma_handle);
117508057504Sxy150489 			break;
117608057504Sxy150489 		default:
117708057504Sxy150489 			ASSERT(B_FALSE);
117808057504Sxy150489 			break;
117908057504Sxy150489 		}
118008057504Sxy150489 		if (mystat != DDI_SUCCESS) {
118108057504Sxy150489 			packet->tx_dma_handle = NULL;
118225f2d433Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
118308057504Sxy150489 			    "Could not allocate tx dma handle: %d\n", mystat);
118408057504Sxy150489 			goto tx_pkt_fail;
118508057504Sxy150489 		}
118608057504Sxy150489 
118708057504Sxy150489 		/*
118808057504Sxy150489 		 * Pre-allocate transmit buffers for small packets that the
118908057504Sxy150489 		 * size is less than tx_bcopy_thresh. The data of those small
119008057504Sxy150489 		 * packets will be bcopy() to the transmit buffers instead of
119108057504Sxy150489 		 * using dynamical DMA binding. For small packets, bcopy will
119208057504Sxy150489 		 * bring better performance than DMA binding.
119308057504Sxy150489 		 */
119408057504Sxy150489 		tx_buf = packet->tx_buf;
119508057504Sxy150489 
119608057504Sxy150489 		switch (e1000g_dma_type) {
119708057504Sxy150489 #ifdef __sparc
119808057504Sxy150489 		case USE_DVMA:
119908057504Sxy150489 			mystat = e1000g_alloc_dvma_buffer(Adapter,
120025f2d433Sxy150489 			    tx_buf, Adapter->tx_buffer_size);
120108057504Sxy150489 			break;
120208057504Sxy150489 #endif
120308057504Sxy150489 		case USE_DMA:
120408057504Sxy150489 			mystat = e1000g_alloc_dma_buffer(Adapter,
120525f2d433Sxy150489 			    tx_buf, Adapter->tx_buffer_size, &dma_attr);
120608057504Sxy150489 			break;
120708057504Sxy150489 		default:
120808057504Sxy150489 			ASSERT(B_FALSE);
120908057504Sxy150489 			break;
121008057504Sxy150489 		}
121108057504Sxy150489 		if (mystat != DDI_SUCCESS) {
121208057504Sxy150489 			ASSERT(packet->tx_dma_handle != NULL);
121308057504Sxy150489 			switch (e1000g_dma_type) {
121408057504Sxy150489 #ifdef __sparc
121508057504Sxy150489 			case USE_DVMA:
121608057504Sxy150489 				dvma_release(packet->tx_dma_handle);
121708057504Sxy150489 				break;
121808057504Sxy150489 #endif
121908057504Sxy150489 			case USE_DMA:
122008057504Sxy150489 				ddi_dma_free_handle(&packet->tx_dma_handle);
122108057504Sxy150489 				break;
122208057504Sxy150489 			default:
122308057504Sxy150489 				ASSERT(B_FALSE);
122408057504Sxy150489 				break;
122508057504Sxy150489 			}
122608057504Sxy150489 			packet->tx_dma_handle = NULL;
122725f2d433Sxy150489 			E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
122808057504Sxy150489 			    "Allocate Tx buffer fail\n");
122908057504Sxy150489 			goto tx_pkt_fail;
123008057504Sxy150489 		}
123108057504Sxy150489 
123208057504Sxy150489 		packet->dma_type = e1000g_dma_type;
123308057504Sxy150489 	} /* for */
123408057504Sxy150489 
123508057504Sxy150489 	return (DDI_SUCCESS);
123608057504Sxy150489 
123708057504Sxy150489 tx_pkt_fail:
123808057504Sxy150489 	e1000g_free_tx_packets(tx_ring);
123908057504Sxy150489 
124008057504Sxy150489 	return (DDI_FAILURE);
124108057504Sxy150489 }
124208057504Sxy150489 
12433fb4efefSchangqing li - Sun Microsystems - Beijing China 
12443fb4efefSchangqing li - Sun Microsystems - Beijing China int
12453fb4efefSchangqing li - Sun Microsystems - Beijing China e1000g_increase_rx_packets(e1000g_rx_data_t *rx_data)
12463fb4efefSchangqing li - Sun Microsystems - Beijing China {
12473fb4efefSchangqing li - Sun Microsystems - Beijing China 	int i;
12483fb4efefSchangqing li - Sun Microsystems - Beijing China 	p_rx_sw_packet_t packet;
12493fb4efefSchangqing li - Sun Microsystems - Beijing China 	p_rx_sw_packet_t cur, next;
12503fb4efefSchangqing li - Sun Microsystems - Beijing China 	struct e1000g *Adapter;
12513fb4efefSchangqing li - Sun Microsystems - Beijing China 	ddi_dma_attr_t dma_attr;
12523fb4efefSchangqing li - Sun Microsystems - Beijing China 
12533fb4efefSchangqing li - Sun Microsystems - Beijing China 	Adapter = rx_data->rx_ring->adapter;
12543fb4efefSchangqing li - Sun Microsystems - Beijing China 	dma_attr = e1000g_buf_dma_attr;
12553fb4efefSchangqing li - Sun Microsystems - Beijing China 	dma_attr.dma_attr_align = Adapter->rx_buf_align;
12563fb4efefSchangqing li - Sun Microsystems - Beijing China 	cur = NULL;
12573fb4efefSchangqing li - Sun Microsystems - Beijing China 
12583fb4efefSchangqing li - Sun Microsystems - Beijing China 	for (i = 0; i < RX_FREELIST_INCREASE_SIZE; i++) {
12593fb4efefSchangqing li - Sun Microsystems - Beijing China 		packet = e1000g_alloc_rx_sw_packet(rx_data, &dma_attr);
12603fb4efefSchangqing li - Sun Microsystems - Beijing China 		if (packet == NULL)
12613fb4efefSchangqing li - Sun Microsystems - Beijing China 			break;
12623fb4efefSchangqing li - Sun Microsystems - Beijing China 		packet->next = cur;
12633fb4efefSchangqing li - Sun Microsystems - Beijing China 		cur = packet;
12643fb4efefSchangqing li - Sun Microsystems - Beijing China 	}
12653fb4efefSchangqing li - Sun Microsystems - Beijing China 	Adapter->rx_freelist_num += i;
12663fb4efefSchangqing li - Sun Microsystems - Beijing China 	rx_data->avail_freepkt += i;
12673fb4efefSchangqing li - Sun Microsystems - Beijing China 
12683fb4efefSchangqing li - Sun Microsystems - Beijing China 	while (cur != NULL) {
12693fb4efefSchangqing li - Sun Microsystems - Beijing China 		QUEUE_PUSH_TAIL(&rx_data->free_list, &cur->Link);
12703fb4efefSchangqing li - Sun Microsystems - Beijing China 		next = cur->next;
12713fb4efefSchangqing li - Sun Microsystems - Beijing China 		cur->next = rx_data->packet_area;
12723fb4efefSchangqing li - Sun Microsystems - Beijing China 		rx_data->packet_area = cur;
12733fb4efefSchangqing li - Sun Microsystems - Beijing China 
12743fb4efefSchangqing li - Sun Microsystems - Beijing China 		cur = next;
12753fb4efefSchangqing li - Sun Microsystems - Beijing China 	}
12763fb4efefSchangqing li - Sun Microsystems - Beijing China 
12773fb4efefSchangqing li - Sun Microsystems - Beijing China 	return (DDI_SUCCESS);
12783fb4efefSchangqing li - Sun Microsystems - Beijing China }
12793fb4efefSchangqing li - Sun Microsystems - Beijing China 
12803fb4efefSchangqing li - Sun Microsystems - Beijing China 
128108057504Sxy150489 static int
128254e0d7a5SMiles Xu, Sun Microsystems e1000g_alloc_rx_packets(e1000g_rx_data_t *rx_data)
128308057504Sxy150489 {
128408057504Sxy150489 	int i;
128525f2d433Sxy150489 	p_rx_sw_packet_t packet;
128608057504Sxy150489 	struct e1000g *Adapter;
128708057504Sxy150489 	uint32_t packet_num;
128825f2d433Sxy150489 	ddi_dma_attr_t dma_attr;
128908057504Sxy150489 
129054e0d7a5SMiles Xu, Sun Microsystems 	Adapter = rx_data->rx_ring->adapter;
129125f2d433Sxy150489 	dma_attr = e1000g_buf_dma_attr;
129225f2d433Sxy150489 	dma_attr.dma_attr_align = Adapter->rx_buf_align;
1293592a4d85Scc210113 
129408057504Sxy150489 	/*
129525f2d433Sxy150489 	 * Allocate memory for the rx_sw_packet structures. Each one of these
129608057504Sxy150489 	 * structures will contain a virtual and physical address to an actual
129725f2d433Sxy150489 	 * receive buffer in host memory. Since we use one rx_sw_packet per
129825f2d433Sxy150489 	 * received packet, the maximum number of rx_sw_packet that we'll
129954e0d7a5SMiles Xu, Sun Microsystems 	 * need is equal to the number of receive descriptors plus the freelist
130054e0d7a5SMiles Xu, Sun Microsystems 	 * size.
130108057504Sxy150489 	 */
13023fb4efefSchangqing li - Sun Microsystems - Beijing China 	packet_num = Adapter->rx_desc_num + RX_FREELIST_INCREASE_SIZE;
130354e0d7a5SMiles Xu, Sun Microsystems 	rx_data->packet_area = NULL;
130408057504Sxy150489 
130508057504Sxy150489 	for (i = 0; i < packet_num; i++) {
130654e0d7a5SMiles Xu, Sun Microsystems 		packet = e1000g_alloc_rx_sw_packet(rx_data, &dma_attr);
130708057504Sxy150489 		if (packet == NULL)
130808057504Sxy150489 			goto rx_pkt_fail;
130908057504Sxy150489 
131054e0d7a5SMiles Xu, Sun Microsystems 		packet->next = rx_data->packet_area;
131154e0d7a5SMiles Xu, Sun Microsystems 		rx_data->packet_area = packet;
131208057504Sxy150489 	}
131308057504Sxy150489 
13143fb4efefSchangqing li - Sun Microsystems - Beijing China 	Adapter->rx_freelist_num = RX_FREELIST_INCREASE_SIZE;
131508057504Sxy150489 	return (DDI_SUCCESS);
131608057504Sxy150489 
131708057504Sxy150489 rx_pkt_fail:
13183fb4efefSchangqing li - Sun Microsystems - Beijing China 	e1000g_free_rx_packets(rx_data, B_TRUE);
131908057504Sxy150489 	return (DDI_FAILURE);
132008057504Sxy150489 }
132108057504Sxy150489 
13223fb4efefSchangqing li - Sun Microsystems - Beijing China 
132325f2d433Sxy150489 static p_rx_sw_packet_t
132454e0d7a5SMiles Xu, Sun Microsystems e1000g_alloc_rx_sw_packet(e1000g_rx_data_t *rx_data, ddi_dma_attr_t *p_dma_attr)
132508057504Sxy150489 {
132608057504Sxy150489 	int mystat;
132725f2d433Sxy150489 	p_rx_sw_packet_t packet;
132808057504Sxy150489 	dma_buffer_t *rx_buf;
132908057504Sxy150489 	struct e1000g *Adapter;
133008057504Sxy150489 
133154e0d7a5SMiles Xu, Sun Microsystems 	Adapter = rx_data->rx_ring->adapter;
133208057504Sxy150489 
133325f2d433Sxy150489 	packet = kmem_zalloc(sizeof (rx_sw_packet_t), KM_NOSLEEP);
133408057504Sxy150489 	if (packet == NULL) {
133525f2d433Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
133608057504Sxy150489 		    "Cound not allocate memory for Rx SwPacket\n");
133708057504Sxy150489 		return (NULL);
133808057504Sxy150489 	}
133908057504Sxy150489 
134008057504Sxy150489 	rx_buf = packet->rx_buf;
134108057504Sxy150489 
134208057504Sxy150489 	switch (e1000g_dma_type) {
134308057504Sxy150489 #ifdef __sparc
134408057504Sxy150489 	case USE_DVMA:
134508057504Sxy150489 		mystat = e1000g_alloc_dvma_buffer(Adapter,
134625f2d433Sxy150489 		    rx_buf, Adapter->rx_buffer_size);
134708057504Sxy150489 		break;
134808057504Sxy150489 #endif
134908057504Sxy150489 	case USE_DMA:
13503d15c084Schenlu chen - Sun Microsystems - Beijing China 		if (Adapter->mem_workaround_82546 &&
13513d15c084Schenlu chen - Sun Microsystems - Beijing China 		    ((Adapter->shared.mac.type == e1000_82545) ||
1352ede5269eSchenlu chen - Sun Microsystems - Beijing China 		    (Adapter->shared.mac.type == e1000_82546) ||
13533d15c084Schenlu chen - Sun Microsystems - Beijing China 		    (Adapter->shared.mac.type == e1000_82546_rev_3))) {
1354ede5269eSchenlu chen - Sun Microsystems - Beijing China 			mystat = e1000g_alloc_dma_buffer_82546(Adapter,
1355ede5269eSchenlu chen - Sun Microsystems - Beijing China 			    rx_buf, Adapter->rx_buffer_size, p_dma_attr);
1356ede5269eSchenlu chen - Sun Microsystems - Beijing China 		} else {
135708057504Sxy150489 			mystat = e1000g_alloc_dma_buffer(Adapter,
135825f2d433Sxy150489 			    rx_buf, Adapter->rx_buffer_size, p_dma_attr);
1359ede5269eSchenlu chen - Sun Microsystems - Beijing China 		}
136008057504Sxy150489 		break;
136108057504Sxy150489 	default:
136208057504Sxy150489 		ASSERT(B_FALSE);
136308057504Sxy150489 		break;
136408057504Sxy150489 	}
136508057504Sxy150489 
136608057504Sxy150489 	if (mystat != DDI_SUCCESS) {
136708057504Sxy150489 		if (packet != NULL)
136825f2d433Sxy150489 			kmem_free(packet, sizeof (rx_sw_packet_t));
136908057504Sxy150489 
137025f2d433Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
137108057504Sxy150489 		    "Failed to allocate Rx buffer\n");
137208057504Sxy150489 		return (NULL);
137308057504Sxy150489 	}
137408057504Sxy150489 
137508057504Sxy150489 	rx_buf->size -= E1000G_IPALIGNROOM;
137608057504Sxy150489 	rx_buf->address += E1000G_IPALIGNROOM;
137708057504Sxy150489 	rx_buf->dma_address += E1000G_IPALIGNROOM;
137808057504Sxy150489 
137954e0d7a5SMiles Xu, Sun Microsystems 	packet->rx_data = (caddr_t)rx_data;
138008057504Sxy150489 	packet->free_rtn.free_func = e1000g_rxfree_func;
138108057504Sxy150489 	packet->free_rtn.free_arg = (char *)packet;
138208057504Sxy150489 	/*
138308057504Sxy150489 	 * esballoc is changed to desballoc which
138408057504Sxy150489 	 * is undocumented call but as per sun,
138508057504Sxy150489 	 * we can use it. It gives better efficiency.
138608057504Sxy150489 	 */
138708057504Sxy150489 	packet->mp = desballoc((unsigned char *)
138846ebaa55SMiles Xu, Sun Microsystems 	    rx_buf->address,
138946ebaa55SMiles Xu, Sun Microsystems 	    rx_buf->size,
139008057504Sxy150489 	    BPRI_MED, &packet->free_rtn);
139108057504Sxy150489 
139208057504Sxy150489 	packet->dma_type = e1000g_dma_type;
139354e0d7a5SMiles Xu, Sun Microsystems 	packet->ref_cnt = 1;
139408057504Sxy150489 
139508057504Sxy150489 	return (packet);
139608057504Sxy150489 }
139708057504Sxy150489 
139808057504Sxy150489 void
139954e0d7a5SMiles Xu, Sun Microsystems e1000g_free_rx_sw_packet(p_rx_sw_packet_t packet, boolean_t full_release)
140008057504Sxy150489 {
140108057504Sxy150489 	dma_buffer_t *rx_buf;
140208057504Sxy150489 
140308057504Sxy150489 	if (packet->mp != NULL) {
140408057504Sxy150489 		freemsg(packet->mp);
140508057504Sxy150489 		packet->mp = NULL;
140608057504Sxy150489 	}
140708057504Sxy150489 
140808057504Sxy150489 	rx_buf = packet->rx_buf;
140908057504Sxy150489 
141008057504Sxy150489 	switch (packet->dma_type) {
141108057504Sxy150489 #ifdef __sparc
141208057504Sxy150489 	case USE_DVMA:
141354e0d7a5SMiles Xu, Sun Microsystems 		if (rx_buf->address != NULL) {
141454e0d7a5SMiles Xu, Sun Microsystems 			rx_buf->size += E1000G_IPALIGNROOM;
141554e0d7a5SMiles Xu, Sun Microsystems 			rx_buf->address -= E1000G_IPALIGNROOM;
141654e0d7a5SMiles Xu, Sun Microsystems 		}
141708057504Sxy150489 		e1000g_free_dvma_buffer(rx_buf);
141808057504Sxy150489 		break;
141908057504Sxy150489 #endif
142008057504Sxy150489 	case USE_DMA:
142108057504Sxy150489 		e1000g_free_dma_buffer(rx_buf);
142208057504Sxy150489 		break;
142308057504Sxy150489 	default:
142408057504Sxy150489 		break;
142508057504Sxy150489 	}
142608057504Sxy150489 
142708057504Sxy150489 	packet->dma_type = USE_NONE;
142808057504Sxy150489 
142954e0d7a5SMiles Xu, Sun Microsystems 	if (!full_release)
143054e0d7a5SMiles Xu, Sun Microsystems 		return;
143154e0d7a5SMiles Xu, Sun Microsystems 
143225f2d433Sxy150489 	kmem_free(packet, sizeof (rx_sw_packet_t));
143308057504Sxy150489 }
143408057504Sxy150489 
143508057504Sxy150489 static void
14363fb4efefSchangqing li - Sun Microsystems - Beijing China e1000g_free_rx_packets(e1000g_rx_data_t *rx_data, boolean_t full_release)
143708057504Sxy150489 {
143854e0d7a5SMiles Xu, Sun Microsystems 	p_rx_sw_packet_t packet, next_packet;
143954e0d7a5SMiles Xu, Sun Microsystems 	uint32_t ref_cnt;
144008057504Sxy150489 
144154e0d7a5SMiles Xu, Sun Microsystems 	mutex_enter(&e1000g_rx_detach_lock);
144208057504Sxy150489 
144354e0d7a5SMiles Xu, Sun Microsystems 	packet = rx_data->packet_area;
144454e0d7a5SMiles Xu, Sun Microsystems 	while (packet != NULL) {
144508057504Sxy150489 		next_packet = packet->next;
144608057504Sxy150489 
144754e0d7a5SMiles Xu, Sun Microsystems 		ref_cnt = atomic_dec_32_nv(&packet->ref_cnt);
144854e0d7a5SMiles Xu, Sun Microsystems 		if (ref_cnt > 0) {
144954e0d7a5SMiles Xu, Sun Microsystems 			atomic_inc_32(&rx_data->pending_count);
145054e0d7a5SMiles Xu, Sun Microsystems 			atomic_inc_32(&e1000g_mblks_pending);
14510f70fbf8Sxy150489 		} else {
14523fb4efefSchangqing li - Sun Microsystems - Beijing China 			e1000g_free_rx_sw_packet(packet, full_release);
14530f70fbf8Sxy150489 		}
145408057504Sxy150489 
145554e0d7a5SMiles Xu, Sun Microsystems 		packet = next_packet;
145608057504Sxy150489 	}
145754e0d7a5SMiles Xu, Sun Microsystems 
1458*bcfab059SJosef 'Jeff' Sipek 	if (full_release)
1459*bcfab059SJosef 'Jeff' Sipek 		rx_data->packet_area = NULL;
1460*bcfab059SJosef 'Jeff' Sipek 
146154e0d7a5SMiles Xu, Sun Microsystems 	mutex_exit(&e1000g_rx_detach_lock);
146208057504Sxy150489 }
146308057504Sxy150489 
146454e0d7a5SMiles Xu, Sun Microsystems 
146508057504Sxy150489 static void
146608057504Sxy150489 e1000g_free_tx_packets(e1000g_tx_ring_t *tx_ring)
146708057504Sxy150489 {
146808057504Sxy150489 	int j;
146908057504Sxy150489 	struct e1000g *Adapter;
147025f2d433Sxy150489 	p_tx_sw_packet_t packet;
147108057504Sxy150489 	dma_buffer_t *tx_buf;
147208057504Sxy150489 
147308057504Sxy150489 	Adapter = tx_ring->adapter;
147408057504Sxy150489 
147508057504Sxy150489 	for (j = 0, packet = tx_ring->packet_area;
147625f2d433Sxy150489 	    j < Adapter->tx_freelist_num; j++, packet++) {
147708057504Sxy150489 
147808057504Sxy150489 		if (packet == NULL)
147908057504Sxy150489 			break;
148008057504Sxy150489 
148108057504Sxy150489 		/* Free the Tx DMA handle for dynamical binding */
148208057504Sxy150489 		if (packet->tx_dma_handle != NULL) {
148308057504Sxy150489 			switch (packet->dma_type) {
148408057504Sxy150489 #ifdef __sparc
148508057504Sxy150489 			case USE_DVMA:
148608057504Sxy150489 				dvma_release(packet->tx_dma_handle);
148708057504Sxy150489 				break;
148808057504Sxy150489 #endif
148908057504Sxy150489 			case USE_DMA:
149008057504Sxy150489 				ddi_dma_free_handle(&packet->tx_dma_handle);
149108057504Sxy150489 				break;
149208057504Sxy150489 			default:
149308057504Sxy150489 				ASSERT(B_FALSE);
149408057504Sxy150489 				break;
149508057504Sxy150489 			}
149608057504Sxy150489 			packet->tx_dma_handle = NULL;
149708057504Sxy150489 		} else {
149808057504Sxy150489 			/*
149908057504Sxy150489 			 * If the dma handle is NULL, then we don't
150008057504Sxy150489 			 * need to check the packets left. For they
150108057504Sxy150489 			 * have not been initialized or have been freed.
150208057504Sxy150489 			 */
150308057504Sxy150489 			break;
150408057504Sxy150489 		}
150508057504Sxy150489 
150608057504Sxy150489 		tx_buf = packet->tx_buf;
150708057504Sxy150489 
150808057504Sxy150489 		switch (packet->dma_type) {
150908057504Sxy150489 #ifdef __sparc
151008057504Sxy150489 		case USE_DVMA:
151108057504Sxy150489 			e1000g_free_dvma_buffer(tx_buf);
151208057504Sxy150489 			break;
151308057504Sxy150489 #endif
151408057504Sxy150489 		case USE_DMA:
151508057504Sxy150489 			e1000g_free_dma_buffer(tx_buf);
151608057504Sxy150489 			break;
151708057504Sxy150489 		default:
151808057504Sxy150489 			ASSERT(B_FALSE);
151908057504Sxy150489 			break;
152008057504Sxy150489 		}
152108057504Sxy150489 
152208057504Sxy150489 		packet->dma_type = USE_NONE;
152308057504Sxy150489 	}
152408057504Sxy150489 	if (tx_ring->packet_area != NULL) {
152508057504Sxy150489 		kmem_free(tx_ring->packet_area, TX_SW_PKT_AREA_SZ);
152608057504Sxy150489 		tx_ring->packet_area = NULL;
152708057504Sxy150489 	}
152808057504Sxy150489 }
152908057504Sxy150489 
153008057504Sxy150489 /*
153125f2d433Sxy150489  * e1000g_release_dma_resources - release allocated DMA resources
153225f2d433Sxy150489  *
153325f2d433Sxy150489  * This function releases any pending buffers that has been
153425f2d433Sxy150489  * previously allocated
153508057504Sxy150489  */
153608057504Sxy150489 void
153725f2d433Sxy150489 e1000g_release_dma_resources(struct e1000g *Adapter)
153808057504Sxy150489 {
153925f2d433Sxy150489 	e1000g_free_descriptors(Adapter);
154025f2d433Sxy150489 	e1000g_free_packets(Adapter);
154108057504Sxy150489 }
15429b6541b3Sgl147354 
1543fe62dec3SChen-Liang Xu /* ARGSUSED */
15449b6541b3Sgl147354 void
1545837c1ac4SStephen Hanson e1000g_set_fma_flags(int dma_flag)
15469b6541b3Sgl147354 {
15479b6541b3Sgl147354 	if (dma_flag) {
15489b6541b3Sgl147354 		e1000g_tx_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
15499b6541b3Sgl147354 		e1000g_buf_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
15509b6541b3Sgl147354 		e1000g_desc_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
15519b6541b3Sgl147354 	} else {
15529b6541b3Sgl147354 		e1000g_tx_dma_attr.dma_attr_flags = 0;
15539b6541b3Sgl147354 		e1000g_buf_dma_attr.dma_attr_flags = 0;
15549b6541b3Sgl147354 		e1000g_desc_dma_attr.dma_attr_flags = 0;
15559b6541b3Sgl147354 	}
15569b6541b3Sgl147354 }
1557