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 2010 Emulex. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Source file containing the implementation of the driver entry points 29 * and related helper functions 30 */ 31 32 #include <oce_impl.h> 33 #include <oce_stat.h> 34 #include <oce_ioctl.h> 35 36 #define ATTACH_DEV_INIT 0x1 37 #define ATTACH_FM_INIT 0x2 38 #define ATTACH_LOCK_INIT 0x4 39 #define ATTACH_PCI_INIT 0x8 40 #define ATTACH_HW_INIT 0x10 41 #define ATTACH_SETUP_TXRX 0x20 42 #define ATTACH_SETUP_ADAP 0x40 43 #define ATTACH_STAT_INIT 0x100 44 #define ATTACH_MAC_REG 0x200 45 46 /* ---[ globals and externs ]-------------------------------------------- */ 47 const char oce_ident_string[] = OCE_IDENT_STRING; 48 const char oce_mod_name[] = OCE_MOD_NAME; 49 50 char oce_version[] = OCE_REVISION; 51 52 /* driver properties */ 53 static const char mtu_prop_name[] = "oce_default_mtu"; 54 static const char tx_ring_size_name[] = "oce_tx_ring_size"; 55 static const char tx_bcopy_limit_name[] = "oce_tx_bcopy_limit"; 56 static const char rx_bcopy_limit_name[] = "oce_rx_bcopy_limit"; 57 static const char fm_cap_name[] = "oce_fm_capability"; 58 static const char log_level_name[] = "oce_log_level"; 59 static const char lso_capable_name[] = "oce_lso_capable"; 60 61 /* --[ static function prototypes here ]------------------------------- */ 62 static int oce_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd); 63 static int oce_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 64 static int oce_quiesce(dev_info_t *dip); 65 static int oce_suspend(dev_info_t *dip); 66 static int oce_resume(dev_info_t *dip); 67 static void oce_unconfigure(struct oce_dev *dev); 68 static void oce_init_locks(struct oce_dev *dev); 69 static void oce_destroy_locks(struct oce_dev *dev); 70 static void oce_get_params(struct oce_dev *dev); 71 72 static struct cb_ops oce_cb_ops = { 73 nulldev, /* cb_open */ 74 nulldev, /* cb_close */ 75 nodev, /* cb_strategy */ 76 nodev, /* cb_print */ 77 nodev, /* cb_dump */ 78 nodev, /* cb_read */ 79 nodev, /* cb_write */ 80 nodev, /* cb_ioctl */ 81 nodev, /* cb_devmap */ 82 nodev, /* cb_mmap */ 83 nodev, /* cb_segmap */ 84 nochpoll, /* cb_chpoll */ 85 ddi_prop_op, /* cb_prop_op */ 86 NULL, /* cb_stream */ 87 D_MP, /* cb_flag */ 88 CB_REV, /* cb_rev */ 89 nodev, /* cb_aread */ 90 nodev /* cb_awrite */ 91 }; 92 93 static struct dev_ops oce_dev_ops = { 94 DEVO_REV, /* devo_rev */ 95 0, /* devo_refcnt */ 96 NULL, /* devo_getinfo */ 97 NULL, /* devo_identify */ 98 nulldev, /* devo_probe */ 99 oce_attach, /* devo_attach */ 100 oce_detach, /* devo_detach */ 101 nodev, /* devo_reset */ 102 &oce_cb_ops, /* devo_cb_ops */ 103 NULL, /* devo_bus_ops */ 104 nodev, /* devo_power */ 105 oce_quiesce /* devo_quiesce */ 106 }; 107 108 static struct modldrv oce_drv = { 109 &mod_driverops, /* Type of module. This one is a driver */ 110 (char *)oce_ident_string, /* Description string */ 111 &oce_dev_ops, /* driver ops */ 112 }; 113 114 static struct modlinkage oce_mod_linkage = { 115 MODREV_1, &oce_drv, NULL 116 }; 117 118 #define OCE_M_CB_FLAGS (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | \ 119 MC_PROPINFO) 120 static mac_callbacks_t oce_mac_cb = { 121 OCE_M_CB_FLAGS, /* mc_callbacks */ 122 oce_m_stat, /* mc_getstat */ 123 oce_m_start, /* mc_start */ 124 oce_m_stop, /* mc_stop */ 125 oce_m_promiscuous, /* mc_setpromisc */ 126 oce_m_multicast, /* mc_multicast */ 127 oce_m_unicast, /* mc_unicast */ 128 oce_m_send, /* mc_tx */ 129 NULL, /* mc_reserve */ 130 oce_m_ioctl, /* mc_ioctl */ 131 oce_m_getcap, /* mc_getcapab */ 132 NULL, /* open */ 133 NULL, /* close */ 134 oce_m_setprop, /* set properties */ 135 oce_m_getprop, /* get properties */ 136 oce_m_propinfo /* properties info */ 137 }; 138 139 extern char *oce_priv_props[]; 140 141 /* Module Init */ 142 int 143 _info(struct modinfo *modinfop) 144 { 145 return (mod_info(&oce_mod_linkage, modinfop)); 146 } /* _info */ 147 148 int 149 _init(void) 150 { 151 int ret = 0; 152 153 /* install the module */ 154 mac_init_ops(&oce_dev_ops, "oce"); 155 156 ret = mod_install(&oce_mod_linkage); 157 if (ret) { 158 cmn_err(CE_WARN, "mod_install failed rval=%x", ret); 159 } 160 161 return (ret); 162 } /* _init */ 163 164 165 int 166 _fini(void) 167 { 168 int ret = 0; 169 /* remove the module */ 170 ret = mod_remove(&oce_mod_linkage); 171 if (ret != 0) { 172 return (ret); 173 } 174 175 mac_fini_ops(&oce_dev_ops); 176 177 return (ret); 178 } /* _fini */ 179 180 181 static int 182 oce_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 183 { 184 int ret = 0; 185 struct oce_dev *dev = NULL; 186 mac_register_t *mac; 187 188 switch (cmd) { 189 case DDI_RESUME: 190 return (oce_resume(dip)); 191 default: 192 return (DDI_FAILURE); 193 194 case DDI_ATTACH: 195 break; 196 } 197 198 /* allocate dev */ 199 dev = kmem_zalloc(sizeof (struct oce_dev), KM_NOSLEEP); 200 if (dev == NULL) { 201 return (DDI_FAILURE); 202 } 203 204 /* populate the dev structure */ 205 dev->dip = dip; 206 dev->dev_id = ddi_get_instance(dip); 207 dev->suspended = B_FALSE; 208 209 /* get the parameters */ 210 oce_get_params(dev); 211 212 /* 213 * set the ddi driver private data pointer. This is 214 * sent to all mac callback entry points 215 */ 216 ddi_set_driver_private(dip, dev); 217 218 dev->attach_state |= ATTACH_DEV_INIT; 219 220 oce_fm_init(dev); 221 dev->attach_state |= ATTACH_FM_INIT; 222 ret = oce_setup_intr(dev); 223 if (ret != DDI_SUCCESS) { 224 oce_log(dev, CE_WARN, MOD_CONFIG, 225 "Interrupt setup failed with %d", ret); 226 goto attach_fail; 227 228 } 229 230 /* initialize locks */ 231 oce_init_locks(dev); 232 dev->attach_state |= ATTACH_LOCK_INIT; 233 234 /* setup PCI bars */ 235 ret = oce_pci_init(dev); 236 if (ret != DDI_SUCCESS) { 237 oce_log(dev, CE_WARN, MOD_CONFIG, 238 "PCI initialization failed with %d", ret); 239 goto attach_fail; 240 } 241 dev->attach_state |= ATTACH_PCI_INIT; 242 243 /* HW init */ 244 ret = oce_hw_init(dev); 245 if (ret != DDI_SUCCESS) { 246 oce_log(dev, CE_WARN, MOD_CONFIG, 247 "HW initialization failed with %d", ret); 248 goto attach_fail; 249 } 250 dev->attach_state |= ATTACH_HW_INIT; 251 252 ret = oce_init_txrx(dev); 253 if (ret != DDI_SUCCESS) { 254 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 255 "Failed to init rings"); 256 goto attach_fail; 257 } 258 dev->attach_state |= ATTACH_SETUP_TXRX; 259 260 ret = oce_setup_adapter(dev); 261 if (ret != DDI_SUCCESS) { 262 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 263 "Failed to setup adapter"); 264 goto attach_fail; 265 } 266 dev->attach_state |= ATTACH_SETUP_ADAP; 267 268 269 ret = oce_stat_init(dev); 270 if (ret != DDI_SUCCESS) { 271 oce_log(dev, CE_WARN, MOD_CONFIG, 272 "kstat setup Failed with %d", ret); 273 goto attach_fail; 274 } 275 dev->attach_state |= ATTACH_STAT_INIT; 276 277 /* mac_register_t */ 278 oce_log(dev, CE_NOTE, MOD_CONFIG, 279 "MAC_VERSION = 0x%x", MAC_VERSION); 280 mac = mac_alloc(MAC_VERSION); 281 if (mac == NULL) { 282 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 283 "MAC allocation Failed"); 284 goto attach_fail; 285 } 286 /* 287 * fill the mac structure before calling mac_register 288 */ 289 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 290 mac->m_driver = dev; 291 mac->m_dip = dip; 292 mac->m_src_addr = dev->mac_addr; 293 mac->m_callbacks = &oce_mac_cb; 294 mac->m_min_sdu = 0; 295 mac->m_max_sdu = dev->mtu; 296 mac->m_margin = VLAN_TAGSZ; 297 mac->m_priv_props = oce_priv_props; 298 299 oce_log(dev, CE_NOTE, MOD_CONFIG, 300 "Driver Private structure = 0x%p", (void *)dev); 301 302 /* now register with GLDv3 */ 303 ret = mac_register(mac, (mac_handle_t *)&dev->mac_handle); 304 /* regardless of the status, free mac_register */ 305 mac_free(mac); 306 mac = NULL; 307 if (ret != DDI_SUCCESS) { 308 oce_log(dev, CE_WARN, MOD_CONFIG, 309 "MAC registration failed :0x%x", ret); 310 goto attach_fail; 311 312 } 313 314 /* correct link status only after start */ 315 mac_link_update(dev->mac_handle, LINK_STATE_UNKNOWN); 316 317 dev->attach_state |= ATTACH_MAC_REG; 318 dev->state |= STATE_INIT; 319 320 oce_log(dev, CE_NOTE, MOD_CONFIG, "%s", 321 "ATTACH SUCCESS"); 322 323 return (DDI_SUCCESS); 324 325 attach_fail: 326 oce_unconfigure(dev); 327 return (DDI_FAILURE); 328 } /* oce_attach */ 329 330 static int 331 oce_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 332 { 333 struct oce_dev *dev; 334 int pcnt = 0; 335 336 dev = ddi_get_driver_private(dip); 337 if (dev == NULL) { 338 return (DDI_FAILURE); 339 } 340 oce_log(dev, CE_NOTE, MOD_CONFIG, 341 "Detaching driver: cmd = 0x%x", cmd); 342 343 switch (cmd) { 344 default: 345 return (DDI_FAILURE); 346 case DDI_SUSPEND: 347 return (oce_suspend(dip)); 348 case DDI_DETACH: 349 break; 350 } /* switch cmd */ 351 352 /* Fail detach if MAC unregister is unsuccessfule */ 353 if (mac_unregister(dev->mac_handle) != 0) { 354 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 355 "Failed to unregister MAC "); 356 return (DDI_FAILURE); 357 } 358 dev->attach_state &= ~ATTACH_MAC_REG; 359 360 /* check if the detach is called with out stopping */ 361 DEV_LOCK(dev); 362 if (dev->state & STATE_MAC_STARTED) { 363 dev->state &= ~STATE_MAC_STARTED; 364 oce_stop(dev); 365 DEV_UNLOCK(dev); 366 } else 367 DEV_UNLOCK(dev); 368 369 /* 370 * Wait for Packets sent up to be freed 371 */ 372 if ((pcnt = oce_rx_pending(dev)) != 0) { 373 oce_log(dev, CE_WARN, MOD_CONFIG, 374 "%d Pending Buffers Detach failed", pcnt); 375 return (DDI_FAILURE); 376 } 377 oce_unconfigure(dev); 378 379 return (DDI_SUCCESS); 380 } /* oce_detach */ 381 382 static int 383 oce_quiesce(dev_info_t *dip) 384 { 385 int ret = DDI_SUCCESS; 386 struct oce_dev *dev = ddi_get_driver_private(dip); 387 388 if (dev == NULL) { 389 return (DDI_FAILURE); 390 } 391 if (dev->suspended) { 392 return (DDI_SUCCESS); 393 } 394 395 oce_chip_di(dev); 396 397 ret = oce_reset_fun(dev); 398 399 return (ret); 400 } 401 402 static int 403 oce_suspend(dev_info_t *dip) 404 { 405 struct oce_dev *dev = ddi_get_driver_private(dip); 406 407 mutex_enter(&dev->dev_lock); 408 /* Suspend the card */ 409 dev->suspended = B_TRUE; 410 /* stop the adapter */ 411 if (dev->state & STATE_MAC_STARTED) { 412 oce_stop(dev); 413 oce_unsetup_adapter(dev); 414 } 415 dev->state &= ~STATE_MAC_STARTED; 416 mutex_exit(&dev->dev_lock); 417 return (DDI_SUCCESS); 418 } /* oce_suspend */ 419 420 static int 421 oce_resume(dev_info_t *dip) 422 { 423 struct oce_dev *dev; 424 int ret; 425 426 /* get the dev pointer from dip */ 427 dev = ddi_get_driver_private(dip); 428 mutex_enter(&dev->dev_lock); 429 if (!dev->suspended) { 430 mutex_exit(&dev->dev_lock); 431 return (DDI_SUCCESS); 432 } 433 if (dev->state & STATE_MAC_STARTED) { 434 ret = oce_setup_adapter(dev); 435 if (ret != DDI_SUCCESS) { 436 mutex_exit(&dev->dev_lock); 437 return (DDI_FAILURE); 438 } 439 ret = oce_start(dev); 440 if (ret != DDI_SUCCESS) { 441 mutex_exit(&dev->dev_lock); 442 return (DDI_FAILURE); 443 } 444 } 445 dev->suspended = B_FALSE; 446 dev->state |= STATE_MAC_STARTED; 447 mutex_exit(&dev->dev_lock); 448 return (ret); 449 } /* oce_resume */ 450 451 static void 452 oce_init_locks(struct oce_dev *dev) 453 { 454 /* initialize locks */ 455 mutex_init(&dev->dev_lock, NULL, MUTEX_DRIVER, 456 DDI_INTR_PRI(dev->intr_pri)); 457 mutex_init(&dev->bmbx_lock, NULL, MUTEX_DRIVER, 458 DDI_INTR_PRI(dev->intr_pri)); 459 } /* oce_init_locks */ 460 461 static void 462 oce_destroy_locks(struct oce_dev *dev) 463 { 464 mutex_destroy(&dev->dev_lock); 465 mutex_destroy(&dev->bmbx_lock); 466 } /* oce_destroy_locks */ 467 468 static void 469 oce_unconfigure(struct oce_dev *dev) 470 { 471 uint32_t state = dev->attach_state; 472 473 if (state & ATTACH_MAC_REG) { 474 (void) mac_unregister(dev->mac_handle); 475 } 476 if (state & ATTACH_STAT_INIT) { 477 oce_stat_fini(dev); 478 } 479 if (state & ATTACH_SETUP_ADAP) { 480 oce_unsetup_adapter(dev); 481 } 482 483 if (state & ATTACH_SETUP_TXRX) { 484 oce_fini_txrx(dev); 485 } 486 487 if (state & ATTACH_HW_INIT) { 488 oce_hw_fini(dev); 489 } 490 if (state & ATTACH_PCI_INIT) { 491 oce_pci_fini(dev); 492 } 493 if (state & ATTACH_LOCK_INIT) { 494 oce_destroy_locks(dev); 495 } 496 if (state & ATTACH_FM_INIT) { 497 oce_fm_fini(dev); 498 } 499 if (state & ATTACH_DEV_INIT) { 500 ddi_set_driver_private(dev->dip, NULL); 501 kmem_free(dev, sizeof (struct oce_dev)); 502 } 503 } /* oce_unconfigure */ 504 505 static void 506 oce_get_params(struct oce_dev *dev) 507 { 508 uint32_t log_level; 509 uint16_t mod_mask; 510 uint16_t severity; 511 512 /* non tunables */ 513 dev->rx_ring_size = OCE_DEFAULT_RX_RING_SIZE; 514 dev->flow_control = OCE_DEFAULT_FLOW_CONTROL; 515 516 /* configurable parameters */ 517 518 /* restrict MTU to 1500 and 9000 only */ 519 dev->mtu = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 520 DDI_PROP_DONTPASS, (char *)mtu_prop_name, OCE_MIN_MTU); 521 if (dev->mtu != OCE_MIN_MTU && dev->mtu != OCE_MAX_MTU) 522 dev->mtu = OCE_MIN_MTU; 523 524 dev->tx_ring_size = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 525 DDI_PROP_DONTPASS, (char *)tx_ring_size_name, 526 OCE_DEFAULT_TX_RING_SIZE); 527 528 dev->tx_bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 529 DDI_PROP_DONTPASS, (char *)tx_bcopy_limit_name, 530 OCE_DEFAULT_TX_BCOPY_LIMIT); 531 dev->rx_bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 532 DDI_PROP_DONTPASS, (char *)rx_bcopy_limit_name, 533 OCE_DEFAULT_RX_BCOPY_LIMIT); 534 535 dev->lso_capable = (boolean_t)ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 536 DDI_PROP_DONTPASS, (char *)lso_capable_name, 1); 537 538 dev->fm_caps = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 539 DDI_PROP_DONTPASS, (char *)fm_cap_name, OCE_FM_CAPABILITY); 540 541 log_level = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 542 DDI_PROP_DONTPASS, (char *)log_level_name, 543 OCE_DEFAULT_LOG_SETTINGS); 544 severity = (uint16_t)(log_level & 0xffff); 545 mod_mask = (uint16_t)(log_level >> 16); 546 if (mod_mask > MOD_ISR) { 547 mod_mask = 0; 548 } 549 if (severity > CE_IGNORE) { 550 severity = 0; 551 } 552 553 dev->mod_mask = mod_mask; 554 dev->severity = severity; 555 } /* oce_get_params */ 556