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-2013 Solarflare Communications Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/ddi.h> 29 #include <sys/sunddi.h> 30 #include <sys/atomic.h> 31 #include <sys/modctl.h> 32 #include <sys/conf.h> 33 #include <sys/ethernet.h> 34 #include <sys/pci.h> 35 #include <sys/pcie.h> 36 37 #include "sfxge.h" 38 39 #include "efx.h" 40 41 42 /* Interrupt table DMA attributes */ 43 static ddi_device_acc_attr_t sfxge_intr_devacc = { 44 45 DDI_DEVICE_ATTR_V0, /* devacc_attr_version */ 46 DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */ 47 DDI_STRICTORDER_ACC /* devacc_attr_dataorder */ 48 }; 49 50 static ddi_dma_attr_t sfxge_intr_dma_attr = { 51 DMA_ATTR_V0, /* dma_attr_version */ 52 0, /* dma_attr_addr_lo */ 53 0xffffffffffffffffull, /* dma_attr_addr_hi */ 54 0xffffffffffffffffull, /* dma_attr_count_max */ 55 EFX_INTR_SIZE, /* dma_attr_align */ 56 0xffffffff, /* dma_attr_burstsizes */ 57 1, /* dma_attr_minxfer */ 58 0xffffffffffffffffull, /* dma_attr_maxxfer */ 59 0xffffffffffffffffull, /* dma_attr_seg */ 60 1, /* dma_attr_sgllen */ 61 1, /* dma_attr_granular */ 62 0 /* dma_attr_flags */ 63 }; 64 65 static unsigned int 66 sfxge_intr_line(caddr_t arg1, caddr_t arg2) 67 { 68 sfxge_t *sp = (void *)arg1; 69 efx_nic_t *enp = sp->s_enp; 70 sfxge_intr_t *sip = &(sp->s_intr); 71 unsigned int index; 72 boolean_t fatal; 73 uint32_t qmask; 74 int rc; 75 76 _NOTE(ARGUNUSED(arg2)) 77 78 ASSERT3U(sip->si_type, ==, EFX_INTR_LINE); 79 80 if (sip->si_state != SFXGE_INTR_STARTED && 81 sip->si_state != SFXGE_INTR_TESTING) { 82 rc = DDI_INTR_UNCLAIMED; 83 goto done; 84 } 85 86 if (sip->si_state == SFXGE_INTR_TESTING) { 87 sip->si_mask |= 1; /* only one interrupt */ 88 rc = DDI_INTR_CLAIMED; 89 goto done; 90 } 91 92 efx_intr_status_line(enp, &fatal, &qmask); 93 94 if (fatal) { 95 sfxge_intr_fatal(sp); 96 97 rc = DDI_INTR_CLAIMED; 98 goto done; 99 } 100 101 if (qmask != 0) { 102 for (index = 0; index < EFX_INTR_NEVQS; index++) { 103 if (qmask & (1 << index)) 104 (void) sfxge_ev_qpoll(sp, index); 105 } 106 107 sip->si_zero_count = 0; 108 sfxge_gld_rx_push(sp); 109 rc = DDI_INTR_CLAIMED; 110 goto done; 111 } 112 113 /* 114 * bug15671/bug17203 workaround. Return CLAIMED for the first ISR=0 115 * interrupt, and poll all evqs for work. For subsequent ISR=0 116 * interrupts (the line must be shared in this case), just rearm the 117 * event queues to ensure we don't miss an interrupt. 118 */ 119 if (sip->si_zero_count++ == 0) { 120 for (index = 0; index < EFX_INTR_NEVQS; index++) { 121 if (sp->s_sep[index] != NULL) 122 (void) sfxge_ev_qpoll(sp, index); 123 } 124 125 rc = DDI_INTR_CLAIMED; 126 } else { 127 for (index = 0; index < EFX_INTR_NEVQS; index++) { 128 if (sp->s_sep[index] != NULL) 129 (void) sfxge_ev_qprime(sp, index); 130 } 131 132 rc = DDI_INTR_UNCLAIMED; 133 } 134 135 done: 136 return (rc); 137 } 138 139 static unsigned int 140 sfxge_intr_message(caddr_t arg1, caddr_t arg2) 141 { 142 sfxge_t *sp = (void *)arg1; 143 efx_nic_t *enp = sp->s_enp; 144 sfxge_intr_t *sip = &(sp->s_intr); 145 unsigned int index = (unsigned int)(uintptr_t)arg2; 146 boolean_t fatal; 147 int rc; 148 149 ASSERT3U(sip->si_type, ==, EFX_INTR_MESSAGE); 150 151 if (sip->si_state != SFXGE_INTR_STARTED && 152 sip->si_state != SFXGE_INTR_TESTING) { 153 rc = DDI_INTR_UNCLAIMED; 154 goto done; 155 } 156 157 if (sip->si_state == SFXGE_INTR_TESTING) { 158 uint64_t mask; 159 160 do { 161 mask = sip->si_mask; 162 } while (atomic_cas_64(&(sip->si_mask), mask, 163 mask | (1 << index)) != mask); 164 165 rc = DDI_INTR_CLAIMED; 166 goto done; 167 } 168 169 efx_intr_status_message(enp, index, &fatal); 170 171 if (fatal) { 172 sfxge_intr_fatal(sp); 173 174 rc = DDI_INTR_CLAIMED; 175 goto done; 176 } 177 178 (void) sfxge_ev_qpoll(sp, index); 179 180 sfxge_gld_rx_push(sp); 181 rc = DDI_INTR_CLAIMED; 182 183 done: 184 return (rc); 185 } 186 187 static int 188 sfxge_intr_bus_enable(sfxge_t *sp) 189 { 190 sfxge_intr_t *sip = &(sp->s_intr); 191 ddi_intr_handler_t *handler; 192 int add_index; 193 int en_index; 194 int err; 195 int rc; 196 197 /* Serialise all instances to avoid problems seen in bug31184. */ 198 mutex_enter(&sfxge_global_lock); 199 200 switch (sip->si_type) { 201 case EFX_INTR_MESSAGE: 202 handler = sfxge_intr_message; 203 break; 204 205 case EFX_INTR_LINE: 206 handler = sfxge_intr_line; 207 break; 208 209 default: 210 cmn_err(CE_WARN, SFXGE_CMN_ERR 211 "[%s%d] bus_enable: unknown intr type" 212 " (si_type=%d nalloc=%d)\n", 213 ddi_driver_name(sp->s_dip), 214 ddi_get_instance(sp->s_dip), 215 sip->si_type, sip->si_nalloc); 216 ASSERT(B_FALSE); 217 rc = EINVAL; 218 goto fail1; 219 } 220 221 /* Try to add the handlers */ 222 for (add_index = 0; add_index < sip->si_nalloc; add_index++) { 223 unsigned int pri; 224 225 (void) ddi_intr_get_pri(sip->si_table[add_index], &pri); 226 DTRACE_PROBE2(pri, unsigned int, add_index, unsigned int, pri); 227 228 err = ddi_intr_add_handler(sip->si_table[add_index], handler, 229 (caddr_t)sp, (caddr_t)(uintptr_t)add_index); 230 if (err != DDI_SUCCESS) { 231 cmn_err(CE_WARN, SFXGE_CMN_ERR 232 "[%s%d] bus_enable: ddi_intr_add_handler failed" 233 " err=%d (h=%p idx=%d nalloc=%d)\n", 234 ddi_driver_name(sp->s_dip), 235 ddi_get_instance(sp->s_dip), 236 err, sip->si_table[add_index], add_index, 237 sip->si_nalloc); 238 239 rc = (err == DDI_EINVAL) ? EINVAL : EFAULT; 240 goto fail2; 241 } 242 } 243 244 /* Get interrupt capabilities */ 245 err = ddi_intr_get_cap(sip->si_table[0], &(sip->si_cap)); 246 if (err != DDI_SUCCESS) { 247 cmn_err(CE_WARN, SFXGE_CMN_ERR 248 "[%s%d] bus_enable: ddi_intr_get_cap failed" 249 " err=%d (h=%p idx=%d nalloc=%d)\n", 250 ddi_driver_name(sp->s_dip), 251 ddi_get_instance(sp->s_dip), 252 err, sip->si_table[0], 0, sip->si_nalloc); 253 254 if (err == DDI_EINVAL) 255 rc = EINVAL; 256 else if (err == DDI_ENOTSUP) 257 rc = ENOTSUP; 258 else 259 rc = EFAULT; 260 261 goto fail3; 262 } 263 264 /* Enable interrupts at the bus */ 265 if (sip->si_cap & DDI_INTR_FLAG_BLOCK) { 266 en_index = 0; /* Silence gcc */ 267 err = ddi_intr_block_enable(sip->si_table, sip->si_nalloc); 268 if (err != DDI_SUCCESS) { 269 cmn_err(CE_WARN, SFXGE_CMN_ERR 270 "[%s%d] bus_enable: ddi_intr_block_enable failed" 271 " err=%d (table=%p nalloc=%d)\n", 272 ddi_driver_name(sp->s_dip), 273 ddi_get_instance(sp->s_dip), 274 err, sip->si_table, sip->si_nalloc); 275 276 rc = (err == DDI_EINVAL) ? EINVAL : EFAULT; 277 goto fail4; 278 } 279 } else { 280 for (en_index = 0; en_index < sip->si_nalloc; en_index++) { 281 err = ddi_intr_enable(sip->si_table[en_index]); 282 if (err != DDI_SUCCESS) { 283 cmn_err(CE_WARN, SFXGE_CMN_ERR 284 "[%s%d] bus_enable: ddi_intr_enable failed" 285 " err=%d (h=%p idx=%d nalloc=%d)\n", 286 ddi_driver_name(sp->s_dip), 287 ddi_get_instance(sp->s_dip), 288 err, sip->si_table[en_index], en_index, 289 sip->si_nalloc); 290 291 rc = (err == DDI_EINVAL) ? EINVAL : EFAULT; 292 goto fail4; 293 } 294 } 295 } 296 297 mutex_exit(&sfxge_global_lock); 298 return (0); 299 300 fail4: 301 DTRACE_PROBE(fail4); 302 303 /* Disable the enabled handlers */ 304 if (!(sip->si_cap & DDI_INTR_FLAG_BLOCK)) { 305 while (--en_index >= 0) { 306 err = ddi_intr_disable(sip->si_table[en_index]); 307 if (err != DDI_SUCCESS) { 308 cmn_err(CE_WARN, SFXGE_CMN_ERR 309 "[%s%d] bus_enable: ddi_intr_disable" 310 " failed err=%d (h=%p idx=%d nalloc=%d)\n", 311 ddi_driver_name(sp->s_dip), 312 ddi_get_instance(sp->s_dip), 313 err, sip->si_table[en_index], en_index, 314 sip->si_nalloc); 315 } 316 } 317 } 318 319 fail3: 320 DTRACE_PROBE(fail3); 321 322 /* Remove all handlers */ 323 add_index = sip->si_nalloc; 324 325 fail2: 326 DTRACE_PROBE(fail2); 327 328 /* Remove remaining handlers */ 329 while (--add_index >= 0) { 330 err = ddi_intr_remove_handler(sip->si_table[add_index]); 331 if (err != DDI_SUCCESS) { 332 cmn_err(CE_WARN, SFXGE_CMN_ERR 333 "[%s%d] bus_enable: ddi_intr_remove_handler" 334 " failed err=%d (h=%p idx=%d nalloc=%d)\n", 335 ddi_driver_name(sp->s_dip), 336 ddi_get_instance(sp->s_dip), 337 err, sip->si_table[add_index], add_index, 338 sip->si_nalloc); 339 } 340 } 341 342 fail1: 343 DTRACE_PROBE1(fail1, int, rc); 344 345 mutex_exit(&sfxge_global_lock); 346 return (rc); 347 } 348 349 static void 350 sfxge_intr_bus_disable(sfxge_t *sp) 351 { 352 sfxge_intr_t *sip = &(sp->s_intr); 353 int index; 354 int err; 355 356 /* Serialise all instances to avoid problems seen in bug31184. */ 357 mutex_enter(&sfxge_global_lock); 358 359 /* Disable interrupts at the bus */ 360 if (sip->si_cap & DDI_INTR_FLAG_BLOCK) { 361 err = ddi_intr_block_disable(sip->si_table, sip->si_nalloc); 362 if (err != DDI_SUCCESS) { 363 cmn_err(CE_WARN, SFXGE_CMN_ERR 364 "[%s%d] bus_disable: ddi_intr_block_disable" 365 " failed err=%d (table=%p nalloc=%d)\n", 366 ddi_driver_name(sp->s_dip), 367 ddi_get_instance(sp->s_dip), 368 err, sip->si_table, sip->si_nalloc); 369 } 370 } else { 371 index = sip->si_nalloc; 372 while (--index >= 0) { 373 err = ddi_intr_disable(sip->si_table[index]); 374 if (err != DDI_SUCCESS) { 375 cmn_err(CE_WARN, SFXGE_CMN_ERR 376 "[%s%d] bus_disable: ddi_intr_disable" 377 " failed err=%d (h=%p idx=%d nalloc=%d)\n", 378 ddi_driver_name(sp->s_dip), 379 ddi_get_instance(sp->s_dip), 380 err, sip->si_table[index], index, 381 sip->si_nalloc); 382 } 383 } 384 } 385 386 sip->si_cap = 0; 387 388 /* Remove all handlers */ 389 index = sip->si_nalloc; 390 while (--index >= 0) { 391 err = ddi_intr_remove_handler(sip->si_table[index]); 392 if (err != DDI_SUCCESS) { 393 cmn_err(CE_WARN, SFXGE_CMN_ERR 394 "[%s%d] bus_disable: ddi_intr_remove_handler" 395 " failed err=%d (h=%p idx=%d nalloc=%d)\n", 396 ddi_driver_name(sp->s_dip), 397 ddi_get_instance(sp->s_dip), 398 err, sip->si_table[index], index, 399 sip->si_nalloc); 400 } 401 } 402 403 mutex_exit(&sfxge_global_lock); 404 } 405 406 static int 407 sfxge_intr_nic_enable(sfxge_t *sp) 408 { 409 sfxge_intr_t *sip = &(sp->s_intr); 410 efsys_mem_t *esmp = &(sip->si_mem); 411 efx_nic_t *enp = sp->s_enp; 412 unsigned int index; 413 uint64_t mask; 414 unsigned int count; 415 int rc; 416 417 /* Zero the memory */ 418 (void) memset(esmp->esm_base, 0, EFX_INTR_SIZE); 419 420 /* Enable interrupts at the NIC */ 421 if ((rc = efx_intr_init(enp, sip->si_type, esmp)) != 0) 422 goto fail1; 423 424 efx_intr_enable(enp); 425 426 /* Test the interrupts */ 427 mask = 0; 428 for (index = 0; index < sip->si_nalloc; index++) { 429 mask |= (1 << index); 430 431 rc = efx_intr_trigger(enp, index); 432 ASSERT3U(rc, ==, 0); 433 } 434 435 /* Wait for the tests to complete */ 436 count = 0; 437 do { 438 DTRACE_PROBE1(wait, unsigned int, count); 439 440 /* Spin for 1 ms */ 441 drv_usecwait(1000); 442 443 /* 444 * Check to see that all the test interrupts have been 445 * processed. 446 */ 447 if ((mask & sip->si_mask) == mask) 448 goto done; 449 450 } while (++count < 20); 451 452 rc = ETIMEDOUT; 453 goto fail2; 454 455 done: 456 return (0); 457 458 fail2: 459 DTRACE_PROBE(fail2); 460 461 cmn_err(CE_WARN, SFXGE_CMN_ERR 462 "[%s%d] Interrupt test failed (mask=%"PRIx64" got=%" 463 PRIx64"). NIC is disabled\n", 464 ddi_driver_name(sp->s_dip), ddi_get_instance(sp->s_dip), 465 mask, sip->si_mask); 466 467 DTRACE_PROBE2(int_test_fail, uint64_t, mask, uint64_t, sip->si_mask); 468 469 sip->si_mask = 0; 470 471 /* Disable interrupts at the NIC */ 472 efx_intr_disable(enp); 473 efx_intr_fini(enp); 474 475 fail1: 476 DTRACE_PROBE1(fail1, int, rc); 477 478 return (rc); 479 } 480 481 static void 482 sfxge_intr_nic_disable(sfxge_t *sp) 483 { 484 sfxge_intr_t *sip = &(sp->s_intr); 485 efx_nic_t *enp = sp->s_enp; 486 487 sip->si_mask = 0; 488 489 /* Disable interrupts at the NIC */ 490 efx_intr_disable(enp); 491 efx_intr_fini(enp); 492 } 493 494 inline unsigned pow2_le(unsigned long n) { 495 unsigned int order = 1; 496 ASSERT3U(n, >, 0); 497 while ((1ul << order) <= n) ++order; 498 return (1ul << (order - 1)); 499 } 500 501 int 502 sfxge_intr_init(sfxge_t *sp) 503 { 504 dev_info_t *dip = sp->s_dip; 505 sfxge_intr_t *sip = &(sp->s_intr); 506 efsys_mem_t *esmp = &(sip->si_mem); 507 sfxge_dma_buffer_attr_t dma_attr; 508 int err; 509 int rc; 510 int types; 511 int type; 512 int index; 513 unsigned int nalloc; 514 int navail; 515 516 SFXGE_OBJ_CHECK(sip, sfxge_intr_t); 517 518 ASSERT3U(sip->si_state, ==, SFXGE_INTR_UNINITIALIZED); 519 520 #ifdef __sparc 521 /* PSARC 2007/453 */ 522 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 523 "#msix-request", NULL, 0); 524 #endif 525 526 /* Get the map of supported interrupt types */ 527 err = ddi_intr_get_supported_types(dip, &types); 528 if (err != DDI_SUCCESS) { 529 cmn_err(CE_WARN, SFXGE_CMN_ERR 530 "[%s%d] intr_init: ddi_intr_get_supported_types" 531 " failed err=%d\n", 532 ddi_driver_name(sp->s_dip), 533 ddi_get_instance(sp->s_dip), 534 err); 535 536 if (err == DDI_EINVAL) 537 rc = EINVAL; 538 else if (err == DDI_INTR_NOTFOUND) 539 rc = ENOENT; 540 else 541 rc = EFAULT; 542 543 goto fail1; 544 } 545 546 /* Choose most favourable type */ 547 if (types & DDI_INTR_TYPE_MSIX) { 548 DTRACE_PROBE(msix); 549 550 type = DDI_INTR_TYPE_MSIX; 551 sip->si_type = EFX_INTR_MESSAGE; 552 } else { 553 DTRACE_PROBE(fixed); 554 555 ASSERT(types & DDI_INTR_TYPE_FIXED); 556 557 type = DDI_INTR_TYPE_FIXED; 558 sip->si_type = EFX_INTR_LINE; 559 } 560 561 /* Get the number of available interrupts */ 562 navail = 0; 563 err = ddi_intr_get_navail(dip, type, &navail); 564 if (err != DDI_SUCCESS) { 565 cmn_err(CE_WARN, SFXGE_CMN_ERR 566 "[%s%d] intr_init: ddi_intr_get_navail failed err=%d\n", 567 ddi_driver_name(sp->s_dip), ddi_get_instance(sp->s_dip), 568 err); 569 570 if (err == DDI_EINVAL) 571 rc = EINVAL; 572 else if (err == DDI_INTR_NOTFOUND) 573 rc = ENOENT; 574 else 575 rc = EFAULT; 576 577 goto fail2; 578 } 579 580 /* Double-check */ 581 if (navail == 0) { 582 rc = ENOENT; 583 goto fail2; 584 } 585 586 /* 587 * Allow greater number of MSI-X interrupts than CPUs. 588 * This can be useful to prevent RX no desc drops; See task 32179. 589 * Limit non MSI-X interrupts to a single instance. 590 */ 591 if (type != DDI_INTR_TYPE_MSIX) 592 navail = 1; 593 else 594 navail = min(navail, sfxge_rx_scale_prop_get(sp)); 595 596 DTRACE_PROBE1(navail, unsigned int, navail); 597 598 /* Allocate a handle table */ 599 sip->si_table_size = navail * sizeof (ddi_intr_handle_t); 600 sip->si_table = kmem_zalloc(sip->si_table_size, KM_SLEEP); 601 602 /* 603 * Allocate interrupt handles. 604 * Serialise all device instances to avoid problems seen in bug31184. 605 */ 606 mutex_enter(&sfxge_global_lock); 607 608 err = ddi_intr_alloc(dip, sip->si_table, type, 0, 609 navail, &(sip->si_nalloc), DDI_INTR_ALLOC_NORMAL); 610 611 mutex_exit(&sfxge_global_lock); 612 613 if (err != DDI_SUCCESS) { 614 cmn_err(CE_WARN, SFXGE_CMN_ERR 615 "[%s%d] intr_init: ddi_intr_alloc failed err=%d" 616 " (navail=%d nalloc=%d)\n", 617 ddi_driver_name(sp->s_dip), ddi_get_instance(sp->s_dip), 618 err, navail, sip->si_nalloc); 619 620 if (err == DDI_EINVAL) 621 rc = EINVAL; 622 else if (err == DDI_EAGAIN) 623 rc = EAGAIN; 624 else if (err == DDI_INTR_NOTFOUND) 625 rc = ENOENT; 626 else 627 rc = EFAULT; 628 629 goto fail3; 630 } 631 632 /* Double-check */ 633 if (sip->si_nalloc == 0) { 634 rc = ENOENT; 635 goto fail3; 636 } 637 638 /* Round down to a power of 2 */ 639 nalloc = pow2_le(sip->si_nalloc); 640 641 /* Free off any excess handles */ 642 mutex_enter(&sfxge_global_lock); 643 644 index = sip->si_nalloc; 645 while (--index >= nalloc) { 646 (void) ddi_intr_free(sip->si_table[index]); 647 sip->si_table[index] = NULL; 648 } 649 650 mutex_exit(&sfxge_global_lock); 651 652 sip->si_nalloc = nalloc; 653 DTRACE_PROBE1(nalloc, unsigned int, sip->si_nalloc); 654 655 dma_attr.sdba_dip = sp->s_dip; 656 dma_attr.sdba_dattrp = &sfxge_intr_dma_attr; 657 dma_attr.sdba_callback = DDI_DMA_SLEEP; 658 dma_attr.sdba_length = EFX_INTR_SIZE; 659 dma_attr.sdba_memflags = DDI_DMA_CONSISTENT; 660 dma_attr.sdba_devaccp = &sfxge_intr_devacc; 661 dma_attr.sdba_bindflags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT; 662 dma_attr.sdba_maxcookies = 1; 663 dma_attr.sdba_zeroinit = B_TRUE; 664 665 if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0) 666 goto fail4; 667 668 /* Store the highest priority for convenience */ 669 sip->si_intr_pri = 0; 670 for (index = 0; index < sip->si_nalloc; index++) { 671 int pri; 672 if ((rc = ddi_intr_get_pri(sip->si_table[index], &pri)) != 0) 673 goto fail5; 674 if (pri > sip->si_intr_pri) 675 sip->si_intr_pri = pri; 676 } 677 678 sip->si_state = SFXGE_INTR_INITIALIZED; 679 return (0); 680 681 fail5: 682 DTRACE_PROBE(fail5); 683 684 fail4: 685 DTRACE_PROBE(fail4); 686 687 /* Free interrupt handles */ 688 mutex_exit(&sfxge_global_lock); 689 690 index = sip->si_nalloc; 691 while (--index >= 0) { 692 err = ddi_intr_free(sip->si_table[index]); 693 if (err != DDI_SUCCESS) { 694 cmn_err(CE_WARN, SFXGE_CMN_ERR 695 "[%s%d] intr_init: ddi_intr_free failed err=%d" 696 " (h=%p idx=%d nalloc=%d)\n", 697 ddi_driver_name(sp->s_dip), 698 ddi_get_instance(sp->s_dip), 699 err, sip->si_table[index], index, sip->si_nalloc); 700 } 701 sip->si_table[index] = NULL; 702 } 703 sip->si_nalloc = 0; 704 705 mutex_exit(&sfxge_global_lock); 706 707 fail3: 708 DTRACE_PROBE(fail3); 709 710 /* Free the handle table */ 711 kmem_free(sip->si_table, sip->si_table_size); 712 sip->si_table = NULL; 713 sip->si_table_size = 0; 714 715 fail2: 716 DTRACE_PROBE(fail2); 717 718 /* Clear the interrupt type */ 719 sip->si_type = EFX_INTR_INVALID; 720 721 fail1: 722 DTRACE_PROBE1(fail1, int, rc); 723 724 SFXGE_OBJ_CHECK(sip, sfxge_intr_t); 725 726 return (rc); 727 } 728 729 int 730 sfxge_intr_start(sfxge_t *sp) 731 { 732 sfxge_intr_t *sip = &(sp->s_intr); 733 int rc; 734 735 ASSERT3U(sip->si_state, ==, SFXGE_INTR_INITIALIZED); 736 737 /* Enable interrupts at the bus */ 738 if ((rc = sfxge_intr_bus_enable(sp)) != 0) 739 goto fail1; 740 741 sip->si_state = SFXGE_INTR_TESTING; 742 743 /* Enable interrupts at the NIC */ 744 if ((rc = sfxge_intr_nic_enable(sp)) != 0) 745 goto fail2; 746 747 sip->si_state = SFXGE_INTR_STARTED; 748 749 return (0); 750 751 fail2: 752 DTRACE_PROBE(fail2); 753 754 /* Disable interrupts at the bus */ 755 sfxge_intr_bus_disable(sp); 756 757 fail1: 758 DTRACE_PROBE1(fail1, int, rc); 759 760 sip->si_state = SFXGE_INTR_INITIALIZED; 761 762 return (rc); 763 } 764 765 void 766 sfxge_intr_stop(sfxge_t *sp) 767 { 768 sfxge_intr_t *sip = &(sp->s_intr); 769 770 ASSERT3U(sip->si_state, ==, SFXGE_INTR_STARTED); 771 772 sip->si_state = SFXGE_INTR_INITIALIZED; 773 774 /* Disable interrupts at the NIC */ 775 sfxge_intr_nic_disable(sp); 776 777 /* Disable interrupts at the bus */ 778 sfxge_intr_bus_disable(sp); 779 } 780 781 void 782 sfxge_intr_fini(sfxge_t *sp) 783 { 784 sfxge_intr_t *sip = &(sp->s_intr); 785 efsys_mem_t *esmp = &(sip->si_mem); 786 int index; 787 int err; 788 789 ASSERT3U(sip->si_state, ==, SFXGE_INTR_INITIALIZED); 790 791 sip->si_state = SFXGE_INTR_UNINITIALIZED; 792 793 /* Tear down dma setup */ 794 sfxge_dma_buffer_destroy(esmp); 795 796 797 /* Free interrupt handles */ 798 mutex_enter(&sfxge_global_lock); 799 800 index = sip->si_nalloc; 801 while (--index >= 0) { 802 err = ddi_intr_free(sip->si_table[index]); 803 if (err != DDI_SUCCESS) { 804 cmn_err(CE_WARN, SFXGE_CMN_ERR 805 "[%s%d] intr_fini: ddi_intr_free failed err=%d" 806 " (h=%p idx=%d nalloc=%d)\n", 807 ddi_driver_name(sp->s_dip), 808 ddi_get_instance(sp->s_dip), 809 err, sip->si_table[index], index, sip->si_nalloc); 810 } 811 sip->si_table[index] = NULL; 812 } 813 sip->si_nalloc = 0; 814 815 mutex_exit(&sfxge_global_lock); 816 817 /* Free the handle table */ 818 kmem_free(sip->si_table, sip->si_table_size); 819 sip->si_table = NULL; 820 sip->si_table_size = 0; 821 822 /* Clear the interrupt type */ 823 sip->si_type = EFX_INTR_INVALID; 824 825 SFXGE_OBJ_CHECK(sip, sfxge_intr_t); 826 }