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