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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/nxge/nxge_impl.h> 29 #include <sys/nxge/nxge_txc.h> 30 31 static nxge_status_t 32 nxge_txc_handle_port_errors(p_nxge_t, uint32_t); 33 static void 34 nxge_txc_inject_port_err(uint8_t, txc_int_stat_dbg_t *, 35 uint8_t istats); 36 extern nxge_status_t nxge_tx_port_fatal_err_recover(p_nxge_t); 37 38 nxge_status_t 39 nxge_txc_init(p_nxge_t nxgep) 40 { 41 uint8_t port; 42 npi_handle_t handle; 43 npi_status_t rs = NPI_SUCCESS; 44 45 handle = NXGE_DEV_NPI_HANDLE(nxgep); 46 port = NXGE_GET_PORT_NUM(nxgep->function_num); 47 48 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txc_init: portn %d", port)); 49 50 /* 51 * Enable the TXC controller. 52 */ 53 if ((rs = npi_txc_global_enable(handle)) != NPI_SUCCESS) { 54 goto fail; 55 } 56 57 /* Enable this port within the TXC. */ 58 if ((rs = npi_txc_port_enable(handle, port)) != NPI_SUCCESS) { 59 goto fail; 60 } 61 62 /* Bind DMA channels to this port. */ 63 if ((rs = npi_txc_port_dma_enable(handle, port, 64 TXDMA_PORT_BITMAP(nxgep))) != NPI_SUCCESS) { 65 goto fail; 66 } 67 68 /* Unmask all TXC interrupts */ 69 npi_txc_global_imask_set(handle, port, 0); 70 71 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txc_init: portn %d", port)); 72 73 return (NXGE_OK); 74 fail: 75 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 76 "nxge_txc_init: Failed to initialize txc on port %d", 77 port)); 78 79 return (NXGE_ERROR | rs); 80 } 81 82 nxge_status_t 83 nxge_txc_uninit(p_nxge_t nxgep) 84 { 85 uint8_t port; 86 npi_handle_t handle; 87 npi_status_t rs = NPI_SUCCESS; 88 89 handle = NXGE_DEV_NPI_HANDLE(nxgep); 90 port = NXGE_GET_PORT_NUM(nxgep->function_num); 91 92 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txc_uninit: portn %d", port)); 93 94 /* 95 * disable the TXC controller. 96 */ 97 if ((rs = npi_txc_global_disable(handle)) != NPI_SUCCESS) { 98 goto fail; 99 } 100 101 /* disable this port within the TXC. */ 102 if ((rs = npi_txc_port_disable(handle, port)) != NPI_SUCCESS) { 103 goto fail; 104 } 105 106 /* unbind DMA channels to this port. */ 107 if ((rs = npi_txc_port_dma_enable(handle, port, 0)) != NPI_SUCCESS) { 108 goto fail; 109 } 110 111 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txc_uninit: portn %d", port)); 112 113 return (NXGE_OK); 114 fail: 115 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 116 "nxge_txc_init: Failed to initialize txc on port %d", 117 port)); 118 119 return (NXGE_ERROR | rs); 120 } 121 122 /* 123 * nxge_txc_tdc_bind 124 * 125 * Bind a TDC to a port. 126 * 127 * Arguments: 128 * nxgep 129 * channel The channel to bind. 130 * 131 * Notes: 132 * 133 * NPI/NXGE function calls: 134 * npi_txc_control() 135 * npi_txc_global_imask_set() 136 * npi_txc_port_dma_enable() 137 * 138 * Registers accessed: 139 * TXC_CONTROL 140 * TXC_PORT_DMA 141 * TXC_INT_MASK 142 * 143 * Context: 144 * Service domain 145 */ 146 nxge_status_t 147 nxge_txc_tdc_bind( 148 p_nxge_t nxgep, 149 int channel) 150 { 151 uint8_t port; 152 uint64_t bitmap; 153 npi_handle_t handle; 154 npi_status_t rs = NPI_SUCCESS; 155 txc_control_t txc_control; 156 157 port = NXGE_GET_PORT_NUM(nxgep->function_num); 158 159 NXGE_DEBUG_MSG((nxgep, TX_CTL, 160 "==> nxge_txc_tdc_bind(port %d, channel %d)", port, channel)); 161 162 handle = NXGE_DEV_NPI_HANDLE(nxgep); 163 164 /* Get the current value of TXC_CONTROL. */ 165 (void) npi_txc_control(handle, OP_GET, &txc_control); 166 167 /* Mask all TXC interrupts for <port>. */ 168 if (txc_control.value & (1 << port)) { 169 npi_txc_global_imask_set(handle, port, TXC_INT_MASK_IVAL); 170 } 171 172 /* Bind <channel> to <port>. */ 173 /* Read in the old bitmap. */ 174 TXC_FZC_CNTL_REG_READ64(handle, TXC_PORT_DMA_ENABLE_REG, port, 175 &bitmap); 176 177 if (bitmap & (1 << channel)) { 178 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 179 "nxge_txc_tdc_bind: channel %d already bound on port %d", 180 channel, port)); 181 } else { 182 /* Bind the new channel. */ 183 bitmap |= (1 << channel); 184 NXGE_DEBUG_MSG((nxgep, TX_CTL, 185 "==> nxge_txc_tdc_bind(): bitmap = %lx", bitmap)); 186 187 /* Write out the new bitmap. */ 188 if ((rs = npi_txc_port_dma_enable(handle, port, 189 (uint32_t)bitmap)) != NPI_SUCCESS) { 190 goto fail; 191 } 192 } 193 194 /* Enable this port, if necessary. */ 195 if (!(txc_control.value & (1 << port))) { 196 if ((rs = npi_txc_port_enable(handle, port)) != NPI_SUCCESS) { 197 goto fail; 198 } 199 } 200 201 /* 202 * Enable the TXC controller, if necessary. 203 */ 204 if (txc_control.bits.ldw.txc_enabled == 0) { 205 if ((rs = npi_txc_global_enable(handle)) != NPI_SUCCESS) { 206 goto fail; 207 } 208 } 209 210 /* Unmask all TXC interrupts on <port> */ 211 npi_txc_global_imask_set(handle, port, 0); 212 213 NXGE_DEBUG_MSG((nxgep, TX_CTL, 214 "<== nxge_txc_tdc_bind(port %d, channel %d)", port, channel)); 215 216 return (NXGE_OK); 217 fail: 218 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 219 "nxge_txc_tdc_bind(port %d, channel %d) failed", port, channel)); 220 221 return (NXGE_ERROR | rs); 222 } 223 224 /* 225 * nxge_txc_tdc_unbind 226 * 227 * Unbind a TDC from a port. 228 * 229 * Arguments: 230 * nxgep 231 * channel The channel to unbind. 232 * 233 * Notes: 234 * 235 * NPI/NXGE function calls: 236 * npi_txc_control() 237 * npi_txc_global_imask_set() 238 * npi_txc_port_dma_enable() 239 * 240 * Registers accessed: 241 * TXC_CONTROL 242 * TXC_PORT_DMA 243 * TXC_INT_MASK 244 * 245 * Context: 246 * Service domain 247 */ 248 nxge_status_t 249 nxge_txc_tdc_unbind( 250 p_nxge_t nxgep, 251 int channel) 252 { 253 uint8_t port; 254 uint64_t bitmap; 255 npi_handle_t handle; 256 npi_status_t rs = NPI_SUCCESS; 257 258 handle = NXGE_DEV_NPI_HANDLE(nxgep); 259 port = NXGE_GET_PORT_NUM(nxgep->function_num); 260 261 NXGE_DEBUG_MSG((nxgep, TX_CTL, 262 "==> nxge_txc_tdc_unbind(port %d, channel %d)", port, channel)); 263 264 /* Mask all TXC interrupts for <port>. */ 265 npi_txc_global_imask_set(handle, port, TXC_INT_MASK_IVAL); 266 267 /* Unbind <channel>. */ 268 /* Read in the old bitmap. */ 269 TXC_FZC_CNTL_REG_READ64(handle, TXC_PORT_DMA_ENABLE_REG, port, 270 &bitmap); 271 272 bitmap &= (~(1 << channel)); 273 274 /* Write out the new bitmap. */ 275 if ((rs = npi_txc_port_dma_enable(handle, port, 276 (uint32_t)bitmap)) != NPI_SUCCESS) { 277 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 278 "npi_txc_port_dma_enable(%d, %d) failed: %x", 279 port, channel, rs)); 280 } 281 282 /* Unmask all TXC interrupts on <port> */ 283 if (bitmap) 284 npi_txc_global_imask_set(handle, port, 0); 285 286 NXGE_DEBUG_MSG((nxgep, TX_CTL, 287 "<== nxge_txc_tdc_unbind(port %d, channel %d)", port, channel)); 288 289 return (NXGE_OK); 290 fail: 291 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 292 "nxge_txc_tdc_unbind(port %d, channel %d) failed", port, channel)); 293 294 return (NXGE_ERROR | rs); 295 } 296 297 void 298 nxge_txc_regs_dump(p_nxge_t nxgep) 299 { 300 uint32_t cnt1, cnt2; 301 npi_handle_t handle; 302 txc_control_t control; 303 uint32_t bitmap = 0; 304 305 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\nTXC dump: func # %d:\n", 306 nxgep->function_num)); 307 308 handle = NXGE_DEV_NPI_HANDLE(nxgep); 309 310 (void) npi_txc_control(handle, OP_GET, &control); 311 (void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap); 312 313 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC port control 0x%0llx", 314 (long long)control.value)); 315 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC port bitmap 0x%x", bitmap)); 316 317 (void) npi_txc_pkt_xmt_to_mac_get(handle, nxgep->function_num, 318 &cnt1, &cnt2); 319 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC bytes to MAC %d " 320 "packets to MAC %d", 321 cnt1, cnt2)); 322 323 (void) npi_txc_pkt_stuffed_get(handle, nxgep->function_num, 324 &cnt1, &cnt2); 325 NXGE_DEBUG_MSG((nxgep, TX_CTL, 326 "\n\tTXC ass packets %d reorder packets %d", 327 cnt1 & 0xffff, cnt2 & 0xffff)); 328 329 (void) npi_txc_reorder_get(handle, nxgep->function_num, &cnt1); 330 NXGE_DEBUG_MSG((nxgep, TX_CTL, 331 "\n\tTXC reorder resource %d", cnt1 & 0xff)); 332 } 333 334 nxge_status_t 335 nxge_txc_handle_sys_errors(p_nxge_t nxgep) 336 { 337 npi_handle_t handle; 338 txc_int_stat_t istatus; 339 uint32_t err_status; 340 uint8_t err_portn; 341 boolean_t my_err = B_FALSE; 342 nxge_status_t status = NXGE_OK; 343 344 handle = nxgep->npi_handle; 345 npi_txc_global_istatus_get(handle, (txc_int_stat_t *)&istatus.value); 346 switch (nxgep->mac.portnum) { 347 case 0: 348 if (istatus.bits.ldw.port0_int_status) { 349 my_err = B_TRUE; 350 err_portn = 0; 351 err_status = istatus.bits.ldw.port0_int_status; 352 } 353 break; 354 case 1: 355 if (istatus.bits.ldw.port1_int_status) { 356 my_err = B_TRUE; 357 err_portn = 1; 358 err_status = istatus.bits.ldw.port1_int_status; 359 } 360 break; 361 case 2: 362 if (istatus.bits.ldw.port2_int_status) { 363 my_err = B_TRUE; 364 err_portn = 2; 365 err_status = istatus.bits.ldw.port2_int_status; 366 } 367 break; 368 case 3: 369 if (istatus.bits.ldw.port3_int_status) { 370 my_err = B_TRUE; 371 err_portn = 3; 372 err_status = istatus.bits.ldw.port3_int_status; 373 } 374 break; 375 default: 376 return (NXGE_ERROR); 377 } 378 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 379 " nxge_txc_handle_sys_errors: errored port %d", 380 err_portn)); 381 if (my_err) { 382 status = nxge_txc_handle_port_errors(nxgep, err_status); 383 } 384 385 return (status); 386 } 387 388 static nxge_status_t 389 nxge_txc_handle_port_errors(p_nxge_t nxgep, uint32_t err_status) 390 { 391 npi_handle_t handle; 392 npi_status_t rs = NPI_SUCCESS; 393 p_nxge_txc_stats_t statsp; 394 txc_int_stat_t istatus; 395 boolean_t txport_fatal = B_FALSE; 396 uint8_t portn; 397 nxge_status_t status = NXGE_OK; 398 399 handle = nxgep->npi_handle; 400 statsp = (p_nxge_txc_stats_t)&nxgep->statsp->txc_stats; 401 portn = nxgep->mac.portnum; 402 istatus.value = 0; 403 404 if ((err_status & TXC_INT_STAT_RO_CORR_ERR) || 405 (err_status & TXC_INT_STAT_RO_CORR_ERR) || 406 (err_status & TXC_INT_STAT_RO_UNCORR_ERR) || 407 (err_status & TXC_INT_STAT_REORDER_ERR)) { 408 if ((rs = npi_txc_ro_states_get(handle, portn, 409 &statsp->errlog.ro_st)) != NPI_SUCCESS) { 410 return (NXGE_ERROR | rs); 411 } 412 413 if (err_status & TXC_INT_STAT_RO_CORR_ERR) { 414 statsp->ro_correct_err++; 415 NXGE_FM_REPORT_ERROR(nxgep, portn, NULL, 416 NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR); 417 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 418 "nxge_txc_err_evnts: " 419 "RO FIFO correctable error")); 420 } 421 if (err_status & TXC_INT_STAT_RO_UNCORR_ERR) { 422 statsp->ro_uncorrect_err++; 423 NXGE_FM_REPORT_ERROR(nxgep, portn, NULL, 424 NXGE_FM_EREPORT_TXC_RO_UNCORRECT_ERR); 425 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 426 "nxge_txc_err_evnts: " 427 "RO FIFO uncorrectable error")); 428 } 429 if (err_status & TXC_INT_STAT_REORDER_ERR) { 430 statsp->reorder_err++; 431 NXGE_FM_REPORT_ERROR(nxgep, portn, NULL, 432 NXGE_FM_EREPORT_TXC_REORDER_ERR); 433 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 434 "nxge_txc_err_evnts: " 435 "fatal error: Reorder error")); 436 txport_fatal = B_TRUE; 437 } 438 439 if ((err_status & TXC_INT_STAT_RO_CORR_ERR) || 440 (err_status & TXC_INT_STAT_RO_CORR_ERR) || 441 (err_status & TXC_INT_STAT_RO_UNCORR_ERR)) { 442 443 if ((rs = npi_txc_ro_ecc_state_clr(handle, portn)) 444 != NPI_SUCCESS) 445 return (NXGE_ERROR | rs); 446 /* 447 * Making sure that error source is cleared if this is 448 * an injected error. 449 */ 450 TXC_FZC_CNTL_REG_WRITE64(handle, TXC_ROECC_CTL_REG, 451 portn, 0); 452 } 453 } 454 455 if ((err_status & TXC_INT_STAT_SF_CORR_ERR) || 456 (err_status & TXC_INT_STAT_SF_UNCORR_ERR)) { 457 if ((rs = npi_txc_sf_states_get(handle, portn, 458 &statsp->errlog.sf_st)) != NPI_SUCCESS) { 459 return (NXGE_ERROR | rs); 460 } 461 if (err_status & TXC_INT_STAT_SF_CORR_ERR) { 462 statsp->sf_correct_err++; 463 NXGE_FM_REPORT_ERROR(nxgep, portn, NULL, 464 NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR); 465 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 466 "nxge_txc_err_evnts: " 467 "SF FIFO correctable error")); 468 } 469 if (err_status & TXC_INT_STAT_SF_UNCORR_ERR) { 470 statsp->sf_uncorrect_err++; 471 NXGE_FM_REPORT_ERROR(nxgep, portn, NULL, 472 NXGE_FM_EREPORT_TXC_SF_UNCORRECT_ERR); 473 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 474 "nxge_txc_err_evnts: " 475 "SF FIFO uncorrectable error")); 476 } 477 if ((rs = npi_txc_sf_ecc_state_clr(handle, portn)) 478 != NPI_SUCCESS) 479 return (NXGE_ERROR | rs); 480 /* 481 * Making sure that error source is cleared if this is 482 * an injected error. 483 */ 484 TXC_FZC_CNTL_REG_WRITE64(handle, TXC_SFECC_CTL_REG, portn, 0); 485 } 486 487 /* Clear corresponding errors */ 488 switch (portn) { 489 case 0: 490 istatus.bits.ldw.port0_int_status = err_status; 491 break; 492 case 1: 493 istatus.bits.ldw.port1_int_status = err_status; 494 break; 495 case 2: 496 istatus.bits.ldw.port2_int_status = err_status; 497 break; 498 case 3: 499 istatus.bits.ldw.port3_int_status = err_status; 500 break; 501 default: 502 return (NXGE_ERROR); 503 } 504 505 npi_txc_global_istatus_clear(handle, istatus.value); 506 507 if (txport_fatal) { 508 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 509 " nxge_txc_handle_port_errors:" 510 " fatal Error on Port#%d\n", 511 portn)); 512 status = nxge_tx_port_fatal_err_recover(nxgep); 513 if (status == NXGE_OK) { 514 FM_SERVICE_RESTORED(nxgep); 515 } 516 } 517 518 return (status); 519 } 520 521 void 522 nxge_txc_inject_err(p_nxge_t nxgep, uint32_t err_id) 523 { 524 txc_int_stat_dbg_t txcs; 525 txc_roecc_ctl_t ro_ecc_ctl; 526 txc_sfecc_ctl_t sf_ecc_ctl; 527 uint8_t portn = nxgep->mac.portnum; 528 529 cmn_err(CE_NOTE, "!TXC error Inject\n"); 530 switch (err_id) { 531 case NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR: 532 case NXGE_FM_EREPORT_TXC_RO_UNCORRECT_ERR: 533 ro_ecc_ctl.value = 0; 534 ro_ecc_ctl.bits.ldw.all_pkts = 1; 535 ro_ecc_ctl.bits.ldw.second_line_pkt = 1; 536 if (err_id == NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR) 537 ro_ecc_ctl.bits.ldw.single_bit_err = 1; 538 else 539 ro_ecc_ctl.bits.ldw.double_bit_err = 1; 540 #if defined(__i386) 541 cmn_err(CE_NOTE, "!Write 0x%llx to TXC_ROECC_CTL_REG\n", 542 ro_ecc_ctl.value); 543 #else 544 cmn_err(CE_NOTE, "!Write 0x%lx to TXC_ROECC_CTL_REG\n", 545 ro_ecc_ctl.value); 546 #endif 547 TXC_FZC_CNTL_REG_WRITE64(nxgep->npi_handle, TXC_ROECC_CTL_REG, 548 portn, ro_ecc_ctl.value); 549 break; 550 case NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR: 551 case NXGE_FM_EREPORT_TXC_SF_UNCORRECT_ERR: 552 sf_ecc_ctl.value = 0; 553 sf_ecc_ctl.bits.ldw.all_pkts = 1; 554 sf_ecc_ctl.bits.ldw.second_line_pkt = 1; 555 if (err_id == NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR) 556 sf_ecc_ctl.bits.ldw.single_bit_err = 1; 557 else 558 sf_ecc_ctl.bits.ldw.double_bit_err = 1; 559 #if defined(__i386) 560 cmn_err(CE_NOTE, "!Write 0x%llx to TXC_SFECC_CTL_REG\n", 561 sf_ecc_ctl.value); 562 #else 563 cmn_err(CE_NOTE, "!Write 0x%lx to TXC_SFECC_CTL_REG\n", 564 sf_ecc_ctl.value); 565 #endif 566 TXC_FZC_CNTL_REG_WRITE64(nxgep->npi_handle, TXC_SFECC_CTL_REG, 567 portn, sf_ecc_ctl.value); 568 break; 569 case NXGE_FM_EREPORT_TXC_REORDER_ERR: 570 NXGE_REG_RD64(nxgep->npi_handle, TXC_INT_STAT_DBG_REG, 571 &txcs.value); 572 nxge_txc_inject_port_err(portn, &txcs, 573 TXC_INT_STAT_REORDER_ERR); 574 #if defined(__i386) 575 cmn_err(CE_NOTE, "!Write 0x%llx to TXC_INT_STAT_DBG_REG\n", 576 txcs.value); 577 #else 578 cmn_err(CE_NOTE, "!Write 0x%lx to TXC_INT_STAT_DBG_REG\n", 579 txcs.value); 580 #endif 581 NXGE_REG_WR64(nxgep->npi_handle, TXC_INT_STAT_DBG_REG, 582 txcs.value); 583 break; 584 default: 585 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 586 "nxge_txc_inject_err: Unknown err_id")); 587 } 588 } 589 590 static void 591 nxge_txc_inject_port_err(uint8_t portn, txc_int_stat_dbg_t *txcs, 592 uint8_t istats) 593 { 594 switch (portn) { 595 case 0: 596 txcs->bits.ldw.port0_int_status |= istats; 597 break; 598 case 1: 599 txcs->bits.ldw.port1_int_status |= istats; 600 break; 601 case 2: 602 txcs->bits.ldw.port2_int_status |= istats; 603 break; 604 case 3: 605 txcs->bits.ldw.port3_int_status |= istats; 606 break; 607 default: 608 ; 609 } 610 } 611