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