xref: /illumos-gate/usr/src/uts/common/io/nge/nge_main.c (revision 51fc88a8)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include "nge.h"
29 
30 /*
31  * Describes the chip's DMA engine
32  */
33 
34 static ddi_dma_attr_t hot_dma_attr = {
35 	DMA_ATTR_V0,			/* dma_attr version	*/
36 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
37 	0x000000FFFFFFFFFFull,		/* dma_attr_addr_hi	*/
38 	0x000000007FFFFFFFull,		/* dma_attr_count_max	*/
39 	0x0000000000000010ull,		/* dma_attr_align	*/
40 	0x00000FFF,			/* dma_attr_burstsizes	*/
41 	0x00000001,			/* dma_attr_minxfer	*/
42 	0x000000000000FFFFull,		/* dma_attr_maxxfer	*/
43 	0x000000FFFFFFFFFFull,		/* dma_attr_seg		*/
44 	1,				/* dma_attr_sgllen 	*/
45 	0x00000001,			/* dma_attr_granular 	*/
46 	0
47 };
48 
49 static ddi_dma_attr_t hot_tx_dma_attr = {
50 	DMA_ATTR_V0,			/* dma_attr version	*/
51 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
52 	0x000000FFFFFFFFFFull,		/* dma_attr_addr_hi	*/
53 	0x0000000000003FFFull,		/* dma_attr_count_max	*/
54 	0x0000000000000010ull,		/* dma_attr_align	*/
55 	0x00000FFF,			/* dma_attr_burstsizes	*/
56 	0x00000001,			/* dma_attr_minxfer	*/
57 	0x0000000000003FFFull,		/* dma_attr_maxxfer	*/
58 	0x000000FFFFFFFFFFull,		/* dma_attr_seg		*/
59 	NGE_MAX_COOKIES,		/* dma_attr_sgllen 	*/
60 	1,				/* dma_attr_granular 	*/
61 	0
62 };
63 
64 static ddi_dma_attr_t sum_dma_attr = {
65 	DMA_ATTR_V0,			/* dma_attr version	*/
66 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
67 	0x00000000FFFFFFFFull,		/* dma_attr_addr_hi	*/
68 	0x000000007FFFFFFFull,		/* dma_attr_count_max	*/
69 	0x0000000000000010ull,		/* dma_attr_align	*/
70 	0x00000FFF,			/* dma_attr_burstsizes	*/
71 	0x00000001,			/* dma_attr_minxfer	*/
72 	0x000000000000FFFFull,		/* dma_attr_maxxfer	*/
73 	0x00000000FFFFFFFFull,		/* dma_attr_seg		*/
74 	1,				/* dma_attr_sgllen 	*/
75 	0x00000001,			/* dma_attr_granular 	*/
76 	0
77 };
78 
79 static ddi_dma_attr_t sum_tx_dma_attr = {
80 	DMA_ATTR_V0,			/* dma_attr version	*/
81 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
82 	0x00000000FFFFFFFFull,		/* dma_attr_addr_hi	*/
83 	0x0000000000003FFFull,		/* dma_attr_count_max	*/
84 	0x0000000000000010ull,		/* dma_attr_align	*/
85 	0x00000FFF,			/* dma_attr_burstsizes	*/
86 	0x00000001,			/* dma_attr_minxfer	*/
87 	0x0000000000003FFFull,		/* dma_attr_maxxfer	*/
88 	0x00000000FFFFFFFFull,		/* dma_attr_seg		*/
89 	NGE_MAX_COOKIES,		/* dma_attr_sgllen 	*/
90 	1,				/* dma_attr_granular 	*/
91 	0
92 };
93 
94 /*
95  * DMA access attributes for data.
96  */
97 ddi_device_acc_attr_t nge_data_accattr = {
98 	DDI_DEVICE_ATTR_V0,
99 	DDI_STRUCTURE_LE_ACC,
100 	DDI_STRICTORDER_ACC,
101 	DDI_DEFAULT_ACC
102 };
103 
104 /*
105  * DMA access attributes for descriptors.
106  */
107 static ddi_device_acc_attr_t nge_desc_accattr = {
108 	DDI_DEVICE_ATTR_V0,
109 	DDI_STRUCTURE_LE_ACC,
110 	DDI_STRICTORDER_ACC,
111 	DDI_DEFAULT_ACC
112 };
113 
114 /*
115  * PIO access attributes for registers
116  */
117 static ddi_device_acc_attr_t nge_reg_accattr = {
118 	DDI_DEVICE_ATTR_V0,
119 	DDI_STRUCTURE_LE_ACC,
120 	DDI_STRICTORDER_ACC,
121 	DDI_DEFAULT_ACC
122 };
123 
124 /*
125  * NIC DESC MODE 2
126  */
127 
128 static const nge_desc_attr_t nge_sum_desc = {
129 
130 	sizeof (sum_rx_bd),
131 	sizeof (sum_tx_bd),
132 	&sum_dma_attr,
133 	&sum_tx_dma_attr,
134 	nge_sum_rxd_fill,
135 	nge_sum_rxd_check,
136 	nge_sum_txd_fill,
137 	nge_sum_txd_check,
138 };
139 
140 /*
141  * NIC DESC MODE 3
142  */
143 
144 static const nge_desc_attr_t nge_hot_desc = {
145 
146 	sizeof (hot_rx_bd),
147 	sizeof (hot_tx_bd),
148 	&hot_dma_attr,
149 	&hot_tx_dma_attr,
150 	nge_hot_rxd_fill,
151 	nge_hot_rxd_check,
152 	nge_hot_txd_fill,
153 	nge_hot_txd_check,
154 };
155 
156 static char nge_ident[] = "nVidia 1Gb Ethernet";
157 static char clsize_propname[] = "cache-line-size";
158 static char latency_propname[] = "latency-timer";
159 static char debug_propname[]	= "nge-debug-flags";
160 static char intr_moderation[] = "intr-moderation";
161 static char rx_data_hw[] = "rx-data-hw";
162 static char rx_prd_lw[] = "rx-prd-lw";
163 static char rx_prd_hw[] = "rx-prd-hw";
164 static char sw_intr_intv[] = "sw-intr-intvl";
165 static char nge_desc_mode[] = "desc-mode";
166 static char default_mtu[] = "default_mtu";
167 static char low_memory_mode[] = "minimal-memory-usage";
168 extern kmutex_t nge_log_mutex[1];
169 
170 static int		nge_m_start(void *);
171 static void		nge_m_stop(void *);
172 static int		nge_m_promisc(void *, boolean_t);
173 static int		nge_m_multicst(void *, boolean_t, const uint8_t *);
174 static int		nge_m_unicst(void *, const uint8_t *);
175 static void		nge_m_ioctl(void *, queue_t *, mblk_t *);
176 static boolean_t	nge_m_getcapab(void *, mac_capab_t, void *);
177 static int		nge_m_setprop(void *, const char *, mac_prop_id_t,
178 	uint_t, const void *);
179 static int		nge_m_getprop(void *, const char *, mac_prop_id_t,
180 	uint_t, uint_t, void *, uint_t *);
181 static int		nge_set_priv_prop(nge_t *, const char *, uint_t,
182 	const void *);
183 static int		nge_get_priv_prop(nge_t *, const char *, uint_t,
184 	uint_t, void *);
185 
186 #define		NGE_M_CALLBACK_FLAGS\
187 		(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP)
188 
189 static mac_callbacks_t nge_m_callbacks = {
190 	NGE_M_CALLBACK_FLAGS,
191 	nge_m_stat,
192 	nge_m_start,
193 	nge_m_stop,
194 	nge_m_promisc,
195 	nge_m_multicst,
196 	nge_m_unicst,
197 	nge_m_tx,
198 	nge_m_ioctl,
199 	nge_m_getcapab,
200 	NULL,
201 	NULL,
202 	nge_m_setprop,
203 	nge_m_getprop
204 };
205 
206 mac_priv_prop_t nge_priv_props[] = {
207 	{"_tx_bcopy_threshold", MAC_PROP_PERM_RW},
208 	{"_rx_bcopy_threshold", MAC_PROP_PERM_RW},
209 	{"_recv_max_packet", MAC_PROP_PERM_RW},
210 	{"_poll_quiet_time", MAC_PROP_PERM_RW},
211 	{"_poll_busy_time", MAC_PROP_PERM_RW},
212 	{"_rx_intr_hwater", MAC_PROP_PERM_RW},
213 	{"_rx_intr_lwater", MAC_PROP_PERM_RW},
214 };
215 
216 #define	NGE_MAX_PRIV_PROPS \
217 	(sizeof (nge_priv_props)/sizeof (mac_priv_prop_t))
218 
219 static int nge_add_intrs(nge_t *, int);
220 static void nge_rem_intrs(nge_t *);
221 static int nge_register_intrs_and_init_locks(nge_t *);
222 
223 /*
224  * NGE MSI tunable:
225  */
226 boolean_t nge_enable_msi = B_FALSE;
227 
228 static enum ioc_reply
229 nge_set_loop_mode(nge_t *ngep, uint32_t mode)
230 {
231 	/*
232 	 * If the mode isn't being changed, there's nothing to do ...
233 	 */
234 	if (mode == ngep->param_loop_mode)
235 		return (IOC_ACK);
236 
237 	/*
238 	 * Validate the requested mode and prepare a suitable message
239 	 * to explain the link down/up cycle that the change will
240 	 * probably induce ...
241 	 */
242 	switch (mode) {
243 	default:
244 		return (IOC_INVAL);
245 
246 	case NGE_LOOP_NONE:
247 	case NGE_LOOP_EXTERNAL_100:
248 	case NGE_LOOP_EXTERNAL_10:
249 	case NGE_LOOP_INTERNAL_PHY:
250 		break;
251 	}
252 
253 	/*
254 	 * All OK; tell the caller to reprogram
255 	 * the PHY and/or MAC for the new mode ...
256 	 */
257 	ngep->param_loop_mode = mode;
258 	return (IOC_RESTART_ACK);
259 }
260 
261 #undef	NGE_DBG
262 #define	NGE_DBG		NGE_DBG_INIT
263 
264 /*
265  * Utility routine to carve a slice off a chunk of allocated memory,
266  * updating the chunk descriptor accordingly.  The size of the slice
267  * is given by the product of the <qty> and <size> parameters.
268  */
269 void
270 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk,
271     uint32_t qty, uint32_t size)
272 {
273 	size_t totsize;
274 
275 	totsize = qty*size;
276 	ASSERT(size > 0);
277 	ASSERT(totsize <= chunk->alength);
278 
279 	*slice = *chunk;
280 	slice->nslots = qty;
281 	slice->size = size;
282 	slice->alength = totsize;
283 
284 	chunk->mem_va = (caddr_t)chunk->mem_va + totsize;
285 	chunk->alength -= totsize;
286 	chunk->offset += totsize;
287 	chunk->cookie.dmac_laddress += totsize;
288 	chunk->cookie.dmac_size -= totsize;
289 }
290 
291 /*
292  * Allocate an area of memory and a DMA handle for accessing it
293  */
294 int
295 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p,
296     uint_t dma_flags, dma_area_t *dma_p)
297 {
298 	int err;
299 	caddr_t va;
300 
301 	NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)",
302 	    (void *)ngep, memsize, attr_p, dma_flags, dma_p));
303 	/*
304 	 * Allocate handle
305 	 */
306 	err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr,
307 	    DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl);
308 	if (err != DDI_SUCCESS)
309 		goto fail;
310 
311 	/*
312 	 * Allocate memory
313 	 */
314 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
315 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
316 	    DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl);
317 	if (err != DDI_SUCCESS)
318 		goto fail;
319 
320 	/*
321 	 * Bind the two together
322 	 */
323 	dma_p->mem_va = va;
324 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
325 	    va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL,
326 	    &dma_p->cookie, &dma_p->ncookies);
327 
328 	if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1)
329 		goto fail;
330 
331 	dma_p->nslots = ~0U;
332 	dma_p->size = ~0U;
333 	dma_p->offset = 0;
334 
335 	return (DDI_SUCCESS);
336 
337 fail:
338 	nge_free_dma_mem(dma_p);
339 	NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!"));
340 
341 	return (DDI_FAILURE);
342 }
343 
344 /*
345  * Free one allocated area of DMAable memory
346  */
347 void
348 nge_free_dma_mem(dma_area_t *dma_p)
349 {
350 	if (dma_p->dma_hdl != NULL) {
351 		if (dma_p->ncookies) {
352 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
353 			dma_p->ncookies = 0;
354 		}
355 	}
356 	if (dma_p->acc_hdl != NULL) {
357 		ddi_dma_mem_free(&dma_p->acc_hdl);
358 		dma_p->acc_hdl = NULL;
359 	}
360 	if (dma_p->dma_hdl != NULL) {
361 		ddi_dma_free_handle(&dma_p->dma_hdl);
362 		dma_p->dma_hdl = NULL;
363 	}
364 }
365 
366 #define	ALLOC_TX_BUF	0x1
367 #define	ALLOC_TX_DESC	0x2
368 #define	ALLOC_RX_DESC	0x4
369 
370 int
371 nge_alloc_bufs(nge_t *ngep)
372 {
373 	int err;
374 	int split;
375 	int progress;
376 	size_t txbuffsize;
377 	size_t rxdescsize;
378 	size_t txdescsize;
379 
380 	txbuffsize = ngep->tx_desc * ngep->buf_size;
381 	rxdescsize = ngep->rx_desc;
382 	txdescsize = ngep->tx_desc;
383 	rxdescsize *= ngep->desc_attr.rxd_size;
384 	txdescsize *= ngep->desc_attr.txd_size;
385 	progress = 0;
386 
387 	NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep));
388 	/*
389 	 * Allocate memory & handles for TX buffers
390 	 */
391 	ASSERT((txbuffsize % ngep->nge_split) == 0);
392 	for (split = 0; split < ngep->nge_split; ++split) {
393 		err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split,
394 		    &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE,
395 		    &ngep->send->buf[split]);
396 		if (err != DDI_SUCCESS)
397 			goto fail;
398 	}
399 
400 	progress |= ALLOC_TX_BUF;
401 
402 	/*
403 	 * Allocate memory & handles for receive return rings and
404 	 * buffer (producer) descriptor rings
405 	 */
406 	err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr,
407 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc);
408 	if (err != DDI_SUCCESS)
409 		goto fail;
410 	progress |= ALLOC_RX_DESC;
411 
412 	/*
413 	 * Allocate memory & handles for TX descriptor rings,
414 	 */
415 	err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr,
416 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc);
417 	if (err != DDI_SUCCESS)
418 		goto fail;
419 	return (DDI_SUCCESS);
420 
421 fail:
422 	if (progress & ALLOC_RX_DESC)
423 		nge_free_dma_mem(&ngep->recv->desc);
424 	if (progress & ALLOC_TX_BUF) {
425 		for (split = 0; split < ngep->nge_split; ++split)
426 			nge_free_dma_mem(&ngep->send->buf[split]);
427 	}
428 
429 	return (DDI_FAILURE);
430 }
431 
432 /*
433  * This routine frees the transmit and receive buffers and descriptors.
434  * Make sure the chip is stopped before calling it!
435  */
436 void
437 nge_free_bufs(nge_t *ngep)
438 {
439 	int split;
440 
441 	NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep));
442 
443 	nge_free_dma_mem(&ngep->recv->desc);
444 	nge_free_dma_mem(&ngep->send->desc);
445 
446 	for (split = 0; split < ngep->nge_split; ++split)
447 		nge_free_dma_mem(&ngep->send->buf[split]);
448 }
449 
450 /*
451  * Clean up initialisation done above before the memory is freed
452  */
453 static void
454 nge_fini_send_ring(nge_t *ngep)
455 {
456 	uint32_t slot;
457 	size_t dmah_num;
458 	send_ring_t *srp;
459 	sw_tx_sbd_t *ssbdp;
460 
461 	srp = ngep->send;
462 	ssbdp = srp->sw_sbds;
463 
464 	NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep));
465 
466 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
467 
468 	for (slot = 0; slot < dmah_num; ++slot) {
469 		if (srp->dmahndl[slot].hndl) {
470 			(void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl);
471 			ddi_dma_free_handle(&srp->dmahndl[slot].hndl);
472 			srp->dmahndl[slot].hndl = NULL;
473 			srp->dmahndl[slot].next = NULL;
474 		}
475 	}
476 
477 	srp->dmah_free.head = NULL;
478 	srp->dmah_free.tail = NULL;
479 
480 	kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp));
481 
482 }
483 
484 /*
485  * Initialise the specified Send Ring, using the information in the
486  * <dma_area> descriptors that it contains to set up all the other
487  * fields. This routine should be called only once for each ring.
488  */
489 static int
490 nge_init_send_ring(nge_t *ngep)
491 {
492 	size_t dmah_num;
493 	uint32_t nslots;
494 	uint32_t err;
495 	uint32_t slot;
496 	uint32_t split;
497 	send_ring_t *srp;
498 	sw_tx_sbd_t *ssbdp;
499 	dma_area_t desc;
500 	dma_area_t pbuf;
501 
502 	srp = ngep->send;
503 	srp->desc.nslots = ngep->tx_desc;
504 	nslots = srp->desc.nslots;
505 
506 	NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep));
507 	/*
508 	 * Other one-off initialisation of per-ring data
509 	 */
510 	srp->ngep = ngep;
511 
512 	/*
513 	 * Allocate the array of s/w Send Buffer Descriptors
514 	 */
515 	ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP);
516 	srp->sw_sbds = ssbdp;
517 
518 	/*
519 	 * Now initialise each array element once and for all
520 	 */
521 	desc = srp->desc;
522 	for (split = 0; split < ngep->nge_split; ++split) {
523 		pbuf = srp->buf[split];
524 		for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) {
525 			nge_slice_chunk(&ssbdp->desc, &desc, 1,
526 			    ngep->desc_attr.txd_size);
527 			nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1,
528 			    ngep->buf_size);
529 		}
530 		ASSERT(pbuf.alength == 0);
531 	}
532 	ASSERT(desc.alength == 0);
533 
534 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
535 
536 	/* preallocate dma handles for tx buffer */
537 	for (slot = 0; slot < dmah_num; ++slot) {
538 
539 		err = ddi_dma_alloc_handle(ngep->devinfo,
540 		    ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT,
541 		    NULL, &srp->dmahndl[slot].hndl);
542 
543 		if (err != DDI_SUCCESS) {
544 			nge_fini_send_ring(ngep);
545 			nge_error(ngep,
546 			    "nge_init_send_ring: alloc dma handle fails");
547 			return (DDI_FAILURE);
548 		}
549 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
550 	}
551 
552 	srp->dmah_free.head = srp->dmahndl;
553 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
554 	srp->dmah_free.tail->next = NULL;
555 
556 	return (DDI_SUCCESS);
557 }
558 
559 /*
560  * Intialize the tx recycle pointer and tx sending pointer of tx ring
561  * and set the type of tx's data descriptor by default.
562  */
563 static void
564 nge_reinit_send_ring(nge_t *ngep)
565 {
566 	size_t dmah_num;
567 	uint32_t slot;
568 	send_ring_t *srp;
569 	sw_tx_sbd_t *ssbdp;
570 
571 	srp = ngep->send;
572 
573 	/*
574 	 * Reinitialise control variables ...
575 	 */
576 
577 	srp->tx_hwmark = NGE_DESC_MIN;
578 	srp->tx_lwmark = NGE_DESC_MIN;
579 
580 	srp->tx_next = 0;
581 	srp->tx_free = srp->desc.nslots;
582 	srp->tc_next = 0;
583 
584 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
585 
586 	for (slot = 0; slot - dmah_num != 0; ++slot)
587 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
588 
589 	srp->dmah_free.head = srp->dmahndl;
590 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
591 	srp->dmah_free.tail->next = NULL;
592 
593 	/*
594 	 * Zero and sync all the h/w Send Buffer Descriptors
595 	 */
596 	for (slot = 0; slot < srp->desc.nslots; ++slot) {
597 		ssbdp = &srp->sw_sbds[slot];
598 		ssbdp->flags = HOST_OWN;
599 	}
600 
601 	DMA_ZERO(srp->desc);
602 	DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV);
603 }
604 
605 /*
606  * Initialize the slot number of rx's ring
607  */
608 static void
609 nge_init_recv_ring(nge_t *ngep)
610 {
611 	recv_ring_t *rrp;
612 
613 	rrp = ngep->recv;
614 	rrp->desc.nslots = ngep->rx_desc;
615 	rrp->ngep = ngep;
616 }
617 
618 /*
619  * Intialize the rx recycle pointer and rx sending pointer of rx ring
620  */
621 static void
622 nge_reinit_recv_ring(nge_t *ngep)
623 {
624 	recv_ring_t *rrp;
625 
626 	rrp = ngep->recv;
627 
628 	/*
629 	 * Reinitialise control variables ...
630 	 */
631 	rrp->prod_index = 0;
632 	/*
633 	 * Zero and sync all the h/w Send Buffer Descriptors
634 	 */
635 	DMA_ZERO(rrp->desc);
636 	DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV);
637 }
638 
639 /*
640  * Clean up initialisation done above before the memory is freed
641  */
642 static void
643 nge_fini_buff_ring(nge_t *ngep)
644 {
645 	uint32_t i;
646 	buff_ring_t *brp;
647 	dma_area_t *bufp;
648 	sw_rx_sbd_t *bsbdp;
649 
650 	brp = ngep->buff;
651 	bsbdp = brp->sw_rbds;
652 
653 	NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep));
654 
655 	mutex_enter(brp->recycle_lock);
656 	brp->buf_sign++;
657 	mutex_exit(brp->recycle_lock);
658 	for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) {
659 		if (bsbdp->bufp) {
660 			if (bsbdp->bufp->mp)
661 				freemsg(bsbdp->bufp->mp);
662 			nge_free_dma_mem(bsbdp->bufp);
663 			kmem_free(bsbdp->bufp, sizeof (dma_area_t));
664 			bsbdp->bufp = NULL;
665 		}
666 	}
667 	while (brp->free_list != NULL) {
668 		bufp = brp->free_list;
669 		brp->free_list = bufp->next;
670 		bufp->next = NULL;
671 		if (bufp->mp)
672 			freemsg(bufp->mp);
673 		nge_free_dma_mem(bufp);
674 		kmem_free(bufp, sizeof (dma_area_t));
675 	}
676 	while (brp->recycle_list != NULL) {
677 		bufp = brp->recycle_list;
678 		brp->recycle_list = bufp->next;
679 		bufp->next = NULL;
680 		if (bufp->mp)
681 			freemsg(bufp->mp);
682 		nge_free_dma_mem(bufp);
683 		kmem_free(bufp, sizeof (dma_area_t));
684 	}
685 
686 
687 	kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp)));
688 	brp->sw_rbds = NULL;
689 }
690 
691 /*
692  * Intialize the Rx's data ring and free ring
693  */
694 static int
695 nge_init_buff_ring(nge_t *ngep)
696 {
697 	uint32_t err;
698 	uint32_t slot;
699 	uint32_t nslots_buff;
700 	uint32_t nslots_recv;
701 	buff_ring_t *brp;
702 	recv_ring_t *rrp;
703 	dma_area_t desc;
704 	dma_area_t *bufp;
705 	sw_rx_sbd_t *bsbdp;
706 
707 	rrp = ngep->recv;
708 	brp = ngep->buff;
709 	brp->nslots = ngep->rx_buf;
710 	brp->rx_bcopy = B_FALSE;
711 	nslots_recv = rrp->desc.nslots;
712 	nslots_buff = brp->nslots;
713 	brp->ngep = ngep;
714 
715 	NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep));
716 
717 	/*
718 	 * Allocate the array of s/w Recv Buffer Descriptors
719 	 */
720 	bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP);
721 	brp->sw_rbds = bsbdp;
722 	brp->free_list = NULL;
723 	brp->recycle_list = NULL;
724 	for (slot = 0; slot < nslots_buff; ++slot) {
725 		bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP);
726 		err = nge_alloc_dma_mem(ngep, (ngep->buf_size
727 		    + NGE_HEADROOM),
728 		    &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp);
729 		if (err != DDI_SUCCESS) {
730 			kmem_free(bufp, sizeof (dma_area_t));
731 			return (DDI_FAILURE);
732 		}
733 
734 		bufp->alength -= NGE_HEADROOM;
735 		bufp->offset += NGE_HEADROOM;
736 		bufp->private = (caddr_t)ngep;
737 		bufp->rx_recycle.free_func = nge_recv_recycle;
738 		bufp->rx_recycle.free_arg = (caddr_t)bufp;
739 		bufp->signature = brp->buf_sign;
740 		bufp->rx_delivered = B_FALSE;
741 		bufp->mp = desballoc(DMA_VPTR(*bufp),
742 		    ngep->buf_size + NGE_HEADROOM,
743 		    0, &bufp->rx_recycle);
744 
745 		if (bufp->mp == NULL) {
746 			return (DDI_FAILURE);
747 		}
748 		bufp->next = brp->free_list;
749 		brp->free_list = bufp;
750 	}
751 
752 	/*
753 	 * Now initialise each array element once and for all
754 	 */
755 	desc = rrp->desc;
756 	for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) {
757 		nge_slice_chunk(&bsbdp->desc, &desc, 1,
758 		    ngep->desc_attr.rxd_size);
759 		bufp = brp->free_list;
760 		brp->free_list = bufp->next;
761 		bsbdp->bufp = bufp;
762 		bsbdp->flags = CONTROLER_OWN;
763 		bufp->next = NULL;
764 	}
765 
766 	ASSERT(desc.alength == 0);
767 	return (DDI_SUCCESS);
768 }
769 
770 /*
771  * Fill the host address of data in rx' descriptor
772  * and initialize free pointers of rx free ring
773  */
774 static int
775 nge_reinit_buff_ring(nge_t *ngep)
776 {
777 	uint32_t slot;
778 	uint32_t nslots_recv;
779 	buff_ring_t *brp;
780 	recv_ring_t *rrp;
781 	sw_rx_sbd_t *bsbdp;
782 	void *hw_bd_p;
783 
784 	brp = ngep->buff;
785 	rrp = ngep->recv;
786 	bsbdp = brp->sw_rbds;
787 	nslots_recv = rrp->desc.nslots;
788 	for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) {
789 		hw_bd_p = DMA_VPTR(bsbdp->desc);
790 	/*
791 	 * There is a scenario: When the traffic of small tcp
792 	 * packet is heavy, suspending the tcp traffic will
793 	 * cause the preallocated buffers for rx not to be
794 	 * released in time by tcp taffic and cause rx's buffer
795 	 * pointers not to be refilled in time.
796 	 *
797 	 * At this point, if we reinitialize the driver, the bufp
798 	 * pointer for rx's traffic will be NULL.
799 	 * So the result of the reinitializion fails.
800 	 */
801 		if (bsbdp->bufp == NULL)
802 			return (DDI_FAILURE);
803 
804 		ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie,
805 		    bsbdp->bufp->alength);
806 	}
807 	return (DDI_SUCCESS);
808 }
809 
810 static void
811 nge_init_ring_param_lock(nge_t *ngep)
812 {
813 	buff_ring_t *brp;
814 	send_ring_t *srp;
815 
816 	srp = ngep->send;
817 	brp = ngep->buff;
818 
819 	/* Init the locks for send ring */
820 	mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER,
821 	    DDI_INTR_PRI(ngep->intr_pri));
822 	mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER,
823 	    DDI_INTR_PRI(ngep->intr_pri));
824 	mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER,
825 	    DDI_INTR_PRI(ngep->intr_pri));
826 
827 	/* Init parameters of buffer ring */
828 	brp->free_list = NULL;
829 	brp->recycle_list = NULL;
830 	brp->rx_hold = 0;
831 	brp->buf_sign = 0;
832 
833 	/* Init recycle list lock */
834 	mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER,
835 	    DDI_INTR_PRI(ngep->intr_pri));
836 }
837 
838 int
839 nge_init_rings(nge_t *ngep)
840 {
841 	uint32_t err;
842 
843 	err = nge_init_send_ring(ngep);
844 	if (err != DDI_SUCCESS) {
845 		return (err);
846 	}
847 	nge_init_recv_ring(ngep);
848 
849 	err = nge_init_buff_ring(ngep);
850 	if (err != DDI_SUCCESS) {
851 		nge_fini_send_ring(ngep);
852 		return (DDI_FAILURE);
853 	}
854 
855 	return (err);
856 }
857 
858 static int
859 nge_reinit_ring(nge_t *ngep)
860 {
861 	int err;
862 
863 	nge_reinit_recv_ring(ngep);
864 	nge_reinit_send_ring(ngep);
865 	err = nge_reinit_buff_ring(ngep);
866 	return (err);
867 }
868 
869 
870 void
871 nge_fini_rings(nge_t *ngep)
872 {
873 	/*
874 	 * For receive ring, nothing need to be finished.
875 	 * So only finish buffer ring and send ring here.
876 	 */
877 	nge_fini_buff_ring(ngep);
878 	nge_fini_send_ring(ngep);
879 }
880 
881 /*
882  * Loopback ioctl code
883  */
884 
885 static lb_property_t loopmodes[] = {
886 	{ normal,	"normal",	NGE_LOOP_NONE		},
887 	{ external,	"100Mbps",	NGE_LOOP_EXTERNAL_100	},
888 	{ external,	"10Mbps",	NGE_LOOP_EXTERNAL_10	},
889 	{ internal,	"PHY",		NGE_LOOP_INTERNAL_PHY	},
890 };
891 
892 enum ioc_reply
893 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp)
894 {
895 	int cmd;
896 	uint32_t *lbmp;
897 	lb_info_sz_t *lbsp;
898 	lb_property_t *lbpp;
899 
900 	/*
901 	 * Validate format of ioctl
902 	 */
903 	if (mp->b_cont == NULL)
904 		return (IOC_INVAL);
905 
906 	cmd = iocp->ioc_cmd;
907 
908 	switch (cmd) {
909 	default:
910 		return (IOC_INVAL);
911 
912 	case LB_GET_INFO_SIZE:
913 		if (iocp->ioc_count != sizeof (lb_info_sz_t))
914 			return (IOC_INVAL);
915 		lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr;
916 		*lbsp = sizeof (loopmodes);
917 		return (IOC_REPLY);
918 
919 	case LB_GET_INFO:
920 		if (iocp->ioc_count != sizeof (loopmodes))
921 			return (IOC_INVAL);
922 		lbpp = (lb_property_t *)mp->b_cont->b_rptr;
923 		bcopy(loopmodes, lbpp, sizeof (loopmodes));
924 		return (IOC_REPLY);
925 
926 	case LB_GET_MODE:
927 		if (iocp->ioc_count != sizeof (uint32_t))
928 			return (IOC_INVAL);
929 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
930 		*lbmp = ngep->param_loop_mode;
931 		return (IOC_REPLY);
932 
933 	case LB_SET_MODE:
934 		if (iocp->ioc_count != sizeof (uint32_t))
935 			return (IOC_INVAL);
936 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
937 		return (nge_set_loop_mode(ngep, *lbmp));
938 	}
939 }
940 
941 #undef	NGE_DBG
942 #define	NGE_DBG	NGE_DBG_NEMO
943 
944 
945 static void
946 nge_check_desc_prop(nge_t *ngep)
947 {
948 	if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD)
949 		ngep->desc_mode = DESC_HOT;
950 
951 	if (ngep->desc_mode == DESC_OFFLOAD)	{
952 
953 		ngep->desc_attr = nge_sum_desc;
954 
955 	}	else if (ngep->desc_mode == DESC_HOT)	{
956 
957 		ngep->desc_attr = nge_hot_desc;
958 	}
959 }
960 
961 /*
962  * nge_get_props -- get the parameters to tune the driver
963  */
964 static void
965 nge_get_props(nge_t *ngep)
966 {
967 	chip_info_t *infop;
968 	dev_info_t *devinfo;
969 	nge_dev_spec_param_t *dev_param_p;
970 
971 	devinfo = ngep->devinfo;
972 	infop = (chip_info_t *)&ngep->chipinfo;
973 	dev_param_p = &ngep->dev_spec_param;
974 
975 	infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
976 	    DDI_PROP_DONTPASS, clsize_propname, 32);
977 
978 	infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
979 	    DDI_PROP_DONTPASS, latency_propname, 64);
980 	ngep->intr_moderation = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
981 	    DDI_PROP_DONTPASS, intr_moderation, NGE_SET);
982 	ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
983 	    DDI_PROP_DONTPASS, rx_data_hw, 0x20);
984 	ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
985 	    DDI_PROP_DONTPASS, rx_prd_lw, 0x4);
986 	ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
987 	    DDI_PROP_DONTPASS, rx_prd_hw, 0xc);
988 
989 	ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
990 	    DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC);
991 	ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
992 	    DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP);
993 	ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
994 	    DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type);
995 	ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
996 	    DDI_PROP_DONTPASS, low_memory_mode, 0);
997 
998 	if (dev_param_p->jumbo) {
999 		ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
1000 		    DDI_PROP_DONTPASS, default_mtu, ETHERMTU);
1001 	} else
1002 		ngep->default_mtu = ETHERMTU;
1003 	if (dev_param_p->tx_pause_frame)
1004 			ngep->param_link_tx_pause = B_TRUE;
1005 	else
1006 			ngep->param_link_tx_pause = B_FALSE;
1007 
1008 	if (dev_param_p->rx_pause_frame)
1009 			ngep->param_link_rx_pause = B_TRUE;
1010 	else
1011 			ngep->param_link_rx_pause = B_FALSE;
1012 
1013 	if (ngep->default_mtu > ETHERMTU &&
1014 	    ngep->default_mtu <= NGE_MTU_2500) {
1015 		ngep->buf_size = NGE_JB2500_BUFSZ;
1016 		ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
1017 		ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
1018 		ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
1019 		ngep->nge_split = NGE_SPLIT_256;
1020 	} else if (ngep->default_mtu > NGE_MTU_2500 &&
1021 	    ngep->default_mtu <= NGE_MTU_4500) {
1022 		ngep->buf_size = NGE_JB4500_BUFSZ;
1023 		ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
1024 		ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
1025 		ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
1026 		ngep->nge_split = NGE_SPLIT_256;
1027 	} else if (ngep->default_mtu > NGE_MTU_4500 &&
1028 	    ngep->default_mtu <= NGE_MAX_MTU) {
1029 		ngep->buf_size = NGE_JB9000_BUFSZ;
1030 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
1031 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
1032 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
1033 		ngep->nge_split = NGE_SPLIT_256;
1034 	} else if (ngep->default_mtu > NGE_MAX_MTU) {
1035 		ngep->default_mtu = NGE_MAX_MTU;
1036 		ngep->buf_size = NGE_JB9000_BUFSZ;
1037 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
1038 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
1039 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
1040 		ngep->nge_split = NGE_SPLIT_256;
1041 	} else if (ngep->lowmem_mode != 0) {
1042 		ngep->default_mtu = ETHERMTU;
1043 		ngep->buf_size = NGE_STD_BUFSZ;
1044 		ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
1045 		ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
1046 		ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
1047 		ngep->nge_split = NGE_SPLIT_32;
1048 	} else {
1049 		ngep->default_mtu = ETHERMTU;
1050 		ngep->buf_size = NGE_STD_BUFSZ;
1051 		ngep->tx_desc = dev_param_p->tx_desc_num;
1052 		ngep->rx_desc = dev_param_p->rx_desc_num;
1053 		ngep->rx_buf = dev_param_p->rx_desc_num * 2;
1054 		ngep->nge_split = dev_param_p->nge_split;
1055 	}
1056 
1057 	nge_check_desc_prop(ngep);
1058 }
1059 
1060 
1061 static int
1062 nge_reset_dev(nge_t *ngep)
1063 {
1064 	int err;
1065 	nge_mul_addr1 maddr1;
1066 	nge_sw_statistics_t *sw_stp;
1067 	sw_stp = &ngep->statistics.sw_statistics;
1068 	send_ring_t *srp = ngep->send;
1069 
1070 	ASSERT(mutex_owned(ngep->genlock));
1071 	mutex_enter(srp->tc_lock);
1072 	mutex_enter(srp->tx_lock);
1073 
1074 	nge_tx_recycle_all(ngep);
1075 	err = nge_reinit_ring(ngep);
1076 	if (err == DDI_FAILURE) {
1077 		mutex_exit(srp->tx_lock);
1078 		mutex_exit(srp->tc_lock);
1079 		return (err);
1080 	}
1081 	err = nge_chip_reset(ngep);
1082 	/*
1083 	 * Clear the Multicast mac address table
1084 	 */
1085 	nge_reg_put32(ngep, NGE_MUL_ADDR0, 0);
1086 	maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1);
1087 	maddr1.addr_bits.addr = 0;
1088 	nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val);
1089 
1090 	mutex_exit(srp->tx_lock);
1091 	mutex_exit(srp->tc_lock);
1092 	if (err == DDI_FAILURE)
1093 		return (err);
1094 	ngep->watchdog = 0;
1095 	ngep->resched_needed = B_FALSE;
1096 	ngep->promisc = B_FALSE;
1097 	ngep->param_loop_mode = NGE_LOOP_NONE;
1098 	ngep->factotum_flag = 0;
1099 	ngep->resched_needed = 0;
1100 	ngep->nge_mac_state = NGE_MAC_RESET;
1101 	ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL;
1102 	ngep->max_sdu += VTAG_SIZE;
1103 	ngep->rx_def = 0x16;
1104 
1105 	/* Clear the software statistics */
1106 	sw_stp->recv_count = 0;
1107 	sw_stp->xmit_count = 0;
1108 	sw_stp->rbytes = 0;
1109 	sw_stp->obytes = 0;
1110 
1111 	return (DDI_SUCCESS);
1112 }
1113 
1114 static void
1115 nge_m_stop(void *arg)
1116 {
1117 	nge_t *ngep = arg;		/* private device info	*/
1118 	int err;
1119 
1120 	NGE_TRACE(("nge_m_stop($%p)", arg));
1121 
1122 	/*
1123 	 * Just stop processing, then record new MAC state
1124 	 */
1125 	mutex_enter(ngep->genlock);
1126 	/* If suspended, the adapter is already stopped, just return. */
1127 	if (ngep->suspended) {
1128 		ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED);
1129 		mutex_exit(ngep->genlock);
1130 		return;
1131 	}
1132 	rw_enter(ngep->rwlock, RW_WRITER);
1133 
1134 	err = nge_chip_stop(ngep, B_FALSE);
1135 	if (err == DDI_FAILURE)
1136 		err = nge_chip_reset(ngep);
1137 	if (err == DDI_FAILURE)
1138 		nge_problem(ngep, "nge_m_stop: stop chip failed");
1139 	ngep->nge_mac_state = NGE_MAC_STOPPED;
1140 
1141 	/* Recycle all the TX BD */
1142 	nge_tx_recycle_all(ngep);
1143 	nge_fini_rings(ngep);
1144 	nge_free_bufs(ngep);
1145 
1146 	NGE_DEBUG(("nge_m_stop($%p) done", arg));
1147 
1148 	rw_exit(ngep->rwlock);
1149 	mutex_exit(ngep->genlock);
1150 }
1151 
1152 static int
1153 nge_m_start(void *arg)
1154 {
1155 	int err;
1156 	nge_t *ngep = arg;
1157 
1158 	NGE_TRACE(("nge_m_start($%p)", arg));
1159 
1160 	/*
1161 	 * Start processing and record new MAC state
1162 	 */
1163 	mutex_enter(ngep->genlock);
1164 	/*
1165 	 * If suspended, don't start, as the resume processing
1166 	 * will recall this function with the suspended flag off.
1167 	 */
1168 	if (ngep->suspended) {
1169 		mutex_exit(ngep->genlock);
1170 		return (EIO);
1171 	}
1172 	rw_enter(ngep->rwlock, RW_WRITER);
1173 	err = nge_alloc_bufs(ngep);
1174 	if (err != DDI_SUCCESS) {
1175 		nge_problem(ngep, "nge_m_start: DMA buffer allocation failed");
1176 		goto finish;
1177 	}
1178 	err = nge_init_rings(ngep);
1179 	if (err != DDI_SUCCESS) {
1180 		nge_free_bufs(ngep);
1181 		nge_problem(ngep, "nge_init_rings() failed,err=%x", err);
1182 		goto finish;
1183 	}
1184 	err = nge_restart(ngep);
1185 
1186 	NGE_DEBUG(("nge_m_start($%p) done", arg));
1187 finish:
1188 	rw_exit(ngep->rwlock);
1189 	mutex_exit(ngep->genlock);
1190 
1191 	return (err == DDI_SUCCESS ? 0 : EIO);
1192 }
1193 
1194 static int
1195 nge_m_unicst(void *arg, const uint8_t *macaddr)
1196 {
1197 	nge_t *ngep = arg;
1198 
1199 	NGE_TRACE(("nge_m_unicst($%p)", arg));
1200 	/*
1201 	 * Remember the new current address in the driver state
1202 	 * Sync the chip's idea of the address too ...
1203 	 */
1204 	mutex_enter(ngep->genlock);
1205 
1206 	ethaddr_copy(macaddr, ngep->cur_uni_addr.addr);
1207 	ngep->cur_uni_addr.set = 1;
1208 
1209 	/*
1210 	 * If we are suspended, we want to quit now, and not update
1211 	 * the chip.  Doing so might put it in a bad state, but the
1212 	 * resume will get the unicast address installed.
1213 	 */
1214 	if (ngep->suspended) {
1215 		mutex_exit(ngep->genlock);
1216 		return (DDI_SUCCESS);
1217 	}
1218 	nge_chip_sync(ngep);
1219 
1220 	NGE_DEBUG(("nge_m_unicst($%p) done", arg));
1221 	mutex_exit(ngep->genlock);
1222 
1223 	return (0);
1224 }
1225 
1226 static int
1227 nge_m_promisc(void *arg, boolean_t on)
1228 {
1229 	nge_t *ngep = arg;
1230 
1231 	NGE_TRACE(("nge_m_promisc($%p)", arg));
1232 
1233 	/*
1234 	 * Store specified mode and pass to chip layer to update h/w
1235 	 */
1236 	mutex_enter(ngep->genlock);
1237 	/*
1238 	 * If suspended, there is no need to do anything, even
1239 	 * recording the promiscuious mode is not neccessary, as
1240 	 * it won't be properly set on resume.  Just return failing.
1241 	 */
1242 	if (ngep->suspended) {
1243 		mutex_exit(ngep->genlock);
1244 		return (DDI_FAILURE);
1245 	}
1246 	if (ngep->promisc == on) {
1247 		mutex_exit(ngep->genlock);
1248 		NGE_DEBUG(("nge_m_promisc($%p) done", arg));
1249 		return (0);
1250 	}
1251 	ngep->promisc = on;
1252 	ngep->record_promisc = ngep->promisc;
1253 	nge_chip_sync(ngep);
1254 	NGE_DEBUG(("nge_m_promisc($%p) done", arg));
1255 	mutex_exit(ngep->genlock);
1256 
1257 	return (0);
1258 }
1259 
1260 static void nge_mulparam(nge_t *ngep)
1261 {
1262 	uint8_t number;
1263 	ether_addr_t pand;
1264 	ether_addr_t por;
1265 	mul_item *plist;
1266 
1267 	for (number = 0; number < ETHERADDRL; number++) {
1268 		pand[number] = 0x00;
1269 		por[number] = 0x00;
1270 	}
1271 	for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) {
1272 		for (number = 0; number < ETHERADDRL; number++) {
1273 			pand[number] &= plist->mul_addr[number];
1274 			por[number] |= plist->mul_addr[number];
1275 		}
1276 	}
1277 	for (number = 0; number < ETHERADDRL; number++) {
1278 		ngep->cur_mul_addr.addr[number]
1279 		    = pand[number] & por[number];
1280 		ngep->cur_mul_mask.addr[number]
1281 		    = pand [number] | (~por[number]);
1282 	}
1283 }
1284 static int
1285 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
1286 {
1287 	boolean_t update;
1288 	boolean_t b_eq;
1289 	nge_t *ngep = arg;
1290 	mul_item *plist;
1291 	mul_item *plist_prev;
1292 	mul_item *pitem;
1293 
1294 	NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg,
1295 	    (add) ? "add" : "remove", ether_sprintf((void *)mca)));
1296 
1297 	update = B_FALSE;
1298 	plist = plist_prev = NULL;
1299 	mutex_enter(ngep->genlock);
1300 	if (add) {
1301 		if (ngep->pcur_mulist != NULL) {
1302 			for (plist = ngep->pcur_mulist; plist != NULL;
1303 			    plist = plist->next) {
1304 				b_eq = ether_eq(plist->mul_addr, mca);
1305 				if (b_eq) {
1306 					plist->ref_cnt++;
1307 					break;
1308 				}
1309 				plist_prev = plist;
1310 			}
1311 		}
1312 
1313 		if (plist == NULL) {
1314 			pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP);
1315 			ether_copy(mca, pitem->mul_addr);
1316 			pitem ->ref_cnt++;
1317 			pitem ->next = NULL;
1318 			if (plist_prev == NULL)
1319 				ngep->pcur_mulist = pitem;
1320 			else
1321 				plist_prev->next = pitem;
1322 			update = B_TRUE;
1323 		}
1324 	} else {
1325 		if (ngep->pcur_mulist != NULL) {
1326 			for (plist = ngep->pcur_mulist; plist != NULL;
1327 			    plist = plist->next) {
1328 				b_eq = ether_eq(plist->mul_addr, mca);
1329 				if (b_eq) {
1330 					update = B_TRUE;
1331 					break;
1332 				}
1333 				plist_prev = plist;
1334 			}
1335 
1336 			if (update) {
1337 				if ((plist_prev == NULL) &&
1338 				    (plist->next == NULL))
1339 					ngep->pcur_mulist = NULL;
1340 				else if ((plist_prev == NULL) &&
1341 				    (plist->next != NULL))
1342 					ngep->pcur_mulist = plist->next;
1343 				else
1344 					plist_prev->next = plist->next;
1345 				kmem_free(plist, sizeof (mul_item));
1346 			}
1347 		}
1348 	}
1349 
1350 	if (update && !ngep->suspended) {
1351 		nge_mulparam(ngep);
1352 		nge_chip_sync(ngep);
1353 	}
1354 	NGE_DEBUG(("nge_m_multicst($%p) done", arg));
1355 	mutex_exit(ngep->genlock);
1356 
1357 	return (0);
1358 }
1359 
1360 static void
1361 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
1362 {
1363 	int err;
1364 	int cmd;
1365 	nge_t *ngep = arg;
1366 	struct iocblk *iocp;
1367 	enum ioc_reply status;
1368 	boolean_t need_privilege;
1369 
1370 	/*
1371 	 * If suspended, we might actually be able to do some of
1372 	 * these ioctls, but it is harder to make sure they occur
1373 	 * without actually putting the hardware in an undesireable
1374 	 * state.  So just NAK it.
1375 	 */
1376 	mutex_enter(ngep->genlock);
1377 	if (ngep->suspended) {
1378 		miocnak(wq, mp, 0, EINVAL);
1379 		mutex_exit(ngep->genlock);
1380 		return;
1381 	}
1382 	mutex_exit(ngep->genlock);
1383 
1384 	/*
1385 	 * Validate the command before bothering with the mutex ...
1386 	 */
1387 	iocp = (struct iocblk *)mp->b_rptr;
1388 	iocp->ioc_error = 0;
1389 	need_privilege = B_TRUE;
1390 	cmd = iocp->ioc_cmd;
1391 
1392 	NGE_DEBUG(("nge_m_ioctl:  cmd 0x%x", cmd));
1393 	switch (cmd) {
1394 	default:
1395 		NGE_LDB(NGE_DBG_BADIOC,
1396 		    ("nge_m_ioctl: unknown cmd 0x%x", cmd));
1397 
1398 		miocnak(wq, mp, 0, EINVAL);
1399 		return;
1400 
1401 	case NGE_MII_READ:
1402 	case NGE_MII_WRITE:
1403 	case NGE_SEE_READ:
1404 	case NGE_SEE_WRITE:
1405 	case NGE_DIAG:
1406 	case NGE_PEEK:
1407 	case NGE_POKE:
1408 	case NGE_PHY_RESET:
1409 	case NGE_SOFT_RESET:
1410 	case NGE_HARD_RESET:
1411 		break;
1412 
1413 	case LB_GET_INFO_SIZE:
1414 	case LB_GET_INFO:
1415 	case LB_GET_MODE:
1416 		need_privilege = B_FALSE;
1417 		break;
1418 	case LB_SET_MODE:
1419 		break;
1420 	}
1421 
1422 	if (need_privilege) {
1423 		/*
1424 		 * Check for specific net_config privilege.
1425 		 */
1426 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
1427 		if (err != 0) {
1428 			NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d",
1429 			    cmd, err));
1430 			miocnak(wq, mp, 0, err);
1431 			return;
1432 		}
1433 	}
1434 
1435 	mutex_enter(ngep->genlock);
1436 
1437 	switch (cmd) {
1438 	default:
1439 		_NOTE(NOTREACHED)
1440 		status = IOC_INVAL;
1441 	break;
1442 
1443 	case NGE_MII_READ:
1444 	case NGE_MII_WRITE:
1445 	case NGE_SEE_READ:
1446 	case NGE_SEE_WRITE:
1447 	case NGE_DIAG:
1448 	case NGE_PEEK:
1449 	case NGE_POKE:
1450 	case NGE_PHY_RESET:
1451 	case NGE_SOFT_RESET:
1452 	case NGE_HARD_RESET:
1453 		status = nge_chip_ioctl(ngep, mp, iocp);
1454 	break;
1455 
1456 	case LB_GET_INFO_SIZE:
1457 	case LB_GET_INFO:
1458 	case LB_GET_MODE:
1459 	case LB_SET_MODE:
1460 		status = nge_loop_ioctl(ngep, mp, iocp);
1461 	break;
1462 
1463 	}
1464 
1465 	/*
1466 	 * Do we need to reprogram the PHY and/or the MAC?
1467 	 * Do it now, while we still have the mutex.
1468 	 *
1469 	 * Note: update the PHY first, 'cos it controls the
1470 	 * speed/duplex parameters that the MAC code uses.
1471 	 */
1472 
1473 	NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status));
1474 
1475 	switch (status) {
1476 	case IOC_RESTART_REPLY:
1477 	case IOC_RESTART_ACK:
1478 		(*ngep->physops->phys_update)(ngep);
1479 		nge_chip_sync(ngep);
1480 		break;
1481 
1482 	default:
1483 	break;
1484 	}
1485 
1486 	mutex_exit(ngep->genlock);
1487 
1488 	/*
1489 	 * Finally, decide how to reply
1490 	 */
1491 	switch (status) {
1492 
1493 	default:
1494 	case IOC_INVAL:
1495 		miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
1496 		    EINVAL : iocp->ioc_error);
1497 		break;
1498 
1499 	case IOC_DONE:
1500 		break;
1501 
1502 	case IOC_RESTART_ACK:
1503 	case IOC_ACK:
1504 		miocack(wq, mp, 0, 0);
1505 		break;
1506 
1507 	case IOC_RESTART_REPLY:
1508 	case IOC_REPLY:
1509 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
1510 		    M_IOCACK : M_IOCNAK;
1511 		qreply(wq, mp);
1512 		break;
1513 	}
1514 }
1515 
1516 static boolean_t
1517 nge_param_locked(mac_prop_id_t pr_num)
1518 {
1519 	/*
1520 	 * All adv_* parameters are locked (read-only) while
1521 	 * the device is in any sort of loopback mode ...
1522 	 */
1523 	switch (pr_num) {
1524 		case MAC_PROP_ADV_1000FDX_CAP:
1525 		case MAC_PROP_EN_1000FDX_CAP:
1526 		case MAC_PROP_ADV_1000HDX_CAP:
1527 		case MAC_PROP_EN_1000HDX_CAP:
1528 		case MAC_PROP_ADV_100FDX_CAP:
1529 		case MAC_PROP_EN_100FDX_CAP:
1530 		case MAC_PROP_ADV_100HDX_CAP:
1531 		case MAC_PROP_EN_100HDX_CAP:
1532 		case MAC_PROP_ADV_10FDX_CAP:
1533 		case MAC_PROP_EN_10FDX_CAP:
1534 		case MAC_PROP_ADV_10HDX_CAP:
1535 		case MAC_PROP_EN_10HDX_CAP:
1536 		case MAC_PROP_AUTONEG:
1537 		case MAC_PROP_FLOWCTRL:
1538 			return (B_TRUE);
1539 	}
1540 	return (B_FALSE);
1541 }
1542 
1543 /*
1544  * callback functions for set/get of properties
1545  */
1546 static int
1547 nge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
1548     uint_t pr_valsize, const void *pr_val)
1549 {
1550 	nge_t *ngep = barg;
1551 	int err = 0;
1552 	uint32_t cur_mtu, new_mtu;
1553 	link_flowctrl_t fl;
1554 
1555 	mutex_enter(ngep->genlock);
1556 	if (ngep->param_loop_mode != NGE_LOOP_NONE &&
1557 	    nge_param_locked(pr_num)) {
1558 		/*
1559 		 * All adv_* parameters are locked (read-only)
1560 		 * while the device is in any sort of loopback mode.
1561 		 */
1562 		mutex_exit(ngep->genlock);
1563 		return (EBUSY);
1564 	}
1565 	switch (pr_num) {
1566 		case MAC_PROP_EN_1000FDX_CAP:
1567 			ngep->param_en_1000fdx = *(uint8_t *)pr_val;
1568 			ngep->param_adv_1000fdx = *(uint8_t *)pr_val;
1569 			goto reprogram;
1570 		case MAC_PROP_EN_100FDX_CAP:
1571 			ngep->param_en_100fdx = *(uint8_t *)pr_val;
1572 			ngep->param_adv_100fdx = *(uint8_t *)pr_val;
1573 			goto reprogram;
1574 		case MAC_PROP_EN_100HDX_CAP:
1575 			ngep->param_en_100hdx = *(uint8_t *)pr_val;
1576 			ngep->param_adv_100hdx = *(uint8_t *)pr_val;
1577 			goto reprogram;
1578 		case MAC_PROP_EN_10FDX_CAP:
1579 			ngep->param_en_10fdx = *(uint8_t *)pr_val;
1580 			ngep->param_adv_10fdx = *(uint8_t *)pr_val;
1581 			goto reprogram;
1582 		case MAC_PROP_EN_10HDX_CAP:
1583 			ngep->param_en_10hdx = *(uint8_t *)pr_val;
1584 			ngep->param_adv_10hdx = *(uint8_t *)pr_val;
1585 reprogram:
1586 		(*ngep->physops->phys_update)(ngep);
1587 		nge_chip_sync(ngep);
1588 		break;
1589 
1590 		case MAC_PROP_ADV_1000FDX_CAP:
1591 		case MAC_PROP_ADV_1000HDX_CAP:
1592 		case MAC_PROP_ADV_100FDX_CAP:
1593 		case MAC_PROP_ADV_100HDX_CAP:
1594 		case MAC_PROP_ADV_10FDX_CAP:
1595 		case MAC_PROP_ADV_10HDX_CAP:
1596 		case MAC_PROP_STATUS:
1597 		case MAC_PROP_SPEED:
1598 		case MAC_PROP_DUPLEX:
1599 		case MAC_PROP_EN_1000HDX_CAP:
1600 			err = ENOTSUP; /* read-only prop. Can't set this */
1601 			break;
1602 		case MAC_PROP_AUTONEG:
1603 			ngep->param_adv_autoneg = *(uint8_t *)pr_val;
1604 			(*ngep->physops->phys_update)(ngep);
1605 			nge_chip_sync(ngep);
1606 			break;
1607 		case MAC_PROP_MTU:
1608 			cur_mtu = ngep->default_mtu;
1609 			bcopy(pr_val, &new_mtu, sizeof (new_mtu));
1610 			if (new_mtu == cur_mtu) {
1611 				err = 0;
1612 				break;
1613 			}
1614 			if (new_mtu < ETHERMTU ||
1615 			    new_mtu > NGE_MAX_MTU) {
1616 				err = EINVAL;
1617 				break;
1618 			}
1619 			if ((new_mtu > ETHERMTU) &&
1620 			    (!ngep->dev_spec_param.jumbo)) {
1621 				err = EINVAL;
1622 				break;
1623 			}
1624 			if (ngep->nge_mac_state == NGE_MAC_STARTED) {
1625 				err = EBUSY;
1626 				break;
1627 			}
1628 
1629 			ngep->default_mtu = new_mtu;
1630 			if (ngep->default_mtu > ETHERMTU &&
1631 			    ngep->default_mtu <= NGE_MTU_2500) {
1632 				ngep->buf_size = NGE_JB2500_BUFSZ;
1633 				ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
1634 				ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
1635 				ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
1636 				ngep->nge_split = NGE_SPLIT_256;
1637 			} else if (ngep->default_mtu > NGE_MTU_2500 &&
1638 			    ngep->default_mtu <= NGE_MTU_4500) {
1639 				ngep->buf_size = NGE_JB4500_BUFSZ;
1640 				ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
1641 				ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
1642 				ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
1643 				ngep->nge_split = NGE_SPLIT_256;
1644 			} else if (ngep->default_mtu > NGE_MTU_4500 &&
1645 			    ngep->default_mtu <= NGE_MAX_MTU) {
1646 				ngep->buf_size = NGE_JB9000_BUFSZ;
1647 				ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
1648 				ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
1649 				ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
1650 				ngep->nge_split = NGE_SPLIT_256;
1651 			} else if (ngep->default_mtu > NGE_MAX_MTU) {
1652 				ngep->default_mtu = NGE_MAX_MTU;
1653 				ngep->buf_size = NGE_JB9000_BUFSZ;
1654 				ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
1655 				ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
1656 				ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
1657 				ngep->nge_split = NGE_SPLIT_256;
1658 			} else if (ngep->lowmem_mode != 0) {
1659 				ngep->default_mtu = ETHERMTU;
1660 				ngep->buf_size = NGE_STD_BUFSZ;
1661 				ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
1662 				ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
1663 				ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
1664 				ngep->nge_split = NGE_SPLIT_32;
1665 			} else {
1666 				ngep->default_mtu = ETHERMTU;
1667 				ngep->buf_size = NGE_STD_BUFSZ;
1668 				ngep->tx_desc =
1669 				    ngep->dev_spec_param.tx_desc_num;
1670 				ngep->rx_desc =
1671 				    ngep->dev_spec_param.rx_desc_num;
1672 				ngep->rx_buf =
1673 				    ngep->dev_spec_param.rx_desc_num * 2;
1674 				ngep->nge_split =
1675 				    ngep->dev_spec_param.nge_split;
1676 			}
1677 
1678 			err = mac_maxsdu_update(ngep->mh, ngep->default_mtu);
1679 
1680 			break;
1681 		case MAC_PROP_FLOWCTRL:
1682 			bcopy(pr_val, &fl, sizeof (fl));
1683 			switch (fl) {
1684 			default:
1685 				err = ENOTSUP;
1686 				break;
1687 			case LINK_FLOWCTRL_NONE:
1688 				ngep->param_adv_pause = 0;
1689 				ngep->param_adv_asym_pause = 0;
1690 
1691 				ngep->param_link_rx_pause = B_FALSE;
1692 				ngep->param_link_tx_pause = B_FALSE;
1693 				break;
1694 			case LINK_FLOWCTRL_RX:
1695 				if (!((ngep->param_lp_pause == 0) &&
1696 				    (ngep->param_lp_asym_pause == 1))) {
1697 					err = EINVAL;
1698 					break;
1699 				}
1700 				ngep->param_adv_pause = 1;
1701 				ngep->param_adv_asym_pause = 1;
1702 
1703 				ngep->param_link_rx_pause = B_TRUE;
1704 				ngep->param_link_tx_pause = B_FALSE;
1705 				break;
1706 			case LINK_FLOWCTRL_TX:
1707 				if (!((ngep->param_lp_pause == 1) &&
1708 				    (ngep->param_lp_asym_pause == 1))) {
1709 					err = EINVAL;
1710 					break;
1711 				}
1712 				ngep->param_adv_pause = 0;
1713 				ngep->param_adv_asym_pause = 1;
1714 
1715 				ngep->param_link_rx_pause = B_FALSE;
1716 				ngep->param_link_tx_pause = B_TRUE;
1717 				break;
1718 			case LINK_FLOWCTRL_BI:
1719 				if (ngep->param_lp_pause != 1) {
1720 					err = EINVAL;
1721 					break;
1722 				}
1723 				ngep->param_adv_pause = 1;
1724 
1725 				ngep->param_link_rx_pause = B_TRUE;
1726 				ngep->param_link_tx_pause = B_TRUE;
1727 				break;
1728 			}
1729 
1730 			if (err == 0) {
1731 				(*ngep->physops->phys_update)(ngep);
1732 				nge_chip_sync(ngep);
1733 			}
1734 
1735 			break;
1736 		case MAC_PROP_PRIVATE:
1737 			err = nge_set_priv_prop(ngep, pr_name, pr_valsize,
1738 			    pr_val);
1739 			if (err == 0) {
1740 				(*ngep->physops->phys_update)(ngep);
1741 				nge_chip_sync(ngep);
1742 			}
1743 			break;
1744 		default:
1745 			err = ENOTSUP;
1746 	}
1747 	mutex_exit(ngep->genlock);
1748 	return (err);
1749 }
1750 
1751 static int
1752 nge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
1753     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
1754 {
1755 	nge_t *ngep = barg;
1756 	int err = 0;
1757 	link_flowctrl_t fl;
1758 	uint64_t speed;
1759 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
1760 
1761 	if (pr_valsize == 0)
1762 		return (EINVAL);
1763 
1764 	*perm = MAC_PROP_PERM_RW;
1765 
1766 	bzero(pr_val, pr_valsize);
1767 
1768 	switch (pr_num) {
1769 		case MAC_PROP_DUPLEX:
1770 			*perm = MAC_PROP_PERM_READ;
1771 			if (pr_valsize >= sizeof (link_duplex_t)) {
1772 				bcopy(&ngep->param_link_duplex, pr_val,
1773 				    sizeof (link_duplex_t));
1774 			} else
1775 				err = EINVAL;
1776 			break;
1777 		case MAC_PROP_SPEED:
1778 			*perm = MAC_PROP_PERM_READ;
1779 			if (pr_valsize >= sizeof (uint64_t)) {
1780 				speed = ngep->param_link_speed * 1000000ull;
1781 				bcopy(&speed, pr_val, sizeof (speed));
1782 			} else
1783 				err = EINVAL;
1784 			break;
1785 		case MAC_PROP_AUTONEG:
1786 			if (is_default) {
1787 				*(uint8_t *)pr_val = 1;
1788 			} else {
1789 				*(uint8_t *)pr_val = ngep->param_adv_autoneg;
1790 			}
1791 			break;
1792 		case MAC_PROP_FLOWCTRL:
1793 			if (pr_valsize >= sizeof (link_flowctrl_t)) {
1794 				if (pr_flags & MAC_PROP_DEFAULT) {
1795 					fl = LINK_FLOWCTRL_BI;
1796 					bcopy(&fl, pr_val, sizeof (fl));
1797 					break;
1798 				}
1799 				if (ngep->param_link_rx_pause &&
1800 				    !ngep->param_link_tx_pause)
1801 					fl = LINK_FLOWCTRL_RX;
1802 
1803 				if (!ngep->param_link_rx_pause &&
1804 				    !ngep->param_link_tx_pause)
1805 					fl = LINK_FLOWCTRL_NONE;
1806 
1807 				if (!ngep->param_link_rx_pause &&
1808 				    ngep->param_link_tx_pause)
1809 					fl = LINK_FLOWCTRL_TX;
1810 
1811 				if (ngep->param_link_rx_pause &&
1812 				    ngep->param_link_tx_pause)
1813 					fl = LINK_FLOWCTRL_BI;
1814 				bcopy(&fl, pr_val, sizeof (fl));
1815 			} else
1816 				err = EINVAL;
1817 			break;
1818 		case MAC_PROP_ADV_1000FDX_CAP:
1819 			*perm = MAC_PROP_PERM_READ;
1820 			if (is_default) {
1821 				*(uint8_t *)pr_val = 1;
1822 			} else {
1823 				*(uint8_t *)pr_val = ngep->param_adv_1000fdx;
1824 			}
1825 			break;
1826 		case MAC_PROP_EN_1000FDX_CAP:
1827 			if (is_default) {
1828 				*(uint8_t *)pr_val = 1;
1829 			} else {
1830 				*(uint8_t *)pr_val = ngep->param_en_1000fdx;
1831 			}
1832 			break;
1833 		case MAC_PROP_ADV_1000HDX_CAP:
1834 			*perm = MAC_PROP_PERM_READ;
1835 			if (is_default) {
1836 				*(uint8_t *)pr_val = 0;
1837 			} else {
1838 				*(uint8_t *)pr_val = ngep->param_adv_1000hdx;
1839 			}
1840 			break;
1841 		case MAC_PROP_EN_1000HDX_CAP:
1842 			*perm = MAC_PROP_PERM_READ;
1843 			if (is_default) {
1844 				*(uint8_t *)pr_val = 0;
1845 			} else {
1846 				*(uint8_t *)pr_val = ngep->param_en_1000hdx;
1847 			}
1848 			break;
1849 		case MAC_PROP_ADV_100FDX_CAP:
1850 			*perm = MAC_PROP_PERM_READ;
1851 			if (is_default) {
1852 				*(uint8_t *)pr_val = 1;
1853 			} else {
1854 				*(uint8_t *)pr_val = ngep->param_adv_100fdx;
1855 			}
1856 			break;
1857 		case MAC_PROP_EN_100FDX_CAP:
1858 			if (is_default) {
1859 				*(uint8_t *)pr_val = 1;
1860 			} else {
1861 				*(uint8_t *)pr_val = ngep->param_en_100fdx;
1862 			}
1863 			break;
1864 		case MAC_PROP_ADV_100HDX_CAP:
1865 			*perm = MAC_PROP_PERM_READ;
1866 			if (is_default) {
1867 				*(uint8_t *)pr_val = 1;
1868 			} else {
1869 				*(uint8_t *)pr_val = ngep->param_adv_100hdx;
1870 			}
1871 			break;
1872 		case MAC_PROP_EN_100HDX_CAP:
1873 			if (is_default) {
1874 				*(uint8_t *)pr_val = 1;
1875 			} else {
1876 				*(uint8_t *)pr_val = ngep->param_en_100hdx;
1877 			}
1878 			break;
1879 		case MAC_PROP_ADV_10FDX_CAP:
1880 			*perm = MAC_PROP_PERM_READ;
1881 			if (is_default) {
1882 				*(uint8_t *)pr_val = 1;
1883 			} else {
1884 				*(uint8_t *)pr_val = ngep->param_adv_10fdx;
1885 			}
1886 			break;
1887 		case MAC_PROP_EN_10FDX_CAP:
1888 			if (is_default) {
1889 				*(uint8_t *)pr_val = 1;
1890 			} else {
1891 				*(uint8_t *)pr_val = ngep->param_en_10fdx;
1892 			}
1893 			break;
1894 		case MAC_PROP_ADV_10HDX_CAP:
1895 			*perm = MAC_PROP_PERM_READ;
1896 			if (is_default) {
1897 				*(uint8_t *)pr_val = 1;
1898 			} else {
1899 				*(uint8_t *)pr_val = ngep->param_adv_10hdx;
1900 			}
1901 			break;
1902 		case MAC_PROP_EN_10HDX_CAP:
1903 			if (is_default) {
1904 				*(uint8_t *)pr_val = 1;
1905 			} else {
1906 				*(uint8_t *)pr_val = ngep->param_en_10hdx;
1907 			}
1908 			break;
1909 		case MAC_PROP_ADV_100T4_CAP:
1910 		case MAC_PROP_EN_100T4_CAP:
1911 			*perm = MAC_PROP_PERM_READ;
1912 			*(uint8_t *)pr_val = 0;
1913 			break;
1914 		case MAC_PROP_PRIVATE:
1915 			err = nge_get_priv_prop(ngep, pr_name, pr_flags,
1916 			    pr_valsize, pr_val);
1917 			break;
1918 		case MAC_PROP_MTU: {
1919 			mac_propval_range_t range;
1920 
1921 			if (!(pr_flags & MAC_PROP_POSSIBLE))
1922 				return (ENOTSUP);
1923 			if (pr_valsize < sizeof (mac_propval_range_t))
1924 				return (EINVAL);
1925 			range.mpr_count = 1;
1926 			range.mpr_type = MAC_PROPVAL_UINT32;
1927 			range.range_uint32[0].mpur_min =
1928 			    range.range_uint32[0].mpur_max = ETHERMTU;
1929 			if (ngep->dev_spec_param.jumbo)
1930 				range.range_uint32[0].mpur_max = NGE_MAX_MTU;
1931 			bcopy(&range, pr_val, sizeof (range));
1932 			break;
1933 		}
1934 		default:
1935 			err = ENOTSUP;
1936 	}
1937 	return (err);
1938 }
1939 
1940 /* ARGSUSED */
1941 static int
1942 nge_set_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize,
1943     const void *pr_val)
1944 {
1945 	int err = 0;
1946 	long result;
1947 
1948 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
1949 		if (pr_val == NULL) {
1950 			err = EINVAL;
1951 			return (err);
1952 		}
1953 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1954 		if (result < 0 || result > NGE_MAX_SDU) {
1955 			err = EINVAL;
1956 		} else {
1957 			ngep->param_txbcopy_threshold = (uint32_t)result;
1958 			goto reprogram;
1959 		}
1960 		return (err);
1961 	}
1962 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
1963 		if (pr_val == NULL) {
1964 			err = EINVAL;
1965 			return (err);
1966 		}
1967 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1968 		if (result < 0 || result > NGE_MAX_SDU) {
1969 			err = EINVAL;
1970 		} else {
1971 			ngep->param_rxbcopy_threshold = (uint32_t)result;
1972 			goto reprogram;
1973 		}
1974 		return (err);
1975 	}
1976 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
1977 		if (pr_val == NULL) {
1978 			err = EINVAL;
1979 			return (err);
1980 		}
1981 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1982 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
1983 			err = EINVAL;
1984 		} else {
1985 			ngep->param_recv_max_packet = (uint32_t)result;
1986 			goto reprogram;
1987 		}
1988 		return (err);
1989 	}
1990 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
1991 		if (pr_val == NULL) {
1992 			err = EINVAL;
1993 			return (err);
1994 		}
1995 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1996 		if (result < 0 || result > 10000) {
1997 			err = EINVAL;
1998 		} else {
1999 			ngep->param_poll_quiet_time = (uint32_t)result;
2000 			goto reprogram;
2001 		}
2002 		return (err);
2003 	}
2004 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
2005 		if (pr_val == NULL) {
2006 			err = EINVAL;
2007 			return (err);
2008 		}
2009 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
2010 		if (result < 0 || result > 10000) {
2011 			err = EINVAL;
2012 		} else {
2013 			ngep->param_poll_busy_time = (uint32_t)result;
2014 			goto reprogram;
2015 		}
2016 		return (err);
2017 	}
2018 	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
2019 		if (pr_val == NULL) {
2020 			err = EINVAL;
2021 			return (err);
2022 		}
2023 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
2024 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
2025 			err = EINVAL;
2026 		} else {
2027 			ngep->param_rx_intr_hwater = (uint32_t)result;
2028 			goto reprogram;
2029 		}
2030 		return (err);
2031 	}
2032 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
2033 		if (pr_val == NULL) {
2034 			err = EINVAL;
2035 			return (err);
2036 		}
2037 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
2038 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
2039 			err = EINVAL;
2040 		} else {
2041 			ngep->param_rx_intr_lwater = (uint32_t)result;
2042 			goto reprogram;
2043 		}
2044 		return (err);
2045 	}
2046 	err = ENOTSUP;
2047 	return (err);
2048 
2049 reprogram:
2050 	if (err == 0) {
2051 		(*ngep->physops->phys_update)(ngep);
2052 		nge_chip_sync(ngep);
2053 	}
2054 
2055 	return (err);
2056 }
2057 
2058 static int
2059 nge_get_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_flags,
2060     uint_t pr_valsize, void *pr_val)
2061 {
2062 	int err = ENOTSUP;
2063 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
2064 	int value;
2065 
2066 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
2067 		value = (is_default ? NGE_TX_COPY_SIZE :
2068 		    ngep->param_txbcopy_threshold);
2069 		err = 0;
2070 		goto done;
2071 	}
2072 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
2073 		value = (is_default ? NGE_RX_COPY_SIZE :
2074 		    ngep->param_rxbcopy_threshold);
2075 		err = 0;
2076 		goto done;
2077 	}
2078 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
2079 		value = (is_default ? 128 : ngep->param_recv_max_packet);
2080 		err = 0;
2081 		goto done;
2082 	}
2083 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
2084 		value = (is_default ? NGE_POLL_QUIET_TIME :
2085 		    ngep->param_poll_quiet_time);
2086 		err = 0;
2087 		goto done;
2088 	}
2089 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
2090 		value = (is_default ? NGE_POLL_BUSY_TIME :
2091 		    ngep->param_poll_busy_time);
2092 		err = 0;
2093 		goto done;
2094 	}
2095 	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
2096 		value = (is_default ? 1 : ngep->param_rx_intr_hwater);
2097 		err = 0;
2098 		goto done;
2099 	}
2100 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
2101 		value = (is_default ? 8 : ngep->param_rx_intr_lwater);
2102 		err = 0;
2103 		goto done;
2104 	}
2105 
2106 done:
2107 	if (err == 0) {
2108 		(void) snprintf(pr_val, pr_valsize, "%d", value);
2109 	}
2110 	return (err);
2111 }
2112 
2113 /* ARGSUSED */
2114 static boolean_t
2115 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
2116 {
2117 	nge_t	*ngep = arg;
2118 	nge_dev_spec_param_t *dev_param_p;
2119 
2120 	dev_param_p = &ngep->dev_spec_param;
2121 
2122 	switch (cap) {
2123 	case MAC_CAPAB_HCKSUM: {
2124 		uint32_t *hcksum_txflags = cap_data;
2125 
2126 		if (dev_param_p->tx_hw_checksum) {
2127 			*hcksum_txflags = dev_param_p->tx_hw_checksum;
2128 		} else
2129 			return (B_FALSE);
2130 		break;
2131 	}
2132 	default:
2133 		return (B_FALSE);
2134 	}
2135 	return (B_TRUE);
2136 }
2137 
2138 #undef	NGE_DBG
2139 #define	NGE_DBG	NGE_DBG_INIT	/* debug flag for this code	*/
2140 int
2141 nge_restart(nge_t *ngep)
2142 {
2143 	int err = 0;
2144 	err = nge_reset_dev(ngep);
2145 	/* write back the promisc setting */
2146 	ngep->promisc = ngep->record_promisc;
2147 	nge_chip_sync(ngep);
2148 	if (!err)
2149 		err = nge_chip_start(ngep);
2150 
2151 	if (err) {
2152 		ngep->nge_mac_state = NGE_MAC_STOPPED;
2153 		return (DDI_FAILURE);
2154 	} else {
2155 		ngep->nge_mac_state = NGE_MAC_STARTED;
2156 		return (DDI_SUCCESS);
2157 	}
2158 }
2159 
2160 void
2161 nge_wake_factotum(nge_t *ngep)
2162 {
2163 	mutex_enter(ngep->softlock);
2164 	if (ngep->factotum_flag == 0) {
2165 		ngep->factotum_flag = 1;
2166 		(void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL);
2167 	}
2168 	mutex_exit(ngep->softlock);
2169 }
2170 
2171 void
2172 nge_interrupt_optimize(nge_t *ngep)
2173 {
2174 	uint32_t tx_pkts;
2175 	tx_pkts = ngep->statistics.sw_statistics.xmit_count - ngep->tpkts_last;
2176 	ngep->tpkts_last = ngep->statistics.sw_statistics.xmit_count;
2177 	if ((tx_pkts > NGE_POLL_TUNE) &&
2178 	    (tx_pkts <= NGE_POLL_MAX))
2179 		ngep->tfint_threshold = (tx_pkts / NGE_POLL_ENTER);
2180 	else
2181 		ngep->tfint_threshold = NGE_TFINT_DEFAULT;
2182 }
2183 
2184 /*
2185  * High-level cyclic handler
2186  *
2187  * This routine schedules a (low-level) softint callback to the
2188  * factotum.
2189  */
2190 
2191 static void
2192 nge_chip_cyclic(void *arg)
2193 {
2194 	nge_t *ngep;
2195 
2196 	ngep = (nge_t *)arg;
2197 
2198 	switch (ngep->nge_chip_state) {
2199 	default:
2200 		return;
2201 
2202 	case NGE_CHIP_RUNNING:
2203 		nge_interrupt_optimize(ngep);
2204 		break;
2205 
2206 	case NGE_CHIP_FAULT:
2207 	case NGE_CHIP_ERROR:
2208 		break;
2209 	}
2210 
2211 	nge_wake_factotum(ngep);
2212 }
2213 
2214 /*
2215  * Get/Release semaphore of SMU
2216  * For SMU enabled chipset
2217  * When nge driver is attached, driver should acquire
2218  * semaphore before PHY init and accessing MAC registers.
2219  * When nge driver is unattached, driver should release
2220  * semaphore.
2221  */
2222 
2223 static int
2224 nge_smu_sema(nge_t *ngep, boolean_t acquire)
2225 {
2226 	nge_tx_en tx_en;
2227 	uint32_t tries;
2228 
2229 	if (acquire) {
2230 		for (tries = 0; tries < 5; tries++) {
2231 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
2232 			if (tx_en.bits.smu2mac == NGE_SMU_FREE)
2233 				break;
2234 			delay(drv_usectohz(1000000));
2235 		}
2236 		if (tx_en.bits.smu2mac != NGE_SMU_FREE)
2237 			return (DDI_FAILURE);
2238 		for (tries = 0; tries < 5; tries++) {
2239 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
2240 			tx_en.bits.mac2smu = NGE_SMU_GET;
2241 			nge_reg_put32(ngep, NGE_TX_EN, tx_en.val);
2242 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
2243 
2244 			if (tx_en.bits.mac2smu == NGE_SMU_GET &&
2245 			    tx_en.bits.smu2mac == NGE_SMU_FREE)
2246 				return (DDI_SUCCESS);
2247 			drv_usecwait(10);
2248 		}
2249 		return (DDI_FAILURE);
2250 	} else
2251 		nge_reg_put32(ngep, NGE_TX_EN, 0x0);
2252 
2253 	return (DDI_SUCCESS);
2254 
2255 }
2256 static void
2257 nge_unattach(nge_t *ngep)
2258 {
2259 	send_ring_t *srp;
2260 	buff_ring_t *brp;
2261 
2262 	srp = ngep->send;
2263 	brp = ngep->buff;
2264 	NGE_TRACE(("nge_unattach($%p)", (void *)ngep));
2265 
2266 	/*
2267 	 * Flag that no more activity may be initiated
2268 	 */
2269 	ngep->progress &= ~PROGRESS_READY;
2270 	ngep->nge_mac_state = NGE_MAC_UNATTACH;
2271 
2272 	/*
2273 	 * Quiesce the PHY and MAC (leave it reset but still powered).
2274 	 * Clean up and free all NGE data structures
2275 	 */
2276 	if (ngep->periodic_id != NULL) {
2277 		ddi_periodic_delete(ngep->periodic_id);
2278 		ngep->periodic_id = NULL;
2279 	}
2280 
2281 	if (ngep->progress & PROGRESS_KSTATS)
2282 		nge_fini_kstats(ngep);
2283 
2284 	if (ngep->progress & PROGRESS_HWINT) {
2285 		mutex_enter(ngep->genlock);
2286 		nge_restore_mac_addr(ngep);
2287 		(void) nge_chip_stop(ngep, B_FALSE);
2288 		if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
2289 		    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
2290 			(void) nge_smu_sema(ngep, B_FALSE);
2291 		}
2292 		mutex_exit(ngep->genlock);
2293 	}
2294 
2295 	if (ngep->progress & PROGRESS_SWINT)
2296 		nge_rem_intrs(ngep);
2297 
2298 	if (ngep->progress & PROGRESS_FACTOTUM)
2299 		(void) ddi_intr_remove_softint(ngep->factotum_hdl);
2300 
2301 	if (ngep->progress & PROGRESS_RESCHED)
2302 		(void) ddi_intr_remove_softint(ngep->resched_hdl);
2303 
2304 	if (ngep->progress & PROGRESS_INTR) {
2305 		mutex_destroy(srp->tx_lock);
2306 		mutex_destroy(srp->tc_lock);
2307 		mutex_destroy(&srp->dmah_lock);
2308 		mutex_destroy(brp->recycle_lock);
2309 
2310 		mutex_destroy(ngep->genlock);
2311 		mutex_destroy(ngep->softlock);
2312 		rw_destroy(ngep->rwlock);
2313 	}
2314 
2315 	if (ngep->progress & PROGRESS_REGS)
2316 		ddi_regs_map_free(&ngep->io_handle);
2317 
2318 	if (ngep->progress & PROGRESS_CFG)
2319 		pci_config_teardown(&ngep->cfg_handle);
2320 
2321 	ddi_remove_minor_node(ngep->devinfo, NULL);
2322 
2323 	kmem_free(ngep, sizeof (*ngep));
2324 }
2325 
2326 static int
2327 nge_resume(dev_info_t *devinfo)
2328 {
2329 	nge_t		*ngep;
2330 	chip_info_t	*infop;
2331 	int 		err;
2332 
2333 	ASSERT(devinfo != NULL);
2334 
2335 	ngep = ddi_get_driver_private(devinfo);
2336 	err = 0;
2337 
2338 	/*
2339 	 * If there are state inconsistancies, this is bad.  Returning
2340 	 * DDI_FAILURE here will eventually cause the machine to panic,
2341 	 * so it is best done here so that there is a possibility of
2342 	 * debugging the problem.
2343 	 */
2344 	if (ngep == NULL)
2345 		cmn_err(CE_PANIC,
2346 		    "nge: ngep returned from ddi_get_driver_private was NULL");
2347 	infop = (chip_info_t *)&ngep->chipinfo;
2348 
2349 	if (ngep->devinfo != devinfo)
2350 		cmn_err(CE_PANIC,
2351 		    "nge: passed devinfo not the same as saved devinfo");
2352 
2353 	mutex_enter(ngep->genlock);
2354 	rw_enter(ngep->rwlock, RW_WRITER);
2355 
2356 	/*
2357 	 * Fetch the config space.  Even though we have most of it cached,
2358 	 * some values *might* change across a suspend/resume.
2359 	 */
2360 	nge_chip_cfg_init(ngep, infop, B_FALSE);
2361 
2362 	/*
2363 	 * Only in one case, this conditional branch can be executed: the port
2364 	 * hasn't been plumbed.
2365 	 */
2366 	if (ngep->suspended == B_FALSE) {
2367 		rw_exit(ngep->rwlock);
2368 		mutex_exit(ngep->genlock);
2369 		return (DDI_SUCCESS);
2370 	}
2371 
2372 	nge_tx_recycle_all(ngep);
2373 	err = nge_reinit_ring(ngep);
2374 	if (!err) {
2375 		err = nge_chip_reset(ngep);
2376 		if (!err)
2377 			err = nge_chip_start(ngep);
2378 	}
2379 
2380 	if (err) {
2381 		/*
2382 		 * We note the failure, but return success, as the
2383 		 * system is still usable without this controller.
2384 		 */
2385 		cmn_err(CE_WARN, "nge: resume: failed to restart controller");
2386 	} else {
2387 		ngep->nge_mac_state = NGE_MAC_STARTED;
2388 	}
2389 	ngep->suspended = B_FALSE;
2390 
2391 	rw_exit(ngep->rwlock);
2392 	mutex_exit(ngep->genlock);
2393 
2394 	return (DDI_SUCCESS);
2395 }
2396 
2397 /*
2398  * attach(9E) -- Attach a device to the system
2399  *
2400  * Called once for each board successfully probed.
2401  */
2402 static int
2403 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
2404 {
2405 	int		err;
2406 	int		i;
2407 	int		instance;
2408 	caddr_t		regs;
2409 	nge_t		*ngep;
2410 	chip_info_t	*infop;
2411 	mac_register_t	*macp;
2412 
2413 	switch (cmd) {
2414 	default:
2415 		return (DDI_FAILURE);
2416 
2417 	case DDI_RESUME:
2418 		return (nge_resume(devinfo));
2419 
2420 	case DDI_ATTACH:
2421 		break;
2422 	}
2423 
2424 	ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP);
2425 	instance = ddi_get_instance(devinfo);
2426 	ddi_set_driver_private(devinfo, ngep);
2427 	ngep->devinfo = devinfo;
2428 
2429 	(void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d",
2430 	    NGE_DRIVER_NAME, instance);
2431 	err = pci_config_setup(devinfo, &ngep->cfg_handle);
2432 	if (err != DDI_SUCCESS) {
2433 		nge_problem(ngep, "nge_attach: pci_config_setup() failed");
2434 		goto attach_fail;
2435 	}
2436 	/*
2437 	 * param_txbcopy_threshold and param_rxbcopy_threshold are tx/rx bcopy
2438 	 * thresholds. Bounds: min 0, max NGE_MAX_SDU
2439 	 */
2440 	ngep->param_txbcopy_threshold = NGE_TX_COPY_SIZE;
2441 	ngep->param_rxbcopy_threshold = NGE_RX_COPY_SIZE;
2442 
2443 	/*
2444 	 * param_recv_max_packet is max packet received per interupt.
2445 	 * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024
2446 	 */
2447 	ngep->param_recv_max_packet = 128;
2448 
2449 	/*
2450 	 * param_poll_quiet_time and param_poll_busy_time are quiet/busy time
2451 	 * switch from per packet interrupt to polling interrupt.
2452 	 * Bounds: min 0, max 10000
2453 	 */
2454 	ngep->param_poll_quiet_time = NGE_POLL_QUIET_TIME;
2455 	ngep->param_poll_busy_time = NGE_POLL_BUSY_TIME;
2456 	ngep->tfint_threshold = NGE_TFINT_DEFAULT;
2457 	ngep->poll = B_FALSE;
2458 	ngep->ch_intr_mode = B_FALSE;
2459 
2460 	/*
2461 	 * param_rx_intr_hwater/param_rx_intr_lwater: ackets received
2462 	 * to trigger the poll_quiet_time/poll_busy_time counter.
2463 	 * Bounds: min 0, max  NGE_RECV_SLOTS_DESC_1024.
2464 	 */
2465 	ngep->param_rx_intr_hwater = 1;
2466 	ngep->param_rx_intr_lwater = 8;
2467 
2468 
2469 	infop = (chip_info_t *)&ngep->chipinfo;
2470 	nge_chip_cfg_init(ngep, infop, B_FALSE);
2471 	nge_init_dev_spec_param(ngep);
2472 	nge_get_props(ngep);
2473 	ngep->progress |= PROGRESS_CFG;
2474 
2475 	err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER,
2476 	    &regs, 0, 0, &nge_reg_accattr, &ngep->io_handle);
2477 	if (err != DDI_SUCCESS) {
2478 		nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed");
2479 		goto attach_fail;
2480 	}
2481 	ngep->io_regs = regs;
2482 	ngep->progress |= PROGRESS_REGS;
2483 
2484 	err = nge_register_intrs_and_init_locks(ngep);
2485 	if (err != DDI_SUCCESS) {
2486 		nge_problem(ngep, "nge_attach:"
2487 		    " register intrs and init locks failed");
2488 		goto attach_fail;
2489 	}
2490 	nge_init_ring_param_lock(ngep);
2491 	ngep->progress |= PROGRESS_INTR;
2492 
2493 	mutex_enter(ngep->genlock);
2494 
2495 	if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
2496 	    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
2497 		err = nge_smu_sema(ngep, B_TRUE);
2498 		if (err != DDI_SUCCESS) {
2499 			nge_problem(ngep, "nge_attach: nge_smu_sema() failed");
2500 			goto attach_fail;
2501 		}
2502 	}
2503 	/*
2504 	 * Initialise link state variables
2505 	 * Stop, reset & reinitialise the chip.
2506 	 * Initialise the (internal) PHY.
2507 	 */
2508 	nge_phys_init(ngep);
2509 	ngep->nge_chip_state = NGE_CHIP_INITIAL;
2510 	err = nge_chip_reset(ngep);
2511 	if (err != DDI_SUCCESS) {
2512 		nge_problem(ngep, "nge_attach: nge_chip_reset() failed");
2513 		mutex_exit(ngep->genlock);
2514 		goto attach_fail;
2515 	}
2516 	nge_chip_sync(ngep);
2517 
2518 	/*
2519 	 * Now that mutex locks are initialized, enable interrupts.
2520 	 */
2521 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
2522 		/* Call ddi_intr_block_enable() for MSI interrupts */
2523 		(void) ddi_intr_block_enable(ngep->htable,
2524 		    ngep->intr_actual_cnt);
2525 	} else {
2526 		/* Call ddi_intr_enable for MSI or FIXED interrupts */
2527 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
2528 			(void) ddi_intr_enable(ngep->htable[i]);
2529 		}
2530 	}
2531 
2532 	ngep->link_state = LINK_STATE_UNKNOWN;
2533 	ngep->progress |= PROGRESS_HWINT;
2534 
2535 	/*
2536 	 * Register NDD-tweakable parameters
2537 	 */
2538 	if (nge_nd_init(ngep)) {
2539 		nge_problem(ngep, "nge_attach: nge_nd_init() failed");
2540 		mutex_exit(ngep->genlock);
2541 		goto attach_fail;
2542 	}
2543 	ngep->progress |= PROGRESS_NDD;
2544 
2545 	/*
2546 	 * Create & initialise named kstats
2547 	 */
2548 	nge_init_kstats(ngep, instance);
2549 	ngep->progress |= PROGRESS_KSTATS;
2550 
2551 	mutex_exit(ngep->genlock);
2552 
2553 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
2554 		goto attach_fail;
2555 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2556 	macp->m_driver = ngep;
2557 	macp->m_dip = devinfo;
2558 	macp->m_src_addr = infop->vendor_addr.addr;
2559 	macp->m_callbacks = &nge_m_callbacks;
2560 	macp->m_min_sdu = 0;
2561 	macp->m_max_sdu = ngep->default_mtu;
2562 	macp->m_margin = VTAG_SIZE;
2563 	macp->m_priv_props = nge_priv_props;
2564 	macp->m_priv_prop_count = NGE_MAX_PRIV_PROPS;
2565 	/*
2566 	 * Finally, we're ready to register ourselves with the mac
2567 	 * interface; if this succeeds, we're all ready to start()
2568 	 */
2569 	err = mac_register(macp, &ngep->mh);
2570 	mac_free(macp);
2571 	if (err != 0)
2572 		goto attach_fail;
2573 
2574 	/*
2575 	 * Register a periodical handler.
2576 	 * nge_chip_cyclic() is invoked in kernel context.
2577 	 */
2578 	ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep,
2579 	    NGE_CYCLIC_PERIOD, DDI_IPL_0);
2580 
2581 	ngep->progress |= PROGRESS_READY;
2582 	return (DDI_SUCCESS);
2583 
2584 attach_fail:
2585 	nge_unattach(ngep);
2586 	return (DDI_FAILURE);
2587 }
2588 
2589 static int
2590 nge_suspend(nge_t *ngep)
2591 {
2592 	mutex_enter(ngep->genlock);
2593 	rw_enter(ngep->rwlock, RW_WRITER);
2594 
2595 	/* if the port hasn't been plumbed, just return */
2596 	if (ngep->nge_mac_state != NGE_MAC_STARTED) {
2597 		rw_exit(ngep->rwlock);
2598 		mutex_exit(ngep->genlock);
2599 		return (DDI_SUCCESS);
2600 	}
2601 	ngep->suspended = B_TRUE;
2602 	(void) nge_chip_stop(ngep, B_FALSE);
2603 	ngep->nge_mac_state = NGE_MAC_STOPPED;
2604 
2605 	rw_exit(ngep->rwlock);
2606 	mutex_exit(ngep->genlock);
2607 	return (DDI_SUCCESS);
2608 }
2609 
2610 /*
2611  * detach(9E) -- Detach a device from the system
2612  */
2613 static int
2614 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
2615 {
2616 	int i;
2617 	nge_t *ngep;
2618 	mul_item *p, *nextp;
2619 	buff_ring_t *brp;
2620 
2621 	NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd));
2622 
2623 	ngep = ddi_get_driver_private(devinfo);
2624 	brp = ngep->buff;
2625 
2626 	switch (cmd) {
2627 	default:
2628 		return (DDI_FAILURE);
2629 
2630 	case DDI_SUSPEND:
2631 		/*
2632 		 * Stop the NIC
2633 		 * Note: This driver doesn't currently support WOL, but
2634 		 *	should it in the future, it is important to
2635 		 *	make sure the PHY remains powered so that the
2636 		 *	wakeup packet can actually be recieved.
2637 		 */
2638 		return (nge_suspend(ngep));
2639 
2640 	case DDI_DETACH:
2641 		break;
2642 	}
2643 
2644 	/* Try to wait all the buffer post to upper layer be released */
2645 	for (i = 0; i < 1000; i++) {
2646 		if (brp->rx_hold == 0)
2647 			break;
2648 		drv_usecwait(1000);
2649 	}
2650 
2651 	/* If there is any posted buffer, reject to detach */
2652 	if (brp->rx_hold != 0)
2653 		return (DDI_FAILURE);
2654 
2655 	/*
2656 	 * Unregister from the GLD subsystem.  This can fail, in
2657 	 * particular if there are DLPI style-2 streams still open -
2658 	 * in which case we just return failure without shutting
2659 	 * down chip operations.
2660 	 */
2661 	if (mac_unregister(ngep->mh) != DDI_SUCCESS)
2662 		return (DDI_FAILURE);
2663 
2664 	/*
2665 	 * Recycle the multicast table. mac_unregister() should be called
2666 	 * before it to ensure the multicast table can be used even if
2667 	 * mac_unregister() fails.
2668 	 */
2669 	for (p = ngep->pcur_mulist; p != NULL; p = nextp) {
2670 		nextp = p->next;
2671 		kmem_free(p, sizeof (mul_item));
2672 	}
2673 	ngep->pcur_mulist = NULL;
2674 
2675 	/*
2676 	 * All activity stopped, so we can clean up & exit
2677 	 */
2678 	nge_unattach(ngep);
2679 	return (DDI_SUCCESS);
2680 }
2681 
2682 /*
2683  * quiesce(9E) entry point.
2684  *
2685  * This function is called when the system is single-threaded at high
2686  * PIL with preemption disabled. Therefore, this function must not be
2687  * blocked.
2688  *
2689  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
2690  * DDI_FAILURE indicates an error condition and should almost never happen.
2691  */
2692 static int
2693 nge_quiesce(dev_info_t *devinfo)
2694 {
2695 	nge_t *ngep;
2696 
2697 	ngep = ddi_get_driver_private(devinfo);
2698 
2699 	if (ngep == NULL)
2700 		return (DDI_FAILURE);
2701 
2702 	/*
2703 	 * Turn off debug tracing
2704 	 */
2705 	nge_debug = 0;
2706 	ngep->debug = 0;
2707 
2708 	nge_restore_mac_addr(ngep);
2709 	(void) nge_chip_stop(ngep, B_FALSE);
2710 
2711 	return (DDI_SUCCESS);
2712 }
2713 
2714 
2715 
2716 /*
2717  * ========== Module Loading Data & Entry Points ==========
2718  */
2719 
2720 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach,
2721     NULL, NULL, D_MP, NULL, nge_quiesce);
2722 
2723 
2724 static struct modldrv nge_modldrv = {
2725 	&mod_driverops,		/* Type of module.  This one is a driver */
2726 	nge_ident,		/* short description */
2727 	&nge_dev_ops		/* driver specific ops */
2728 };
2729 
2730 static struct modlinkage modlinkage = {
2731 	MODREV_1, (void *)&nge_modldrv, NULL
2732 };
2733 
2734 
2735 int
2736 _info(struct modinfo *modinfop)
2737 {
2738 	return (mod_info(&modlinkage, modinfop));
2739 }
2740 
2741 int
2742 _init(void)
2743 {
2744 	int status;
2745 
2746 	mac_init_ops(&nge_dev_ops, "nge");
2747 	status = mod_install(&modlinkage);
2748 	if (status != DDI_SUCCESS)
2749 		mac_fini_ops(&nge_dev_ops);
2750 	else
2751 		mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL);
2752 
2753 	return (status);
2754 }
2755 
2756 int
2757 _fini(void)
2758 {
2759 	int status;
2760 
2761 	status = mod_remove(&modlinkage);
2762 	if (status == DDI_SUCCESS) {
2763 		mac_fini_ops(&nge_dev_ops);
2764 		mutex_destroy(nge_log_mutex);
2765 	}
2766 
2767 	return (status);
2768 }
2769 
2770 /*
2771  * ============ Init MSI/Fixed/SoftInterrupt routines ==============
2772  */
2773 
2774 /*
2775  * Register interrupts and initialize each mutex and condition variables
2776  */
2777 
2778 static int
2779 nge_register_intrs_and_init_locks(nge_t *ngep)
2780 {
2781 	int		err;
2782 	int		intr_types;
2783 	uint_t		soft_prip;
2784 	nge_msi_mask	msi_mask;
2785 	nge_msi_map0_vec map0_vec;
2786 	nge_msi_map1_vec map1_vec;
2787 
2788 	/*
2789 	 * Add the softint handlers:
2790 	 *
2791 	 * Both of these handlers are used to avoid restrictions on the
2792 	 * context and/or mutexes required for some operations.  In
2793 	 * particular, the hardware interrupt handler and its subfunctions
2794 	 * can detect a number of conditions that we don't want to handle
2795 	 * in that context or with that set of mutexes held.  So, these
2796 	 * softints are triggered instead:
2797 	 *
2798 	 * the <resched> softint is triggered if if we have previously
2799 	 * had to refuse to send a packet because of resource shortage
2800 	 * (we've run out of transmit buffers), but the send completion
2801 	 * interrupt handler has now detected that more buffers have
2802 	 * become available.  Its only purpose is to call gld_sched()
2803 	 * to retry the pending transmits (we're not allowed to hold
2804 	 * driver-defined mutexes across gld_sched()).
2805 	 *
2806 	 * the <factotum> is triggered if the h/w interrupt handler
2807 	 * sees the <link state changed> or <error> bits in the status
2808 	 * block.  It's also triggered periodically to poll the link
2809 	 * state, just in case we aren't getting link status change
2810 	 * interrupts ...
2811 	 */
2812 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl,
2813 	    DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep);
2814 	if (err != DDI_SUCCESS) {
2815 		nge_problem(ngep,
2816 		    "nge_attach: add nge_reschedule softintr failed");
2817 
2818 		return (DDI_FAILURE);
2819 	}
2820 	ngep->progress |= PROGRESS_RESCHED;
2821 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl,
2822 	    DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep);
2823 	if (err != DDI_SUCCESS) {
2824 		nge_problem(ngep,
2825 		    "nge_attach: add nge_chip_factotum softintr failed!");
2826 
2827 		return (DDI_FAILURE);
2828 	}
2829 	if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip)
2830 	    != DDI_SUCCESS) {
2831 		nge_problem(ngep, "nge_attach: get softintr priority failed\n");
2832 
2833 		return (DDI_FAILURE);
2834 	}
2835 	ngep->soft_pri = soft_prip;
2836 
2837 	ngep->progress |= PROGRESS_FACTOTUM;
2838 	/* Get supported interrupt types */
2839 	if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types)
2840 	    != DDI_SUCCESS) {
2841 		nge_error(ngep, "ddi_intr_get_supported_types failed\n");
2842 
2843 		return (DDI_FAILURE);
2844 	}
2845 
2846 	NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x",
2847 	    intr_types));
2848 
2849 	if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) {
2850 
2851 		/* MSI Configurations for mcp55 chipset */
2852 		if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
2853 		    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
2854 
2855 
2856 			/* Enable the 8 vectors */
2857 			msi_mask.msi_mask_val =
2858 			    nge_reg_get32(ngep, NGE_MSI_MASK);
2859 			msi_mask.msi_msk_bits.vec0 = NGE_SET;
2860 			msi_mask.msi_msk_bits.vec1 = NGE_SET;
2861 			msi_mask.msi_msk_bits.vec2 = NGE_SET;
2862 			msi_mask.msi_msk_bits.vec3 = NGE_SET;
2863 			msi_mask.msi_msk_bits.vec4 = NGE_SET;
2864 			msi_mask.msi_msk_bits.vec5 = NGE_SET;
2865 			msi_mask.msi_msk_bits.vec6 = NGE_SET;
2866 			msi_mask.msi_msk_bits.vec7 = NGE_SET;
2867 			nge_reg_put32(ngep, NGE_MSI_MASK,
2868 			    msi_mask.msi_mask_val);
2869 
2870 			/*
2871 			 * Remapping the MSI MAP0 and MAP1. MCP55
2872 			 * is default mapping all the interrupt to 0 vector.
2873 			 * Software needs to remapping this.
2874 			 * This mapping is same as CK804.
2875 			 */
2876 			map0_vec.msi_map0_val =
2877 			    nge_reg_get32(ngep, NGE_MSI_MAP0);
2878 			map1_vec.msi_map1_val =
2879 			    nge_reg_get32(ngep, NGE_MSI_MAP1);
2880 			map0_vec.vecs_bits.reint_vec = 0;
2881 			map0_vec.vecs_bits.rcint_vec = 0;
2882 			map0_vec.vecs_bits.miss_vec = 3;
2883 			map0_vec.vecs_bits.teint_vec = 5;
2884 			map0_vec.vecs_bits.tcint_vec = 5;
2885 			map0_vec.vecs_bits.stint_vec = 2;
2886 			map0_vec.vecs_bits.mint_vec = 6;
2887 			map0_vec.vecs_bits.rfint_vec = 0;
2888 			map1_vec.vecs_bits.tfint_vec = 5;
2889 			map1_vec.vecs_bits.feint_vec = 6;
2890 			map1_vec.vecs_bits.resv8_11 = 3;
2891 			map1_vec.vecs_bits.resv12_15 = 1;
2892 			map1_vec.vecs_bits.resv16_19 = 0;
2893 			map1_vec.vecs_bits.resv20_23 = 7;
2894 			map1_vec.vecs_bits.resv24_31 = 0xff;
2895 			nge_reg_put32(ngep, NGE_MSI_MAP0,
2896 			    map0_vec.msi_map0_val);
2897 			nge_reg_put32(ngep, NGE_MSI_MAP1,
2898 			    map1_vec.msi_map1_val);
2899 		}
2900 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) {
2901 			NGE_DEBUG(("MSI registration failed, "
2902 			    "trying FIXED interrupt type\n"));
2903 		} else {
2904 			nge_log(ngep, "Using MSI interrupt type\n");
2905 
2906 			ngep->intr_type = DDI_INTR_TYPE_MSI;
2907 			ngep->progress |= PROGRESS_SWINT;
2908 		}
2909 	}
2910 
2911 	if (!(ngep->progress & PROGRESS_SWINT) &&
2912 	    (intr_types & DDI_INTR_TYPE_FIXED)) {
2913 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
2914 			nge_error(ngep, "FIXED interrupt "
2915 			    "registration failed\n");
2916 
2917 			return (DDI_FAILURE);
2918 		}
2919 
2920 		nge_log(ngep, "Using FIXED interrupt type\n");
2921 
2922 		ngep->intr_type = DDI_INTR_TYPE_FIXED;
2923 		ngep->progress |= PROGRESS_SWINT;
2924 	}
2925 
2926 
2927 	if (!(ngep->progress & PROGRESS_SWINT)) {
2928 		nge_error(ngep, "No interrupts registered\n");
2929 
2930 		return (DDI_FAILURE);
2931 	}
2932 	mutex_init(ngep->genlock, NULL, MUTEX_DRIVER,
2933 	    DDI_INTR_PRI(ngep->intr_pri));
2934 	mutex_init(ngep->softlock, NULL, MUTEX_DRIVER,
2935 	    DDI_INTR_PRI(ngep->soft_pri));
2936 	rw_init(ngep->rwlock, NULL, RW_DRIVER,
2937 	    DDI_INTR_PRI(ngep->intr_pri));
2938 
2939 	return (DDI_SUCCESS);
2940 }
2941 
2942 /*
2943  * nge_add_intrs:
2944  *
2945  * Register FIXED or MSI interrupts.
2946  */
2947 static int
2948 nge_add_intrs(nge_t *ngep, int	intr_type)
2949 {
2950 	dev_info_t	*dip = ngep->devinfo;
2951 	int		avail, actual, intr_size, count = 0;
2952 	int		i, flag, ret;
2953 
2954 	NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type));
2955 
2956 	/* Get number of interrupts */
2957 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
2958 	if ((ret != DDI_SUCCESS) || (count == 0)) {
2959 		nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, "
2960 		    "count: %d", ret, count);
2961 
2962 		return (DDI_FAILURE);
2963 	}
2964 
2965 	/* Get number of available interrupts */
2966 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
2967 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
2968 		nge_error(ngep, "ddi_intr_get_navail() failure, "
2969 		    "ret: %d, avail: %d\n", ret, avail);
2970 
2971 		return (DDI_FAILURE);
2972 	}
2973 
2974 	if (avail < count) {
2975 		NGE_DEBUG(("nitrs() returned %d, navail returned %d\n",
2976 		    count, avail));
2977 	}
2978 	flag = DDI_INTR_ALLOC_NORMAL;
2979 
2980 	/* Allocate an array of interrupt handles */
2981 	intr_size = count * sizeof (ddi_intr_handle_t);
2982 	ngep->htable = kmem_alloc(intr_size, KM_SLEEP);
2983 
2984 	/* Call ddi_intr_alloc() */
2985 	ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0,
2986 	    count, &actual, flag);
2987 
2988 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
2989 		nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret);
2990 
2991 		kmem_free(ngep->htable, intr_size);
2992 		return (DDI_FAILURE);
2993 	}
2994 
2995 	if (actual < count) {
2996 		NGE_DEBUG(("Requested: %d, Received: %d\n",
2997 		    count, actual));
2998 	}
2999 
3000 	ngep->intr_actual_cnt = actual;
3001 	ngep->intr_req_cnt = count;
3002 
3003 	/*
3004 	 * Get priority for first msi, assume remaining are all the same
3005 	 */
3006 	if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) !=
3007 	    DDI_SUCCESS) {
3008 		nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret);
3009 
3010 		/* Free already allocated intr */
3011 		for (i = 0; i < actual; i++) {
3012 			(void) ddi_intr_free(ngep->htable[i]);
3013 		}
3014 
3015 		kmem_free(ngep->htable, intr_size);
3016 
3017 		return (DDI_FAILURE);
3018 	}
3019 	/* Test for high level mutex */
3020 	if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) {
3021 		nge_error(ngep, "nge_add_intrs:"
3022 		    "Hi level interrupt not supported");
3023 
3024 		for (i = 0; i < actual; i++)
3025 			(void) ddi_intr_free(ngep->htable[i]);
3026 
3027 		kmem_free(ngep->htable, intr_size);
3028 
3029 		return (DDI_FAILURE);
3030 	}
3031 
3032 
3033 	/* Call ddi_intr_add_handler() */
3034 	for (i = 0; i < actual; i++) {
3035 		if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr,
3036 		    (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
3037 			nge_error(ngep, "ddi_intr_add_handler() "
3038 			    "failed %d\n", ret);
3039 
3040 			/* Free already allocated intr */
3041 			for (i = 0; i < actual; i++) {
3042 				(void) ddi_intr_free(ngep->htable[i]);
3043 			}
3044 
3045 			kmem_free(ngep->htable, intr_size);
3046 
3047 			return (DDI_FAILURE);
3048 		}
3049 	}
3050 
3051 	if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap))
3052 	    != DDI_SUCCESS) {
3053 		nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret);
3054 
3055 		for (i = 0; i < actual; i++) {
3056 			(void) ddi_intr_remove_handler(ngep->htable[i]);
3057 			(void) ddi_intr_free(ngep->htable[i]);
3058 		}
3059 
3060 		kmem_free(ngep->htable, intr_size);
3061 
3062 		return (DDI_FAILURE);
3063 	}
3064 
3065 	return (DDI_SUCCESS);
3066 }
3067 
3068 /*
3069  * nge_rem_intrs:
3070  *
3071  * Unregister FIXED or MSI interrupts
3072  */
3073 static void
3074 nge_rem_intrs(nge_t *ngep)
3075 {
3076 	int	i;
3077 
3078 	NGE_DEBUG(("nge_rem_intrs\n"));
3079 
3080 	/* Disable all interrupts */
3081 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
3082 		/* Call ddi_intr_block_disable() */
3083 		(void) ddi_intr_block_disable(ngep->htable,
3084 		    ngep->intr_actual_cnt);
3085 	} else {
3086 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
3087 			(void) ddi_intr_disable(ngep->htable[i]);
3088 		}
3089 	}
3090 
3091 	/* Call ddi_intr_remove_handler() */
3092 	for (i = 0; i < ngep->intr_actual_cnt; i++) {
3093 		(void) ddi_intr_remove_handler(ngep->htable[i]);
3094 		(void) ddi_intr_free(ngep->htable[i]);
3095 	}
3096 
3097 	kmem_free(ngep->htable,
3098 	    ngep->intr_req_cnt * sizeof (ddi_intr_handle_t));
3099 }
3100