xref: /illumos-gate/usr/src/uts/common/io/xge/drv/xgell.c (revision 3d393ee6c37fa10ac512ed6d36109ad616dc7c1a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  *  Copyright (c) 2002-2008 Neterion, Inc.
29  *  All right Reserved.
30  *
31  *  FileName :    xgell.c
32  *
33  *  Description:  Xge Link Layer data path implementation
34  *
35  */
36 
37 #include "xgell.h"
38 
39 #include <netinet/ip.h>
40 #include <netinet/tcp.h>
41 #include <netinet/udp.h>
42 
43 #define	XGELL_MAX_FRAME_SIZE(hldev)	((hldev)->config.mtu +	\
44     sizeof (struct ether_vlan_header))
45 
46 #define	HEADROOM		2	/* for DIX-only packets */
47 
48 void header_free_func(void *arg) { }
49 frtn_t header_frtn = {header_free_func, NULL};
50 
51 /* DMA attributes used for Tx side */
52 static struct ddi_dma_attr tx_dma_attr = {
53 	DMA_ATTR_V0,			/* dma_attr_version */
54 	0x0ULL,				/* dma_attr_addr_lo */
55 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_addr_hi */
56 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_count_max */
57 #if defined(__sparc)
58 	0x2000,				/* dma_attr_align */
59 #else
60 	0x1000,				/* dma_attr_align */
61 #endif
62 	0xFC00FC,			/* dma_attr_burstsizes */
63 	0x1,				/* dma_attr_minxfer */
64 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_maxxfer */
65 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_seg */
66 	18,				/* dma_attr_sgllen */
67 	(unsigned int)1,		/* dma_attr_granular */
68 	0				/* dma_attr_flags */
69 };
70 
71 /*
72  * DMA attributes used when using ddi_dma_mem_alloc to
73  * allocat HAL descriptors and Rx buffers during replenish
74  */
75 static struct ddi_dma_attr hal_dma_attr = {
76 	DMA_ATTR_V0,			/* dma_attr_version */
77 	0x0ULL,				/* dma_attr_addr_lo */
78 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_addr_hi */
79 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_count_max */
80 #if defined(__sparc)
81 	0x2000,				/* dma_attr_align */
82 #else
83 	0x1000,				/* dma_attr_align */
84 #endif
85 	0xFC00FC,			/* dma_attr_burstsizes */
86 	0x1,				/* dma_attr_minxfer */
87 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_maxxfer */
88 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_seg */
89 	1,				/* dma_attr_sgllen */
90 	(unsigned int)1,		/* dma_attr_sgllen */
91 	DDI_DMA_RELAXED_ORDERING	/* dma_attr_flags */
92 };
93 
94 struct ddi_dma_attr *p_hal_dma_attr = &hal_dma_attr;
95 
96 static int		xgell_m_stat(void *, uint_t, uint64_t *);
97 static int		xgell_m_start(void *);
98 static void		xgell_m_stop(void *);
99 static int		xgell_m_promisc(void *, boolean_t);
100 static int		xgell_m_multicst(void *, boolean_t, const uint8_t *);
101 static void		xgell_m_ioctl(void *, queue_t *, mblk_t *);
102 static boolean_t	xgell_m_getcapab(void *, mac_capab_t, void *);
103 
104 #define	XGELL_M_CALLBACK_FLAGS	(MC_IOCTL | MC_GETCAPAB)
105 
106 static mac_callbacks_t xgell_m_callbacks = {
107 	XGELL_M_CALLBACK_FLAGS,
108 	xgell_m_stat,
109 	xgell_m_start,
110 	xgell_m_stop,
111 	xgell_m_promisc,
112 	xgell_m_multicst,
113 	NULL,
114 	NULL,
115 	xgell_m_ioctl,
116 	xgell_m_getcapab
117 };
118 
119 /*
120  * xge_device_poll
121  *
122  * Timeout should call me every 1s. xge_callback_event_queued should call me
123  * when HAL hope event was rescheduled.
124  */
125 /*ARGSUSED*/
126 void
127 xge_device_poll(void *data)
128 {
129 	xgelldev_t *lldev = xge_hal_device_private(data);
130 
131 	mutex_enter(&lldev->genlock);
132 	if (lldev->is_initialized) {
133 		xge_hal_device_poll(data);
134 		lldev->timeout_id = timeout(xge_device_poll, data,
135 		    XGE_DEV_POLL_TICKS);
136 	} else if (lldev->in_reset == 1) {
137 		lldev->timeout_id = timeout(xge_device_poll, data,
138 		    XGE_DEV_POLL_TICKS);
139 	} else {
140 		lldev->timeout_id = 0;
141 	}
142 	mutex_exit(&lldev->genlock);
143 }
144 
145 /*
146  * xge_device_poll_now
147  *
148  * Will call xge_device_poll() immediately
149  */
150 void
151 xge_device_poll_now(void *data)
152 {
153 	xgelldev_t *lldev = xge_hal_device_private(data);
154 
155 	mutex_enter(&lldev->genlock);
156 	if (lldev->is_initialized) {
157 		xge_hal_device_poll(data);
158 	}
159 	mutex_exit(&lldev->genlock);
160 }
161 
162 /*
163  * xgell_callback_link_up
164  *
165  * This function called by HAL to notify HW link up state change.
166  */
167 void
168 xgell_callback_link_up(void *userdata)
169 {
170 	xgelldev_t *lldev = (xgelldev_t *)userdata;
171 
172 	mac_link_update(lldev->mh, LINK_STATE_UP);
173 }
174 
175 /*
176  * xgell_callback_link_down
177  *
178  * This function called by HAL to notify HW link down state change.
179  */
180 void
181 xgell_callback_link_down(void *userdata)
182 {
183 	xgelldev_t *lldev = (xgelldev_t *)userdata;
184 
185 	mac_link_update(lldev->mh, LINK_STATE_DOWN);
186 }
187 
188 /*
189  * xgell_rx_buffer_replenish_all
190  *
191  * To replenish all freed dtr(s) with buffers in free pool. It's called by
192  * xgell_rx_buffer_recycle() or xgell_rx_1b_callback().
193  * Must be called with pool_lock held.
194  */
195 static void
196 xgell_rx_buffer_replenish_all(xgell_rx_ring_t *ring)
197 {
198 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
199 	xge_hal_dtr_h dtr;
200 	xgell_rx_buffer_t *rx_buffer;
201 	xgell_rxd_priv_t *rxd_priv;
202 
203 	xge_assert(mutex_owned(&bf_pool->pool_lock));
204 
205 	while ((bf_pool->free > 0) &&
206 	    (xge_hal_ring_dtr_reserve(ring->channelh, &dtr) == XGE_HAL_OK)) {
207 		xge_assert(bf_pool->head);
208 
209 		rx_buffer = bf_pool->head;
210 
211 		bf_pool->head = rx_buffer->next;
212 		bf_pool->free--;
213 
214 		xge_assert(rx_buffer->dma_addr);
215 
216 		rxd_priv = (xgell_rxd_priv_t *)
217 		    xge_hal_ring_dtr_private(ring->channelh, dtr);
218 		xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr,
219 		    bf_pool->size);
220 
221 		rxd_priv->rx_buffer = rx_buffer;
222 		xge_hal_ring_dtr_post(ring->channelh, dtr);
223 	}
224 }
225 
226 /*
227  * xgell_rx_buffer_release
228  *
229  * The only thing done here is to put the buffer back to the pool.
230  * Calling this function need be protected by mutex, bf_pool.pool_lock.
231  */
232 static void
233 xgell_rx_buffer_release(xgell_rx_buffer_t *rx_buffer)
234 {
235 	xgell_rx_ring_t *ring = rx_buffer->ring;
236 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
237 
238 	xge_assert(mutex_owned(&bf_pool->pool_lock));
239 
240 	/* Put the buffer back to pool */
241 	rx_buffer->next = bf_pool->head;
242 	bf_pool->head = rx_buffer;
243 
244 	bf_pool->free++;
245 }
246 
247 /*
248  * xgell_rx_buffer_recycle
249  *
250  * Called by desballoc() to "free" the resource.
251  * We will try to replenish all descripters.
252  */
253 
254 /*
255  * Previously there were much lock contention between xgell_rx_1b_compl() and
256  * xgell_rx_buffer_recycle(), which consumed a lot of CPU resources and had bad
257  * effect on rx performance. A separate recycle list is introduced to overcome
258  * this. The recycle list is used to record the rx buffer that has been recycled
259  * and these buffers will be retuned back to the free list in bulk instead of
260  * one-by-one.
261  */
262 
263 static void
264 xgell_rx_buffer_recycle(char *arg)
265 {
266 	xgell_rx_buffer_t *rx_buffer = (xgell_rx_buffer_t *)arg;
267 	xgell_rx_ring_t *ring = rx_buffer->ring;
268 	xgelldev_t *lldev = ring->lldev;
269 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
270 
271 	mutex_enter(&bf_pool->recycle_lock);
272 
273 	rx_buffer->next = bf_pool->recycle_head;
274 	bf_pool->recycle_head = rx_buffer;
275 	if (bf_pool->recycle_tail == NULL)
276 		bf_pool->recycle_tail = rx_buffer;
277 	bf_pool->recycle++;
278 
279 	/*
280 	 * Before finding a good way to set this hiwat, just always call to
281 	 * replenish_all. *TODO*
282 	 */
283 	if ((lldev->is_initialized != 0) && (ring->live) &&
284 	    (bf_pool->recycle >= XGELL_RX_BUFFER_RECYCLE_CACHE)) {
285 		mutex_enter(&bf_pool->pool_lock);
286 		bf_pool->recycle_tail->next = bf_pool->head;
287 		bf_pool->head = bf_pool->recycle_head;
288 		bf_pool->recycle_head = bf_pool->recycle_tail = NULL;
289 		bf_pool->post -= bf_pool->recycle;
290 		bf_pool->free += bf_pool->recycle;
291 		bf_pool->recycle = 0;
292 		xgell_rx_buffer_replenish_all(ring);
293 		mutex_exit(&bf_pool->pool_lock);
294 	}
295 
296 	mutex_exit(&bf_pool->recycle_lock);
297 }
298 
299 /*
300  * xgell_rx_buffer_alloc
301  *
302  * Allocate one rx buffer and return with the pointer to the buffer.
303  * Return NULL if failed.
304  */
305 static xgell_rx_buffer_t *
306 xgell_rx_buffer_alloc(xgell_rx_ring_t *ring)
307 {
308 	xgelldev_t *lldev = ring->lldev;
309 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
310 	xge_hal_device_t *hldev;
311 	void *vaddr;
312 	ddi_dma_handle_t dma_handle;
313 	ddi_acc_handle_t dma_acch;
314 	dma_addr_t dma_addr;
315 	uint_t ncookies;
316 	ddi_dma_cookie_t dma_cookie;
317 	size_t real_size;
318 	extern ddi_device_acc_attr_t *p_xge_dev_attr;
319 	xgell_rx_buffer_t *rx_buffer;
320 
321 	hldev = (xge_hal_device_t *)lldev->devh;
322 
323 	if (ddi_dma_alloc_handle(hldev->pdev, p_hal_dma_attr, DDI_DMA_SLEEP,
324 	    0, &dma_handle) != DDI_SUCCESS) {
325 		xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA handle",
326 		    XGELL_IFNAME, lldev->instance);
327 		goto handle_failed;
328 	}
329 
330 	/* reserve some space at the end of the buffer for recycling */
331 	if (ddi_dma_mem_alloc(dma_handle, HEADROOM + bf_pool->size +
332 	    sizeof (xgell_rx_buffer_t), p_xge_dev_attr, DDI_DMA_STREAMING,
333 	    DDI_DMA_SLEEP, 0, (caddr_t *)&vaddr, &real_size, &dma_acch) !=
334 	    DDI_SUCCESS) {
335 		xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory",
336 		    XGELL_IFNAME, lldev->instance);
337 		goto mem_failed;
338 	}
339 
340 	if (HEADROOM + bf_pool->size + sizeof (xgell_rx_buffer_t) >
341 	    real_size) {
342 		xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory",
343 		    XGELL_IFNAME, lldev->instance);
344 		goto bind_failed;
345 	}
346 
347 	if (ddi_dma_addr_bind_handle(dma_handle, NULL, (char *)vaddr + HEADROOM,
348 	    bf_pool->size, DDI_DMA_READ | DDI_DMA_STREAMING,
349 	    DDI_DMA_SLEEP, 0, &dma_cookie, &ncookies) != DDI_SUCCESS) {
350 		xge_debug_ll(XGE_ERR, "%s%d: out of mapping for mblk",
351 		    XGELL_IFNAME, lldev->instance);
352 		goto bind_failed;
353 	}
354 
355 	if (ncookies != 1 || dma_cookie.dmac_size < bf_pool->size) {
356 		xge_debug_ll(XGE_ERR, "%s%d: can not handle partial DMA",
357 		    XGELL_IFNAME, lldev->instance);
358 		goto check_failed;
359 	}
360 
361 	dma_addr = dma_cookie.dmac_laddress;
362 
363 	rx_buffer = (xgell_rx_buffer_t *)((char *)vaddr + real_size -
364 	    sizeof (xgell_rx_buffer_t));
365 	rx_buffer->next = NULL;
366 	rx_buffer->vaddr = vaddr;
367 	rx_buffer->dma_addr = dma_addr;
368 	rx_buffer->dma_handle = dma_handle;
369 	rx_buffer->dma_acch = dma_acch;
370 	rx_buffer->ring = ring;
371 	rx_buffer->frtn.free_func = xgell_rx_buffer_recycle;
372 	rx_buffer->frtn.free_arg = (void *)rx_buffer;
373 
374 	return (rx_buffer);
375 
376 check_failed:
377 	(void) ddi_dma_unbind_handle(dma_handle);
378 bind_failed:
379 	XGE_OS_MEMORY_CHECK_FREE(vaddr, 0);
380 	ddi_dma_mem_free(&dma_acch);
381 mem_failed:
382 	ddi_dma_free_handle(&dma_handle);
383 handle_failed:
384 
385 	return (NULL);
386 }
387 
388 /*
389  * xgell_rx_destroy_buffer_pool
390  *
391  * Destroy buffer pool. If there is still any buffer hold by upper layer,
392  * recorded by bf_pool.post, return DDI_FAILURE to reject to be unloaded.
393  */
394 static boolean_t
395 xgell_rx_destroy_buffer_pool(xgell_rx_ring_t *ring)
396 {
397 	xgelldev_t *lldev = ring->lldev;
398 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
399 	xgell_rx_buffer_t *rx_buffer;
400 	ddi_dma_handle_t  dma_handle;
401 	ddi_acc_handle_t  dma_acch;
402 	int i;
403 
404 	/*
405 	 * If the pool has been destroied, just return B_TRUE
406 	 */
407 	if (!bf_pool->live)
408 		return (B_TRUE);
409 
410 	mutex_enter(&bf_pool->recycle_lock);
411 	if (bf_pool->recycle > 0) {
412 		mutex_enter(&bf_pool->pool_lock);
413 		bf_pool->recycle_tail->next = bf_pool->head;
414 		bf_pool->head = bf_pool->recycle_head;
415 		bf_pool->recycle_tail = bf_pool->recycle_head = NULL;
416 		bf_pool->post -= bf_pool->recycle;
417 		bf_pool->free += bf_pool->recycle;
418 		bf_pool->recycle = 0;
419 		mutex_exit(&bf_pool->pool_lock);
420 	}
421 	mutex_exit(&bf_pool->recycle_lock);
422 
423 	/*
424 	 * If there is any posted buffer, the driver should reject to be
425 	 * detached. Need notice upper layer to release them.
426 	 */
427 	if (bf_pool->post != 0) {
428 		xge_debug_ll(XGE_ERR,
429 		    "%s%d has some buffers not be recycled, try later!",
430 		    XGELL_IFNAME, lldev->instance);
431 		return (B_FALSE);
432 	}
433 
434 	/*
435 	 * Release buffers one by one.
436 	 */
437 	for (i = bf_pool->total; i > 0; i--) {
438 		rx_buffer = bf_pool->head;
439 		xge_assert(rx_buffer != NULL);
440 
441 		bf_pool->head = rx_buffer->next;
442 
443 		dma_handle = rx_buffer->dma_handle;
444 		dma_acch = rx_buffer->dma_acch;
445 
446 		if (ddi_dma_unbind_handle(dma_handle) != DDI_SUCCESS) {
447 			xge_debug_ll(XGE_ERR, "failed to unbind DMA handle!");
448 			bf_pool->head = rx_buffer;
449 			return (B_FALSE);
450 		}
451 		ddi_dma_mem_free(&dma_acch);
452 		ddi_dma_free_handle(&dma_handle);
453 
454 		bf_pool->total--;
455 		bf_pool->free--;
456 	}
457 
458 	xge_assert(!mutex_owned(&bf_pool->pool_lock));
459 
460 	mutex_destroy(&bf_pool->recycle_lock);
461 	mutex_destroy(&bf_pool->pool_lock);
462 	bf_pool->live = B_FALSE;
463 
464 	return (B_TRUE);
465 }
466 
467 /*
468  * xgell_rx_create_buffer_pool
469  *
470  * Initialize RX buffer pool for all RX rings. Refer to rx_buffer_pool_t.
471  */
472 static boolean_t
473 xgell_rx_create_buffer_pool(xgell_rx_ring_t *ring)
474 {
475 	xgelldev_t *lldev = ring->lldev;
476 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
477 	xge_hal_device_t *hldev;
478 	xgell_rx_buffer_t *rx_buffer;
479 	int i;
480 
481 	if (bf_pool->live)
482 		return (B_TRUE);
483 
484 	hldev = (xge_hal_device_t *)lldev->devh;
485 
486 	bf_pool->total = 0;
487 	bf_pool->size = XGELL_MAX_FRAME_SIZE(hldev);
488 	bf_pool->head = NULL;
489 	bf_pool->free = 0;
490 	bf_pool->post = 0;
491 	bf_pool->post_hiwat = lldev->config.rx_buffer_post_hiwat;
492 	bf_pool->recycle = 0;
493 	bf_pool->recycle_head = NULL;
494 	bf_pool->recycle_tail = NULL;
495 	bf_pool->live = B_TRUE;
496 
497 	mutex_init(&bf_pool->pool_lock, NULL, MUTEX_DRIVER,
498 	    DDI_INTR_PRI(hldev->irqh));
499 	mutex_init(&bf_pool->recycle_lock, NULL, MUTEX_DRIVER,
500 	    DDI_INTR_PRI(hldev->irqh));
501 
502 	/*
503 	 * Allocate buffers one by one. If failed, destroy whole pool by
504 	 * call to xgell_rx_destroy_buffer_pool().
505 	 */
506 
507 	for (i = 0; i < lldev->config.rx_buffer_total; i++) {
508 		if ((rx_buffer = xgell_rx_buffer_alloc(ring)) == NULL) {
509 			(void) xgell_rx_destroy_buffer_pool(ring);
510 			return (B_FALSE);
511 		}
512 
513 		rx_buffer->next = bf_pool->head;
514 		bf_pool->head = rx_buffer;
515 
516 		bf_pool->total++;
517 		bf_pool->free++;
518 	}
519 
520 	return (B_TRUE);
521 }
522 
523 /*
524  * xgell_rx_dtr_replenish
525  *
526  * Replenish descriptor with rx_buffer in RX buffer pool.
527  * The dtr should be post right away.
528  */
529 xge_hal_status_e
530 xgell_rx_dtr_replenish(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, int index,
531     void *userdata, xge_hal_channel_reopen_e reopen)
532 {
533 	xgell_rx_ring_t *ring = userdata;
534 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
535 	xgell_rx_buffer_t *rx_buffer;
536 	xgell_rxd_priv_t *rxd_priv;
537 
538 	mutex_enter(&bf_pool->pool_lock);
539 	if (bf_pool->head == NULL) {
540 		xge_debug_ll(XGE_ERR, "no more available rx DMA buffer!");
541 		return (XGE_HAL_FAIL);
542 	}
543 	rx_buffer = bf_pool->head;
544 	xge_assert(rx_buffer);
545 	xge_assert(rx_buffer->dma_addr);
546 
547 	bf_pool->head = rx_buffer->next;
548 	bf_pool->free--;
549 	mutex_exit(&bf_pool->pool_lock);
550 
551 	rxd_priv = (xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtr);
552 	xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr, bf_pool->size);
553 
554 	rxd_priv->rx_buffer = rx_buffer;
555 
556 	return (XGE_HAL_OK);
557 }
558 
559 /*
560  * xgell_get_ip_offset
561  *
562  * Calculate the offset to IP header.
563  */
564 static inline int
565 xgell_get_ip_offset(xge_hal_dtr_info_t *ext_info)
566 {
567 	int ip_off;
568 
569 	/* get IP-header offset */
570 	switch (ext_info->frame) {
571 	case XGE_HAL_FRAME_TYPE_DIX:
572 		ip_off = XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE;
573 		break;
574 	case XGE_HAL_FRAME_TYPE_IPX:
575 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
576 		    XGE_HAL_HEADER_802_2_SIZE +
577 		    XGE_HAL_HEADER_SNAP_SIZE);
578 		break;
579 	case XGE_HAL_FRAME_TYPE_LLC:
580 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
581 		    XGE_HAL_HEADER_802_2_SIZE);
582 		break;
583 	case XGE_HAL_FRAME_TYPE_SNAP:
584 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
585 		    XGE_HAL_HEADER_SNAP_SIZE);
586 		break;
587 	default:
588 		ip_off = 0;
589 		break;
590 	}
591 
592 	if ((ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4 ||
593 	    ext_info->proto & XGE_HAL_FRAME_PROTO_IPV6) &&
594 	    (ext_info->proto & XGE_HAL_FRAME_PROTO_VLAN_TAGGED)) {
595 		ip_off += XGE_HAL_HEADER_VLAN_SIZE;
596 	}
597 
598 	return (ip_off);
599 }
600 
601 /*
602  * xgell_rx_hcksum_assoc
603  *
604  * Judge the packet type and then call to hcksum_assoc() to associate
605  * h/w checksum information.
606  */
607 static inline void
608 xgell_rx_hcksum_assoc(mblk_t *mp, char *vaddr, int pkt_length,
609     xge_hal_dtr_info_t *ext_info)
610 {
611 	int cksum_flags = 0;
612 
613 	if (!(ext_info->proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED)) {
614 		if (ext_info->proto & XGE_HAL_FRAME_PROTO_TCP_OR_UDP) {
615 			if (ext_info->l3_cksum == XGE_HAL_L3_CKSUM_OK) {
616 				cksum_flags |= HCK_IPV4_HDRCKSUM;
617 			}
618 			if (ext_info->l4_cksum == XGE_HAL_L4_CKSUM_OK) {
619 				cksum_flags |= HCK_FULLCKSUM_OK;
620 			}
621 			if (cksum_flags) {
622 				cksum_flags |= HCK_FULLCKSUM;
623 				(void) hcksum_assoc(mp, NULL, NULL, 0,
624 				    0, 0, 0, cksum_flags, 0);
625 			}
626 		}
627 	} else if (ext_info->proto &
628 	    (XGE_HAL_FRAME_PROTO_IPV4 | XGE_HAL_FRAME_PROTO_IPV6)) {
629 		/*
630 		 * Just pass the partial cksum up to IP.
631 		 */
632 		int ip_off = xgell_get_ip_offset(ext_info);
633 		int start, end = pkt_length - ip_off;
634 
635 		if (ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4) {
636 			struct ip *ip =
637 			    (struct ip *)(vaddr + ip_off);
638 			start = ip->ip_hl * 4 + ip_off;
639 		} else {
640 			start = ip_off + 40;
641 		}
642 		cksum_flags |= HCK_PARTIALCKSUM;
643 		(void) hcksum_assoc(mp, NULL, NULL, start, 0,
644 		    end, ntohs(ext_info->l4_cksum), cksum_flags,
645 		    0);
646 	}
647 }
648 
649 /*
650  * xgell_rx_1b_msg_alloc
651  *
652  * Allocate message header for data buffer, and decide if copy the packet to
653  * new data buffer to release big rx_buffer to save memory.
654  *
655  * If the pkt_length <= XGELL_RX_DMA_LOWAT, call allocb() to allocate
656  * new message and copy the payload in.
657  */
658 static mblk_t *
659 xgell_rx_1b_msg_alloc(xgell_rx_ring_t *ring, xgell_rx_buffer_t *rx_buffer,
660     int pkt_length, xge_hal_dtr_info_t *ext_info, boolean_t *copyit)
661 {
662 	xgelldev_t *lldev = ring->lldev;
663 	mblk_t *mp;
664 	char *vaddr;
665 
666 	vaddr = (char *)rx_buffer->vaddr + HEADROOM;
667 	/*
668 	 * Copy packet into new allocated message buffer, if pkt_length
669 	 * is less than XGELL_RX_DMA_LOWAT
670 	 */
671 	if (*copyit || pkt_length <= lldev->config.rx_dma_lowat) {
672 		if ((mp = allocb(pkt_length + HEADROOM, 0)) == NULL) {
673 			return (NULL);
674 		}
675 		mp->b_rptr += HEADROOM;
676 		bcopy(vaddr, mp->b_rptr, pkt_length);
677 		mp->b_wptr = mp->b_rptr + pkt_length;
678 		*copyit = B_TRUE;
679 		return (mp);
680 	}
681 
682 	/*
683 	 * Just allocate mblk for current data buffer
684 	 */
685 	if ((mp = (mblk_t *)desballoc((unsigned char *)vaddr, pkt_length, 0,
686 	    &rx_buffer->frtn)) == NULL) {
687 		/* Drop it */
688 		return (NULL);
689 	}
690 	/*
691 	 * Adjust the b_rptr/b_wptr in the mblk_t structure.
692 	 */
693 	mp->b_wptr += pkt_length;
694 
695 	return (mp);
696 }
697 
698 /*
699  * xgell_rx_1b_callback
700  *
701  * If the interrupt is because of a received frame or if the receive ring
702  * contains fresh as yet un-processed frames, this function is called.
703  */
704 static xge_hal_status_e
705 xgell_rx_1b_callback(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
706     void *userdata)
707 {
708 	xgell_rx_ring_t *ring = (xgell_rx_ring_t *)userdata;
709 	xgelldev_t *lldev = ring->lldev;
710 	xgell_rx_buffer_t *rx_buffer;
711 	mblk_t *mp_head = NULL;
712 	mblk_t *mp_end  = NULL;
713 	int pkt_burst = 0;
714 
715 	xge_debug_ll(XGE_TRACE, "xgell_rx_1b_callback on ring %d", ring->index);
716 
717 	mutex_enter(&ring->bf_pool.pool_lock);
718 	do {
719 		int pkt_length;
720 		dma_addr_t dma_data;
721 		mblk_t *mp;
722 		boolean_t copyit = B_FALSE;
723 
724 		xgell_rxd_priv_t *rxd_priv = ((xgell_rxd_priv_t *)
725 		    xge_hal_ring_dtr_private(channelh, dtr));
726 		xge_hal_dtr_info_t ext_info;
727 
728 		rx_buffer = rxd_priv->rx_buffer;
729 
730 		xge_hal_ring_dtr_1b_get(channelh, dtr, &dma_data, &pkt_length);
731 		xge_hal_ring_dtr_info_get(channelh, dtr, &ext_info);
732 
733 		xge_assert(dma_data == rx_buffer->dma_addr);
734 
735 		if (t_code != 0) {
736 			xge_debug_ll(XGE_ERR, "%s%d: rx: dtr 0x%"PRIx64
737 			    " completed due to error t_code %01x", XGELL_IFNAME,
738 			    lldev->instance, (uint64_t)(uintptr_t)dtr, t_code);
739 
740 			(void) xge_hal_device_handle_tcode(channelh, dtr,
741 			    t_code);
742 			xge_hal_ring_dtr_free(channelh, dtr); /* drop it */
743 			xgell_rx_buffer_release(rx_buffer);
744 			continue;
745 		}
746 
747 		/*
748 		 * Sync the DMA memory
749 		 */
750 		if (ddi_dma_sync(rx_buffer->dma_handle, 0, pkt_length,
751 		    DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) {
752 			xge_debug_ll(XGE_ERR, "%s%d: rx: can not do DMA sync",
753 			    XGELL_IFNAME, lldev->instance);
754 			xge_hal_ring_dtr_free(channelh, dtr); /* drop it */
755 			xgell_rx_buffer_release(rx_buffer);
756 			continue;
757 		}
758 
759 		/*
760 		 * Allocate message for the packet.
761 		 */
762 		if (ring->bf_pool.post > ring->bf_pool.post_hiwat) {
763 			copyit = B_TRUE;
764 		} else {
765 			copyit = B_FALSE;
766 		}
767 
768 		mp = xgell_rx_1b_msg_alloc(ring, rx_buffer, pkt_length,
769 		    &ext_info, &copyit);
770 
771 		xge_hal_ring_dtr_free(channelh, dtr);
772 
773 		/*
774 		 * Release the buffer and recycle it later
775 		 */
776 		if ((mp == NULL) || copyit) {
777 			xgell_rx_buffer_release(rx_buffer);
778 		} else {
779 			/*
780 			 * Count it since the buffer should be loaned up.
781 			 */
782 			ring->bf_pool.post++;
783 		}
784 		if (mp == NULL) {
785 			xge_debug_ll(XGE_ERR,
786 			    "%s%d: rx: can not allocate mp mblk",
787 			    XGELL_IFNAME, lldev->instance);
788 			continue;
789 		}
790 
791 		/*
792 		 * Associate cksum_flags per packet type and h/w
793 		 * cksum flags.
794 		 */
795 		xgell_rx_hcksum_assoc(mp, (char *)rx_buffer->vaddr + HEADROOM,
796 		    pkt_length, &ext_info);
797 
798 		ring->received_bytes += pkt_length;
799 
800 		if (mp_head == NULL) {
801 			mp_head = mp;
802 			mp_end = mp;
803 		} else {
804 			mp_end->b_next = mp;
805 			mp_end = mp;
806 		}
807 
808 		/*
809 		 * Inlined implemented polling function.
810 		 */
811 		if ((ring->poll_mp == NULL) && (ring->poll_bytes > 0)) {
812 			ring->poll_mp = mp_head;
813 		}
814 		if (ring->poll_mp != NULL) {
815 			if ((ring->poll_bytes -= pkt_length) <= 0) {
816 				/* have polled enough packets. */
817 				break;
818 			} else {
819 				/* continue polling packets. */
820 				continue;
821 			}
822 		}
823 
824 		/*
825 		 * We're not in polling mode, so try to chain more messages
826 		 * or send the chain up according to pkt_burst.
827 		 */
828 		if (++pkt_burst < lldev->config.rx_pkt_burst)
829 			continue;
830 
831 		if (ring->bf_pool.post > ring->bf_pool.post_hiwat) {
832 			/* Replenish rx buffers */
833 			xgell_rx_buffer_replenish_all(ring);
834 		}
835 		mutex_exit(&ring->bf_pool.pool_lock);
836 		if (mp_head != NULL) {
837 			mac_rx_ring(lldev->mh, ring->ring_handle, mp_head,
838 			    ring->ring_gen_num);
839 		}
840 		mp_head = mp_end  = NULL;
841 		pkt_burst = 0;
842 		mutex_enter(&ring->bf_pool.pool_lock);
843 
844 	} while (xge_hal_ring_dtr_next_completed(channelh, &dtr, &t_code) ==
845 	    XGE_HAL_OK);
846 
847 	/*
848 	 * Always call replenish_all to recycle rx_buffers.
849 	 */
850 	xgell_rx_buffer_replenish_all(ring);
851 	mutex_exit(&ring->bf_pool.pool_lock);
852 
853 	/*
854 	 * If we're not in polling cycle, call mac_rx(), otherwise
855 	 * just return while leaving packets chained to ring->poll_mp.
856 	 */
857 	if ((ring->poll_mp == NULL) && (mp_head != NULL)) {
858 		mac_rx_ring(lldev->mh, ring->ring_handle, mp_head,
859 		    ring->ring_gen_num);
860 	}
861 
862 	return (XGE_HAL_OK);
863 }
864 
865 mblk_t *
866 xgell_rx_poll(void *arg, int bytes_to_pickup)
867 {
868 	xgell_rx_ring_t *ring = (xgell_rx_ring_t *)arg;
869 	int got_rx = 0;
870 	mblk_t *mp;
871 
872 	xge_debug_ll(XGE_TRACE, "xgell_rx_poll on ring %d", ring->index);
873 
874 	ring->poll_mp = NULL;
875 	ring->poll_bytes = bytes_to_pickup;
876 	(void) xge_hal_device_poll_rx_channel(ring->channelh, &got_rx);
877 
878 	mp = ring->poll_mp;
879 	ring->poll_bytes = -1;
880 	ring->polled_bytes += got_rx;
881 	ring->poll_mp = NULL;
882 
883 	return (mp);
884 }
885 
886 /*
887  * xgell_xmit_compl
888  *
889  * If an interrupt was raised to indicate DMA complete of the Tx packet,
890  * this function is called. It identifies the last TxD whose buffer was
891  * freed and frees all skbs whose data have already DMA'ed into the NICs
892  * internal memory.
893  */
894 static xge_hal_status_e
895 xgell_xmit_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
896     void *userdata)
897 {
898 	xgell_tx_ring_t *ring = userdata;
899 	xgelldev_t *lldev = ring->lldev;
900 
901 	do {
902 		xgell_txd_priv_t *txd_priv = ((xgell_txd_priv_t *)
903 		    xge_hal_fifo_dtr_private(dtr));
904 		int i;
905 
906 		if (t_code) {
907 			xge_debug_ll(XGE_TRACE, "%s%d: tx: dtr 0x%"PRIx64
908 			    " completed due to error t_code %01x", XGELL_IFNAME,
909 			    lldev->instance, (uint64_t)(uintptr_t)dtr, t_code);
910 
911 			(void) xge_hal_device_handle_tcode(channelh, dtr,
912 			    t_code);
913 		}
914 
915 		for (i = 0; i < txd_priv->handle_cnt; i++) {
916 			if (txd_priv->dma_handles[i] != NULL) {
917 				xge_assert(txd_priv->dma_handles[i]);
918 				(void) ddi_dma_unbind_handle(
919 				    txd_priv->dma_handles[i]);
920 				ddi_dma_free_handle(&txd_priv->dma_handles[i]);
921 				txd_priv->dma_handles[i] = 0;
922 			}
923 		}
924 		txd_priv->handle_cnt = 0;
925 
926 		xge_hal_fifo_dtr_free(channelh, dtr);
927 
928 		if (txd_priv->mblk != NULL) {
929 			freemsg(txd_priv->mblk);
930 			txd_priv->mblk = NULL;
931 		}
932 
933 	} while (xge_hal_fifo_dtr_next_completed(channelh, &dtr, &t_code) ==
934 	    XGE_HAL_OK);
935 
936 	if (ring->need_resched)
937 		mac_tx_ring_update(lldev->mh, ring->ring_handle);
938 
939 	return (XGE_HAL_OK);
940 }
941 
942 mblk_t *
943 xgell_ring_tx(void *arg, mblk_t *mp)
944 {
945 	xgell_tx_ring_t *ring = (xgell_tx_ring_t *)arg;
946 	mblk_t *bp;
947 	xgelldev_t *lldev = ring->lldev;
948 	xge_hal_device_t *hldev = lldev->devh;
949 	xge_hal_status_e status;
950 	xge_hal_dtr_h dtr;
951 	xgell_txd_priv_t *txd_priv;
952 	uint32_t hckflags;
953 	uint32_t lsoflags;
954 	uint32_t mss;
955 	int handle_cnt, frag_cnt, ret, i, copied;
956 	boolean_t used_copy;
957 
958 _begin:
959 	handle_cnt = frag_cnt = 0;
960 
961 	if (!lldev->is_initialized || lldev->in_reset)
962 		return (mp);
963 
964 	/*
965 	 * If the free Tx dtrs count reaches the lower threshold,
966 	 * inform the gld to stop sending more packets till the free
967 	 * dtrs count exceeds higher threshold. Driver informs the
968 	 * gld through gld_sched call, when the free dtrs count exceeds
969 	 * the higher threshold.
970 	 */
971 	if (xge_hal_channel_dtr_count(ring->channelh)
972 	    <= XGELL_TX_LEVEL_LOW) {
973 		xge_debug_ll(XGE_TRACE, "%s%d: queue %d: err on xmit,"
974 		    "free descriptors count at low threshold %d",
975 		    XGELL_IFNAME, lldev->instance,
976 		    ((xge_hal_channel_t *)ring->channelh)->post_qid,
977 		    XGELL_TX_LEVEL_LOW);
978 		goto _exit;
979 	}
980 
981 	status = xge_hal_fifo_dtr_reserve(ring->channelh, &dtr);
982 	if (status != XGE_HAL_OK) {
983 		switch (status) {
984 		case XGE_HAL_INF_CHANNEL_IS_NOT_READY:
985 			xge_debug_ll(XGE_ERR,
986 			    "%s%d: channel %d is not ready.", XGELL_IFNAME,
987 			    lldev->instance,
988 			    ((xge_hal_channel_t *)
989 			    ring->channelh)->post_qid);
990 			goto _exit;
991 		case XGE_HAL_INF_OUT_OF_DESCRIPTORS:
992 			xge_debug_ll(XGE_TRACE, "%s%d: queue %d: error in xmit,"
993 			    " out of descriptors.", XGELL_IFNAME,
994 			    lldev->instance,
995 			    ((xge_hal_channel_t *)
996 			    ring->channelh)->post_qid);
997 			goto _exit;
998 		default:
999 			return (mp);
1000 		}
1001 	}
1002 
1003 	txd_priv = xge_hal_fifo_dtr_private(dtr);
1004 	txd_priv->mblk = mp;
1005 
1006 	/*
1007 	 * VLAN tag should be passed down along with MAC header, so h/w needn't
1008 	 * do insertion.
1009 	 *
1010 	 * For NIC driver that has to strip and re-insert VLAN tag, the example
1011 	 * is the other implementation for xge. The driver can simple bcopy()
1012 	 * ether_vlan_header to overwrite VLAN tag and let h/w insert the tag
1013 	 * automatically, since it's impossible that GLD sends down mp(s) with
1014 	 * splited ether_vlan_header.
1015 	 *
1016 	 * struct ether_vlan_header *evhp;
1017 	 * uint16_t tci;
1018 	 *
1019 	 * evhp = (struct ether_vlan_header *)mp->b_rptr;
1020 	 * if (evhp->ether_tpid == htons(VLAN_TPID)) {
1021 	 *	tci = ntohs(evhp->ether_tci);
1022 	 *	(void) bcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ,
1023 	 *	    2 * ETHERADDRL);
1024 	 *	mp->b_rptr += VLAN_TAGSZ;
1025 	 *
1026 	 *	xge_hal_fifo_dtr_vlan_set(dtr, tci);
1027 	 * }
1028 	 */
1029 
1030 	copied = 0;
1031 	used_copy = B_FALSE;
1032 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
1033 		int mblen;
1034 		uint_t ncookies;
1035 		ddi_dma_cookie_t dma_cookie;
1036 		ddi_dma_handle_t dma_handle;
1037 
1038 		/* skip zero-length message blocks */
1039 		mblen = MBLKL(bp);
1040 		if (mblen == 0) {
1041 			continue;
1042 		}
1043 
1044 		ring->sent_bytes += mblen;
1045 
1046 		/*
1047 		 * Check the message length to decide to DMA or bcopy() data
1048 		 * to tx descriptor(s).
1049 		 */
1050 		if (mblen < lldev->config.tx_dma_lowat &&
1051 		    (copied + mblen) < lldev->tx_copied_max) {
1052 			xge_hal_status_e rc;
1053 			rc = xge_hal_fifo_dtr_buffer_append(ring->channelh,
1054 			    dtr, bp->b_rptr, mblen);
1055 			if (rc == XGE_HAL_OK) {
1056 				used_copy = B_TRUE;
1057 				copied += mblen;
1058 				continue;
1059 			} else if (used_copy) {
1060 				xge_hal_fifo_dtr_buffer_finalize(
1061 				    ring->channelh, dtr, frag_cnt++);
1062 				used_copy = B_FALSE;
1063 			}
1064 		} else if (used_copy) {
1065 			xge_hal_fifo_dtr_buffer_finalize(ring->channelh,
1066 			    dtr, frag_cnt++);
1067 			used_copy = B_FALSE;
1068 		}
1069 
1070 		ret = ddi_dma_alloc_handle(lldev->dev_info, &tx_dma_attr,
1071 		    DDI_DMA_DONTWAIT, 0, &dma_handle);
1072 		if (ret != DDI_SUCCESS) {
1073 			xge_debug_ll(XGE_ERR,
1074 			    "%s%d: can not allocate dma handle", XGELL_IFNAME,
1075 			    lldev->instance);
1076 			goto _exit_cleanup;
1077 		}
1078 
1079 		ret = ddi_dma_addr_bind_handle(dma_handle, NULL,
1080 		    (caddr_t)bp->b_rptr, mblen,
1081 		    DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
1082 		    &dma_cookie, &ncookies);
1083 
1084 		switch (ret) {
1085 		case DDI_DMA_MAPPED:
1086 			/* everything's fine */
1087 			break;
1088 
1089 		case DDI_DMA_NORESOURCES:
1090 			xge_debug_ll(XGE_ERR,
1091 			    "%s%d: can not bind dma address",
1092 			    XGELL_IFNAME, lldev->instance);
1093 			ddi_dma_free_handle(&dma_handle);
1094 			goto _exit_cleanup;
1095 
1096 		case DDI_DMA_NOMAPPING:
1097 		case DDI_DMA_INUSE:
1098 		case DDI_DMA_TOOBIG:
1099 		default:
1100 			/* drop packet, don't retry */
1101 			xge_debug_ll(XGE_ERR,
1102 			    "%s%d: can not map message buffer",
1103 			    XGELL_IFNAME, lldev->instance);
1104 			ddi_dma_free_handle(&dma_handle);
1105 			goto _exit_cleanup;
1106 		}
1107 
1108 		if (ncookies + frag_cnt > hldev->config.fifo.max_frags) {
1109 			xge_debug_ll(XGE_ERR, "%s%d: too many fragments, "
1110 			    "requested c:%d+f:%d", XGELL_IFNAME,
1111 			    lldev->instance, ncookies, frag_cnt);
1112 			(void) ddi_dma_unbind_handle(dma_handle);
1113 			ddi_dma_free_handle(&dma_handle);
1114 			goto _exit_cleanup;
1115 		}
1116 
1117 		/* setup the descriptors for this data buffer */
1118 		while (ncookies) {
1119 			xge_hal_fifo_dtr_buffer_set(ring->channelh, dtr,
1120 			    frag_cnt++, dma_cookie.dmac_laddress,
1121 			    dma_cookie.dmac_size);
1122 			if (--ncookies) {
1123 				ddi_dma_nextcookie(dma_handle, &dma_cookie);
1124 			}
1125 
1126 		}
1127 
1128 		txd_priv->dma_handles[handle_cnt++] = dma_handle;
1129 
1130 		if (bp->b_cont &&
1131 		    (frag_cnt + XGE_HAL_DEFAULT_FIFO_FRAGS_THRESHOLD >=
1132 		    hldev->config.fifo.max_frags)) {
1133 			mblk_t *nmp;
1134 
1135 			xge_debug_ll(XGE_TRACE,
1136 			    "too many FRAGs [%d], pull up them", frag_cnt);
1137 
1138 			if ((nmp = msgpullup(bp->b_cont, -1)) == NULL) {
1139 				/* Drop packet, don't retry */
1140 				xge_debug_ll(XGE_ERR,
1141 				    "%s%d: can not pullup message buffer",
1142 				    XGELL_IFNAME, lldev->instance);
1143 				goto _exit_cleanup;
1144 			}
1145 			freemsg(bp->b_cont);
1146 			bp->b_cont = nmp;
1147 		}
1148 	}
1149 
1150 	/* finalize unfinished copies */
1151 	if (used_copy) {
1152 		xge_hal_fifo_dtr_buffer_finalize(ring->channelh, dtr,
1153 		    frag_cnt++);
1154 	}
1155 
1156 	txd_priv->handle_cnt = handle_cnt;
1157 
1158 	/*
1159 	 * If LSO is required, just call xge_hal_fifo_dtr_mss_set(dtr, mss) to
1160 	 * do all necessary work.
1161 	 */
1162 	lso_info_get(mp, &mss, &lsoflags);
1163 
1164 	if (lsoflags & HW_LSO) {
1165 		xge_assert((mss != 0) && (mss <= XGE_HAL_DEFAULT_MTU));
1166 		xge_hal_fifo_dtr_mss_set(dtr, mss);
1167 	}
1168 
1169 	hcksum_retrieve(mp, NULL, NULL, NULL, NULL, NULL, NULL, &hckflags);
1170 	if (hckflags & HCK_IPV4_HDRCKSUM) {
1171 		xge_hal_fifo_dtr_cksum_set_bits(dtr,
1172 		    XGE_HAL_TXD_TX_CKO_IPV4_EN);
1173 	}
1174 	if (hckflags & HCK_FULLCKSUM) {
1175 		xge_hal_fifo_dtr_cksum_set_bits(dtr, XGE_HAL_TXD_TX_CKO_TCP_EN |
1176 		    XGE_HAL_TXD_TX_CKO_UDP_EN);
1177 	}
1178 
1179 	xge_hal_fifo_dtr_post(ring->channelh, dtr);
1180 
1181 	return (NULL);
1182 
1183 _exit_cleanup:
1184 	/*
1185 	 * Could not successfully transmit but have changed the message,
1186 	 * so just free it and return NULL
1187 	 */
1188 	for (i = 0; i < handle_cnt; i++) {
1189 		(void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
1190 		ddi_dma_free_handle(&txd_priv->dma_handles[i]);
1191 		txd_priv->dma_handles[i] = 0;
1192 	}
1193 
1194 	xge_hal_fifo_dtr_free(ring->channelh, dtr);
1195 
1196 	freemsg(mp);
1197 	return (NULL);
1198 
1199 _exit:
1200 	ring->need_resched = B_TRUE;
1201 	return (mp);
1202 }
1203 
1204 /*
1205  * xgell_ring_macaddr_init
1206  */
1207 static void
1208 xgell_rx_ring_maddr_init(xgell_rx_ring_t *ring)
1209 {
1210 	int i;
1211 	xgelldev_t *lldev = ring->lldev;
1212 	xge_hal_device_t *hldev = lldev->devh;
1213 	int slot_start;
1214 
1215 	xge_debug_ll(XGE_TRACE, "%s", "xgell_rx_ring_maddr_init");
1216 
1217 	ring->mmac.naddr = XGE_RX_MULTI_MAC_ADDRESSES_MAX;
1218 	ring->mmac.naddrfree = ring->mmac.naddr;
1219 
1220 	/*
1221 	 * For the default rx ring, the first MAC address is the factory one.
1222 	 * This will be set by the framework, so need to clear it for now.
1223 	 */
1224 	(void) xge_hal_device_macaddr_clear(hldev, 0);
1225 
1226 	/*
1227 	 * Read the MAC address Configuration Memory from HAL.
1228 	 * The first slot will hold a factory MAC address, contents in other
1229 	 * slots will be FF:FF:FF:FF:FF:FF.
1230 	 */
1231 	slot_start = ring->index * 32;
1232 	for (i = 0; i < ring->mmac.naddr; i++) {
1233 		(void) xge_hal_device_macaddr_get(hldev, slot_start + i,
1234 		    ring->mmac.mac_addr + i);
1235 		ring->mmac.mac_addr_set[i] = B_FALSE;
1236 	}
1237 }
1238 
1239 static int xgell_maddr_set(xgelldev_t *, int, uint8_t *);
1240 
1241 static int
1242 xgell_addmac(void *arg, const uint8_t *mac_addr)
1243 {
1244 	xgell_rx_ring_t *ring = arg;
1245 	xgelldev_t *lldev = ring->lldev;
1246 	xge_hal_device_t *hldev = lldev->devh;
1247 	int slot;
1248 	int slot_start;
1249 
1250 	xge_debug_ll(XGE_TRACE, "%s", "xgell_addmac");
1251 
1252 	mutex_enter(&lldev->genlock);
1253 
1254 	if (ring->mmac.naddrfree == 0) {
1255 		mutex_exit(&lldev->genlock);
1256 		return (ENOSPC);
1257 	}
1258 
1259 	/* First slot is for factory MAC address */
1260 	for (slot = 0; slot < ring->mmac.naddr; slot++) {
1261 		if (ring->mmac.mac_addr_set[slot] == B_FALSE) {
1262 			break;
1263 		}
1264 	}
1265 
1266 	ASSERT(slot < ring->mmac.naddr);
1267 
1268 	slot_start = ring->index * 32;
1269 
1270 	if (xgell_maddr_set(lldev, slot_start + slot, (uint8_t *)mac_addr) !=
1271 	    0) {
1272 		mutex_exit(&lldev->genlock);
1273 		return (EIO);
1274 	}
1275 
1276 	/* Simply enable RTS for the whole section. */
1277 	(void) xge_hal_device_rts_section_enable(hldev, slot_start + slot);
1278 
1279 	/*
1280 	 * Read back the MAC address from HAL to keep the array up to date.
1281 	 */
1282 	if (xge_hal_device_macaddr_get(hldev, slot_start + slot,
1283 	    ring->mmac.mac_addr + slot) != XGE_HAL_OK) {
1284 		(void) xge_hal_device_macaddr_clear(hldev, slot_start + slot);
1285 		return (EIO);
1286 	}
1287 
1288 	ring->mmac.mac_addr_set[slot] = B_TRUE;
1289 	ring->mmac.naddrfree--;
1290 
1291 	mutex_exit(&lldev->genlock);
1292 
1293 	return (0);
1294 }
1295 
1296 static int
1297 xgell_remmac(void *arg, const uint8_t *mac_addr)
1298 {
1299 	xgell_rx_ring_t *ring = arg;
1300 	xgelldev_t *lldev = ring->lldev;
1301 	xge_hal_device_t *hldev = lldev->devh;
1302 	xge_hal_status_e status;
1303 	int slot;
1304 	int slot_start;
1305 
1306 	xge_debug_ll(XGE_TRACE, "%s", "xgell_remmac");
1307 
1308 	slot = xge_hal_device_macaddr_find(hldev, (uint8_t *)mac_addr);
1309 	if (slot == -1)
1310 		return (EINVAL);
1311 
1312 	slot_start = ring->index * 32;
1313 
1314 	/*
1315 	 * Adjust slot to the offset in the MAC array of this ring (group).
1316 	 */
1317 	slot -= slot_start;
1318 
1319 	/*
1320 	 * Only can remove a pre-set MAC address for this ring (group).
1321 	 */
1322 	if (slot < 0 || slot >= ring->mmac.naddr)
1323 		return (EINVAL);
1324 
1325 
1326 	xge_assert(ring->mmac.mac_addr_set[slot]);
1327 
1328 	mutex_enter(&lldev->genlock);
1329 	if (!ring->mmac.mac_addr_set[slot]) {
1330 		mutex_exit(&lldev->genlock);
1331 		/*
1332 		 * The result will be unexpected when reach here. WARNING!
1333 		 */
1334 		xge_debug_ll(XGE_ERR,
1335 		    "%s%d: caller is trying to remove an unset MAC address",
1336 		    XGELL_IFNAME, lldev->instance);
1337 		return (ENXIO);
1338 	}
1339 
1340 	status = xge_hal_device_macaddr_clear(hldev, slot_start + slot);
1341 	if (status != XGE_HAL_OK) {
1342 		mutex_exit(&lldev->genlock);
1343 		return (EIO);
1344 	}
1345 
1346 	ring->mmac.mac_addr_set[slot] = B_FALSE;
1347 	ring->mmac.naddrfree++;
1348 
1349 	/*
1350 	 * TODO: Disable MAC RTS if all addresses have been cleared.
1351 	 */
1352 
1353 	/*
1354 	 * Read back the MAC address from HAL to keep the array up to date.
1355 	 */
1356 	(void) xge_hal_device_macaddr_get(hldev, slot_start + slot,
1357 	    ring->mmac.mac_addr + slot);
1358 	mutex_exit(&lldev->genlock);
1359 
1360 	return (0);
1361 }
1362 
1363 /*
1364  * Temporarily calling hal function.
1365  *
1366  * With MSI-X implementation, no lock is needed, so that the interrupt
1367  * handling could be faster.
1368  */
1369 int
1370 xgell_rx_ring_intr_enable(mac_intr_handle_t ih)
1371 {
1372 	xgell_rx_ring_t *ring = (xgell_rx_ring_t *)ih;
1373 
1374 	mutex_enter(&ring->ring_lock);
1375 	xge_hal_device_rx_channel_disable_polling(ring->channelh);
1376 	mutex_exit(&ring->ring_lock);
1377 
1378 	return (0);
1379 }
1380 
1381 int
1382 xgell_rx_ring_intr_disable(mac_intr_handle_t ih)
1383 {
1384 	xgell_rx_ring_t *ring = (xgell_rx_ring_t *)ih;
1385 
1386 	mutex_enter(&ring->ring_lock);
1387 	xge_hal_device_rx_channel_enable_polling(ring->channelh);
1388 	mutex_exit(&ring->ring_lock);
1389 
1390 	return (0);
1391 }
1392 
1393 static int
1394 xgell_rx_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
1395 {
1396 	xgell_rx_ring_t *rx_ring = (xgell_rx_ring_t *)rh;
1397 
1398 	rx_ring->ring_gen_num = mr_gen_num;
1399 
1400 	return (0);
1401 }
1402 
1403 /*ARGSUSED*/
1404 static void
1405 xgell_rx_ring_stop(mac_ring_driver_t rh)
1406 {
1407 }
1408 
1409 /*ARGSUSED*/
1410 static int
1411 xgell_tx_ring_start(mac_ring_driver_t rh, uint64_t useless)
1412 {
1413 	return (0);
1414 }
1415 
1416 /*ARGSUSED*/
1417 static void
1418 xgell_tx_ring_stop(mac_ring_driver_t rh)
1419 {
1420 }
1421 
1422 /*
1423  * Callback funtion for MAC layer to register all rings.
1424  *
1425  * Xframe hardware doesn't support grouping explicitly, so the driver needs
1426  * to pretend having resource groups. We may also optionally group all 8 rx
1427  * rings into a single group for increased scalability on CMT architectures,
1428  * or group one rx ring per group for maximum virtualization.
1429  *
1430  * TX grouping is actually done by framework, so, just register all TX
1431  * resources without grouping them.
1432  */
1433 void
1434 xgell_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index,
1435     const int index, mac_ring_info_t *infop, mac_ring_handle_t rh)
1436 {
1437 	xgelldev_t *lldev = (xgelldev_t *)arg;
1438 	mac_intr_t *mintr;
1439 
1440 	switch (rtype) {
1441 	case MAC_RING_TYPE_RX: {
1442 		xgell_rx_ring_t *rx_ring;
1443 
1444 		xge_assert(index < lldev->init_rx_rings);
1445 		xge_assert(rg_index < lldev->init_rx_groups);
1446 
1447 		/*
1448 		 * Performance vs. Virtualization
1449 		 */
1450 		if (lldev->init_rx_rings == lldev->init_rx_groups)
1451 			rx_ring = lldev->rx_ring + rg_index;
1452 		else
1453 			rx_ring = lldev->rx_ring + index;
1454 
1455 		rx_ring->ring_handle = rh;
1456 
1457 		infop->mri_driver = (mac_ring_driver_t)rx_ring;
1458 		infop->mri_start = xgell_rx_ring_start;
1459 		infop->mri_stop = xgell_rx_ring_stop;
1460 		infop->mri_poll = xgell_rx_poll;
1461 
1462 		mintr = &infop->mri_intr;
1463 		mintr->mi_handle = (mac_intr_handle_t)rx_ring;
1464 		mintr->mi_enable = xgell_rx_ring_intr_enable;
1465 		mintr->mi_disable = xgell_rx_ring_intr_disable;
1466 
1467 		break;
1468 	}
1469 	case MAC_RING_TYPE_TX: {
1470 		xgell_tx_ring_t *tx_ring;
1471 
1472 		xge_assert(rg_index == -1);
1473 
1474 		xge_assert((index >= 0) && (index < lldev->init_tx_rings));
1475 
1476 		tx_ring = lldev->tx_ring + index;
1477 		tx_ring->ring_handle = rh;
1478 
1479 		infop->mri_driver = (mac_ring_driver_t)tx_ring;
1480 		infop->mri_start = xgell_tx_ring_start;
1481 		infop->mri_stop = xgell_tx_ring_stop;
1482 		infop->mri_tx = xgell_ring_tx;
1483 
1484 		break;
1485 	}
1486 	default:
1487 		break;
1488 	}
1489 }
1490 
1491 void
1492 xgell_fill_group(void *arg, mac_ring_type_t rtype, const int index,
1493     mac_group_info_t *infop, mac_group_handle_t gh)
1494 {
1495 	xgelldev_t *lldev = (xgelldev_t *)arg;
1496 
1497 	switch (rtype) {
1498 	case MAC_RING_TYPE_RX: {
1499 		xgell_rx_ring_t *rx_ring;
1500 
1501 		xge_assert(index < lldev->init_rx_groups);
1502 
1503 		rx_ring = lldev->rx_ring + index;
1504 
1505 		rx_ring->group_handle = gh;
1506 
1507 		infop->mgi_driver = (mac_group_driver_t)rx_ring;
1508 		infop->mgi_start = NULL;
1509 		infop->mgi_stop = NULL;
1510 		infop->mgi_addmac = xgell_addmac;
1511 		infop->mgi_remmac = xgell_remmac;
1512 		infop->mgi_count = lldev->init_rx_rings / lldev->init_rx_groups;
1513 
1514 		break;
1515 	}
1516 	case MAC_RING_TYPE_TX:
1517 		xge_assert(0);
1518 		break;
1519 	default:
1520 		break;
1521 	}
1522 }
1523 
1524 /*
1525  * xgell_macaddr_set
1526  */
1527 static int
1528 xgell_maddr_set(xgelldev_t *lldev, int index, uint8_t *macaddr)
1529 {
1530 	xge_hal_device_t *hldev = lldev->devh;
1531 	xge_hal_status_e status;
1532 
1533 	xge_debug_ll(XGE_TRACE, "%s", "xgell_maddr_set");
1534 
1535 	xge_debug_ll(XGE_TRACE,
1536 	    "setting macaddr: 0x%02x-%02x-%02x-%02x-%02x-%02x",
1537 	    macaddr[0], macaddr[1], macaddr[2],
1538 	    macaddr[3], macaddr[4], macaddr[5]);
1539 
1540 	status = xge_hal_device_macaddr_set(hldev, index, (uchar_t *)macaddr);
1541 
1542 	if (status != XGE_HAL_OK) {
1543 		xge_debug_ll(XGE_ERR, "%s%d: can not set mac address",
1544 		    XGELL_IFNAME, lldev->instance);
1545 		return (EIO);
1546 	}
1547 
1548 	return (0);
1549 }
1550 
1551 /*
1552  * xgell_rx_dtr_term
1553  *
1554  * Function will be called by HAL to terminate all DTRs for
1555  * Ring(s) type of channels.
1556  */
1557 static void
1558 xgell_rx_dtr_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
1559     xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen)
1560 {
1561 	xgell_rxd_priv_t *rxd_priv =
1562 	    ((xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtrh));
1563 	xgell_rx_buffer_t *rx_buffer = rxd_priv->rx_buffer;
1564 
1565 	if (state == XGE_HAL_DTR_STATE_POSTED) {
1566 		xgell_rx_ring_t *ring = rx_buffer->ring;
1567 
1568 		mutex_enter(&ring->bf_pool.pool_lock);
1569 		xge_hal_ring_dtr_free(channelh, dtrh);
1570 		xgell_rx_buffer_release(rx_buffer);
1571 		mutex_exit(&ring->bf_pool.pool_lock);
1572 	}
1573 }
1574 
1575 /*
1576  * To open a rx ring.
1577  */
1578 static boolean_t
1579 xgell_rx_ring_open(xgell_rx_ring_t *rx_ring)
1580 {
1581 	xge_hal_status_e status;
1582 	xge_hal_channel_attr_t attr;
1583 	xgelldev_t *lldev = rx_ring->lldev;
1584 	xge_hal_device_t *hldev = lldev->devh;
1585 
1586 	if (rx_ring->live)
1587 		return (B_TRUE);
1588 
1589 	/* Create the buffer pool first */
1590 	if (!xgell_rx_create_buffer_pool(rx_ring)) {
1591 		xge_debug_ll(XGE_ERR, "can not create buffer pool for ring: %d",
1592 		    rx_ring->index);
1593 		return (B_FALSE);
1594 	}
1595 
1596 	/* Default ring initialization */
1597 	attr.post_qid		= rx_ring->index;
1598 	attr.compl_qid		= 0;
1599 	attr.callback		= xgell_rx_1b_callback;
1600 	attr.per_dtr_space	= sizeof (xgell_rxd_priv_t);
1601 	attr.flags		= 0;
1602 	attr.type		= XGE_HAL_CHANNEL_TYPE_RING;
1603 	attr.dtr_init		= xgell_rx_dtr_replenish;
1604 	attr.dtr_term		= xgell_rx_dtr_term;
1605 	attr.userdata		= rx_ring;
1606 
1607 	status = xge_hal_channel_open(lldev->devh, &attr, &rx_ring->channelh,
1608 	    XGE_HAL_CHANNEL_OC_NORMAL);
1609 	if (status != XGE_HAL_OK) {
1610 		xge_debug_ll(XGE_ERR, "%s%d: cannot open Rx channel got status "
1611 		    " code %d", XGELL_IFNAME, lldev->instance, status);
1612 		(void) xgell_rx_destroy_buffer_pool(rx_ring);
1613 		return (B_FALSE);
1614 	}
1615 
1616 	xgell_rx_ring_maddr_init(rx_ring);
1617 
1618 	mutex_init(&rx_ring->ring_lock, NULL, MUTEX_DRIVER,
1619 	    DDI_INTR_PRI(hldev->irqh));
1620 
1621 	rx_ring->received_bytes = 0;
1622 	rx_ring->poll_bytes = -1;
1623 	rx_ring->polled_bytes = 0;
1624 	rx_ring->poll_mp = NULL;
1625 	rx_ring->live = B_TRUE;
1626 
1627 	xge_debug_ll(XGE_TRACE, "RX ring [%d] is opened successfully",
1628 	    rx_ring->index);
1629 
1630 	return (B_TRUE);
1631 }
1632 
1633 static void
1634 xgell_rx_ring_close(xgell_rx_ring_t *rx_ring)
1635 {
1636 	if (!rx_ring->live)
1637 		return;
1638 	xge_hal_channel_close(rx_ring->channelh, XGE_HAL_CHANNEL_OC_NORMAL);
1639 	rx_ring->channelh = NULL;
1640 	/* This may not clean up all used buffers, driver will handle it */
1641 	if (xgell_rx_destroy_buffer_pool(rx_ring))
1642 		rx_ring->live = B_FALSE;
1643 
1644 	mutex_destroy(&rx_ring->ring_lock);
1645 }
1646 
1647 /*
1648  * xgell_rx_open
1649  * @lldev: the link layer object
1650  *
1651  * Initialize and open all RX channels.
1652  */
1653 static boolean_t
1654 xgell_rx_open(xgelldev_t *lldev)
1655 {
1656 	xgell_rx_ring_t *rx_ring;
1657 	int i;
1658 
1659 	if (lldev->live_rx_rings != 0)
1660 		return (B_TRUE);
1661 
1662 	lldev->live_rx_rings = 0;
1663 
1664 	/*
1665 	 * Initialize all rings
1666 	 */
1667 	for (i = 0; i < lldev->init_rx_rings; i++) {
1668 		rx_ring = &lldev->rx_ring[i];
1669 		rx_ring->index = i;
1670 		rx_ring->lldev = lldev;
1671 		rx_ring->live = B_FALSE;
1672 
1673 		if (!xgell_rx_ring_open(rx_ring))
1674 			return (B_FALSE);
1675 
1676 		lldev->live_rx_rings++;
1677 	}
1678 
1679 	return (B_TRUE);
1680 }
1681 
1682 static void
1683 xgell_rx_close(xgelldev_t *lldev)
1684 {
1685 	xgell_rx_ring_t *rx_ring;
1686 	int i;
1687 
1688 	if (lldev->live_rx_rings == 0)
1689 		return;
1690 
1691 	/*
1692 	 * Close all rx rings
1693 	 */
1694 	for (i = 0; i < lldev->init_rx_rings; i++) {
1695 		rx_ring = &lldev->rx_ring[i];
1696 
1697 		if (rx_ring->live) {
1698 			xgell_rx_ring_close(rx_ring);
1699 			lldev->live_rx_rings--;
1700 		}
1701 	}
1702 
1703 	xge_assert(lldev->live_rx_rings == 0);
1704 }
1705 
1706 /*
1707  * xgell_tx_term
1708  *
1709  * Function will be called by HAL to terminate all DTRs for
1710  * Fifo(s) type of channels.
1711  */
1712 static void
1713 xgell_tx_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
1714     xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen)
1715 {
1716 	xgell_txd_priv_t *txd_priv =
1717 	    ((xgell_txd_priv_t *)xge_hal_fifo_dtr_private(dtrh));
1718 	mblk_t *mp = txd_priv->mblk;
1719 	int i;
1720 
1721 	/*
1722 	 * for Tx we must clean up the DTR *only* if it has been
1723 	 * posted!
1724 	 */
1725 	if (state != XGE_HAL_DTR_STATE_POSTED) {
1726 		return;
1727 	}
1728 
1729 	for (i = 0; i < txd_priv->handle_cnt; i++) {
1730 		xge_assert(txd_priv->dma_handles[i]);
1731 		(void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
1732 		ddi_dma_free_handle(&txd_priv->dma_handles[i]);
1733 		txd_priv->dma_handles[i] = 0;
1734 	}
1735 
1736 	xge_hal_fifo_dtr_free(channelh, dtrh);
1737 
1738 	if (mp) {
1739 		txd_priv->mblk = NULL;
1740 		freemsg(mp);
1741 	}
1742 }
1743 
1744 static boolean_t
1745 xgell_tx_ring_open(xgell_tx_ring_t *tx_ring)
1746 {
1747 	xge_hal_status_e status;
1748 	xge_hal_channel_attr_t attr;
1749 	xgelldev_t *lldev = tx_ring->lldev;
1750 
1751 	if (tx_ring->live)
1752 		return (B_TRUE);
1753 
1754 	attr.post_qid		= tx_ring->index;
1755 	attr.compl_qid		= 0;
1756 	attr.callback		= xgell_xmit_compl;
1757 	attr.per_dtr_space	= sizeof (xgell_txd_priv_t);
1758 	attr.flags		= 0;
1759 	attr.type		= XGE_HAL_CHANNEL_TYPE_FIFO;
1760 	attr.dtr_init		= NULL;
1761 	attr.dtr_term		= xgell_tx_term;
1762 	attr.userdata		= tx_ring;
1763 
1764 	status = xge_hal_channel_open(lldev->devh, &attr, &tx_ring->channelh,
1765 	    XGE_HAL_CHANNEL_OC_NORMAL);
1766 	if (status != XGE_HAL_OK) {
1767 		xge_debug_ll(XGE_ERR, "%s%d: cannot open Tx channel got status "
1768 		    "code %d", XGELL_IFNAME, lldev->instance, status);
1769 		return (B_FALSE);
1770 	}
1771 
1772 	tx_ring->sent_bytes = 0;
1773 	tx_ring->live = B_TRUE;
1774 
1775 	return (B_TRUE);
1776 }
1777 
1778 static void
1779 xgell_tx_ring_close(xgell_tx_ring_t *tx_ring)
1780 {
1781 	if (!tx_ring->live)
1782 		return;
1783 	xge_hal_channel_close(tx_ring->channelh, XGE_HAL_CHANNEL_OC_NORMAL);
1784 	tx_ring->live = B_FALSE;
1785 }
1786 
1787 /*
1788  * xgell_tx_open
1789  * @lldev: the link layer object
1790  *
1791  * Initialize and open all TX channels.
1792  */
1793 static boolean_t
1794 xgell_tx_open(xgelldev_t *lldev)
1795 {
1796 	xgell_tx_ring_t *tx_ring;
1797 	int i;
1798 
1799 	if (lldev->live_tx_rings != 0)
1800 		return (B_TRUE);
1801 
1802 	lldev->live_tx_rings = 0;
1803 
1804 	/*
1805 	 * Enable rings by reserve sequence to match the h/w sequences.
1806 	 */
1807 	for (i = 0; i < lldev->init_tx_rings; i++) {
1808 		tx_ring = &lldev->tx_ring[i];
1809 		tx_ring->index = i;
1810 		tx_ring->lldev = lldev;
1811 		tx_ring->live = B_FALSE;
1812 
1813 		if (!xgell_tx_ring_open(tx_ring))
1814 			return (B_FALSE);
1815 
1816 		lldev->live_tx_rings++;
1817 	}
1818 
1819 	return (B_TRUE);
1820 }
1821 
1822 static void
1823 xgell_tx_close(xgelldev_t *lldev)
1824 {
1825 	xgell_tx_ring_t *tx_ring;
1826 	int i;
1827 
1828 	if (lldev->live_tx_rings == 0)
1829 		return;
1830 
1831 	/*
1832 	 * Enable rings by reserve sequence to match the h/w sequences.
1833 	 */
1834 	for (i = 0; i < lldev->init_tx_rings; i++) {
1835 		tx_ring = &lldev->tx_ring[i];
1836 		if (tx_ring->live) {
1837 			xgell_tx_ring_close(tx_ring);
1838 			lldev->live_tx_rings--;
1839 		}
1840 	}
1841 }
1842 
1843 static int
1844 xgell_initiate_start(xgelldev_t *lldev)
1845 {
1846 	xge_hal_status_e status;
1847 	xge_hal_device_t *hldev = lldev->devh;
1848 	int maxpkt = hldev->config.mtu;
1849 
1850 	/* check initial mtu before enabling the device */
1851 	status = xge_hal_device_mtu_check(lldev->devh, maxpkt);
1852 	if (status != XGE_HAL_OK) {
1853 		xge_debug_ll(XGE_ERR, "%s%d: MTU size %d is invalid",
1854 		    XGELL_IFNAME, lldev->instance, maxpkt);
1855 		return (EINVAL);
1856 	}
1857 
1858 	/* set initial mtu before enabling the device */
1859 	status = xge_hal_device_mtu_set(lldev->devh, maxpkt);
1860 	if (status != XGE_HAL_OK) {
1861 		xge_debug_ll(XGE_ERR, "%s%d: can not set new MTU %d",
1862 		    XGELL_IFNAME, lldev->instance, maxpkt);
1863 		return (EIO);
1864 	}
1865 
1866 	/* tune jumbo/normal frame UFC counters */
1867 	hldev->config.ring.queue[XGELL_RX_RING_MAIN].rti.ufc_b =
1868 	    (maxpkt > XGE_HAL_DEFAULT_MTU) ?
1869 	    XGE_HAL_DEFAULT_RX_UFC_B_J :
1870 	    XGE_HAL_DEFAULT_RX_UFC_B_N;
1871 
1872 	hldev->config.ring.queue[XGELL_RX_RING_MAIN].rti.ufc_c =
1873 	    (maxpkt > XGE_HAL_DEFAULT_MTU) ?
1874 	    XGE_HAL_DEFAULT_RX_UFC_C_J :
1875 	    XGE_HAL_DEFAULT_RX_UFC_C_N;
1876 
1877 	/* now, enable the device */
1878 	status = xge_hal_device_enable(lldev->devh);
1879 	if (status != XGE_HAL_OK) {
1880 		xge_debug_ll(XGE_ERR, "%s%d: can not enable the device",
1881 		    XGELL_IFNAME, lldev->instance);
1882 		return (EIO);
1883 	}
1884 
1885 	if (!xgell_rx_open(lldev)) {
1886 		status = xge_hal_device_disable(lldev->devh);
1887 		if (status != XGE_HAL_OK) {
1888 			u64 adapter_status;
1889 			(void) xge_hal_device_status(lldev->devh,
1890 			    &adapter_status);
1891 			xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
1892 			    "the device. adaper status 0x%"PRIx64
1893 			    " returned status %d",
1894 			    XGELL_IFNAME, lldev->instance,
1895 			    (uint64_t)adapter_status, status);
1896 		}
1897 		xgell_rx_close(lldev);
1898 		xge_os_mdelay(1500);
1899 		return (ENOMEM);
1900 	}
1901 
1902 	if (!xgell_tx_open(lldev)) {
1903 		status = xge_hal_device_disable(lldev->devh);
1904 		if (status != XGE_HAL_OK) {
1905 			u64 adapter_status;
1906 			(void) xge_hal_device_status(lldev->devh,
1907 			    &adapter_status);
1908 			xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
1909 			    "the device. adaper status 0x%"PRIx64
1910 			    " returned status %d",
1911 			    XGELL_IFNAME, lldev->instance,
1912 			    (uint64_t)adapter_status, status);
1913 		}
1914 		xgell_tx_close(lldev);
1915 		xgell_rx_close(lldev);
1916 		xge_os_mdelay(1500);
1917 		return (ENOMEM);
1918 	}
1919 
1920 	/* time to enable interrupts */
1921 	(void) xge_enable_intrs(lldev);
1922 	xge_hal_device_intr_enable(lldev->devh);
1923 
1924 	lldev->is_initialized = 1;
1925 
1926 	return (0);
1927 }
1928 
1929 static void
1930 xgell_initiate_stop(xgelldev_t *lldev)
1931 {
1932 	xge_hal_status_e status;
1933 
1934 	lldev->is_initialized = 0;
1935 
1936 	status = xge_hal_device_disable(lldev->devh);
1937 	if (status != XGE_HAL_OK) {
1938 		u64 adapter_status;
1939 		(void) xge_hal_device_status(lldev->devh, &adapter_status);
1940 		xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
1941 		    "the device. adaper status 0x%"PRIx64" returned status %d",
1942 		    XGELL_IFNAME, lldev->instance,
1943 		    (uint64_t)adapter_status, status);
1944 	}
1945 	xge_hal_device_intr_disable(lldev->devh);
1946 	/* disable OS ISR's */
1947 	xge_disable_intrs(lldev);
1948 
1949 	xge_debug_ll(XGE_TRACE, "%s",
1950 	    "waiting for device irq to become quiescent...");
1951 	xge_os_mdelay(1500);
1952 
1953 	xge_queue_flush(xge_hal_device_queue(lldev->devh));
1954 
1955 	xgell_rx_close(lldev);
1956 	xgell_tx_close(lldev);
1957 }
1958 
1959 /*
1960  * xgell_m_start
1961  * @arg: pointer to device private strucutre(hldev)
1962  *
1963  * This function is called by MAC Layer to enable the XFRAME
1964  * firmware to generate interrupts and also prepare the
1965  * driver to call mac_rx for delivering receive packets
1966  * to MAC Layer.
1967  */
1968 static int
1969 xgell_m_start(void *arg)
1970 {
1971 	xgelldev_t *lldev = arg;
1972 	xge_hal_device_t *hldev = lldev->devh;
1973 	int ret;
1974 
1975 	xge_debug_ll(XGE_TRACE, "%s%d: M_START", XGELL_IFNAME,
1976 	    lldev->instance);
1977 
1978 	mutex_enter(&lldev->genlock);
1979 
1980 	if (lldev->is_initialized) {
1981 		xge_debug_ll(XGE_ERR, "%s%d: device is already initialized",
1982 		    XGELL_IFNAME, lldev->instance);
1983 		mutex_exit(&lldev->genlock);
1984 		return (EINVAL);
1985 	}
1986 
1987 	hldev->terminating = 0;
1988 	if (ret = xgell_initiate_start(lldev)) {
1989 		mutex_exit(&lldev->genlock);
1990 		return (ret);
1991 	}
1992 
1993 	lldev->timeout_id = timeout(xge_device_poll, hldev, XGE_DEV_POLL_TICKS);
1994 
1995 	mutex_exit(&lldev->genlock);
1996 
1997 	return (0);
1998 }
1999 
2000 /*
2001  * xgell_m_stop
2002  * @arg: pointer to device private data (hldev)
2003  *
2004  * This function is called by the MAC Layer to disable
2005  * the XFRAME firmware for generating any interrupts and
2006  * also stop the driver from calling mac_rx() for
2007  * delivering data packets to the MAC Layer.
2008  */
2009 static void
2010 xgell_m_stop(void *arg)
2011 {
2012 	xgelldev_t *lldev = arg;
2013 	xge_hal_device_t *hldev = lldev->devh;
2014 
2015 	xge_debug_ll(XGE_TRACE, "%s", "MAC_STOP");
2016 
2017 	mutex_enter(&lldev->genlock);
2018 	if (!lldev->is_initialized) {
2019 		xge_debug_ll(XGE_ERR, "%s", "device is not initialized...");
2020 		mutex_exit(&lldev->genlock);
2021 		return;
2022 	}
2023 
2024 	xge_hal_device_terminating(hldev);
2025 	xgell_initiate_stop(lldev);
2026 
2027 	/* reset device */
2028 	(void) xge_hal_device_reset(lldev->devh);
2029 
2030 	mutex_exit(&lldev->genlock);
2031 
2032 	if (lldev->timeout_id != 0) {
2033 		(void) untimeout(lldev->timeout_id);
2034 	}
2035 
2036 	xge_debug_ll(XGE_TRACE, "%s", "returning back to MAC Layer...");
2037 }
2038 
2039 /*
2040  * xgell_onerr_reset
2041  * @lldev: pointer to xgelldev_t structure
2042  *
2043  * This function is called by HAL Event framework to reset the HW
2044  * This function is must be called with genlock taken.
2045  */
2046 int
2047 xgell_onerr_reset(xgelldev_t *lldev)
2048 {
2049 	int rc = 0;
2050 
2051 	if (!lldev->is_initialized) {
2052 		xge_debug_ll(XGE_ERR, "%s%d: can not reset",
2053 		    XGELL_IFNAME, lldev->instance);
2054 		return (rc);
2055 	}
2056 
2057 	lldev->in_reset = 1;
2058 	xgell_initiate_stop(lldev);
2059 
2060 	/* reset device */
2061 	(void) xge_hal_device_reset(lldev->devh);
2062 
2063 	rc = xgell_initiate_start(lldev);
2064 	lldev->in_reset = 0;
2065 
2066 	return (rc);
2067 }
2068 
2069 /*
2070  * xgell_m_multicst
2071  * @arg: pointer to device private strucutre(hldev)
2072  * @add:
2073  * @mc_addr:
2074  *
2075  * This function is called by MAC Layer to enable or
2076  * disable device-level reception of specific multicast addresses.
2077  */
2078 static int
2079 xgell_m_multicst(void *arg, boolean_t add, const uint8_t *mc_addr)
2080 {
2081 	xge_hal_status_e status;
2082 	xgelldev_t *lldev = (xgelldev_t *)arg;
2083 	xge_hal_device_t *hldev = lldev->devh;
2084 
2085 	xge_debug_ll(XGE_TRACE, "M_MULTICAST add %d", add);
2086 
2087 	mutex_enter(&lldev->genlock);
2088 
2089 	if (!lldev->is_initialized) {
2090 		xge_debug_ll(XGE_ERR, "%s%d: can not set multicast",
2091 		    XGELL_IFNAME, lldev->instance);
2092 		mutex_exit(&lldev->genlock);
2093 		return (EIO);
2094 	}
2095 
2096 	/* FIXME: missing HAL functionality: enable_one() */
2097 
2098 	status = (add) ?
2099 	    xge_hal_device_mcast_enable(hldev) :
2100 	    xge_hal_device_mcast_disable(hldev);
2101 
2102 	if (status != XGE_HAL_OK) {
2103 		xge_debug_ll(XGE_ERR, "failed to %s multicast, status %d",
2104 		    add ? "enable" : "disable", status);
2105 		mutex_exit(&lldev->genlock);
2106 		return (EIO);
2107 	}
2108 
2109 	mutex_exit(&lldev->genlock);
2110 
2111 	return (0);
2112 }
2113 
2114 
2115 /*
2116  * xgell_m_promisc
2117  * @arg: pointer to device private strucutre(hldev)
2118  * @on:
2119  *
2120  * This function is called by MAC Layer to enable or
2121  * disable the reception of all the packets on the medium
2122  */
2123 static int
2124 xgell_m_promisc(void *arg, boolean_t on)
2125 {
2126 	xgelldev_t *lldev = (xgelldev_t *)arg;
2127 	xge_hal_device_t *hldev = lldev->devh;
2128 
2129 	mutex_enter(&lldev->genlock);
2130 
2131 	xge_debug_ll(XGE_TRACE, "%s", "MAC_PROMISC_SET");
2132 
2133 	if (!lldev->is_initialized) {
2134 		xge_debug_ll(XGE_ERR, "%s%d: can not set promiscuous",
2135 		    XGELL_IFNAME, lldev->instance);
2136 		mutex_exit(&lldev->genlock);
2137 		return (EIO);
2138 	}
2139 
2140 	if (on) {
2141 		xge_hal_device_promisc_enable(hldev);
2142 	} else {
2143 		xge_hal_device_promisc_disable(hldev);
2144 	}
2145 
2146 	mutex_exit(&lldev->genlock);
2147 
2148 	return (0);
2149 }
2150 
2151 /*
2152  * xgell_m_stat
2153  * @arg: pointer to device private strucutre(hldev)
2154  *
2155  * This function is called by MAC Layer to get network statistics
2156  * from the driver.
2157  */
2158 static int
2159 xgell_m_stat(void *arg, uint_t stat, uint64_t *val)
2160 {
2161 	xge_hal_stats_hw_info_t *hw_info;
2162 	xgelldev_t *lldev = (xgelldev_t *)arg;
2163 	xge_hal_device_t *hldev = lldev->devh;
2164 
2165 	xge_debug_ll(XGE_TRACE, "%s", "MAC_STATS_GET");
2166 
2167 	mutex_enter(&lldev->genlock);
2168 
2169 	if (!lldev->is_initialized) {
2170 		mutex_exit(&lldev->genlock);
2171 		return (EAGAIN);
2172 	}
2173 
2174 	if (xge_hal_stats_hw(hldev, &hw_info) != XGE_HAL_OK) {
2175 		mutex_exit(&lldev->genlock);
2176 		return (EAGAIN);
2177 	}
2178 
2179 	switch (stat) {
2180 	case MAC_STAT_IFSPEED:
2181 		*val = 10000000000ull; /* 10G */
2182 		break;
2183 
2184 	case MAC_STAT_MULTIRCV:
2185 		*val = ((u64) hw_info->rmac_vld_mcst_frms_oflow << 32) |
2186 		    hw_info->rmac_vld_mcst_frms;
2187 		break;
2188 
2189 	case MAC_STAT_BRDCSTRCV:
2190 		*val = ((u64) hw_info->rmac_vld_bcst_frms_oflow << 32) |
2191 		    hw_info->rmac_vld_bcst_frms;
2192 		break;
2193 
2194 	case MAC_STAT_MULTIXMT:
2195 		*val = ((u64) hw_info->tmac_mcst_frms_oflow << 32) |
2196 		    hw_info->tmac_mcst_frms;
2197 		break;
2198 
2199 	case MAC_STAT_BRDCSTXMT:
2200 		*val = ((u64) hw_info->tmac_bcst_frms_oflow << 32) |
2201 		    hw_info->tmac_bcst_frms;
2202 		break;
2203 
2204 	case MAC_STAT_RBYTES:
2205 		*val = ((u64) hw_info->rmac_ttl_octets_oflow << 32) |
2206 		    hw_info->rmac_ttl_octets;
2207 		break;
2208 
2209 	case MAC_STAT_NORCVBUF:
2210 		*val = hw_info->rmac_drop_frms;
2211 		break;
2212 
2213 	case MAC_STAT_IERRORS:
2214 		*val = ((u64) hw_info->rmac_discarded_frms_oflow << 32) |
2215 		    hw_info->rmac_discarded_frms;
2216 		break;
2217 
2218 	case MAC_STAT_OBYTES:
2219 		*val = ((u64) hw_info->tmac_ttl_octets_oflow << 32) |
2220 		    hw_info->tmac_ttl_octets;
2221 		break;
2222 
2223 	case MAC_STAT_NOXMTBUF:
2224 		*val = hw_info->tmac_drop_frms;
2225 		break;
2226 
2227 	case MAC_STAT_OERRORS:
2228 		*val = ((u64) hw_info->tmac_any_err_frms_oflow << 32) |
2229 		    hw_info->tmac_any_err_frms;
2230 		break;
2231 
2232 	case MAC_STAT_IPACKETS:
2233 		*val = ((u64) hw_info->rmac_vld_frms_oflow << 32) |
2234 		    hw_info->rmac_vld_frms;
2235 		break;
2236 
2237 	case MAC_STAT_OPACKETS:
2238 		*val = ((u64) hw_info->tmac_frms_oflow << 32) |
2239 		    hw_info->tmac_frms;
2240 		break;
2241 
2242 	case ETHER_STAT_FCS_ERRORS:
2243 		*val = hw_info->rmac_fcs_err_frms;
2244 		break;
2245 
2246 	case ETHER_STAT_TOOLONG_ERRORS:
2247 		*val = hw_info->rmac_long_frms;
2248 		break;
2249 
2250 	case ETHER_STAT_LINK_DUPLEX:
2251 		*val = LINK_DUPLEX_FULL;
2252 		break;
2253 
2254 	default:
2255 		mutex_exit(&lldev->genlock);
2256 		return (ENOTSUP);
2257 	}
2258 
2259 	mutex_exit(&lldev->genlock);
2260 
2261 	return (0);
2262 }
2263 
2264 /*
2265  * xgell_device_alloc - Allocate new LL device
2266  */
2267 int
2268 xgell_device_alloc(xge_hal_device_h devh,
2269     dev_info_t *dev_info, xgelldev_t **lldev_out)
2270 {
2271 	xgelldev_t *lldev;
2272 	xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
2273 	int instance = ddi_get_instance(dev_info);
2274 
2275 	*lldev_out = NULL;
2276 
2277 	xge_debug_ll(XGE_TRACE, "trying to register etherenet device %s%d...",
2278 	    XGELL_IFNAME, instance);
2279 
2280 	lldev = kmem_zalloc(sizeof (xgelldev_t), KM_SLEEP);
2281 
2282 	lldev->devh = hldev;
2283 	lldev->instance = instance;
2284 	lldev->dev_info = dev_info;
2285 
2286 	*lldev_out = lldev;
2287 
2288 	ddi_set_driver_private(dev_info, (caddr_t)hldev);
2289 
2290 	return (DDI_SUCCESS);
2291 }
2292 
2293 /*
2294  * xgell_device_free
2295  */
2296 void
2297 xgell_device_free(xgelldev_t *lldev)
2298 {
2299 	xge_debug_ll(XGE_TRACE, "freeing device %s%d",
2300 	    XGELL_IFNAME, lldev->instance);
2301 
2302 	kmem_free(lldev, sizeof (xgelldev_t));
2303 }
2304 
2305 /*
2306  * xgell_ioctl
2307  */
2308 static void
2309 xgell_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
2310 {
2311 	xgelldev_t *lldev = arg;
2312 	struct iocblk *iocp;
2313 	int err = 0;
2314 	int cmd;
2315 	int need_privilege = 1;
2316 	int ret = 0;
2317 
2318 
2319 	iocp = (struct iocblk *)mp->b_rptr;
2320 	iocp->ioc_error = 0;
2321 	cmd = iocp->ioc_cmd;
2322 	xge_debug_ll(XGE_TRACE, "MAC_IOCTL cmd 0x%x", cmd);
2323 	switch (cmd) {
2324 	case ND_GET:
2325 		need_privilege = 0;
2326 		/* FALLTHRU */
2327 	case ND_SET:
2328 		break;
2329 	default:
2330 		xge_debug_ll(XGE_TRACE, "unknown cmd 0x%x", cmd);
2331 		miocnak(wq, mp, 0, EINVAL);
2332 		return;
2333 	}
2334 
2335 	if (need_privilege) {
2336 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
2337 		if (err != 0) {
2338 			xge_debug_ll(XGE_ERR,
2339 			    "drv_priv(): rejected cmd 0x%x, err %d",
2340 			    cmd, err);
2341 			miocnak(wq, mp, 0, err);
2342 			return;
2343 		}
2344 	}
2345 
2346 	switch (cmd) {
2347 	case ND_GET:
2348 		/*
2349 		 * If nd_getset() returns B_FALSE, the command was
2350 		 * not valid (e.g. unknown name), so we just tell the
2351 		 * top-level ioctl code to send a NAK (with code EINVAL).
2352 		 *
2353 		 * Otherwise, nd_getset() will have built the reply to
2354 		 * be sent (but not actually sent it), so we tell the
2355 		 * caller to send the prepared reply.
2356 		 */
2357 		ret = nd_getset(wq, lldev->ndp, mp);
2358 		xge_debug_ll(XGE_TRACE, "%s", "got ndd get ioctl");
2359 		break;
2360 
2361 	case ND_SET:
2362 		ret = nd_getset(wq, lldev->ndp, mp);
2363 		xge_debug_ll(XGE_TRACE, "%s", "got ndd set ioctl");
2364 		break;
2365 
2366 	default:
2367 		break;
2368 	}
2369 
2370 	if (ret == B_FALSE) {
2371 		xge_debug_ll(XGE_ERR,
2372 		    "nd_getset(): rejected cmd 0x%x, err %d",
2373 		    cmd, err);
2374 		miocnak(wq, mp, 0, EINVAL);
2375 	} else {
2376 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
2377 		    M_IOCACK : M_IOCNAK;
2378 		qreply(wq, mp);
2379 	}
2380 }
2381 
2382 
2383 static boolean_t
2384 xgell_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
2385 {
2386 	xgelldev_t *lldev = arg;
2387 
2388 	xge_debug_ll(XGE_TRACE, "xgell_m_getcapab: %x", cap);
2389 
2390 	switch (cap) {
2391 	case MAC_CAPAB_HCKSUM: {
2392 		uint32_t *hcksum_txflags = cap_data;
2393 		*hcksum_txflags = HCKSUM_INET_FULL_V4 | HCKSUM_INET_FULL_V6 |
2394 		    HCKSUM_IPHDRCKSUM;
2395 		break;
2396 	}
2397 	case MAC_CAPAB_LSO: {
2398 		mac_capab_lso_t *cap_lso = cap_data;
2399 
2400 		if (lldev->config.lso_enable) {
2401 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
2402 			cap_lso->lso_basic_tcp_ipv4.lso_max = XGELL_LSO_MAXLEN;
2403 			break;
2404 		} else {
2405 			return (B_FALSE);
2406 		}
2407 	}
2408 	case MAC_CAPAB_RINGS: {
2409 		mac_capab_rings_t *cap_rings = cap_data;
2410 
2411 		switch (cap_rings->mr_type) {
2412 		case MAC_RING_TYPE_RX:
2413 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
2414 			cap_rings->mr_rnum = lldev->init_rx_rings;
2415 			cap_rings->mr_gnum = lldev->init_rx_groups;
2416 			cap_rings->mr_rget = xgell_fill_ring;
2417 			cap_rings->mr_gget = xgell_fill_group;
2418 			break;
2419 		case MAC_RING_TYPE_TX:
2420 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
2421 			cap_rings->mr_rnum = lldev->init_tx_rings;
2422 			cap_rings->mr_gnum = 0;
2423 			cap_rings->mr_rget = xgell_fill_ring;
2424 			cap_rings->mr_gget = NULL;
2425 			break;
2426 		default:
2427 			break;
2428 		}
2429 		break;
2430 	}
2431 	default:
2432 		return (B_FALSE);
2433 	}
2434 	return (B_TRUE);
2435 }
2436 
2437 static int
2438 xgell_stats_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2439 {
2440 	xgelldev_t *lldev = (xgelldev_t *)cp;
2441 	xge_hal_status_e status;
2442 	int count = 0, retsize;
2443 	char *buf;
2444 
2445 	buf = kmem_alloc(XGELL_STATS_BUFSIZE, KM_SLEEP);
2446 	if (buf == NULL) {
2447 		return (ENOSPC);
2448 	}
2449 
2450 	status = xge_hal_aux_stats_tmac_read(lldev->devh, XGELL_STATS_BUFSIZE,
2451 	    buf, &retsize);
2452 	if (status != XGE_HAL_OK) {
2453 		kmem_free(buf, XGELL_STATS_BUFSIZE);
2454 		xge_debug_ll(XGE_ERR, "tmac_read(): status %d", status);
2455 		return (EINVAL);
2456 	}
2457 	count += retsize;
2458 
2459 	status = xge_hal_aux_stats_rmac_read(lldev->devh,
2460 	    XGELL_STATS_BUFSIZE - count,
2461 	    buf+count, &retsize);
2462 	if (status != XGE_HAL_OK) {
2463 		kmem_free(buf, XGELL_STATS_BUFSIZE);
2464 		xge_debug_ll(XGE_ERR, "rmac_read(): status %d", status);
2465 		return (EINVAL);
2466 	}
2467 	count += retsize;
2468 
2469 	status = xge_hal_aux_stats_pci_read(lldev->devh,
2470 	    XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
2471 	if (status != XGE_HAL_OK) {
2472 		kmem_free(buf, XGELL_STATS_BUFSIZE);
2473 		xge_debug_ll(XGE_ERR, "pci_read(): status %d", status);
2474 		return (EINVAL);
2475 	}
2476 	count += retsize;
2477 
2478 	status = xge_hal_aux_stats_sw_dev_read(lldev->devh,
2479 	    XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
2480 	if (status != XGE_HAL_OK) {
2481 		kmem_free(buf, XGELL_STATS_BUFSIZE);
2482 		xge_debug_ll(XGE_ERR, "sw_dev_read(): status %d", status);
2483 		return (EINVAL);
2484 	}
2485 	count += retsize;
2486 
2487 	status = xge_hal_aux_stats_hal_read(lldev->devh,
2488 	    XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
2489 	if (status != XGE_HAL_OK) {
2490 		kmem_free(buf, XGELL_STATS_BUFSIZE);
2491 		xge_debug_ll(XGE_ERR, "pci_read(): status %d", status);
2492 		return (EINVAL);
2493 	}
2494 	count += retsize;
2495 
2496 	*(buf + count - 1) = '\0'; /* remove last '\n' */
2497 	(void) mi_mpprintf(mp, "%s", buf);
2498 	kmem_free(buf, XGELL_STATS_BUFSIZE);
2499 
2500 	return (0);
2501 }
2502 
2503 static int
2504 xgell_pciconf_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2505 {
2506 	xgelldev_t *lldev = (xgelldev_t *)cp;
2507 	xge_hal_status_e status;
2508 	int retsize;
2509 	char *buf;
2510 
2511 	buf = kmem_alloc(XGELL_PCICONF_BUFSIZE, KM_SLEEP);
2512 	if (buf == NULL) {
2513 		return (ENOSPC);
2514 	}
2515 	status = xge_hal_aux_pci_config_read(lldev->devh, XGELL_PCICONF_BUFSIZE,
2516 	    buf, &retsize);
2517 	if (status != XGE_HAL_OK) {
2518 		kmem_free(buf, XGELL_PCICONF_BUFSIZE);
2519 		xge_debug_ll(XGE_ERR, "pci_config_read(): status %d", status);
2520 		return (EINVAL);
2521 	}
2522 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
2523 	(void) mi_mpprintf(mp, "%s", buf);
2524 	kmem_free(buf, XGELL_PCICONF_BUFSIZE);
2525 
2526 	return (0);
2527 }
2528 
2529 static int
2530 xgell_about_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2531 {
2532 	xgelldev_t *lldev = (xgelldev_t *)cp;
2533 	xge_hal_status_e status;
2534 	int retsize;
2535 	char *buf;
2536 
2537 	buf = kmem_alloc(XGELL_ABOUT_BUFSIZE, KM_SLEEP);
2538 	if (buf == NULL) {
2539 		return (ENOSPC);
2540 	}
2541 	status = xge_hal_aux_about_read(lldev->devh, XGELL_ABOUT_BUFSIZE,
2542 	    buf, &retsize);
2543 	if (status != XGE_HAL_OK) {
2544 		kmem_free(buf, XGELL_ABOUT_BUFSIZE);
2545 		xge_debug_ll(XGE_ERR, "about_read(): status %d", status);
2546 		return (EINVAL);
2547 	}
2548 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
2549 	(void) mi_mpprintf(mp, "%s", buf);
2550 	kmem_free(buf, XGELL_ABOUT_BUFSIZE);
2551 
2552 	return (0);
2553 }
2554 
2555 static unsigned long bar0_offset = 0x110; /* adapter_control */
2556 
2557 static int
2558 xgell_bar0_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2559 {
2560 	xgelldev_t *lldev = (xgelldev_t *)cp;
2561 	xge_hal_status_e status;
2562 	int retsize;
2563 	char *buf;
2564 
2565 	buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
2566 	if (buf == NULL) {
2567 		return (ENOSPC);
2568 	}
2569 	status = xge_hal_aux_bar0_read(lldev->devh, bar0_offset,
2570 	    XGELL_IOCTL_BUFSIZE, buf, &retsize);
2571 	if (status != XGE_HAL_OK) {
2572 		kmem_free(buf, XGELL_IOCTL_BUFSIZE);
2573 		xge_debug_ll(XGE_ERR, "bar0_read(): status %d", status);
2574 		return (EINVAL);
2575 	}
2576 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
2577 	(void) mi_mpprintf(mp, "%s", buf);
2578 	kmem_free(buf, XGELL_IOCTL_BUFSIZE);
2579 
2580 	return (0);
2581 }
2582 
2583 static int
2584 xgell_bar0_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *credp)
2585 {
2586 	unsigned long old_offset = bar0_offset;
2587 	char *end;
2588 
2589 	if (value && *value == '0' &&
2590 	    (*(value + 1) == 'x' || *(value + 1) == 'X')) {
2591 		value += 2;
2592 	}
2593 
2594 	bar0_offset = mi_strtol(value, &end, 16);
2595 	if (end == value) {
2596 		bar0_offset = old_offset;
2597 		return (EINVAL);
2598 	}
2599 
2600 	xge_debug_ll(XGE_TRACE, "bar0: new value %s:%lX", value, bar0_offset);
2601 
2602 	return (0);
2603 }
2604 
2605 static int
2606 xgell_debug_level_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2607 {
2608 	char *buf;
2609 
2610 	buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
2611 	if (buf == NULL) {
2612 		return (ENOSPC);
2613 	}
2614 	(void) mi_mpprintf(mp, "debug_level %d", xge_hal_driver_debug_level());
2615 	kmem_free(buf, XGELL_IOCTL_BUFSIZE);
2616 
2617 	return (0);
2618 }
2619 
2620 static int
2621 xgell_debug_level_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
2622     cred_t *credp)
2623 {
2624 	int level;
2625 	char *end;
2626 
2627 	level = mi_strtol(value, &end, 10);
2628 	if (level < XGE_NONE || level > XGE_ERR || end == value) {
2629 		return (EINVAL);
2630 	}
2631 
2632 	xge_hal_driver_debug_level_set(level);
2633 
2634 	return (0);
2635 }
2636 
2637 static int
2638 xgell_debug_module_mask_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2639 {
2640 	char *buf;
2641 
2642 	buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
2643 	if (buf == NULL) {
2644 		return (ENOSPC);
2645 	}
2646 	(void) mi_mpprintf(mp, "debug_module_mask 0x%08x",
2647 	    xge_hal_driver_debug_module_mask());
2648 	kmem_free(buf, XGELL_IOCTL_BUFSIZE);
2649 
2650 	return (0);
2651 }
2652 
2653 static int
2654 xgell_debug_module_mask_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
2655 			    cred_t *credp)
2656 {
2657 	u32 mask;
2658 	char *end;
2659 
2660 	if (value && *value == '0' &&
2661 	    (*(value + 1) == 'x' || *(value + 1) == 'X')) {
2662 		value += 2;
2663 	}
2664 
2665 	mask = mi_strtol(value, &end, 16);
2666 	if (end == value) {
2667 		return (EINVAL);
2668 	}
2669 
2670 	xge_hal_driver_debug_module_mask_set(mask);
2671 
2672 	return (0);
2673 }
2674 
2675 static int
2676 xgell_devconfig_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2677 {
2678 	xgelldev_t *lldev = (xgelldev_t *)(void *)cp;
2679 	xge_hal_status_e status;
2680 	int retsize;
2681 	char *buf;
2682 
2683 	buf = kmem_alloc(XGELL_DEVCONF_BUFSIZE, KM_SLEEP);
2684 	if (buf == NULL) {
2685 		return (ENOSPC);
2686 	}
2687 	status = xge_hal_aux_device_config_read(lldev->devh,
2688 	    XGELL_DEVCONF_BUFSIZE, buf, &retsize);
2689 	if (status != XGE_HAL_OK) {
2690 		kmem_free(buf, XGELL_DEVCONF_BUFSIZE);
2691 		xge_debug_ll(XGE_ERR, "device_config_read(): status %d",
2692 		    status);
2693 		return (EINVAL);
2694 	}
2695 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
2696 	(void) mi_mpprintf(mp, "%s", buf);
2697 	kmem_free(buf, XGELL_DEVCONF_BUFSIZE);
2698 
2699 	return (0);
2700 }
2701 
2702 /*
2703  * xgell_device_register
2704  * @devh: pointer on HAL device
2705  * @config: pointer on this network device configuration
2706  * @ll_out: output pointer. Will be assigned to valid LL device.
2707  *
2708  * This function will allocate and register network device
2709  */
2710 int
2711 xgell_device_register(xgelldev_t *lldev, xgell_config_t *config)
2712 {
2713 	mac_register_t *macp = NULL;
2714 	xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
2715 
2716 	/*
2717 	 * Initialize some NDD interface for internal debug.
2718 	 */
2719 	if (nd_load(&lldev->ndp, "pciconf", xgell_pciconf_get, NULL,
2720 	    (caddr_t)lldev) == B_FALSE)
2721 		goto xgell_ndd_fail;
2722 
2723 	if (nd_load(&lldev->ndp, "about", xgell_about_get, NULL,
2724 	    (caddr_t)lldev) == B_FALSE)
2725 		goto xgell_ndd_fail;
2726 
2727 	if (nd_load(&lldev->ndp, "stats", xgell_stats_get, NULL,
2728 	    (caddr_t)lldev) == B_FALSE)
2729 		goto xgell_ndd_fail;
2730 
2731 	if (nd_load(&lldev->ndp, "bar0", xgell_bar0_get, xgell_bar0_set,
2732 	    (caddr_t)lldev) == B_FALSE)
2733 		goto xgell_ndd_fail;
2734 
2735 	if (nd_load(&lldev->ndp, "debug_level", xgell_debug_level_get,
2736 	    xgell_debug_level_set, (caddr_t)lldev) == B_FALSE)
2737 		goto xgell_ndd_fail;
2738 
2739 	if (nd_load(&lldev->ndp, "debug_module_mask",
2740 	    xgell_debug_module_mask_get, xgell_debug_module_mask_set,
2741 	    (caddr_t)lldev) == B_FALSE)
2742 		goto xgell_ndd_fail;
2743 
2744 	if (nd_load(&lldev->ndp, "devconfig", xgell_devconfig_get, NULL,
2745 	    (caddr_t)lldev) == B_FALSE)
2746 		goto xgell_ndd_fail;
2747 
2748 	bcopy(config, &lldev->config, sizeof (xgell_config_t));
2749 
2750 	mutex_init(&lldev->genlock, NULL, MUTEX_DRIVER,
2751 	    DDI_INTR_PRI(hldev->irqh));
2752 
2753 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
2754 		goto xgell_register_fail;
2755 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2756 	macp->m_driver = lldev;
2757 	macp->m_dip = lldev->dev_info;
2758 	macp->m_src_addr = hldev->macaddr[0];
2759 	macp->m_callbacks = &xgell_m_callbacks;
2760 	macp->m_min_sdu = 0;
2761 	macp->m_max_sdu = hldev->config.mtu;
2762 	macp->m_margin = VLAN_TAGSZ;
2763 	macp->m_v12n = MAC_VIRT_LEVEL1;
2764 
2765 	/*
2766 	 * MAC Registration.
2767 	 */
2768 	if (mac_register(macp, &lldev->mh) != 0)
2769 		goto xgell_register_fail;
2770 
2771 	/* Always free the macp after register */
2772 	if (macp != NULL)
2773 		mac_free(macp);
2774 
2775 	/* Calculate tx_copied_max here ??? */
2776 	lldev->tx_copied_max = hldev->config.fifo.max_frags *
2777 	    hldev->config.fifo.alignment_size *
2778 	    hldev->config.fifo.max_aligned_frags;
2779 
2780 	xge_debug_ll(XGE_TRACE, "etherenet device %s%d registered",
2781 	    XGELL_IFNAME, lldev->instance);
2782 
2783 	return (DDI_SUCCESS);
2784 
2785 xgell_ndd_fail:
2786 	nd_free(&lldev->ndp);
2787 	xge_debug_ll(XGE_ERR, "%s", "unable to load ndd parameter");
2788 	return (DDI_FAILURE);
2789 
2790 xgell_register_fail:
2791 	if (macp != NULL)
2792 		mac_free(macp);
2793 	nd_free(&lldev->ndp);
2794 	mutex_destroy(&lldev->genlock);
2795 	xge_debug_ll(XGE_ERR, "%s", "unable to register networking device");
2796 	return (DDI_FAILURE);
2797 }
2798 
2799 /*
2800  * xgell_device_unregister
2801  * @devh: pointer on HAL device
2802  * @lldev: pointer to valid LL device.
2803  *
2804  * This function will unregister and free network device
2805  */
2806 int
2807 xgell_device_unregister(xgelldev_t *lldev)
2808 {
2809 	if (mac_unregister(lldev->mh) != 0) {
2810 		xge_debug_ll(XGE_ERR, "unable to unregister device %s%d",
2811 		    XGELL_IFNAME, lldev->instance);
2812 		return (DDI_FAILURE);
2813 	}
2814 
2815 	mutex_destroy(&lldev->genlock);
2816 
2817 	nd_free(&lldev->ndp);
2818 
2819 	xge_debug_ll(XGE_TRACE, "etherenet device %s%d unregistered",
2820 	    XGELL_IFNAME, lldev->instance);
2821 
2822 	return (DDI_SUCCESS);
2823 }
2824