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 } 289 290 void 291 nxge_txc_regs_dump(p_nxge_t nxgep) 292 { 293 uint32_t cnt1, cnt2; 294 npi_handle_t handle; 295 txc_control_t control; 296 uint32_t bitmap = 0; 297 298 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\nTXC dump: func # %d:\n", 299 nxgep->function_num)); 300 301 handle = NXGE_DEV_NPI_HANDLE(nxgep); 302 303 (void) npi_txc_control(handle, OP_GET, &control); 304 (void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap); 305 306 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC port control 0x%0llx", 307 (long long)control.value)); 308 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC port bitmap 0x%x", bitmap)); 309 310 (void) npi_txc_pkt_xmt_to_mac_get(handle, nxgep->function_num, 311 &cnt1, &cnt2); 312 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC bytes to MAC %d " 313 "packets to MAC %d", 314 cnt1, cnt2)); 315 316 (void) npi_txc_pkt_stuffed_get(handle, nxgep->function_num, 317 &cnt1, &cnt2); 318 NXGE_DEBUG_MSG((nxgep, TX_CTL, 319 "\n\tTXC ass packets %d reorder packets %d", 320 cnt1 & 0xffff, cnt2 & 0xffff)); 321 322 (void) npi_txc_reorder_get(handle, nxgep->function_num, &cnt1); 323 NXGE_DEBUG_MSG((nxgep, TX_CTL, 324 "\n\tTXC reorder resource %d", cnt1 & 0xff)); 325 } 326 327 nxge_status_t 328 nxge_txc_handle_sys_errors(p_nxge_t nxgep) 329 { 330 npi_handle_t handle; 331 txc_int_stat_t istatus; 332 uint32_t err_status; 333 uint8_t err_portn; 334 boolean_t my_err = B_FALSE; 335 nxge_status_t status = NXGE_OK; 336 337 handle = nxgep->npi_handle; 338 npi_txc_global_istatus_get(handle, (txc_int_stat_t *)&istatus.value); 339 switch (nxgep->mac.portnum) { 340 case 0: 341 if (istatus.bits.ldw.port0_int_status) { 342 my_err = B_TRUE; 343 err_portn = 0; 344 err_status = istatus.bits.ldw.port0_int_status; 345 } 346 break; 347 case 1: 348 if (istatus.bits.ldw.port1_int_status) { 349 my_err = B_TRUE; 350 err_portn = 1; 351 err_status = istatus.bits.ldw.port1_int_status; 352 } 353 break; 354 case 2: 355 if (istatus.bits.ldw.port2_int_status) { 356 my_err = B_TRUE; 357 err_portn = 2; 358 err_status = istatus.bits.ldw.port2_int_status; 359 } 360 break; 361 case 3: 362 if (istatus.bits.ldw.port3_int_status) { 363 my_err = B_TRUE; 364 err_portn = 3; 365 err_status = istatus.bits.ldw.port3_int_status; 366 } 367 break; 368 default: 369 return (NXGE_ERROR); 370 } 371 if (my_err) { 372 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 373 " nxge_txc_handle_sys_errors: errored port %d", 374 err_portn)); 375 status = nxge_txc_handle_port_errors(nxgep, err_status); 376 } 377 378 return (status); 379 } 380 381 static nxge_status_t 382 nxge_txc_handle_port_errors(p_nxge_t nxgep, uint32_t err_status) 383 { 384 npi_handle_t handle; 385 npi_status_t rs = NPI_SUCCESS; 386 p_nxge_txc_stats_t statsp; 387 txc_int_stat_t istatus; 388 boolean_t txport_fatal = B_FALSE; 389 uint8_t portn; 390 nxge_status_t status = NXGE_OK; 391 392 handle = nxgep->npi_handle; 393 statsp = (p_nxge_txc_stats_t)&nxgep->statsp->txc_stats; 394 portn = nxgep->mac.portnum; 395 istatus.value = 0; 396 397 if ((err_status & TXC_INT_STAT_RO_CORR_ERR) || 398 (err_status & TXC_INT_STAT_RO_CORR_ERR) || 399 (err_status & TXC_INT_STAT_RO_UNCORR_ERR) || 400 (err_status & TXC_INT_STAT_REORDER_ERR)) { 401 if ((rs = npi_txc_ro_states_get(handle, portn, 402 &statsp->errlog.ro_st)) != NPI_SUCCESS) { 403 return (NXGE_ERROR | rs); 404 } 405 406 if (err_status & TXC_INT_STAT_RO_CORR_ERR) { 407 statsp->ro_correct_err++; 408 NXGE_FM_REPORT_ERROR(nxgep, portn, 0, 409 NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR); 410 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 411 "nxge_txc_err_evnts: " 412 "RO FIFO correctable error")); 413 } 414 if (err_status & TXC_INT_STAT_RO_UNCORR_ERR) { 415 statsp->ro_uncorrect_err++; 416 NXGE_FM_REPORT_ERROR(nxgep, portn, 0, 417 NXGE_FM_EREPORT_TXC_RO_UNCORRECT_ERR); 418 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 419 "nxge_txc_err_evnts: " 420 "RO FIFO uncorrectable error")); 421 } 422 if (err_status & TXC_INT_STAT_REORDER_ERR) { 423 statsp->reorder_err++; 424 NXGE_FM_REPORT_ERROR(nxgep, portn, 0, 425 NXGE_FM_EREPORT_TXC_REORDER_ERR); 426 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 427 "nxge_txc_err_evnts: " 428 "fatal error: Reorder error")); 429 txport_fatal = B_TRUE; 430 } 431 432 if ((err_status & TXC_INT_STAT_RO_CORR_ERR) || 433 (err_status & TXC_INT_STAT_RO_CORR_ERR) || 434 (err_status & TXC_INT_STAT_RO_UNCORR_ERR)) { 435 436 if ((rs = npi_txc_ro_ecc_state_clr(handle, portn)) 437 != NPI_SUCCESS) 438 return (NXGE_ERROR | rs); 439 /* 440 * Making sure that error source is cleared if this is 441 * an injected error. 442 */ 443 TXC_FZC_CNTL_REG_WRITE64(handle, TXC_ROECC_CTL_REG, 444 portn, 0); 445 } 446 } 447 448 if ((err_status & TXC_INT_STAT_SF_CORR_ERR) || 449 (err_status & TXC_INT_STAT_SF_UNCORR_ERR)) { 450 if ((rs = npi_txc_sf_states_get(handle, portn, 451 &statsp->errlog.sf_st)) != NPI_SUCCESS) { 452 return (NXGE_ERROR | rs); 453 } 454 if (err_status & TXC_INT_STAT_SF_CORR_ERR) { 455 statsp->sf_correct_err++; 456 NXGE_FM_REPORT_ERROR(nxgep, portn, 0, 457 NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR); 458 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 459 "nxge_txc_err_evnts: " 460 "SF FIFO correctable error")); 461 } 462 if (err_status & TXC_INT_STAT_SF_UNCORR_ERR) { 463 statsp->sf_uncorrect_err++; 464 NXGE_FM_REPORT_ERROR(nxgep, portn, 0, 465 NXGE_FM_EREPORT_TXC_SF_UNCORRECT_ERR); 466 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 467 "nxge_txc_err_evnts: " 468 "SF FIFO uncorrectable error")); 469 } 470 if ((rs = npi_txc_sf_ecc_state_clr(handle, portn)) 471 != NPI_SUCCESS) 472 return (NXGE_ERROR | rs); 473 /* 474 * Making sure that error source is cleared if this is 475 * an injected error. 476 */ 477 TXC_FZC_CNTL_REG_WRITE64(handle, TXC_SFECC_CTL_REG, portn, 0); 478 } 479 480 /* Clear corresponding errors */ 481 switch (portn) { 482 case 0: 483 istatus.bits.ldw.port0_int_status = err_status; 484 break; 485 case 1: 486 istatus.bits.ldw.port1_int_status = err_status; 487 break; 488 case 2: 489 istatus.bits.ldw.port2_int_status = err_status; 490 break; 491 case 3: 492 istatus.bits.ldw.port3_int_status = err_status; 493 break; 494 default: 495 return (NXGE_ERROR); 496 } 497 498 npi_txc_global_istatus_clear(handle, istatus.value); 499 500 if (txport_fatal) { 501 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 502 " nxge_txc_handle_port_errors:" 503 " fatal Error on Port#%d\n", 504 portn)); 505 status = nxge_tx_port_fatal_err_recover(nxgep); 506 if (status == NXGE_OK) { 507 FM_SERVICE_RESTORED(nxgep); 508 } 509 } 510 511 return (status); 512 } 513 514 void 515 nxge_txc_inject_err(p_nxge_t nxgep, uint32_t err_id) 516 { 517 txc_int_stat_dbg_t txcs; 518 txc_roecc_ctl_t ro_ecc_ctl; 519 txc_sfecc_ctl_t sf_ecc_ctl; 520 uint8_t portn = nxgep->mac.portnum; 521 522 cmn_err(CE_NOTE, "!TXC error Inject\n"); 523 switch (err_id) { 524 case NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR: 525 case NXGE_FM_EREPORT_TXC_RO_UNCORRECT_ERR: 526 ro_ecc_ctl.value = 0; 527 ro_ecc_ctl.bits.ldw.all_pkts = 1; 528 ro_ecc_ctl.bits.ldw.second_line_pkt = 1; 529 if (err_id == NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR) 530 ro_ecc_ctl.bits.ldw.single_bit_err = 1; 531 else 532 ro_ecc_ctl.bits.ldw.double_bit_err = 1; 533 cmn_err(CE_NOTE, "!Write 0x%lx to TXC_ROECC_CTL_REG\n", 534 ro_ecc_ctl.value); 535 TXC_FZC_CNTL_REG_WRITE64(nxgep->npi_handle, TXC_ROECC_CTL_REG, 536 portn, ro_ecc_ctl.value); 537 break; 538 case NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR: 539 case NXGE_FM_EREPORT_TXC_SF_UNCORRECT_ERR: 540 sf_ecc_ctl.value = 0; 541 sf_ecc_ctl.bits.ldw.all_pkts = 1; 542 sf_ecc_ctl.bits.ldw.second_line_pkt = 1; 543 if (err_id == NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR) 544 sf_ecc_ctl.bits.ldw.single_bit_err = 1; 545 else 546 sf_ecc_ctl.bits.ldw.double_bit_err = 1; 547 cmn_err(CE_NOTE, "!Write 0x%lx to TXC_SFECC_CTL_REG\n", 548 sf_ecc_ctl.value); 549 TXC_FZC_CNTL_REG_WRITE64(nxgep->npi_handle, TXC_SFECC_CTL_REG, 550 portn, sf_ecc_ctl.value); 551 break; 552 case NXGE_FM_EREPORT_TXC_REORDER_ERR: 553 NXGE_REG_RD64(nxgep->npi_handle, TXC_INT_STAT_DBG_REG, 554 &txcs.value); 555 nxge_txc_inject_port_err(portn, &txcs, 556 TXC_INT_STAT_REORDER_ERR); 557 cmn_err(CE_NOTE, "!Write 0x%lx to TXC_INT_STAT_DBG_REG\n", 558 txcs.value); 559 NXGE_REG_WR64(nxgep->npi_handle, TXC_INT_STAT_DBG_REG, 560 txcs.value); 561 break; 562 default: 563 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 564 "nxge_txc_inject_err: Unknown err_id")); 565 } 566 } 567 568 static void 569 nxge_txc_inject_port_err(uint8_t portn, txc_int_stat_dbg_t *txcs, 570 uint8_t istats) 571 { 572 switch (portn) { 573 case 0: 574 txcs->bits.ldw.port0_int_status |= istats; 575 break; 576 case 1: 577 txcs->bits.ldw.port1_int_status |= istats; 578 break; 579 case 2: 580 txcs->bits.ldw.port2_int_status |= istats; 581 break; 582 case 3: 583 txcs->bits.ldw.port3_int_status |= istats; 584 break; 585 default: 586 ; 587 } 588 } 589