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