xref: /illumos-gate/usr/src/uts/common/io/xge/drv/xge.c (revision 3afe87ebb25691cb6d158edaa34a6fb9b703a691)
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-2005 Neterion, Inc.
29  *  All right Reserved.
30  *
31  *  FileName :    xge.c
32  *
33  *  Description:  Xge main Solaris specific initialization & routines
34  *		  for upper layer driver
35  *
36  */
37 #include "xgell.h"
38 
39 static int xge_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd);
40 static int xge_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd);
41 static int xge_quiesce(dev_info_t *dev_info);
42 
43 DDI_DEFINE_STREAM_OPS(xge_ops, nulldev, nulldev, xge_attach, xge_detach,
44     nodev, NULL, D_MP, NULL, xge_quiesce);
45 
46 /* Standard Module linkage initialization for a Streams driver */
47 extern struct mod_ops mod_driverops;
48 
49 static struct modldrv modldrv = {
50 	&mod_driverops,		/* Type of module.  This one is a driver */
51 	XGELL_DESC,		/* short description */
52 	&xge_ops		/* driver specific ops */
53 };
54 
55 static struct modlinkage modlinkage = {
56 	MODREV_1, {(void *)&modldrv, NULL}
57 };
58 
59 /* Xge device attributes */
60 ddi_device_acc_attr_t xge_dev_attr = {
61 	DDI_DEVICE_ATTR_V0,
62 	DDI_NEVERSWAP_ACC,
63 	DDI_STRICTORDER_ACC
64 };
65 ddi_device_acc_attr_t *p_xge_dev_attr = &xge_dev_attr;
66 
67 /*
68  * xgell_callback_crit_err
69  *
70  * This function called by HAL on Serious Error event. XGE_HAL_EVENT_SERR.
71  * Upper layer must analyze it based on %type.
72  */
73 static void
74 xge_callback_crit_err(void *userdata, xge_hal_event_e type, u64 serr_data)
75 {
76 	(void) xgell_onerr_reset(userdata);
77 }
78 
79 /*
80  * xge_xpak_alarm_log
81  * This function called by HAL on XPAK alarms. Upper layer must log the msg
82  * based on the xpak alarm type
83  */
84 static void
85 xge_xpak_alarm_log(void *userdata, xge_hal_xpak_alarm_type_e type)
86 {
87 	switch (type) {
88 	case XGE_HAL_XPAK_ALARM_EXCESS_TEMP:
89 		xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of "
90 		    "service. Excessive temperatures may result in "
91 		    "premature transceiver failure \n");
92 
93 		break;
94 	case XGE_HAL_XPAK_ALARM_EXCESS_BIAS_CURRENT:
95 		xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of "
96 		    "service Excessive bias currents may indicate "
97 		    "imminent laser diode failure \n");
98 
99 		break;
100 	case XGE_HAL_XPAK_ALARM_EXCESS_LASER_OUTPUT:
101 		xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of "
102 		    "service Excessive laser output power may saturate "
103 		    "far-end receiver\n");
104 
105 		break;
106 	default:
107 		xge_debug_osdep(XGE_ERR, "%s", "Undefined Xpak Alarm");
108 		break;
109 	}
110 
111 }
112 
113 /*
114  * xge_driver_init_hal
115  *
116  * To initialize HAL portion of driver.
117  */
118 static xge_hal_status_e
119 xge_driver_init_hal(void)
120 {
121 	static xge_hal_driver_config_t driver_config;
122 	xge_hal_uld_cbs_t uld_callbacks;
123 
124 	driver_config.queue_size_initial = 1;
125 	driver_config.queue_size_max = 4;
126 
127 	uld_callbacks.link_up = xgell_callback_link_up;
128 	uld_callbacks.link_down = xgell_callback_link_down;
129 	uld_callbacks.crit_err = xge_callback_crit_err;
130 	uld_callbacks.event = NULL;
131 	uld_callbacks.event_queued = NULL;
132 	uld_callbacks.before_device_poll = NULL;
133 	uld_callbacks.after_device_poll = NULL;
134 	uld_callbacks.sched_timer = NULL;
135 	uld_callbacks.xpak_alarm_log = xge_xpak_alarm_log;
136 
137 	return (xge_hal_driver_initialize(&driver_config, &uld_callbacks));
138 
139 }
140 
141 /*
142  * _init
143  *
144  * Solaris standard _init function for a device driver
145  */
146 int
147 _init(void)
148 {
149 	int ret = 0;
150 	xge_hal_status_e status;
151 
152 	status = xge_driver_init_hal();
153 	if (status != XGE_HAL_OK) {
154 		xge_debug_osdep(XGE_ERR, "can't initialize the driver (%d)",
155 		    status);
156 		return (EINVAL);
157 	}
158 
159 	xge_hal_driver_debug_module_mask_set(0xffffffff);
160 	xge_hal_driver_debug_level_set(XGE_TRACE);
161 
162 	mac_init_ops(&xge_ops, "xge");
163 	if ((ret = mod_install(&modlinkage)) != 0) {
164 		xge_hal_driver_terminate();
165 		mac_fini_ops(&xge_ops);
166 		xge_debug_osdep(XGE_ERR, "%s",
167 		    "Unable to install the driver");
168 		return (ret);
169 	}
170 
171 	return (0);
172 }
173 
174 /*
175  * _fini
176  *
177  * Solaris standard _fini function for device driver
178  */
179 int
180 _fini(void)
181 {
182 	int ret;
183 
184 	ret = mod_remove(&modlinkage);
185 	if (ret == 0) {
186 		xge_hal_driver_terminate();
187 		mac_fini_ops(&xge_ops);
188 	}
189 
190 	return (ret);
191 }
192 
193 /*
194  * _info
195  *
196  * Solaris standard _info function for device driver
197  */
198 int
199 _info(struct modinfo *pModinfo)
200 {
201 	return (mod_info(&modlinkage, pModinfo));
202 }
203 
204 /*
205  * xge_isr
206  * @arg: pointer to device private strucutre(hldev)
207  *
208  * This is the ISR scheduled by the OS to indicate to the
209  * driver that the receive/transmit operation is completed.
210  */
211 /* ARGSUSED */
212 static uint_t
213 xge_isr(caddr_t arg0, caddr_t arg1)
214 {
215 	xge_hal_status_e status;
216 	xge_hal_device_t *hldev = (xge_hal_device_t *)arg0;
217 	xgelldev_t *lldev = xge_hal_device_private(hldev);
218 
219 	if (!lldev->is_initialized) {
220 		return (DDI_INTR_UNCLAIMED);
221 	}
222 
223 	status = xge_hal_device_handle_irq(hldev);
224 
225 	return ((status == XGE_HAL_ERR_WRONG_IRQ) ?
226 	    DDI_INTR_UNCLAIMED : DDI_INTR_CLAIMED);
227 }
228 
229 /*
230  * Interrupt handler for transmit when MSI-X interrupt mechasnism is used
231  */
232 /* ARGSUSED */
233 static uint_t
234 xge_fifo_msix_isr(caddr_t arg0, caddr_t arg1)
235 {
236 	int got_tx;
237 	xge_hal_channel_t *channel = (xge_hal_channel_t *)arg0;
238 	xgelldev_t *lldev = xge_hal_device_private(channel->devh);
239 
240 	if (!lldev->is_initialized) {
241 		return (DDI_INTR_UNCLAIMED);
242 	}
243 	(void) xge_hal_device_poll_tx_channel(channel, &got_tx);
244 
245 	return (DDI_INTR_CLAIMED);
246 }
247 
248 /*
249  * Interrupt handler for receive when MSI-X interrupt mechasnism is used
250  */
251 /* ARGSUSED */
252 static uint_t
253 xge_ring_msix_isr(caddr_t arg0, caddr_t arg1)
254 {
255 	int got_rx;
256 	xge_hal_channel_t *channel = (xge_hal_channel_t *)arg0;
257 	xgelldev_t *lldev = xge_hal_device_private(channel->devh);
258 
259 	if (!lldev->is_initialized) {
260 		return (DDI_INTR_UNCLAIMED);
261 	}
262 	(void) xge_hal_device_poll_rx_channel(channel, &got_rx);
263 
264 	return (DDI_INTR_CLAIMED);
265 }
266 
267 /*
268  * Configure single ring
269  */
270 static void
271 xge_ring_config(dev_info_t *dev_info, xge_hal_device_config_t *device_config,
272     int index)
273 {
274 	char msg[MSG_SIZE];
275 
276 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_configured", index);
277 	device_config->ring.queue[index].configured =
278 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS,
279 	    msg, index < XGELL_RX_RING_NUM_MAX ? 1 : 0);
280 
281 	/* no point to configure it further if unconfigured */
282 	if (!device_config->ring.queue[index].configured)
283 		return;
284 
285 #if defined(__sparc)
286 	device_config->ring.queue[index].no_snoop_bits = 1;
287 #endif
288 
289 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_max", index);
290 	device_config->ring.queue[index].max =
291 	    ddi_prop_get_int(DDI_DEV_T_ANY,
292 	    dev_info, DDI_PROP_DONTPASS, msg,
293 	    XGE_HAL_DEFAULT_USE_HARDCODE);
294 
295 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_initial", index);
296 	device_config->ring.queue[index].initial =
297 	    ddi_prop_get_int(DDI_DEV_T_ANY,
298 	    dev_info, DDI_PROP_DONTPASS, msg,
299 	    XGE_HAL_DEFAULT_USE_HARDCODE);
300 
301 	if (device_config->ring.queue[index].initial ==
302 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
303 		device_config->ring.queue[index].initial =
304 		    device_config->ring.queue[index].max =
305 		    XGE_HAL_DEFAULT_RING_QUEUE_BLOCKS;
306 	}
307 
308 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_buffer_mode", index);
309 	device_config->ring.queue[index].buffer_mode =
310 	    ddi_prop_get_int(DDI_DEV_T_ANY,
311 	    dev_info, DDI_PROP_DONTPASS, msg,
312 	    XGE_HAL_RING_QUEUE_BUFFER_MODE_DEFAULT);
313 
314 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_dram_size_mb", index);
315 	device_config->ring.queue[index].dram_size_mb =
316 	    ddi_prop_get_int(DDI_DEV_T_ANY,
317 	    dev_info, DDI_PROP_DONTPASS, msg,
318 	    XGE_HAL_DEFAULT_USE_HARDCODE);
319 
320 	(void) xge_os_snprintf(msg, MSG_SIZE,
321 	    "ring%d_backoff_interval_us", index);
322 	device_config->ring.queue[index].backoff_interval_us =
323 	    ddi_prop_get_int(DDI_DEV_T_ANY,
324 	    dev_info, DDI_PROP_DONTPASS, msg,
325 	    XGE_HAL_DEFAULT_BACKOFF_INTERVAL_US);
326 
327 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_max_frm_len", index);
328 	device_config->ring.queue[index].max_frm_len =
329 	    ddi_prop_get_int(DDI_DEV_T_ANY,
330 	    dev_info, DDI_PROP_DONTPASS, msg,
331 	    XGE_HAL_RING_USE_MTU);
332 
333 
334 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_priority", index);
335 	device_config->ring.queue[index].priority =
336 	    ddi_prop_get_int(DDI_DEV_T_ANY,
337 	    dev_info, DDI_PROP_DONTPASS, msg,
338 	    XGE_HAL_DEFAULT_RING_PRIORITY);
339 
340 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_a", index);
341 	device_config->ring.queue[index].rti.urange_a =
342 	    ddi_prop_get_int(DDI_DEV_T_ANY,
343 	    dev_info, DDI_PROP_DONTPASS, msg,
344 	    XGE_HAL_DEFAULT_RX_URANGE_A);
345 
346 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_a", index);
347 	device_config->ring.queue[index].rti.ufc_a =
348 	    ddi_prop_get_int(DDI_DEV_T_ANY,
349 	    dev_info, DDI_PROP_DONTPASS, msg,
350 	    XGE_HAL_DEFAULT_RX_UFC_A);
351 
352 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_b", index);
353 	device_config->ring.queue[index].rti.urange_b =
354 	    ddi_prop_get_int(DDI_DEV_T_ANY,
355 	    dev_info, DDI_PROP_DONTPASS, msg,
356 	    XGE_HAL_DEFAULT_RX_URANGE_B);
357 
358 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_b", index);
359 	device_config->ring.queue[index].rti.ufc_b =
360 	    ddi_prop_get_int(DDI_DEV_T_ANY,
361 	    dev_info, DDI_PROP_DONTPASS, msg,
362 	    device_config->mtu > XGE_HAL_DEFAULT_MTU ?
363 	    XGE_HAL_DEFAULT_RX_UFC_B_J:
364 	    XGE_HAL_DEFAULT_RX_UFC_B_N);
365 
366 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_c", index);
367 	device_config->ring.queue[index].rti.urange_c =
368 	    ddi_prop_get_int(DDI_DEV_T_ANY,
369 	    dev_info, DDI_PROP_DONTPASS, msg,
370 	    XGE_HAL_DEFAULT_RX_URANGE_C);
371 
372 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_c", index);
373 	device_config->ring.queue[index].rti.ufc_c =
374 	    ddi_prop_get_int(DDI_DEV_T_ANY,
375 	    dev_info, DDI_PROP_DONTPASS, msg,
376 	    device_config->mtu > XGE_HAL_DEFAULT_MTU ?
377 	    XGE_HAL_DEFAULT_RX_UFC_C_J:
378 	    XGE_HAL_DEFAULT_RX_UFC_C_N);
379 
380 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_d", index);
381 	device_config->ring.queue[index].rti.ufc_d =
382 	    ddi_prop_get_int(DDI_DEV_T_ANY,
383 	    dev_info, DDI_PROP_DONTPASS, msg,
384 	    XGE_HAL_DEFAULT_RX_UFC_D);
385 
386 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_timer_val", index);
387 	device_config->ring.queue[index].rti.timer_val_us =
388 	    ddi_prop_get_int(DDI_DEV_T_ANY,
389 	    dev_info, DDI_PROP_DONTPASS, msg,
390 	    XGE_HAL_DEFAULT_RX_TIMER_VAL);
391 
392 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_timer_ac_en", index);
393 	device_config->ring.queue[index].rti.timer_ac_en =
394 	    ddi_prop_get_int(DDI_DEV_T_ANY,
395 	    dev_info, DDI_PROP_DONTPASS, msg,
396 	    XGE_HAL_DEFAULT_RX_TIMER_AC_EN);
397 
398 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_indicate_max_pkts",
399 	    index);
400 	device_config->ring.queue[index].indicate_max_pkts =
401 	    ddi_prop_get_int(DDI_DEV_T_ANY,
402 	    dev_info, DDI_PROP_DONTPASS, msg,
403 	    (device_config->bimodal_interrupts ?
404 	    XGE_HAL_DEFAULT_INDICATE_MAX_PKTS_B :
405 	    XGE_HAL_DEFAULT_INDICATE_MAX_PKTS_N));
406 
407 	/*
408 	 * Enable RTH steering if needed HERE!!!!
409 	 */
410 	if (device_config->rth_en == XGE_HAL_RTH_ENABLE)
411 		device_config->ring.queue[index].rth_en = 1;
412 }
413 
414 /*
415  * Configure single fifo
416  */
417 static void
418 xge_fifo_config(dev_info_t *dev_info, xge_hal_device_config_t *device_config,
419     int index)
420 {
421 	char msg[MSG_SIZE];
422 
423 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_configured", index);
424 	device_config->fifo.queue[index].configured =
425 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS,
426 	    msg, index < XGELL_TX_RING_NUM_MAX ? 1 : 0);
427 
428 	/* no point to configure it further */
429 	if (!device_config->fifo.queue[index].configured)
430 		return;
431 
432 #if defined(__sparc)
433 	device_config->fifo.queue[index].no_snoop_bits = 1;
434 #endif
435 
436 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_max", index);
437 	device_config->fifo.queue[index].max = ddi_prop_get_int(DDI_DEV_T_ANY,
438 	    dev_info, DDI_PROP_DONTPASS, msg,
439 	    XGE_HAL_DEFAULT_USE_HARDCODE);
440 
441 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_initial", index);
442 	device_config->fifo.queue[index].initial =
443 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
444 	    XGE_HAL_DEFAULT_USE_HARDCODE);
445 
446 #if 0
447 	if (device_config->fifo.queue[index].initial ==
448 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
449 		if (device_config->mtu > XGE_HAL_DEFAULT_MTU) {
450 			device_config->fifo.queue[index].initial =
451 			    device_config->fifo.queue[index].max =
452 			    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_J;
453 		} else {
454 			device_config->fifo.queue[index].initial =
455 			    device_config->fifo.queue[index].max =
456 			    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_N;
457 		}
458 	}
459 #else
460 	if (device_config->fifo.queue[index].initial ==
461 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
462 		device_config->fifo.queue[index].max =
463 		    device_config->fifo.queue[index].initial =
464 		    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_A;
465 	}
466 #endif
467 
468 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_intr", index);
469 	device_config->fifo.queue[index].intr = ddi_prop_get_int(DDI_DEV_T_ANY,
470 	    dev_info, DDI_PROP_DONTPASS, msg,
471 	    XGE_HAL_DEFAULT_FIFO_QUEUE_INTR);
472 
473 	/*
474 	 * TTI 0 configuration
475 	 */
476 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_enable", index);
477 	device_config->fifo.queue[index].tti[index].enabled = ddi_prop_get_int(
478 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 1);
479 
480 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_a", index);
481 	device_config->fifo.queue[index].tti[index].urange_a = ddi_prop_get_int(
482 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
483 	    XGE_HAL_DEFAULT_TX_URANGE_A);
484 
485 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_a", index);
486 	device_config->fifo.queue[index].tti[index].ufc_a = ddi_prop_get_int(
487 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
488 	    XGE_HAL_DEFAULT_TX_UFC_A);
489 
490 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_b", index);
491 	device_config->fifo.queue[index].tti[index].urange_b = ddi_prop_get_int(
492 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
493 	    XGE_HAL_DEFAULT_TX_URANGE_B);
494 
495 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_b", index);
496 	device_config->fifo.queue[index].tti[index].ufc_b = ddi_prop_get_int(
497 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
498 	    XGE_HAL_DEFAULT_TX_UFC_B);
499 
500 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_c", index);
501 	device_config->fifo.queue[index].tti[index].urange_c = ddi_prop_get_int(
502 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
503 	    XGE_HAL_DEFAULT_TX_URANGE_C);
504 
505 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_c", index);
506 	device_config->fifo.queue[index].tti[index].ufc_c = ddi_prop_get_int(
507 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
508 	    XGE_HAL_DEFAULT_TX_UFC_C);
509 
510 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_d", index);
511 	device_config->fifo.queue[index].tti[index].ufc_d = ddi_prop_get_int(
512 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
513 	    XGE_HAL_DEFAULT_TX_UFC_D);
514 
515 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_timer_ac_en", index);
516 	device_config->fifo.queue[index].tti[index].timer_ac_en =
517 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
518 	    XGE_HAL_DEFAULT_TX_TIMER_AC_EN);
519 
520 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_timer_val", index);
521 	device_config->fifo.queue[index].tti[index].timer_val_us =
522 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
523 	    XGE_HAL_DEFAULT_TX_TIMER_VAL);
524 
525 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_timer_ci_en", index);
526 	device_config->fifo.queue[index].tti[index].timer_ci_en =
527 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
528 	    XGE_HAL_DEFAULT_TX_TIMER_CI_EN);
529 }
530 
531 /*
532  * xge_configuration_init
533  * @device_config: pointer to xge_hal_device_config_t
534  *
535  * This function will lookup properties from .conf file to init
536  * the configuration data structure. If a property is not in .conf
537  * file, the default value should be set.
538  */
539 static void
540 xge_configuration_init(dev_info_t *dev_info,
541     xge_hal_device_config_t *device_config, xgell_config_t *xgell_config)
542 {
543 	int i, rings_configured = 0, fifos_configured = 0;
544 
545 	/*
546 	 * Initialize link layer configuration first
547 	 */
548 	xgell_config->rx_dma_lowat = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
549 	    DDI_PROP_DONTPASS, "rx_dma_lowat", XGELL_RX_DMA_LOWAT);
550 	xgell_config->rx_pkt_burst = ddi_prop_get_int(DDI_DEV_T_ANY,
551 	    dev_info, DDI_PROP_DONTPASS, "rx_pkt_burst", XGELL_RX_PKT_BURST);
552 	xgell_config->tx_dma_lowat = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
553 	    DDI_PROP_DONTPASS, "tx_dma_lowat", XGELL_TX_DMA_LOWAT);
554 	xgell_config->lso_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
555 	    DDI_PROP_DONTPASS, "lso_enable", XGELL_CONF_ENABLE_BY_DEFAULT);
556 	xgell_config->msix_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
557 	    DDI_PROP_DONTPASS, "msix_enable", XGELL_CONF_ENABLE_BY_DEFAULT);
558 
559 	xgell_config->grouping = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
560 	    DDI_PROP_DONTPASS, "grouping", XGELL_CONF_GROUP_POLICY_DEFAULT);
561 
562 	switch (xgell_config->grouping) {
563 	case XGELL_CONF_GROUP_POLICY_VIRT:
564 		/*
565 		 * Enable layer 2 steering for better virtualization
566 		 */
567 		device_config->rth_en = XGE_HAL_RTH_DISABLE;
568 		device_config->rts_mac_en = XGE_HAL_RTS_MAC_ENABLE;
569 		break;
570 	case XGELL_CONF_GROUP_POLICY_PERF:
571 		/*
572 		 * Configure layer 4 RTH to hashing inbound traffic
573 		 */
574 		device_config->rth_en = XGE_HAL_RTH_ENABLE;
575 		device_config->rth_bucket_size = XGE_HAL_MAX_RTH_BUCKET_SIZE;
576 		device_config->rth_spdm_en = XGE_HAL_RTH_SPDM_DISABLE;
577 		device_config->rth_spdm_use_l4 = XGE_HAL_RTH_SPDM_USE_L4;
578 
579 		device_config->rts_mac_en = XGE_HAL_RTS_MAC_DISABLE;
580 		break;
581 	case XGELL_CONF_GROUP_POLICY_BASIC:
582 	default:
583 		/*
584 		 * Disable both RTS and RTH for single ring configuration
585 		 */
586 		device_config->rth_en = XGE_HAL_RTH_DISABLE;
587 		device_config->rts_mac_en = XGE_HAL_RTS_MAC_DISABLE;
588 		break;
589 	}
590 
591 	/*
592 	 * Initialize common properties
593 	 */
594 	device_config->mtu = ddi_prop_get_int(DDI_DEV_T_ANY,
595 	    dev_info, DDI_PROP_DONTPASS, "default_mtu",
596 	    XGE_HAL_DEFAULT_INITIAL_MTU);
597 	device_config->isr_polling_cnt = ddi_prop_get_int(DDI_DEV_T_ANY,
598 	    dev_info, DDI_PROP_DONTPASS, "isr_polling_cnt",
599 	    XGE_HAL_DEFAULT_ISR_POLLING_CNT);
600 	device_config->latency_timer = ddi_prop_get_int(DDI_DEV_T_ANY,
601 	    dev_info, DDI_PROP_DONTPASS, "latency_timer",
602 	    XGE_HAL_DEFAULT_LATENCY_TIMER);
603 	device_config->max_splits_trans = ddi_prop_get_int(DDI_DEV_T_ANY,
604 	    dev_info, DDI_PROP_DONTPASS, "max_splits_trans",
605 	    XGE_HAL_DEFAULT_SPLIT_TRANSACTION);
606 	device_config->mmrb_count = ddi_prop_get_int(DDI_DEV_T_ANY,
607 	    dev_info, DDI_PROP_DONTPASS, "mmrb_count",
608 	    XGE_HAL_DEFAULT_MMRB_COUNT);
609 	device_config->shared_splits = ddi_prop_get_int(DDI_DEV_T_ANY,
610 	    dev_info, DDI_PROP_DONTPASS, "shared_splits",
611 	    XGE_HAL_DEFAULT_SHARED_SPLITS);
612 	device_config->stats_refresh_time_sec = ddi_prop_get_int(DDI_DEV_T_ANY,
613 	    dev_info, DDI_PROP_DONTPASS, "stats_refresh_time",
614 	    XGE_HAL_DEFAULT_STATS_REFRESH_TIME);
615 	device_config->device_poll_millis = ddi_prop_get_int(DDI_DEV_T_ANY,
616 	    dev_info, DDI_PROP_DONTPASS, "device_poll_millis",
617 	    XGE_HAL_DEFAULT_DEVICE_POLL_MILLIS);
618 	device_config->pci_freq_mherz = ddi_prop_get_int(DDI_DEV_T_ANY,
619 	    dev_info, DDI_PROP_DONTPASS, "pci_freq_mherz",
620 	    XGE_HAL_DEFAULT_USE_HARDCODE);
621 
622 	/*
623 	 * Initialize ring properties
624 	 */
625 	device_config->ring.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY,
626 	    dev_info, DDI_PROP_DONTPASS, "ring_memblock_size",
627 	    XGE_HAL_DEFAULT_RING_MEMBLOCK_SIZE);
628 	device_config->ring.strip_vlan_tag = XGE_HAL_RING_DONOT_STRIP_VLAN_TAG;
629 
630 	/*
631 	 * Bimodal Interrupts - TTI 56 configuration
632 	 */
633 	device_config->bimodal_interrupts = ddi_prop_get_int(
634 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_interrupts",
635 	    XGE_HAL_DEFAULT_BIMODAL_INTERRUPTS);
636 	device_config->bimodal_timer_lo_us = ddi_prop_get_int(
637 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_timer_lo_us",
638 	    XGE_HAL_DEFAULT_BIMODAL_TIMER_LO_US);
639 	device_config->bimodal_timer_hi_us = ddi_prop_get_int(
640 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_timer_hi_us",
641 	    XGE_HAL_DEFAULT_BIMODAL_TIMER_HI_US);
642 
643 	/*
644 	 * Go through all possibly configured rings. Each ring could be
645 	 * configured individually. To enable/disable specific ring, just
646 	 * set ring->configured = [1|0].
647 	 *
648 	 * By default *all* rings enabled.
649 	 */
650 	for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
651 		xge_ring_config(dev_info, device_config, i);
652 		if (device_config->ring.queue[i].configured)
653 			rings_configured++;
654 	}
655 
656 	/*
657 	 * Initialize mac properties
658 	 */
659 	device_config->mac.tmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY,
660 	    dev_info, DDI_PROP_DONTPASS, "mac_tmac_util_period",
661 	    XGE_HAL_DEFAULT_TMAC_UTIL_PERIOD);
662 	device_config->mac.rmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY,
663 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_util_period",
664 	    XGE_HAL_DEFAULT_RMAC_UTIL_PERIOD);
665 	device_config->mac.rmac_bcast_en = ddi_prop_get_int(DDI_DEV_T_ANY,
666 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_bcast_en",
667 	    1); /* HAL never provide a good named macro */
668 	device_config->mac.rmac_pause_gen_en = ddi_prop_get_int(DDI_DEV_T_ANY,
669 	    dev_info, DDI_PROP_DONTPASS, "rmac_pause_gen_en",
670 	    XGE_HAL_DEFAULT_RMAC_PAUSE_GEN_DIS);
671 	device_config->mac.rmac_pause_rcv_en = ddi_prop_get_int(DDI_DEV_T_ANY,
672 	    dev_info, DDI_PROP_DONTPASS, "rmac_pause_rcv_en",
673 	    XGE_HAL_DEFAULT_RMAC_PAUSE_RCV_DIS);
674 	device_config->mac.rmac_pause_time = ddi_prop_get_int(DDI_DEV_T_ANY,
675 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_pause_time",
676 	    XGE_HAL_DEFAULT_RMAC_HIGH_PTIME);
677 	device_config->mac.mc_pause_threshold_q0q3 =
678 	    ddi_prop_get_int(DDI_DEV_T_ANY,
679 	    dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q0q3",
680 	    XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q0Q3);
681 	device_config->mac.mc_pause_threshold_q4q7 =
682 	    ddi_prop_get_int(DDI_DEV_T_ANY,
683 	    dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q4q7",
684 	    XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q4Q7);
685 
686 	/*
687 	 * Initialize fifo properties
688 	 */
689 	device_config->fifo.max_frags = ddi_prop_get_int(DDI_DEV_T_ANY,
690 	    dev_info, DDI_PROP_DONTPASS, "fifo_max_frags",
691 	    XGE_HAL_DEFAULT_FIFO_FRAGS);
692 	device_config->fifo.reserve_threshold = ddi_prop_get_int(DDI_DEV_T_ANY,
693 	    dev_info, DDI_PROP_DONTPASS, "fifo_reserve_threshold",
694 	    XGE_HAL_DEFAULT_FIFO_RESERVE_THRESHOLD);
695 	device_config->fifo.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY,
696 	    dev_info, DDI_PROP_DONTPASS, "fifo_memblock_size",
697 	    XGE_HAL_DEFAULT_FIFO_MEMBLOCK_SIZE);
698 #ifdef XGE_HAL_ALIGN_XMIT
699 	device_config->fifo.alignment_size = ddi_prop_get_int(DDI_DEV_T_ANY,
700 	    dev_info, DDI_PROP_DONTPASS, "fifo_copied_frag_size",
701 	    XGE_HAL_DEFAULT_FIFO_ALIGNMENT_SIZE);
702 	device_config->fifo.max_aligned_frags = ddi_prop_get_int(DDI_DEV_T_ANY,
703 	    dev_info, DDI_PROP_DONTPASS, "fifo_copied_max_frags",
704 	    XGE_HAL_DEFAULT_FIFO_MAX_ALIGNED_FRAGS);
705 #endif
706 
707 	/*
708 	 * Go through all possibly configured fifos. Each fifo could be
709 	 * configured individually. To enable/disable specific fifo, just
710 	 * set fifo->configured = [0|1].
711 	 *
712 	 * By default *all* fifos enabled.
713 	 */
714 	for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++) {
715 		xge_fifo_config(dev_info, device_config, i);
716 		if (device_config->fifo.queue[i].configured)
717 			fifos_configured++;
718 	}
719 
720 	/*
721 	 * Initialize errors dumping
722 	 */
723 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
724 	    dev_info, DDI_PROP_DONTPASS, "dump_on_serr",
725 	    0);
726 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
727 	    dev_info, DDI_PROP_DONTPASS, "dump_on_eccerr",
728 	    0);
729 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
730 	    dev_info, DDI_PROP_DONTPASS, "dump_on_parityerr",
731 	    0);
732 
733 	/*
734 	 * LRO tunables
735 	 */
736 	device_config->lro_sg_size = ddi_prop_get_int(DDI_DEV_T_ANY,
737 	    dev_info, DDI_PROP_DONTPASS, "lro_sg_size",
738 	    XGE_HAL_DEFAULT_LRO_SG_SIZE);
739 	device_config->lro_frm_len = ddi_prop_get_int(DDI_DEV_T_ANY,
740 	    dev_info, DDI_PROP_DONTPASS, "lro_frm_len",
741 	    XGE_HAL_DEFAULT_LRO_FRM_LEN);
742 
743 	/*
744 	 * Initialize other link layer configuration first
745 	 */
746 	xgell_config->rx_buffer_total = ddi_prop_get_int(DDI_DEV_T_ANY,
747 	    dev_info, DDI_PROP_DONTPASS, "rx_buffer_total",
748 	    device_config->ring.queue[XGELL_RX_RING_MAIN].initial *
749 	    XGELL_RX_BUFFER_TOTAL);
750 	xgell_config->rx_buffer_total += XGELL_RX_BUFFER_RECYCLE_CACHE;
751 	xgell_config->rx_buffer_post_hiwat = ddi_prop_get_int(DDI_DEV_T_ANY,
752 	    dev_info, DDI_PROP_DONTPASS, "rx_buffer_post_hiwat",
753 	    device_config->ring.queue[XGELL_RX_RING_MAIN].initial *
754 	    XGELL_RX_BUFFER_POST_HIWAT);
755 	xgell_config->rx_buffer_post_hiwat += XGELL_RX_BUFFER_RECYCLE_CACHE;
756 }
757 
758 /*
759  * xge_alloc_intrs:
760  *
761  * Allocate FIXED or MSIX interrupts.
762  */
763 static int
764 xge_alloc_intrs(xgelldev_t *lldev)
765 {
766 	dev_info_t *dip = lldev->dev_info;
767 	int avail, actual, count = 0;
768 	int i, intr_behavior, ret;
769 
770 	if (lldev->intr_type == DDI_INTR_TYPE_MSIX) {
771 		intr_behavior = DDI_INTR_ALLOC_STRICT;
772 		(void) ddi_prop_create(DDI_DEV_T_NONE, dip,
773 		    DDI_PROP_CANSLEEP, "#msix-request", NULL, 0);
774 	} else {
775 		intr_behavior = DDI_INTR_ALLOC_NORMAL;
776 	}
777 
778 	/* Get number of interrupts */
779 	ret = ddi_intr_get_nintrs(dip, lldev->intr_type, &count);
780 	if ((ret != DDI_SUCCESS) || (count == 0)) {
781 		xge_debug_osdep(XGE_ERR, "ddi_intr_get_nintrs() failed, "
782 		    "ret: %d, count: %d", ret, count);
783 
784 		goto _err_exit0;
785 	}
786 
787 	/* Get number of available interrupts */
788 	ret = ddi_intr_get_navail(dip, lldev->intr_type, &avail);
789 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
790 		xge_debug_osdep(XGE_ERR, "ddi_intr_get_navail() failure, "
791 		    "ret: %d, avail: %d", ret, avail);
792 
793 		goto _err_exit0;
794 	}
795 
796 	if (avail < lldev->intr_cnt) {
797 		xge_debug_osdep(XGE_ERR, "%d interrupts wanted while only "
798 		    "%d available", lldev->intr_cnt, avail);
799 		goto _err_exit0;
800 	}
801 
802 	/* Allocate an array of interrupt handles */
803 	lldev->intr_table_size = lldev->intr_cnt * sizeof (ddi_intr_handle_t);
804 	lldev->intr_table = kmem_alloc(lldev->intr_table_size, KM_SLEEP);
805 
806 	/* Call ddi_intr_alloc() */
807 	ret = ddi_intr_alloc(dip, lldev->intr_table, lldev->intr_type, 0,
808 	    lldev->intr_cnt, &actual, intr_behavior);
809 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
810 		xge_debug_osdep(XGE_ERR, "ddi_intr_alloc() failed %d", ret);
811 		goto _err_exit1;
812 	}
813 
814 	xge_debug_osdep(XGE_TRACE, "%s: Requested: %d, Granted: %d",
815 	    lldev->intr_type == DDI_INTR_TYPE_MSIX ? "MSI-X" :
816 	    "IRQA", count, actual);
817 
818 	if (lldev->intr_cnt != actual) {
819 		xge_debug_osdep(XGE_ERR, "Not enough resources granted");
820 		goto _err_exit2;
821 	}
822 
823 	/*
824 	 * Get priority for first msi, assume remaining are all the same
825 	 */
826 	if ((ret = ddi_intr_get_pri(lldev->intr_table[0], &lldev->intr_pri)) !=
827 	    DDI_SUCCESS) {
828 		xge_debug_osdep(XGE_ERR, "ddi_intr_get_pri() failed %d", ret);
829 		goto _err_exit2;
830 	}
831 
832 	return (DDI_SUCCESS);
833 
834 _err_exit2:
835 	/* Free already allocated intr */
836 	for (i = 0; i < actual; i++) {
837 		(void) ddi_intr_free(lldev->intr_table[i]);
838 	}
839 _err_exit1:
840 	kmem_free(lldev->intr_table, lldev->intr_table_size);
841 	lldev->intr_table = NULL;
842 _err_exit0:
843 	if (lldev->intr_type == DDI_INTR_TYPE_MSIX)
844 		(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "#msix-request");
845 	return (DDI_FAILURE);
846 }
847 
848 /*
849  * xge_free_intrs:
850  *
851  * Free previously allocated interrupts.
852  */
853 static void
854 xge_free_intrs(xgelldev_t *lldev)
855 {
856 	int i;
857 	dev_info_t *dip = lldev->dev_info;
858 
859 	/* Free already allocated intr */
860 	for (i = 0; i < lldev->intr_cnt; i++) {
861 		(void) ddi_intr_free(lldev->intr_table[i]);
862 	}
863 	kmem_free(lldev->intr_table, lldev->intr_table_size);
864 	lldev->intr_table = NULL;
865 
866 	if (lldev->intr_type == DDI_INTR_TYPE_MSIX)
867 		(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "#msix-request");
868 }
869 
870 /*
871  * xge_add_intrs:
872  *
873  * Register FIXED or MSI interrupts.
874  */
875 int
876 xge_add_intrs(xgelldev_t *lldev)
877 {
878 	int i, ret;
879 	xge_hal_device_t *hldev = lldev->devh;
880 	xge_hal_device_config_t *hal_conf = &hldev->config;
881 	xge_hal_ring_config_t *ring_conf = &hal_conf->ring;
882 	xge_hal_fifo_config_t *fifo_conf = &hal_conf->fifo;
883 	xge_list_t *item;
884 	int msix_idx = 1; /* 0 by default is reserved for Alarms. */
885 	xge_hal_channel_t *assigned[XGELL_RX_RING_NUM_MAX +
886 	    XGELL_TX_RING_NUM_MAX + 1];
887 
888 	xge_assert(lldev->intr_table != NULL);
889 	switch (lldev->intr_type) {
890 	case DDI_INTR_TYPE_FIXED:
891 		ret = ddi_intr_add_handler(lldev->intr_table[0],
892 		    (ddi_intr_handler_t *)xge_isr,
893 		    (caddr_t)hldev, 0);
894 		if (ret != DDI_SUCCESS) {
895 			xge_debug_osdep(XGE_ERR, "ddi_intr_add_handler(FIXED)"
896 			    "failed %d", ret);
897 			return (DDI_FAILURE);
898 		}
899 		break;
900 
901 	case DDI_INTR_TYPE_MSIX:
902 		i = 0;
903 		xge_list_for_each(item, &hldev->free_channels) {
904 			xge_hal_channel_t *channel = xge_container_of(item,
905 			    xge_hal_channel_t, item);
906 			i = channel->post_qid;
907 			if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
908 				if (fifo_conf->queue[i].configured) {
909 					assigned[msix_idx] = channel;
910 					msix_idx++;
911 				}
912 			} else {
913 				if (ring_conf->queue[i].configured) {
914 					assigned[msix_idx] = channel;
915 					msix_idx++;
916 				}
917 			}
918 		}
919 		for (i = 0; i < lldev->intr_cnt; i++) {
920 			uint_t (*intr)(caddr_t, caddr_t);
921 			caddr_t intr_arg;
922 
923 			/* partition MSIX vectors */
924 			if (i == 0) {
925 				intr = xge_isr;
926 				intr_arg = (caddr_t)hldev;
927 				xge_debug_osdep(XGE_TRACE,
928 				    "Channel-A: using MSI-X #0");
929 			} else if (assigned[i] && assigned[i]->type ==
930 			    XGE_HAL_CHANNEL_TYPE_FIFO) {
931 				intr = xge_fifo_msix_isr;
932 				intr_arg = (caddr_t)assigned[i];
933 				xge_debug_osdep(XGE_TRACE, "Channel-Tx%d"
934 				    "using MSI-X #%d",
935 				    assigned[i]->post_qid, i);
936 			} else if (assigned[i] && assigned[i]->type ==
937 			    XGE_HAL_CHANNEL_TYPE_RING) {
938 				intr = xge_ring_msix_isr;
939 				intr_arg = (caddr_t)assigned[i];
940 				xge_debug_osdep(XGE_TRACE, "Channel-Rx%d: "
941 				    "using MSI-X #%d",
942 				    assigned[i]->post_qid, i);
943 			}
944 			ret = ddi_intr_add_handler(lldev->intr_table[i], intr,
945 			    intr_arg, (caddr_t)(uintptr_t)i);
946 			if (ret != DDI_SUCCESS) {
947 				int j;
948 				xge_debug_osdep(XGE_ERR,
949 				    "ddi_intr_add_handler()"
950 				    " failed %d", ret);
951 				for (j = 0; j < i; j++) {
952 					(void) ddi_intr_remove_handler(
953 					    lldev->intr_table[j]);
954 				}
955 				return (DDI_FAILURE);
956 			}
957 		}
958 
959 		for (i = 1; i < msix_idx; i++)
960 			(void) xge_hal_channel_msix_set(assigned[i], i);
961 		break;
962 
963 	default:
964 		break;
965 	}
966 	ret = ddi_intr_get_cap(lldev->intr_table[0], &lldev->intr_cap);
967 	if (ret != DDI_SUCCESS) {
968 		xge_debug_osdep(XGE_ERR, "ddi_intr_get_cap() failed %d", ret);
969 		for (i = 0; i < lldev->intr_cnt; i++) {
970 			(void) ddi_intr_remove_handler(lldev->intr_table[i]);
971 		}
972 		return (DDI_FAILURE);
973 	}
974 	return (DDI_SUCCESS);
975 }
976 
977 
978 /*
979  * xge_enable_intrs:
980  *
981  * Enable FIXED or MSI interrupts
982  */
983 int
984 xge_enable_intrs(xgelldev_t *lldev)
985 {
986 	int ret, i;
987 
988 	if (lldev->intr_cap & DDI_INTR_FLAG_BLOCK) {
989 		/* Call ddi_intr_block_enable() for MSI(X) interrupts */
990 		if ((ret = ddi_intr_block_enable(lldev->intr_table,
991 		    lldev->intr_cnt)) != DDI_SUCCESS) {
992 			xge_debug_osdep(XGE_ERR, "ddi_intr_enable() failed, "
993 			    "ret 0x%x", ret);
994 			return (DDI_FAILURE);
995 		}
996 	} else {
997 		/* Call ddi_intr_enable for MSI(X) or FIXED interrupts */
998 		for (i = 0; i < lldev->intr_cnt; i++) {
999 			if ((ret = ddi_intr_enable(lldev->intr_table[i]))
1000 			    != DDI_SUCCESS) {
1001 				int j;
1002 
1003 				xge_debug_osdep(XGE_ERR, "ddi_intr_enable() "
1004 				    "failed, ret 0x%x", ret);
1005 
1006 				/* unwind */
1007 				for (j = 0; j < i; j++) {
1008 					(void) ddi_intr_disable(
1009 					    lldev->intr_table[j]);
1010 				}
1011 
1012 				return (DDI_FAILURE);
1013 			}
1014 		}
1015 	}
1016 
1017 	return (DDI_SUCCESS);
1018 }
1019 
1020 /*
1021  * xge_disable_intrs:
1022  *
1023  * Disable FIXED or MSI interrupts
1024  */
1025 void
1026 xge_disable_intrs(xgelldev_t *lldev)
1027 {
1028 	int i;
1029 
1030 	if (lldev->intr_cap & DDI_INTR_FLAG_BLOCK) {
1031 		/* Call ddi_intr_block_disable() */
1032 		(void) ddi_intr_block_disable(lldev->intr_table,
1033 		    lldev->intr_cnt);
1034 	} else {
1035 		for (i = 0; i < lldev->intr_cnt; i++) {
1036 			(void) ddi_intr_disable(lldev->intr_table[i]);
1037 		}
1038 	}
1039 }
1040 
1041 /*
1042  * xge_rem_intrs:
1043  *
1044  * Unregister FIXED or MSI interrupts
1045  */
1046 void
1047 xge_rem_intrs(xgelldev_t *lldev)
1048 {
1049 	int i;
1050 
1051 	xge_assert(lldev->intr_table != NULL);
1052 
1053 	/* Call ddi_intr_remove_handler() */
1054 	for (i = 0; i < lldev->intr_cnt; i++) {
1055 		(void) ddi_intr_remove_handler(lldev->intr_table[i]);
1056 	}
1057 }
1058 
1059 /*
1060  * xge_attach
1061  * @dev_info: pointer to dev_info_t structure
1062  * @cmd: attach command to process
1063  *
1064  * This is a solaris standard attach function.  This
1065  * function initializes the Xframe  identified
1066  * by the dev_info_t structure and setup the driver
1067  * data structures corresponding to the Xframe Card.
1068  * This function also registers the XFRAME device
1069  * instance with the MAC Layer.
1070  * If this function returns success then the OS
1071  * will attach the HBA controller to this
1072  * driver.
1073  */
1074 static int
1075 xge_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd)
1076 {
1077 	xgelldev_t *ll;
1078 	xgell_config_t *xgell_config;
1079 	xge_hal_device_config_t *device_config;
1080 	xge_hal_device_t *hldev;
1081 	xge_hal_device_attr_t attr;
1082 	xge_hal_status_e status;
1083 	int ret, intr_types, i;
1084 
1085 	xge_debug_osdep(XGE_TRACE, "XGE_ATTACH cmd %d", cmd);
1086 
1087 	switch (cmd) {
1088 	case DDI_ATTACH:
1089 		break;
1090 
1091 	case DDI_RESUME:
1092 	case DDI_PM_RESUME:
1093 		xge_debug_osdep(XGE_ERR, "%s", "resume unsupported yet");
1094 		ret = DDI_FAILURE;
1095 		goto _exit0;
1096 
1097 	default:
1098 		xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd);
1099 		ret = DDI_FAILURE;
1100 		goto _exit0;
1101 	}
1102 
1103 	xgell_config = kmem_zalloc(sizeof (xgell_config_t), KM_SLEEP);
1104 	device_config = kmem_zalloc(sizeof (xge_hal_device_config_t), KM_SLEEP);
1105 
1106 	/*
1107 	 * Initialize all configurations
1108 	 */
1109 	xge_configuration_init(dev_info, device_config, xgell_config);
1110 
1111 	/* Determine which types of interrupts supported */
1112 	ret = ddi_intr_get_supported_types(dev_info, &intr_types);
1113 	if ((ret != DDI_SUCCESS) || (!(intr_types & DDI_INTR_TYPE_FIXED))) {
1114 		xge_debug_osdep(XGE_ERR, "%s",
1115 		    "fixed type interrupt is not supported");
1116 		goto _exit0a;
1117 	}
1118 
1119 	/* map BAR0 */
1120 	ret = ddi_regs_map_setup(dev_info, 1, (caddr_t *)&attr.bar0,
1121 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh0);
1122 	if (ret != DDI_SUCCESS) {
1123 		xge_debug_osdep(XGE_ERR, "unable to map bar0: [%d]", ret);
1124 		goto _exit0a;
1125 	}
1126 
1127 	/* map BAR1 */
1128 	ret = ddi_regs_map_setup(dev_info, 2, (caddr_t *)&attr.bar1,
1129 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh1);
1130 	if (ret != DDI_SUCCESS) {
1131 		xge_debug_osdep(XGE_ERR, "unable to map bar1: [%d]", ret);
1132 		goto _exit1;
1133 	}
1134 
1135 	/* map BAR2 MSI(X) */
1136 	ret = ddi_regs_map_setup(dev_info, 2, (caddr_t *)&attr.bar2,
1137 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh2);
1138 	if (ret != DDI_SUCCESS) {
1139 		xge_debug_osdep(XGE_ERR, "unable to map bar2: [%d]", ret);
1140 		goto _exit1a;
1141 	}
1142 
1143 	/* preallocate memory for new HAL device and private LL part */
1144 	hldev = kmem_zalloc(sizeof (xge_hal_device_t), KM_SLEEP);
1145 
1146 	/* Get the PCI Configuartion space handle */
1147 	ret = pci_config_setup(dev_info, &attr.cfgh);
1148 	if (ret != DDI_SUCCESS) {
1149 		xge_debug_osdep(XGE_ERR, "%s", "can not setup config space");
1150 		goto _exit2a;
1151 	}
1152 
1153 	attr.pdev = dev_info;
1154 
1155 	ret = xgell_device_alloc(hldev, dev_info, &ll);
1156 	if (ret != DDI_SUCCESS) {
1157 		xge_debug_osdep(XGE_ERR,
1158 		    "%s",
1159 		    "unable to allocate new LL device");
1160 		goto _exit3;
1161 	}
1162 
1163 	/*
1164 	 * Init multiple rings configuration
1165 	 */
1166 	switch (xgell_config->grouping) {
1167 	case XGELL_CONF_GROUP_POLICY_VIRT:
1168 		ll->init_rx_rings = XGELL_RX_RING_NUM_MAX; /* 8 */
1169 		ll->init_tx_rings = XGELL_TX_RING_NUM_MAX; /* 8 */
1170 		ll->init_rx_groups = ll->init_rx_rings;
1171 		break;
1172 	case XGELL_CONF_GROUP_POLICY_PERF:
1173 		ll->init_rx_rings = XGELL_RX_RING_NUM_MAX; /* 8 */
1174 		ll->init_tx_rings = XGELL_TX_RING_NUM_MAX; /* 8 */
1175 		ll->init_rx_groups = 1;
1176 		break;
1177 	case XGELL_CONF_GROUP_POLICY_BASIC:
1178 		ll->init_rx_rings = XGELL_RX_RING_NUM_MIN; /* 1 */
1179 		ll->init_tx_rings = XGELL_TX_RING_NUM_MIN; /* 1 */
1180 		ll->init_rx_groups = ll->init_rx_rings;
1181 		break;
1182 	default:
1183 		ASSERT(0);
1184 		break;
1185 	}
1186 
1187 	/*
1188 	 * Init MSI-X configuration
1189 	 */
1190 	if (xgell_config->msix_enable && intr_types & DDI_INTR_TYPE_MSIX) {
1191 		ll->intr_type = DDI_INTR_TYPE_MSIX;
1192 		ll->intr_cnt = 1;
1193 		for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++)
1194 			if (device_config->fifo.queue[i].configured)
1195 				ll->intr_cnt++;
1196 		for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++)
1197 			if (device_config->ring.queue[i].configured)
1198 				ll->intr_cnt++;
1199 	} else {
1200 		ll->intr_type = DDI_INTR_TYPE_FIXED;
1201 		ll->intr_cnt = 1;
1202 	}
1203 
1204 	/*
1205 	 * Allocate interrupt(s)
1206 	 */
1207 	while ((ret = xge_alloc_intrs(ll)) != DDI_SUCCESS) {
1208 		if (ll->intr_type == DDI_INTR_TYPE_MSIX) {
1209 			xgell_config->msix_enable = 0;
1210 			ll->intr_type = DDI_INTR_TYPE_FIXED;
1211 			ll->intr_cnt = 1;
1212 			device_config->intr_mode = XGE_HAL_INTR_MODE_IRQLINE;
1213 			xge_debug_osdep(XGE_TRACE,
1214 			    "Unable to allocate MSI-X handlers"
1215 			    " - defaulting to IRQA");
1216 			continue;
1217 		}
1218 		goto _exit3a;
1219 	}
1220 
1221 	if (ll->intr_type == DDI_INTR_TYPE_MSIX) {
1222 		device_config->intr_mode = XGE_HAL_INTR_MODE_MSIX;
1223 		device_config->bimodal_interrupts = 0;
1224 	} else {
1225 		device_config->intr_mode = XGE_HAL_INTR_MODE_IRQLINE;
1226 	}
1227 
1228 	attr.irqh = ll->intr_pri;
1229 
1230 	/* initialize HW */
1231 	status = xge_hal_device_initialize(hldev, &attr, device_config);
1232 	if (status != XGE_HAL_OK) {
1233 		switch (status) {
1234 		case XGE_HAL_ERR_DRIVER_NOT_INITIALIZED:
1235 			xge_debug_osdep(XGE_ERR, "%s",
1236 			    "driver is not initialized");
1237 			ret = DDI_FAILURE;
1238 			goto _exit3b;
1239 		case XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT:
1240 			xge_debug_osdep(XGE_ERR, "%s",
1241 			    "device is not quiescent");
1242 			ret = DDI_EBUSY;
1243 			goto _exit3b;
1244 		case XGE_HAL_ERR_OUT_OF_MEMORY:
1245 			xge_debug_osdep(XGE_ERR, "%s",
1246 			    "unable to allocate memory");
1247 			ret = DDI_ENOMEM;
1248 			goto _exit3b;
1249 		default:
1250 			xge_debug_osdep(XGE_ERR,
1251 			    "can't initialize the device: %d", status);
1252 			ret = DDI_FAILURE;
1253 			goto _exit3b;
1254 		}
1255 	}
1256 
1257 	/* register interrupt handler for handling xge device interrupts */
1258 	ret = xge_add_intrs(ll);
1259 	if (ret != DDI_SUCCESS)
1260 		goto _exit4;
1261 
1262 	/* allocate and register Link Layer */
1263 	ret = xgell_device_register(ll, xgell_config);
1264 	if (ret != DDI_SUCCESS) {
1265 		goto _exit5;
1266 	}
1267 
1268 	/* store ll as a HAL private part */
1269 	xge_hal_device_private_set(hldev, ll);
1270 
1271 	kmem_free(device_config, sizeof (xge_hal_device_config_t));
1272 	kmem_free(xgell_config, sizeof (xgell_config_t));
1273 
1274 	return (DDI_SUCCESS);
1275 
1276 _exit5:
1277 	xge_rem_intrs(ll);
1278 _exit4:
1279 	xge_hal_device_terminate(hldev);
1280 _exit3b:
1281 	xge_free_intrs(ll);
1282 _exit3a:
1283 	xgell_device_free(ll);
1284 _exit3:
1285 	pci_config_teardown(&attr.cfgh);
1286 _exit2a:
1287 	kmem_free(hldev, sizeof (xge_hal_device_t));
1288 _exit2:
1289 	ddi_regs_map_free(&attr.regh2);
1290 _exit1a:
1291 	ddi_regs_map_free(&attr.regh1);
1292 _exit1:
1293 	ddi_regs_map_free(&attr.regh0);
1294 _exit0a:
1295 	kmem_free(device_config, sizeof (xge_hal_device_config_t));
1296 	kmem_free(xgell_config, sizeof (xgell_config_t));
1297 _exit0:
1298 	return (ret);
1299 }
1300 
1301 /*
1302  * quiesce(9E) entry point.
1303  *
1304  * This function is called when the system is single-threaded at high
1305  * PIL with preemption disabled. Therefore, this function must not be
1306  * blocked.
1307  *
1308  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
1309  * DDI_FAILURE indicates an error condition and should almost never happen.
1310  */
1311 static int
1312 xge_quiesce(dev_info_t *dev_info)
1313 {
1314 	xge_hal_device_t *hldev =
1315 	    (xge_hal_device_t *)ddi_get_driver_private(dev_info);
1316 
1317 	xgelldev_t *lldev = xge_hal_device_private(hldev);
1318 
1319 	xge_hal_device_quiesce(hldev, lldev->devh);
1320 
1321 	return (DDI_SUCCESS);
1322 }
1323 
1324 /*
1325  * xge_detach
1326  * @dev_info: pointer to dev_info_t structure
1327  * @cmd: attach command to process
1328  *
1329  * This function is called by OS when the system is about
1330  * to shutdown or when the super user tries to unload
1331  * the driver. This function frees all the memory allocated
1332  * during xge_attach() and also unregisters the Xframe
1333  * device instance from the GLD framework.
1334  */
1335 static int
1336 xge_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd)
1337 {
1338 	xge_hal_device_t *hldev;
1339 	xge_hal_device_attr_t *attr;
1340 	xgelldev_t *lldev;
1341 
1342 	xge_debug_osdep(XGE_TRACE, "XGE_DETACH cmd %d", cmd);
1343 
1344 	hldev = (xge_hal_device_t *)ddi_get_driver_private(dev_info);
1345 	attr = xge_hal_device_attr(hldev);
1346 	lldev = xge_hal_device_private(hldev);
1347 
1348 	switch (cmd) {
1349 	case DDI_DETACH:
1350 		break;
1351 
1352 	case DDI_PM_SUSPEND:
1353 		xge_debug_osdep(XGE_ERR, "%s", "suspend unsupported yet");
1354 		return (DDI_FAILURE);
1355 
1356 	default:
1357 		xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd);
1358 		return (DDI_FAILURE);
1359 	}
1360 
1361 	if (lldev->is_initialized) {
1362 		xge_debug_osdep(XGE_ERR, "%s",
1363 		    "can not detach: device is not unplumbed");
1364 		return (DDI_FAILURE);
1365 	}
1366 
1367 	xge_hal_device_terminating(hldev);
1368 	if (xgell_device_unregister(lldev) != DDI_SUCCESS) {
1369 		return (DDI_FAILURE);
1370 	}
1371 	xge_hal_device_terminate(hldev);
1372 
1373 	xge_rem_intrs(lldev);
1374 	xge_free_intrs(lldev);
1375 	xgell_device_free(lldev);
1376 	pci_config_teardown(&attr->cfgh);
1377 	ddi_regs_map_free(&attr->regh2);
1378 	ddi_regs_map_free(&attr->regh1);
1379 	ddi_regs_map_free(&attr->regh0);
1380 	kmem_free(hldev, sizeof (xge_hal_device_t));
1381 
1382 	return (DDI_SUCCESS);
1383 }
1384