xref: /illumos-gate/usr/src/uts/common/io/xge/drv/xge.c (revision da14cebe)
1a23fd118Syl /*
2a23fd118Syl  * CDDL HEADER START
3a23fd118Syl  *
4a23fd118Syl  * The contents of this file are subject to the terms of the
5a23fd118Syl  * Common Development and Distribution License (the "License").
6a23fd118Syl  * You may not use this file except in compliance with the License.
7a23fd118Syl  *
8a23fd118Syl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a23fd118Syl  * or http://www.opensolaris.org/os/licensing.
10a23fd118Syl  * See the License for the specific language governing permissions
11a23fd118Syl  * and limitations under the License.
12a23fd118Syl  *
13a23fd118Syl  * When distributing Covered Code, include this CDDL HEADER in each
14a23fd118Syl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a23fd118Syl  * If applicable, add the following below this CDDL HEADER, with the
16a23fd118Syl  * fields enclosed by brackets "[]" replaced with your own identifying
17a23fd118Syl  * information: Portions Copyright [yyyy] [name of copyright owner]
18a23fd118Syl  *
19a23fd118Syl  * CDDL HEADER END
20a23fd118Syl  */
21a23fd118Syl 
22a23fd118Syl /*
237eced415Sxw  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24a23fd118Syl  * Use is subject to license terms.
25a23fd118Syl  */
26a23fd118Syl 
27a23fd118Syl /*
28a23fd118Syl  *  Copyright (c) 2002-2005 Neterion, Inc.
29a23fd118Syl  *  All right Reserved.
30a23fd118Syl  *
31a23fd118Syl  *  FileName :    xge.c
32a23fd118Syl  *
33a23fd118Syl  *  Description:  Xge main Solaris specific initialization & routines
34a23fd118Syl  *		  for upper layer driver
35a23fd118Syl  *
36a23fd118Syl  */
37a23fd118Syl #include "xgell.h"
38a23fd118Syl 
39a23fd118Syl static int xge_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd);
40a23fd118Syl static int xge_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd);
4119397407SSherry Moore static int xge_quiesce(dev_info_t *dev_info);
42a23fd118Syl 
43a23fd118Syl DDI_DEFINE_STREAM_OPS(xge_ops, nulldev, nulldev, xge_attach, xge_detach,
4419397407SSherry Moore     nodev, NULL, D_MP, NULL, xge_quiesce);
45a23fd118Syl 
46a23fd118Syl /* Standard Module linkage initialization for a Streams driver */
47a23fd118Syl extern struct mod_ops mod_driverops;
48a23fd118Syl 
49a23fd118Syl static struct modldrv modldrv = {
50a23fd118Syl 	&mod_driverops,		/* Type of module.  This one is a driver */
51a23fd118Syl 	XGELL_DESC,		/* short description */
52a23fd118Syl 	&xge_ops		/* driver specific ops */
53a23fd118Syl };
54a23fd118Syl 
55a23fd118Syl static struct modlinkage modlinkage = {
56a23fd118Syl 	MODREV_1, {(void *)&modldrv, NULL}
57a23fd118Syl };
58a23fd118Syl 
59a23fd118Syl /* Xge device attributes */
60a23fd118Syl ddi_device_acc_attr_t xge_dev_attr = {
61a23fd118Syl 	DDI_DEVICE_ATTR_V0,
62a23fd118Syl 	DDI_NEVERSWAP_ACC,
63a23fd118Syl 	DDI_STRICTORDER_ACC
64a23fd118Syl };
65a23fd118Syl ddi_device_acc_attr_t *p_xge_dev_attr = &xge_dev_attr;
66a23fd118Syl 
67a23fd118Syl /*
68a23fd118Syl  * xgell_callback_crit_err
69a23fd118Syl  *
70a23fd118Syl  * This function called by HAL on Serious Error event. XGE_HAL_EVENT_SERR.
71a23fd118Syl  * Upper layer must analyze it based on %type.
72a23fd118Syl  */
73a23fd118Syl static void
xge_callback_crit_err(void * userdata,xge_hal_event_e type,u64 serr_data)74a23fd118Syl xge_callback_crit_err(void *userdata, xge_hal_event_e type, u64 serr_data)
75a23fd118Syl {
76a23fd118Syl 	(void) xgell_onerr_reset(userdata);
77a23fd118Syl }
78a23fd118Syl 
797eced415Sxw /*
807eced415Sxw  * xge_xpak_alarm_log
817eced415Sxw  * This function called by HAL on XPAK alarms. Upper layer must log the msg
827eced415Sxw  * based on the xpak alarm type
837eced415Sxw  */
847eced415Sxw static void
xge_xpak_alarm_log(void * userdata,xge_hal_xpak_alarm_type_e type)857eced415Sxw xge_xpak_alarm_log(void *userdata, xge_hal_xpak_alarm_type_e type)
867eced415Sxw {
877eced415Sxw 	switch (type) {
887eced415Sxw 	case XGE_HAL_XPAK_ALARM_EXCESS_TEMP:
897eced415Sxw 		xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of "
907eced415Sxw 		    "service. Excessive temperatures may result in "
917eced415Sxw 		    "premature transceiver failure \n");
927eced415Sxw 
937eced415Sxw 		break;
947eced415Sxw 	case XGE_HAL_XPAK_ALARM_EXCESS_BIAS_CURRENT:
957eced415Sxw 		xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of "
967eced415Sxw 		    "service Excessive bias currents may indicate "
977eced415Sxw 		    "imminent laser diode failure \n");
987eced415Sxw 
997eced415Sxw 		break;
1007eced415Sxw 	case XGE_HAL_XPAK_ALARM_EXCESS_LASER_OUTPUT:
1017eced415Sxw 		xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of "
1027eced415Sxw 		    "service Excessive laser output power may saturate "
1037eced415Sxw 		    "far-end receiver\n");
1047eced415Sxw 
1057eced415Sxw 		break;
1067eced415Sxw 	default:
1077eced415Sxw 		xge_debug_osdep(XGE_ERR, "%s", "Undefined Xpak Alarm");
1087eced415Sxw 		break;
1097eced415Sxw 	}
1107eced415Sxw 
1117eced415Sxw }
1127eced415Sxw 
113a23fd118Syl /*
114a23fd118Syl  * xge_driver_init_hal
115a23fd118Syl  *
116a23fd118Syl  * To initialize HAL portion of driver.
117a23fd118Syl  */
118a23fd118Syl static xge_hal_status_e
xge_driver_init_hal(void)119a23fd118Syl xge_driver_init_hal(void)
120a23fd118Syl {
121a23fd118Syl 	static xge_hal_driver_config_t driver_config;
122a23fd118Syl 	xge_hal_uld_cbs_t uld_callbacks;
123a23fd118Syl 
124a23fd118Syl 	driver_config.queue_size_initial = 1;
125a23fd118Syl 	driver_config.queue_size_max = 4;
126a23fd118Syl 
127a23fd118Syl 	uld_callbacks.link_up = xgell_callback_link_up;
128a23fd118Syl 	uld_callbacks.link_down = xgell_callback_link_down;
129a23fd118Syl 	uld_callbacks.crit_err = xge_callback_crit_err;
130*da14cebeSEric Cheng 	uld_callbacks.event = NULL;
131*da14cebeSEric Cheng 	uld_callbacks.event_queued = NULL;
132a23fd118Syl 	uld_callbacks.before_device_poll = NULL;
133a23fd118Syl 	uld_callbacks.after_device_poll = NULL;
134a23fd118Syl 	uld_callbacks.sched_timer = NULL;
1357eced415Sxw 	uld_callbacks.xpak_alarm_log = xge_xpak_alarm_log;
136a23fd118Syl 
137a23fd118Syl 	return (xge_hal_driver_initialize(&driver_config, &uld_callbacks));
138a23fd118Syl 
139a23fd118Syl }
140a23fd118Syl 
141a23fd118Syl /*
142a23fd118Syl  * _init
143a23fd118Syl  *
144a23fd118Syl  * Solaris standard _init function for a device driver
145a23fd118Syl  */
146a23fd118Syl int
_init(void)147a23fd118Syl _init(void)
148a23fd118Syl {
149a23fd118Syl 	int ret = 0;
150a23fd118Syl 	xge_hal_status_e status;
151a23fd118Syl 
152a23fd118Syl 	status = xge_driver_init_hal();
153a23fd118Syl 	if (status != XGE_HAL_OK) {
154a23fd118Syl 		xge_debug_osdep(XGE_ERR, "can't initialize the driver (%d)",
155a23fd118Syl 		    status);
156a23fd118Syl 		return (EINVAL);
157a23fd118Syl 	}
158a23fd118Syl 
159a23fd118Syl 	xge_hal_driver_debug_module_mask_set(0xffffffff);
160a23fd118Syl 	xge_hal_driver_debug_level_set(XGE_TRACE);
161a23fd118Syl 
162a23fd118Syl 	mac_init_ops(&xge_ops, "xge");
163a23fd118Syl 	if ((ret = mod_install(&modlinkage)) != 0) {
164a23fd118Syl 		xge_hal_driver_terminate();
165a23fd118Syl 		mac_fini_ops(&xge_ops);
166a23fd118Syl 		xge_debug_osdep(XGE_ERR, "%s",
167a23fd118Syl 		    "Unable to install the driver");
168a23fd118Syl 		return (ret);
169a23fd118Syl 	}
170a23fd118Syl 
171a23fd118Syl 	return (0);
172a23fd118Syl }
173a23fd118Syl 
174a23fd118Syl /*
175a23fd118Syl  * _fini
176a23fd118Syl  *
177a23fd118Syl  * Solaris standard _fini function for device driver
178a23fd118Syl  */
179a23fd118Syl int
_fini(void)180a23fd118Syl _fini(void)
181a23fd118Syl {
182a23fd118Syl 	int ret;
183a23fd118Syl 
184a23fd118Syl 	ret = mod_remove(&modlinkage);
185a23fd118Syl 	if (ret == 0) {
186a23fd118Syl 		xge_hal_driver_terminate();
187a23fd118Syl 		mac_fini_ops(&xge_ops);
188a23fd118Syl 	}
189a23fd118Syl 
190a23fd118Syl 	return (ret);
191a23fd118Syl }
192a23fd118Syl 
193a23fd118Syl /*
194a23fd118Syl  * _info
195a23fd118Syl  *
196a23fd118Syl  * Solaris standard _info function for device driver
197a23fd118Syl  */
198a23fd118Syl int
_info(struct modinfo * pModinfo)199a23fd118Syl _info(struct modinfo *pModinfo)
200a23fd118Syl {
201a23fd118Syl 	return (mod_info(&modlinkage, pModinfo));
202a23fd118Syl }
203a23fd118Syl 
204a23fd118Syl /*
205a23fd118Syl  * xge_isr
206a23fd118Syl  * @arg: pointer to device private strucutre(hldev)
207a23fd118Syl  *
208a23fd118Syl  * This is the ISR scheduled by the OS to indicate to the
209a23fd118Syl  * driver that the receive/transmit operation is completed.
210a23fd118Syl  */
211*da14cebeSEric Cheng /* ARGSUSED */
212a23fd118Syl static uint_t
xge_isr(caddr_t arg0,caddr_t arg1)2137eced415Sxw xge_isr(caddr_t arg0, caddr_t arg1)
214a23fd118Syl {
215a23fd118Syl 	xge_hal_status_e status;
2167eced415Sxw 	xge_hal_device_t *hldev = (xge_hal_device_t *)arg0;
217a23fd118Syl 	xgelldev_t *lldev = xge_hal_device_private(hldev);
218a23fd118Syl 
219a23fd118Syl 	if (!lldev->is_initialized) {
2207eced415Sxw 		return (DDI_INTR_UNCLAIMED);
221a23fd118Syl 	}
222a23fd118Syl 
223a23fd118Syl 	status = xge_hal_device_handle_irq(hldev);
224a23fd118Syl 
225a23fd118Syl 	return ((status == XGE_HAL_ERR_WRONG_IRQ) ?
226a23fd118Syl 	    DDI_INTR_UNCLAIMED : DDI_INTR_CLAIMED);
227a23fd118Syl }
228a23fd118Syl 
2297eced415Sxw /*
2307eced415Sxw  * Interrupt handler for transmit when MSI-X interrupt mechasnism is used
2317eced415Sxw  */
2327eced415Sxw /* ARGSUSED */
2337eced415Sxw static uint_t
xge_fifo_msix_isr(caddr_t arg0,caddr_t arg1)2347eced415Sxw xge_fifo_msix_isr(caddr_t arg0, caddr_t arg1)
2357eced415Sxw {
2367eced415Sxw 	int got_tx;
2377eced415Sxw 	xge_hal_channel_t *channel = (xge_hal_channel_t *)arg0;
2387eced415Sxw 	xgelldev_t *lldev = xge_hal_device_private(channel->devh);
2397eced415Sxw 
2407eced415Sxw 	if (!lldev->is_initialized) {
2417eced415Sxw 		return (DDI_INTR_UNCLAIMED);
2427eced415Sxw 	}
2437eced415Sxw 	(void) xge_hal_device_poll_tx_channel(channel, &got_tx);
2447eced415Sxw 
2457eced415Sxw 	return (DDI_INTR_CLAIMED);
2467eced415Sxw }
2477eced415Sxw 
2487eced415Sxw /*
2497eced415Sxw  * Interrupt handler for receive when MSI-X interrupt mechasnism is used
2507eced415Sxw  */
2517eced415Sxw /* ARGSUSED */
2527eced415Sxw static uint_t
xge_ring_msix_isr(caddr_t arg0,caddr_t arg1)2537eced415Sxw xge_ring_msix_isr(caddr_t arg0, caddr_t arg1)
2547eced415Sxw {
2557eced415Sxw 	int got_rx;
2567eced415Sxw 	xge_hal_channel_t *channel = (xge_hal_channel_t *)arg0;
2577eced415Sxw 	xgelldev_t *lldev = xge_hal_device_private(channel->devh);
2587eced415Sxw 
2597eced415Sxw 	if (!lldev->is_initialized) {
2607eced415Sxw 		return (DDI_INTR_UNCLAIMED);
2617eced415Sxw 	}
2627eced415Sxw 	(void) xge_hal_device_poll_rx_channel(channel, &got_rx);
2637eced415Sxw 
2647eced415Sxw 	return (DDI_INTR_CLAIMED);
2657eced415Sxw }
2667eced415Sxw 
2677eced415Sxw /*
2687eced415Sxw  * Configure single ring
2697eced415Sxw  */
2707eced415Sxw static void
xge_ring_config(dev_info_t * dev_info,xge_hal_device_config_t * device_config,int index)271*da14cebeSEric Cheng xge_ring_config(dev_info_t *dev_info, xge_hal_device_config_t *device_config,
272*da14cebeSEric Cheng     int index)
2737eced415Sxw {
2747eced415Sxw 	char msg[MSG_SIZE];
2757eced415Sxw 
276*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_configured", index);
277*da14cebeSEric Cheng 	device_config->ring.queue[index].configured =
2787eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS,
279*da14cebeSEric Cheng 	    msg, index < XGELL_RX_RING_NUM_MAX ? 1 : 0);
2807eced415Sxw 
2817eced415Sxw 	/* no point to configure it further if unconfigured */
282*da14cebeSEric Cheng 	if (!device_config->ring.queue[index].configured)
2837eced415Sxw 		return;
2847eced415Sxw 
2857eced415Sxw #if defined(__sparc)
286*da14cebeSEric Cheng 	device_config->ring.queue[index].no_snoop_bits = 1;
2877eced415Sxw #endif
2887eced415Sxw 
289*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_max", index);
290*da14cebeSEric Cheng 	device_config->ring.queue[index].max =
2917eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
2927eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
2937eced415Sxw 	    XGE_HAL_DEFAULT_USE_HARDCODE);
2947eced415Sxw 
295*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_initial", index);
296*da14cebeSEric Cheng 	device_config->ring.queue[index].initial =
2977eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
2987eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
2997eced415Sxw 	    XGE_HAL_DEFAULT_USE_HARDCODE);
3007eced415Sxw 
301*da14cebeSEric Cheng 	if (device_config->ring.queue[index].initial ==
3027eced415Sxw 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
303*da14cebeSEric Cheng 		device_config->ring.queue[index].initial =
304*da14cebeSEric Cheng 		    device_config->ring.queue[index].max =
305*da14cebeSEric Cheng 		    XGE_HAL_DEFAULT_RING_QUEUE_BLOCKS;
3067eced415Sxw 	}
3077eced415Sxw 
308*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_buffer_mode", index);
309*da14cebeSEric Cheng 	device_config->ring.queue[index].buffer_mode =
3107eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3117eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3127eced415Sxw 	    XGE_HAL_RING_QUEUE_BUFFER_MODE_DEFAULT);
3137eced415Sxw 
314*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_dram_size_mb", index);
315*da14cebeSEric Cheng 	device_config->ring.queue[index].dram_size_mb =
3167eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3177eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3187eced415Sxw 	    XGE_HAL_DEFAULT_USE_HARDCODE);
3197eced415Sxw 
3207eced415Sxw 	(void) xge_os_snprintf(msg, MSG_SIZE,
321*da14cebeSEric Cheng 	    "ring%d_backoff_interval_us", index);
322*da14cebeSEric Cheng 	device_config->ring.queue[index].backoff_interval_us =
3237eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3247eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3257eced415Sxw 	    XGE_HAL_DEFAULT_BACKOFF_INTERVAL_US);
3267eced415Sxw 
327*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_max_frm_len", index);
328*da14cebeSEric Cheng 	device_config->ring.queue[index].max_frm_len =
3297eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3307eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3317eced415Sxw 	    XGE_HAL_RING_USE_MTU);
3327eced415Sxw 
3337eced415Sxw 
334*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_priority", index);
335*da14cebeSEric Cheng 	device_config->ring.queue[index].priority =
3367eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3377eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3387eced415Sxw 	    XGE_HAL_DEFAULT_RING_PRIORITY);
3397eced415Sxw 
340*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_a", index);
341*da14cebeSEric Cheng 	device_config->ring.queue[index].rti.urange_a =
3427eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3437eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3447eced415Sxw 	    XGE_HAL_DEFAULT_RX_URANGE_A);
3457eced415Sxw 
346*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_a", index);
347*da14cebeSEric Cheng 	device_config->ring.queue[index].rti.ufc_a =
3487eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3497eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3507eced415Sxw 	    XGE_HAL_DEFAULT_RX_UFC_A);
3517eced415Sxw 
352*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_b", index);
353*da14cebeSEric Cheng 	device_config->ring.queue[index].rti.urange_b =
3547eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3557eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3567eced415Sxw 	    XGE_HAL_DEFAULT_RX_URANGE_B);
3577eced415Sxw 
358*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_b", index);
359*da14cebeSEric Cheng 	device_config->ring.queue[index].rti.ufc_b =
3607eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3617eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3627eced415Sxw 	    device_config->mtu > XGE_HAL_DEFAULT_MTU ?
3637eced415Sxw 	    XGE_HAL_DEFAULT_RX_UFC_B_J:
3647eced415Sxw 	    XGE_HAL_DEFAULT_RX_UFC_B_N);
3657eced415Sxw 
366*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_c", index);
367*da14cebeSEric Cheng 	device_config->ring.queue[index].rti.urange_c =
3687eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3697eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3707eced415Sxw 	    XGE_HAL_DEFAULT_RX_URANGE_C);
3717eced415Sxw 
372*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_c", index);
373*da14cebeSEric Cheng 	device_config->ring.queue[index].rti.ufc_c =
3747eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3757eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3767eced415Sxw 	    device_config->mtu > XGE_HAL_DEFAULT_MTU ?
3777eced415Sxw 	    XGE_HAL_DEFAULT_RX_UFC_C_J:
3787eced415Sxw 	    XGE_HAL_DEFAULT_RX_UFC_C_N);
3797eced415Sxw 
380*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_d", index);
381*da14cebeSEric Cheng 	device_config->ring.queue[index].rti.ufc_d =
3827eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3837eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3847eced415Sxw 	    XGE_HAL_DEFAULT_RX_UFC_D);
3857eced415Sxw 
386*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_timer_val", index);
387*da14cebeSEric Cheng 	device_config->ring.queue[index].rti.timer_val_us =
3887eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3897eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3907eced415Sxw 	    XGE_HAL_DEFAULT_RX_TIMER_VAL);
3917eced415Sxw 
392*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_timer_ac_en", index);
393*da14cebeSEric Cheng 	device_config->ring.queue[index].rti.timer_ac_en =
3947eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
3957eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
3967eced415Sxw 	    XGE_HAL_DEFAULT_RX_TIMER_AC_EN);
3977eced415Sxw 
398*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_indicate_max_pkts",
399*da14cebeSEric Cheng 	    index);
400*da14cebeSEric Cheng 	device_config->ring.queue[index].indicate_max_pkts =
4017eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY,
4027eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
4037eced415Sxw 	    (device_config->bimodal_interrupts ?
4047eced415Sxw 	    XGE_HAL_DEFAULT_INDICATE_MAX_PKTS_B :
4057eced415Sxw 	    XGE_HAL_DEFAULT_INDICATE_MAX_PKTS_N));
4067eced415Sxw 
407*da14cebeSEric Cheng 	/*
408*da14cebeSEric Cheng 	 * Enable RTH steering if needed HERE!!!!
409*da14cebeSEric Cheng 	 */
410*da14cebeSEric Cheng 	if (device_config->rth_en == XGE_HAL_RTH_ENABLE)
411*da14cebeSEric Cheng 		device_config->ring.queue[index].rth_en = 1;
4127eced415Sxw }
4137eced415Sxw 
4147eced415Sxw /*
4157eced415Sxw  * Configure single fifo
4167eced415Sxw  */
4177eced415Sxw static void
xge_fifo_config(dev_info_t * dev_info,xge_hal_device_config_t * device_config,int index)418*da14cebeSEric Cheng xge_fifo_config(dev_info_t *dev_info, xge_hal_device_config_t *device_config,
419*da14cebeSEric Cheng     int index)
4207eced415Sxw {
4217eced415Sxw 	char msg[MSG_SIZE];
4227eced415Sxw 
423*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_configured", index);
424*da14cebeSEric Cheng 	device_config->fifo.queue[index].configured =
4257eced415Sxw 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS,
426*da14cebeSEric Cheng 	    msg, index < XGELL_TX_RING_NUM_MAX ? 1 : 0);
4277eced415Sxw 
4287eced415Sxw 	/* no point to configure it further */
429*da14cebeSEric Cheng 	if (!device_config->fifo.queue[index].configured)
4307eced415Sxw 		return;
4317eced415Sxw 
4327eced415Sxw #if defined(__sparc)
433*da14cebeSEric Cheng 	device_config->fifo.queue[index].no_snoop_bits = 1;
4347eced415Sxw #endif
4357eced415Sxw 
436*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_max", index);
437*da14cebeSEric Cheng 	device_config->fifo.queue[index].max = ddi_prop_get_int(DDI_DEV_T_ANY,
4387eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
4397eced415Sxw 	    XGE_HAL_DEFAULT_USE_HARDCODE);
4407eced415Sxw 
441*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_initial", index);
442*da14cebeSEric Cheng 	device_config->fifo.queue[index].initial =
443*da14cebeSEric Cheng 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
4447eced415Sxw 	    XGE_HAL_DEFAULT_USE_HARDCODE);
4457eced415Sxw 
446*da14cebeSEric Cheng #if 0
447*da14cebeSEric Cheng 	if (device_config->fifo.queue[index].initial ==
4487eced415Sxw 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
4497eced415Sxw 		if (device_config->mtu > XGE_HAL_DEFAULT_MTU) {
450*da14cebeSEric Cheng 			device_config->fifo.queue[index].initial =
451*da14cebeSEric Cheng 			    device_config->fifo.queue[index].max =
4527eced415Sxw 			    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_J;
4537eced415Sxw 		} else {
454*da14cebeSEric Cheng 			device_config->fifo.queue[index].initial =
455*da14cebeSEric Cheng 			    device_config->fifo.queue[index].max =
4567eced415Sxw 			    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_N;
4577eced415Sxw 		}
4587eced415Sxw 	}
459*da14cebeSEric Cheng #else
460*da14cebeSEric Cheng 	if (device_config->fifo.queue[index].initial ==
461*da14cebeSEric Cheng 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
462*da14cebeSEric Cheng 		device_config->fifo.queue[index].max =
463*da14cebeSEric Cheng 		    device_config->fifo.queue[index].initial =
464*da14cebeSEric Cheng 		    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_A;
465*da14cebeSEric Cheng 	}
466*da14cebeSEric Cheng #endif
4677eced415Sxw 
468*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_intr", index);
469*da14cebeSEric Cheng 	device_config->fifo.queue[index].intr = ddi_prop_get_int(DDI_DEV_T_ANY,
4707eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, msg,
4717eced415Sxw 	    XGE_HAL_DEFAULT_FIFO_QUEUE_INTR);
4727eced415Sxw 
4737eced415Sxw 	/*
4747eced415Sxw 	 * TTI 0 configuration
4757eced415Sxw 	 */
476*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_enable", index);
477*da14cebeSEric Cheng 	device_config->fifo.queue[index].tti[index].enabled = ddi_prop_get_int(
4787eced415Sxw 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 1);
4797eced415Sxw 
480*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_a", index);
481*da14cebeSEric Cheng 	device_config->fifo.queue[index].tti[index].urange_a = ddi_prop_get_int(
4827eced415Sxw 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
4837eced415Sxw 	    XGE_HAL_DEFAULT_TX_URANGE_A);
4847eced415Sxw 
485*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_a", index);
486*da14cebeSEric Cheng 	device_config->fifo.queue[index].tti[index].ufc_a = ddi_prop_get_int(
4877eced415Sxw 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
4887eced415Sxw 	    XGE_HAL_DEFAULT_TX_UFC_A);
4897eced415Sxw 
490*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_b", index);
491*da14cebeSEric Cheng 	device_config->fifo.queue[index].tti[index].urange_b = ddi_prop_get_int(
4927eced415Sxw 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
4937eced415Sxw 	    XGE_HAL_DEFAULT_TX_URANGE_B);
4947eced415Sxw 
495*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_b", index);
496*da14cebeSEric Cheng 	device_config->fifo.queue[index].tti[index].ufc_b = ddi_prop_get_int(
4977eced415Sxw 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
4987eced415Sxw 	    XGE_HAL_DEFAULT_TX_UFC_B);
4997eced415Sxw 
500*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_c", index);
501*da14cebeSEric Cheng 	device_config->fifo.queue[index].tti[index].urange_c = ddi_prop_get_int(
5027eced415Sxw 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
5037eced415Sxw 	    XGE_HAL_DEFAULT_TX_URANGE_C);
5047eced415Sxw 
505*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_c", index);
506*da14cebeSEric Cheng 	device_config->fifo.queue[index].tti[index].ufc_c = ddi_prop_get_int(
5077eced415Sxw 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
5087eced415Sxw 	    XGE_HAL_DEFAULT_TX_UFC_C);
5097eced415Sxw 
510*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_d", index);
511*da14cebeSEric Cheng 	device_config->fifo.queue[index].tti[index].ufc_d = ddi_prop_get_int(
5127eced415Sxw 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
5137eced415Sxw 	    XGE_HAL_DEFAULT_TX_UFC_D);
5147eced415Sxw 
515*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_timer_ac_en", index);
516*da14cebeSEric Cheng 	device_config->fifo.queue[index].tti[index].timer_ac_en =
517*da14cebeSEric Cheng 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
5187eced415Sxw 	    XGE_HAL_DEFAULT_TX_TIMER_AC_EN);
5197eced415Sxw 
520*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_timer_val", index);
521*da14cebeSEric Cheng 	device_config->fifo.queue[index].tti[index].timer_val_us =
522*da14cebeSEric Cheng 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
5237eced415Sxw 	    XGE_HAL_DEFAULT_TX_TIMER_VAL);
5247eced415Sxw 
525*da14cebeSEric Cheng 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_timer_ci_en", index);
526*da14cebeSEric Cheng 	device_config->fifo.queue[index].tti[index].timer_ci_en =
527*da14cebeSEric Cheng 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
5287eced415Sxw 	    XGE_HAL_DEFAULT_TX_TIMER_CI_EN);
5297eced415Sxw }
5307eced415Sxw 
531a23fd118Syl /*
532a23fd118Syl  * xge_configuration_init
533a23fd118Syl  * @device_config: pointer to xge_hal_device_config_t
534a23fd118Syl  *
535a23fd118Syl  * This function will lookup properties from .conf file to init
536a23fd118Syl  * the configuration data structure. If a property is not in .conf
537a23fd118Syl  * file, the default value should be set.
538a23fd118Syl  */
539a23fd118Syl static void
xge_configuration_init(dev_info_t * dev_info,xge_hal_device_config_t * device_config,xgell_config_t * xgell_config)540a23fd118Syl xge_configuration_init(dev_info_t *dev_info,
541*da14cebeSEric Cheng     xge_hal_device_config_t *device_config, xgell_config_t *xgell_config)
542a23fd118Syl {
5437eced415Sxw 	int i, rings_configured = 0, fifos_configured = 0;
5447eced415Sxw 
545*da14cebeSEric Cheng 	/*
546*da14cebeSEric Cheng 	 * Initialize link layer configuration first
547*da14cebeSEric Cheng 	 */
548*da14cebeSEric Cheng 	xgell_config->rx_dma_lowat = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
549*da14cebeSEric Cheng 	    DDI_PROP_DONTPASS, "rx_dma_lowat", XGELL_RX_DMA_LOWAT);
550*da14cebeSEric Cheng 	xgell_config->rx_pkt_burst = ddi_prop_get_int(DDI_DEV_T_ANY,
551*da14cebeSEric Cheng 	    dev_info, DDI_PROP_DONTPASS, "rx_pkt_burst", XGELL_RX_PKT_BURST);
552*da14cebeSEric Cheng 	xgell_config->tx_dma_lowat = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
553*da14cebeSEric Cheng 	    DDI_PROP_DONTPASS, "tx_dma_lowat", XGELL_TX_DMA_LOWAT);
554*da14cebeSEric Cheng 	xgell_config->lso_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
555*da14cebeSEric Cheng 	    DDI_PROP_DONTPASS, "lso_enable", XGELL_CONF_ENABLE_BY_DEFAULT);
556*da14cebeSEric Cheng 	xgell_config->msix_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
557*da14cebeSEric Cheng 	    DDI_PROP_DONTPASS, "msix_enable", XGELL_CONF_ENABLE_BY_DEFAULT);
558*da14cebeSEric Cheng 
559*da14cebeSEric Cheng 	xgell_config->grouping = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
560*da14cebeSEric Cheng 	    DDI_PROP_DONTPASS, "grouping", XGELL_CONF_GROUP_POLICY_DEFAULT);
561*da14cebeSEric Cheng 
562*da14cebeSEric Cheng 	switch (xgell_config->grouping) {
563*da14cebeSEric Cheng 	case XGELL_CONF_GROUP_POLICY_VIRT:
564*da14cebeSEric Cheng 		/*
565*da14cebeSEric Cheng 		 * Enable layer 2 steering for better virtualization
566*da14cebeSEric Cheng 		 */
567*da14cebeSEric Cheng 		device_config->rth_en = XGE_HAL_RTH_DISABLE;
568*da14cebeSEric Cheng 		device_config->rts_mac_en = XGE_HAL_RTS_MAC_ENABLE;
569*da14cebeSEric Cheng 		break;
570*da14cebeSEric Cheng 	case XGELL_CONF_GROUP_POLICY_PERF:
571*da14cebeSEric Cheng 		/*
572*da14cebeSEric Cheng 		 * Configure layer 4 RTH to hashing inbound traffic
573*da14cebeSEric Cheng 		 */
574*da14cebeSEric Cheng 		device_config->rth_en = XGE_HAL_RTH_ENABLE;
575*da14cebeSEric Cheng 		device_config->rth_bucket_size = XGE_HAL_MAX_RTH_BUCKET_SIZE;
576*da14cebeSEric Cheng 		device_config->rth_spdm_en = XGE_HAL_RTH_SPDM_DISABLE;
577*da14cebeSEric Cheng 		device_config->rth_spdm_use_l4 = XGE_HAL_RTH_SPDM_USE_L4;
578*da14cebeSEric Cheng 
579*da14cebeSEric Cheng 		device_config->rts_mac_en = XGE_HAL_RTS_MAC_DISABLE;
580*da14cebeSEric Cheng 		break;
581*da14cebeSEric Cheng 	case XGELL_CONF_GROUP_POLICY_BASIC:
582*da14cebeSEric Cheng 	default:
583*da14cebeSEric Cheng 		/*
584*da14cebeSEric Cheng 		 * Disable both RTS and RTH for single ring configuration
585*da14cebeSEric Cheng 		 */
586*da14cebeSEric Cheng 		device_config->rth_en = XGE_HAL_RTH_DISABLE;
587*da14cebeSEric Cheng 		device_config->rts_mac_en = XGE_HAL_RTS_MAC_DISABLE;
588*da14cebeSEric Cheng 		break;
589*da14cebeSEric Cheng 	}
590*da14cebeSEric Cheng 
591a23fd118Syl 	/*
592a23fd118Syl 	 * Initialize common properties
593a23fd118Syl 	 */
594a23fd118Syl 	device_config->mtu = ddi_prop_get_int(DDI_DEV_T_ANY,
595a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "default_mtu",
596a23fd118Syl 	    XGE_HAL_DEFAULT_INITIAL_MTU);
597a23fd118Syl 	device_config->isr_polling_cnt = ddi_prop_get_int(DDI_DEV_T_ANY,
598a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "isr_polling_cnt",
599a23fd118Syl 	    XGE_HAL_DEFAULT_ISR_POLLING_CNT);
600a23fd118Syl 	device_config->latency_timer = ddi_prop_get_int(DDI_DEV_T_ANY,
601a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "latency_timer",
602a23fd118Syl 	    XGE_HAL_DEFAULT_LATENCY_TIMER);
603a23fd118Syl 	device_config->max_splits_trans = ddi_prop_get_int(DDI_DEV_T_ANY,
604a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "max_splits_trans",
605a23fd118Syl 	    XGE_HAL_DEFAULT_SPLIT_TRANSACTION);
606a23fd118Syl 	device_config->mmrb_count = ddi_prop_get_int(DDI_DEV_T_ANY,
607a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "mmrb_count",
608a23fd118Syl 	    XGE_HAL_DEFAULT_MMRB_COUNT);
609a23fd118Syl 	device_config->shared_splits = ddi_prop_get_int(DDI_DEV_T_ANY,
610a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "shared_splits",
611a23fd118Syl 	    XGE_HAL_DEFAULT_SHARED_SPLITS);
612a23fd118Syl 	device_config->stats_refresh_time_sec = ddi_prop_get_int(DDI_DEV_T_ANY,
613a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "stats_refresh_time",
614a23fd118Syl 	    XGE_HAL_DEFAULT_STATS_REFRESH_TIME);
615a23fd118Syl 	device_config->device_poll_millis = ddi_prop_get_int(DDI_DEV_T_ANY,
616a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "device_poll_millis",
617a23fd118Syl 	    XGE_HAL_DEFAULT_DEVICE_POLL_MILLIS);
618a23fd118Syl 	device_config->pci_freq_mherz = ddi_prop_get_int(DDI_DEV_T_ANY,
6198347601bSyl 	    dev_info, DDI_PROP_DONTPASS, "pci_freq_mherz",
6208347601bSyl 	    XGE_HAL_DEFAULT_USE_HARDCODE);
621a23fd118Syl 
622a23fd118Syl 	/*
623a23fd118Syl 	 * Initialize ring properties
624a23fd118Syl 	 */
625a23fd118Syl 	device_config->ring.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY,
626a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "ring_memblock_size",
627a23fd118Syl 	    XGE_HAL_DEFAULT_RING_MEMBLOCK_SIZE);
628a23fd118Syl 	device_config->ring.strip_vlan_tag = XGE_HAL_RING_DONOT_STRIP_VLAN_TAG;
629a23fd118Syl 
6307eced415Sxw 	/*
6317eced415Sxw 	 * Bimodal Interrupts - TTI 56 configuration
6327eced415Sxw 	 */
6337eced415Sxw 	device_config->bimodal_interrupts = ddi_prop_get_int(
6347eced415Sxw 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_interrupts",
6357eced415Sxw 	    XGE_HAL_DEFAULT_BIMODAL_INTERRUPTS);
6367eced415Sxw 	device_config->bimodal_timer_lo_us = ddi_prop_get_int(
6377eced415Sxw 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_timer_lo_us",
6387eced415Sxw 	    XGE_HAL_DEFAULT_BIMODAL_TIMER_LO_US);
6397eced415Sxw 	device_config->bimodal_timer_hi_us = ddi_prop_get_int(
6407eced415Sxw 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_timer_hi_us",
6417eced415Sxw 	    XGE_HAL_DEFAULT_BIMODAL_TIMER_HI_US);
6427eced415Sxw 
6437eced415Sxw 	/*
6447eced415Sxw 	 * Go through all possibly configured rings. Each ring could be
6457eced415Sxw 	 * configured individually. To enable/disable specific ring, just
6467eced415Sxw 	 * set ring->configured = [1|0].
6477eced415Sxw 	 *
6487eced415Sxw 	 * By default *all* rings enabled.
6497eced415Sxw 	 */
6507eced415Sxw 	for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
6517eced415Sxw 		xge_ring_config(dev_info, device_config, i);
6527eced415Sxw 		if (device_config->ring.queue[i].configured)
6537eced415Sxw 			rings_configured++;
654a23fd118Syl 	}
655a23fd118Syl 
656a23fd118Syl 	/*
657a23fd118Syl 	 * Initialize mac properties
658a23fd118Syl 	 */
659a23fd118Syl 	device_config->mac.tmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY,
660a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "mac_tmac_util_period",
661a23fd118Syl 	    XGE_HAL_DEFAULT_TMAC_UTIL_PERIOD);
662a23fd118Syl 	device_config->mac.rmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY,
663a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_util_period",
664a23fd118Syl 	    XGE_HAL_DEFAULT_RMAC_UTIL_PERIOD);
665a23fd118Syl 	device_config->mac.rmac_bcast_en = ddi_prop_get_int(DDI_DEV_T_ANY,
666a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_bcast_en",
667a23fd118Syl 	    1); /* HAL never provide a good named macro */
6688347601bSyl 	device_config->mac.rmac_pause_gen_en = ddi_prop_get_int(DDI_DEV_T_ANY,
6698347601bSyl 	    dev_info, DDI_PROP_DONTPASS, "rmac_pause_gen_en",
6708347601bSyl 	    XGE_HAL_DEFAULT_RMAC_PAUSE_GEN_DIS);
6718347601bSyl 	device_config->mac.rmac_pause_rcv_en = ddi_prop_get_int(DDI_DEV_T_ANY,
6728347601bSyl 	    dev_info, DDI_PROP_DONTPASS, "rmac_pause_rcv_en",
6738347601bSyl 	    XGE_HAL_DEFAULT_RMAC_PAUSE_RCV_DIS);
674a23fd118Syl 	device_config->mac.rmac_pause_time = ddi_prop_get_int(DDI_DEV_T_ANY,
675a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_pause_time",
676a23fd118Syl 	    XGE_HAL_DEFAULT_RMAC_HIGH_PTIME);
677a23fd118Syl 	device_config->mac.mc_pause_threshold_q0q3 =
678a23fd118Syl 	    ddi_prop_get_int(DDI_DEV_T_ANY,
6797eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q0q3",
6807eced415Sxw 	    XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q0Q3);
681a23fd118Syl 	device_config->mac.mc_pause_threshold_q4q7 =
682a23fd118Syl 	    ddi_prop_get_int(DDI_DEV_T_ANY,
6837eced415Sxw 	    dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q4q7",
6847eced415Sxw 	    XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q4Q7);
685a23fd118Syl 
686a23fd118Syl 	/*
687a23fd118Syl 	 * Initialize fifo properties
688a23fd118Syl 	 */
689a23fd118Syl 	device_config->fifo.max_frags = ddi_prop_get_int(DDI_DEV_T_ANY,
690a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "fifo_max_frags",
691a23fd118Syl 	    XGE_HAL_DEFAULT_FIFO_FRAGS);
692a23fd118Syl 	device_config->fifo.reserve_threshold = ddi_prop_get_int(DDI_DEV_T_ANY,
693a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "fifo_reserve_threshold",
694a23fd118Syl 	    XGE_HAL_DEFAULT_FIFO_RESERVE_THRESHOLD);
695a23fd118Syl 	device_config->fifo.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY,
696a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "fifo_memblock_size",
697a23fd118Syl 	    XGE_HAL_DEFAULT_FIFO_MEMBLOCK_SIZE);
698a23fd118Syl #ifdef XGE_HAL_ALIGN_XMIT
6998347601bSyl 	device_config->fifo.alignment_size = ddi_prop_get_int(DDI_DEV_T_ANY,
7008347601bSyl 	    dev_info, DDI_PROP_DONTPASS, "fifo_copied_frag_size",
7018347601bSyl 	    XGE_HAL_DEFAULT_FIFO_ALIGNMENT_SIZE);
7028347601bSyl 	device_config->fifo.max_aligned_frags = ddi_prop_get_int(DDI_DEV_T_ANY,
7038347601bSyl 	    dev_info, DDI_PROP_DONTPASS, "fifo_copied_max_frags",
7048347601bSyl 	    XGE_HAL_DEFAULT_FIFO_MAX_ALIGNED_FRAGS);
705a23fd118Syl #endif
7068347601bSyl 
7078347601bSyl 	/*
7087eced415Sxw 	 * Go through all possibly configured fifos. Each fifo could be
7097eced415Sxw 	 * configured individually. To enable/disable specific fifo, just
7107eced415Sxw 	 * set fifo->configured = [0|1].
7117eced415Sxw 	 *
7127eced415Sxw 	 * By default *all* fifos enabled.
713a23fd118Syl 	 */
7147eced415Sxw 	for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++) {
7157eced415Sxw 		xge_fifo_config(dev_info, device_config, i);
7167eced415Sxw 		if (device_config->fifo.queue[i].configured)
7177eced415Sxw 			fifos_configured++;
7187eced415Sxw 	}
719a23fd118Syl 
720a23fd118Syl 	/*
721a23fd118Syl 	 * Initialize errors dumping
722a23fd118Syl 	 */
723a23fd118Syl 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
724a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "dump_on_serr",
725a23fd118Syl 	    0);
726a23fd118Syl 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
727a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "dump_on_eccerr",
728a23fd118Syl 	    0);
729a23fd118Syl 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
730a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "dump_on_parityerr",
731a23fd118Syl 	    0);
732a23fd118Syl 
7338347601bSyl 	/*
7348347601bSyl 	 * LRO tunables
7358347601bSyl 	 */
7368347601bSyl 	device_config->lro_sg_size = ddi_prop_get_int(DDI_DEV_T_ANY,
7378347601bSyl 	    dev_info, DDI_PROP_DONTPASS, "lro_sg_size",
7388347601bSyl 	    XGE_HAL_DEFAULT_LRO_SG_SIZE);
7398347601bSyl 	device_config->lro_frm_len = ddi_prop_get_int(DDI_DEV_T_ANY,
7408347601bSyl 	    dev_info, DDI_PROP_DONTPASS, "lro_frm_len",
7418347601bSyl 	    XGE_HAL_DEFAULT_LRO_FRM_LEN);
7428347601bSyl 
743a23fd118Syl 	/*
744*da14cebeSEric Cheng 	 * Initialize other link layer configuration first
745a23fd118Syl 	 */
746*da14cebeSEric Cheng 	xgell_config->rx_buffer_total = ddi_prop_get_int(DDI_DEV_T_ANY,
747a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "rx_buffer_total",
748*da14cebeSEric Cheng 	    device_config->ring.queue[XGELL_RX_RING_MAIN].initial *
7497eced415Sxw 	    XGELL_RX_BUFFER_TOTAL);
750*da14cebeSEric Cheng 	xgell_config->rx_buffer_total += XGELL_RX_BUFFER_RECYCLE_CACHE;
751*da14cebeSEric Cheng 	xgell_config->rx_buffer_post_hiwat = ddi_prop_get_int(DDI_DEV_T_ANY,
752a23fd118Syl 	    dev_info, DDI_PROP_DONTPASS, "rx_buffer_post_hiwat",
753*da14cebeSEric Cheng 	    device_config->ring.queue[XGELL_RX_RING_MAIN].initial *
7547eced415Sxw 	    XGELL_RX_BUFFER_POST_HIWAT);
755*da14cebeSEric Cheng 	xgell_config->rx_buffer_post_hiwat += XGELL_RX_BUFFER_RECYCLE_CACHE;
756a23fd118Syl }
757a23fd118Syl 
7587eced415Sxw /*
7597eced415Sxw  * xge_alloc_intrs:
7607eced415Sxw  *
7617eced415Sxw  * Allocate FIXED or MSIX interrupts.
7627eced415Sxw  */
7637eced415Sxw static int
xge_alloc_intrs(xgelldev_t * lldev)7647eced415Sxw xge_alloc_intrs(xgelldev_t *lldev)
7657eced415Sxw {
7667eced415Sxw 	dev_info_t *dip = lldev->dev_info;
7677eced415Sxw 	int avail, actual, count = 0;
7687eced415Sxw 	int i, intr_behavior, ret;
7697eced415Sxw 
7707eced415Sxw 	if (lldev->intr_type == DDI_INTR_TYPE_MSIX) {
7717eced415Sxw 		intr_behavior = DDI_INTR_ALLOC_STRICT;
7727eced415Sxw 		(void) ddi_prop_create(DDI_DEV_T_NONE, dip,
7737eced415Sxw 		    DDI_PROP_CANSLEEP, "#msix-request", NULL, 0);
7747eced415Sxw 	} else {
7757eced415Sxw 		intr_behavior = DDI_INTR_ALLOC_NORMAL;
7767eced415Sxw 	}
7777eced415Sxw 
7787eced415Sxw 	/* Get number of interrupts */
7797eced415Sxw 	ret = ddi_intr_get_nintrs(dip, lldev->intr_type, &count);
7807eced415Sxw 	if ((ret != DDI_SUCCESS) || (count == 0)) {
7817eced415Sxw 		xge_debug_osdep(XGE_ERR, "ddi_intr_get_nintrs() failed, "
7827eced415Sxw 		    "ret: %d, count: %d", ret, count);
7837eced415Sxw 
7847eced415Sxw 		goto _err_exit0;
7857eced415Sxw 	}
7867eced415Sxw 
7877eced415Sxw 	/* Get number of available interrupts */
7887eced415Sxw 	ret = ddi_intr_get_navail(dip, lldev->intr_type, &avail);
7897eced415Sxw 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
7907eced415Sxw 		xge_debug_osdep(XGE_ERR, "ddi_intr_get_navail() failure, "
7917eced415Sxw 		    "ret: %d, avail: %d", ret, avail);
7927eced415Sxw 
7937eced415Sxw 		goto _err_exit0;
7947eced415Sxw 	}
7957eced415Sxw 
7967eced415Sxw 	if (avail < lldev->intr_cnt) {
7977eced415Sxw 		xge_debug_osdep(XGE_ERR, "%d interrupts wanted while only "
7987eced415Sxw 		    "%d available", lldev->intr_cnt, avail);
7997eced415Sxw 		goto _err_exit0;
8007eced415Sxw 	}
8017eced415Sxw 
8027eced415Sxw 	/* Allocate an array of interrupt handles */
8037eced415Sxw 	lldev->intr_table_size = lldev->intr_cnt * sizeof (ddi_intr_handle_t);
8047eced415Sxw 	lldev->intr_table = kmem_alloc(lldev->intr_table_size, KM_SLEEP);
8057eced415Sxw 
8067eced415Sxw 	/* Call ddi_intr_alloc() */
8077eced415Sxw 	ret = ddi_intr_alloc(dip, lldev->intr_table, lldev->intr_type, 0,
8087eced415Sxw 	    lldev->intr_cnt, &actual, intr_behavior);
8097eced415Sxw 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
8107eced415Sxw 		xge_debug_osdep(XGE_ERR, "ddi_intr_alloc() failed %d", ret);
8117eced415Sxw 		goto _err_exit1;
8127eced415Sxw 	}
8137eced415Sxw 
8147eced415Sxw 	xge_debug_osdep(XGE_TRACE, "%s: Requested: %d, Granted: %d",
8157eced415Sxw 	    lldev->intr_type == DDI_INTR_TYPE_MSIX ? "MSI-X" :
8167eced415Sxw 	    "IRQA", count, actual);
8177eced415Sxw 
8187eced415Sxw 	if (lldev->intr_cnt != actual) {
8197eced415Sxw 		xge_debug_osdep(XGE_ERR, "Not enough resources granted");
8207eced415Sxw 		goto _err_exit2;
8217eced415Sxw 	}
8227eced415Sxw 
8237eced415Sxw 	/*
8247eced415Sxw 	 * Get priority for first msi, assume remaining are all the same
8257eced415Sxw 	 */
8267eced415Sxw 	if ((ret = ddi_intr_get_pri(lldev->intr_table[0], &lldev->intr_pri)) !=
8277eced415Sxw 	    DDI_SUCCESS) {
8287eced415Sxw 		xge_debug_osdep(XGE_ERR, "ddi_intr_get_pri() failed %d", ret);
8297eced415Sxw 		goto _err_exit2;
8307eced415Sxw 	}
8317eced415Sxw 
8327eced415Sxw 	return (DDI_SUCCESS);
8337eced415Sxw 
8347eced415Sxw _err_exit2:
8357eced415Sxw 	/* Free already allocated intr */
8367eced415Sxw 	for (i = 0; i < actual; i++) {
8377eced415Sxw 		(void) ddi_intr_free(lldev->intr_table[i]);
8387eced415Sxw 	}
8397eced415Sxw _err_exit1:
8407eced415Sxw 	kmem_free(lldev->intr_table, lldev->intr_table_size);
841*da14cebeSEric Cheng 	lldev->intr_table = NULL;
8427eced415Sxw _err_exit0:
8437eced415Sxw 	if (lldev->intr_type == DDI_INTR_TYPE_MSIX)
8447eced415Sxw 		(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "#msix-request");
8457eced415Sxw 	return (DDI_FAILURE);
8467eced415Sxw }
8477eced415Sxw 
8487eced415Sxw /*
8497eced415Sxw  * xge_free_intrs:
8507eced415Sxw  *
8517eced415Sxw  * Free previously allocated interrupts.
8527eced415Sxw  */
8537eced415Sxw static void
xge_free_intrs(xgelldev_t * lldev)8547eced415Sxw xge_free_intrs(xgelldev_t *lldev)
8557eced415Sxw {
8567eced415Sxw 	int i;
8577eced415Sxw 	dev_info_t *dip = lldev->dev_info;
8587eced415Sxw 
8597eced415Sxw 	/* Free already allocated intr */
8607eced415Sxw 	for (i = 0; i < lldev->intr_cnt; i++) {
8617eced415Sxw 		(void) ddi_intr_free(lldev->intr_table[i]);
8627eced415Sxw 	}
8637eced415Sxw 	kmem_free(lldev->intr_table, lldev->intr_table_size);
864*da14cebeSEric Cheng 	lldev->intr_table = NULL;
8657eced415Sxw 
8667eced415Sxw 	if (lldev->intr_type == DDI_INTR_TYPE_MSIX)
8677eced415Sxw 		(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "#msix-request");
8687eced415Sxw }
8697eced415Sxw 
8707eced415Sxw /*
8717eced415Sxw  * xge_add_intrs:
8727eced415Sxw  *
8737eced415Sxw  * Register FIXED or MSI interrupts.
8747eced415Sxw  */
8757eced415Sxw int
xge_add_intrs(xgelldev_t * lldev)8767eced415Sxw xge_add_intrs(xgelldev_t *lldev)
8777eced415Sxw {
8787eced415Sxw 	int i, ret;
8797eced415Sxw 	xge_hal_device_t *hldev = lldev->devh;
8807eced415Sxw 	xge_hal_device_config_t *hal_conf = &hldev->config;
8817eced415Sxw 	xge_hal_ring_config_t *ring_conf = &hal_conf->ring;
8827eced415Sxw 	xge_hal_fifo_config_t *fifo_conf = &hal_conf->fifo;
8837eced415Sxw 	xge_list_t *item;
8847eced415Sxw 	int msix_idx = 1; /* 0 by default is reserved for Alarms. */
885*da14cebeSEric Cheng 	xge_hal_channel_t *assigned[XGELL_RX_RING_NUM_MAX +
886*da14cebeSEric Cheng 	    XGELL_TX_RING_NUM_MAX + 1];
8877eced415Sxw 
888*da14cebeSEric Cheng 	xge_assert(lldev->intr_table != NULL);
8897eced415Sxw 	switch (lldev->intr_type) {
8907eced415Sxw 	case DDI_INTR_TYPE_FIXED:
8917eced415Sxw 		ret = ddi_intr_add_handler(lldev->intr_table[0],
8927eced415Sxw 		    (ddi_intr_handler_t *)xge_isr,
8937eced415Sxw 		    (caddr_t)hldev, 0);
8947eced415Sxw 		if (ret != DDI_SUCCESS) {
8957eced415Sxw 			xge_debug_osdep(XGE_ERR, "ddi_intr_add_handler(FIXED)"
8967eced415Sxw 			    "failed %d", ret);
8977eced415Sxw 			return (DDI_FAILURE);
8987eced415Sxw 		}
8997eced415Sxw 		break;
9007eced415Sxw 
9017eced415Sxw 	case DDI_INTR_TYPE_MSIX:
9027eced415Sxw 		i = 0;
9037eced415Sxw 		xge_list_for_each(item, &hldev->free_channels) {
9047eced415Sxw 			xge_hal_channel_t *channel = xge_container_of(item,
9057eced415Sxw 			    xge_hal_channel_t, item);
9067eced415Sxw 			i = channel->post_qid;
9077eced415Sxw 			if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
9087eced415Sxw 				if (fifo_conf->queue[i].configured) {
9097eced415Sxw 					assigned[msix_idx] = channel;
9107eced415Sxw 					msix_idx++;
9117eced415Sxw 				}
9127eced415Sxw 			} else {
9137eced415Sxw 				if (ring_conf->queue[i].configured) {
9147eced415Sxw 					assigned[msix_idx] = channel;
9157eced415Sxw 					msix_idx++;
9167eced415Sxw 				}
9177eced415Sxw 			}
9187eced415Sxw 		}
9197eced415Sxw 		for (i = 0; i < lldev->intr_cnt; i++) {
9207eced415Sxw 			uint_t (*intr)(caddr_t, caddr_t);
9217eced415Sxw 			caddr_t intr_arg;
9227eced415Sxw 
9237eced415Sxw 			/* partition MSIX vectors */
9247eced415Sxw 			if (i == 0) {
9257eced415Sxw 				intr = xge_isr;
9267eced415Sxw 				intr_arg = (caddr_t)hldev;
9277eced415Sxw 				xge_debug_osdep(XGE_TRACE,
9287eced415Sxw 				    "Channel-A: using MSI-X #0");
9297eced415Sxw 			} else if (assigned[i] && assigned[i]->type ==
9307eced415Sxw 			    XGE_HAL_CHANNEL_TYPE_FIFO) {
9317eced415Sxw 				intr = xge_fifo_msix_isr;
9327eced415Sxw 				intr_arg = (caddr_t)assigned[i];
9337eced415Sxw 				xge_debug_osdep(XGE_TRACE, "Channel-Tx%d"
9347eced415Sxw 				    "using MSI-X #%d",
9357eced415Sxw 				    assigned[i]->post_qid, i);
9367eced415Sxw 			} else if (assigned[i] && assigned[i]->type ==
9377eced415Sxw 			    XGE_HAL_CHANNEL_TYPE_RING) {
9387eced415Sxw 				intr = xge_ring_msix_isr;
9397eced415Sxw 				intr_arg = (caddr_t)assigned[i];
9407eced415Sxw 				xge_debug_osdep(XGE_TRACE, "Channel-Rx%d: "
9417eced415Sxw 				    "using MSI-X #%d",
9427eced415Sxw 				    assigned[i]->post_qid, i);
9437eced415Sxw 			}
9447eced415Sxw 			ret = ddi_intr_add_handler(lldev->intr_table[i], intr,
9457eced415Sxw 			    intr_arg, (caddr_t)(uintptr_t)i);
9467eced415Sxw 			if (ret != DDI_SUCCESS) {
9477eced415Sxw 				int j;
9487eced415Sxw 				xge_debug_osdep(XGE_ERR,
9497eced415Sxw 				    "ddi_intr_add_handler()"
9507eced415Sxw 				    " failed %d", ret);
9517eced415Sxw 				for (j = 0; j < i; j++) {
9527eced415Sxw 					(void) ddi_intr_remove_handler(
9537eced415Sxw 					    lldev->intr_table[j]);
9547eced415Sxw 				}
9557eced415Sxw 				return (DDI_FAILURE);
9567eced415Sxw 			}
9577eced415Sxw 		}
9587eced415Sxw 
9597eced415Sxw 		for (i = 1; i < msix_idx; i++)
9607eced415Sxw 			(void) xge_hal_channel_msix_set(assigned[i], i);
9617eced415Sxw 		break;
9627eced415Sxw 
9637eced415Sxw 	default:
9647eced415Sxw 		break;
9657eced415Sxw 	}
9667eced415Sxw 	ret = ddi_intr_get_cap(lldev->intr_table[0], &lldev->intr_cap);
9677eced415Sxw 	if (ret != DDI_SUCCESS) {
9687eced415Sxw 		xge_debug_osdep(XGE_ERR, "ddi_intr_get_cap() failed %d", ret);
9697eced415Sxw 		for (i = 0; i < lldev->intr_cnt; i++) {
9707eced415Sxw 			(void) ddi_intr_remove_handler(lldev->intr_table[i]);
9717eced415Sxw 		}
9727eced415Sxw 		return (DDI_FAILURE);
9737eced415Sxw 	}
9747eced415Sxw 	return (DDI_SUCCESS);
9757eced415Sxw }
9767eced415Sxw 
9777eced415Sxw 
9787eced415Sxw /*
9797eced415Sxw  * xge_enable_intrs:
9807eced415Sxw  *
9817eced415Sxw  * Enable FIXED or MSI interrupts
9827eced415Sxw  */
9837eced415Sxw int
xge_enable_intrs(xgelldev_t * lldev)9847eced415Sxw xge_enable_intrs(xgelldev_t *lldev)
9857eced415Sxw {
9867eced415Sxw 	int ret, i;
9877eced415Sxw 
9887eced415Sxw 	if (lldev->intr_cap & DDI_INTR_FLAG_BLOCK) {
9897eced415Sxw 		/* Call ddi_intr_block_enable() for MSI(X) interrupts */
9907eced415Sxw 		if ((ret = ddi_intr_block_enable(lldev->intr_table,
9917eced415Sxw 		    lldev->intr_cnt)) != DDI_SUCCESS) {
9927eced415Sxw 			xge_debug_osdep(XGE_ERR, "ddi_intr_enable() failed, "
9937eced415Sxw 			    "ret 0x%x", ret);
9947eced415Sxw 			return (DDI_FAILURE);
9957eced415Sxw 		}
9967eced415Sxw 	} else {
9977eced415Sxw 		/* Call ddi_intr_enable for MSI(X) or FIXED interrupts */
9987eced415Sxw 		for (i = 0; i < lldev->intr_cnt; i++) {
9997eced415Sxw 			if ((ret = ddi_intr_enable(lldev->intr_table[i]))
10007eced415Sxw 			    != DDI_SUCCESS) {
10017eced415Sxw 				int j;
10027eced415Sxw 
10037eced415Sxw 				xge_debug_osdep(XGE_ERR, "ddi_intr_enable() "
10047eced415Sxw 				    "failed, ret 0x%x", ret);
10057eced415Sxw 
10067eced415Sxw 				/* unwind */
10077eced415Sxw 				for (j = 0; j < i; j++) {
10087eced415Sxw 					(void) ddi_intr_disable(
10097eced415Sxw 					    lldev->intr_table[j]);
10107eced415Sxw 				}
10117eced415Sxw 
10127eced415Sxw 				return (DDI_FAILURE);
10137eced415Sxw 			}
10147eced415Sxw 		}
10157eced415Sxw 	}
10167eced415Sxw 
10177eced415Sxw 	return (DDI_SUCCESS);
10187eced415Sxw }
10197eced415Sxw 
10207eced415Sxw /*
10217eced415Sxw  * xge_disable_intrs:
10227eced415Sxw  *
10237eced415Sxw  * Disable FIXED or MSI interrupts
10247eced415Sxw  */
10257eced415Sxw void
xge_disable_intrs(xgelldev_t * lldev)10267eced415Sxw xge_disable_intrs(xgelldev_t *lldev)
10277eced415Sxw {
10287eced415Sxw 	int i;
10297eced415Sxw 
10307eced415Sxw 	if (lldev->intr_cap & DDI_INTR_FLAG_BLOCK) {
10317eced415Sxw 		/* Call ddi_intr_block_disable() */
10327eced415Sxw 		(void) ddi_intr_block_disable(lldev->intr_table,
10337eced415Sxw 		    lldev->intr_cnt);
10347eced415Sxw 	} else {
10357eced415Sxw 		for (i = 0; i < lldev->intr_cnt; i++) {
10367eced415Sxw 			(void) ddi_intr_disable(lldev->intr_table[i]);
10377eced415Sxw 		}
10387eced415Sxw 	}
10397eced415Sxw }
10407eced415Sxw 
10417eced415Sxw /*
10427eced415Sxw  * xge_rem_intrs:
10437eced415Sxw  *
10447eced415Sxw  * Unregister FIXED or MSI interrupts
10457eced415Sxw  */
10467eced415Sxw void
xge_rem_intrs(xgelldev_t * lldev)10477eced415Sxw xge_rem_intrs(xgelldev_t *lldev)
10487eced415Sxw {
10497eced415Sxw 	int i;
10507eced415Sxw 
1051*da14cebeSEric Cheng 	xge_assert(lldev->intr_table != NULL);
1052*da14cebeSEric Cheng 
10537eced415Sxw 	/* Call ddi_intr_remove_handler() */
10547eced415Sxw 	for (i = 0; i < lldev->intr_cnt; i++) {
10557eced415Sxw 		(void) ddi_intr_remove_handler(lldev->intr_table[i]);
10567eced415Sxw 	}
10577eced415Sxw }
10587eced415Sxw 
1059a23fd118Syl /*
1060a23fd118Syl  * xge_attach
1061a23fd118Syl  * @dev_info: pointer to dev_info_t structure
1062a23fd118Syl  * @cmd: attach command to process
1063a23fd118Syl  *
1064a23fd118Syl  * This is a solaris standard attach function.  This
1065a23fd118Syl  * function initializes the Xframe  identified
1066a23fd118Syl  * by the dev_info_t structure and setup the driver
1067a23fd118Syl  * data structures corresponding to the Xframe Card.
1068a23fd118Syl  * This function also registers the XFRAME device
1069a23fd118Syl  * instance with the MAC Layer.
1070a23fd118Syl  * If this function returns success then the OS
1071a23fd118Syl  * will attach the HBA controller to this
1072a23fd118Syl  * driver.
1073a23fd118Syl  */
1074a23fd118Syl static int
xge_attach(dev_info_t * dev_info,ddi_attach_cmd_t cmd)1075a23fd118Syl xge_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd)
1076a23fd118Syl {
1077a23fd118Syl 	xgelldev_t *ll;
1078*da14cebeSEric Cheng 	xgell_config_t *xgell_config;
10797eced415Sxw 	xge_hal_device_config_t *device_config;
1080a23fd118Syl 	xge_hal_device_t *hldev;
1081a23fd118Syl 	xge_hal_device_attr_t attr;
1082a23fd118Syl 	xge_hal_status_e status;
10837eced415Sxw 	int ret, intr_types, i;
1084a23fd118Syl 
1085a23fd118Syl 	xge_debug_osdep(XGE_TRACE, "XGE_ATTACH cmd %d", cmd);
1086a23fd118Syl 
1087a23fd118Syl 	switch (cmd) {
1088a23fd118Syl 	case DDI_ATTACH:
1089a23fd118Syl 		break;
1090a23fd118Syl 
1091a23fd118Syl 	case DDI_RESUME:
1092a23fd118Syl 	case DDI_PM_RESUME:
1093a23fd118Syl 		xge_debug_osdep(XGE_ERR, "%s", "resume unsupported yet");
1094a23fd118Syl 		ret = DDI_FAILURE;
1095a23fd118Syl 		goto _exit0;
1096a23fd118Syl 
1097a23fd118Syl 	default:
1098a23fd118Syl 		xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd);
1099a23fd118Syl 		ret = DDI_FAILURE;
1100a23fd118Syl 		goto _exit0;
1101a23fd118Syl 	}
1102a23fd118Syl 
1103*da14cebeSEric Cheng 	xgell_config = kmem_zalloc(sizeof (xgell_config_t), KM_SLEEP);
11047eced415Sxw 	device_config = kmem_zalloc(sizeof (xge_hal_device_config_t), KM_SLEEP);
1105a23fd118Syl 
1106*da14cebeSEric Cheng 	/*
1107*da14cebeSEric Cheng 	 * Initialize all configurations
1108*da14cebeSEric Cheng 	 */
1109*da14cebeSEric Cheng 	xge_configuration_init(dev_info, device_config, xgell_config);
11107eced415Sxw 
11117eced415Sxw 	/* Determine which types of interrupts supported */
11127eced415Sxw 	ret = ddi_intr_get_supported_types(dev_info, &intr_types);
11137eced415Sxw 	if ((ret != DDI_SUCCESS) || (!(intr_types & DDI_INTR_TYPE_FIXED))) {
11147eced415Sxw 		xge_debug_osdep(XGE_ERR, "%s",
11157eced415Sxw 		    "fixed type interrupt is not supported");
11167eced415Sxw 		goto _exit0a;
11177eced415Sxw 	}
1118a23fd118Syl 
1119a23fd118Syl 	/* map BAR0 */
1120a23fd118Syl 	ret = ddi_regs_map_setup(dev_info, 1, (caddr_t *)&attr.bar0,
1121a23fd118Syl 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh0);
1122a23fd118Syl 	if (ret != DDI_SUCCESS) {
1123a23fd118Syl 		xge_debug_osdep(XGE_ERR, "unable to map bar0: [%d]", ret);
11247eced415Sxw 		goto _exit0a;
1125a23fd118Syl 	}
1126a23fd118Syl 
1127a23fd118Syl 	/* map BAR1 */
1128a23fd118Syl 	ret = ddi_regs_map_setup(dev_info, 2, (caddr_t *)&attr.bar1,
1129a23fd118Syl 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh1);
1130a23fd118Syl 	if (ret != DDI_SUCCESS) {
1131a23fd118Syl 		xge_debug_osdep(XGE_ERR, "unable to map bar1: [%d]", ret);
1132a23fd118Syl 		goto _exit1;
1133a23fd118Syl 	}
1134a23fd118Syl 
11357eced415Sxw 	/* map BAR2 MSI(X) */
11367eced415Sxw 	ret = ddi_regs_map_setup(dev_info, 2, (caddr_t *)&attr.bar2,
11377eced415Sxw 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh2);
1138a23fd118Syl 	if (ret != DDI_SUCCESS) {
11397eced415Sxw 		xge_debug_osdep(XGE_ERR, "unable to map bar2: [%d]", ret);
11407eced415Sxw 		goto _exit1a;
1141a23fd118Syl 	}
1142a23fd118Syl 
11437eced415Sxw 	/* preallocate memory for new HAL device and private LL part */
11447eced415Sxw 	hldev = kmem_zalloc(sizeof (xge_hal_device_t), KM_SLEEP);
11457eced415Sxw 
1146a23fd118Syl 	/* Get the PCI Configuartion space handle */
1147a23fd118Syl 	ret = pci_config_setup(dev_info, &attr.cfgh);
1148a23fd118Syl 	if (ret != DDI_SUCCESS) {
1149a23fd118Syl 		xge_debug_osdep(XGE_ERR, "%s", "can not setup config space");
1150a23fd118Syl 		goto _exit2a;
1151a23fd118Syl 	}
1152a23fd118Syl 
1153a23fd118Syl 	attr.pdev = dev_info;
1154a23fd118Syl 
1155a23fd118Syl 	ret = xgell_device_alloc(hldev, dev_info, &ll);
1156a23fd118Syl 	if (ret != DDI_SUCCESS) {
1157a23fd118Syl 		xge_debug_osdep(XGE_ERR,
1158a23fd118Syl 		    "%s",
1159a23fd118Syl 		    "unable to allocate new LL device");
1160a23fd118Syl 		goto _exit3;
1161a23fd118Syl 	}
1162a23fd118Syl 
1163*da14cebeSEric Cheng 	/*
1164*da14cebeSEric Cheng 	 * Init multiple rings configuration
1165*da14cebeSEric Cheng 	 */
1166*da14cebeSEric Cheng 	switch (xgell_config->grouping) {
1167*da14cebeSEric Cheng 	case XGELL_CONF_GROUP_POLICY_VIRT:
1168*da14cebeSEric Cheng 		ll->init_rx_rings = XGELL_RX_RING_NUM_MAX; /* 8 */
1169*da14cebeSEric Cheng 		ll->init_tx_rings = XGELL_TX_RING_NUM_MAX; /* 8 */
1170*da14cebeSEric Cheng 		ll->init_rx_groups = ll->init_rx_rings;
1171*da14cebeSEric Cheng 		break;
1172*da14cebeSEric Cheng 	case XGELL_CONF_GROUP_POLICY_PERF:
1173*da14cebeSEric Cheng 		ll->init_rx_rings = XGELL_RX_RING_NUM_MAX; /* 8 */
1174*da14cebeSEric Cheng 		ll->init_tx_rings = XGELL_TX_RING_NUM_MAX; /* 8 */
1175*da14cebeSEric Cheng 		ll->init_rx_groups = 1;
1176*da14cebeSEric Cheng 		break;
1177*da14cebeSEric Cheng 	case XGELL_CONF_GROUP_POLICY_BASIC:
1178*da14cebeSEric Cheng 		ll->init_rx_rings = XGELL_RX_RING_NUM_MIN; /* 1 */
1179*da14cebeSEric Cheng 		ll->init_tx_rings = XGELL_TX_RING_NUM_MIN; /* 1 */
1180*da14cebeSEric Cheng 		ll->init_rx_groups = ll->init_rx_rings;
1181*da14cebeSEric Cheng 		break;
1182*da14cebeSEric Cheng 	default:
1183*da14cebeSEric Cheng 		ASSERT(0);
1184*da14cebeSEric Cheng 		break;
1185*da14cebeSEric Cheng 	}
1186*da14cebeSEric Cheng 
1187*da14cebeSEric Cheng 	/*
1188*da14cebeSEric Cheng 	 * Init MSI-X configuration
1189*da14cebeSEric Cheng 	 */
1190*da14cebeSEric Cheng 	if (xgell_config->msix_enable && intr_types & DDI_INTR_TYPE_MSIX) {
11917eced415Sxw 		ll->intr_type = DDI_INTR_TYPE_MSIX;
11927eced415Sxw 		ll->intr_cnt = 1;
11937eced415Sxw 		for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++)
11947eced415Sxw 			if (device_config->fifo.queue[i].configured)
11957eced415Sxw 				ll->intr_cnt++;
11967eced415Sxw 		for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++)
11977eced415Sxw 			if (device_config->ring.queue[i].configured)
11987eced415Sxw 				ll->intr_cnt++;
11997eced415Sxw 	} else {
12007eced415Sxw 		ll->intr_type = DDI_INTR_TYPE_FIXED;
12017eced415Sxw 		ll->intr_cnt = 1;
12027eced415Sxw 	}
12037eced415Sxw 
1204*da14cebeSEric Cheng 	/*
1205*da14cebeSEric Cheng 	 * Allocate interrupt(s)
1206*da14cebeSEric Cheng 	 */
12077eced415Sxw 	while ((ret = xge_alloc_intrs(ll)) != DDI_SUCCESS) {
12087eced415Sxw 		if (ll->intr_type == DDI_INTR_TYPE_MSIX) {
1209*da14cebeSEric Cheng 			xgell_config->msix_enable = 0;
12107eced415Sxw 			ll->intr_type = DDI_INTR_TYPE_FIXED;
12117eced415Sxw 			ll->intr_cnt = 1;
12127eced415Sxw 			device_config->intr_mode = XGE_HAL_INTR_MODE_IRQLINE;
12137eced415Sxw 			xge_debug_osdep(XGE_TRACE,
12147eced415Sxw 			    "Unable to allocate MSI-X handlers"
12157eced415Sxw 			    " - defaulting to IRQA");
12167eced415Sxw 			continue;
12177eced415Sxw 		}
1218a23fd118Syl 		goto _exit3a;
1219a23fd118Syl 	}
1220a23fd118Syl 
12217eced415Sxw 	if (ll->intr_type == DDI_INTR_TYPE_MSIX) {
12227eced415Sxw 		device_config->intr_mode = XGE_HAL_INTR_MODE_MSIX;
12237eced415Sxw 		device_config->bimodal_interrupts = 0;
12247eced415Sxw 	} else {
12257eced415Sxw 		device_config->intr_mode = XGE_HAL_INTR_MODE_IRQLINE;
12267eced415Sxw 	}
12277eced415Sxw 
12287eced415Sxw 	attr.irqh = ll->intr_pri;
12297eced415Sxw 
1230a23fd118Syl 	/* initialize HW */
12317eced415Sxw 	status = xge_hal_device_initialize(hldev, &attr, device_config);
1232a23fd118Syl 	if (status != XGE_HAL_OK) {
1233a23fd118Syl 		switch (status) {
1234a23fd118Syl 		case XGE_HAL_ERR_DRIVER_NOT_INITIALIZED:
1235a23fd118Syl 			xge_debug_osdep(XGE_ERR, "%s",
1236a23fd118Syl 			    "driver is not initialized");
1237a23fd118Syl 			ret = DDI_FAILURE;
1238a23fd118Syl 			goto _exit3b;
1239a23fd118Syl 		case XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT:
1240a23fd118Syl 			xge_debug_osdep(XGE_ERR, "%s",
1241a23fd118Syl 			    "device is not quiescent");
1242a23fd118Syl 			ret = DDI_EBUSY;
1243a23fd118Syl 			goto _exit3b;
1244a23fd118Syl 		case XGE_HAL_ERR_OUT_OF_MEMORY:
1245a23fd118Syl 			xge_debug_osdep(XGE_ERR, "%s",
1246a23fd118Syl 			    "unable to allocate memory");
1247a23fd118Syl 			ret = DDI_ENOMEM;
1248a23fd118Syl 			goto _exit3b;
1249a23fd118Syl 		default:
1250a23fd118Syl 			xge_debug_osdep(XGE_ERR,
1251a23fd118Syl 			    "can't initialize the device: %d", status);
1252a23fd118Syl 			ret = DDI_FAILURE;
1253a23fd118Syl 			goto _exit3b;
1254a23fd118Syl 		}
1255a23fd118Syl 	}
1256a23fd118Syl 
12577eced415Sxw 	/* register interrupt handler for handling xge device interrupts */
12587eced415Sxw 	ret = xge_add_intrs(ll);
12597eced415Sxw 	if (ret != DDI_SUCCESS)
12607eced415Sxw 		goto _exit4;
12617eced415Sxw 
1262a23fd118Syl 	/* allocate and register Link Layer */
1263*da14cebeSEric Cheng 	ret = xgell_device_register(ll, xgell_config);
1264a23fd118Syl 	if (ret != DDI_SUCCESS) {
12657eced415Sxw 		goto _exit5;
1266a23fd118Syl 	}
1267a23fd118Syl 
1268a23fd118Syl 	/* store ll as a HAL private part */
1269a23fd118Syl 	xge_hal_device_private_set(hldev, ll);
1270a23fd118Syl 
12717eced415Sxw 	kmem_free(device_config, sizeof (xge_hal_device_config_t));
1272*da14cebeSEric Cheng 	kmem_free(xgell_config, sizeof (xgell_config_t));
12737eced415Sxw 
1274a23fd118Syl 	return (DDI_SUCCESS);
1275a23fd118Syl 
12767eced415Sxw _exit5:
12777eced415Sxw 	xge_rem_intrs(ll);
1278a23fd118Syl _exit4:
1279a23fd118Syl 	xge_hal_device_terminate(hldev);
1280a23fd118Syl _exit3b:
12817eced415Sxw 	xge_free_intrs(ll);
1282a23fd118Syl _exit3a:
1283a23fd118Syl 	xgell_device_free(ll);
1284a23fd118Syl _exit3:
1285a23fd118Syl 	pci_config_teardown(&attr.cfgh);
1286a23fd118Syl _exit2a:
1287a23fd118Syl 	kmem_free(hldev, sizeof (xge_hal_device_t));
1288a23fd118Syl _exit2:
12897eced415Sxw 	ddi_regs_map_free(&attr.regh2);
12907eced415Sxw _exit1a:
1291a23fd118Syl 	ddi_regs_map_free(&attr.regh1);
1292a23fd118Syl _exit1:
1293a23fd118Syl 	ddi_regs_map_free(&attr.regh0);
12947eced415Sxw _exit0a:
12957eced415Sxw 	kmem_free(device_config, sizeof (xge_hal_device_config_t));
1296*da14cebeSEric Cheng 	kmem_free(xgell_config, sizeof (xgell_config_t));
1297a23fd118Syl _exit0:
1298a23fd118Syl 	return (ret);
1299a23fd118Syl }
1300a23fd118Syl 
130119397407SSherry Moore /*
130219397407SSherry Moore  * quiesce(9E) entry point.
130319397407SSherry Moore  *
130419397407SSherry Moore  * This function is called when the system is single-threaded at high
130519397407SSherry Moore  * PIL with preemption disabled. Therefore, this function must not be
130619397407SSherry Moore  * blocked.
130719397407SSherry Moore  *
130819397407SSherry Moore  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
130919397407SSherry Moore  * DDI_FAILURE indicates an error condition and should almost never happen.
131019397407SSherry Moore  */
131119397407SSherry Moore static int
xge_quiesce(dev_info_t * dev_info)131219397407SSherry Moore xge_quiesce(dev_info_t *dev_info)
131319397407SSherry Moore {
131419397407SSherry Moore 	xge_hal_device_t *hldev =
131519397407SSherry Moore 	    (xge_hal_device_t *)ddi_get_driver_private(dev_info);
131619397407SSherry Moore 
131719397407SSherry Moore 	xgelldev_t *lldev = xge_hal_device_private(hldev);
131819397407SSherry Moore 
131919397407SSherry Moore 	xge_hal_device_quiesce(hldev, lldev->devh);
132019397407SSherry Moore 
132119397407SSherry Moore 	return (DDI_SUCCESS);
132219397407SSherry Moore }
132319397407SSherry Moore 
1324a23fd118Syl /*
1325a23fd118Syl  * xge_detach
1326a23fd118Syl  * @dev_info: pointer to dev_info_t structure
1327a23fd118Syl  * @cmd: attach command to process
1328a23fd118Syl  *
1329a23fd118Syl  * This function is called by OS when the system is about
1330a23fd118Syl  * to shutdown or when the super user tries to unload
1331a23fd118Syl  * the driver. This function frees all the memory allocated
1332*da14cebeSEric Cheng  * during xge_attach() and also unregisters the Xframe
1333a23fd118Syl  * device instance from the GLD framework.
1334a23fd118Syl  */
1335a23fd118Syl static int
xge_detach(dev_info_t * dev_info,ddi_detach_cmd_t cmd)1336a23fd118Syl xge_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd)
1337a23fd118Syl {
1338a23fd118Syl 	xge_hal_device_t *hldev;
1339a23fd118Syl 	xge_hal_device_attr_t *attr;
1340a23fd118Syl 	xgelldev_t *lldev;
1341a23fd118Syl 
1342a23fd118Syl 	xge_debug_osdep(XGE_TRACE, "XGE_DETACH cmd %d", cmd);
1343a23fd118Syl 
1344a23fd118Syl 	hldev = (xge_hal_device_t *)ddi_get_driver_private(dev_info);
1345a23fd118Syl 	attr = xge_hal_device_attr(hldev);
1346a23fd118Syl 	lldev = xge_hal_device_private(hldev);
1347a23fd118Syl 
1348a23fd118Syl 	switch (cmd) {
1349a23fd118Syl 	case DDI_DETACH:
1350a23fd118Syl 		break;
1351a23fd118Syl 
1352a23fd118Syl 	case DDI_PM_SUSPEND:
1353a23fd118Syl 		xge_debug_osdep(XGE_ERR, "%s", "suspend unsupported yet");
1354a23fd118Syl 		return (DDI_FAILURE);
1355a23fd118Syl 
1356a23fd118Syl 	default:
1357a23fd118Syl 		xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd);
1358a23fd118Syl 		return (DDI_FAILURE);
1359a23fd118Syl 	}
1360a23fd118Syl 
1361a23fd118Syl 	if (lldev->is_initialized) {
1362a23fd118Syl 		xge_debug_osdep(XGE_ERR, "%s",
1363a23fd118Syl 		    "can not detach: device is not unplumbed");
1364a23fd118Syl 		return (DDI_FAILURE);
1365a23fd118Syl 	}
1366a23fd118Syl 
1367a23fd118Syl 	xge_hal_device_terminating(hldev);
1368a23fd118Syl 	if (xgell_device_unregister(lldev) != DDI_SUCCESS) {
1369a23fd118Syl 		return (DDI_FAILURE);
1370a23fd118Syl 	}
1371a23fd118Syl 	xge_hal_device_terminate(hldev);
1372a23fd118Syl 
13737eced415Sxw 	xge_rem_intrs(lldev);
13747eced415Sxw 	xge_free_intrs(lldev);
1375a23fd118Syl 	xgell_device_free(lldev);
1376a23fd118Syl 	pci_config_teardown(&attr->cfgh);
13777eced415Sxw 	ddi_regs_map_free(&attr->regh2);
1378a23fd118Syl 	ddi_regs_map_free(&attr->regh1);
1379a23fd118Syl 	ddi_regs_map_free(&attr->regh0);
1380a23fd118Syl 	kmem_free(hldev, sizeof (xge_hal_device_t));
1381a23fd118Syl 
1382a23fd118Syl 	return (DDI_SUCCESS);
1383a23fd118Syl }
1384