xref: /onnv-gate/usr/src/uts/common/io/e1000g/e1000g_alloc.c (revision 11143:f855b68211a7)
13526Sxy150489 /*
23526Sxy150489  * This file is provided under a CDDLv1 license.  When using or
33526Sxy150489  * redistributing this file, you may do so under this license.
43526Sxy150489  * In redistributing this file this license must be included
53526Sxy150489  * and no other modification of this header file is permitted.
63526Sxy150489  *
73526Sxy150489  * CDDL LICENSE SUMMARY
83526Sxy150489  *
98850SMin.Xu@Sun.COM  * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
103526Sxy150489  *
113526Sxy150489  * The contents of this file are subject to the terms of Version
123526Sxy150489  * 1.0 of the Common Development and Distribution License (the "License").
133526Sxy150489  *
143526Sxy150489  * You should have received a copy of the License with this software.
153526Sxy150489  * You can obtain a copy of the License at
163526Sxy150489  *	http://www.opensolaris.org/os/licensing.
173526Sxy150489  * See the License for the specific language governing permissions
183526Sxy150489  * and limitations under the License.
193526Sxy150489  */
203526Sxy150489 
213526Sxy150489 /*
228850SMin.Xu@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
233526Sxy150489  * Use is subject to license terms of the CDDLv1.
243526Sxy150489  */
253526Sxy150489 
263526Sxy150489 /*
273526Sxy150489  * **********************************************************************
283526Sxy150489  * Module Name:								*
294919Sxy150489  *   e1000g_alloc.c							*
303526Sxy150489  *									*
313526Sxy150489  * Abstract:								*
324919Sxy150489  *   This file contains some routines that take care of			*
334919Sxy150489  *   memory allocation for descriptors and buffers.			*
343526Sxy150489  *									*
353526Sxy150489  * **********************************************************************
363526Sxy150489  */
373526Sxy150489 
383526Sxy150489 #include "e1000g_sw.h"
393526Sxy150489 #include "e1000g_debug.h"
403526Sxy150489 
413526Sxy150489 #define	TX_SW_PKT_AREA_SZ \
424919Sxy150489 	(sizeof (tx_sw_packet_t) * Adapter->tx_freelist_num)
433526Sxy150489 
443526Sxy150489 static int e1000g_alloc_tx_descriptors(e1000g_tx_ring_t *);
458850SMin.Xu@Sun.COM static int e1000g_alloc_rx_descriptors(e1000g_rx_data_t *);
463526Sxy150489 static void e1000g_free_tx_descriptors(e1000g_tx_ring_t *);
478850SMin.Xu@Sun.COM static void e1000g_free_rx_descriptors(e1000g_rx_data_t *);
483526Sxy150489 static int e1000g_alloc_tx_packets(e1000g_tx_ring_t *);
498850SMin.Xu@Sun.COM static int e1000g_alloc_rx_packets(e1000g_rx_data_t *);
503526Sxy150489 static void e1000g_free_tx_packets(e1000g_tx_ring_t *);
518850SMin.Xu@Sun.COM static void e1000g_free_rx_packets(e1000g_rx_data_t *);
524919Sxy150489 static int e1000g_alloc_dma_buffer(struct e1000g *,
534919Sxy150489     dma_buffer_t *, size_t, ddi_dma_attr_t *p_dma_attr);
548178SChenlu.Chen@Sun.COM 
558178SChenlu.Chen@Sun.COM /*
568178SChenlu.Chen@Sun.COM  * In order to avoid address error crossing 64KB boundary
578178SChenlu.Chen@Sun.COM  * during PCI-X packets receving, e1000g_alloc_dma_buffer_82546
588178SChenlu.Chen@Sun.COM  * is used by some necessary adapter types.
598178SChenlu.Chen@Sun.COM  */
608178SChenlu.Chen@Sun.COM static int e1000g_alloc_dma_buffer_82546(struct e1000g *,
618178SChenlu.Chen@Sun.COM     dma_buffer_t *, size_t, ddi_dma_attr_t *p_dma_attr);
628178SChenlu.Chen@Sun.COM static int e1000g_dma_mem_alloc_82546(dma_buffer_t *buf,
638178SChenlu.Chen@Sun.COM     size_t size, size_t *len);
648178SChenlu.Chen@Sun.COM static boolean_t e1000g_cross_64k_bound(void *, uintptr_t);
658178SChenlu.Chen@Sun.COM 
663526Sxy150489 static void e1000g_free_dma_buffer(dma_buffer_t *);
673526Sxy150489 #ifdef __sparc
683526Sxy150489 static int e1000g_alloc_dvma_buffer(struct e1000g *, dma_buffer_t *, size_t);
693526Sxy150489 static void e1000g_free_dvma_buffer(dma_buffer_t *);
703526Sxy150489 #endif
713526Sxy150489 static int e1000g_alloc_descriptors(struct e1000g *Adapter);
724919Sxy150489 static void e1000g_free_descriptors(struct e1000g *Adapter);
733526Sxy150489 static int e1000g_alloc_packets(struct e1000g *Adapter);
744919Sxy150489 static void e1000g_free_packets(struct e1000g *Adapter);
758850SMin.Xu@Sun.COM static p_rx_sw_packet_t e1000g_alloc_rx_sw_packet(e1000g_rx_data_t *,
764919Sxy150489     ddi_dma_attr_t *p_dma_attr);
774919Sxy150489 
784919Sxy150489 /* DMA access attributes for descriptors <Little Endian> */
794919Sxy150489 static ddi_device_acc_attr_t e1000g_desc_acc_attr = {
804919Sxy150489 	DDI_DEVICE_ATTR_V0,
814919Sxy150489 	DDI_STRUCTURE_LE_ACC,
824919Sxy150489 	DDI_STRICTORDER_ACC,
835273Sgl147354 	DDI_FLAGERR_ACC
844919Sxy150489 };
854919Sxy150489 
864919Sxy150489 /* DMA access attributes for DMA buffers */
874919Sxy150489 #ifdef __sparc
884919Sxy150489 static ddi_device_acc_attr_t e1000g_buf_acc_attr = {
894919Sxy150489 	DDI_DEVICE_ATTR_V0,
904919Sxy150489 	DDI_STRUCTURE_BE_ACC,
914919Sxy150489 	DDI_STRICTORDER_ACC,
924919Sxy150489 };
934919Sxy150489 #else
944919Sxy150489 static ddi_device_acc_attr_t e1000g_buf_acc_attr = {
954919Sxy150489 	DDI_DEVICE_ATTR_V0,
964919Sxy150489 	DDI_STRUCTURE_LE_ACC,
974919Sxy150489 	DDI_STRICTORDER_ACC,
984919Sxy150489 };
994919Sxy150489 #endif
1004919Sxy150489 
1014919Sxy150489 /* DMA attributes for tx mblk buffers */
1024919Sxy150489 static ddi_dma_attr_t e1000g_tx_dma_attr = {
1034919Sxy150489 	DMA_ATTR_V0,		/* version of this structure */
1044919Sxy150489 	0,			/* lowest usable address */
1054919Sxy150489 	0xffffffffffffffffULL,	/* highest usable address */
1064919Sxy150489 	0x7fffffff,		/* maximum DMAable byte count */
1074919Sxy150489 	1,			/* alignment in bytes */
1084919Sxy150489 	0x7ff,			/* burst sizes (any?) */
1094919Sxy150489 	1,			/* minimum transfer */
1104919Sxy150489 	0xffffffffU,		/* maximum transfer */
1114919Sxy150489 	0xffffffffffffffffULL,	/* maximum segment length */
1127607STed.You@Sun.COM 	MAX_COOKIES,		/* maximum number of segments */
1134919Sxy150489 	1,			/* granularity */
1145273Sgl147354 	DDI_DMA_FLAGERR,	/* dma_attr_flags */
1154919Sxy150489 };
1164919Sxy150489 
1174919Sxy150489 /* DMA attributes for pre-allocated rx/tx buffers */
1184919Sxy150489 static ddi_dma_attr_t e1000g_buf_dma_attr = {
1194919Sxy150489 	DMA_ATTR_V0,		/* version of this structure */
1204919Sxy150489 	0,			/* lowest usable address */
1214919Sxy150489 	0xffffffffffffffffULL,	/* highest usable address */
1224919Sxy150489 	0x7fffffff,		/* maximum DMAable byte count */
1234919Sxy150489 	1,			/* alignment in bytes */
1244919Sxy150489 	0x7ff,			/* burst sizes (any?) */
1254919Sxy150489 	1,			/* minimum transfer */
1264919Sxy150489 	0xffffffffU,		/* maximum transfer */
1274919Sxy150489 	0xffffffffffffffffULL,	/* maximum segment length */
1284919Sxy150489 	1,			/* maximum number of segments */
1294919Sxy150489 	1,			/* granularity */
1305273Sgl147354 	DDI_DMA_FLAGERR,	/* dma_attr_flags */
1314919Sxy150489 };
1324919Sxy150489 
1334919Sxy150489 /* DMA attributes for rx/tx descriptors */
1344919Sxy150489 static ddi_dma_attr_t e1000g_desc_dma_attr = {
1354919Sxy150489 	DMA_ATTR_V0,		/* version of this structure */
1364919Sxy150489 	0,			/* lowest usable address */
1374919Sxy150489 	0xffffffffffffffffULL,	/* highest usable address */
1384919Sxy150489 	0x7fffffff,		/* maximum DMAable byte count */
1398178SChenlu.Chen@Sun.COM 	E1000_MDALIGN,		/* default alignment is 4k but can be changed */
1404919Sxy150489 	0x7ff,			/* burst sizes (any?) */
1414919Sxy150489 	1,			/* minimum transfer */
1424919Sxy150489 	0xffffffffU,		/* maximum transfer */
1434919Sxy150489 	0xffffffffffffffffULL,	/* maximum segment length */
1444919Sxy150489 	1,			/* maximum number of segments */
1454919Sxy150489 	1,			/* granularity */
1465273Sgl147354 	DDI_DMA_FLAGERR,	/* dma_attr_flags */
1474919Sxy150489 };
1483526Sxy150489 
1493526Sxy150489 #ifdef __sparc
1503526Sxy150489 static ddi_dma_lim_t e1000g_dma_limits = {
1513526Sxy150489 	(uint_t)0,		/* dlim_addr_lo */
1523526Sxy150489 	(uint_t)0xffffffff,	/* dlim_addr_hi */
1533526Sxy150489 	(uint_t)0xffffffff,	/* dlim_cntr_max */
1543526Sxy150489 	(uint_t)0xfc00fc,	/* dlim_burstsizes for 32 and 64 bit xfers */
1553526Sxy150489 	0x1,			/* dlim_minxfer */
1563526Sxy150489 	1024			/* dlim_speed */
1573526Sxy150489 };
1583526Sxy150489 #endif
1593526Sxy150489 
1603526Sxy150489 #ifdef __sparc
1613526Sxy150489 static dma_type_t e1000g_dma_type = USE_DVMA;
1623526Sxy150489 #else
1633526Sxy150489 static dma_type_t e1000g_dma_type = USE_DMA;
1643526Sxy150489 #endif
1653526Sxy150489 
1663526Sxy150489 extern krwlock_t e1000g_dma_type_lock;
1673526Sxy150489 
1684919Sxy150489 
1693526Sxy150489 int
1703526Sxy150489 e1000g_alloc_dma_resources(struct e1000g *Adapter)
1713526Sxy150489 {
1724919Sxy150489 	int result;
1734919Sxy150489 
1744919Sxy150489 	result = DDI_FAILURE;
1753526Sxy150489 
1764919Sxy150489 	while ((result != DDI_SUCCESS) &&
1774919Sxy150489 	    (Adapter->tx_desc_num >= MIN_NUM_TX_DESCRIPTOR) &&
1784919Sxy150489 	    (Adapter->rx_desc_num >= MIN_NUM_RX_DESCRIPTOR) &&
1794919Sxy150489 	    (Adapter->tx_freelist_num >= MIN_NUM_TX_FREELIST) &&
1804919Sxy150489 	    (Adapter->rx_freelist_num >= MIN_NUM_RX_FREELIST)) {
1814919Sxy150489 
1824919Sxy150489 		result = e1000g_alloc_descriptors(Adapter);
1834919Sxy150489 
1844919Sxy150489 		if (result == DDI_SUCCESS) {
1854919Sxy150489 			result = e1000g_alloc_packets(Adapter);
1864919Sxy150489 
1874919Sxy150489 			if (result != DDI_SUCCESS)
1884919Sxy150489 				e1000g_free_descriptors(Adapter);
1894919Sxy150489 		}
1903526Sxy150489 
1914919Sxy150489 		/*
1924919Sxy150489 		 * If the allocation fails due to resource shortage,
1934919Sxy150489 		 * we'll reduce the numbers of descriptors/buffers by
1944919Sxy150489 		 * half, and try the allocation again.
1954919Sxy150489 		 */
1964919Sxy150489 		if (result != DDI_SUCCESS) {
1974919Sxy150489 			/*
1984919Sxy150489 			 * We must ensure the number of descriptors
1994919Sxy150489 			 * is always a multiple of 8.
2004919Sxy150489 			 */
2014919Sxy150489 			Adapter->tx_desc_num =
2024919Sxy150489 			    (Adapter->tx_desc_num >> 4) << 3;
2034919Sxy150489 			Adapter->rx_desc_num =
2044919Sxy150489 			    (Adapter->rx_desc_num >> 4) << 3;
2053526Sxy150489 
2064919Sxy150489 			Adapter->tx_freelist_num >>= 1;
2074919Sxy150489 			Adapter->rx_freelist_num >>= 1;
2084919Sxy150489 		}
2093526Sxy150489 	}
2103526Sxy150489 
2114919Sxy150489 	return (result);
2123526Sxy150489 }
2133526Sxy150489 
2143526Sxy150489 /*
2154919Sxy150489  * e1000g_alloc_descriptors - allocate DMA buffers for descriptors
2164919Sxy150489  *
2174919Sxy150489  * This routine allocates neccesary DMA buffers for
2184919Sxy150489  *	Transmit Descriptor Area
2194919Sxy150489  *	Receive Descrpitor Area
2203526Sxy150489  */
2213526Sxy150489 static int
2223526Sxy150489 e1000g_alloc_descriptors(struct e1000g *Adapter)
2233526Sxy150489 {
2243526Sxy150489 	int result;
2253526Sxy150489 	e1000g_tx_ring_t *tx_ring;
2268850SMin.Xu@Sun.COM 	e1000g_rx_data_t *rx_data;
2273526Sxy150489 
2288417SChenlu.Chen@Sun.COM 	if (Adapter->mem_workaround_82546 &&
2298417SChenlu.Chen@Sun.COM 	    ((Adapter->shared.mac.type == e1000_82545) ||
2308178SChenlu.Chen@Sun.COM 	    (Adapter->shared.mac.type == e1000_82546) ||
2318417SChenlu.Chen@Sun.COM 	    (Adapter->shared.mac.type == e1000_82546_rev_3))) {
2328178SChenlu.Chen@Sun.COM 		/* Align on a 64k boundary for these adapter types */
2338178SChenlu.Chen@Sun.COM 		Adapter->desc_align = E1000_MDALIGN_82546;
2348178SChenlu.Chen@Sun.COM 	} else {
2358178SChenlu.Chen@Sun.COM 		/* Align on a 4k boundary for all other adapter types */
2368178SChenlu.Chen@Sun.COM 		Adapter->desc_align = E1000_MDALIGN;
2378178SChenlu.Chen@Sun.COM 	}
2388178SChenlu.Chen@Sun.COM 
2393526Sxy150489 	tx_ring = Adapter->tx_ring;
2403526Sxy150489 
2413526Sxy150489 	result = e1000g_alloc_tx_descriptors(tx_ring);
2423526Sxy150489 	if (result != DDI_SUCCESS)
2433526Sxy150489 		return (DDI_FAILURE);
2443526Sxy150489 
2458850SMin.Xu@Sun.COM 	rx_data = Adapter->rx_ring->rx_data;
2463526Sxy150489 
2478850SMin.Xu@Sun.COM 	result = e1000g_alloc_rx_descriptors(rx_data);
2483526Sxy150489 	if (result != DDI_SUCCESS) {
2493526Sxy150489 		e1000g_free_tx_descriptors(tx_ring);
2503526Sxy150489 		return (DDI_FAILURE);
2513526Sxy150489 	}
2523526Sxy150489 
2533526Sxy150489 	return (DDI_SUCCESS);
2543526Sxy150489 }
2553526Sxy150489 
2564919Sxy150489 static void
2574919Sxy150489 e1000g_free_descriptors(struct e1000g *Adapter)
2584919Sxy150489 {
2594919Sxy150489 	e1000g_tx_ring_t *tx_ring;
2608850SMin.Xu@Sun.COM 	e1000g_rx_data_t *rx_data;
2614919Sxy150489 
2624919Sxy150489 	tx_ring = Adapter->tx_ring;
2638850SMin.Xu@Sun.COM 	rx_data = Adapter->rx_ring->rx_data;
2644919Sxy150489 
2654919Sxy150489 	e1000g_free_tx_descriptors(tx_ring);
2668850SMin.Xu@Sun.COM 	e1000g_free_rx_descriptors(rx_data);
2674919Sxy150489 }
2684919Sxy150489 
2693526Sxy150489 static int
2703526Sxy150489 e1000g_alloc_tx_descriptors(e1000g_tx_ring_t *tx_ring)
2713526Sxy150489 {
2723526Sxy150489 	int mystat;
2733526Sxy150489 	boolean_t alloc_flag;
2743526Sxy150489 	size_t size;
2753526Sxy150489 	size_t len;
2763526Sxy150489 	uintptr_t templong;
2773526Sxy150489 	uint_t cookie_count;
2783526Sxy150489 	dev_info_t *devinfo;
2793526Sxy150489 	ddi_dma_cookie_t cookie;
2803526Sxy150489 	struct e1000g *Adapter;
2814919Sxy150489 	ddi_dma_attr_t dma_attr;
2823526Sxy150489 
2833526Sxy150489 	Adapter = tx_ring->adapter;
2844919Sxy150489 	devinfo = Adapter->dip;
2853526Sxy150489 
2863526Sxy150489 	alloc_flag = B_FALSE;
2874919Sxy150489 	dma_attr = e1000g_desc_dma_attr;
2883526Sxy150489 
2893526Sxy150489 	/*
2903526Sxy150489 	 * Solaris 7 has a problem with allocating physically contiguous memory
2913526Sxy150489 	 * that is aligned on a 4K boundary. The transmit and rx descriptors
2923526Sxy150489 	 * need to aligned on a 4kbyte boundary. We first try to allocate the
2933526Sxy150489 	 * memory with DMA attributes set to 4K alignment and also no scatter/
2943526Sxy150489 	 * gather mechanism specified. In most cases, this does not allocate
2953526Sxy150489 	 * memory aligned at a 4Kbyte boundary. We then try asking for memory
2963526Sxy150489 	 * aligned on 4K boundary with scatter/gather set to 2. This works when
2973526Sxy150489 	 * the amount of memory is less than 4k i.e a page size. If neither of
2983526Sxy150489 	 * these options work or if the number of descriptors is greater than
2993526Sxy150489 	 * 4K, ie more than 256 descriptors, we allocate 4k extra memory and
3003526Sxy150489 	 * and then align the memory at a 4k boundary.
3013526Sxy150489 	 */
3024919Sxy150489 	size = sizeof (struct e1000_tx_desc) * Adapter->tx_desc_num;
3033526Sxy150489 
3043526Sxy150489 	/*
3053526Sxy150489 	 * Memory allocation for the transmit buffer descriptors.
3063526Sxy150489 	 */
3074919Sxy150489 	dma_attr.dma_attr_sgllen = 1;
3088178SChenlu.Chen@Sun.COM 	dma_attr.dma_attr_align = Adapter->desc_align;
3093526Sxy150489 
3103526Sxy150489 	/*
3113526Sxy150489 	 * Allocate a new DMA handle for the transmit descriptor
3123526Sxy150489 	 * memory area.
3133526Sxy150489 	 */
3144919Sxy150489 	mystat = ddi_dma_alloc_handle(devinfo, &dma_attr,
3153526Sxy150489 	    DDI_DMA_DONTWAIT, 0,
3163526Sxy150489 	    &tx_ring->tbd_dma_handle);
3173526Sxy150489 
3183526Sxy150489 	if (mystat != DDI_SUCCESS) {
3194919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
3203526Sxy150489 		    "Could not allocate tbd dma handle: %d", mystat);
3213526Sxy150489 		tx_ring->tbd_dma_handle = NULL;
3223526Sxy150489 		return (DDI_FAILURE);
3233526Sxy150489 	}
3243526Sxy150489 
3253526Sxy150489 	/*
3263526Sxy150489 	 * Allocate memory to DMA data to and from the transmit
3273526Sxy150489 	 * descriptors.
3283526Sxy150489 	 */
3293526Sxy150489 	mystat = ddi_dma_mem_alloc(tx_ring->tbd_dma_handle,
3303526Sxy150489 	    size,
3314919Sxy150489 	    &e1000g_desc_acc_attr, DDI_DMA_CONSISTENT,
3323526Sxy150489 	    DDI_DMA_DONTWAIT, 0,
3333526Sxy150489 	    (caddr_t *)&tx_ring->tbd_area,
3343526Sxy150489 	    &len, &tx_ring->tbd_acc_handle);
3353526Sxy150489 
3363526Sxy150489 	if ((mystat != DDI_SUCCESS) ||
3378178SChenlu.Chen@Sun.COM 	    ((uintptr_t)tx_ring->tbd_area & (Adapter->desc_align - 1))) {
3383526Sxy150489 		if (mystat == DDI_SUCCESS) {
3393526Sxy150489 			ddi_dma_mem_free(&tx_ring->tbd_acc_handle);
3403526Sxy150489 			tx_ring->tbd_acc_handle = NULL;
3413526Sxy150489 			tx_ring->tbd_area = NULL;
3423526Sxy150489 		}
3433526Sxy150489 		if (tx_ring->tbd_dma_handle != NULL) {
3443526Sxy150489 			ddi_dma_free_handle(&tx_ring->tbd_dma_handle);
3453526Sxy150489 			tx_ring->tbd_dma_handle = NULL;
3463526Sxy150489 		}
3473526Sxy150489 		alloc_flag = B_FALSE;
3483526Sxy150489 	} else
3493526Sxy150489 		alloc_flag = B_TRUE;
3503526Sxy150489 
3513526Sxy150489 	/*
3523526Sxy150489 	 * Initialize the entire transmit buffer descriptor area to zero
3533526Sxy150489 	 */
3543526Sxy150489 	if (alloc_flag)
3553526Sxy150489 		bzero(tx_ring->tbd_area, len);
3563526Sxy150489 
3573526Sxy150489 	/*
3583526Sxy150489 	 * If the previous DMA attributes setting could not give us contiguous
3593526Sxy150489 	 * memory or the number of descriptors is greater than the page size,
3608178SChenlu.Chen@Sun.COM 	 * we allocate extra memory and then align it at appropriate boundary.
3613526Sxy150489 	 */
3623526Sxy150489 	if (!alloc_flag) {
3638178SChenlu.Chen@Sun.COM 		size = size + Adapter->desc_align;
3643526Sxy150489 
3653526Sxy150489 		/*
3663526Sxy150489 		 * DMA attributes set to no scatter/gather and 16 bit alignment
3673526Sxy150489 		 */
3684919Sxy150489 		dma_attr.dma_attr_align = 1;
3694919Sxy150489 		dma_attr.dma_attr_sgllen = 1;
3703526Sxy150489 
3713526Sxy150489 		/*
3723526Sxy150489 		 * Allocate a new DMA handle for the transmit descriptor memory
3733526Sxy150489 		 * area.
3743526Sxy150489 		 */
3754919Sxy150489 		mystat = ddi_dma_alloc_handle(devinfo, &dma_attr,
3763526Sxy150489 		    DDI_DMA_DONTWAIT, 0,
3773526Sxy150489 		    &tx_ring->tbd_dma_handle);
3783526Sxy150489 
3793526Sxy150489 		if (mystat != DDI_SUCCESS) {
3804919Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
3813526Sxy150489 			    "Could not re-allocate tbd dma handle: %d", mystat);
3823526Sxy150489 			tx_ring->tbd_dma_handle = NULL;
3833526Sxy150489 			return (DDI_FAILURE);
3843526Sxy150489 		}
3853526Sxy150489 
3863526Sxy150489 		/*
3873526Sxy150489 		 * Allocate memory to DMA data to and from the transmit
3883526Sxy150489 		 * descriptors.
3893526Sxy150489 		 */
3903526Sxy150489 		mystat = ddi_dma_mem_alloc(tx_ring->tbd_dma_handle,
3913526Sxy150489 		    size,
3924919Sxy150489 		    &e1000g_desc_acc_attr, DDI_DMA_CONSISTENT,
3933526Sxy150489 		    DDI_DMA_DONTWAIT, 0,
3943526Sxy150489 		    (caddr_t *)&tx_ring->tbd_area,
3953526Sxy150489 		    &len, &tx_ring->tbd_acc_handle);
3963526Sxy150489 
3973526Sxy150489 		if (mystat != DDI_SUCCESS) {
3984919Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
3993526Sxy150489 			    "Could not allocate tbd dma memory: %d", mystat);
4003526Sxy150489 			tx_ring->tbd_acc_handle = NULL;
4013526Sxy150489 			tx_ring->tbd_area = NULL;
4023526Sxy150489 			if (tx_ring->tbd_dma_handle != NULL) {
4033526Sxy150489 				ddi_dma_free_handle(&tx_ring->tbd_dma_handle);
4043526Sxy150489 				tx_ring->tbd_dma_handle = NULL;
4053526Sxy150489 			}
4063526Sxy150489 			return (DDI_FAILURE);
4073526Sxy150489 		} else
4083526Sxy150489 			alloc_flag = B_TRUE;
4093526Sxy150489 
4103526Sxy150489 		/*
4113526Sxy150489 		 * Initialize the entire transmit buffer descriptor area to zero
4123526Sxy150489 		 */
4133526Sxy150489 		bzero(tx_ring->tbd_area, len);
4143526Sxy150489 		/*
4153526Sxy150489 		 * Memory has been allocated with the ddi_dma_mem_alloc call,
4168178SChenlu.Chen@Sun.COM 		 * but has not been aligned.
4178178SChenlu.Chen@Sun.COM 		 * We now align it on the appropriate boundary.
4183526Sxy150489 		 */
4198178SChenlu.Chen@Sun.COM 		templong = P2NPHASE((uintptr_t)tx_ring->tbd_area,
4208178SChenlu.Chen@Sun.COM 		    Adapter->desc_align);
4213526Sxy150489 		len = size - templong;
4223526Sxy150489 		templong += (uintptr_t)tx_ring->tbd_area;
4233526Sxy150489 		tx_ring->tbd_area = (struct e1000_tx_desc *)templong;
4243526Sxy150489 	}	/* alignment workaround */
4253526Sxy150489 
4263526Sxy150489 	/*
4273526Sxy150489 	 * Transmit buffer descriptor memory allocation succeeded
4283526Sxy150489 	 */
4293526Sxy150489 	ASSERT(alloc_flag);
4303526Sxy150489 
4313526Sxy150489 	/*
4323526Sxy150489 	 * Allocates DMA resources for the memory that was allocated by
4333526Sxy150489 	 * the ddi_dma_mem_alloc call. The DMA resources then get bound to the
4343526Sxy150489 	 * the memory address
4353526Sxy150489 	 */
4363526Sxy150489 	mystat = ddi_dma_addr_bind_handle(tx_ring->tbd_dma_handle,
4373526Sxy150489 	    (struct as *)NULL, (caddr_t)tx_ring->tbd_area,
4383526Sxy150489 	    len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
4394919Sxy150489 	    DDI_DMA_DONTWAIT, 0, &cookie, &cookie_count);
4403526Sxy150489 
4413526Sxy150489 	if (mystat != DDI_SUCCESS) {
4424919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
4433526Sxy150489 		    "Could not bind tbd dma resource: %d", mystat);
4443526Sxy150489 		if (tx_ring->tbd_acc_handle != NULL) {
4453526Sxy150489 			ddi_dma_mem_free(&tx_ring->tbd_acc_handle);
4463526Sxy150489 			tx_ring->tbd_acc_handle = NULL;
4473526Sxy150489 			tx_ring->tbd_area = NULL;
4483526Sxy150489 		}
4493526Sxy150489 		if (tx_ring->tbd_dma_handle != NULL) {
4503526Sxy150489 			ddi_dma_free_handle(&tx_ring->tbd_dma_handle);
4513526Sxy150489 			tx_ring->tbd_dma_handle = NULL;
4523526Sxy150489 		}
4533526Sxy150489 		return (DDI_FAILURE);
4543526Sxy150489 	}
4553526Sxy150489 
4563526Sxy150489 	ASSERT(cookie_count == 1);	/* 1 cookie */
4573526Sxy150489 
4583526Sxy150489 	if (cookie_count != 1) {
4594919Sxy150489 		E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL,
4603526Sxy150489 		    "Could not bind tbd dma resource in a single frag. "
4613526Sxy150489 		    "Count - %d Len - %d", cookie_count, len);
4623526Sxy150489 		e1000g_free_tx_descriptors(tx_ring);
4633526Sxy150489 		return (DDI_FAILURE);
4643526Sxy150489 	}
4653526Sxy150489 
4663526Sxy150489 	tx_ring->tbd_dma_addr = cookie.dmac_laddress;
4673526Sxy150489 	tx_ring->tbd_first = tx_ring->tbd_area;
4683526Sxy150489 	tx_ring->tbd_last = tx_ring->tbd_first +
4694919Sxy150489 	    (Adapter->tx_desc_num - 1);
4703526Sxy150489 
4713526Sxy150489 	return (DDI_SUCCESS);
4723526Sxy150489 }
4733526Sxy150489 
4743526Sxy150489 static int
4758850SMin.Xu@Sun.COM e1000g_alloc_rx_descriptors(e1000g_rx_data_t *rx_data)
4763526Sxy150489 {
4773526Sxy150489 	int mystat;
4783526Sxy150489 	boolean_t alloc_flag;
4793526Sxy150489 	size_t size;
4803526Sxy150489 	size_t len;
4813526Sxy150489 	uintptr_t templong;
4823526Sxy150489 	uint_t cookie_count;
4833526Sxy150489 	dev_info_t *devinfo;
4843526Sxy150489 	ddi_dma_cookie_t cookie;
4853526Sxy150489 	struct e1000g *Adapter;
4864919Sxy150489 	ddi_dma_attr_t dma_attr;
4873526Sxy150489 
4888850SMin.Xu@Sun.COM 	Adapter = rx_data->rx_ring->adapter;
4894919Sxy150489 	devinfo = Adapter->dip;
4903526Sxy150489 
4913526Sxy150489 	alloc_flag = B_FALSE;
4924919Sxy150489 	dma_attr = e1000g_desc_dma_attr;
4933526Sxy150489 
4943526Sxy150489 	/*
4953526Sxy150489 	 * Memory allocation for the receive buffer descriptors.
4963526Sxy150489 	 */
4974919Sxy150489 	size = (sizeof (struct e1000_rx_desc)) * Adapter->rx_desc_num;
4983526Sxy150489 
4993526Sxy150489 	/*
5008178SChenlu.Chen@Sun.COM 	 * Asking for aligned memory with DMA attributes set for suitable value
5013526Sxy150489 	 */
5024919Sxy150489 	dma_attr.dma_attr_sgllen = 1;
5038178SChenlu.Chen@Sun.COM 	dma_attr.dma_attr_align = Adapter->desc_align;
5043526Sxy150489 
5053526Sxy150489 	/*
5064919Sxy150489 	 * Allocate a new DMA handle for the receive descriptors
5073526Sxy150489 	 */
5084919Sxy150489 	mystat = ddi_dma_alloc_handle(devinfo, &dma_attr,
5093526Sxy150489 	    DDI_DMA_DONTWAIT, 0,
5108850SMin.Xu@Sun.COM 	    &rx_data->rbd_dma_handle);
5113526Sxy150489 
5123526Sxy150489 	if (mystat != DDI_SUCCESS) {
5134919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
5143526Sxy150489 		    "Could not allocate rbd dma handle: %d", mystat);
5158850SMin.Xu@Sun.COM 		rx_data->rbd_dma_handle = NULL;
5163526Sxy150489 		return (DDI_FAILURE);
5173526Sxy150489 	}
5183526Sxy150489 	/*
5193526Sxy150489 	 * Allocate memory to DMA data to and from the receive
5203526Sxy150489 	 * descriptors.
5213526Sxy150489 	 */
5228850SMin.Xu@Sun.COM 	mystat = ddi_dma_mem_alloc(rx_data->rbd_dma_handle,
5233526Sxy150489 	    size,
5244919Sxy150489 	    &e1000g_desc_acc_attr, DDI_DMA_CONSISTENT,
5253526Sxy150489 	    DDI_DMA_DONTWAIT, 0,
5268850SMin.Xu@Sun.COM 	    (caddr_t *)&rx_data->rbd_area,
5278850SMin.Xu@Sun.COM 	    &len, &rx_data->rbd_acc_handle);
5283526Sxy150489 
5293526Sxy150489 	/*
5303526Sxy150489 	 * Check if memory allocation succeeded and also if the
5313526Sxy150489 	 * allocated memory is aligned correctly.
5323526Sxy150489 	 */
5333526Sxy150489 	if ((mystat != DDI_SUCCESS) ||
5348850SMin.Xu@Sun.COM 	    ((uintptr_t)rx_data->rbd_area & (Adapter->desc_align - 1))) {
5353526Sxy150489 		if (mystat == DDI_SUCCESS) {
5368850SMin.Xu@Sun.COM 			ddi_dma_mem_free(&rx_data->rbd_acc_handle);
5378850SMin.Xu@Sun.COM 			rx_data->rbd_acc_handle = NULL;
5388850SMin.Xu@Sun.COM 			rx_data->rbd_area = NULL;
5393526Sxy150489 		}
5408850SMin.Xu@Sun.COM 		if (rx_data->rbd_dma_handle != NULL) {
5418850SMin.Xu@Sun.COM 			ddi_dma_free_handle(&rx_data->rbd_dma_handle);
5428850SMin.Xu@Sun.COM 			rx_data->rbd_dma_handle = NULL;
5433526Sxy150489 		}
5443526Sxy150489 		alloc_flag = B_FALSE;
5453526Sxy150489 	} else
5463526Sxy150489 		alloc_flag = B_TRUE;
5473526Sxy150489 
5483526Sxy150489 	/*
5493526Sxy150489 	 * Initialize the allocated receive descriptor memory to zero.
5503526Sxy150489 	 */
5513526Sxy150489 	if (alloc_flag)
5528850SMin.Xu@Sun.COM 		bzero((caddr_t)rx_data->rbd_area, len);
5533526Sxy150489 
5543526Sxy150489 	/*
5554919Sxy150489 	 * If memory allocation did not succeed, do the alignment ourselves
5563526Sxy150489 	 */
5573526Sxy150489 	if (!alloc_flag) {
5584919Sxy150489 		dma_attr.dma_attr_align = 1;
5594919Sxy150489 		dma_attr.dma_attr_sgllen = 1;
5608178SChenlu.Chen@Sun.COM 		size = size + Adapter->desc_align;
5613526Sxy150489 		/*
5624919Sxy150489 		 * Allocate a new DMA handle for the receive descriptor.
5633526Sxy150489 		 */
5644919Sxy150489 		mystat = ddi_dma_alloc_handle(devinfo, &dma_attr,
5653526Sxy150489 		    DDI_DMA_DONTWAIT, 0,
5668850SMin.Xu@Sun.COM 		    &rx_data->rbd_dma_handle);
5673526Sxy150489 
5683526Sxy150489 		if (mystat != DDI_SUCCESS) {
5694919Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
5703526Sxy150489 			    "Could not re-allocate rbd dma handle: %d", mystat);
5718850SMin.Xu@Sun.COM 			rx_data->rbd_dma_handle = NULL;
5723526Sxy150489 			return (DDI_FAILURE);
5733526Sxy150489 		}
5743526Sxy150489 		/*
5753526Sxy150489 		 * Allocate memory to DMA data to and from the receive
5763526Sxy150489 		 * descriptors.
5773526Sxy150489 		 */
5788850SMin.Xu@Sun.COM 		mystat = ddi_dma_mem_alloc(rx_data->rbd_dma_handle,
5793526Sxy150489 		    size,
5804919Sxy150489 		    &e1000g_desc_acc_attr, DDI_DMA_CONSISTENT,
5813526Sxy150489 		    DDI_DMA_DONTWAIT, 0,
5828850SMin.Xu@Sun.COM 		    (caddr_t *)&rx_data->rbd_area,
5838850SMin.Xu@Sun.COM 		    &len, &rx_data->rbd_acc_handle);
5843526Sxy150489 
5853526Sxy150489 		if (mystat != DDI_SUCCESS) {
5864919Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
5873526Sxy150489 			    "Could not allocate rbd dma memory: %d", mystat);
5888850SMin.Xu@Sun.COM 			rx_data->rbd_acc_handle = NULL;
5898850SMin.Xu@Sun.COM 			rx_data->rbd_area = NULL;
5908850SMin.Xu@Sun.COM 			if (rx_data->rbd_dma_handle != NULL) {
5918850SMin.Xu@Sun.COM 				ddi_dma_free_handle(&rx_data->rbd_dma_handle);
5928850SMin.Xu@Sun.COM 				rx_data->rbd_dma_handle = NULL;
5933526Sxy150489 			}
5943526Sxy150489 			return (DDI_FAILURE);
5953526Sxy150489 		} else
5963526Sxy150489 			alloc_flag = B_TRUE;
5973526Sxy150489 
5983526Sxy150489 		/*
5993526Sxy150489 		 * Initialize the allocated receive descriptor memory to zero.
6003526Sxy150489 		 */
6018850SMin.Xu@Sun.COM 		bzero((caddr_t)rx_data->rbd_area, len);
6028850SMin.Xu@Sun.COM 		templong = P2NPHASE((uintptr_t)rx_data->rbd_area,
6038178SChenlu.Chen@Sun.COM 		    Adapter->desc_align);
6043526Sxy150489 		len = size - templong;
6058850SMin.Xu@Sun.COM 		templong += (uintptr_t)rx_data->rbd_area;
6068850SMin.Xu@Sun.COM 		rx_data->rbd_area = (struct e1000_rx_desc *)templong;
6073526Sxy150489 	}	/* alignment workaround */
6083526Sxy150489 
6093526Sxy150489 	/*
6103526Sxy150489 	 * The memory allocation of the receive descriptors succeeded
6113526Sxy150489 	 */
6123526Sxy150489 	ASSERT(alloc_flag);
6133526Sxy150489 
6143526Sxy150489 	/*
6153526Sxy150489 	 * Allocates DMA resources for the memory that was allocated by
6163526Sxy150489 	 * the ddi_dma_mem_alloc call.
6173526Sxy150489 	 */
6188850SMin.Xu@Sun.COM 	mystat = ddi_dma_addr_bind_handle(rx_data->rbd_dma_handle,
6198850SMin.Xu@Sun.COM 	    (struct as *)NULL, (caddr_t)rx_data->rbd_area,
6204349Sxy150489 	    len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6214919Sxy150489 	    DDI_DMA_DONTWAIT, 0, &cookie, &cookie_count);
6223526Sxy150489 
6233526Sxy150489 	if (mystat != DDI_SUCCESS) {
6244919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
6253526Sxy150489 		    "Could not bind rbd dma resource: %d", mystat);
6268850SMin.Xu@Sun.COM 		if (rx_data->rbd_acc_handle != NULL) {
6278850SMin.Xu@Sun.COM 			ddi_dma_mem_free(&rx_data->rbd_acc_handle);
6288850SMin.Xu@Sun.COM 			rx_data->rbd_acc_handle = NULL;
6298850SMin.Xu@Sun.COM 			rx_data->rbd_area = NULL;
6303526Sxy150489 		}
6318850SMin.Xu@Sun.COM 		if (rx_data->rbd_dma_handle != NULL) {
6328850SMin.Xu@Sun.COM 			ddi_dma_free_handle(&rx_data->rbd_dma_handle);
6338850SMin.Xu@Sun.COM 			rx_data->rbd_dma_handle = NULL;
6343526Sxy150489 		}
6353526Sxy150489 		return (DDI_FAILURE);
6363526Sxy150489 	}
6373526Sxy150489 
6383526Sxy150489 	ASSERT(cookie_count == 1);
6393526Sxy150489 	if (cookie_count != 1) {
6404919Sxy150489 		E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL,
6413526Sxy150489 		    "Could not bind rbd dma resource in a single frag. "
6423526Sxy150489 		    "Count - %d Len - %d", cookie_count, len);
6438850SMin.Xu@Sun.COM 		e1000g_free_rx_descriptors(rx_data);
6443526Sxy150489 		return (DDI_FAILURE);
6453526Sxy150489 	}
6464919Sxy150489 
6478850SMin.Xu@Sun.COM 	rx_data->rbd_dma_addr = cookie.dmac_laddress;
6488850SMin.Xu@Sun.COM 	rx_data->rbd_first = rx_data->rbd_area;
6498850SMin.Xu@Sun.COM 	rx_data->rbd_last = rx_data->rbd_first +
6504919Sxy150489 	    (Adapter->rx_desc_num - 1);
6513526Sxy150489 
6523526Sxy150489 	return (DDI_SUCCESS);
6533526Sxy150489 }
6543526Sxy150489 
6553526Sxy150489 static void
6568850SMin.Xu@Sun.COM e1000g_free_rx_descriptors(e1000g_rx_data_t *rx_data)
6573526Sxy150489 {
6588850SMin.Xu@Sun.COM 	if (rx_data->rbd_dma_handle != NULL) {
6598850SMin.Xu@Sun.COM 		(void) ddi_dma_unbind_handle(rx_data->rbd_dma_handle);
6603526Sxy150489 	}
6618850SMin.Xu@Sun.COM 	if (rx_data->rbd_acc_handle != NULL) {
6628850SMin.Xu@Sun.COM 		ddi_dma_mem_free(&rx_data->rbd_acc_handle);
6638850SMin.Xu@Sun.COM 		rx_data->rbd_acc_handle = NULL;
6648850SMin.Xu@Sun.COM 		rx_data->rbd_area = NULL;
6653526Sxy150489 	}
6668850SMin.Xu@Sun.COM 	if (rx_data->rbd_dma_handle != NULL) {
6678850SMin.Xu@Sun.COM 		ddi_dma_free_handle(&rx_data->rbd_dma_handle);
6688850SMin.Xu@Sun.COM 		rx_data->rbd_dma_handle = NULL;
6693526Sxy150489 	}
6708850SMin.Xu@Sun.COM 	rx_data->rbd_dma_addr = NULL;
6718850SMin.Xu@Sun.COM 	rx_data->rbd_first = NULL;
6728850SMin.Xu@Sun.COM 	rx_data->rbd_last = NULL;
6733526Sxy150489 }
6743526Sxy150489 
6753526Sxy150489 static void
6763526Sxy150489 e1000g_free_tx_descriptors(e1000g_tx_ring_t *tx_ring)
6773526Sxy150489 {
6783526Sxy150489 	if (tx_ring->tbd_dma_handle != NULL) {
6797426SChenliang.Xu@Sun.COM 		(void) ddi_dma_unbind_handle(tx_ring->tbd_dma_handle);
6803526Sxy150489 	}
6813526Sxy150489 	if (tx_ring->tbd_acc_handle != NULL) {
6823526Sxy150489 		ddi_dma_mem_free(&tx_ring->tbd_acc_handle);
6833526Sxy150489 		tx_ring->tbd_acc_handle = NULL;
6843526Sxy150489 		tx_ring->tbd_area = NULL;
6853526Sxy150489 	}
6863526Sxy150489 	if (tx_ring->tbd_dma_handle != NULL) {
6873526Sxy150489 		ddi_dma_free_handle(&tx_ring->tbd_dma_handle);
6883526Sxy150489 		tx_ring->tbd_dma_handle = NULL;
6893526Sxy150489 	}
6903526Sxy150489 	tx_ring->tbd_dma_addr = NULL;
6913526Sxy150489 	tx_ring->tbd_first = NULL;
6923526Sxy150489 	tx_ring->tbd_last = NULL;
6933526Sxy150489 }
6943526Sxy150489 
6953526Sxy150489 
6963526Sxy150489 /*
6974919Sxy150489  * e1000g_alloc_packets - allocate DMA buffers for rx/tx
6984919Sxy150489  *
6994919Sxy150489  * This routine allocates neccesary buffers for
7004919Sxy150489  *	 Transmit sw packet structure
7014919Sxy150489  *	 DMA handle for Transmit
7024919Sxy150489  *	 DMA buffer for Transmit
7034919Sxy150489  *	 Receive sw packet structure
7044919Sxy150489  *	 DMA buffer for Receive
7053526Sxy150489  */
7063526Sxy150489 static int
7073526Sxy150489 e1000g_alloc_packets(struct e1000g *Adapter)
7083526Sxy150489 {
7093526Sxy150489 	int result;
7103526Sxy150489 	e1000g_tx_ring_t *tx_ring;
7118850SMin.Xu@Sun.COM 	e1000g_rx_data_t *rx_data;
7123526Sxy150489 
7133526Sxy150489 	tx_ring = Adapter->tx_ring;
7148850SMin.Xu@Sun.COM 	rx_data = Adapter->rx_ring->rx_data;
7153526Sxy150489 
7163526Sxy150489 again:
7173526Sxy150489 	rw_enter(&e1000g_dma_type_lock, RW_READER);
7183526Sxy150489 
7193526Sxy150489 	result = e1000g_alloc_tx_packets(tx_ring);
7203526Sxy150489 	if (result != DDI_SUCCESS) {
7213526Sxy150489 		if (e1000g_dma_type == USE_DVMA) {
7223526Sxy150489 			rw_exit(&e1000g_dma_type_lock);
7233526Sxy150489 
7243526Sxy150489 			rw_enter(&e1000g_dma_type_lock, RW_WRITER);
7253526Sxy150489 			e1000g_dma_type = USE_DMA;
7263526Sxy150489 			rw_exit(&e1000g_dma_type_lock);
7273526Sxy150489 
7284919Sxy150489 			E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
7293526Sxy150489 			    "No enough dvma resource for Tx packets, "
7303526Sxy150489 			    "trying to allocate dma buffers...\n");
7313526Sxy150489 			goto again;
7323526Sxy150489 		}
7333526Sxy150489 		rw_exit(&e1000g_dma_type_lock);
7343526Sxy150489 
7354919Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
7363526Sxy150489 		    "Failed to allocate dma buffers for Tx packets\n");
7373526Sxy150489 		return (DDI_FAILURE);
7383526Sxy150489 	}
7393526Sxy150489 
7408850SMin.Xu@Sun.COM 	result = e1000g_alloc_rx_packets(rx_data);
7413526Sxy150489 	if (result != DDI_SUCCESS) {
7423526Sxy150489 		e1000g_free_tx_packets(tx_ring);
7433526Sxy150489 		if (e1000g_dma_type == USE_DVMA) {
7443526Sxy150489 			rw_exit(&e1000g_dma_type_lock);
7453526Sxy150489 
7463526Sxy150489 			rw_enter(&e1000g_dma_type_lock, RW_WRITER);
7473526Sxy150489 			e1000g_dma_type = USE_DMA;
7483526Sxy150489 			rw_exit(&e1000g_dma_type_lock);
7493526Sxy150489 
7504919Sxy150489 			E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
7513526Sxy150489 			    "No enough dvma resource for Rx packets, "
7523526Sxy150489 			    "trying to allocate dma buffers...\n");
7533526Sxy150489 			goto again;
7543526Sxy150489 		}
7553526Sxy150489 		rw_exit(&e1000g_dma_type_lock);
7563526Sxy150489 
7574919Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
7583526Sxy150489 		    "Failed to allocate dma buffers for Rx packets\n");
7593526Sxy150489 		return (DDI_FAILURE);
7603526Sxy150489 	}
7613526Sxy150489 
7623526Sxy150489 	rw_exit(&e1000g_dma_type_lock);
7633526Sxy150489 
7643526Sxy150489 	return (DDI_SUCCESS);
7653526Sxy150489 }
7663526Sxy150489 
7674919Sxy150489 static void
7684919Sxy150489 e1000g_free_packets(struct e1000g *Adapter)
7694919Sxy150489 {
7704919Sxy150489 	e1000g_tx_ring_t *tx_ring;
7718850SMin.Xu@Sun.COM 	e1000g_rx_data_t *rx_data;
7724919Sxy150489 
7734919Sxy150489 	tx_ring = Adapter->tx_ring;
7748850SMin.Xu@Sun.COM 	rx_data = Adapter->rx_ring->rx_data;
7754919Sxy150489 
7764919Sxy150489 	e1000g_free_tx_packets(tx_ring);
7778850SMin.Xu@Sun.COM 	e1000g_free_rx_packets(rx_data);
7784919Sxy150489 }
7794919Sxy150489 
7803526Sxy150489 #ifdef __sparc
7813526Sxy150489 static int
7823526Sxy150489 e1000g_alloc_dvma_buffer(struct e1000g *Adapter,
7833526Sxy150489     dma_buffer_t *buf, size_t size)
7843526Sxy150489 {
7853526Sxy150489 	int mystat;
7863526Sxy150489 	dev_info_t *devinfo;
7873526Sxy150489 	ddi_dma_cookie_t cookie;
7883526Sxy150489 
7894349Sxy150489 	if (e1000g_force_detach)
7904349Sxy150489 		devinfo = Adapter->priv_dip;
7914349Sxy150489 	else
7924349Sxy150489 		devinfo = Adapter->dip;
7933526Sxy150489 
7943526Sxy150489 	mystat = dvma_reserve(devinfo,
7953526Sxy150489 	    &e1000g_dma_limits,
7963526Sxy150489 	    Adapter->dvma_page_num,
7973526Sxy150489 	    &buf->dma_handle);
7983526Sxy150489 
7993526Sxy150489 	if (mystat != DDI_SUCCESS) {
8003526Sxy150489 		buf->dma_handle = NULL;
8014919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
8023526Sxy150489 		    "Could not allocate dvma buffer handle: %d\n", mystat);
8033526Sxy150489 		return (DDI_FAILURE);
8043526Sxy150489 	}
8053526Sxy150489 
8063526Sxy150489 	buf->address = kmem_alloc(size, KM_NOSLEEP);
8073526Sxy150489 
8083526Sxy150489 	if (buf->address == NULL) {
8093526Sxy150489 		if (buf->dma_handle != NULL) {
8103526Sxy150489 			dvma_release(buf->dma_handle);
8113526Sxy150489 			buf->dma_handle = NULL;
8123526Sxy150489 		}
8134919Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
8143526Sxy150489 		    "Could not allocate dvma buffer memory\n");
8153526Sxy150489 		return (DDI_FAILURE);
8163526Sxy150489 	}
8173526Sxy150489 
8183526Sxy150489 	dvma_kaddr_load(buf->dma_handle,
8193526Sxy150489 	    buf->address, size, 0, &cookie);
8203526Sxy150489 
8213526Sxy150489 	buf->dma_address = cookie.dmac_laddress;
8223526Sxy150489 	buf->size = size;
8233526Sxy150489 	buf->len = 0;
8243526Sxy150489 
8253526Sxy150489 	return (DDI_SUCCESS);
8263526Sxy150489 }
8273526Sxy150489 
8283526Sxy150489 static void
8293526Sxy150489 e1000g_free_dvma_buffer(dma_buffer_t *buf)
8303526Sxy150489 {
8313526Sxy150489 	if (buf->dma_handle != NULL) {
8323526Sxy150489 		dvma_unload(buf->dma_handle, 0, -1);
8333526Sxy150489 	} else {
8343526Sxy150489 		return;
8353526Sxy150489 	}
8363526Sxy150489 
8373526Sxy150489 	buf->dma_address = NULL;
8383526Sxy150489 
8393526Sxy150489 	if (buf->address != NULL) {
8403526Sxy150489 		kmem_free(buf->address, buf->size);
8413526Sxy150489 		buf->address = NULL;
8423526Sxy150489 	}
8433526Sxy150489 
8443526Sxy150489 	if (buf->dma_handle != NULL) {
8453526Sxy150489 		dvma_release(buf->dma_handle);
8463526Sxy150489 		buf->dma_handle = NULL;
8473526Sxy150489 	}
8483526Sxy150489 
8493526Sxy150489 	buf->size = 0;
8503526Sxy150489 	buf->len = 0;
8513526Sxy150489 }
8523526Sxy150489 #endif
8533526Sxy150489 
8543526Sxy150489 static int
8553526Sxy150489 e1000g_alloc_dma_buffer(struct e1000g *Adapter,
8564919Sxy150489     dma_buffer_t *buf, size_t size, ddi_dma_attr_t *p_dma_attr)
8573526Sxy150489 {
8583526Sxy150489 	int mystat;
8593526Sxy150489 	dev_info_t *devinfo;
8603526Sxy150489 	ddi_dma_cookie_t cookie;
8613526Sxy150489 	size_t len;
8623526Sxy150489 	uint_t count;
8633526Sxy150489 
8644349Sxy150489 	if (e1000g_force_detach)
8654349Sxy150489 		devinfo = Adapter->priv_dip;
8664349Sxy150489 	else
8674349Sxy150489 		devinfo = Adapter->dip;
8683526Sxy150489 
8693526Sxy150489 	mystat = ddi_dma_alloc_handle(devinfo,
8704919Sxy150489 	    p_dma_attr,
8713526Sxy150489 	    DDI_DMA_DONTWAIT, 0,
8723526Sxy150489 	    &buf->dma_handle);
8733526Sxy150489 
8743526Sxy150489 	if (mystat != DDI_SUCCESS) {
8753526Sxy150489 		buf->dma_handle = NULL;
8764919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
8773526Sxy150489 		    "Could not allocate dma buffer handle: %d\n", mystat);
8783526Sxy150489 		return (DDI_FAILURE);
8793526Sxy150489 	}
8803526Sxy150489 
8813526Sxy150489 	mystat = ddi_dma_mem_alloc(buf->dma_handle,
8824919Sxy150489 	    size, &e1000g_buf_acc_attr, DDI_DMA_STREAMING,
8833526Sxy150489 	    DDI_DMA_DONTWAIT, 0,
8843526Sxy150489 	    &buf->address,
8853526Sxy150489 	    &len, &buf->acc_handle);
8863526Sxy150489 
8873526Sxy150489 	if (mystat != DDI_SUCCESS) {
8883526Sxy150489 		buf->acc_handle = NULL;
8893526Sxy150489 		buf->address = NULL;
8903526Sxy150489 		if (buf->dma_handle != NULL) {
8913526Sxy150489 			ddi_dma_free_handle(&buf->dma_handle);
8923526Sxy150489 			buf->dma_handle = NULL;
8933526Sxy150489 		}
8944919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
8953526Sxy150489 		    "Could not allocate dma buffer memory: %d\n", mystat);
8963526Sxy150489 		return (DDI_FAILURE);
8973526Sxy150489 	}
8983526Sxy150489 
8993526Sxy150489 	mystat = ddi_dma_addr_bind_handle(buf->dma_handle,
9003526Sxy150489 	    (struct as *)NULL,
9013526Sxy150489 	    buf->address,
9023526Sxy150489 	    len, DDI_DMA_READ | DDI_DMA_STREAMING,
9034919Sxy150489 	    DDI_DMA_DONTWAIT, 0, &cookie, &count);
9043526Sxy150489 
9053526Sxy150489 	if (mystat != DDI_SUCCESS) {
9063526Sxy150489 		if (buf->acc_handle != NULL) {
9073526Sxy150489 			ddi_dma_mem_free(&buf->acc_handle);
9083526Sxy150489 			buf->acc_handle = NULL;
9093526Sxy150489 			buf->address = NULL;
9103526Sxy150489 		}
9113526Sxy150489 		if (buf->dma_handle != NULL) {
9123526Sxy150489 			ddi_dma_free_handle(&buf->dma_handle);
9133526Sxy150489 			buf->dma_handle = NULL;
9143526Sxy150489 		}
9154919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
9163526Sxy150489 		    "Could not bind buffer dma handle: %d\n", mystat);
9173526Sxy150489 		return (DDI_FAILURE);
9183526Sxy150489 	}
9193526Sxy150489 
9203526Sxy150489 	ASSERT(count == 1);
9213526Sxy150489 	if (count != 1) {
9223526Sxy150489 		if (buf->dma_handle != NULL) {
9237426SChenliang.Xu@Sun.COM 			(void) ddi_dma_unbind_handle(buf->dma_handle);
9243526Sxy150489 		}
9253526Sxy150489 		if (buf->acc_handle != NULL) {
9263526Sxy150489 			ddi_dma_mem_free(&buf->acc_handle);
9273526Sxy150489 			buf->acc_handle = NULL;
9283526Sxy150489 			buf->address = NULL;
9293526Sxy150489 		}
9303526Sxy150489 		if (buf->dma_handle != NULL) {
9313526Sxy150489 			ddi_dma_free_handle(&buf->dma_handle);
9323526Sxy150489 			buf->dma_handle = NULL;
9333526Sxy150489 		}
9344919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
9353526Sxy150489 		    "Could not bind buffer as a single frag. "
9363526Sxy150489 		    "Count = %d\n", count);
9373526Sxy150489 		return (DDI_FAILURE);
9383526Sxy150489 	}
9393526Sxy150489 
9403526Sxy150489 	buf->dma_address = cookie.dmac_laddress;
9413526Sxy150489 	buf->size = len;
9423526Sxy150489 	buf->len = 0;
9433526Sxy150489 
9443526Sxy150489 	return (DDI_SUCCESS);
9453526Sxy150489 }
9463526Sxy150489 
9478178SChenlu.Chen@Sun.COM /*
9488178SChenlu.Chen@Sun.COM  * e1000g_alloc_dma_buffer_82546 - allocate a dma buffer along with all
9498178SChenlu.Chen@Sun.COM  * necessary handles.  Same as e1000g_alloc_dma_buffer() except ensure
9508178SChenlu.Chen@Sun.COM  * that buffer that doesn't cross a 64k boundary.
9518178SChenlu.Chen@Sun.COM  */
9528178SChenlu.Chen@Sun.COM static int
9538178SChenlu.Chen@Sun.COM e1000g_alloc_dma_buffer_82546(struct e1000g *Adapter,
9548178SChenlu.Chen@Sun.COM     dma_buffer_t *buf, size_t size, ddi_dma_attr_t *p_dma_attr)
9558178SChenlu.Chen@Sun.COM {
9568178SChenlu.Chen@Sun.COM 	int mystat;
9578178SChenlu.Chen@Sun.COM 	dev_info_t *devinfo;
9588178SChenlu.Chen@Sun.COM 	ddi_dma_cookie_t cookie;
9598178SChenlu.Chen@Sun.COM 	size_t len;
9608178SChenlu.Chen@Sun.COM 	uint_t count;
9618178SChenlu.Chen@Sun.COM 
9628178SChenlu.Chen@Sun.COM 	if (e1000g_force_detach)
9638178SChenlu.Chen@Sun.COM 		devinfo = Adapter->priv_dip;
9648178SChenlu.Chen@Sun.COM 	else
9658178SChenlu.Chen@Sun.COM 		devinfo = Adapter->dip;
9668178SChenlu.Chen@Sun.COM 
9678178SChenlu.Chen@Sun.COM 	mystat = ddi_dma_alloc_handle(devinfo,
9688178SChenlu.Chen@Sun.COM 	    p_dma_attr,
9698178SChenlu.Chen@Sun.COM 	    DDI_DMA_DONTWAIT, 0,
9708178SChenlu.Chen@Sun.COM 	    &buf->dma_handle);
9718178SChenlu.Chen@Sun.COM 
9728178SChenlu.Chen@Sun.COM 	if (mystat != DDI_SUCCESS) {
9738178SChenlu.Chen@Sun.COM 		buf->dma_handle = NULL;
9748178SChenlu.Chen@Sun.COM 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
9758178SChenlu.Chen@Sun.COM 		    "Could not allocate dma buffer handle: %d\n", mystat);
9768178SChenlu.Chen@Sun.COM 		return (DDI_FAILURE);
9778178SChenlu.Chen@Sun.COM 	}
9788178SChenlu.Chen@Sun.COM 
9798178SChenlu.Chen@Sun.COM 	mystat = e1000g_dma_mem_alloc_82546(buf, size, &len);
9808178SChenlu.Chen@Sun.COM 	if (mystat != DDI_SUCCESS) {
9818178SChenlu.Chen@Sun.COM 		buf->acc_handle = NULL;
9828178SChenlu.Chen@Sun.COM 		buf->address = NULL;
9838178SChenlu.Chen@Sun.COM 		if (buf->dma_handle != NULL) {
9848178SChenlu.Chen@Sun.COM 			ddi_dma_free_handle(&buf->dma_handle);
9858178SChenlu.Chen@Sun.COM 			buf->dma_handle = NULL;
9868178SChenlu.Chen@Sun.COM 		}
9878178SChenlu.Chen@Sun.COM 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
9888178SChenlu.Chen@Sun.COM 		    "Could not allocate dma buffer memory: %d\n", mystat);
9898178SChenlu.Chen@Sun.COM 		return (DDI_FAILURE);
9908178SChenlu.Chen@Sun.COM 	}
9918178SChenlu.Chen@Sun.COM 
9928178SChenlu.Chen@Sun.COM 	mystat = ddi_dma_addr_bind_handle(buf->dma_handle,
9938178SChenlu.Chen@Sun.COM 	    (struct as *)NULL,
9948178SChenlu.Chen@Sun.COM 	    buf->address,
9958178SChenlu.Chen@Sun.COM 	    len, DDI_DMA_READ | DDI_DMA_STREAMING,
9968178SChenlu.Chen@Sun.COM 	    DDI_DMA_DONTWAIT, 0, &cookie, &count);
9978178SChenlu.Chen@Sun.COM 
9988178SChenlu.Chen@Sun.COM 	if (mystat != DDI_SUCCESS) {
9998178SChenlu.Chen@Sun.COM 		if (buf->acc_handle != NULL) {
10008178SChenlu.Chen@Sun.COM 			ddi_dma_mem_free(&buf->acc_handle);
10018178SChenlu.Chen@Sun.COM 			buf->acc_handle = NULL;
10028178SChenlu.Chen@Sun.COM 			buf->address = NULL;
10038178SChenlu.Chen@Sun.COM 		}
10048178SChenlu.Chen@Sun.COM 		if (buf->dma_handle != NULL) {
10058178SChenlu.Chen@Sun.COM 			ddi_dma_free_handle(&buf->dma_handle);
10068178SChenlu.Chen@Sun.COM 			buf->dma_handle = NULL;
10078178SChenlu.Chen@Sun.COM 		}
10088178SChenlu.Chen@Sun.COM 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
10098178SChenlu.Chen@Sun.COM 		    "Could not bind buffer dma handle: %d\n", mystat);
10108178SChenlu.Chen@Sun.COM 		return (DDI_FAILURE);
10118178SChenlu.Chen@Sun.COM 	}
10128178SChenlu.Chen@Sun.COM 
10138178SChenlu.Chen@Sun.COM 	ASSERT(count == 1);
10148178SChenlu.Chen@Sun.COM 	if (count != 1) {
10158178SChenlu.Chen@Sun.COM 		if (buf->dma_handle != NULL) {
1016*11143SGuoqing.Zhu@Sun.COM 			(void) ddi_dma_unbind_handle(buf->dma_handle);
10178178SChenlu.Chen@Sun.COM 		}
10188178SChenlu.Chen@Sun.COM 		if (buf->acc_handle != NULL) {
10198178SChenlu.Chen@Sun.COM 			ddi_dma_mem_free(&buf->acc_handle);
10208178SChenlu.Chen@Sun.COM 			buf->acc_handle = NULL;
10218178SChenlu.Chen@Sun.COM 			buf->address = NULL;
10228178SChenlu.Chen@Sun.COM 		}
10238178SChenlu.Chen@Sun.COM 		if (buf->dma_handle != NULL) {
10248178SChenlu.Chen@Sun.COM 			ddi_dma_free_handle(&buf->dma_handle);
10258178SChenlu.Chen@Sun.COM 			buf->dma_handle = NULL;
10268178SChenlu.Chen@Sun.COM 		}
10278178SChenlu.Chen@Sun.COM 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
10288178SChenlu.Chen@Sun.COM 		    "Could not bind buffer as a single frag. "
10298178SChenlu.Chen@Sun.COM 		    "Count = %d\n", count);
10308178SChenlu.Chen@Sun.COM 		return (DDI_FAILURE);
10318178SChenlu.Chen@Sun.COM 	}
10328178SChenlu.Chen@Sun.COM 
10338178SChenlu.Chen@Sun.COM 	buf->dma_address = cookie.dmac_laddress;
10348178SChenlu.Chen@Sun.COM 	buf->size = len;
10358178SChenlu.Chen@Sun.COM 	buf->len = 0;
10368178SChenlu.Chen@Sun.COM 
10378178SChenlu.Chen@Sun.COM 	return (DDI_SUCCESS);
10388178SChenlu.Chen@Sun.COM }
10398178SChenlu.Chen@Sun.COM 
10408178SChenlu.Chen@Sun.COM /*
10418178SChenlu.Chen@Sun.COM  * e1000g_dma_mem_alloc_82546 - allocate a dma buffer, making up to
10428178SChenlu.Chen@Sun.COM  * ALLOC_RETRY attempts to get a buffer that doesn't cross a 64k boundary.
10438178SChenlu.Chen@Sun.COM  */
10448178SChenlu.Chen@Sun.COM static int
10458178SChenlu.Chen@Sun.COM e1000g_dma_mem_alloc_82546(dma_buffer_t *buf, size_t size, size_t *len)
10468178SChenlu.Chen@Sun.COM {
10478178SChenlu.Chen@Sun.COM #define	ALLOC_RETRY	10
10488178SChenlu.Chen@Sun.COM 	int stat;
10498178SChenlu.Chen@Sun.COM 	int cnt = 0;
10508178SChenlu.Chen@Sun.COM 	ddi_acc_handle_t hold[ALLOC_RETRY];
10518178SChenlu.Chen@Sun.COM 
10528178SChenlu.Chen@Sun.COM 	while (cnt < ALLOC_RETRY) {
10538178SChenlu.Chen@Sun.COM 		hold[cnt] = NULL;
10548178SChenlu.Chen@Sun.COM 
10558178SChenlu.Chen@Sun.COM 		/* allocate memory */
10568178SChenlu.Chen@Sun.COM 		stat = ddi_dma_mem_alloc(buf->dma_handle, size,
10578178SChenlu.Chen@Sun.COM 		    &e1000g_buf_acc_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT,
10588178SChenlu.Chen@Sun.COM 		    0, &buf->address, len, &buf->acc_handle);
10598178SChenlu.Chen@Sun.COM 
10608178SChenlu.Chen@Sun.COM 		if (stat != DDI_SUCCESS) {
10618178SChenlu.Chen@Sun.COM 			break;
10628178SChenlu.Chen@Sun.COM 		}
10638178SChenlu.Chen@Sun.COM 
10648178SChenlu.Chen@Sun.COM 		/*
10658178SChenlu.Chen@Sun.COM 		 * Check 64k bounday:
10668178SChenlu.Chen@Sun.COM 		 * if it is bad, hold it and retry
10678178SChenlu.Chen@Sun.COM 		 * if it is good, exit loop
10688178SChenlu.Chen@Sun.COM 		 */
10698178SChenlu.Chen@Sun.COM 		if (e1000g_cross_64k_bound(buf->address, *len)) {
10708178SChenlu.Chen@Sun.COM 			hold[cnt] = buf->acc_handle;
10718178SChenlu.Chen@Sun.COM 			stat = DDI_FAILURE;
10728178SChenlu.Chen@Sun.COM 		} else {
10738178SChenlu.Chen@Sun.COM 			break;
10748178SChenlu.Chen@Sun.COM 		}
10758178SChenlu.Chen@Sun.COM 
10768178SChenlu.Chen@Sun.COM 		cnt++;
10778178SChenlu.Chen@Sun.COM 	}
10788178SChenlu.Chen@Sun.COM 
10798178SChenlu.Chen@Sun.COM 	/* Release any held buffers crossing 64k bounday */
10808178SChenlu.Chen@Sun.COM 	for (--cnt; cnt >= 0; cnt--) {
10818178SChenlu.Chen@Sun.COM 		if (hold[cnt])
10828178SChenlu.Chen@Sun.COM 			ddi_dma_mem_free(&hold[cnt]);
10838178SChenlu.Chen@Sun.COM 	}
10848178SChenlu.Chen@Sun.COM 
10858178SChenlu.Chen@Sun.COM 	return (stat);
10868178SChenlu.Chen@Sun.COM }
10878178SChenlu.Chen@Sun.COM 
10888178SChenlu.Chen@Sun.COM /*
10898178SChenlu.Chen@Sun.COM  * e1000g_cross_64k_bound - If starting and ending address cross a 64k boundary
10908178SChenlu.Chen@Sun.COM  * return true; otherwise return false
10918178SChenlu.Chen@Sun.COM  */
10928178SChenlu.Chen@Sun.COM static boolean_t
10938178SChenlu.Chen@Sun.COM e1000g_cross_64k_bound(void *addr, uintptr_t len)
10948178SChenlu.Chen@Sun.COM {
10958178SChenlu.Chen@Sun.COM 	uintptr_t start = (uintptr_t)addr;
10968178SChenlu.Chen@Sun.COM 	uintptr_t end = start + len - 1;
10978178SChenlu.Chen@Sun.COM 
10988178SChenlu.Chen@Sun.COM 	return (((start ^ end) >> 16) == 0 ? B_FALSE : B_TRUE);
10998178SChenlu.Chen@Sun.COM }
11008178SChenlu.Chen@Sun.COM 
11013526Sxy150489 static void
11023526Sxy150489 e1000g_free_dma_buffer(dma_buffer_t *buf)
11033526Sxy150489 {
11043526Sxy150489 	if (buf->dma_handle != NULL) {
11057426SChenliang.Xu@Sun.COM 		(void) ddi_dma_unbind_handle(buf->dma_handle);
11063526Sxy150489 	} else {
11073526Sxy150489 		return;
11083526Sxy150489 	}
11093526Sxy150489 
11103526Sxy150489 	buf->dma_address = NULL;
11113526Sxy150489 
11123526Sxy150489 	if (buf->acc_handle != NULL) {
11133526Sxy150489 		ddi_dma_mem_free(&buf->acc_handle);
11143526Sxy150489 		buf->acc_handle = NULL;
11153526Sxy150489 		buf->address = NULL;
11163526Sxy150489 	}
11173526Sxy150489 
11183526Sxy150489 	if (buf->dma_handle != NULL) {
11193526Sxy150489 		ddi_dma_free_handle(&buf->dma_handle);
11203526Sxy150489 		buf->dma_handle = NULL;
11213526Sxy150489 	}
11223526Sxy150489 
11233526Sxy150489 	buf->size = 0;
11243526Sxy150489 	buf->len = 0;
11253526Sxy150489 }
11263526Sxy150489 
11273526Sxy150489 static int
11283526Sxy150489 e1000g_alloc_tx_packets(e1000g_tx_ring_t *tx_ring)
11293526Sxy150489 {
11303526Sxy150489 	int j;
11314919Sxy150489 	p_tx_sw_packet_t packet;
11323526Sxy150489 	int mystat;
11333526Sxy150489 	dma_buffer_t *tx_buf;
11344919Sxy150489 	struct e1000g *Adapter;
11354919Sxy150489 	dev_info_t *devinfo;
11364919Sxy150489 	ddi_dma_attr_t dma_attr;
11374919Sxy150489 
11384919Sxy150489 	Adapter = tx_ring->adapter;
11394919Sxy150489 	devinfo = Adapter->dip;
11404919Sxy150489 	dma_attr = e1000g_buf_dma_attr;
11413526Sxy150489 
11423526Sxy150489 	/*
11433526Sxy150489 	 * Memory allocation for the Transmit software structure, the transmit
11443526Sxy150489 	 * software packet. This structure stores all the relevant information
11453526Sxy150489 	 * for transmitting a single packet.
11463526Sxy150489 	 */
11473526Sxy150489 	tx_ring->packet_area =
11483526Sxy150489 	    kmem_zalloc(TX_SW_PKT_AREA_SZ, KM_NOSLEEP);
11493526Sxy150489 
11503526Sxy150489 	if (tx_ring->packet_area == NULL)
11513526Sxy150489 		return (DDI_FAILURE);
11523526Sxy150489 
11533526Sxy150489 	for (j = 0, packet = tx_ring->packet_area;
11544919Sxy150489 	    j < Adapter->tx_freelist_num; j++, packet++) {
11553526Sxy150489 
11563526Sxy150489 		ASSERT(packet != NULL);
11573526Sxy150489 
11583526Sxy150489 		/*
11593526Sxy150489 		 * Pre-allocate dma handles for transmit. These dma handles
11603526Sxy150489 		 * will be dynamically bound to the data buffers passed down
11613526Sxy150489 		 * from the upper layers at the time of transmitting. The
11623526Sxy150489 		 * dynamic binding only applies for the packets that are larger
11633526Sxy150489 		 * than the tx_bcopy_thresh.
11643526Sxy150489 		 */
11653526Sxy150489 		switch (e1000g_dma_type) {
11663526Sxy150489 #ifdef __sparc
11673526Sxy150489 		case USE_DVMA:
11683526Sxy150489 			mystat = dvma_reserve(devinfo,
11693526Sxy150489 			    &e1000g_dma_limits,
11703526Sxy150489 			    Adapter->dvma_page_num,
11713526Sxy150489 			    &packet->tx_dma_handle);
11723526Sxy150489 			break;
11733526Sxy150489 #endif
11743526Sxy150489 		case USE_DMA:
11753526Sxy150489 			mystat = ddi_dma_alloc_handle(devinfo,
11764919Sxy150489 			    &e1000g_tx_dma_attr,
11773526Sxy150489 			    DDI_DMA_DONTWAIT, 0,
11783526Sxy150489 			    &packet->tx_dma_handle);
11793526Sxy150489 			break;
11803526Sxy150489 		default:
11813526Sxy150489 			ASSERT(B_FALSE);
11823526Sxy150489 			break;
11833526Sxy150489 		}
11843526Sxy150489 		if (mystat != DDI_SUCCESS) {
11853526Sxy150489 			packet->tx_dma_handle = NULL;
11864919Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
11873526Sxy150489 			    "Could not allocate tx dma handle: %d\n", mystat);
11883526Sxy150489 			goto tx_pkt_fail;
11893526Sxy150489 		}
11903526Sxy150489 
11913526Sxy150489 		/*
11923526Sxy150489 		 * Pre-allocate transmit buffers for small packets that the
11933526Sxy150489 		 * size is less than tx_bcopy_thresh. The data of those small
11943526Sxy150489 		 * packets will be bcopy() to the transmit buffers instead of
11953526Sxy150489 		 * using dynamical DMA binding. For small packets, bcopy will
11963526Sxy150489 		 * bring better performance than DMA binding.
11973526Sxy150489 		 */
11983526Sxy150489 		tx_buf = packet->tx_buf;
11993526Sxy150489 
12003526Sxy150489 		switch (e1000g_dma_type) {
12013526Sxy150489 #ifdef __sparc
12023526Sxy150489 		case USE_DVMA:
12033526Sxy150489 			mystat = e1000g_alloc_dvma_buffer(Adapter,
12044919Sxy150489 			    tx_buf, Adapter->tx_buffer_size);
12053526Sxy150489 			break;
12063526Sxy150489 #endif
12073526Sxy150489 		case USE_DMA:
12083526Sxy150489 			mystat = e1000g_alloc_dma_buffer(Adapter,
12094919Sxy150489 			    tx_buf, Adapter->tx_buffer_size, &dma_attr);
12103526Sxy150489 			break;
12113526Sxy150489 		default:
12123526Sxy150489 			ASSERT(B_FALSE);
12133526Sxy150489 			break;
12143526Sxy150489 		}
12153526Sxy150489 		if (mystat != DDI_SUCCESS) {
12163526Sxy150489 			ASSERT(packet->tx_dma_handle != NULL);
12173526Sxy150489 			switch (e1000g_dma_type) {
12183526Sxy150489 #ifdef __sparc
12193526Sxy150489 			case USE_DVMA:
12203526Sxy150489 				dvma_release(packet->tx_dma_handle);
12213526Sxy150489 				break;
12223526Sxy150489 #endif
12233526Sxy150489 			case USE_DMA:
12243526Sxy150489 				ddi_dma_free_handle(&packet->tx_dma_handle);
12253526Sxy150489 				break;
12263526Sxy150489 			default:
12273526Sxy150489 				ASSERT(B_FALSE);
12283526Sxy150489 				break;
12293526Sxy150489 			}
12303526Sxy150489 			packet->tx_dma_handle = NULL;
12314919Sxy150489 			E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
12323526Sxy150489 			    "Allocate Tx buffer fail\n");
12333526Sxy150489 			goto tx_pkt_fail;
12343526Sxy150489 		}
12353526Sxy150489 
12363526Sxy150489 		packet->dma_type = e1000g_dma_type;
12373526Sxy150489 	} /* for */
12383526Sxy150489 
12393526Sxy150489 	return (DDI_SUCCESS);
12403526Sxy150489 
12413526Sxy150489 tx_pkt_fail:
12423526Sxy150489 	e1000g_free_tx_packets(tx_ring);
12433526Sxy150489 
12443526Sxy150489 	return (DDI_FAILURE);
12453526Sxy150489 }
12463526Sxy150489 
12473526Sxy150489 static int
12488850SMin.Xu@Sun.COM e1000g_alloc_rx_packets(e1000g_rx_data_t *rx_data)
12493526Sxy150489 {
12503526Sxy150489 	int i;
12514919Sxy150489 	p_rx_sw_packet_t packet;
12523526Sxy150489 	struct e1000g *Adapter;
12533526Sxy150489 	uint32_t packet_num;
12544919Sxy150489 	ddi_dma_attr_t dma_attr;
12553526Sxy150489 
12568850SMin.Xu@Sun.COM 	Adapter = rx_data->rx_ring->adapter;
12574919Sxy150489 	dma_attr = e1000g_buf_dma_attr;
12586735Scc210113 	dma_attr.dma_attr_align = Adapter->rx_buf_align;
12593526Sxy150489 
12603526Sxy150489 	/*
12614919Sxy150489 	 * Allocate memory for the rx_sw_packet structures. Each one of these
12623526Sxy150489 	 * structures will contain a virtual and physical address to an actual
12634919Sxy150489 	 * receive buffer in host memory. Since we use one rx_sw_packet per
12644919Sxy150489 	 * received packet, the maximum number of rx_sw_packet that we'll
12658850SMin.Xu@Sun.COM 	 * need is equal to the number of receive descriptors plus the freelist
12668850SMin.Xu@Sun.COM 	 * size.
12673526Sxy150489 	 */
12684919Sxy150489 	packet_num = Adapter->rx_desc_num + Adapter->rx_freelist_num;
12698850SMin.Xu@Sun.COM 	rx_data->packet_area = NULL;
12703526Sxy150489 
12713526Sxy150489 	for (i = 0; i < packet_num; i++) {
12728850SMin.Xu@Sun.COM 		packet = e1000g_alloc_rx_sw_packet(rx_data, &dma_attr);
12733526Sxy150489 		if (packet == NULL)
12743526Sxy150489 			goto rx_pkt_fail;
12753526Sxy150489 
12768850SMin.Xu@Sun.COM 		packet->next = rx_data->packet_area;
12778850SMin.Xu@Sun.COM 		rx_data->packet_area = packet;
12783526Sxy150489 	}
12793526Sxy150489 
12803526Sxy150489 	return (DDI_SUCCESS);
12813526Sxy150489 
12823526Sxy150489 rx_pkt_fail:
12838850SMin.Xu@Sun.COM 	e1000g_free_rx_packets(rx_data);
12843526Sxy150489 
12853526Sxy150489 	return (DDI_FAILURE);
12863526Sxy150489 }
12873526Sxy150489 
12884919Sxy150489 static p_rx_sw_packet_t
12898850SMin.Xu@Sun.COM e1000g_alloc_rx_sw_packet(e1000g_rx_data_t *rx_data, ddi_dma_attr_t *p_dma_attr)
12903526Sxy150489 {
12913526Sxy150489 	int mystat;
12924919Sxy150489 	p_rx_sw_packet_t packet;
12933526Sxy150489 	dma_buffer_t *rx_buf;
12943526Sxy150489 	struct e1000g *Adapter;
12953526Sxy150489 
12968850SMin.Xu@Sun.COM 	Adapter = rx_data->rx_ring->adapter;
12973526Sxy150489 
12984919Sxy150489 	packet = kmem_zalloc(sizeof (rx_sw_packet_t), KM_NOSLEEP);
12993526Sxy150489 	if (packet == NULL) {
13004919Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
13013526Sxy150489 		    "Cound not allocate memory for Rx SwPacket\n");
13023526Sxy150489 		return (NULL);
13033526Sxy150489 	}
13043526Sxy150489 
13053526Sxy150489 	rx_buf = packet->rx_buf;
13063526Sxy150489 
13073526Sxy150489 	switch (e1000g_dma_type) {
13083526Sxy150489 #ifdef __sparc
13093526Sxy150489 	case USE_DVMA:
13103526Sxy150489 		mystat = e1000g_alloc_dvma_buffer(Adapter,
13114919Sxy150489 		    rx_buf, Adapter->rx_buffer_size);
13123526Sxy150489 		break;
13133526Sxy150489 #endif
13143526Sxy150489 	case USE_DMA:
13158417SChenlu.Chen@Sun.COM 		if (Adapter->mem_workaround_82546 &&
13168417SChenlu.Chen@Sun.COM 		    ((Adapter->shared.mac.type == e1000_82545) ||
13178178SChenlu.Chen@Sun.COM 		    (Adapter->shared.mac.type == e1000_82546) ||
13188417SChenlu.Chen@Sun.COM 		    (Adapter->shared.mac.type == e1000_82546_rev_3))) {
13198178SChenlu.Chen@Sun.COM 			mystat = e1000g_alloc_dma_buffer_82546(Adapter,
13208178SChenlu.Chen@Sun.COM 			    rx_buf, Adapter->rx_buffer_size, p_dma_attr);
13218178SChenlu.Chen@Sun.COM 		} else {
13228178SChenlu.Chen@Sun.COM 			mystat = e1000g_alloc_dma_buffer(Adapter,
13238178SChenlu.Chen@Sun.COM 			    rx_buf, Adapter->rx_buffer_size, p_dma_attr);
13248178SChenlu.Chen@Sun.COM 		}
13253526Sxy150489 		break;
13263526Sxy150489 	default:
13273526Sxy150489 		ASSERT(B_FALSE);
13283526Sxy150489 		break;
13293526Sxy150489 	}
13303526Sxy150489 
13313526Sxy150489 	if (mystat != DDI_SUCCESS) {
13323526Sxy150489 		if (packet != NULL)
13334919Sxy150489 			kmem_free(packet, sizeof (rx_sw_packet_t));
13343526Sxy150489 
13354919Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
13363526Sxy150489 		    "Failed to allocate Rx buffer\n");
13373526Sxy150489 		return (NULL);
13383526Sxy150489 	}
13393526Sxy150489 
13403526Sxy150489 	rx_buf->size -= E1000G_IPALIGNROOM;
13413526Sxy150489 	rx_buf->address += E1000G_IPALIGNROOM;
13423526Sxy150489 	rx_buf->dma_address += E1000G_IPALIGNROOM;
13433526Sxy150489 
13448850SMin.Xu@Sun.COM 	packet->rx_data = (caddr_t)rx_data;
13453526Sxy150489 	packet->free_rtn.free_func = e1000g_rxfree_func;
13463526Sxy150489 	packet->free_rtn.free_arg = (char *)packet;
13473526Sxy150489 	/*
13483526Sxy150489 	 * esballoc is changed to desballoc which
13493526Sxy150489 	 * is undocumented call but as per sun,
13503526Sxy150489 	 * we can use it. It gives better efficiency.
13513526Sxy150489 	 */
13523526Sxy150489 	packet->mp = desballoc((unsigned char *)
13538995SMin.Xu@Sun.COM 	    rx_buf->address,
13548995SMin.Xu@Sun.COM 	    rx_buf->size,
13553526Sxy150489 	    BPRI_MED, &packet->free_rtn);
13563526Sxy150489 
13573526Sxy150489 	packet->dma_type = e1000g_dma_type;
13588850SMin.Xu@Sun.COM 	packet->ref_cnt = 1;
13593526Sxy150489 
13603526Sxy150489 	return (packet);
13613526Sxy150489 }
13623526Sxy150489 
13633526Sxy150489 void
13648850SMin.Xu@Sun.COM e1000g_free_rx_sw_packet(p_rx_sw_packet_t packet, boolean_t full_release)
13653526Sxy150489 {
13663526Sxy150489 	dma_buffer_t *rx_buf;
13673526Sxy150489 
13683526Sxy150489 	if (packet->mp != NULL) {
13693526Sxy150489 		freemsg(packet->mp);
13703526Sxy150489 		packet->mp = NULL;
13713526Sxy150489 	}
13723526Sxy150489 
13733526Sxy150489 	rx_buf = packet->rx_buf;
13743526Sxy150489 
13753526Sxy150489 	switch (packet->dma_type) {
13763526Sxy150489 #ifdef __sparc
13773526Sxy150489 	case USE_DVMA:
13788850SMin.Xu@Sun.COM 		if (rx_buf->address != NULL) {
13798850SMin.Xu@Sun.COM 			rx_buf->size += E1000G_IPALIGNROOM;
13808850SMin.Xu@Sun.COM 			rx_buf->address -= E1000G_IPALIGNROOM;
13818850SMin.Xu@Sun.COM 		}
13823526Sxy150489 		e1000g_free_dvma_buffer(rx_buf);
13833526Sxy150489 		break;
13843526Sxy150489 #endif
13853526Sxy150489 	case USE_DMA:
13863526Sxy150489 		e1000g_free_dma_buffer(rx_buf);
13873526Sxy150489 		break;
13883526Sxy150489 	default:
13893526Sxy150489 		break;
13903526Sxy150489 	}
13913526Sxy150489 
13923526Sxy150489 	packet->dma_type = USE_NONE;
13933526Sxy150489 
13948850SMin.Xu@Sun.COM 	if (!full_release)
13958850SMin.Xu@Sun.COM 		return;
13968850SMin.Xu@Sun.COM 
13974919Sxy150489 	kmem_free(packet, sizeof (rx_sw_packet_t));
13983526Sxy150489 }
13993526Sxy150489 
14003526Sxy150489 static void
14018850SMin.Xu@Sun.COM e1000g_free_rx_packets(e1000g_rx_data_t *rx_data)
14023526Sxy150489 {
14038850SMin.Xu@Sun.COM 	p_rx_sw_packet_t packet, next_packet;
14048850SMin.Xu@Sun.COM 	uint32_t ref_cnt;
14053526Sxy150489 
14068850SMin.Xu@Sun.COM 	mutex_enter(&e1000g_rx_detach_lock);
14074349Sxy150489 
14088850SMin.Xu@Sun.COM 	packet = rx_data->packet_area;
14098850SMin.Xu@Sun.COM 	while (packet != NULL) {
14104349Sxy150489 		next_packet = packet->next;
14114349Sxy150489 
14128850SMin.Xu@Sun.COM 		ref_cnt = atomic_dec_32_nv(&packet->ref_cnt);
14138850SMin.Xu@Sun.COM 		if (ref_cnt > 0) {
14148850SMin.Xu@Sun.COM 			atomic_inc_32(&rx_data->pending_count);
14158850SMin.Xu@Sun.COM 			atomic_inc_32(&e1000g_mblks_pending);
14164349Sxy150489 		} else {
14178850SMin.Xu@Sun.COM 			e1000g_free_rx_sw_packet(packet, B_FALSE);
14183526Sxy150489 		}
14198850SMin.Xu@Sun.COM 
14208850SMin.Xu@Sun.COM 		packet = next_packet;
14213526Sxy150489 	}
14223526Sxy150489 
14238850SMin.Xu@Sun.COM 	mutex_exit(&e1000g_rx_detach_lock);
14248850SMin.Xu@Sun.COM }
14253526Sxy150489 
14263526Sxy150489 
14273526Sxy150489 static void
14283526Sxy150489 e1000g_free_tx_packets(e1000g_tx_ring_t *tx_ring)
14293526Sxy150489 {
14303526Sxy150489 	int j;
14313526Sxy150489 	struct e1000g *Adapter;
14324919Sxy150489 	p_tx_sw_packet_t packet;
14333526Sxy150489 	dma_buffer_t *tx_buf;
14343526Sxy150489 
14353526Sxy150489 	Adapter = tx_ring->adapter;
14363526Sxy150489 
14373526Sxy150489 	for (j = 0, packet = tx_ring->packet_area;
14384919Sxy150489 	    j < Adapter->tx_freelist_num; j++, packet++) {
14393526Sxy150489 
14403526Sxy150489 		if (packet == NULL)
14413526Sxy150489 			break;
14423526Sxy150489 
14433526Sxy150489 		/* Free the Tx DMA handle for dynamical binding */
14443526Sxy150489 		if (packet->tx_dma_handle != NULL) {
14453526Sxy150489 			switch (packet->dma_type) {
14463526Sxy150489 #ifdef __sparc
14473526Sxy150489 			case USE_DVMA:
14483526Sxy150489 				dvma_release(packet->tx_dma_handle);
14493526Sxy150489 				break;
14503526Sxy150489 #endif
14513526Sxy150489 			case USE_DMA:
14523526Sxy150489 				ddi_dma_free_handle(&packet->tx_dma_handle);
14533526Sxy150489 				break;
14543526Sxy150489 			default:
14553526Sxy150489 				ASSERT(B_FALSE);
14563526Sxy150489 				break;
14573526Sxy150489 			}
14583526Sxy150489 			packet->tx_dma_handle = NULL;
14593526Sxy150489 		} else {
14603526Sxy150489 			/*
14613526Sxy150489 			 * If the dma handle is NULL, then we don't
14623526Sxy150489 			 * need to check the packets left. For they
14633526Sxy150489 			 * have not been initialized or have been freed.
14643526Sxy150489 			 */
14653526Sxy150489 			break;
14663526Sxy150489 		}
14673526Sxy150489 
14683526Sxy150489 		tx_buf = packet->tx_buf;
14693526Sxy150489 
14703526Sxy150489 		switch (packet->dma_type) {
14713526Sxy150489 #ifdef __sparc
14723526Sxy150489 		case USE_DVMA:
14733526Sxy150489 			e1000g_free_dvma_buffer(tx_buf);
14743526Sxy150489 			break;
14753526Sxy150489 #endif
14763526Sxy150489 		case USE_DMA:
14773526Sxy150489 			e1000g_free_dma_buffer(tx_buf);
14783526Sxy150489 			break;
14793526Sxy150489 		default:
14803526Sxy150489 			ASSERT(B_FALSE);
14813526Sxy150489 			break;
14823526Sxy150489 		}
14833526Sxy150489 
14843526Sxy150489 		packet->dma_type = USE_NONE;
14853526Sxy150489 	}
14863526Sxy150489 	if (tx_ring->packet_area != NULL) {
14873526Sxy150489 		kmem_free(tx_ring->packet_area, TX_SW_PKT_AREA_SZ);
14883526Sxy150489 		tx_ring->packet_area = NULL;
14893526Sxy150489 	}
14903526Sxy150489 }
14913526Sxy150489 
14923526Sxy150489 /*
14934919Sxy150489  * e1000g_release_dma_resources - release allocated DMA resources
14944919Sxy150489  *
14954919Sxy150489  * This function releases any pending buffers that has been
14964919Sxy150489  * previously allocated
14973526Sxy150489  */
14983526Sxy150489 void
14994919Sxy150489 e1000g_release_dma_resources(struct e1000g *Adapter)
15003526Sxy150489 {
15014919Sxy150489 	e1000g_free_descriptors(Adapter);
15024919Sxy150489 	e1000g_free_packets(Adapter);
15033526Sxy150489 }
15045273Sgl147354 
15057426SChenliang.Xu@Sun.COM /* ARGSUSED */
15065273Sgl147354 void
15075273Sgl147354 e1000g_set_fma_flags(struct e1000g *Adapter, int acc_flag, int dma_flag)
15085273Sgl147354 {
15095273Sgl147354 	if (acc_flag) {
15105273Sgl147354 		e1000g_desc_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC;
15115273Sgl147354 	} else {
15125273Sgl147354 		e1000g_desc_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC;
15135273Sgl147354 	}
15145273Sgl147354 
15155273Sgl147354 	if (dma_flag) {
15165273Sgl147354 		e1000g_tx_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
15175273Sgl147354 		e1000g_buf_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
15185273Sgl147354 		e1000g_desc_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
15195273Sgl147354 	} else {
15205273Sgl147354 		e1000g_tx_dma_attr.dma_attr_flags = 0;
15215273Sgl147354 		e1000g_buf_dma_attr.dma_attr_flags = 0;
15225273Sgl147354 		e1000g_desc_dma_attr.dma_attr_flags = 0;
15235273Sgl147354 	}
15245273Sgl147354 }
1525