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