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