13859Sml29623 /* 23859Sml29623 * CDDL HEADER START 33859Sml29623 * 43859Sml29623 * The contents of this file are subject to the terms of the 53859Sml29623 * Common Development and Distribution License (the "License"). 63859Sml29623 * You may not use this file except in compliance with the License. 73859Sml29623 * 83859Sml29623 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93859Sml29623 * or http://www.opensolaris.org/os/licensing. 103859Sml29623 * See the License for the specific language governing permissions 113859Sml29623 * and limitations under the License. 123859Sml29623 * 133859Sml29623 * When distributing Covered Code, include this CDDL HEADER in each 143859Sml29623 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153859Sml29623 * If applicable, add the following below this CDDL HEADER, with the 163859Sml29623 * fields enclosed by brackets "[]" replaced with your own identifying 173859Sml29623 * information: Portions Copyright [yyyy] [name of copyright owner] 183859Sml29623 * 193859Sml29623 * CDDL HEADER END 203859Sml29623 */ 213859Sml29623 /* 223859Sml29623 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 233859Sml29623 * Use is subject to license terms. 243859Sml29623 */ 253859Sml29623 263859Sml29623 #pragma ident "%Z%%M% %I% %E% SMI" 273859Sml29623 283859Sml29623 #include <nxge_impl.h> 293859Sml29623 #include <nxge_ipp.h> 303859Sml29623 313859Sml29623 #define NXGE_IPP_FIFO_SYNC_TRY_COUNT 100 323859Sml29623 333859Sml29623 /* ARGSUSED */ 343859Sml29623 nxge_status_t 353859Sml29623 nxge_ipp_init(p_nxge_t nxgep) 363859Sml29623 { 373859Sml29623 uint8_t portn; 383859Sml29623 uint32_t config; 393859Sml29623 npi_handle_t handle; 403859Sml29623 uint32_t pkt_size; 413859Sml29623 ipp_status_t istatus; 423859Sml29623 npi_status_t rs = NPI_SUCCESS; 433859Sml29623 uint64_t val; 443859Sml29623 uint32_t d0, d1, d2, d3, d4; 453859Sml29623 int i; 463859Sml29623 uint32_t dfifo_entries; 473859Sml29623 483859Sml29623 handle = nxgep->npi_handle; 493859Sml29623 portn = NXGE_GET_PORT_NUM(nxgep->function_num); 503859Sml29623 513859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_init: port%d", portn)); 523859Sml29623 533859Sml29623 /* Initialize ECC and parity in SRAM of DFIFO and PFIFO */ 544732Sdavemq if (nxgep->niu_type == N2_NIU) { 554732Sdavemq dfifo_entries = IPP_NIU_DFIFO_ENTRIES; 564977Sraghus } else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) { 573859Sml29623 if (portn < 2) 583859Sml29623 dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES; 593859Sml29623 else 603859Sml29623 dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES; 614732Sdavemq } else { 623859Sml29623 goto fail; 634732Sdavemq } 643859Sml29623 653859Sml29623 for (i = 0; i < dfifo_entries; i++) { 663859Sml29623 if ((rs = npi_ipp_write_dfifo(handle, 673859Sml29623 portn, i, 0, 0, 0, 0, 0)) != NPI_SUCCESS) 683859Sml29623 goto fail; 693859Sml29623 if ((rs = npi_ipp_read_dfifo(handle, portn, 703859Sml29623 i, &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS) 713859Sml29623 goto fail; 723859Sml29623 } 733859Sml29623 743859Sml29623 /* Clear PFIFO DFIFO status bits */ 753859Sml29623 if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS) 763859Sml29623 goto fail; 773859Sml29623 if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS) 783859Sml29623 goto fail; 793859Sml29623 803859Sml29623 /* 813859Sml29623 * Soft reset to make sure we bring the FIFO pointers back to the 823859Sml29623 * original initial position. 833859Sml29623 */ 843859Sml29623 if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS) 853859Sml29623 goto fail; 863859Sml29623 873859Sml29623 /* Clean up ECC counter */ 883859Sml29623 IPP_REG_RD(nxgep->npi_handle, portn, IPP_ECC_ERR_COUNTER_REG, &val); 89*5523Syc148097 IPP_REG_RD(nxgep->npi_handle, portn, IPP_BAD_CKSUM_ERR_CNT_REG, &val); 903859Sml29623 IPP_REG_RD(nxgep->npi_handle, portn, IPP_DISCARD_PKT_CNT_REG, &val); 913859Sml29623 923859Sml29623 if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS) 933859Sml29623 goto fail; 943859Sml29623 953859Sml29623 /* Configure IPP port */ 963859Sml29623 if ((rs = npi_ipp_iconfig(handle, INIT, portn, ICFG_IPP_ALL)) 973859Sml29623 != NPI_SUCCESS) 983859Sml29623 goto fail; 993859Sml29623 nxgep->ipp.iconfig = ICFG_IPP_ALL; 1003859Sml29623 1013859Sml29623 config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC | 1023859Sml29623 CFG_IPP_TCP_UDP_CKSUM; 1033859Sml29623 if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS) 1043859Sml29623 goto fail; 1053859Sml29623 nxgep->ipp.config = config; 1063859Sml29623 1073859Sml29623 /* Set max packet size */ 1083859Sml29623 pkt_size = IPP_MAX_PKT_SIZE; 1093859Sml29623 if ((rs = npi_ipp_set_max_pktsize(handle, portn, 1103859Sml29623 IPP_MAX_PKT_SIZE)) != NPI_SUCCESS) 1113859Sml29623 goto fail; 1123859Sml29623 nxgep->ipp.max_pkt_size = pkt_size; 1133859Sml29623 1143859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_init: port%d", portn)); 1153859Sml29623 1163859Sml29623 return (NXGE_OK); 1173859Sml29623 fail: 1183859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 1193859Sml29623 "nxge_ipp_init: Fail to initialize IPP Port #%d\n", 1203859Sml29623 portn)); 1213859Sml29623 return (NXGE_ERROR | rs); 1223859Sml29623 } 1233859Sml29623 1243859Sml29623 /* ARGSUSED */ 1253859Sml29623 nxge_status_t 1263859Sml29623 nxge_ipp_disable(p_nxge_t nxgep) 1273859Sml29623 { 1283859Sml29623 uint8_t portn; 1293859Sml29623 uint32_t config; 1303859Sml29623 npi_handle_t handle; 1313859Sml29623 npi_status_t rs = NPI_SUCCESS; 1323859Sml29623 uint16_t wr_ptr, rd_ptr; 1333859Sml29623 uint32_t try_count; 1343859Sml29623 1353859Sml29623 handle = nxgep->npi_handle; 1363859Sml29623 portn = NXGE_GET_PORT_NUM(nxgep->function_num); 1373859Sml29623 1383859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_disable: port%d", portn)); 1393859Sml29623 (void) nxge_rx_mac_disable(nxgep); 1403859Sml29623 1413859Sml29623 /* 1423859Sml29623 * Wait until ip read and write fifo pointers are equal 1433859Sml29623 */ 1443859Sml29623 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr); 1453859Sml29623 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr); 1463859Sml29623 try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT; 1473859Sml29623 1483859Sml29623 while ((try_count > 0) && (rd_ptr != wr_ptr)) { 1493859Sml29623 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr); 1503859Sml29623 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr); 1513859Sml29623 try_count--; 1523859Sml29623 } 1533859Sml29623 1543859Sml29623 if (try_count == 0) { 1553859Sml29623 if ((rd_ptr != 0) && (wr_ptr != 1)) { 1563859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 1573859Sml29623 " nxge_ipp_disable: port%d failed" 1583859Sml29623 " rd_fifo != wr_fifo", portn)); 1593859Sml29623 goto fail; 1603859Sml29623 } 1613859Sml29623 } 1623859Sml29623 /* disable the IPP */ 1633859Sml29623 config = nxgep->ipp.config; 1643859Sml29623 if ((rs = npi_ipp_config(handle, DISABLE, 1653859Sml29623 portn, config)) != NPI_SUCCESS) 1663859Sml29623 goto fail; 1673859Sml29623 1683859Sml29623 /* IPP soft reset */ 1693859Sml29623 if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS) 1703859Sml29623 goto fail; 1713859Sml29623 1723859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_disable: port%d", portn)); 1733859Sml29623 return (NXGE_OK); 1743859Sml29623 fail: 1753859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 1763859Sml29623 "nxge_ipp_disable: Fail to disable IPP Port #%d\n", portn)); 1773859Sml29623 return (NXGE_ERROR | rs); 1783859Sml29623 } 1793859Sml29623 1803859Sml29623 /* ARGSUSED */ 1813859Sml29623 nxge_status_t 1823859Sml29623 nxge_ipp_reset(p_nxge_t nxgep) 1833859Sml29623 { 1843859Sml29623 uint8_t portn; 1853859Sml29623 uint32_t config; 1863859Sml29623 npi_handle_t handle; 1873859Sml29623 npi_status_t rs = NPI_SUCCESS; 1883859Sml29623 uint16_t wr_ptr, rd_ptr; 1893859Sml29623 uint32_t try_count; 1903859Sml29623 1913859Sml29623 handle = nxgep->npi_handle; 1923859Sml29623 portn = NXGE_GET_PORT_NUM(nxgep->function_num); 1933859Sml29623 1943859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_reset: port%d", portn)); 1953859Sml29623 1963859Sml29623 /* disable the IPP */ 1973859Sml29623 config = nxgep->ipp.config; 1983859Sml29623 if ((rs = npi_ipp_config(handle, DISABLE, 1993859Sml29623 portn, config)) != NPI_SUCCESS) 2003859Sml29623 goto fail; 2013859Sml29623 2023859Sml29623 /* 2033859Sml29623 * Wait until ip read and write fifo pointers are equal 2043859Sml29623 */ 2053859Sml29623 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr); 2063859Sml29623 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr); 2073859Sml29623 try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT; 2083859Sml29623 2093859Sml29623 while ((try_count > 0) && (rd_ptr != wr_ptr)) { 2103859Sml29623 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr); 2113859Sml29623 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr); 2123859Sml29623 try_count--; 2133859Sml29623 } 2143859Sml29623 2153859Sml29623 if (try_count == 0) { 2163859Sml29623 if ((rd_ptr != 0) && (wr_ptr != 1)) { 2173859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 2183859Sml29623 " nxge_ipp_disable: port%d failed" 2193859Sml29623 " rd_fifo != wr_fifo", portn)); 2203859Sml29623 goto fail; 2213859Sml29623 } 2223859Sml29623 } 2233859Sml29623 2243859Sml29623 /* IPP soft reset */ 2253859Sml29623 if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS) { 2263859Sml29623 goto fail; 2273859Sml29623 } 2283859Sml29623 2293859Sml29623 /* to reset control FIFO */ 2303859Sml29623 if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS) 2313859Sml29623 goto fail; 2323859Sml29623 2333859Sml29623 /* 2343859Sml29623 * Making sure that error source is cleared if this is an injected 2353859Sml29623 * error. 2363859Sml29623 */ 2373859Sml29623 IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0); 2383859Sml29623 2393859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_reset: port%d", portn)); 2403859Sml29623 return (NXGE_OK); 2413859Sml29623 fail: 2423859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 2433859Sml29623 "nxge_ipp_init: Fail to Reset IPP Port #%d\n", 2443859Sml29623 portn)); 2453859Sml29623 return (NXGE_ERROR | rs); 2463859Sml29623 } 2473859Sml29623 2483859Sml29623 /* ARGSUSED */ 2493859Sml29623 nxge_status_t 2503859Sml29623 nxge_ipp_enable(p_nxge_t nxgep) 2513859Sml29623 { 2523859Sml29623 uint8_t portn; 2533859Sml29623 uint32_t config; 2543859Sml29623 npi_handle_t handle; 2553859Sml29623 uint32_t pkt_size; 2563859Sml29623 npi_status_t rs = NPI_SUCCESS; 2573859Sml29623 2583859Sml29623 handle = nxgep->npi_handle; 2593859Sml29623 portn = NXGE_GET_PORT_NUM(nxgep->function_num); 2603859Sml29623 2613859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_enable: port%d", portn)); 2623859Sml29623 2633859Sml29623 config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC | 2643859Sml29623 CFG_IPP_TCP_UDP_CKSUM; 2653859Sml29623 if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS) 2663859Sml29623 goto fail; 2673859Sml29623 nxgep->ipp.config = config; 2683859Sml29623 2693859Sml29623 /* Set max packet size */ 2703859Sml29623 pkt_size = IPP_MAX_PKT_SIZE; 2713859Sml29623 if ((rs = npi_ipp_set_max_pktsize(handle, portn, 2723859Sml29623 IPP_MAX_PKT_SIZE)) != NPI_SUCCESS) 2733859Sml29623 goto fail; 2743859Sml29623 nxgep->ipp.max_pkt_size = pkt_size; 2753859Sml29623 2763859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_enable: port%d", portn)); 2773859Sml29623 return (NXGE_OK); 2783859Sml29623 fail: 2793859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 2803859Sml29623 "nxge_ipp_init: Fail to Enable IPP Port #%d\n", portn)); 2813859Sml29623 return (NXGE_ERROR | rs); 2823859Sml29623 } 2833859Sml29623 2843859Sml29623 /* ARGSUSED */ 2853859Sml29623 nxge_status_t 2863859Sml29623 nxge_ipp_handle_sys_errors(p_nxge_t nxgep) 2873859Sml29623 { 2883859Sml29623 npi_handle_t handle; 2893859Sml29623 npi_status_t rs = NPI_SUCCESS; 2903859Sml29623 p_nxge_ipp_stats_t statsp; 2913859Sml29623 ipp_status_t istatus; 2923859Sml29623 uint8_t portn; 2933859Sml29623 p_ipp_errlog_t errlogp; 2943859Sml29623 boolean_t rxport_fatal = B_FALSE; 2953859Sml29623 nxge_status_t status = NXGE_OK; 2965165Syc148097 uint8_t cnt8; 2975165Syc148097 uint16_t cnt16; 2983859Sml29623 2993859Sml29623 handle = nxgep->npi_handle; 3003859Sml29623 statsp = (p_nxge_ipp_stats_t)&nxgep->statsp->ipp_stats; 3013859Sml29623 portn = nxgep->mac.portnum; 3023859Sml29623 3033859Sml29623 errlogp = (p_ipp_errlog_t)&statsp->errlog; 3043859Sml29623 3053859Sml29623 if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS) 3063859Sml29623 return (NXGE_ERROR | rs); 3073859Sml29623 3083859Sml29623 if (istatus.value == 0) { 3093859Sml29623 /* 3103859Sml29623 * The error is not initiated from this port, so just exit. 3113859Sml29623 */ 3123859Sml29623 return (NXGE_OK); 3133859Sml29623 } 3143859Sml29623 3153859Sml29623 if (istatus.bits.w0.dfifo_missed_sop) { 3163859Sml29623 statsp->sop_miss++; 3173859Sml29623 if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn, 3183859Sml29623 &errlogp->dfifo_rd_ptr)) != NPI_SUCCESS) 3193859Sml29623 return (NXGE_ERROR | rs); 3203859Sml29623 if ((rs = npi_ipp_get_state_mach(handle, portn, 3213859Sml29623 &errlogp->state_mach)) != NPI_SUCCESS) 3223859Sml29623 return (NXGE_ERROR | rs); 3233859Sml29623 NXGE_FM_REPORT_ERROR(nxgep, portn, NULL, 3243859Sml29623 NXGE_FM_EREPORT_IPP_SOP_MISS); 3253859Sml29623 if (statsp->sop_miss < IPP_MAX_ERR_SHOW) 3263859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3273859Sml29623 "nxge_ipp_err_evnts: fatal error: sop_miss\n")); 3283859Sml29623 rxport_fatal = B_TRUE; 3293859Sml29623 } 3303859Sml29623 if (istatus.bits.w0.dfifo_missed_eop) { 3313859Sml29623 statsp->eop_miss++; 3323859Sml29623 if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn, 3333859Sml29623 &errlogp->dfifo_rd_ptr)) != NPI_SUCCESS) 3343859Sml29623 return (NXGE_ERROR | rs); 3353859Sml29623 if ((rs = npi_ipp_get_state_mach(handle, portn, 3363859Sml29623 &errlogp->state_mach)) != NPI_SUCCESS) 3373859Sml29623 return (NXGE_ERROR | rs); 3383859Sml29623 NXGE_FM_REPORT_ERROR(nxgep, portn, NULL, 3393859Sml29623 NXGE_FM_EREPORT_IPP_EOP_MISS); 3403859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3413859Sml29623 "nxge_ipp_err_evnts: fatal error: eop_miss\n")); 3423859Sml29623 rxport_fatal = B_TRUE; 3433859Sml29623 } 3443859Sml29623 if (istatus.bits.w0.dfifo_uncorr_ecc_err) { 3453859Sml29623 boolean_t ue_ecc_valid; 3463859Sml29623 3473859Sml29623 if ((status = nxge_ipp_eccue_valid_check(nxgep, 3483859Sml29623 &ue_ecc_valid)) != NXGE_OK) 3493859Sml29623 return (status); 3503859Sml29623 3513859Sml29623 if (ue_ecc_valid) { 3523859Sml29623 statsp->dfifo_ue++; 3533859Sml29623 if ((rs = npi_ipp_get_ecc_syndrome(handle, portn, 3543859Sml29623 &errlogp->ecc_syndrome)) != NPI_SUCCESS) 3553859Sml29623 return (NXGE_ERROR | rs); 3563859Sml29623 NXGE_FM_REPORT_ERROR(nxgep, portn, NULL, 3573859Sml29623 NXGE_FM_EREPORT_IPP_DFIFO_UE); 3583859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3593859Sml29623 "nxge_ipp_err_evnts: fatal error: dfifo_ue\n")); 3603859Sml29623 rxport_fatal = B_TRUE; 3613859Sml29623 } 3623859Sml29623 } 3633859Sml29623 if (istatus.bits.w0.pre_fifo_perr) { 3643859Sml29623 statsp->pfifo_perr++; 3653859Sml29623 NXGE_FM_REPORT_ERROR(nxgep, portn, NULL, 3663859Sml29623 NXGE_FM_EREPORT_IPP_PFIFO_PERR); 3673859Sml29623 if (statsp->pfifo_perr < IPP_MAX_ERR_SHOW) 3683859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3693859Sml29623 "nxge_ipp_err_evnts: " 3703859Sml29623 "fatal error: pre_pifo_perr\n")); 3713859Sml29623 rxport_fatal = B_TRUE; 3723859Sml29623 } 3733859Sml29623 if (istatus.bits.w0.pre_fifo_overrun) { 3743859Sml29623 statsp->pfifo_over++; 3753859Sml29623 NXGE_FM_REPORT_ERROR(nxgep, portn, NULL, 3763859Sml29623 NXGE_FM_EREPORT_IPP_PFIFO_OVER); 3773859Sml29623 if (statsp->pfifo_over < IPP_MAX_ERR_SHOW) 3783859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3793859Sml29623 "nxge_ipp_err_evnts: " 3803859Sml29623 "fatal error: pfifo_over\n")); 3813859Sml29623 rxport_fatal = B_TRUE; 3823859Sml29623 } 3833859Sml29623 if (istatus.bits.w0.pre_fifo_underrun) { 3843859Sml29623 statsp->pfifo_und++; 3853859Sml29623 NXGE_FM_REPORT_ERROR(nxgep, portn, NULL, 3863859Sml29623 NXGE_FM_EREPORT_IPP_PFIFO_UND); 3873859Sml29623 if (statsp->pfifo_und < IPP_MAX_ERR_SHOW) 3883859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3893859Sml29623 "nxge_ipp_err_evnts: " 3903859Sml29623 "fatal error: pfifo_und\n")); 3913859Sml29623 rxport_fatal = B_TRUE; 3923859Sml29623 } 3933859Sml29623 if (istatus.bits.w0.bad_cksum_cnt_ovfl) { 3945222Syc148097 /* 3955222Syc148097 * Clear bit BAD_CS_MX of register IPP_INT_STAT 3965222Syc148097 * by reading register IPP_BAD_CS_CNT 3975222Syc148097 */ 3985165Syc148097 (void) npi_ipp_get_cs_err_count(handle, portn, &cnt16); 3993859Sml29623 statsp->bad_cs_cnt += IPP_BAD_CS_CNT_MASK; 400*5523Syc148097 /* 401*5523Syc148097 * Do not send FMA ereport because this error does not 402*5523Syc148097 * indicate a HW failure 403*5523Syc148097 */ 4043859Sml29623 if (statsp->bad_cs_cnt < (IPP_MAX_ERR_SHOW * 4053859Sml29623 IPP_BAD_CS_CNT_MASK)) 4063859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 4073859Sml29623 "nxge_ipp_err_evnts: bad_cs_max\n")); 4083859Sml29623 } 4093859Sml29623 if (istatus.bits.w0.pkt_discard_cnt_ovfl) { 4105222Syc148097 /* 4115222Syc148097 * Clear bit PKT_DIS_MX of register IPP_INT_STAT 4125222Syc148097 * by reading register IPP_PKT_DIS 4135222Syc148097 */ 4145165Syc148097 (void) npi_ipp_get_pkt_dis_count(handle, portn, &cnt16); 4153859Sml29623 statsp->pkt_dis_cnt += IPP_PKT_DIS_CNT_MASK; 416*5523Syc148097 /* 417*5523Syc148097 * Do not send FMA ereport because this error does not 418*5523Syc148097 * indicate a HW failure 419*5523Syc148097 */ 4203859Sml29623 if (statsp->pkt_dis_cnt < (IPP_MAX_ERR_SHOW * 4213859Sml29623 IPP_PKT_DIS_CNT_MASK)) 4223859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 4233859Sml29623 "nxge_ipp_err_evnts: pkt_dis_max\n")); 4243859Sml29623 } 4255165Syc148097 if (istatus.bits.w0.ecc_err_cnt_ovfl) { 4265222Syc148097 /* 4275222Syc148097 * Clear bit ECC_ERR_MAX of register IPP_INI_STAT 4285222Syc148097 * by reading register IPP_ECC 4295222Syc148097 */ 4305165Syc148097 (void) npi_ipp_get_ecc_err_count(handle, portn, &cnt8); 4315165Syc148097 statsp->ecc_err_cnt += IPP_ECC_CNT_MASK; 432*5523Syc148097 /* 433*5523Syc148097 * A defect in Neptune port2's IPP module could generate 434*5523Syc148097 * many fake but harmless ECC errors under stress and cause 435*5523Syc148097 * the ecc-error-counter register IPP_ECC to reach its 436*5523Syc148097 * maximum value in a few seconds. To avoid false alarm, do 437*5523Syc148097 * not report the error if it is port2. 438*5523Syc148097 */ 439*5523Syc148097 if (portn != 2) { 440*5523Syc148097 NXGE_FM_REPORT_ERROR(nxgep, portn, NULL, 441*5523Syc148097 NXGE_FM_EREPORT_IPP_ECC_ERR_MAX); 442*5523Syc148097 if (statsp->ecc_err_cnt < (IPP_MAX_ERR_SHOW * 443*5523Syc148097 IPP_ECC_CNT_MASK)) { 444*5523Syc148097 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 445*5523Syc148097 "nxge_ipp_err_evnts: pkt_ecc_err_max\n")); 446*5523Syc148097 } 447*5523Syc148097 } 4485165Syc148097 } 4493859Sml29623 /* 4503859Sml29623 * Making sure that error source is cleared if this is an injected 4513859Sml29623 * error. 4523859Sml29623 */ 4533859Sml29623 IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0); 4543859Sml29623 4553859Sml29623 if (rxport_fatal) { 4563859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, 4573859Sml29623 " nxge_ipp_handle_sys_errors:" 4583859Sml29623 " fatal Error on Port #%d\n", portn)); 4593859Sml29623 status = nxge_ipp_fatal_err_recover(nxgep); 4603859Sml29623 if (status == NXGE_OK) { 4613859Sml29623 FM_SERVICE_RESTORED(nxgep); 4623859Sml29623 } 4633859Sml29623 } 4643859Sml29623 return (status); 4653859Sml29623 } 4663859Sml29623 4673859Sml29623 /* ARGSUSED */ 4683859Sml29623 void 4693859Sml29623 nxge_ipp_inject_err(p_nxge_t nxgep, uint32_t err_id) 4703859Sml29623 { 4713859Sml29623 ipp_status_t ipps; 4723859Sml29623 ipp_ecc_ctrl_t ecc_ctrl; 4733859Sml29623 uint8_t portn = nxgep->mac.portnum; 4743859Sml29623 4753859Sml29623 switch (err_id) { 4763859Sml29623 case NXGE_FM_EREPORT_IPP_DFIFO_UE: 4773859Sml29623 ecc_ctrl.value = 0; 4783859Sml29623 ecc_ctrl.bits.w0.cor_dbl = 1; 4793859Sml29623 ecc_ctrl.bits.w0.cor_1 = 1; 4803859Sml29623 ecc_ctrl.bits.w0.cor_lst = 1; 4813859Sml29623 cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n", 4823859Sml29623 (unsigned long long) ecc_ctrl.value); 4833859Sml29623 IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG, 4843859Sml29623 ecc_ctrl.value); 4853859Sml29623 break; 4863859Sml29623 4873859Sml29623 case NXGE_FM_EREPORT_IPP_DFIFO_CE: 4883859Sml29623 ecc_ctrl.value = 0; 4893859Sml29623 ecc_ctrl.bits.w0.cor_sng = 1; 4903859Sml29623 ecc_ctrl.bits.w0.cor_1 = 1; 4913859Sml29623 ecc_ctrl.bits.w0.cor_snd = 1; 4923859Sml29623 cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n", 4933859Sml29623 (unsigned long long) ecc_ctrl.value); 4943859Sml29623 IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG, 4953859Sml29623 ecc_ctrl.value); 4963859Sml29623 break; 4973859Sml29623 4983859Sml29623 case NXGE_FM_EREPORT_IPP_EOP_MISS: 4993859Sml29623 case NXGE_FM_EREPORT_IPP_SOP_MISS: 5003859Sml29623 case NXGE_FM_EREPORT_IPP_PFIFO_PERR: 5013859Sml29623 case NXGE_FM_EREPORT_IPP_ECC_ERR_MAX: 5023859Sml29623 case NXGE_FM_EREPORT_IPP_PFIFO_OVER: 5033859Sml29623 case NXGE_FM_EREPORT_IPP_PFIFO_UND: 5043859Sml29623 case NXGE_FM_EREPORT_IPP_BAD_CS_MX: 5053859Sml29623 case NXGE_FM_EREPORT_IPP_PKT_DIS_MX: 5063859Sml29623 case NXGE_FM_EREPORT_IPP_RESET_FAIL: 5073859Sml29623 IPP_REG_RD(nxgep->npi_handle, portn, IPP_INT_STATUS_REG, 5083859Sml29623 &ipps.value); 5093859Sml29623 if (err_id == NXGE_FM_EREPORT_IPP_EOP_MISS) 5103859Sml29623 ipps.bits.w0.dfifo_missed_eop = 1; 5113859Sml29623 else if (err_id == NXGE_FM_EREPORT_IPP_SOP_MISS) 5123859Sml29623 ipps.bits.w0.dfifo_missed_sop = 1; 5133859Sml29623 else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_UE) 5143859Sml29623 ipps.bits.w0.dfifo_uncorr_ecc_err = 1; 5153859Sml29623 else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_CE) 5163859Sml29623 ipps.bits.w0.dfifo_corr_ecc_err = 1; 5173859Sml29623 else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_PERR) 5183859Sml29623 ipps.bits.w0.pre_fifo_perr = 1; 5195222Syc148097 else if (err_id == NXGE_FM_EREPORT_IPP_ECC_ERR_MAX) { 5205222Syc148097 /* 5215222Syc148097 * Fill register IPP_ECC with max ECC-error- 5225222Syc148097 * counter value (0xff) to set the ECC_ERR_MAX bit 5235222Syc148097 * of the IPP_INT_STAT register and trigger an 5245222Syc148097 * FMA ereport. 5255222Syc148097 */ 5265222Syc148097 IPP_REG_WR(nxgep->npi_handle, portn, 5275222Syc148097 IPP_ECC_ERR_COUNTER_REG, IPP_ECC_CNT_MASK); 5285222Syc148097 } else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_OVER) 5293859Sml29623 ipps.bits.w0.pre_fifo_overrun = 1; 5303859Sml29623 else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_UND) 5313859Sml29623 ipps.bits.w0.pre_fifo_underrun = 1; 5325222Syc148097 else if (err_id == NXGE_FM_EREPORT_IPP_BAD_CS_MX) { 5335222Syc148097 /* 5345222Syc148097 * Fill IPP_BAD_CS_CNT with max bad-checksum-counter 5355222Syc148097 * value (0x3fff) to set the BAD_CS_MX bit of 5365222Syc148097 * IPP_INT_STAT and trigger an FMA ereport. 5375222Syc148097 */ 5385222Syc148097 IPP_REG_WR(nxgep->npi_handle, portn, 539*5523Syc148097 IPP_BAD_CKSUM_ERR_CNT_REG, IPP_BAD_CS_CNT_MASK); 5405222Syc148097 } else if (err_id == NXGE_FM_EREPORT_IPP_PKT_DIS_MX) { 5415222Syc148097 /* 5425222Syc148097 * Fill IPP_PKT_DIS with max packet-discard-counter 5435222Syc148097 * value (0x3fff) to set the PKT_DIS_MX bit of 5445222Syc148097 * IPP_INT_STAT and trigger an FMA ereport. 5455222Syc148097 */ 5465222Syc148097 IPP_REG_WR(nxgep->npi_handle, portn, 5475222Syc148097 IPP_DISCARD_PKT_CNT_REG, IPP_PKT_DIS_CNT_MASK); 5485222Syc148097 } 5493859Sml29623 cmn_err(CE_NOTE, "!Write 0x%llx to IPP_INT_STATUS_REG\n", 5503859Sml29623 (unsigned long long) ipps.value); 5513859Sml29623 IPP_REG_WR(nxgep->npi_handle, portn, IPP_INT_STATUS_REG, 5523859Sml29623 ipps.value); 5533859Sml29623 break; 5543859Sml29623 } 5553859Sml29623 } 5563859Sml29623 5573859Sml29623 /* ARGSUSED */ 5583859Sml29623 nxge_status_t 5593859Sml29623 nxge_ipp_fatal_err_recover(p_nxge_t nxgep) 5603859Sml29623 { 5613859Sml29623 npi_handle_t handle; 5623859Sml29623 npi_status_t rs = NPI_SUCCESS; 5633859Sml29623 nxge_status_t status = NXGE_OK; 5643859Sml29623 uint8_t portn; 5653859Sml29623 uint16_t wr_ptr; 5663859Sml29623 uint16_t rd_ptr; 5673859Sml29623 uint32_t try_count; 5683859Sml29623 uint32_t dfifo_entries; 5693859Sml29623 ipp_status_t istatus; 5703859Sml29623 uint32_t d0, d1, d2, d3, d4; 5713859Sml29623 int i; 5723859Sml29623 5733859Sml29623 NXGE_DEBUG_MSG((nxgep, RX_CTL, "<== nxge_ipp_fatal_err_recover")); 5743859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 5753859Sml29623 "Recovering from RxPort error...")); 5763859Sml29623 5773859Sml29623 handle = nxgep->npi_handle; 5783859Sml29623 portn = nxgep->mac.portnum; 5793859Sml29623 5803859Sml29623 /* 5813859Sml29623 * Making sure that error source is cleared if this is an injected 5823859Sml29623 * error. 5833859Sml29623 */ 5843859Sml29623 IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0); 5853859Sml29623 5863859Sml29623 /* Disable RxMAC */ 5873859Sml29623 if (nxge_rx_mac_disable(nxgep) != NXGE_OK) 5883859Sml29623 goto fail; 5893859Sml29623 5903859Sml29623 /* When recovering from IPP, RxDMA channel resets are not necessary */ 5913859Sml29623 /* Reset ZCP CFIFO */ 5923859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset ZCP CFIFO...", portn)); 5933859Sml29623 if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS) 5943859Sml29623 goto fail; 5953859Sml29623 5963859Sml29623 /* 5973859Sml29623 * Wait until ip read and write fifo pointers are equal 5983859Sml29623 */ 5993859Sml29623 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr); 6003859Sml29623 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr); 6013859Sml29623 try_count = 512; 6023859Sml29623 6033859Sml29623 while ((try_count > 0) && (rd_ptr != wr_ptr)) { 6043859Sml29623 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr); 6053859Sml29623 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr); 6063859Sml29623 try_count--; 6073859Sml29623 } 6083859Sml29623 6093859Sml29623 if (try_count == 0) { 6103859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 6113859Sml29623 " nxge_ipp_reset: port%d IPP stalled..." 6123859Sml29623 " rd_fifo_ptr = 0x%x wr_fifo_ptr = 0x%x", 6133859Sml29623 portn, rd_ptr, wr_ptr)); 6143859Sml29623 /* 6153859Sml29623 * This means the fatal error occurred on the first line of the 6163859Sml29623 * fifo. In this case, just reset the IPP without draining the 6173859Sml29623 * PFIFO. 6183859Sml29623 */ 6193859Sml29623 } 6203859Sml29623 6214732Sdavemq if (nxgep->niu_type == N2_NIU) { 6224732Sdavemq dfifo_entries = IPP_NIU_DFIFO_ENTRIES; 6234977Sraghus } else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) { 6243859Sml29623 if (portn < 2) 6253859Sml29623 dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES; 6263859Sml29623 else 6273859Sml29623 dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES; 6284732Sdavemq } else { 6293859Sml29623 goto fail; 6304732Sdavemq } 6313859Sml29623 6323859Sml29623 /* Clean up DFIFO SRAM entries */ 6333859Sml29623 for (i = 0; i < dfifo_entries; i++) { 6343859Sml29623 if ((rs = npi_ipp_write_dfifo(handle, portn, 6353859Sml29623 i, 0, 0, 0, 0, 0)) != NPI_SUCCESS) 6363859Sml29623 goto fail; 6373859Sml29623 if ((rs = npi_ipp_read_dfifo(handle, portn, i, 6383859Sml29623 &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS) 6393859Sml29623 goto fail; 6403859Sml29623 } 6413859Sml29623 6423859Sml29623 /* Clear PFIFO DFIFO status bits */ 6433859Sml29623 if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS) 6443859Sml29623 goto fail; 6453859Sml29623 if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS) 6463859Sml29623 goto fail; 6473859Sml29623 6483859Sml29623 /* Reset IPP */ 6493859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset IPP...", portn)); 6503859Sml29623 if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS) 6513859Sml29623 goto fail; 6523859Sml29623 6533859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset RxMAC...", portn)); 6543859Sml29623 if (nxge_rx_mac_reset(nxgep) != NXGE_OK) 6553859Sml29623 goto fail; 6563859Sml29623 6573859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Initialize RxMAC...", portn)); 6583859Sml29623 if ((status = nxge_rx_mac_init(nxgep)) != NXGE_OK) 6593859Sml29623 goto fail; 6603859Sml29623 6613859Sml29623 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Enable RxMAC...", portn)); 6623859Sml29623 if (nxge_rx_mac_enable(nxgep) != NXGE_OK) 6633859Sml29623 goto fail; 6643859Sml29623 6653859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 6665222Syc148097 "Recovery successful, RxPort restored")); 6673859Sml29623 NXGE_DEBUG_MSG((nxgep, RX_CTL, "==> nxge_ipp_fatal_err_recover")); 6683859Sml29623 6693859Sml29623 return (NXGE_OK); 6703859Sml29623 fail: 6713859Sml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed")); 6723859Sml29623 return (status | rs); 6733859Sml29623 } 6743859Sml29623 6753859Sml29623 /* ARGSUSED */ 6764638Syc148097 /* 6775165Syc148097 * A hardware bug may cause fake ECCUEs (ECC Uncorrectable Error). 6784638Syc148097 * This function checks if a ECCUE is real(valid) or not. It is not 6794638Syc148097 * real if rd_ptr == wr_ptr. 6804638Syc148097 * The hardware module that has the bug is used not only by the IPP 6814638Syc148097 * FIFO but also by the ZCP FIFO, therefore this function is also 6824638Syc148097 * called by nxge_zcp_handle_sys_errors for validating the ZCP FIFO 6834638Syc148097 * error. 6844638Syc148097 */ 6853859Sml29623 nxge_status_t 6863859Sml29623 nxge_ipp_eccue_valid_check(p_nxge_t nxgep, boolean_t *valid) 6873859Sml29623 { 6883859Sml29623 npi_handle_t handle; 6893859Sml29623 npi_status_t rs = NPI_SUCCESS; 6903859Sml29623 uint8_t portn; 6913859Sml29623 uint16_t rd_ptr; 6923859Sml29623 uint16_t wr_ptr; 6933859Sml29623 uint16_t curr_rd_ptr; 6943859Sml29623 uint16_t curr_wr_ptr; 6953859Sml29623 uint32_t stall_cnt; 6963859Sml29623 uint32_t d0, d1, d2, d3, d4; 6973859Sml29623 6983859Sml29623 handle = nxgep->npi_handle; 6993859Sml29623 portn = nxgep->mac.portnum; 7003859Sml29623 *valid = B_TRUE; 7013859Sml29623 7023859Sml29623 if ((rs = npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr)) 7033859Sml29623 != NPI_SUCCESS) 7043859Sml29623 goto fail; 7054638Syc148097 if ((rs = npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr)) 7063859Sml29623 != NPI_SUCCESS) 7073859Sml29623 goto fail; 7083859Sml29623 7093859Sml29623 if (rd_ptr == wr_ptr) { 7104638Syc148097 *valid = B_FALSE; /* FIFO not stuck, so it's not a real ECCUE */ 7113859Sml29623 } else { 7123859Sml29623 stall_cnt = 0; 7135060Syc148097 /* 7145060Syc148097 * Check if the two pointers are moving, the ECCUE is invali 7155060Syc148097 * if either pointer is moving, which indicates that the FIFO 7165060Syc148097 * is functional. 7175060Syc148097 */ 7183859Sml29623 while (stall_cnt < 16) { 7193859Sml29623 if ((rs = npi_ipp_get_dfifo_rd_ptr(handle, 7203859Sml29623 portn, &curr_rd_ptr)) != NPI_SUCCESS) 7213859Sml29623 goto fail; 7223859Sml29623 if ((rs = npi_ipp_get_dfifo_wr_ptr(handle, 7233859Sml29623 portn, &curr_wr_ptr)) != NPI_SUCCESS) 7243859Sml29623 goto fail; 7253859Sml29623 7265060Syc148097 if (rd_ptr == curr_rd_ptr && wr_ptr == curr_wr_ptr) { 7273859Sml29623 stall_cnt++; 7285060Syc148097 } else { 7293859Sml29623 *valid = B_FALSE; 7303859Sml29623 break; 7313859Sml29623 } 7323859Sml29623 } 7333859Sml29623 7343859Sml29623 if (valid) { 7355060Syc148097 /* 7365222Syc148097 * Further check to see if the ECCUE is valid. The 7375060Syc148097 * error is real if the LSB of d4 is 1, which 7385060Syc148097 * indicates that the data that has set the ECC 7395060Syc148097 * error flag is the 16-byte internal control word. 7405060Syc148097 */ 7415060Syc148097 if ((rs = npi_ipp_read_dfifo(handle, portn, rd_ptr, 7425060Syc148097 &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS) 7433859Sml29623 goto fail; 7443859Sml29623 if ((d4 & 0x1) == 0) /* Not the 1st line */ 7453859Sml29623 *valid = B_FALSE; 7463859Sml29623 } 7473859Sml29623 } 7483859Sml29623 return (NXGE_OK); 7493859Sml29623 fail: 7503859Sml29623 return (NXGE_ERROR | rs); 7513859Sml29623 } 752