xref: /onnv-gate/usr/src/uts/common/io/xge/drv/xgell.c (revision 11878:ac93462db6d7)
11256Syl150051 /*
21256Syl150051  * CDDL HEADER START
31256Syl150051  *
41256Syl150051  * The contents of this file are subject to the terms of the
51256Syl150051  * Common Development and Distribution License (the "License").
61256Syl150051  * You may not use this file except in compliance with the License.
71256Syl150051  *
81256Syl150051  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91256Syl150051  * or http://www.opensolaris.org/os/licensing.
101256Syl150051  * See the License for the specific language governing permissions
111256Syl150051  * and limitations under the License.
121256Syl150051  *
131256Syl150051  * When distributing Covered Code, include this CDDL HEADER in each
141256Syl150051  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151256Syl150051  * If applicable, add the following below this CDDL HEADER, with the
161256Syl150051  * fields enclosed by brackets "[]" replaced with your own identifying
171256Syl150051  * information: Portions Copyright [yyyy] [name of copyright owner]
181256Syl150051  *
191256Syl150051  * CDDL HEADER END
201256Syl150051  */
211256Syl150051 
221256Syl150051 /*
23*11878SVenu.Iyer@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
241256Syl150051  * Use is subject to license terms.
251256Syl150051  */
261256Syl150051 
271256Syl150051 /*
2811145SRoamer@Sun.COM  *  Copyright (c) 2002-2009 Neterion, Inc.
291256Syl150051  *  All right Reserved.
301256Syl150051  *
311256Syl150051  *  FileName :    xgell.c
321256Syl150051  *
331256Syl150051  *  Description:  Xge Link Layer data path implementation
341256Syl150051  *
351256Syl150051  */
361256Syl150051 
371256Syl150051 #include "xgell.h"
381256Syl150051 
391256Syl150051 #include <netinet/ip.h>
401256Syl150051 #include <netinet/tcp.h>
413115Syl150051 #include <netinet/udp.h>
421256Syl150051 
432311Sseb #define	XGELL_MAX_FRAME_SIZE(hldev)	((hldev)->config.mtu +	\
441256Syl150051     sizeof (struct ether_vlan_header))
451256Syl150051 
461256Syl150051 #define	HEADROOM		2	/* for DIX-only packets */
471256Syl150051 
header_free_func(void * arg)481256Syl150051 void header_free_func(void *arg) { }
491256Syl150051 frtn_t header_frtn = {header_free_func, NULL};
501256Syl150051 
511256Syl150051 /* DMA attributes used for Tx side */
521256Syl150051 static struct ddi_dma_attr tx_dma_attr = {
531256Syl150051 	DMA_ATTR_V0,			/* dma_attr_version */
541256Syl150051 	0x0ULL,				/* dma_attr_addr_lo */
551256Syl150051 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_addr_hi */
566937Sxw161283 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_count_max */
576937Sxw161283 #if defined(__sparc)
586937Sxw161283 	0x2000,				/* dma_attr_align */
596937Sxw161283 #else
606937Sxw161283 	0x1000,				/* dma_attr_align */
616937Sxw161283 #endif
626937Sxw161283 	0xFC00FC,			/* dma_attr_burstsizes */
636937Sxw161283 	0x1,				/* dma_attr_minxfer */
646937Sxw161283 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_maxxfer */
651256Syl150051 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_seg */
663115Syl150051 	18,				/* dma_attr_sgllen */
676937Sxw161283 	(unsigned int)1,		/* dma_attr_granular */
681256Syl150051 	0				/* dma_attr_flags */
691256Syl150051 };
701256Syl150051 
711256Syl150051 /*
721256Syl150051  * DMA attributes used when using ddi_dma_mem_alloc to
731256Syl150051  * allocat HAL descriptors and Rx buffers during replenish
741256Syl150051  */
751256Syl150051 static struct ddi_dma_attr hal_dma_attr = {
761256Syl150051 	DMA_ATTR_V0,			/* dma_attr_version */
771256Syl150051 	0x0ULL,				/* dma_attr_addr_lo */
781256Syl150051 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_addr_hi */
796937Sxw161283 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_count_max */
806937Sxw161283 #if defined(__sparc)
816937Sxw161283 	0x2000,				/* dma_attr_align */
826937Sxw161283 #else
836937Sxw161283 	0x1000,				/* dma_attr_align */
846937Sxw161283 #endif
856937Sxw161283 	0xFC00FC,			/* dma_attr_burstsizes */
866937Sxw161283 	0x1,				/* dma_attr_minxfer */
876937Sxw161283 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_maxxfer */
881256Syl150051 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_seg */
891256Syl150051 	1,				/* dma_attr_sgllen */
906937Sxw161283 	(unsigned int)1,		/* dma_attr_sgllen */
916937Sxw161283 	DDI_DMA_RELAXED_ORDERING	/* dma_attr_flags */
921256Syl150051 };
931256Syl150051 
941256Syl150051 struct ddi_dma_attr *p_hal_dma_attr = &hal_dma_attr;
951256Syl150051 
962311Sseb static int		xgell_m_stat(void *, uint_t, uint64_t *);
972311Sseb static int		xgell_m_start(void *);
982311Sseb static void		xgell_m_stop(void *);
992311Sseb static int		xgell_m_promisc(void *, boolean_t);
1002311Sseb static int		xgell_m_multicst(void *, boolean_t, const uint8_t *);
1012311Sseb static void		xgell_m_ioctl(void *, queue_t *, mblk_t *);
1022311Sseb static boolean_t	xgell_m_getcapab(void *, mac_capab_t, void *);
1032311Sseb 
1042311Sseb #define	XGELL_M_CALLBACK_FLAGS	(MC_IOCTL | MC_GETCAPAB)
1052311Sseb 
1062311Sseb static mac_callbacks_t xgell_m_callbacks = {
1072311Sseb 	XGELL_M_CALLBACK_FLAGS,
1082311Sseb 	xgell_m_stat,
1092311Sseb 	xgell_m_start,
1102311Sseb 	xgell_m_stop,
1112311Sseb 	xgell_m_promisc,
1122311Sseb 	xgell_m_multicst,
1138275SEric Cheng 	NULL,
1142311Sseb 	NULL,
115*11878SVenu.Iyer@Sun.COM 	NULL,
1162311Sseb 	xgell_m_ioctl,
1172311Sseb 	xgell_m_getcapab
1182311Sseb };
1192311Sseb 
1201256Syl150051 /*
1211256Syl150051  * xge_device_poll
1221256Syl150051  *
1238275SEric Cheng  * Timeout should call me every 1s. xge_callback_event_queued should call me
1241256Syl150051  * when HAL hope event was rescheduled.
1251256Syl150051  */
1261256Syl150051 /*ARGSUSED*/
1271256Syl150051 void
xge_device_poll(void * data)1281256Syl150051 xge_device_poll(void *data)
1291256Syl150051 {
1301256Syl150051 	xgelldev_t *lldev = xge_hal_device_private(data);
1311256Syl150051 
1321256Syl150051 	mutex_enter(&lldev->genlock);
1331256Syl150051 	if (lldev->is_initialized) {
1341256Syl150051 		xge_hal_device_poll(data);
1351256Syl150051 		lldev->timeout_id = timeout(xge_device_poll, data,
1361256Syl150051 		    XGE_DEV_POLL_TICKS);
1373115Syl150051 	} else if (lldev->in_reset == 1) {
1383115Syl150051 		lldev->timeout_id = timeout(xge_device_poll, data,
1393115Syl150051 		    XGE_DEV_POLL_TICKS);
1403115Syl150051 	} else {
1413115Syl150051 		lldev->timeout_id = 0;
1421256Syl150051 	}
1431256Syl150051 	mutex_exit(&lldev->genlock);
1441256Syl150051 }
1451256Syl150051 
1461256Syl150051 /*
1471256Syl150051  * xge_device_poll_now
1481256Syl150051  *
1491256Syl150051  * Will call xge_device_poll() immediately
1501256Syl150051  */
1511256Syl150051 void
xge_device_poll_now(void * data)1521256Syl150051 xge_device_poll_now(void *data)
1531256Syl150051 {
1541256Syl150051 	xgelldev_t *lldev = xge_hal_device_private(data);
1551256Syl150051 
1561256Syl150051 	mutex_enter(&lldev->genlock);
1573115Syl150051 	if (lldev->is_initialized) {
1583115Syl150051 		xge_hal_device_poll(data);
1593115Syl150051 	}
1601256Syl150051 	mutex_exit(&lldev->genlock);
1611256Syl150051 }
1621256Syl150051 
1631256Syl150051 /*
1641256Syl150051  * xgell_callback_link_up
1651256Syl150051  *
1661256Syl150051  * This function called by HAL to notify HW link up state change.
1671256Syl150051  */
1681256Syl150051 void
xgell_callback_link_up(void * userdata)1691256Syl150051 xgell_callback_link_up(void *userdata)
1701256Syl150051 {
1711256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)userdata;
1721256Syl150051 
1732311Sseb 	mac_link_update(lldev->mh, LINK_STATE_UP);
1741256Syl150051 }
1751256Syl150051 
1761256Syl150051 /*
1771256Syl150051  * xgell_callback_link_down
1781256Syl150051  *
1791256Syl150051  * This function called by HAL to notify HW link down state change.
1801256Syl150051  */
1811256Syl150051 void
xgell_callback_link_down(void * userdata)1821256Syl150051 xgell_callback_link_down(void *userdata)
1831256Syl150051 {
1841256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)userdata;
1851256Syl150051 
1862311Sseb 	mac_link_update(lldev->mh, LINK_STATE_DOWN);
1871256Syl150051 }
1881256Syl150051 
1891256Syl150051 /*
1901256Syl150051  * xgell_rx_buffer_replenish_all
1911256Syl150051  *
1921256Syl150051  * To replenish all freed dtr(s) with buffers in free pool. It's called by
1938275SEric Cheng  * xgell_rx_buffer_recycle() or xgell_rx_1b_callback().
1941256Syl150051  * Must be called with pool_lock held.
1951256Syl150051  */
1961256Syl150051 static void
xgell_rx_buffer_replenish_all(xgell_rx_ring_t * ring)1978275SEric Cheng xgell_rx_buffer_replenish_all(xgell_rx_ring_t *ring)
1981256Syl150051 {
1998275SEric Cheng 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
2001256Syl150051 	xge_hal_dtr_h dtr;
2011256Syl150051 	xgell_rx_buffer_t *rx_buffer;
2021256Syl150051 	xgell_rxd_priv_t *rxd_priv;
2031256Syl150051 
2048275SEric Cheng 	xge_assert(mutex_owned(&bf_pool->pool_lock));
2058275SEric Cheng 
2068275SEric Cheng 	while ((bf_pool->free > 0) &&
2078275SEric Cheng 	    (xge_hal_ring_dtr_reserve(ring->channelh, &dtr) == XGE_HAL_OK)) {
2088275SEric Cheng 		xge_assert(bf_pool->head);
2098275SEric Cheng 
2108275SEric Cheng 		rx_buffer = bf_pool->head;
2118275SEric Cheng 
2128275SEric Cheng 		bf_pool->head = rx_buffer->next;
2138275SEric Cheng 		bf_pool->free--;
2148275SEric Cheng 
2151256Syl150051 		xge_assert(rx_buffer->dma_addr);
2161256Syl150051 
2171256Syl150051 		rxd_priv = (xgell_rxd_priv_t *)
2186937Sxw161283 		    xge_hal_ring_dtr_private(ring->channelh, dtr);
2191256Syl150051 		xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr,
2208275SEric Cheng 		    bf_pool->size);
2211256Syl150051 
2221256Syl150051 		rxd_priv->rx_buffer = rx_buffer;
2236937Sxw161283 		xge_hal_ring_dtr_post(ring->channelh, dtr);
2241256Syl150051 	}
2251256Syl150051 }
2261256Syl150051 
2271256Syl150051 /*
2281256Syl150051  * xgell_rx_buffer_release
2291256Syl150051  *
2301256Syl150051  * The only thing done here is to put the buffer back to the pool.
2313115Syl150051  * Calling this function need be protected by mutex, bf_pool.pool_lock.
2321256Syl150051  */
2331256Syl150051 static void
xgell_rx_buffer_release(xgell_rx_buffer_t * rx_buffer)2341256Syl150051 xgell_rx_buffer_release(xgell_rx_buffer_t *rx_buffer)
2351256Syl150051 {
2368275SEric Cheng 	xgell_rx_ring_t *ring = rx_buffer->ring;
2378275SEric Cheng 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
2388275SEric Cheng 
2398275SEric Cheng 	xge_assert(mutex_owned(&bf_pool->pool_lock));
2401256Syl150051 
2411256Syl150051 	/* Put the buffer back to pool */
2428275SEric Cheng 	rx_buffer->next = bf_pool->head;
2438275SEric Cheng 	bf_pool->head = rx_buffer;
2448275SEric Cheng 
2458275SEric Cheng 	bf_pool->free++;
2461256Syl150051 }
2471256Syl150051 
2481256Syl150051 /*
2491256Syl150051  * xgell_rx_buffer_recycle
2501256Syl150051  *
2511256Syl150051  * Called by desballoc() to "free" the resource.
2521256Syl150051  * We will try to replenish all descripters.
2531256Syl150051  */
2546937Sxw161283 
2556937Sxw161283 /*
2566937Sxw161283  * Previously there were much lock contention between xgell_rx_1b_compl() and
2576937Sxw161283  * xgell_rx_buffer_recycle(), which consumed a lot of CPU resources and had bad
2586937Sxw161283  * effect on rx performance. A separate recycle list is introduced to overcome
2596937Sxw161283  * this. The recycle list is used to record the rx buffer that has been recycled
2606937Sxw161283  * and these buffers will be retuned back to the free list in bulk instead of
2616937Sxw161283  * one-by-one.
2626937Sxw161283  */
2636937Sxw161283 
2641256Syl150051 static void
xgell_rx_buffer_recycle(char * arg)2651256Syl150051 xgell_rx_buffer_recycle(char *arg)
2661256Syl150051 {
2671256Syl150051 	xgell_rx_buffer_t *rx_buffer = (xgell_rx_buffer_t *)arg;
2688275SEric Cheng 	xgell_rx_ring_t *ring = rx_buffer->ring;
2696937Sxw161283 	xgelldev_t *lldev = ring->lldev;
2706937Sxw161283 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
2716937Sxw161283 
2726937Sxw161283 	mutex_enter(&bf_pool->recycle_lock);
2731256Syl150051 
2746937Sxw161283 	rx_buffer->next = bf_pool->recycle_head;
2756937Sxw161283 	bf_pool->recycle_head = rx_buffer;
2766937Sxw161283 	if (bf_pool->recycle_tail == NULL)
2776937Sxw161283 		bf_pool->recycle_tail = rx_buffer;
2786937Sxw161283 	bf_pool->recycle++;
2791256Syl150051 
2801256Syl150051 	/*
2811256Syl150051 	 * Before finding a good way to set this hiwat, just always call to
2821256Syl150051 	 * replenish_all. *TODO*
2831256Syl150051 	 */
2848275SEric Cheng 	if ((lldev->is_initialized != 0) && (ring->live) &&
2856937Sxw161283 	    (bf_pool->recycle >= XGELL_RX_BUFFER_RECYCLE_CACHE)) {
2868275SEric Cheng 		mutex_enter(&bf_pool->pool_lock);
2878275SEric Cheng 		bf_pool->recycle_tail->next = bf_pool->head;
2888275SEric Cheng 		bf_pool->head = bf_pool->recycle_head;
2898275SEric Cheng 		bf_pool->recycle_head = bf_pool->recycle_tail = NULL;
2908275SEric Cheng 		bf_pool->post -= bf_pool->recycle;
2918275SEric Cheng 		bf_pool->free += bf_pool->recycle;
2928275SEric Cheng 		bf_pool->recycle = 0;
2938275SEric Cheng 		xgell_rx_buffer_replenish_all(ring);
2948275SEric Cheng 		mutex_exit(&bf_pool->pool_lock);
2951256Syl150051 	}
2961256Syl150051 
2976937Sxw161283 	mutex_exit(&bf_pool->recycle_lock);
2981256Syl150051 }
2991256Syl150051 
3001256Syl150051 /*
3011256Syl150051  * xgell_rx_buffer_alloc
3021256Syl150051  *
3031256Syl150051  * Allocate one rx buffer and return with the pointer to the buffer.
3041256Syl150051  * Return NULL if failed.
3051256Syl150051  */
3061256Syl150051 static xgell_rx_buffer_t *
xgell_rx_buffer_alloc(xgell_rx_ring_t * ring)3078275SEric Cheng xgell_rx_buffer_alloc(xgell_rx_ring_t *ring)
3081256Syl150051 {
3098275SEric Cheng 	xgelldev_t *lldev = ring->lldev;
3108275SEric Cheng 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
3111256Syl150051 	xge_hal_device_t *hldev;
3121256Syl150051 	void *vaddr;
3131256Syl150051 	ddi_dma_handle_t dma_handle;
3141256Syl150051 	ddi_acc_handle_t dma_acch;
3151256Syl150051 	dma_addr_t dma_addr;
3161256Syl150051 	uint_t ncookies;
3171256Syl150051 	ddi_dma_cookie_t dma_cookie;
3181256Syl150051 	size_t real_size;
3191256Syl150051 	extern ddi_device_acc_attr_t *p_xge_dev_attr;
3201256Syl150051 	xgell_rx_buffer_t *rx_buffer;
3211256Syl150051 
3223115Syl150051 	hldev = (xge_hal_device_t *)lldev->devh;
3231256Syl150051 
3241256Syl150051 	if (ddi_dma_alloc_handle(hldev->pdev, p_hal_dma_attr, DDI_DMA_SLEEP,
3251256Syl150051 	    0, &dma_handle) != DDI_SUCCESS) {
3261256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA handle",
3271256Syl150051 		    XGELL_IFNAME, lldev->instance);
3281256Syl150051 		goto handle_failed;
3291256Syl150051 	}
3301256Syl150051 
3311256Syl150051 	/* reserve some space at the end of the buffer for recycling */
3328275SEric Cheng 	if (ddi_dma_mem_alloc(dma_handle, HEADROOM + bf_pool->size +
3331256Syl150051 	    sizeof (xgell_rx_buffer_t), p_xge_dev_attr, DDI_DMA_STREAMING,
3341256Syl150051 	    DDI_DMA_SLEEP, 0, (caddr_t *)&vaddr, &real_size, &dma_acch) !=
3351256Syl150051 	    DDI_SUCCESS) {
3361256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory",
3371256Syl150051 		    XGELL_IFNAME, lldev->instance);
3381256Syl150051 		goto mem_failed;
3391256Syl150051 	}
3401256Syl150051 
3418275SEric Cheng 	if (HEADROOM + bf_pool->size + sizeof (xgell_rx_buffer_t) >
3421256Syl150051 	    real_size) {
3431256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory",
3441256Syl150051 		    XGELL_IFNAME, lldev->instance);
3451256Syl150051 		goto bind_failed;
3461256Syl150051 	}
3471256Syl150051 
3481256Syl150051 	if (ddi_dma_addr_bind_handle(dma_handle, NULL, (char *)vaddr + HEADROOM,
3498275SEric Cheng 	    bf_pool->size, DDI_DMA_READ | DDI_DMA_STREAMING,
3501256Syl150051 	    DDI_DMA_SLEEP, 0, &dma_cookie, &ncookies) != DDI_SUCCESS) {
3511256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: out of mapping for mblk",
3521256Syl150051 		    XGELL_IFNAME, lldev->instance);
3531256Syl150051 		goto bind_failed;
3541256Syl150051 	}
3551256Syl150051 
3568275SEric Cheng 	if (ncookies != 1 || dma_cookie.dmac_size < bf_pool->size) {
3571256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not handle partial DMA",
3581256Syl150051 		    XGELL_IFNAME, lldev->instance);
3591256Syl150051 		goto check_failed;
3601256Syl150051 	}
3611256Syl150051 
3621256Syl150051 	dma_addr = dma_cookie.dmac_laddress;
3631256Syl150051 
3641256Syl150051 	rx_buffer = (xgell_rx_buffer_t *)((char *)vaddr + real_size -
3651256Syl150051 	    sizeof (xgell_rx_buffer_t));
3661256Syl150051 	rx_buffer->next = NULL;
3671256Syl150051 	rx_buffer->vaddr = vaddr;
3681256Syl150051 	rx_buffer->dma_addr = dma_addr;
3691256Syl150051 	rx_buffer->dma_handle = dma_handle;
3701256Syl150051 	rx_buffer->dma_acch = dma_acch;
3716937Sxw161283 	rx_buffer->ring = ring;
3721256Syl150051 	rx_buffer->frtn.free_func = xgell_rx_buffer_recycle;
3731256Syl150051 	rx_buffer->frtn.free_arg = (void *)rx_buffer;
3741256Syl150051 
3751256Syl150051 	return (rx_buffer);
3761256Syl150051 
3771256Syl150051 check_failed:
3781256Syl150051 	(void) ddi_dma_unbind_handle(dma_handle);
3791256Syl150051 bind_failed:
3801256Syl150051 	XGE_OS_MEMORY_CHECK_FREE(vaddr, 0);
3811256Syl150051 	ddi_dma_mem_free(&dma_acch);
3821256Syl150051 mem_failed:
3831256Syl150051 	ddi_dma_free_handle(&dma_handle);
3841256Syl150051 handle_failed:
3851256Syl150051 
3861256Syl150051 	return (NULL);
3871256Syl150051 }
3881256Syl150051 
3891256Syl150051 /*
3901256Syl150051  * xgell_rx_destroy_buffer_pool
3911256Syl150051  *
3921256Syl150051  * Destroy buffer pool. If there is still any buffer hold by upper layer,
3931256Syl150051  * recorded by bf_pool.post, return DDI_FAILURE to reject to be unloaded.
3941256Syl150051  */
3958275SEric Cheng static boolean_t
xgell_rx_destroy_buffer_pool(xgell_rx_ring_t * ring)3968275SEric Cheng xgell_rx_destroy_buffer_pool(xgell_rx_ring_t *ring)
3971256Syl150051 {
3988275SEric Cheng 	xgelldev_t *lldev = ring->lldev;
3998275SEric Cheng 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
4001256Syl150051 	xgell_rx_buffer_t *rx_buffer;
4011256Syl150051 	ddi_dma_handle_t  dma_handle;
4021256Syl150051 	ddi_acc_handle_t  dma_acch;
4031256Syl150051 	int i;
4041256Syl150051 
4058275SEric Cheng 	/*
4068275SEric Cheng 	 * If the pool has been destroied, just return B_TRUE
4078275SEric Cheng 	 */
4088275SEric Cheng 	if (!bf_pool->live)
4098275SEric Cheng 		return (B_TRUE);
4108275SEric Cheng 
4118275SEric Cheng 	mutex_enter(&bf_pool->recycle_lock);
4128275SEric Cheng 	if (bf_pool->recycle > 0) {
4138275SEric Cheng 		mutex_enter(&bf_pool->pool_lock);
4148275SEric Cheng 		bf_pool->recycle_tail->next = bf_pool->head;
4158275SEric Cheng 		bf_pool->head = bf_pool->recycle_head;
4168275SEric Cheng 		bf_pool->recycle_tail = bf_pool->recycle_head = NULL;
4178275SEric Cheng 		bf_pool->post -= bf_pool->recycle;
4188275SEric Cheng 		bf_pool->free += bf_pool->recycle;
4198275SEric Cheng 		bf_pool->recycle = 0;
4208275SEric Cheng 		mutex_exit(&bf_pool->pool_lock);
4216937Sxw161283 	}
4228275SEric Cheng 	mutex_exit(&bf_pool->recycle_lock);
4236937Sxw161283 
4241256Syl150051 	/*
4251256Syl150051 	 * If there is any posted buffer, the driver should reject to be
4261256Syl150051 	 * detached. Need notice upper layer to release them.
4271256Syl150051 	 */
4288275SEric Cheng 	if (bf_pool->post != 0) {
4291256Syl150051 		xge_debug_ll(XGE_ERR,
4301256Syl150051 		    "%s%d has some buffers not be recycled, try later!",
4311256Syl150051 		    XGELL_IFNAME, lldev->instance);
4328275SEric Cheng 		return (B_FALSE);
4331256Syl150051 	}
4341256Syl150051 
4351256Syl150051 	/*
4368275SEric Cheng 	 * Release buffers one by one.
4371256Syl150051 	 */
4388275SEric Cheng 	for (i = bf_pool->total; i > 0; i--) {
4398275SEric Cheng 		rx_buffer = bf_pool->head;
4401256Syl150051 		xge_assert(rx_buffer != NULL);
4411256Syl150051 
4428275SEric Cheng 		bf_pool->head = rx_buffer->next;
4431256Syl150051 
4441256Syl150051 		dma_handle = rx_buffer->dma_handle;
4451256Syl150051 		dma_acch = rx_buffer->dma_acch;
4461256Syl150051 
4471256Syl150051 		if (ddi_dma_unbind_handle(dma_handle) != DDI_SUCCESS) {
4488275SEric Cheng 			xge_debug_ll(XGE_ERR, "failed to unbind DMA handle!");
4498275SEric Cheng 			bf_pool->head = rx_buffer;
4508275SEric Cheng 			return (B_FALSE);
4511256Syl150051 		}
4521256Syl150051 		ddi_dma_mem_free(&dma_acch);
4531256Syl150051 		ddi_dma_free_handle(&dma_handle);
4541256Syl150051 
4558275SEric Cheng 		bf_pool->total--;
4568275SEric Cheng 		bf_pool->free--;
4571256Syl150051 	}
4581256Syl150051 
4598275SEric Cheng 	xge_assert(!mutex_owned(&bf_pool->pool_lock));
4608275SEric Cheng 
4618275SEric Cheng 	mutex_destroy(&bf_pool->recycle_lock);
4628275SEric Cheng 	mutex_destroy(&bf_pool->pool_lock);
4638275SEric Cheng 	bf_pool->live = B_FALSE;
4648275SEric Cheng 
4658275SEric Cheng 	return (B_TRUE);
4661256Syl150051 }
4671256Syl150051 
4681256Syl150051 /*
4691256Syl150051  * xgell_rx_create_buffer_pool
4701256Syl150051  *
4711256Syl150051  * Initialize RX buffer pool for all RX rings. Refer to rx_buffer_pool_t.
4721256Syl150051  */
4738275SEric Cheng static boolean_t
xgell_rx_create_buffer_pool(xgell_rx_ring_t * ring)4748275SEric Cheng xgell_rx_create_buffer_pool(xgell_rx_ring_t *ring)
4751256Syl150051 {
4768275SEric Cheng 	xgelldev_t *lldev = ring->lldev;
4778275SEric Cheng 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
4781256Syl150051 	xge_hal_device_t *hldev;
4791256Syl150051 	xgell_rx_buffer_t *rx_buffer;
4801256Syl150051 	int i;
4811256Syl150051 
4828275SEric Cheng 	if (bf_pool->live)
4838275SEric Cheng 		return (B_TRUE);
4848275SEric Cheng 
4852311Sseb 	hldev = (xge_hal_device_t *)lldev->devh;
4861256Syl150051 
4878275SEric Cheng 	bf_pool->total = 0;
4888275SEric Cheng 	bf_pool->size = XGELL_MAX_FRAME_SIZE(hldev);
4898275SEric Cheng 	bf_pool->head = NULL;
4908275SEric Cheng 	bf_pool->free = 0;
4918275SEric Cheng 	bf_pool->post = 0;
4928275SEric Cheng 	bf_pool->post_hiwat = lldev->config.rx_buffer_post_hiwat;
4938275SEric Cheng 	bf_pool->recycle = 0;
4948275SEric Cheng 	bf_pool->recycle_head = NULL;
4958275SEric Cheng 	bf_pool->recycle_tail = NULL;
4968275SEric Cheng 	bf_pool->live = B_TRUE;
4978275SEric Cheng 
4988275SEric Cheng 	mutex_init(&bf_pool->pool_lock, NULL, MUTEX_DRIVER,
4996937Sxw161283 	    DDI_INTR_PRI(hldev->irqh));
5008275SEric Cheng 	mutex_init(&bf_pool->recycle_lock, NULL, MUTEX_DRIVER,
5016937Sxw161283 	    DDI_INTR_PRI(hldev->irqh));
5021256Syl150051 
5031256Syl150051 	/*
5041256Syl150051 	 * Allocate buffers one by one. If failed, destroy whole pool by
5051256Syl150051 	 * call to xgell_rx_destroy_buffer_pool().
5061256Syl150051 	 */
5076937Sxw161283 
5081256Syl150051 	for (i = 0; i < lldev->config.rx_buffer_total; i++) {
5096937Sxw161283 		if ((rx_buffer = xgell_rx_buffer_alloc(ring)) == NULL) {
5106937Sxw161283 			(void) xgell_rx_destroy_buffer_pool(ring);
5118275SEric Cheng 			return (B_FALSE);
5121256Syl150051 		}
5131256Syl150051 
5148275SEric Cheng 		rx_buffer->next = bf_pool->head;
5158275SEric Cheng 		bf_pool->head = rx_buffer;
5168275SEric Cheng 
5178275SEric Cheng 		bf_pool->total++;
5188275SEric Cheng 		bf_pool->free++;
5191256Syl150051 	}
5201256Syl150051 
5218275SEric Cheng 	return (B_TRUE);
5221256Syl150051 }
5231256Syl150051 
5241256Syl150051 /*
5251256Syl150051  * xgell_rx_dtr_replenish
5261256Syl150051  *
5271256Syl150051  * Replenish descriptor with rx_buffer in RX buffer pool.
5281256Syl150051  * The dtr should be post right away.
5291256Syl150051  */
5301256Syl150051 xge_hal_status_e
xgell_rx_dtr_replenish(xge_hal_channel_h channelh,xge_hal_dtr_h dtr,int index,void * userdata,xge_hal_channel_reopen_e reopen)5311256Syl150051 xgell_rx_dtr_replenish(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, int index,
5321256Syl150051     void *userdata, xge_hal_channel_reopen_e reopen)
5331256Syl150051 {
5348275SEric Cheng 	xgell_rx_ring_t *ring = userdata;
5358275SEric Cheng 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
5361256Syl150051 	xgell_rx_buffer_t *rx_buffer;
5371256Syl150051 	xgell_rxd_priv_t *rxd_priv;
5381256Syl150051 
5398275SEric Cheng 	mutex_enter(&bf_pool->pool_lock);
5408275SEric Cheng 	if (bf_pool->head == NULL) {
5418275SEric Cheng 		xge_debug_ll(XGE_ERR, "no more available rx DMA buffer!");
5421256Syl150051 		return (XGE_HAL_FAIL);
5431256Syl150051 	}
5448275SEric Cheng 	rx_buffer = bf_pool->head;
5451256Syl150051 	xge_assert(rx_buffer);
5461256Syl150051 	xge_assert(rx_buffer->dma_addr);
5471256Syl150051 
5488275SEric Cheng 	bf_pool->head = rx_buffer->next;
5498275SEric Cheng 	bf_pool->free--;
5508275SEric Cheng 	mutex_exit(&bf_pool->pool_lock);
5518275SEric Cheng 
5526937Sxw161283 	rxd_priv = (xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtr);
5538275SEric Cheng 	xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr, bf_pool->size);
5541256Syl150051 
5551256Syl150051 	rxd_priv->rx_buffer = rx_buffer;
5561256Syl150051 
5571256Syl150051 	return (XGE_HAL_OK);
5581256Syl150051 }
5591256Syl150051 
5601256Syl150051 /*
5611256Syl150051  * xgell_get_ip_offset
5621256Syl150051  *
5631256Syl150051  * Calculate the offset to IP header.
5641256Syl150051  */
5651256Syl150051 static inline int
xgell_get_ip_offset(xge_hal_dtr_info_t * ext_info)5661256Syl150051 xgell_get_ip_offset(xge_hal_dtr_info_t *ext_info)
5671256Syl150051 {
5681256Syl150051 	int ip_off;
5691256Syl150051 
5701256Syl150051 	/* get IP-header offset */
5711256Syl150051 	switch (ext_info->frame) {
5721256Syl150051 	case XGE_HAL_FRAME_TYPE_DIX:
5731256Syl150051 		ip_off = XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE;
5741256Syl150051 		break;
5751256Syl150051 	case XGE_HAL_FRAME_TYPE_IPX:
5761256Syl150051 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
5771256Syl150051 		    XGE_HAL_HEADER_802_2_SIZE +
5781256Syl150051 		    XGE_HAL_HEADER_SNAP_SIZE);
5791256Syl150051 		break;
5801256Syl150051 	case XGE_HAL_FRAME_TYPE_LLC:
5811256Syl150051 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
5821256Syl150051 		    XGE_HAL_HEADER_802_2_SIZE);
5831256Syl150051 		break;
5841256Syl150051 	case XGE_HAL_FRAME_TYPE_SNAP:
5851256Syl150051 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
5861256Syl150051 		    XGE_HAL_HEADER_SNAP_SIZE);
5871256Syl150051 		break;
5881256Syl150051 	default:
5891256Syl150051 		ip_off = 0;
5901256Syl150051 		break;
5911256Syl150051 	}
5921256Syl150051 
5931256Syl150051 	if ((ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4 ||
5941256Syl150051 	    ext_info->proto & XGE_HAL_FRAME_PROTO_IPV6) &&
5951256Syl150051 	    (ext_info->proto & XGE_HAL_FRAME_PROTO_VLAN_TAGGED)) {
5961256Syl150051 		ip_off += XGE_HAL_HEADER_VLAN_SIZE;
5971256Syl150051 	}
5981256Syl150051 
5991256Syl150051 	return (ip_off);
6001256Syl150051 }
6011256Syl150051 
6021256Syl150051 /*
6031256Syl150051  * xgell_rx_hcksum_assoc
6041256Syl150051  *
6051256Syl150051  * Judge the packet type and then call to hcksum_assoc() to associate
6061256Syl150051  * h/w checksum information.
6071256Syl150051  */
6081256Syl150051 static inline void
xgell_rx_hcksum_assoc(mblk_t * mp,char * vaddr,int pkt_length,xge_hal_dtr_info_t * ext_info)6091256Syl150051 xgell_rx_hcksum_assoc(mblk_t *mp, char *vaddr, int pkt_length,
6101256Syl150051     xge_hal_dtr_info_t *ext_info)
6111256Syl150051 {
6121256Syl150051 	int cksum_flags = 0;
6131256Syl150051 
6141256Syl150051 	if (!(ext_info->proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED)) {
6151256Syl150051 		if (ext_info->proto & XGE_HAL_FRAME_PROTO_TCP_OR_UDP) {
6161256Syl150051 			if (ext_info->l3_cksum == XGE_HAL_L3_CKSUM_OK) {
617*11878SVenu.Iyer@Sun.COM 				cksum_flags |= HCK_IPV4_HDRCKSUM_OK;
6181256Syl150051 			}
6191256Syl150051 			if (ext_info->l4_cksum == XGE_HAL_L4_CKSUM_OK) {
6201256Syl150051 				cksum_flags |= HCK_FULLCKSUM_OK;
6211256Syl150051 			}
622*11878SVenu.Iyer@Sun.COM 			if (cksum_flags != 0) {
623*11878SVenu.Iyer@Sun.COM 				mac_hcksum_set(mp, 0, 0, 0, 0, cksum_flags);
6241256Syl150051 			}
6251256Syl150051 		}
6261256Syl150051 	} else if (ext_info->proto &
6271256Syl150051 	    (XGE_HAL_FRAME_PROTO_IPV4 | XGE_HAL_FRAME_PROTO_IPV6)) {
6281256Syl150051 		/*
6291256Syl150051 		 * Just pass the partial cksum up to IP.
6301256Syl150051 		 */
6313115Syl150051 		int ip_off = xgell_get_ip_offset(ext_info);
6321256Syl150051 		int start, end = pkt_length - ip_off;
6331256Syl150051 
6341256Syl150051 		if (ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4) {
6351256Syl150051 			struct ip *ip =
6361256Syl150051 			    (struct ip *)(vaddr + ip_off);
63711145SRoamer@Sun.COM 			start = ip->ip_hl * 4;
6381256Syl150051 		} else {
63911145SRoamer@Sun.COM 			start = 40;
6401256Syl150051 		}
6411256Syl150051 		cksum_flags |= HCK_PARTIALCKSUM;
642*11878SVenu.Iyer@Sun.COM 		mac_hcksum_set(mp, start, 0, end,
643*11878SVenu.Iyer@Sun.COM 		    ntohs(ext_info->l4_cksum), cksum_flags);
6441256Syl150051 	}
6451256Syl150051 }
6461256Syl150051 
6471256Syl150051 /*
6481256Syl150051  * xgell_rx_1b_msg_alloc
6491256Syl150051  *
6501256Syl150051  * Allocate message header for data buffer, and decide if copy the packet to
6511256Syl150051  * new data buffer to release big rx_buffer to save memory.
6521256Syl150051  *
6533115Syl150051  * If the pkt_length <= XGELL_RX_DMA_LOWAT, call allocb() to allocate
6541256Syl150051  * new message and copy the payload in.
6551256Syl150051  */
6561256Syl150051 static mblk_t *
xgell_rx_1b_msg_alloc(xgell_rx_ring_t * ring,xgell_rx_buffer_t * rx_buffer,int pkt_length,xge_hal_dtr_info_t * ext_info,boolean_t * copyit)6578275SEric Cheng xgell_rx_1b_msg_alloc(xgell_rx_ring_t *ring, xgell_rx_buffer_t *rx_buffer,
6583115Syl150051     int pkt_length, xge_hal_dtr_info_t *ext_info, boolean_t *copyit)
6591256Syl150051 {
6608275SEric Cheng 	xgelldev_t *lldev = ring->lldev;
6611256Syl150051 	mblk_t *mp;
6621256Syl150051 	char *vaddr;
6631256Syl150051 
6641256Syl150051 	vaddr = (char *)rx_buffer->vaddr + HEADROOM;
6651256Syl150051 	/*
6661256Syl150051 	 * Copy packet into new allocated message buffer, if pkt_length
6673115Syl150051 	 * is less than XGELL_RX_DMA_LOWAT
6681256Syl150051 	 */
6693115Syl150051 	if (*copyit || pkt_length <= lldev->config.rx_dma_lowat) {
6706937Sxw161283 		if ((mp = allocb(pkt_length + HEADROOM, 0)) == NULL) {
6711256Syl150051 			return (NULL);
6721256Syl150051 		}
6736937Sxw161283 		mp->b_rptr += HEADROOM;
6741256Syl150051 		bcopy(vaddr, mp->b_rptr, pkt_length);
6751256Syl150051 		mp->b_wptr = mp->b_rptr + pkt_length;
6761256Syl150051 		*copyit = B_TRUE;
6771256Syl150051 		return (mp);
6781256Syl150051 	}
6791256Syl150051 
6801256Syl150051 	/*
6811256Syl150051 	 * Just allocate mblk for current data buffer
6821256Syl150051 	 */
6833392Syl150051 	if ((mp = (mblk_t *)desballoc((unsigned char *)vaddr, pkt_length, 0,
6841256Syl150051 	    &rx_buffer->frtn)) == NULL) {
6851256Syl150051 		/* Drop it */
6861256Syl150051 		return (NULL);
6871256Syl150051 	}
6881256Syl150051 	/*
6893392Syl150051 	 * Adjust the b_rptr/b_wptr in the mblk_t structure.
6901256Syl150051 	 */
6913392Syl150051 	mp->b_wptr += pkt_length;
6921256Syl150051 
6931256Syl150051 	return (mp);
6941256Syl150051 }
6951256Syl150051 
6961256Syl150051 /*
6978275SEric Cheng  * xgell_rx_1b_callback
6981256Syl150051  *
6991256Syl150051  * If the interrupt is because of a received frame or if the receive ring
7001256Syl150051  * contains fresh as yet un-processed frames, this function is called.
7011256Syl150051  */
7021256Syl150051 static xge_hal_status_e
xgell_rx_1b_callback(xge_hal_channel_h channelh,xge_hal_dtr_h dtr,u8 t_code,void * userdata)7038275SEric Cheng xgell_rx_1b_callback(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
7041256Syl150051     void *userdata)
7051256Syl150051 {
7068275SEric Cheng 	xgell_rx_ring_t *ring = (xgell_rx_ring_t *)userdata;
7076937Sxw161283 	xgelldev_t *lldev = ring->lldev;
7081256Syl150051 	xgell_rx_buffer_t *rx_buffer;
7091256Syl150051 	mblk_t *mp_head = NULL;
7101256Syl150051 	mblk_t *mp_end  = NULL;
7113115Syl150051 	int pkt_burst = 0;
7123115Syl150051 
7138275SEric Cheng 	xge_debug_ll(XGE_TRACE, "xgell_rx_1b_callback on ring %d", ring->index);
7148275SEric Cheng 
7156937Sxw161283 	mutex_enter(&ring->bf_pool.pool_lock);
7161256Syl150051 	do {
7171256Syl150051 		int pkt_length;
7181256Syl150051 		dma_addr_t dma_data;
7191256Syl150051 		mblk_t *mp;
7201256Syl150051 		boolean_t copyit = B_FALSE;
7211256Syl150051 
7221256Syl150051 		xgell_rxd_priv_t *rxd_priv = ((xgell_rxd_priv_t *)
7231256Syl150051 		    xge_hal_ring_dtr_private(channelh, dtr));
7241256Syl150051 		xge_hal_dtr_info_t ext_info;
7251256Syl150051 
7261256Syl150051 		rx_buffer = rxd_priv->rx_buffer;
7271256Syl150051 
7281256Syl150051 		xge_hal_ring_dtr_1b_get(channelh, dtr, &dma_data, &pkt_length);
7291256Syl150051 		xge_hal_ring_dtr_info_get(channelh, dtr, &ext_info);
7301256Syl150051 
7311256Syl150051 		xge_assert(dma_data == rx_buffer->dma_addr);
7321256Syl150051 
7331256Syl150051 		if (t_code != 0) {
7341256Syl150051 			xge_debug_ll(XGE_ERR, "%s%d: rx: dtr 0x%"PRIx64
7351256Syl150051 			    " completed due to error t_code %01x", XGELL_IFNAME,
7361256Syl150051 			    lldev->instance, (uint64_t)(uintptr_t)dtr, t_code);
7371256Syl150051 
7381256Syl150051 			(void) xge_hal_device_handle_tcode(channelh, dtr,
7391256Syl150051 			    t_code);
7401256Syl150051 			xge_hal_ring_dtr_free(channelh, dtr); /* drop it */
7411256Syl150051 			xgell_rx_buffer_release(rx_buffer);
7421256Syl150051 			continue;
7431256Syl150051 		}
7441256Syl150051 
7451256Syl150051 		/*
7461256Syl150051 		 * Sync the DMA memory
7471256Syl150051 		 */
7483115Syl150051 		if (ddi_dma_sync(rx_buffer->dma_handle, 0, pkt_length,
7493115Syl150051 		    DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) {
7501256Syl150051 			xge_debug_ll(XGE_ERR, "%s%d: rx: can not do DMA sync",
7511256Syl150051 			    XGELL_IFNAME, lldev->instance);
7521256Syl150051 			xge_hal_ring_dtr_free(channelh, dtr); /* drop it */
7531256Syl150051 			xgell_rx_buffer_release(rx_buffer);
7541256Syl150051 			continue;
7551256Syl150051 		}
7561256Syl150051 
7571256Syl150051 		/*
7581256Syl150051 		 * Allocate message for the packet.
7591256Syl150051 		 */
7606937Sxw161283 		if (ring->bf_pool.post > ring->bf_pool.post_hiwat) {
7611256Syl150051 			copyit = B_TRUE;
7621256Syl150051 		} else {
7631256Syl150051 			copyit = B_FALSE;
7641256Syl150051 		}
7651256Syl150051 
7668275SEric Cheng 		mp = xgell_rx_1b_msg_alloc(ring, rx_buffer, pkt_length,
7673115Syl150051 		    &ext_info, &copyit);
7681256Syl150051 
7691256Syl150051 		xge_hal_ring_dtr_free(channelh, dtr);
7701256Syl150051 
7711256Syl150051 		/*
7721256Syl150051 		 * Release the buffer and recycle it later
7731256Syl150051 		 */
7741256Syl150051 		if ((mp == NULL) || copyit) {
7751256Syl150051 			xgell_rx_buffer_release(rx_buffer);
7761256Syl150051 		} else {
7771256Syl150051 			/*
7781256Syl150051 			 * Count it since the buffer should be loaned up.
7791256Syl150051 			 */
7806937Sxw161283 			ring->bf_pool.post++;
7811256Syl150051 		}
7821256Syl150051 		if (mp == NULL) {
7831256Syl150051 			xge_debug_ll(XGE_ERR,
7843115Syl150051 			    "%s%d: rx: can not allocate mp mblk",
7853115Syl150051 			    XGELL_IFNAME, lldev->instance);
7861256Syl150051 			continue;
7871256Syl150051 		}
7881256Syl150051 
7891256Syl150051 		/*
7903115Syl150051 		 * Associate cksum_flags per packet type and h/w
7913115Syl150051 		 * cksum flags.
7921256Syl150051 		 */
7938275SEric Cheng 		xgell_rx_hcksum_assoc(mp, (char *)rx_buffer->vaddr + HEADROOM,
7948275SEric Cheng 		    pkt_length, &ext_info);
7958275SEric Cheng 
796*11878SVenu.Iyer@Sun.COM 		ring->rx_pkts++;
797*11878SVenu.Iyer@Sun.COM 		ring->rx_bytes += pkt_length;
7981256Syl150051 
7991256Syl150051 		if (mp_head == NULL) {
8001256Syl150051 			mp_head = mp;
8011256Syl150051 			mp_end = mp;
8021256Syl150051 		} else {
8031256Syl150051 			mp_end->b_next = mp;
8041256Syl150051 			mp_end = mp;
8051256Syl150051 		}
8061256Syl150051 
8078275SEric Cheng 		/*
8088275SEric Cheng 		 * Inlined implemented polling function.
8098275SEric Cheng 		 */
8108275SEric Cheng 		if ((ring->poll_mp == NULL) && (ring->poll_bytes > 0)) {
8118275SEric Cheng 			ring->poll_mp = mp_head;
8128275SEric Cheng 		}
8138275SEric Cheng 		if (ring->poll_mp != NULL) {
8148275SEric Cheng 			if ((ring->poll_bytes -= pkt_length) <= 0) {
8158275SEric Cheng 				/* have polled enough packets. */
8168275SEric Cheng 				break;
8178275SEric Cheng 			} else {
8188275SEric Cheng 				/* continue polling packets. */
8198275SEric Cheng 				continue;
8208275SEric Cheng 			}
8218275SEric Cheng 		}
8228275SEric Cheng 
8238275SEric Cheng 		/*
8248275SEric Cheng 		 * We're not in polling mode, so try to chain more messages
8258275SEric Cheng 		 * or send the chain up according to pkt_burst.
8268275SEric Cheng 		 */
8273115Syl150051 		if (++pkt_burst < lldev->config.rx_pkt_burst)
8283115Syl150051 			continue;
8293115Syl150051 
8306937Sxw161283 		if (ring->bf_pool.post > ring->bf_pool.post_hiwat) {
8313115Syl150051 			/* Replenish rx buffers */
8326937Sxw161283 			xgell_rx_buffer_replenish_all(ring);
8333115Syl150051 		}
8346937Sxw161283 		mutex_exit(&ring->bf_pool.pool_lock);
8353115Syl150051 		if (mp_head != NULL) {
8368275SEric Cheng 			mac_rx_ring(lldev->mh, ring->ring_handle, mp_head,
8378275SEric Cheng 			    ring->ring_gen_num);
8383115Syl150051 		}
8393115Syl150051 		mp_head = mp_end  = NULL;
8403115Syl150051 		pkt_burst = 0;
8416937Sxw161283 		mutex_enter(&ring->bf_pool.pool_lock);
8423115Syl150051 
8431256Syl150051 	} while (xge_hal_ring_dtr_next_completed(channelh, &dtr, &t_code) ==
8441256Syl150051 	    XGE_HAL_OK);
8451256Syl150051 
8461256Syl150051 	/*
8471256Syl150051 	 * Always call replenish_all to recycle rx_buffers.
8481256Syl150051 	 */
8496937Sxw161283 	xgell_rx_buffer_replenish_all(ring);
8506937Sxw161283 	mutex_exit(&ring->bf_pool.pool_lock);
8511256Syl150051 
8528275SEric Cheng 	/*
8538275SEric Cheng 	 * If we're not in polling cycle, call mac_rx(), otherwise
8548275SEric Cheng 	 * just return while leaving packets chained to ring->poll_mp.
8558275SEric Cheng 	 */
8568275SEric Cheng 	if ((ring->poll_mp == NULL) && (mp_head != NULL)) {
8578275SEric Cheng 		mac_rx_ring(lldev->mh, ring->ring_handle, mp_head,
8588275SEric Cheng 		    ring->ring_gen_num);
8593115Syl150051 	}
8603115Syl150051 
8611256Syl150051 	return (XGE_HAL_OK);
8621256Syl150051 }
8631256Syl150051 
8648275SEric Cheng mblk_t *
xgell_rx_poll(void * arg,int bytes_to_pickup)8658275SEric Cheng xgell_rx_poll(void *arg, int bytes_to_pickup)
8668275SEric Cheng {
8678275SEric Cheng 	xgell_rx_ring_t *ring = (xgell_rx_ring_t *)arg;
8688275SEric Cheng 	int got_rx = 0;
8698275SEric Cheng 	mblk_t *mp;
8708275SEric Cheng 
8718275SEric Cheng 	xge_debug_ll(XGE_TRACE, "xgell_rx_poll on ring %d", ring->index);
8728275SEric Cheng 
8738275SEric Cheng 	ring->poll_mp = NULL;
8748275SEric Cheng 	ring->poll_bytes = bytes_to_pickup;
8758275SEric Cheng 	(void) xge_hal_device_poll_rx_channel(ring->channelh, &got_rx);
8768275SEric Cheng 
8778275SEric Cheng 	mp = ring->poll_mp;
8788275SEric Cheng 	ring->poll_bytes = -1;
8798275SEric Cheng 	ring->polled_bytes += got_rx;
8808275SEric Cheng 	ring->poll_mp = NULL;
8818275SEric Cheng 
8828275SEric Cheng 	return (mp);
8838275SEric Cheng }
8848275SEric Cheng 
8851256Syl150051 /*
8861256Syl150051  * xgell_xmit_compl
8871256Syl150051  *
8881256Syl150051  * If an interrupt was raised to indicate DMA complete of the Tx packet,
8891256Syl150051  * this function is called. It identifies the last TxD whose buffer was
8901256Syl150051  * freed and frees all skbs whose data have already DMA'ed into the NICs
8911256Syl150051  * internal memory.
8921256Syl150051  */
8931256Syl150051 static xge_hal_status_e
xgell_xmit_compl(xge_hal_channel_h channelh,xge_hal_dtr_h dtr,u8 t_code,void * userdata)8941256Syl150051 xgell_xmit_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
8951256Syl150051     void *userdata)
8961256Syl150051 {
8978275SEric Cheng 	xgell_tx_ring_t *ring = userdata;
8988275SEric Cheng 	xgelldev_t *lldev = ring->lldev;
8991256Syl150051 
9001256Syl150051 	do {
9011256Syl150051 		xgell_txd_priv_t *txd_priv = ((xgell_txd_priv_t *)
9021256Syl150051 		    xge_hal_fifo_dtr_private(dtr));
9031256Syl150051 		int i;
9041256Syl150051 
9051256Syl150051 		if (t_code) {
9061256Syl150051 			xge_debug_ll(XGE_TRACE, "%s%d: tx: dtr 0x%"PRIx64
9071256Syl150051 			    " completed due to error t_code %01x", XGELL_IFNAME,
9081256Syl150051 			    lldev->instance, (uint64_t)(uintptr_t)dtr, t_code);
9091256Syl150051 
9101256Syl150051 			(void) xge_hal_device_handle_tcode(channelh, dtr,
9111256Syl150051 			    t_code);
9121256Syl150051 		}
9131256Syl150051 
9141256Syl150051 		for (i = 0; i < txd_priv->handle_cnt; i++) {
9156937Sxw161283 			if (txd_priv->dma_handles[i] != NULL) {
9166937Sxw161283 				xge_assert(txd_priv->dma_handles[i]);
9176937Sxw161283 				(void) ddi_dma_unbind_handle(
9186937Sxw161283 				    txd_priv->dma_handles[i]);
9196937Sxw161283 				ddi_dma_free_handle(&txd_priv->dma_handles[i]);
9206937Sxw161283 				txd_priv->dma_handles[i] = 0;
9216937Sxw161283 			}
9221256Syl150051 		}
9236937Sxw161283 		txd_priv->handle_cnt = 0;
9241256Syl150051 
9251256Syl150051 		xge_hal_fifo_dtr_free(channelh, dtr);
9261256Syl150051 
9276937Sxw161283 		if (txd_priv->mblk != NULL) {
9286937Sxw161283 			freemsg(txd_priv->mblk);
9296937Sxw161283 			txd_priv->mblk = NULL;
9306937Sxw161283 		}
9316937Sxw161283 
9321256Syl150051 	} while (xge_hal_fifo_dtr_next_completed(channelh, &dtr, &t_code) ==
9331256Syl150051 	    XGE_HAL_OK);
9341256Syl150051 
9358275SEric Cheng 	if (ring->need_resched)
9368275SEric Cheng 		mac_tx_ring_update(lldev->mh, ring->ring_handle);
9371256Syl150051 
9381256Syl150051 	return (XGE_HAL_OK);
9391256Syl150051 }
9401256Syl150051 
9418275SEric Cheng mblk_t *
xgell_ring_tx(void * arg,mblk_t * mp)9428275SEric Cheng xgell_ring_tx(void *arg, mblk_t *mp)
9431256Syl150051 {
9448275SEric Cheng 	xgell_tx_ring_t *ring = (xgell_tx_ring_t *)arg;
9451256Syl150051 	mblk_t *bp;
9468275SEric Cheng 	xgelldev_t *lldev = ring->lldev;
9473115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
9481256Syl150051 	xge_hal_status_e status;
9491256Syl150051 	xge_hal_dtr_h dtr;
9501256Syl150051 	xgell_txd_priv_t *txd_priv;
9513115Syl150051 	uint32_t hckflags;
9528275SEric Cheng 	uint32_t lsoflags;
9533115Syl150051 	uint32_t mss;
9543115Syl150051 	int handle_cnt, frag_cnt, ret, i, copied;
9553115Syl150051 	boolean_t used_copy;
956*11878SVenu.Iyer@Sun.COM 	uint64_t sent_bytes;
9571256Syl150051 
9581256Syl150051 _begin:
9591256Syl150051 	handle_cnt = frag_cnt = 0;
960*11878SVenu.Iyer@Sun.COM 	sent_bytes = 0;
9611256Syl150051 
9621256Syl150051 	if (!lldev->is_initialized || lldev->in_reset)
9638275SEric Cheng 		return (mp);
9646937Sxw161283 
9651256Syl150051 	/*
9661256Syl150051 	 * If the free Tx dtrs count reaches the lower threshold,
9671256Syl150051 	 * inform the gld to stop sending more packets till the free
9681256Syl150051 	 * dtrs count exceeds higher threshold. Driver informs the
9691256Syl150051 	 * gld through gld_sched call, when the free dtrs count exceeds
9701256Syl150051 	 * the higher threshold.
9711256Syl150051 	 */
9728275SEric Cheng 	if (xge_hal_channel_dtr_count(ring->channelh)
9731256Syl150051 	    <= XGELL_TX_LEVEL_LOW) {
9748275SEric Cheng 		xge_debug_ll(XGE_TRACE, "%s%d: queue %d: err on xmit,"
9758275SEric Cheng 		    "free descriptors count at low threshold %d",
9768275SEric Cheng 		    XGELL_IFNAME, lldev->instance,
9778275SEric Cheng 		    ((xge_hal_channel_t *)ring->channelh)->post_qid,
9788275SEric Cheng 		    XGELL_TX_LEVEL_LOW);
9798275SEric Cheng 		goto _exit;
9801256Syl150051 	}
9811256Syl150051 
9828275SEric Cheng 	status = xge_hal_fifo_dtr_reserve(ring->channelh, &dtr);
9831256Syl150051 	if (status != XGE_HAL_OK) {
9841256Syl150051 		switch (status) {
9851256Syl150051 		case XGE_HAL_INF_CHANNEL_IS_NOT_READY:
9861256Syl150051 			xge_debug_ll(XGE_ERR,
9871256Syl150051 			    "%s%d: channel %d is not ready.", XGELL_IFNAME,
9881256Syl150051 			    lldev->instance,
9891256Syl150051 			    ((xge_hal_channel_t *)
9908275SEric Cheng 			    ring->channelh)->post_qid);
9911256Syl150051 			goto _exit;
9921256Syl150051 		case XGE_HAL_INF_OUT_OF_DESCRIPTORS:
9931256Syl150051 			xge_debug_ll(XGE_TRACE, "%s%d: queue %d: error in xmit,"
9941256Syl150051 			    " out of descriptors.", XGELL_IFNAME,
9951256Syl150051 			    lldev->instance,
9961256Syl150051 			    ((xge_hal_channel_t *)
9978275SEric Cheng 			    ring->channelh)->post_qid);
9981256Syl150051 			goto _exit;
9991256Syl150051 		default:
10008275SEric Cheng 			return (mp);
10011256Syl150051 		}
10021256Syl150051 	}
10031256Syl150051 
10041256Syl150051 	txd_priv = xge_hal_fifo_dtr_private(dtr);
10051256Syl150051 	txd_priv->mblk = mp;
10061256Syl150051 
10071256Syl150051 	/*
10081256Syl150051 	 * VLAN tag should be passed down along with MAC header, so h/w needn't
10091256Syl150051 	 * do insertion.
10101256Syl150051 	 *
10111256Syl150051 	 * For NIC driver that has to strip and re-insert VLAN tag, the example
10121256Syl150051 	 * is the other implementation for xge. The driver can simple bcopy()
10131256Syl150051 	 * ether_vlan_header to overwrite VLAN tag and let h/w insert the tag
10141256Syl150051 	 * automatically, since it's impossible that GLD sends down mp(s) with
10151256Syl150051 	 * splited ether_vlan_header.
10161256Syl150051 	 *
10171256Syl150051 	 * struct ether_vlan_header *evhp;
10181256Syl150051 	 * uint16_t tci;
10191256Syl150051 	 *
10201256Syl150051 	 * evhp = (struct ether_vlan_header *)mp->b_rptr;
10211256Syl150051 	 * if (evhp->ether_tpid == htons(VLAN_TPID)) {
10223115Syl150051 	 *	tci = ntohs(evhp->ether_tci);
10233115Syl150051 	 *	(void) bcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ,
10241256Syl150051 	 *	    2 * ETHERADDRL);
10253115Syl150051 	 *	mp->b_rptr += VLAN_TAGSZ;
10261256Syl150051 	 *
10273115Syl150051 	 *	xge_hal_fifo_dtr_vlan_set(dtr, tci);
10281256Syl150051 	 * }
10291256Syl150051 	 */
10301256Syl150051 
10313115Syl150051 	copied = 0;
10323115Syl150051 	used_copy = B_FALSE;
10331256Syl150051 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
10341256Syl150051 		int mblen;
10351256Syl150051 		uint_t ncookies;
10361256Syl150051 		ddi_dma_cookie_t dma_cookie;
10371256Syl150051 		ddi_dma_handle_t dma_handle;
10381256Syl150051 
10391256Syl150051 		/* skip zero-length message blocks */
10401256Syl150051 		mblen = MBLKL(bp);
10411256Syl150051 		if (mblen == 0) {
10421256Syl150051 			continue;
10431256Syl150051 		}
10441256Syl150051 
1045*11878SVenu.Iyer@Sun.COM 		sent_bytes += mblen;
10468275SEric Cheng 
10473115Syl150051 		/*
10483115Syl150051 		 * Check the message length to decide to DMA or bcopy() data
10493115Syl150051 		 * to tx descriptor(s).
10503115Syl150051 		 */
10513115Syl150051 		if (mblen < lldev->config.tx_dma_lowat &&
10523115Syl150051 		    (copied + mblen) < lldev->tx_copied_max) {
10533115Syl150051 			xge_hal_status_e rc;
10548275SEric Cheng 			rc = xge_hal_fifo_dtr_buffer_append(ring->channelh,
10553115Syl150051 			    dtr, bp->b_rptr, mblen);
10563115Syl150051 			if (rc == XGE_HAL_OK) {
10573115Syl150051 				used_copy = B_TRUE;
10583115Syl150051 				copied += mblen;
10593115Syl150051 				continue;
10603115Syl150051 			} else if (used_copy) {
10613115Syl150051 				xge_hal_fifo_dtr_buffer_finalize(
10628275SEric Cheng 				    ring->channelh, dtr, frag_cnt++);
10633115Syl150051 				used_copy = B_FALSE;
10643115Syl150051 			}
10653115Syl150051 		} else if (used_copy) {
10668275SEric Cheng 			xge_hal_fifo_dtr_buffer_finalize(ring->channelh,
10673115Syl150051 			    dtr, frag_cnt++);
10683115Syl150051 			used_copy = B_FALSE;
10693115Syl150051 		}
10703115Syl150051 
10712311Sseb 		ret = ddi_dma_alloc_handle(lldev->dev_info, &tx_dma_attr,
10721256Syl150051 		    DDI_DMA_DONTWAIT, 0, &dma_handle);
10731256Syl150051 		if (ret != DDI_SUCCESS) {
10741256Syl150051 			xge_debug_ll(XGE_ERR,
10753115Syl150051 			    "%s%d: can not allocate dma handle", XGELL_IFNAME,
10763115Syl150051 			    lldev->instance);
10771256Syl150051 			goto _exit_cleanup;
10781256Syl150051 		}
10791256Syl150051 
10801256Syl150051 		ret = ddi_dma_addr_bind_handle(dma_handle, NULL,
10811256Syl150051 		    (caddr_t)bp->b_rptr, mblen,
10821256Syl150051 		    DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
10831256Syl150051 		    &dma_cookie, &ncookies);
10841256Syl150051 
10851256Syl150051 		switch (ret) {
10861256Syl150051 		case DDI_DMA_MAPPED:
10871256Syl150051 			/* everything's fine */
10881256Syl150051 			break;
10891256Syl150051 
10901256Syl150051 		case DDI_DMA_NORESOURCES:
10911256Syl150051 			xge_debug_ll(XGE_ERR,
10921256Syl150051 			    "%s%d: can not bind dma address",
10931256Syl150051 			    XGELL_IFNAME, lldev->instance);
10941256Syl150051 			ddi_dma_free_handle(&dma_handle);
10951256Syl150051 			goto _exit_cleanup;
10961256Syl150051 
10971256Syl150051 		case DDI_DMA_NOMAPPING:
10981256Syl150051 		case DDI_DMA_INUSE:
10991256Syl150051 		case DDI_DMA_TOOBIG:
11001256Syl150051 		default:
11011256Syl150051 			/* drop packet, don't retry */
11021256Syl150051 			xge_debug_ll(XGE_ERR,
11031256Syl150051 			    "%s%d: can not map message buffer",
11041256Syl150051 			    XGELL_IFNAME, lldev->instance);
11051256Syl150051 			ddi_dma_free_handle(&dma_handle);
11061256Syl150051 			goto _exit_cleanup;
11071256Syl150051 		}
11081256Syl150051 
11093115Syl150051 		if (ncookies + frag_cnt > hldev->config.fifo.max_frags) {
11101256Syl150051 			xge_debug_ll(XGE_ERR, "%s%d: too many fragments, "
11111256Syl150051 			    "requested c:%d+f:%d", XGELL_IFNAME,
11121256Syl150051 			    lldev->instance, ncookies, frag_cnt);
11131256Syl150051 			(void) ddi_dma_unbind_handle(dma_handle);
11141256Syl150051 			ddi_dma_free_handle(&dma_handle);
11151256Syl150051 			goto _exit_cleanup;
11161256Syl150051 		}
11171256Syl150051 
11181256Syl150051 		/* setup the descriptors for this data buffer */
11191256Syl150051 		while (ncookies) {
11208275SEric Cheng 			xge_hal_fifo_dtr_buffer_set(ring->channelh, dtr,
11211256Syl150051 			    frag_cnt++, dma_cookie.dmac_laddress,
11221256Syl150051 			    dma_cookie.dmac_size);
11231256Syl150051 			if (--ncookies) {
11241256Syl150051 				ddi_dma_nextcookie(dma_handle, &dma_cookie);
11251256Syl150051 			}
11261256Syl150051 
11271256Syl150051 		}
11281256Syl150051 
11291256Syl150051 		txd_priv->dma_handles[handle_cnt++] = dma_handle;
11301256Syl150051 
11311256Syl150051 		if (bp->b_cont &&
11321256Syl150051 		    (frag_cnt + XGE_HAL_DEFAULT_FIFO_FRAGS_THRESHOLD >=
11336937Sxw161283 		    hldev->config.fifo.max_frags)) {
11341256Syl150051 			mblk_t *nmp;
11351256Syl150051 
11361256Syl150051 			xge_debug_ll(XGE_TRACE,
11371256Syl150051 			    "too many FRAGs [%d], pull up them", frag_cnt);
11381256Syl150051 
11391256Syl150051 			if ((nmp = msgpullup(bp->b_cont, -1)) == NULL) {
11401256Syl150051 				/* Drop packet, don't retry */
11411256Syl150051 				xge_debug_ll(XGE_ERR,
11421256Syl150051 				    "%s%d: can not pullup message buffer",
11431256Syl150051 				    XGELL_IFNAME, lldev->instance);
11441256Syl150051 				goto _exit_cleanup;
11451256Syl150051 			}
11461256Syl150051 			freemsg(bp->b_cont);
11471256Syl150051 			bp->b_cont = nmp;
11481256Syl150051 		}
11491256Syl150051 	}
11501256Syl150051 
11513115Syl150051 	/* finalize unfinished copies */
11523115Syl150051 	if (used_copy) {
11538275SEric Cheng 		xge_hal_fifo_dtr_buffer_finalize(ring->channelh, dtr,
11543115Syl150051 		    frag_cnt++);
11553115Syl150051 	}
11563115Syl150051 
11571256Syl150051 	txd_priv->handle_cnt = handle_cnt;
11581256Syl150051 
11593115Syl150051 	/*
11603115Syl150051 	 * If LSO is required, just call xge_hal_fifo_dtr_mss_set(dtr, mss) to
11613115Syl150051 	 * do all necessary work.
11623115Syl150051 	 */
1163*11878SVenu.Iyer@Sun.COM 	mac_lso_get(mp, &mss, &lsoflags);
11648275SEric Cheng 
11658275SEric Cheng 	if (lsoflags & HW_LSO) {
11668275SEric Cheng 		xge_assert((mss != 0) && (mss <= XGE_HAL_DEFAULT_MTU));
11673115Syl150051 		xge_hal_fifo_dtr_mss_set(dtr, mss);
11683115Syl150051 	}
11693115Syl150051 
1170*11878SVenu.Iyer@Sun.COM 	mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &hckflags);
11713115Syl150051 	if (hckflags & HCK_IPV4_HDRCKSUM) {
11721256Syl150051 		xge_hal_fifo_dtr_cksum_set_bits(dtr,
11731256Syl150051 		    XGE_HAL_TXD_TX_CKO_IPV4_EN);
11741256Syl150051 	}
11753115Syl150051 	if (hckflags & HCK_FULLCKSUM) {
11761256Syl150051 		xge_hal_fifo_dtr_cksum_set_bits(dtr, XGE_HAL_TXD_TX_CKO_TCP_EN |
11771256Syl150051 		    XGE_HAL_TXD_TX_CKO_UDP_EN);
11781256Syl150051 	}
11791256Syl150051 
11808275SEric Cheng 	xge_hal_fifo_dtr_post(ring->channelh, dtr);
11818275SEric Cheng 
1182*11878SVenu.Iyer@Sun.COM 	/* Update per-ring tx statistics */
1183*11878SVenu.Iyer@Sun.COM 	atomic_add_64(&ring->tx_pkts, 1);
1184*11878SVenu.Iyer@Sun.COM 	atomic_add_64(&ring->tx_bytes, sent_bytes);
1185*11878SVenu.Iyer@Sun.COM 
11868275SEric Cheng 	return (NULL);
11871256Syl150051 
11881256Syl150051 _exit_cleanup:
11898275SEric Cheng 	/*
11908275SEric Cheng 	 * Could not successfully transmit but have changed the message,
11918275SEric Cheng 	 * so just free it and return NULL
11928275SEric Cheng 	 */
11931256Syl150051 	for (i = 0; i < handle_cnt; i++) {
11941256Syl150051 		(void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
11951256Syl150051 		ddi_dma_free_handle(&txd_priv->dma_handles[i]);
11961256Syl150051 		txd_priv->dma_handles[i] = 0;
11971256Syl150051 	}
11981256Syl150051 
11998275SEric Cheng 	xge_hal_fifo_dtr_free(ring->channelh, dtr);
12008275SEric Cheng 
12018275SEric Cheng 	freemsg(mp);
12028275SEric Cheng 	return (NULL);
12031256Syl150051 
12041256Syl150051 _exit:
12058275SEric Cheng 	ring->need_resched = B_TRUE;
12068275SEric Cheng 	return (mp);
12078275SEric Cheng }
12088275SEric Cheng 
12098275SEric Cheng /*
12108275SEric Cheng  * xgell_ring_macaddr_init
12118275SEric Cheng  */
12128275SEric Cheng static void
xgell_rx_ring_maddr_init(xgell_rx_ring_t * ring)12138275SEric Cheng xgell_rx_ring_maddr_init(xgell_rx_ring_t *ring)
12148275SEric Cheng {
12158275SEric Cheng 	int i;
12168275SEric Cheng 	xgelldev_t *lldev = ring->lldev;
12178275SEric Cheng 	xge_hal_device_t *hldev = lldev->devh;
12188275SEric Cheng 	int slot_start;
12198275SEric Cheng 
12208275SEric Cheng 	xge_debug_ll(XGE_TRACE, "%s", "xgell_rx_ring_maddr_init");
12218275SEric Cheng 
12228275SEric Cheng 	ring->mmac.naddr = XGE_RX_MULTI_MAC_ADDRESSES_MAX;
12238275SEric Cheng 	ring->mmac.naddrfree = ring->mmac.naddr;
12248275SEric Cheng 
12258275SEric Cheng 	/*
12268275SEric Cheng 	 * For the default rx ring, the first MAC address is the factory one.
12278275SEric Cheng 	 * This will be set by the framework, so need to clear it for now.
12288275SEric Cheng 	 */
12298275SEric Cheng 	(void) xge_hal_device_macaddr_clear(hldev, 0);
12308275SEric Cheng 
12318275SEric Cheng 	/*
12328275SEric Cheng 	 * Read the MAC address Configuration Memory from HAL.
12338275SEric Cheng 	 * The first slot will hold a factory MAC address, contents in other
12348275SEric Cheng 	 * slots will be FF:FF:FF:FF:FF:FF.
12358275SEric Cheng 	 */
12368275SEric Cheng 	slot_start = ring->index * 32;
12378275SEric Cheng 	for (i = 0; i < ring->mmac.naddr; i++) {
12388275SEric Cheng 		(void) xge_hal_device_macaddr_get(hldev, slot_start + i,
12398275SEric Cheng 		    ring->mmac.mac_addr + i);
12408275SEric Cheng 		ring->mmac.mac_addr_set[i] = B_FALSE;
12418275SEric Cheng 	}
12428275SEric Cheng }
12438275SEric Cheng 
12448275SEric Cheng static int xgell_maddr_set(xgelldev_t *, int, uint8_t *);
12458275SEric Cheng 
12468275SEric Cheng static int
xgell_addmac(void * arg,const uint8_t * mac_addr)12478275SEric Cheng xgell_addmac(void *arg, const uint8_t *mac_addr)
12488275SEric Cheng {
12498275SEric Cheng 	xgell_rx_ring_t *ring = arg;
12508275SEric Cheng 	xgelldev_t *lldev = ring->lldev;
12518275SEric Cheng 	xge_hal_device_t *hldev = lldev->devh;
12528275SEric Cheng 	int slot;
12538275SEric Cheng 	int slot_start;
12548275SEric Cheng 
12558275SEric Cheng 	xge_debug_ll(XGE_TRACE, "%s", "xgell_addmac");
12568275SEric Cheng 
12578275SEric Cheng 	mutex_enter(&lldev->genlock);
12588275SEric Cheng 
12598275SEric Cheng 	if (ring->mmac.naddrfree == 0) {
12608275SEric Cheng 		mutex_exit(&lldev->genlock);
12618275SEric Cheng 		return (ENOSPC);
12628275SEric Cheng 	}
12638275SEric Cheng 
12648275SEric Cheng 	/* First slot is for factory MAC address */
12658275SEric Cheng 	for (slot = 0; slot < ring->mmac.naddr; slot++) {
12668275SEric Cheng 		if (ring->mmac.mac_addr_set[slot] == B_FALSE) {
12678275SEric Cheng 			break;
12681256Syl150051 		}
12691256Syl150051 	}
12701256Syl150051 
12718275SEric Cheng 	ASSERT(slot < ring->mmac.naddr);
12728275SEric Cheng 
12738275SEric Cheng 	slot_start = ring->index * 32;
12748275SEric Cheng 
12758275SEric Cheng 	if (xgell_maddr_set(lldev, slot_start + slot, (uint8_t *)mac_addr) !=
12768275SEric Cheng 	    0) {
12778275SEric Cheng 		mutex_exit(&lldev->genlock);
12788275SEric Cheng 		return (EIO);
12798275SEric Cheng 	}
12808275SEric Cheng 
12818275SEric Cheng 	/* Simply enable RTS for the whole section. */
12828275SEric Cheng 	(void) xge_hal_device_rts_section_enable(hldev, slot_start + slot);
12838275SEric Cheng 
12848275SEric Cheng 	/*
12858275SEric Cheng 	 * Read back the MAC address from HAL to keep the array up to date.
12868275SEric Cheng 	 */
12878275SEric Cheng 	if (xge_hal_device_macaddr_get(hldev, slot_start + slot,
12888275SEric Cheng 	    ring->mmac.mac_addr + slot) != XGE_HAL_OK) {
12898275SEric Cheng 		(void) xge_hal_device_macaddr_clear(hldev, slot_start + slot);
12908275SEric Cheng 		return (EIO);
12918275SEric Cheng 	}
12928275SEric Cheng 
12938275SEric Cheng 	ring->mmac.mac_addr_set[slot] = B_TRUE;
12948275SEric Cheng 	ring->mmac.naddrfree--;
12958275SEric Cheng 
12968275SEric Cheng 	mutex_exit(&lldev->genlock);
12978275SEric Cheng 
12988275SEric Cheng 	return (0);
12998275SEric Cheng }
13008275SEric Cheng 
13018275SEric Cheng static int
xgell_remmac(void * arg,const uint8_t * mac_addr)13028275SEric Cheng xgell_remmac(void *arg, const uint8_t *mac_addr)
13038275SEric Cheng {
13048275SEric Cheng 	xgell_rx_ring_t *ring = arg;
13058275SEric Cheng 	xgelldev_t *lldev = ring->lldev;
13068275SEric Cheng 	xge_hal_device_t *hldev = lldev->devh;
13078275SEric Cheng 	xge_hal_status_e status;
13088275SEric Cheng 	int slot;
13098275SEric Cheng 	int slot_start;
13108275SEric Cheng 
13118275SEric Cheng 	xge_debug_ll(XGE_TRACE, "%s", "xgell_remmac");
13128275SEric Cheng 
13138275SEric Cheng 	slot = xge_hal_device_macaddr_find(hldev, (uint8_t *)mac_addr);
13148275SEric Cheng 	if (slot == -1)
13158275SEric Cheng 		return (EINVAL);
13168275SEric Cheng 
13178275SEric Cheng 	slot_start = ring->index * 32;
13188275SEric Cheng 
13198275SEric Cheng 	/*
13208275SEric Cheng 	 * Adjust slot to the offset in the MAC array of this ring (group).
13218275SEric Cheng 	 */
13228275SEric Cheng 	slot -= slot_start;
13238275SEric Cheng 
13248275SEric Cheng 	/*
13258275SEric Cheng 	 * Only can remove a pre-set MAC address for this ring (group).
13268275SEric Cheng 	 */
13278275SEric Cheng 	if (slot < 0 || slot >= ring->mmac.naddr)
13288275SEric Cheng 		return (EINVAL);
13298275SEric Cheng 
13308275SEric Cheng 
13318275SEric Cheng 	xge_assert(ring->mmac.mac_addr_set[slot]);
13328275SEric Cheng 
13338275SEric Cheng 	mutex_enter(&lldev->genlock);
13348275SEric Cheng 	if (!ring->mmac.mac_addr_set[slot]) {
13358275SEric Cheng 		mutex_exit(&lldev->genlock);
13368275SEric Cheng 		/*
13378275SEric Cheng 		 * The result will be unexpected when reach here. WARNING!
13388275SEric Cheng 		 */
13398275SEric Cheng 		xge_debug_ll(XGE_ERR,
13408275SEric Cheng 		    "%s%d: caller is trying to remove an unset MAC address",
13418275SEric Cheng 		    XGELL_IFNAME, lldev->instance);
13428275SEric Cheng 		return (ENXIO);
13438275SEric Cheng 	}
13448275SEric Cheng 
13458275SEric Cheng 	status = xge_hal_device_macaddr_clear(hldev, slot_start + slot);
13468275SEric Cheng 	if (status != XGE_HAL_OK) {
13478275SEric Cheng 		mutex_exit(&lldev->genlock);
13488275SEric Cheng 		return (EIO);
13498275SEric Cheng 	}
13508275SEric Cheng 
13518275SEric Cheng 	ring->mmac.mac_addr_set[slot] = B_FALSE;
13528275SEric Cheng 	ring->mmac.naddrfree++;
13538275SEric Cheng 
13548275SEric Cheng 	/*
13558275SEric Cheng 	 * TODO: Disable MAC RTS if all addresses have been cleared.
13568275SEric Cheng 	 */
13578275SEric Cheng 
13588275SEric Cheng 	/*
13598275SEric Cheng 	 * Read back the MAC address from HAL to keep the array up to date.
13608275SEric Cheng 	 */
13618275SEric Cheng 	(void) xge_hal_device_macaddr_get(hldev, slot_start + slot,
13628275SEric Cheng 	    ring->mmac.mac_addr + slot);
13638275SEric Cheng 	mutex_exit(&lldev->genlock);
13648275SEric Cheng 
13658275SEric Cheng 	return (0);
13661256Syl150051 }
13671256Syl150051 
13681256Syl150051 /*
13698275SEric Cheng  * Temporarily calling hal function.
13701256Syl150051  *
13718275SEric Cheng  * With MSI-X implementation, no lock is needed, so that the interrupt
13728275SEric Cheng  * handling could be faster.
13731256Syl150051  */
13748275SEric Cheng int
xgell_rx_ring_intr_enable(mac_intr_handle_t ih)13758275SEric Cheng xgell_rx_ring_intr_enable(mac_intr_handle_t ih)
13768275SEric Cheng {
13778275SEric Cheng 	xgell_rx_ring_t *ring = (xgell_rx_ring_t *)ih;
13788275SEric Cheng 
13798275SEric Cheng 	mutex_enter(&ring->ring_lock);
13808275SEric Cheng 	xge_hal_device_rx_channel_disable_polling(ring->channelh);
13818275SEric Cheng 	mutex_exit(&ring->ring_lock);
13828275SEric Cheng 
13838275SEric Cheng 	return (0);
13848275SEric Cheng }
13858275SEric Cheng 
13868275SEric Cheng int
xgell_rx_ring_intr_disable(mac_intr_handle_t ih)13878275SEric Cheng xgell_rx_ring_intr_disable(mac_intr_handle_t ih)
13888275SEric Cheng {
13898275SEric Cheng 	xgell_rx_ring_t *ring = (xgell_rx_ring_t *)ih;
13908275SEric Cheng 
13918275SEric Cheng 	mutex_enter(&ring->ring_lock);
13928275SEric Cheng 	xge_hal_device_rx_channel_enable_polling(ring->channelh);
13938275SEric Cheng 	mutex_exit(&ring->ring_lock);
13948275SEric Cheng 
13958275SEric Cheng 	return (0);
13968275SEric Cheng }
13978275SEric Cheng 
13988275SEric Cheng static int
xgell_rx_ring_start(mac_ring_driver_t rh,uint64_t mr_gen_num)13998275SEric Cheng xgell_rx_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
14008275SEric Cheng {
14018275SEric Cheng 	xgell_rx_ring_t *rx_ring = (xgell_rx_ring_t *)rh;
14028275SEric Cheng 
14038275SEric Cheng 	rx_ring->ring_gen_num = mr_gen_num;
14048275SEric Cheng 
14058275SEric Cheng 	return (0);
14068275SEric Cheng }
14078275SEric Cheng 
14088275SEric Cheng /*ARGSUSED*/
14098275SEric Cheng static void
xgell_rx_ring_stop(mac_ring_driver_t rh)14108275SEric Cheng xgell_rx_ring_stop(mac_ring_driver_t rh)
14118275SEric Cheng {
14128275SEric Cheng }
14138275SEric Cheng 
14148275SEric Cheng /*ARGSUSED*/
14158275SEric Cheng static int
xgell_tx_ring_start(mac_ring_driver_t rh,uint64_t useless)14168275SEric Cheng xgell_tx_ring_start(mac_ring_driver_t rh, uint64_t useless)
14178275SEric Cheng {
14188275SEric Cheng 	return (0);
14198275SEric Cheng }
14208275SEric Cheng 
14218275SEric Cheng /*ARGSUSED*/
14228275SEric Cheng static void
xgell_tx_ring_stop(mac_ring_driver_t rh)14238275SEric Cheng xgell_tx_ring_stop(mac_ring_driver_t rh)
14248275SEric Cheng {
14258275SEric Cheng }
14268275SEric Cheng 
14278275SEric Cheng /*
14288275SEric Cheng  * Callback funtion for MAC layer to register all rings.
14298275SEric Cheng  *
14308275SEric Cheng  * Xframe hardware doesn't support grouping explicitly, so the driver needs
14318275SEric Cheng  * to pretend having resource groups. We may also optionally group all 8 rx
14328275SEric Cheng  * rings into a single group for increased scalability on CMT architectures,
14338275SEric Cheng  * or group one rx ring per group for maximum virtualization.
14348275SEric Cheng  *
14358275SEric Cheng  * TX grouping is actually done by framework, so, just register all TX
14368275SEric Cheng  * resources without grouping them.
14378275SEric Cheng  */
14388275SEric Cheng void
xgell_fill_ring(void * arg,mac_ring_type_t rtype,const int rg_index,const int index,mac_ring_info_t * infop,mac_ring_handle_t rh)14398275SEric Cheng xgell_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index,
14408275SEric Cheng     const int index, mac_ring_info_t *infop, mac_ring_handle_t rh)
14411256Syl150051 {
14428275SEric Cheng 	xgelldev_t *lldev = (xgelldev_t *)arg;
14438275SEric Cheng 	mac_intr_t *mintr;
14448275SEric Cheng 
14458275SEric Cheng 	switch (rtype) {
14468275SEric Cheng 	case MAC_RING_TYPE_RX: {
14478275SEric Cheng 		xgell_rx_ring_t *rx_ring;
14488275SEric Cheng 
14498275SEric Cheng 		xge_assert(index < lldev->init_rx_rings);
14508275SEric Cheng 		xge_assert(rg_index < lldev->init_rx_groups);
14518275SEric Cheng 
14528275SEric Cheng 		/*
14538275SEric Cheng 		 * Performance vs. Virtualization
14548275SEric Cheng 		 */
14558275SEric Cheng 		if (lldev->init_rx_rings == lldev->init_rx_groups)
14568275SEric Cheng 			rx_ring = lldev->rx_ring + rg_index;
14578275SEric Cheng 		else
14588275SEric Cheng 			rx_ring = lldev->rx_ring + index;
14598275SEric Cheng 
14608275SEric Cheng 		rx_ring->ring_handle = rh;
14618275SEric Cheng 
14628275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)rx_ring;
14638275SEric Cheng 		infop->mri_start = xgell_rx_ring_start;
14648275SEric Cheng 		infop->mri_stop = xgell_rx_ring_stop;
14658275SEric Cheng 		infop->mri_poll = xgell_rx_poll;
1466*11878SVenu.Iyer@Sun.COM 		infop->mri_stat = xgell_rx_ring_stat;
14678275SEric Cheng 
14688275SEric Cheng 		mintr = &infop->mri_intr;
14698275SEric Cheng 		mintr->mi_handle = (mac_intr_handle_t)rx_ring;
14708275SEric Cheng 		mintr->mi_enable = xgell_rx_ring_intr_enable;
14718275SEric Cheng 		mintr->mi_disable = xgell_rx_ring_intr_disable;
14728275SEric Cheng 
14738275SEric Cheng 		break;
14748275SEric Cheng 	}
14758275SEric Cheng 	case MAC_RING_TYPE_TX: {
14768275SEric Cheng 		xgell_tx_ring_t *tx_ring;
14778275SEric Cheng 
14788275SEric Cheng 		xge_assert(rg_index == -1);
14798275SEric Cheng 
14808275SEric Cheng 		xge_assert((index >= 0) && (index < lldev->init_tx_rings));
14818275SEric Cheng 
14828275SEric Cheng 		tx_ring = lldev->tx_ring + index;
14838275SEric Cheng 		tx_ring->ring_handle = rh;
14848275SEric Cheng 
14858275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)tx_ring;
14868275SEric Cheng 		infop->mri_start = xgell_tx_ring_start;
14878275SEric Cheng 		infop->mri_stop = xgell_tx_ring_stop;
14888275SEric Cheng 		infop->mri_tx = xgell_ring_tx;
1489*11878SVenu.Iyer@Sun.COM 		infop->mri_stat = xgell_tx_ring_stat;
14908275SEric Cheng 
14918275SEric Cheng 		break;
14928275SEric Cheng 	}
14938275SEric Cheng 	default:
14948275SEric Cheng 		break;
14951256Syl150051 	}
14968275SEric Cheng }
14978275SEric Cheng 
14988275SEric Cheng void
xgell_fill_group(void * arg,mac_ring_type_t rtype,const int index,mac_group_info_t * infop,mac_group_handle_t gh)14998275SEric Cheng xgell_fill_group(void *arg, mac_ring_type_t rtype, const int index,
15008275SEric Cheng     mac_group_info_t *infop, mac_group_handle_t gh)
15018275SEric Cheng {
15028275SEric Cheng 	xgelldev_t *lldev = (xgelldev_t *)arg;
15038275SEric Cheng 
15048275SEric Cheng 	switch (rtype) {
15058275SEric Cheng 	case MAC_RING_TYPE_RX: {
15068275SEric Cheng 		xgell_rx_ring_t *rx_ring;
15078275SEric Cheng 
15088275SEric Cheng 		xge_assert(index < lldev->init_rx_groups);
15098275SEric Cheng 
15108275SEric Cheng 		rx_ring = lldev->rx_ring + index;
15118275SEric Cheng 
15128275SEric Cheng 		rx_ring->group_handle = gh;
15138275SEric Cheng 
15148275SEric Cheng 		infop->mgi_driver = (mac_group_driver_t)rx_ring;
15158275SEric Cheng 		infop->mgi_start = NULL;
15168275SEric Cheng 		infop->mgi_stop = NULL;
15178275SEric Cheng 		infop->mgi_addmac = xgell_addmac;
15188275SEric Cheng 		infop->mgi_remmac = xgell_remmac;
15198275SEric Cheng 		infop->mgi_count = lldev->init_rx_rings / lldev->init_rx_groups;
15208275SEric Cheng 
15218275SEric Cheng 		break;
15228275SEric Cheng 	}
15238275SEric Cheng 	case MAC_RING_TYPE_TX:
15248275SEric Cheng 		xge_assert(0);
15258275SEric Cheng 		break;
15268275SEric Cheng 	default:
15278275SEric Cheng 		break;
15288275SEric Cheng 	}
15298275SEric Cheng }
15308275SEric Cheng 
15318275SEric Cheng /*
15328275SEric Cheng  * xgell_macaddr_set
15338275SEric Cheng  */
15348275SEric Cheng static int
xgell_maddr_set(xgelldev_t * lldev,int index,uint8_t * macaddr)15358275SEric Cheng xgell_maddr_set(xgelldev_t *lldev, int index, uint8_t *macaddr)
15368275SEric Cheng {
15378275SEric Cheng 	xge_hal_device_t *hldev = lldev->devh;
15388275SEric Cheng 	xge_hal_status_e status;
15398275SEric Cheng 
15408275SEric Cheng 	xge_debug_ll(XGE_TRACE, "%s", "xgell_maddr_set");
15418275SEric Cheng 
15428275SEric Cheng 	xge_debug_ll(XGE_TRACE,
15438275SEric Cheng 	    "setting macaddr: 0x%02x-%02x-%02x-%02x-%02x-%02x",
15448275SEric Cheng 	    macaddr[0], macaddr[1], macaddr[2],
15458275SEric Cheng 	    macaddr[3], macaddr[4], macaddr[5]);
15468275SEric Cheng 
15478275SEric Cheng 	status = xge_hal_device_macaddr_set(hldev, index, (uchar_t *)macaddr);
15488275SEric Cheng 
15498275SEric Cheng 	if (status != XGE_HAL_OK) {
15508275SEric Cheng 		xge_debug_ll(XGE_ERR, "%s%d: can not set mac address",
15518275SEric Cheng 		    XGELL_IFNAME, lldev->instance);
15528275SEric Cheng 		return (EIO);
15538275SEric Cheng 	}
15548275SEric Cheng 
15558275SEric Cheng 	return (0);
15561256Syl150051 }
15571256Syl150051 
15581256Syl150051 /*
15591256Syl150051  * xgell_rx_dtr_term
15601256Syl150051  *
15611256Syl150051  * Function will be called by HAL to terminate all DTRs for
15621256Syl150051  * Ring(s) type of channels.
15631256Syl150051  */
15641256Syl150051 static void
xgell_rx_dtr_term(xge_hal_channel_h channelh,xge_hal_dtr_h dtrh,xge_hal_dtr_state_e state,void * userdata,xge_hal_channel_reopen_e reopen)15651256Syl150051 xgell_rx_dtr_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
15661256Syl150051     xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen)
15671256Syl150051 {
15681256Syl150051 	xgell_rxd_priv_t *rxd_priv =
15691256Syl150051 	    ((xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtrh));
15701256Syl150051 	xgell_rx_buffer_t *rx_buffer = rxd_priv->rx_buffer;
15711256Syl150051 
15721256Syl150051 	if (state == XGE_HAL_DTR_STATE_POSTED) {
15738275SEric Cheng 		xgell_rx_ring_t *ring = rx_buffer->ring;
15748275SEric Cheng 
15756937Sxw161283 		mutex_enter(&ring->bf_pool.pool_lock);
15761256Syl150051 		xge_hal_ring_dtr_free(channelh, dtrh);
15771256Syl150051 		xgell_rx_buffer_release(rx_buffer);
15786937Sxw161283 		mutex_exit(&ring->bf_pool.pool_lock);
15791256Syl150051 	}
15801256Syl150051 }
15811256Syl150051 
15821256Syl150051 /*
15838275SEric Cheng  * To open a rx ring.
15848275SEric Cheng  */
15858275SEric Cheng static boolean_t
xgell_rx_ring_open(xgell_rx_ring_t * rx_ring)15868275SEric Cheng xgell_rx_ring_open(xgell_rx_ring_t *rx_ring)
15878275SEric Cheng {
15888275SEric Cheng 	xge_hal_status_e status;
15898275SEric Cheng 	xge_hal_channel_attr_t attr;
15908275SEric Cheng 	xgelldev_t *lldev = rx_ring->lldev;
15918275SEric Cheng 	xge_hal_device_t *hldev = lldev->devh;
15928275SEric Cheng 
15938275SEric Cheng 	if (rx_ring->live)
15948275SEric Cheng 		return (B_TRUE);
15958275SEric Cheng 
15968275SEric Cheng 	/* Create the buffer pool first */
15978275SEric Cheng 	if (!xgell_rx_create_buffer_pool(rx_ring)) {
15988275SEric Cheng 		xge_debug_ll(XGE_ERR, "can not create buffer pool for ring: %d",
15998275SEric Cheng 		    rx_ring->index);
16008275SEric Cheng 		return (B_FALSE);
16018275SEric Cheng 	}
16028275SEric Cheng 
16038275SEric Cheng 	/* Default ring initialization */
16048275SEric Cheng 	attr.post_qid		= rx_ring->index;
16058275SEric Cheng 	attr.compl_qid		= 0;
16068275SEric Cheng 	attr.callback		= xgell_rx_1b_callback;
16078275SEric Cheng 	attr.per_dtr_space	= sizeof (xgell_rxd_priv_t);
16088275SEric Cheng 	attr.flags		= 0;
16098275SEric Cheng 	attr.type		= XGE_HAL_CHANNEL_TYPE_RING;
16108275SEric Cheng 	attr.dtr_init		= xgell_rx_dtr_replenish;
16118275SEric Cheng 	attr.dtr_term		= xgell_rx_dtr_term;
16128275SEric Cheng 	attr.userdata		= rx_ring;
16138275SEric Cheng 
16148275SEric Cheng 	status = xge_hal_channel_open(lldev->devh, &attr, &rx_ring->channelh,
16158275SEric Cheng 	    XGE_HAL_CHANNEL_OC_NORMAL);
16168275SEric Cheng 	if (status != XGE_HAL_OK) {
16178275SEric Cheng 		xge_debug_ll(XGE_ERR, "%s%d: cannot open Rx channel got status "
16188275SEric Cheng 		    " code %d", XGELL_IFNAME, lldev->instance, status);
16198275SEric Cheng 		(void) xgell_rx_destroy_buffer_pool(rx_ring);
16208275SEric Cheng 		return (B_FALSE);
16218275SEric Cheng 	}
16228275SEric Cheng 
16238275SEric Cheng 	xgell_rx_ring_maddr_init(rx_ring);
16248275SEric Cheng 
16258275SEric Cheng 	mutex_init(&rx_ring->ring_lock, NULL, MUTEX_DRIVER,
16268275SEric Cheng 	    DDI_INTR_PRI(hldev->irqh));
16278275SEric Cheng 
16288275SEric Cheng 	rx_ring->poll_bytes = -1;
16298275SEric Cheng 	rx_ring->polled_bytes = 0;
16308275SEric Cheng 	rx_ring->poll_mp = NULL;
16318275SEric Cheng 	rx_ring->live = B_TRUE;
16328275SEric Cheng 
16338275SEric Cheng 	xge_debug_ll(XGE_TRACE, "RX ring [%d] is opened successfully",
16348275SEric Cheng 	    rx_ring->index);
16358275SEric Cheng 
16368275SEric Cheng 	return (B_TRUE);
16378275SEric Cheng }
16388275SEric Cheng 
16398275SEric Cheng static void
xgell_rx_ring_close(xgell_rx_ring_t * rx_ring)16408275SEric Cheng xgell_rx_ring_close(xgell_rx_ring_t *rx_ring)
16418275SEric Cheng {
16428275SEric Cheng 	if (!rx_ring->live)
16438275SEric Cheng 		return;
16448275SEric Cheng 	xge_hal_channel_close(rx_ring->channelh, XGE_HAL_CHANNEL_OC_NORMAL);
16458275SEric Cheng 	rx_ring->channelh = NULL;
16468275SEric Cheng 	/* This may not clean up all used buffers, driver will handle it */
16478275SEric Cheng 	if (xgell_rx_destroy_buffer_pool(rx_ring))
16488275SEric Cheng 		rx_ring->live = B_FALSE;
16498275SEric Cheng 
16508275SEric Cheng 	mutex_destroy(&rx_ring->ring_lock);
16518275SEric Cheng }
16528275SEric Cheng 
16538275SEric Cheng /*
16548275SEric Cheng  * xgell_rx_open
16558275SEric Cheng  * @lldev: the link layer object
16568275SEric Cheng  *
16578275SEric Cheng  * Initialize and open all RX channels.
16588275SEric Cheng  */
16598275SEric Cheng static boolean_t
xgell_rx_open(xgelldev_t * lldev)16608275SEric Cheng xgell_rx_open(xgelldev_t *lldev)
16618275SEric Cheng {
16628275SEric Cheng 	xgell_rx_ring_t *rx_ring;
16638275SEric Cheng 	int i;
16648275SEric Cheng 
16658275SEric Cheng 	if (lldev->live_rx_rings != 0)
16668275SEric Cheng 		return (B_TRUE);
16678275SEric Cheng 
16688275SEric Cheng 	lldev->live_rx_rings = 0;
16698275SEric Cheng 
16708275SEric Cheng 	/*
16718275SEric Cheng 	 * Initialize all rings
16728275SEric Cheng 	 */
16738275SEric Cheng 	for (i = 0; i < lldev->init_rx_rings; i++) {
16748275SEric Cheng 		rx_ring = &lldev->rx_ring[i];
16758275SEric Cheng 		rx_ring->index = i;
16768275SEric Cheng 		rx_ring->lldev = lldev;
16778275SEric Cheng 		rx_ring->live = B_FALSE;
16788275SEric Cheng 
16798275SEric Cheng 		if (!xgell_rx_ring_open(rx_ring))
16808275SEric Cheng 			return (B_FALSE);
16818275SEric Cheng 
16828275SEric Cheng 		lldev->live_rx_rings++;
16838275SEric Cheng 	}
16848275SEric Cheng 
16858275SEric Cheng 	return (B_TRUE);
16868275SEric Cheng }
16878275SEric Cheng 
16888275SEric Cheng static void
xgell_rx_close(xgelldev_t * lldev)16898275SEric Cheng xgell_rx_close(xgelldev_t *lldev)
16908275SEric Cheng {
16918275SEric Cheng 	xgell_rx_ring_t *rx_ring;
16928275SEric Cheng 	int i;
16938275SEric Cheng 
16948275SEric Cheng 	if (lldev->live_rx_rings == 0)
16958275SEric Cheng 		return;
16968275SEric Cheng 
16978275SEric Cheng 	/*
16988275SEric Cheng 	 * Close all rx rings
16998275SEric Cheng 	 */
17008275SEric Cheng 	for (i = 0; i < lldev->init_rx_rings; i++) {
17018275SEric Cheng 		rx_ring = &lldev->rx_ring[i];
17028275SEric Cheng 
17038275SEric Cheng 		if (rx_ring->live) {
17048275SEric Cheng 			xgell_rx_ring_close(rx_ring);
17058275SEric Cheng 			lldev->live_rx_rings--;
17068275SEric Cheng 		}
17078275SEric Cheng 	}
17088275SEric Cheng 
17098275SEric Cheng 	xge_assert(lldev->live_rx_rings == 0);
17108275SEric Cheng }
17118275SEric Cheng 
17128275SEric Cheng /*
17131256Syl150051  * xgell_tx_term
17141256Syl150051  *
17151256Syl150051  * Function will be called by HAL to terminate all DTRs for
17161256Syl150051  * Fifo(s) type of channels.
17171256Syl150051  */
17181256Syl150051 static void
xgell_tx_term(xge_hal_channel_h channelh,xge_hal_dtr_h dtrh,xge_hal_dtr_state_e state,void * userdata,xge_hal_channel_reopen_e reopen)17191256Syl150051 xgell_tx_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
17201256Syl150051     xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen)
17211256Syl150051 {
17221256Syl150051 	xgell_txd_priv_t *txd_priv =
17231256Syl150051 	    ((xgell_txd_priv_t *)xge_hal_fifo_dtr_private(dtrh));
17241256Syl150051 	mblk_t *mp = txd_priv->mblk;
17251256Syl150051 	int i;
17263115Syl150051 
17271256Syl150051 	/*
17281256Syl150051 	 * for Tx we must clean up the DTR *only* if it has been
17291256Syl150051 	 * posted!
17301256Syl150051 	 */
17311256Syl150051 	if (state != XGE_HAL_DTR_STATE_POSTED) {
17321256Syl150051 		return;
17331256Syl150051 	}
17341256Syl150051 
17351256Syl150051 	for (i = 0; i < txd_priv->handle_cnt; i++) {
17361256Syl150051 		xge_assert(txd_priv->dma_handles[i]);
17371256Syl150051 		(void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
17381256Syl150051 		ddi_dma_free_handle(&txd_priv->dma_handles[i]);
17391256Syl150051 		txd_priv->dma_handles[i] = 0;
17401256Syl150051 	}
17411256Syl150051 
17421256Syl150051 	xge_hal_fifo_dtr_free(channelh, dtrh);
17431256Syl150051 
17446937Sxw161283 	if (mp) {
17456937Sxw161283 		txd_priv->mblk = NULL;
17466937Sxw161283 		freemsg(mp);
17476937Sxw161283 	}
17486937Sxw161283 }
17496937Sxw161283 
17508275SEric Cheng static boolean_t
xgell_tx_ring_open(xgell_tx_ring_t * tx_ring)17518275SEric Cheng xgell_tx_ring_open(xgell_tx_ring_t *tx_ring)
17526937Sxw161283 {
17538275SEric Cheng 	xge_hal_status_e status;
17548275SEric Cheng 	xge_hal_channel_attr_t attr;
17558275SEric Cheng 	xgelldev_t *lldev = tx_ring->lldev;
17568275SEric Cheng 
17578275SEric Cheng 	if (tx_ring->live)
17588275SEric Cheng 		return (B_TRUE);
17598275SEric Cheng 
17608275SEric Cheng 	attr.post_qid		= tx_ring->index;
17618275SEric Cheng 	attr.compl_qid		= 0;
17628275SEric Cheng 	attr.callback		= xgell_xmit_compl;
17638275SEric Cheng 	attr.per_dtr_space	= sizeof (xgell_txd_priv_t);
17648275SEric Cheng 	attr.flags		= 0;
17658275SEric Cheng 	attr.type		= XGE_HAL_CHANNEL_TYPE_FIFO;
17668275SEric Cheng 	attr.dtr_init		= NULL;
17678275SEric Cheng 	attr.dtr_term		= xgell_tx_term;
17688275SEric Cheng 	attr.userdata		= tx_ring;
17698275SEric Cheng 
17708275SEric Cheng 	status = xge_hal_channel_open(lldev->devh, &attr, &tx_ring->channelh,
17718275SEric Cheng 	    XGE_HAL_CHANNEL_OC_NORMAL);
17728275SEric Cheng 	if (status != XGE_HAL_OK) {
17738275SEric Cheng 		xge_debug_ll(XGE_ERR, "%s%d: cannot open Tx channel got status "
17748275SEric Cheng 		    "code %d", XGELL_IFNAME, lldev->instance, status);
17758275SEric Cheng 		return (B_FALSE);
17766937Sxw161283 	}
17778275SEric Cheng 
17788275SEric Cheng 	tx_ring->live = B_TRUE;
17798275SEric Cheng 
17808275SEric Cheng 	return (B_TRUE);
17818275SEric Cheng }
17828275SEric Cheng 
17838275SEric Cheng static void
xgell_tx_ring_close(xgell_tx_ring_t * tx_ring)17848275SEric Cheng xgell_tx_ring_close(xgell_tx_ring_t *tx_ring)
17858275SEric Cheng {
17868275SEric Cheng 	if (!tx_ring->live)
17878275SEric Cheng 		return;
17888275SEric Cheng 	xge_hal_channel_close(tx_ring->channelh, XGE_HAL_CHANNEL_OC_NORMAL);
17898275SEric Cheng 	tx_ring->live = B_FALSE;
17901256Syl150051 }
17911256Syl150051 
17921256Syl150051 /*
17931256Syl150051  * xgell_tx_open
17941256Syl150051  * @lldev: the link layer object
17951256Syl150051  *
17968275SEric Cheng  * Initialize and open all TX channels.
17971256Syl150051  */
17981256Syl150051 static boolean_t
xgell_tx_open(xgelldev_t * lldev)17991256Syl150051 xgell_tx_open(xgelldev_t *lldev)
18001256Syl150051 {
18018275SEric Cheng 	xgell_tx_ring_t *tx_ring;
18028275SEric Cheng 	int i;
18038275SEric Cheng 
18048275SEric Cheng 	if (lldev->live_tx_rings != 0)
18058275SEric Cheng 		return (B_TRUE);
18068275SEric Cheng 
18078275SEric Cheng 	lldev->live_tx_rings = 0;
18081256Syl150051 
18096937Sxw161283 	/*
18108275SEric Cheng 	 * Enable rings by reserve sequence to match the h/w sequences.
18116937Sxw161283 	 */
18128275SEric Cheng 	for (i = 0; i < lldev->init_tx_rings; i++) {
18138275SEric Cheng 		tx_ring = &lldev->tx_ring[i];
18148275SEric Cheng 		tx_ring->index = i;
18158275SEric Cheng 		tx_ring->lldev = lldev;
18168275SEric Cheng 		tx_ring->live = B_FALSE;
18178275SEric Cheng 
18188275SEric Cheng 		if (!xgell_tx_ring_open(tx_ring))
18196937Sxw161283 			return (B_FALSE);
18208275SEric Cheng 
18218275SEric Cheng 		lldev->live_tx_rings++;
18221256Syl150051 	}
18231256Syl150051 
18241256Syl150051 	return (B_TRUE);
18251256Syl150051 }
18261256Syl150051 
18276937Sxw161283 static void
xgell_tx_close(xgelldev_t * lldev)18288275SEric Cheng xgell_tx_close(xgelldev_t *lldev)
18296937Sxw161283 {
18308275SEric Cheng 	xgell_tx_ring_t *tx_ring;
18318275SEric Cheng 	int i;
18328275SEric Cheng 
18338275SEric Cheng 	if (lldev->live_tx_rings == 0)
18348275SEric Cheng 		return;
18351256Syl150051 
18366937Sxw161283 	/*
18378275SEric Cheng 	 * Enable rings by reserve sequence to match the h/w sequences.
18386937Sxw161283 	 */
18398275SEric Cheng 	for (i = 0; i < lldev->init_tx_rings; i++) {
18408275SEric Cheng 		tx_ring = &lldev->tx_ring[i];
18418275SEric Cheng 		if (tx_ring->live) {
18428275SEric Cheng 			xgell_tx_ring_close(tx_ring);
18438275SEric Cheng 			lldev->live_tx_rings--;
18446937Sxw161283 		}
18451256Syl150051 	}
18461256Syl150051 }
18471256Syl150051 
18481256Syl150051 static int
xgell_initiate_start(xgelldev_t * lldev)18491256Syl150051 xgell_initiate_start(xgelldev_t *lldev)
18501256Syl150051 {
18511256Syl150051 	xge_hal_status_e status;
18521256Syl150051 	xge_hal_device_t *hldev = lldev->devh;
18532311Sseb 	int maxpkt = hldev->config.mtu;
18541256Syl150051 
18551256Syl150051 	/* check initial mtu before enabling the device */
18561256Syl150051 	status = xge_hal_device_mtu_check(lldev->devh, maxpkt);
18571256Syl150051 	if (status != XGE_HAL_OK) {
18581256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: MTU size %d is invalid",
18591256Syl150051 		    XGELL_IFNAME, lldev->instance, maxpkt);
18601256Syl150051 		return (EINVAL);
18611256Syl150051 	}
18621256Syl150051 
18631256Syl150051 	/* set initial mtu before enabling the device */
18641256Syl150051 	status = xge_hal_device_mtu_set(lldev->devh, maxpkt);
18651256Syl150051 	if (status != XGE_HAL_OK) {
18661256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not set new MTU %d",
18671256Syl150051 		    XGELL_IFNAME, lldev->instance, maxpkt);
18681256Syl150051 		return (EIO);
18691256Syl150051 	}
18701256Syl150051 
18713115Syl150051 	/* tune jumbo/normal frame UFC counters */
18728275SEric Cheng 	hldev->config.ring.queue[XGELL_RX_RING_MAIN].rti.ufc_b =
18738275SEric Cheng 	    (maxpkt > XGE_HAL_DEFAULT_MTU) ?
18746937Sxw161283 	    XGE_HAL_DEFAULT_RX_UFC_B_J :
18756937Sxw161283 	    XGE_HAL_DEFAULT_RX_UFC_B_N;
18763115Syl150051 
18778275SEric Cheng 	hldev->config.ring.queue[XGELL_RX_RING_MAIN].rti.ufc_c =
18788275SEric Cheng 	    (maxpkt > XGE_HAL_DEFAULT_MTU) ?
18796937Sxw161283 	    XGE_HAL_DEFAULT_RX_UFC_C_J :
18806937Sxw161283 	    XGE_HAL_DEFAULT_RX_UFC_C_N;
18813115Syl150051 
18821256Syl150051 	/* now, enable the device */
18831256Syl150051 	status = xge_hal_device_enable(lldev->devh);
18841256Syl150051 	if (status != XGE_HAL_OK) {
18851256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not enable the device",
18861256Syl150051 		    XGELL_IFNAME, lldev->instance);
18871256Syl150051 		return (EIO);
18881256Syl150051 	}
18891256Syl150051 
18901256Syl150051 	if (!xgell_rx_open(lldev)) {
18911256Syl150051 		status = xge_hal_device_disable(lldev->devh);
18921256Syl150051 		if (status != XGE_HAL_OK) {
18931256Syl150051 			u64 adapter_status;
18941256Syl150051 			(void) xge_hal_device_status(lldev->devh,
18951256Syl150051 			    &adapter_status);
18961256Syl150051 			xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
18971256Syl150051 			    "the device. adaper status 0x%"PRIx64
18981256Syl150051 			    " returned status %d",
18991256Syl150051 			    XGELL_IFNAME, lldev->instance,
19001256Syl150051 			    (uint64_t)adapter_status, status);
19011256Syl150051 		}
19028275SEric Cheng 		xgell_rx_close(lldev);
19031256Syl150051 		xge_os_mdelay(1500);
19041256Syl150051 		return (ENOMEM);
19051256Syl150051 	}
19061256Syl150051 
19071256Syl150051 	if (!xgell_tx_open(lldev)) {
19081256Syl150051 		status = xge_hal_device_disable(lldev->devh);
19091256Syl150051 		if (status != XGE_HAL_OK) {
19101256Syl150051 			u64 adapter_status;
19111256Syl150051 			(void) xge_hal_device_status(lldev->devh,
19121256Syl150051 			    &adapter_status);
19131256Syl150051 			xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
19141256Syl150051 			    "the device. adaper status 0x%"PRIx64
19151256Syl150051 			    " returned status %d",
19161256Syl150051 			    XGELL_IFNAME, lldev->instance,
19171256Syl150051 			    (uint64_t)adapter_status, status);
19181256Syl150051 		}
19198275SEric Cheng 		xgell_tx_close(lldev);
19206937Sxw161283 		xgell_rx_close(lldev);
19218275SEric Cheng 		xge_os_mdelay(1500);
19221256Syl150051 		return (ENOMEM);
19231256Syl150051 	}
19241256Syl150051 
19251256Syl150051 	/* time to enable interrupts */
19266937Sxw161283 	(void) xge_enable_intrs(lldev);
19271256Syl150051 	xge_hal_device_intr_enable(lldev->devh);
19281256Syl150051 
19291256Syl150051 	lldev->is_initialized = 1;
19301256Syl150051 
19311256Syl150051 	return (0);
19321256Syl150051 }
19331256Syl150051 
19341256Syl150051 static void
xgell_initiate_stop(xgelldev_t * lldev)19351256Syl150051 xgell_initiate_stop(xgelldev_t *lldev)
19361256Syl150051 {
19371256Syl150051 	xge_hal_status_e status;
19381256Syl150051 
19391256Syl150051 	lldev->is_initialized = 0;
19401256Syl150051 
19411256Syl150051 	status = xge_hal_device_disable(lldev->devh);
19421256Syl150051 	if (status != XGE_HAL_OK) {
19431256Syl150051 		u64 adapter_status;
19441256Syl150051 		(void) xge_hal_device_status(lldev->devh, &adapter_status);
19451256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
19461256Syl150051 		    "the device. adaper status 0x%"PRIx64" returned status %d",
19471256Syl150051 		    XGELL_IFNAME, lldev->instance,
19481256Syl150051 		    (uint64_t)adapter_status, status);
19491256Syl150051 	}
19501256Syl150051 	xge_hal_device_intr_disable(lldev->devh);
19516937Sxw161283 	/* disable OS ISR's */
19526937Sxw161283 	xge_disable_intrs(lldev);
19531256Syl150051 
19541256Syl150051 	xge_debug_ll(XGE_TRACE, "%s",
19551256Syl150051 	    "waiting for device irq to become quiescent...");
19561256Syl150051 	xge_os_mdelay(1500);
19571256Syl150051 
19581256Syl150051 	xge_queue_flush(xge_hal_device_queue(lldev->devh));
19591256Syl150051 
19606937Sxw161283 	xgell_rx_close(lldev);
19616937Sxw161283 	xgell_tx_close(lldev);
19621256Syl150051 }
19631256Syl150051 
19641256Syl150051 /*
19651256Syl150051  * xgell_m_start
19661256Syl150051  * @arg: pointer to device private strucutre(hldev)
19671256Syl150051  *
19681256Syl150051  * This function is called by MAC Layer to enable the XFRAME
19691256Syl150051  * firmware to generate interrupts and also prepare the
19701256Syl150051  * driver to call mac_rx for delivering receive packets
19711256Syl150051  * to MAC Layer.
19721256Syl150051  */
19731256Syl150051 static int
xgell_m_start(void * arg)19741256Syl150051 xgell_m_start(void *arg)
19751256Syl150051 {
19763115Syl150051 	xgelldev_t *lldev = arg;
19773115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
19781256Syl150051 	int ret;
19791256Syl150051 
19801256Syl150051 	xge_debug_ll(XGE_TRACE, "%s%d: M_START", XGELL_IFNAME,
19811256Syl150051 	    lldev->instance);
19821256Syl150051 
19831256Syl150051 	mutex_enter(&lldev->genlock);
19841256Syl150051 
19851256Syl150051 	if (lldev->is_initialized) {
19861256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: device is already initialized",
19871256Syl150051 		    XGELL_IFNAME, lldev->instance);
19881256Syl150051 		mutex_exit(&lldev->genlock);
19891256Syl150051 		return (EINVAL);
19901256Syl150051 	}
19911256Syl150051 
19921256Syl150051 	hldev->terminating = 0;
19931256Syl150051 	if (ret = xgell_initiate_start(lldev)) {
19941256Syl150051 		mutex_exit(&lldev->genlock);
19951256Syl150051 		return (ret);
19961256Syl150051 	}
19971256Syl150051 
19981256Syl150051 	lldev->timeout_id = timeout(xge_device_poll, hldev, XGE_DEV_POLL_TICKS);
19991256Syl150051 
20001256Syl150051 	mutex_exit(&lldev->genlock);
20011256Syl150051 
20021256Syl150051 	return (0);
20031256Syl150051 }
20041256Syl150051 
20051256Syl150051 /*
20061256Syl150051  * xgell_m_stop
20071256Syl150051  * @arg: pointer to device private data (hldev)
20081256Syl150051  *
20091256Syl150051  * This function is called by the MAC Layer to disable
20101256Syl150051  * the XFRAME firmware for generating any interrupts and
20111256Syl150051  * also stop the driver from calling mac_rx() for
20121256Syl150051  * delivering data packets to the MAC Layer.
20131256Syl150051  */
20141256Syl150051 static void
xgell_m_stop(void * arg)20151256Syl150051 xgell_m_stop(void *arg)
20161256Syl150051 {
20173115Syl150051 	xgelldev_t *lldev = arg;
20183115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
20191256Syl150051 
20201256Syl150051 	xge_debug_ll(XGE_TRACE, "%s", "MAC_STOP");
20211256Syl150051 
20221256Syl150051 	mutex_enter(&lldev->genlock);
20231256Syl150051 	if (!lldev->is_initialized) {
20241256Syl150051 		xge_debug_ll(XGE_ERR, "%s", "device is not initialized...");
20251256Syl150051 		mutex_exit(&lldev->genlock);
20261256Syl150051 		return;
20271256Syl150051 	}
20281256Syl150051 
20291256Syl150051 	xge_hal_device_terminating(hldev);
20301256Syl150051 	xgell_initiate_stop(lldev);
20311256Syl150051 
20321256Syl150051 	/* reset device */
20331256Syl150051 	(void) xge_hal_device_reset(lldev->devh);
20341256Syl150051 
20351256Syl150051 	mutex_exit(&lldev->genlock);
20361256Syl150051 
20373115Syl150051 	if (lldev->timeout_id != 0) {
20383115Syl150051 		(void) untimeout(lldev->timeout_id);
20393115Syl150051 	}
20401256Syl150051 
20411256Syl150051 	xge_debug_ll(XGE_TRACE, "%s", "returning back to MAC Layer...");
20421256Syl150051 }
20431256Syl150051 
20441256Syl150051 /*
20451256Syl150051  * xgell_onerr_reset
20461256Syl150051  * @lldev: pointer to xgelldev_t structure
20471256Syl150051  *
20481256Syl150051  * This function is called by HAL Event framework to reset the HW
20491256Syl150051  * This function is must be called with genlock taken.
20501256Syl150051  */
20511256Syl150051 int
xgell_onerr_reset(xgelldev_t * lldev)20521256Syl150051 xgell_onerr_reset(xgelldev_t *lldev)
20531256Syl150051 {
20541256Syl150051 	int rc = 0;
20551256Syl150051 
20561256Syl150051 	if (!lldev->is_initialized) {
20571256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not reset",
20581256Syl150051 		    XGELL_IFNAME, lldev->instance);
20591256Syl150051 		return (rc);
20601256Syl150051 	}
20611256Syl150051 
20621256Syl150051 	lldev->in_reset = 1;
20631256Syl150051 	xgell_initiate_stop(lldev);
20641256Syl150051 
20651256Syl150051 	/* reset device */
20661256Syl150051 	(void) xge_hal_device_reset(lldev->devh);
20671256Syl150051 
20681256Syl150051 	rc = xgell_initiate_start(lldev);
20691256Syl150051 	lldev->in_reset = 0;
20701256Syl150051 
20711256Syl150051 	return (rc);
20721256Syl150051 }
20731256Syl150051 
20741256Syl150051 /*
20751256Syl150051  * xgell_m_multicst
20761256Syl150051  * @arg: pointer to device private strucutre(hldev)
20771256Syl150051  * @add:
20781256Syl150051  * @mc_addr:
20791256Syl150051  *
20801256Syl150051  * This function is called by MAC Layer to enable or
20811256Syl150051  * disable device-level reception of specific multicast addresses.
20821256Syl150051  */
20831256Syl150051 static int
xgell_m_multicst(void * arg,boolean_t add,const uint8_t * mc_addr)20841256Syl150051 xgell_m_multicst(void *arg, boolean_t add, const uint8_t *mc_addr)
20851256Syl150051 {
20861256Syl150051 	xge_hal_status_e status;
20873115Syl150051 	xgelldev_t *lldev = (xgelldev_t *)arg;
20883115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
20891256Syl150051 
20901256Syl150051 	xge_debug_ll(XGE_TRACE, "M_MULTICAST add %d", add);
20911256Syl150051 
20921256Syl150051 	mutex_enter(&lldev->genlock);
20931256Syl150051 
20941256Syl150051 	if (!lldev->is_initialized) {
20951256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not set multicast",
20961256Syl150051 		    XGELL_IFNAME, lldev->instance);
20971256Syl150051 		mutex_exit(&lldev->genlock);
20981256Syl150051 		return (EIO);
20991256Syl150051 	}
21001256Syl150051 
21011256Syl150051 	/* FIXME: missing HAL functionality: enable_one() */
21021256Syl150051 
21031256Syl150051 	status = (add) ?
21041256Syl150051 	    xge_hal_device_mcast_enable(hldev) :
21051256Syl150051 	    xge_hal_device_mcast_disable(hldev);
21061256Syl150051 
21071256Syl150051 	if (status != XGE_HAL_OK) {
21081256Syl150051 		xge_debug_ll(XGE_ERR, "failed to %s multicast, status %d",
21091256Syl150051 		    add ? "enable" : "disable", status);
21101256Syl150051 		mutex_exit(&lldev->genlock);
21111256Syl150051 		return (EIO);
21121256Syl150051 	}
21131256Syl150051 
21141256Syl150051 	mutex_exit(&lldev->genlock);
21151256Syl150051 
21161256Syl150051 	return (0);
21171256Syl150051 }
21181256Syl150051 
21191256Syl150051 
21201256Syl150051 /*
21211256Syl150051  * xgell_m_promisc
21221256Syl150051  * @arg: pointer to device private strucutre(hldev)
21231256Syl150051  * @on:
21241256Syl150051  *
21251256Syl150051  * This function is called by MAC Layer to enable or
21261256Syl150051  * disable the reception of all the packets on the medium
21271256Syl150051  */
21281256Syl150051 static int
xgell_m_promisc(void * arg,boolean_t on)21291256Syl150051 xgell_m_promisc(void *arg, boolean_t on)
21301256Syl150051 {
21313115Syl150051 	xgelldev_t *lldev = (xgelldev_t *)arg;
21323115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
21331256Syl150051 
21341256Syl150051 	mutex_enter(&lldev->genlock);
21351256Syl150051 
21361256Syl150051 	xge_debug_ll(XGE_TRACE, "%s", "MAC_PROMISC_SET");
21371256Syl150051 
21381256Syl150051 	if (!lldev->is_initialized) {
21391256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not set promiscuous",
21401256Syl150051 		    XGELL_IFNAME, lldev->instance);
21411256Syl150051 		mutex_exit(&lldev->genlock);
21421256Syl150051 		return (EIO);
21431256Syl150051 	}
21441256Syl150051 
21451256Syl150051 	if (on) {
21461256Syl150051 		xge_hal_device_promisc_enable(hldev);
21471256Syl150051 	} else {
21481256Syl150051 		xge_hal_device_promisc_disable(hldev);
21491256Syl150051 	}
21501256Syl150051 
21511256Syl150051 	mutex_exit(&lldev->genlock);
21521256Syl150051 
21531256Syl150051 	return (0);
21541256Syl150051 }
21551256Syl150051 
21561256Syl150051 /*
21572311Sseb  * xgell_m_stat
21581256Syl150051  * @arg: pointer to device private strucutre(hldev)
21591256Syl150051  *
21602311Sseb  * This function is called by MAC Layer to get network statistics
21611256Syl150051  * from the driver.
21621256Syl150051  */
21632311Sseb static int
xgell_m_stat(void * arg,uint_t stat,uint64_t * val)21642311Sseb xgell_m_stat(void *arg, uint_t stat, uint64_t *val)
21651256Syl150051 {
21661256Syl150051 	xge_hal_stats_hw_info_t *hw_info;
21673115Syl150051 	xgelldev_t *lldev = (xgelldev_t *)arg;
21683115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
21691256Syl150051 
21701256Syl150051 	xge_debug_ll(XGE_TRACE, "%s", "MAC_STATS_GET");
21711256Syl150051 
21726937Sxw161283 	mutex_enter(&lldev->genlock);
21731256Syl150051 
21741256Syl150051 	if (!lldev->is_initialized) {
21751256Syl150051 		mutex_exit(&lldev->genlock);
21762311Sseb 		return (EAGAIN);
21771256Syl150051 	}
21781256Syl150051 
21791256Syl150051 	if (xge_hal_stats_hw(hldev, &hw_info) != XGE_HAL_OK) {
21801256Syl150051 		mutex_exit(&lldev->genlock);
21812311Sseb 		return (EAGAIN);
21821256Syl150051 	}
21831256Syl150051 
21841256Syl150051 	switch (stat) {
21851256Syl150051 	case MAC_STAT_IFSPEED:
21862311Sseb 		*val = 10000000000ull; /* 10G */
21871256Syl150051 		break;
21881256Syl150051 
21891256Syl150051 	case MAC_STAT_MULTIRCV:
21903115Syl150051 		*val = ((u64) hw_info->rmac_vld_mcst_frms_oflow << 32) |
21913115Syl150051 		    hw_info->rmac_vld_mcst_frms;
21921256Syl150051 		break;
21931256Syl150051 
21941256Syl150051 	case MAC_STAT_BRDCSTRCV:
21953115Syl150051 		*val = ((u64) hw_info->rmac_vld_bcst_frms_oflow << 32) |
21963115Syl150051 		    hw_info->rmac_vld_bcst_frms;
21971256Syl150051 		break;
21981256Syl150051 
21991256Syl150051 	case MAC_STAT_MULTIXMT:
22003115Syl150051 		*val = ((u64) hw_info->tmac_mcst_frms_oflow << 32) |
22013115Syl150051 		    hw_info->tmac_mcst_frms;
22021256Syl150051 		break;
22031256Syl150051 
22041256Syl150051 	case MAC_STAT_BRDCSTXMT:
22053115Syl150051 		*val = ((u64) hw_info->tmac_bcst_frms_oflow << 32) |
22063115Syl150051 		    hw_info->tmac_bcst_frms;
22071256Syl150051 		break;
22081256Syl150051 
22091256Syl150051 	case MAC_STAT_RBYTES:
22103115Syl150051 		*val = ((u64) hw_info->rmac_ttl_octets_oflow << 32) |
22113115Syl150051 		    hw_info->rmac_ttl_octets;
22121256Syl150051 		break;
22131256Syl150051 
22141256Syl150051 	case MAC_STAT_NORCVBUF:
22152311Sseb 		*val = hw_info->rmac_drop_frms;
22161256Syl150051 		break;
22171256Syl150051 
22181256Syl150051 	case MAC_STAT_IERRORS:
22193115Syl150051 		*val = ((u64) hw_info->rmac_discarded_frms_oflow << 32) |
22203115Syl150051 		    hw_info->rmac_discarded_frms;
22211256Syl150051 		break;
22221256Syl150051 
22231256Syl150051 	case MAC_STAT_OBYTES:
22243115Syl150051 		*val = ((u64) hw_info->tmac_ttl_octets_oflow << 32) |
22253115Syl150051 		    hw_info->tmac_ttl_octets;
22261256Syl150051 		break;
22271256Syl150051 
22281256Syl150051 	case MAC_STAT_NOXMTBUF:
22292311Sseb 		*val = hw_info->tmac_drop_frms;
22301256Syl150051 		break;
22311256Syl150051 
22321256Syl150051 	case MAC_STAT_OERRORS:
22333115Syl150051 		*val = ((u64) hw_info->tmac_any_err_frms_oflow << 32) |
22343115Syl150051 		    hw_info->tmac_any_err_frms;
22351256Syl150051 		break;
22361256Syl150051 
22371256Syl150051 	case MAC_STAT_IPACKETS:
22383115Syl150051 		*val = ((u64) hw_info->rmac_vld_frms_oflow << 32) |
22393115Syl150051 		    hw_info->rmac_vld_frms;
22401256Syl150051 		break;
22411256Syl150051 
22421256Syl150051 	case MAC_STAT_OPACKETS:
22433115Syl150051 		*val = ((u64) hw_info->tmac_frms_oflow << 32) |
22443115Syl150051 		    hw_info->tmac_frms;
22452311Sseb 		break;
22462311Sseb 
22472311Sseb 	case ETHER_STAT_FCS_ERRORS:
22482311Sseb 		*val = hw_info->rmac_fcs_err_frms;
22491256Syl150051 		break;
22501256Syl150051 
22512311Sseb 	case ETHER_STAT_TOOLONG_ERRORS:
22522311Sseb 		*val = hw_info->rmac_long_frms;
22531256Syl150051 		break;
22541256Syl150051 
22552311Sseb 	case ETHER_STAT_LINK_DUPLEX:
22562311Sseb 		*val = LINK_DUPLEX_FULL;
22571256Syl150051 		break;
22581256Syl150051 
22591256Syl150051 	default:
22602311Sseb 		mutex_exit(&lldev->genlock);
22612311Sseb 		return (ENOTSUP);
22621256Syl150051 	}
22631256Syl150051 
22641256Syl150051 	mutex_exit(&lldev->genlock);
22651256Syl150051 
22662311Sseb 	return (0);
22671256Syl150051 }
22681256Syl150051 
22691256Syl150051 /*
2270*11878SVenu.Iyer@Sun.COM  * Retrieve a value for one of the statistics for a particular rx ring
2271*11878SVenu.Iyer@Sun.COM  */
2272*11878SVenu.Iyer@Sun.COM int
xgell_rx_ring_stat(mac_ring_driver_t rh,uint_t stat,uint64_t * val)2273*11878SVenu.Iyer@Sun.COM xgell_rx_ring_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
2274*11878SVenu.Iyer@Sun.COM {
2275*11878SVenu.Iyer@Sun.COM 	xgell_rx_ring_t	*rx_ring = (xgell_rx_ring_t *)rh;
2276*11878SVenu.Iyer@Sun.COM 
2277*11878SVenu.Iyer@Sun.COM 	switch (stat) {
2278*11878SVenu.Iyer@Sun.COM 	case MAC_STAT_RBYTES:
2279*11878SVenu.Iyer@Sun.COM 		*val = rx_ring->rx_bytes;
2280*11878SVenu.Iyer@Sun.COM 		break;
2281*11878SVenu.Iyer@Sun.COM 
2282*11878SVenu.Iyer@Sun.COM 	case MAC_STAT_IPACKETS:
2283*11878SVenu.Iyer@Sun.COM 		*val = rx_ring->rx_pkts;
2284*11878SVenu.Iyer@Sun.COM 		break;
2285*11878SVenu.Iyer@Sun.COM 
2286*11878SVenu.Iyer@Sun.COM 	default:
2287*11878SVenu.Iyer@Sun.COM 		*val = 0;
2288*11878SVenu.Iyer@Sun.COM 		return (ENOTSUP);
2289*11878SVenu.Iyer@Sun.COM 	}
2290*11878SVenu.Iyer@Sun.COM 
2291*11878SVenu.Iyer@Sun.COM 	return (0);
2292*11878SVenu.Iyer@Sun.COM }
2293*11878SVenu.Iyer@Sun.COM 
2294*11878SVenu.Iyer@Sun.COM /*
2295*11878SVenu.Iyer@Sun.COM  * Retrieve a value for one of the statistics for a particular tx ring
2296*11878SVenu.Iyer@Sun.COM  */
2297*11878SVenu.Iyer@Sun.COM int
xgell_tx_ring_stat(mac_ring_driver_t rh,uint_t stat,uint64_t * val)2298*11878SVenu.Iyer@Sun.COM xgell_tx_ring_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
2299*11878SVenu.Iyer@Sun.COM {
2300*11878SVenu.Iyer@Sun.COM 	xgell_tx_ring_t	*tx_ring = (xgell_tx_ring_t *)rh;
2301*11878SVenu.Iyer@Sun.COM 
2302*11878SVenu.Iyer@Sun.COM 	switch (stat) {
2303*11878SVenu.Iyer@Sun.COM 	case MAC_STAT_OBYTES:
2304*11878SVenu.Iyer@Sun.COM 		*val = tx_ring->tx_bytes;
2305*11878SVenu.Iyer@Sun.COM 		break;
2306*11878SVenu.Iyer@Sun.COM 
2307*11878SVenu.Iyer@Sun.COM 	case MAC_STAT_OPACKETS:
2308*11878SVenu.Iyer@Sun.COM 		*val = tx_ring->tx_pkts;
2309*11878SVenu.Iyer@Sun.COM 		break;
2310*11878SVenu.Iyer@Sun.COM 
2311*11878SVenu.Iyer@Sun.COM 	default:
2312*11878SVenu.Iyer@Sun.COM 		*val = 0;
2313*11878SVenu.Iyer@Sun.COM 		return (ENOTSUP);
2314*11878SVenu.Iyer@Sun.COM 	}
2315*11878SVenu.Iyer@Sun.COM 
2316*11878SVenu.Iyer@Sun.COM 	return (0);
2317*11878SVenu.Iyer@Sun.COM }
2318*11878SVenu.Iyer@Sun.COM 
2319*11878SVenu.Iyer@Sun.COM /*
23201256Syl150051  * xgell_device_alloc - Allocate new LL device
23211256Syl150051  */
23221256Syl150051 int
xgell_device_alloc(xge_hal_device_h devh,dev_info_t * dev_info,xgelldev_t ** lldev_out)23231256Syl150051 xgell_device_alloc(xge_hal_device_h devh,
23241256Syl150051     dev_info_t *dev_info, xgelldev_t **lldev_out)
23251256Syl150051 {
23261256Syl150051 	xgelldev_t *lldev;
23271256Syl150051 	xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
23281256Syl150051 	int instance = ddi_get_instance(dev_info);
23291256Syl150051 
23301256Syl150051 	*lldev_out = NULL;
23311256Syl150051 
23321256Syl150051 	xge_debug_ll(XGE_TRACE, "trying to register etherenet device %s%d...",
23331256Syl150051 	    XGELL_IFNAME, instance);
23341256Syl150051 
23351256Syl150051 	lldev = kmem_zalloc(sizeof (xgelldev_t), KM_SLEEP);
23361256Syl150051 
23371256Syl150051 	lldev->devh = hldev;
23381256Syl150051 	lldev->instance = instance;
23391256Syl150051 	lldev->dev_info = dev_info;
23401256Syl150051 
23411256Syl150051 	*lldev_out = lldev;
23421256Syl150051 
23431256Syl150051 	ddi_set_driver_private(dev_info, (caddr_t)hldev);
23441256Syl150051 
23451256Syl150051 	return (DDI_SUCCESS);
23461256Syl150051 }
23471256Syl150051 
23481256Syl150051 /*
23491256Syl150051  * xgell_device_free
23501256Syl150051  */
23511256Syl150051 void
xgell_device_free(xgelldev_t * lldev)23521256Syl150051 xgell_device_free(xgelldev_t *lldev)
23531256Syl150051 {
23541256Syl150051 	xge_debug_ll(XGE_TRACE, "freeing device %s%d",
23551256Syl150051 	    XGELL_IFNAME, lldev->instance);
23561256Syl150051 
23571256Syl150051 	kmem_free(lldev, sizeof (xgelldev_t));
23581256Syl150051 }
23591256Syl150051 
23601256Syl150051 /*
23611256Syl150051  * xgell_ioctl
23621256Syl150051  */
23631256Syl150051 static void
xgell_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)23641256Syl150051 xgell_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
23651256Syl150051 {
23663115Syl150051 	xgelldev_t *lldev = arg;
23671256Syl150051 	struct iocblk *iocp;
23681256Syl150051 	int err = 0;
23691256Syl150051 	int cmd;
23701256Syl150051 	int need_privilege = 1;
23711256Syl150051 	int ret = 0;
23721256Syl150051 
23731256Syl150051 
23741256Syl150051 	iocp = (struct iocblk *)mp->b_rptr;
23751256Syl150051 	iocp->ioc_error = 0;
23761256Syl150051 	cmd = iocp->ioc_cmd;
23771256Syl150051 	xge_debug_ll(XGE_TRACE, "MAC_IOCTL cmd 0x%x", cmd);
23781256Syl150051 	switch (cmd) {
23791256Syl150051 	case ND_GET:
23801256Syl150051 		need_privilege = 0;
23811256Syl150051 		/* FALLTHRU */
23821256Syl150051 	case ND_SET:
23831256Syl150051 		break;
23841256Syl150051 	default:
23851256Syl150051 		xge_debug_ll(XGE_TRACE, "unknown cmd 0x%x", cmd);
23861256Syl150051 		miocnak(wq, mp, 0, EINVAL);
23871256Syl150051 		return;
23881256Syl150051 	}
23891256Syl150051 
23901256Syl150051 	if (need_privilege) {
23911256Syl150051 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
23921256Syl150051 		if (err != 0) {
23931256Syl150051 			xge_debug_ll(XGE_ERR,
23941256Syl150051 			    "drv_priv(): rejected cmd 0x%x, err %d",
23951256Syl150051 			    cmd, err);
23961256Syl150051 			miocnak(wq, mp, 0, err);
23971256Syl150051 			return;
23981256Syl150051 		}
23991256Syl150051 	}
24001256Syl150051 
24011256Syl150051 	switch (cmd) {
24021256Syl150051 	case ND_GET:
24031256Syl150051 		/*
24041256Syl150051 		 * If nd_getset() returns B_FALSE, the command was
24051256Syl150051 		 * not valid (e.g. unknown name), so we just tell the
24061256Syl150051 		 * top-level ioctl code to send a NAK (with code EINVAL).
24071256Syl150051 		 *
24081256Syl150051 		 * Otherwise, nd_getset() will have built the reply to
24091256Syl150051 		 * be sent (but not actually sent it), so we tell the
24101256Syl150051 		 * caller to send the prepared reply.
24111256Syl150051 		 */
24121256Syl150051 		ret = nd_getset(wq, lldev->ndp, mp);
24136937Sxw161283 		xge_debug_ll(XGE_TRACE, "%s", "got ndd get ioctl");
24141256Syl150051 		break;
24151256Syl150051 
24161256Syl150051 	case ND_SET:
24171256Syl150051 		ret = nd_getset(wq, lldev->ndp, mp);
24186937Sxw161283 		xge_debug_ll(XGE_TRACE, "%s", "got ndd set ioctl");
24191256Syl150051 		break;
24201256Syl150051 
24211256Syl150051 	default:
24221256Syl150051 		break;
24231256Syl150051 	}
24241256Syl150051 
24251256Syl150051 	if (ret == B_FALSE) {
24261256Syl150051 		xge_debug_ll(XGE_ERR,
24271256Syl150051 		    "nd_getset(): rejected cmd 0x%x, err %d",
24281256Syl150051 		    cmd, err);
24291256Syl150051 		miocnak(wq, mp, 0, EINVAL);
24301256Syl150051 	} else {
24311256Syl150051 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
24321256Syl150051 		    M_IOCACK : M_IOCNAK;
24331256Syl150051 		qreply(wq, mp);
24341256Syl150051 	}
24351256Syl150051 }
24361256Syl150051 
24378275SEric Cheng 
24382311Sseb static boolean_t
xgell_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)24392311Sseb xgell_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
24401256Syl150051 {
24413115Syl150051 	xgelldev_t *lldev = arg;
24423115Syl150051 
24438275SEric Cheng 	xge_debug_ll(XGE_TRACE, "xgell_m_getcapab: %x", cap);
24448275SEric Cheng 
24452311Sseb 	switch (cap) {
24462311Sseb 	case MAC_CAPAB_HCKSUM: {
24472311Sseb 		uint32_t *hcksum_txflags = cap_data;
24482311Sseb 		*hcksum_txflags = HCKSUM_INET_FULL_V4 | HCKSUM_INET_FULL_V6 |
24492311Sseb 		    HCKSUM_IPHDRCKSUM;
24502311Sseb 		break;
24512311Sseb 	}
24523115Syl150051 	case MAC_CAPAB_LSO: {
24533115Syl150051 		mac_capab_lso_t *cap_lso = cap_data;
24543115Syl150051 
24553115Syl150051 		if (lldev->config.lso_enable) {
24563115Syl150051 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
24573115Syl150051 			cap_lso->lso_basic_tcp_ipv4.lso_max = XGELL_LSO_MAXLEN;
24583115Syl150051 			break;
24593115Syl150051 		} else {
24603115Syl150051 			return (B_FALSE);
24613115Syl150051 		}
24623115Syl150051 	}
24638275SEric Cheng 	case MAC_CAPAB_RINGS: {
24648275SEric Cheng 		mac_capab_rings_t *cap_rings = cap_data;
24658275SEric Cheng 
24668275SEric Cheng 		switch (cap_rings->mr_type) {
24678275SEric Cheng 		case MAC_RING_TYPE_RX:
24688275SEric Cheng 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
24698275SEric Cheng 			cap_rings->mr_rnum = lldev->init_rx_rings;
24708275SEric Cheng 			cap_rings->mr_gnum = lldev->init_rx_groups;
24718275SEric Cheng 			cap_rings->mr_rget = xgell_fill_ring;
24728275SEric Cheng 			cap_rings->mr_gget = xgell_fill_group;
24738275SEric Cheng 			break;
24748275SEric Cheng 		case MAC_RING_TYPE_TX:
24758275SEric Cheng 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
24768275SEric Cheng 			cap_rings->mr_rnum = lldev->init_tx_rings;
24778275SEric Cheng 			cap_rings->mr_gnum = 0;
24788275SEric Cheng 			cap_rings->mr_rget = xgell_fill_ring;
24798275SEric Cheng 			cap_rings->mr_gget = NULL;
24808275SEric Cheng 			break;
24818275SEric Cheng 		default:
24828275SEric Cheng 			break;
24838275SEric Cheng 		}
24848275SEric Cheng 		break;
24858275SEric Cheng 	}
24862311Sseb 	default:
24872311Sseb 		return (B_FALSE);
24882311Sseb 	}
24892311Sseb 	return (B_TRUE);
24901256Syl150051 }
24911256Syl150051 
24921256Syl150051 static int
xgell_stats_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)24931256Syl150051 xgell_stats_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
24941256Syl150051 {
24951256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)cp;
24961256Syl150051 	xge_hal_status_e status;
24971256Syl150051 	int count = 0, retsize;
24981256Syl150051 	char *buf;
24991256Syl150051 
25001256Syl150051 	buf = kmem_alloc(XGELL_STATS_BUFSIZE, KM_SLEEP);
25011256Syl150051 	if (buf == NULL) {
25021256Syl150051 		return (ENOSPC);
25031256Syl150051 	}
25041256Syl150051 
25051256Syl150051 	status = xge_hal_aux_stats_tmac_read(lldev->devh, XGELL_STATS_BUFSIZE,
25061256Syl150051 	    buf, &retsize);
25071256Syl150051 	if (status != XGE_HAL_OK) {
25081256Syl150051 		kmem_free(buf, XGELL_STATS_BUFSIZE);
25091256Syl150051 		xge_debug_ll(XGE_ERR, "tmac_read(): status %d", status);
25101256Syl150051 		return (EINVAL);
25111256Syl150051 	}
25121256Syl150051 	count += retsize;
25131256Syl150051 
25141256Syl150051 	status = xge_hal_aux_stats_rmac_read(lldev->devh,
25151256Syl150051 	    XGELL_STATS_BUFSIZE - count,
25161256Syl150051 	    buf+count, &retsize);
25171256Syl150051 	if (status != XGE_HAL_OK) {
25181256Syl150051 		kmem_free(buf, XGELL_STATS_BUFSIZE);
25191256Syl150051 		xge_debug_ll(XGE_ERR, "rmac_read(): status %d", status);
25201256Syl150051 		return (EINVAL);
25211256Syl150051 	}
25221256Syl150051 	count += retsize;
25231256Syl150051 
25241256Syl150051 	status = xge_hal_aux_stats_pci_read(lldev->devh,
25251256Syl150051 	    XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
25261256Syl150051 	if (status != XGE_HAL_OK) {
25271256Syl150051 		kmem_free(buf, XGELL_STATS_BUFSIZE);
25281256Syl150051 		xge_debug_ll(XGE_ERR, "pci_read(): status %d", status);
25291256Syl150051 		return (EINVAL);
25301256Syl150051 	}
25311256Syl150051 	count += retsize;
25321256Syl150051 
25331256Syl150051 	status = xge_hal_aux_stats_sw_dev_read(lldev->devh,
25341256Syl150051 	    XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
25351256Syl150051 	if (status != XGE_HAL_OK) {
25361256Syl150051 		kmem_free(buf, XGELL_STATS_BUFSIZE);
25371256Syl150051 		xge_debug_ll(XGE_ERR, "sw_dev_read(): status %d", status);
25381256Syl150051 		return (EINVAL);
25391256Syl150051 	}
25401256Syl150051 	count += retsize;
25411256Syl150051 
25421256Syl150051 	status = xge_hal_aux_stats_hal_read(lldev->devh,
25431256Syl150051 	    XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
25441256Syl150051 	if (status != XGE_HAL_OK) {
25451256Syl150051 		kmem_free(buf, XGELL_STATS_BUFSIZE);
25461256Syl150051 		xge_debug_ll(XGE_ERR, "pci_read(): status %d", status);
25471256Syl150051 		return (EINVAL);
25481256Syl150051 	}
25491256Syl150051 	count += retsize;
25501256Syl150051 
25511256Syl150051 	*(buf + count - 1) = '\0'; /* remove last '\n' */
25521256Syl150051 	(void) mi_mpprintf(mp, "%s", buf);
25531256Syl150051 	kmem_free(buf, XGELL_STATS_BUFSIZE);
25541256Syl150051 
25551256Syl150051 	return (0);
25561256Syl150051 }
25571256Syl150051 
25581256Syl150051 static int
xgell_pciconf_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)25591256Syl150051 xgell_pciconf_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
25601256Syl150051 {
25611256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)cp;
25621256Syl150051 	xge_hal_status_e status;
25631256Syl150051 	int retsize;
25641256Syl150051 	char *buf;
25651256Syl150051 
25661256Syl150051 	buf = kmem_alloc(XGELL_PCICONF_BUFSIZE, KM_SLEEP);
25671256Syl150051 	if (buf == NULL) {
25681256Syl150051 		return (ENOSPC);
25691256Syl150051 	}
25701256Syl150051 	status = xge_hal_aux_pci_config_read(lldev->devh, XGELL_PCICONF_BUFSIZE,
25711256Syl150051 	    buf, &retsize);
25721256Syl150051 	if (status != XGE_HAL_OK) {
25731256Syl150051 		kmem_free(buf, XGELL_PCICONF_BUFSIZE);
25741256Syl150051 		xge_debug_ll(XGE_ERR, "pci_config_read(): status %d", status);
25751256Syl150051 		return (EINVAL);
25761256Syl150051 	}
25771256Syl150051 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
25781256Syl150051 	(void) mi_mpprintf(mp, "%s", buf);
25791256Syl150051 	kmem_free(buf, XGELL_PCICONF_BUFSIZE);
25801256Syl150051 
25811256Syl150051 	return (0);
25821256Syl150051 }
25831256Syl150051 
25841256Syl150051 static int
xgell_about_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)25851256Syl150051 xgell_about_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
25861256Syl150051 {
25871256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)cp;
25881256Syl150051 	xge_hal_status_e status;
25891256Syl150051 	int retsize;
25901256Syl150051 	char *buf;
25911256Syl150051 
25921256Syl150051 	buf = kmem_alloc(XGELL_ABOUT_BUFSIZE, KM_SLEEP);
25931256Syl150051 	if (buf == NULL) {
25941256Syl150051 		return (ENOSPC);
25951256Syl150051 	}
25961256Syl150051 	status = xge_hal_aux_about_read(lldev->devh, XGELL_ABOUT_BUFSIZE,
25971256Syl150051 	    buf, &retsize);
25981256Syl150051 	if (status != XGE_HAL_OK) {
25991256Syl150051 		kmem_free(buf, XGELL_ABOUT_BUFSIZE);
26001256Syl150051 		xge_debug_ll(XGE_ERR, "about_read(): status %d", status);
26011256Syl150051 		return (EINVAL);
26021256Syl150051 	}
26031256Syl150051 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
26041256Syl150051 	(void) mi_mpprintf(mp, "%s", buf);
26051256Syl150051 	kmem_free(buf, XGELL_ABOUT_BUFSIZE);
26061256Syl150051 
26071256Syl150051 	return (0);
26081256Syl150051 }
26091256Syl150051 
26101256Syl150051 static unsigned long bar0_offset = 0x110; /* adapter_control */
26111256Syl150051 
26121256Syl150051 static int
xgell_bar0_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)26131256Syl150051 xgell_bar0_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
26141256Syl150051 {
26151256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)cp;
26161256Syl150051 	xge_hal_status_e status;
26171256Syl150051 	int retsize;
26181256Syl150051 	char *buf;
26191256Syl150051 
26201256Syl150051 	buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
26211256Syl150051 	if (buf == NULL) {
26221256Syl150051 		return (ENOSPC);
26231256Syl150051 	}
26241256Syl150051 	status = xge_hal_aux_bar0_read(lldev->devh, bar0_offset,
26251256Syl150051 	    XGELL_IOCTL_BUFSIZE, buf, &retsize);
26261256Syl150051 	if (status != XGE_HAL_OK) {
26271256Syl150051 		kmem_free(buf, XGELL_IOCTL_BUFSIZE);
26281256Syl150051 		xge_debug_ll(XGE_ERR, "bar0_read(): status %d", status);
26291256Syl150051 		return (EINVAL);
26301256Syl150051 	}
26311256Syl150051 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
26321256Syl150051 	(void) mi_mpprintf(mp, "%s", buf);
26331256Syl150051 	kmem_free(buf, XGELL_IOCTL_BUFSIZE);
26341256Syl150051 
26351256Syl150051 	return (0);
26361256Syl150051 }
26371256Syl150051 
26381256Syl150051 static int
xgell_bar0_set(queue_t * q,mblk_t * mp,char * value,caddr_t cp,cred_t * credp)26391256Syl150051 xgell_bar0_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *credp)
26401256Syl150051 {
26411256Syl150051 	unsigned long old_offset = bar0_offset;
26421256Syl150051 	char *end;
26431256Syl150051 
26441256Syl150051 	if (value && *value == '0' &&
26451256Syl150051 	    (*(value + 1) == 'x' || *(value + 1) == 'X')) {
26461256Syl150051 		value += 2;
26471256Syl150051 	}
26481256Syl150051 
26491256Syl150051 	bar0_offset = mi_strtol(value, &end, 16);
26501256Syl150051 	if (end == value) {
26511256Syl150051 		bar0_offset = old_offset;
26521256Syl150051 		return (EINVAL);
26531256Syl150051 	}
26541256Syl150051 
26551256Syl150051 	xge_debug_ll(XGE_TRACE, "bar0: new value %s:%lX", value, bar0_offset);
26561256Syl150051 
26571256Syl150051 	return (0);
26581256Syl150051 }
26591256Syl150051 
26601256Syl150051 static int
xgell_debug_level_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)26611256Syl150051 xgell_debug_level_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
26621256Syl150051 {
26631256Syl150051 	char *buf;
26641256Syl150051 
26651256Syl150051 	buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
26661256Syl150051 	if (buf == NULL) {
26671256Syl150051 		return (ENOSPC);
26681256Syl150051 	}
26691256Syl150051 	(void) mi_mpprintf(mp, "debug_level %d", xge_hal_driver_debug_level());
26701256Syl150051 	kmem_free(buf, XGELL_IOCTL_BUFSIZE);
26711256Syl150051 
26721256Syl150051 	return (0);
26731256Syl150051 }
26741256Syl150051 
26751256Syl150051 static int
xgell_debug_level_set(queue_t * q,mblk_t * mp,char * value,caddr_t cp,cred_t * credp)26761256Syl150051 xgell_debug_level_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
26771256Syl150051     cred_t *credp)
26781256Syl150051 {
26791256Syl150051 	int level;
26801256Syl150051 	char *end;
26811256Syl150051 
26821256Syl150051 	level = mi_strtol(value, &end, 10);
26831256Syl150051 	if (level < XGE_NONE || level > XGE_ERR || end == value) {
26841256Syl150051 		return (EINVAL);
26851256Syl150051 	}
26861256Syl150051 
26871256Syl150051 	xge_hal_driver_debug_level_set(level);
26881256Syl150051 
26891256Syl150051 	return (0);
26901256Syl150051 }
26911256Syl150051 
26921256Syl150051 static int
xgell_debug_module_mask_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)26931256Syl150051 xgell_debug_module_mask_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
26941256Syl150051 {
26951256Syl150051 	char *buf;
26961256Syl150051 
26971256Syl150051 	buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
26981256Syl150051 	if (buf == NULL) {
26991256Syl150051 		return (ENOSPC);
27001256Syl150051 	}
27011256Syl150051 	(void) mi_mpprintf(mp, "debug_module_mask 0x%08x",
27021256Syl150051 	    xge_hal_driver_debug_module_mask());
27031256Syl150051 	kmem_free(buf, XGELL_IOCTL_BUFSIZE);
27041256Syl150051 
27051256Syl150051 	return (0);
27061256Syl150051 }
27071256Syl150051 
27081256Syl150051 static int
xgell_debug_module_mask_set(queue_t * q,mblk_t * mp,char * value,caddr_t cp,cred_t * credp)27091256Syl150051 xgell_debug_module_mask_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
27101256Syl150051 			    cred_t *credp)
27111256Syl150051 {
27121256Syl150051 	u32 mask;
27131256Syl150051 	char *end;
27141256Syl150051 
27151256Syl150051 	if (value && *value == '0' &&
27161256Syl150051 	    (*(value + 1) == 'x' || *(value + 1) == 'X')) {
27171256Syl150051 		value += 2;
27181256Syl150051 	}
27191256Syl150051 
27201256Syl150051 	mask = mi_strtol(value, &end, 16);
27211256Syl150051 	if (end == value) {
27221256Syl150051 		return (EINVAL);
27231256Syl150051 	}
27241256Syl150051 
27251256Syl150051 	xge_hal_driver_debug_module_mask_set(mask);
27261256Syl150051 
27271256Syl150051 	return (0);
27281256Syl150051 }
27291256Syl150051 
27301256Syl150051 static int
xgell_devconfig_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)27311256Syl150051 xgell_devconfig_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
27321256Syl150051 {
27331256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)(void *)cp;
27341256Syl150051 	xge_hal_status_e status;
27351256Syl150051 	int retsize;
27361256Syl150051 	char *buf;
27371256Syl150051 
27381256Syl150051 	buf = kmem_alloc(XGELL_DEVCONF_BUFSIZE, KM_SLEEP);
27391256Syl150051 	if (buf == NULL) {
27401256Syl150051 		return (ENOSPC);
27411256Syl150051 	}
27421256Syl150051 	status = xge_hal_aux_device_config_read(lldev->devh,
27438275SEric Cheng 	    XGELL_DEVCONF_BUFSIZE, buf, &retsize);
27441256Syl150051 	if (status != XGE_HAL_OK) {
27451256Syl150051 		kmem_free(buf, XGELL_DEVCONF_BUFSIZE);
27461256Syl150051 		xge_debug_ll(XGE_ERR, "device_config_read(): status %d",
27471256Syl150051 		    status);
27481256Syl150051 		return (EINVAL);
27491256Syl150051 	}
27501256Syl150051 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
27511256Syl150051 	(void) mi_mpprintf(mp, "%s", buf);
27521256Syl150051 	kmem_free(buf, XGELL_DEVCONF_BUFSIZE);
27531256Syl150051 
27541256Syl150051 	return (0);
27551256Syl150051 }
27561256Syl150051 
27571256Syl150051 /*
27581256Syl150051  * xgell_device_register
27591256Syl150051  * @devh: pointer on HAL device
27601256Syl150051  * @config: pointer on this network device configuration
27611256Syl150051  * @ll_out: output pointer. Will be assigned to valid LL device.
27621256Syl150051  *
27631256Syl150051  * This function will allocate and register network device
27641256Syl150051  */
27651256Syl150051 int
xgell_device_register(xgelldev_t * lldev,xgell_config_t * config)27661256Syl150051 xgell_device_register(xgelldev_t *lldev, xgell_config_t *config)
27671256Syl150051 {
27683115Syl150051 	mac_register_t *macp = NULL;
27691256Syl150051 	xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
27701256Syl150051 
27718275SEric Cheng 	/*
27728275SEric Cheng 	 * Initialize some NDD interface for internal debug.
27738275SEric Cheng 	 */
27741256Syl150051 	if (nd_load(&lldev->ndp, "pciconf", xgell_pciconf_get, NULL,
27752311Sseb 	    (caddr_t)lldev) == B_FALSE)
27762311Sseb 		goto xgell_ndd_fail;
27771256Syl150051 
27781256Syl150051 	if (nd_load(&lldev->ndp, "about", xgell_about_get, NULL,
27792311Sseb 	    (caddr_t)lldev) == B_FALSE)
27802311Sseb 		goto xgell_ndd_fail;
27811256Syl150051 
27821256Syl150051 	if (nd_load(&lldev->ndp, "stats", xgell_stats_get, NULL,
27832311Sseb 	    (caddr_t)lldev) == B_FALSE)
27842311Sseb 		goto xgell_ndd_fail;
27851256Syl150051 
27861256Syl150051 	if (nd_load(&lldev->ndp, "bar0", xgell_bar0_get, xgell_bar0_set,
27872311Sseb 	    (caddr_t)lldev) == B_FALSE)
27882311Sseb 		goto xgell_ndd_fail;
27891256Syl150051 
27901256Syl150051 	if (nd_load(&lldev->ndp, "debug_level", xgell_debug_level_get,
27912311Sseb 	    xgell_debug_level_set, (caddr_t)lldev) == B_FALSE)
27922311Sseb 		goto xgell_ndd_fail;
27931256Syl150051 
27941256Syl150051 	if (nd_load(&lldev->ndp, "debug_module_mask",
27951256Syl150051 	    xgell_debug_module_mask_get, xgell_debug_module_mask_set,
27962311Sseb 	    (caddr_t)lldev) == B_FALSE)
27972311Sseb 		goto xgell_ndd_fail;
27981256Syl150051 
27991256Syl150051 	if (nd_load(&lldev->ndp, "devconfig", xgell_devconfig_get, NULL,
28002311Sseb 	    (caddr_t)lldev) == B_FALSE)
28012311Sseb 		goto xgell_ndd_fail;
28021256Syl150051 
28031256Syl150051 	bcopy(config, &lldev->config, sizeof (xgell_config_t));
28041256Syl150051 
28056937Sxw161283 	mutex_init(&lldev->genlock, NULL, MUTEX_DRIVER,
28066937Sxw161283 	    DDI_INTR_PRI(hldev->irqh));
28071256Syl150051 
28082311Sseb 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
28092311Sseb 		goto xgell_register_fail;
28102311Sseb 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
28113115Syl150051 	macp->m_driver = lldev;
28122311Sseb 	macp->m_dip = lldev->dev_info;
28132311Sseb 	macp->m_src_addr = hldev->macaddr[0];
28142311Sseb 	macp->m_callbacks = &xgell_m_callbacks;
28152311Sseb 	macp->m_min_sdu = 0;
28162311Sseb 	macp->m_max_sdu = hldev->config.mtu;
28175895Syz147064 	macp->m_margin = VLAN_TAGSZ;
28188275SEric Cheng 	macp->m_v12n = MAC_VIRT_LEVEL1;
28198275SEric Cheng 
28201256Syl150051 	/*
28218275SEric Cheng 	 * MAC Registration.
28221256Syl150051 	 */
28233115Syl150051 	if (mac_register(macp, &lldev->mh) != 0)
28242311Sseb 		goto xgell_register_fail;
28251256Syl150051 
28263392Syl150051 	/* Always free the macp after register */
28273392Syl150051 	if (macp != NULL)
28283392Syl150051 		mac_free(macp);
28293392Syl150051 
28303115Syl150051 	/* Calculate tx_copied_max here ??? */
28313115Syl150051 	lldev->tx_copied_max = hldev->config.fifo.max_frags *
28326937Sxw161283 	    hldev->config.fifo.alignment_size *
28336937Sxw161283 	    hldev->config.fifo.max_aligned_frags;
28343115Syl150051 
28351256Syl150051 	xge_debug_ll(XGE_TRACE, "etherenet device %s%d registered",
28361256Syl150051 	    XGELL_IFNAME, lldev->instance);
28371256Syl150051 
28381256Syl150051 	return (DDI_SUCCESS);
28392311Sseb 
28402311Sseb xgell_ndd_fail:
28412311Sseb 	nd_free(&lldev->ndp);
28422311Sseb 	xge_debug_ll(XGE_ERR, "%s", "unable to load ndd parameter");
28432311Sseb 	return (DDI_FAILURE);
28442311Sseb 
28452311Sseb xgell_register_fail:
28463115Syl150051 	if (macp != NULL)
28473115Syl150051 		mac_free(macp);
28482311Sseb 	nd_free(&lldev->ndp);
28492311Sseb 	mutex_destroy(&lldev->genlock);
28502311Sseb 	xge_debug_ll(XGE_ERR, "%s", "unable to register networking device");
28512311Sseb 	return (DDI_FAILURE);
28521256Syl150051 }
28531256Syl150051 
28541256Syl150051 /*
28551256Syl150051  * xgell_device_unregister
28561256Syl150051  * @devh: pointer on HAL device
28571256Syl150051  * @lldev: pointer to valid LL device.
28581256Syl150051  *
28591256Syl150051  * This function will unregister and free network device
28601256Syl150051  */
28611256Syl150051 int
xgell_device_unregister(xgelldev_t * lldev)28621256Syl150051 xgell_device_unregister(xgelldev_t *lldev)
28631256Syl150051 {
28642311Sseb 	if (mac_unregister(lldev->mh) != 0) {
28651256Syl150051 		xge_debug_ll(XGE_ERR, "unable to unregister device %s%d",
28661256Syl150051 		    XGELL_IFNAME, lldev->instance);
28671256Syl150051 		return (DDI_FAILURE);
28681256Syl150051 	}
28691256Syl150051 
28701256Syl150051 	mutex_destroy(&lldev->genlock);
28711256Syl150051 
28721256Syl150051 	nd_free(&lldev->ndp);
28731256Syl150051 
28741256Syl150051 	xge_debug_ll(XGE_TRACE, "etherenet device %s%d unregistered",
28751256Syl150051 	    XGELL_IFNAME, lldev->instance);
28761256Syl150051 
28771256Syl150051 	return (DDI_SUCCESS);
28781256Syl150051 }
2879