/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <nxge_impl.h>
#include <nxge_ipp.h>
/* ARGSUSED */
{
int i;
/* Initialize ECC and parity in SRAM of DFIFO and PFIFO */
} else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
if (portn < 2)
else
} else {
goto fail;
}
for (i = 0; i < dfifo_entries; i++) {
portn, i, 0, 0, 0, 0, 0)) != NPI_SUCCESS)
goto fail;
goto fail;
}
/* Clear PFIFO DFIFO status bits */
goto fail;
goto fail;
/*
* Soft reset to make sure we bring the FIFO pointers back to the
* original initial position.
*/
goto fail;
/* Clean up ECC counter */
goto fail;
/* Configure IPP port */
!= NPI_SUCCESS)
goto fail;
goto fail;
/* Set max packet size */
IPP_MAX_PKT_SIZE)) != NPI_SUCCESS)
goto fail;
return (NXGE_OK);
fail:
"nxge_ipp_init: Fail to initialize IPP Port #%d\n",
portn));
return (NXGE_ERROR | rs);
}
/* ARGSUSED */
{
(void) nxge_rx_mac_disable(nxgep);
/*
* Wait until ip read and write fifo pointers are equal
*/
try_count--;
}
if (try_count == 0) {
" nxge_ipp_disable: port%d failed"
" rd_fifo != wr_fifo", portn));
goto fail;
}
}
/* disable the IPP */
goto fail;
/* IPP soft reset */
goto fail;
return (NXGE_OK);
fail:
"nxge_ipp_disable: Fail to disable IPP Port #%d\n", portn));
return (NXGE_ERROR | rs);
}
/* ARGSUSED */
{
/* disable the IPP */
goto fail;
/*
* Wait until ip read and write fifo pointers are equal
*/
try_count--;
}
if (try_count == 0) {
" nxge_ipp_disable: port%d failed"
" rd_fifo != wr_fifo", portn));
goto fail;
}
}
/* IPP soft reset */
goto fail;
}
/* to reset control FIFO */
goto fail;
/*
* Making sure that error source is cleared if this is an injected
* error.
*/
return (NXGE_OK);
fail:
"nxge_ipp_init: Fail to Reset IPP Port #%d\n",
portn));
return (NXGE_ERROR | rs);
}
/* ARGSUSED */
{
goto fail;
/* Set max packet size */
IPP_MAX_PKT_SIZE)) != NPI_SUCCESS)
goto fail;
return (NXGE_OK);
fail:
"nxge_ipp_init: Fail to Enable IPP Port #%d\n", portn));
return (NXGE_ERROR | rs);
}
/* ARGSUSED */
{
/*
* Wait until ip read and write fifo pointers are equal
*/
try_count--;
}
if (try_count == 0) {
" nxge_ipp_drain: port%d failed"
" rd_fifo != wr_fifo", portn));
goto fail;
}
}
return (NXGE_OK);
fail:
"Fail to Reset IPP Port #%d\n", portn));
return (NXGE_ERROR | rs);
}
/* ARGSUSED */
{
return (NXGE_ERROR | rs);
/*
* The error is not initiated from this port, so just exit.
*/
return (NXGE_OK);
}
return (NXGE_ERROR | rs);
return (NXGE_ERROR | rs);
"nxge_ipp_err_evnts: fatal error: sop_miss\n"));
}
return (NXGE_ERROR | rs);
return (NXGE_ERROR | rs);
"nxge_ipp_err_evnts: fatal error: eop_miss\n"));
}
&ue_ecc_valid)) != NXGE_OK)
return (status);
if (ue_ecc_valid) {
return (NXGE_ERROR | rs);
"nxge_ipp_err_evnts: fatal error: dfifo_ue\n"));
}
}
statsp->pfifo_perr++;
"nxge_ipp_err_evnts: "
"fatal error: pre_pifo_perr\n"));
}
statsp->pfifo_over++;
"nxge_ipp_err_evnts: "
"fatal error: pfifo_over\n"));
}
"nxge_ipp_err_evnts: "
"fatal error: pfifo_und\n"));
}
/*
* Do not send FMA ereport or log error message
* indicate a HW failure.
*
* Clear bit BAD_CS_MX of register IPP_INT_STAT
* by reading register IPP_BAD_CS_CNT
*/
}
/*
* Do not send FMA ereport or log error message
* indicate a HW failure.
*
* Clear bit PKT_DIS_MX of register IPP_INT_STAT
* by reading register IPP_PKT_DIS
*/
}
/*
* Clear bit ECC_ERR_MAX of register IPP_INI_STAT
* by reading register IPP_ECC
*/
/*
* A defect in Neptune port2's IPP module could generate
* many fake but harmless ECC errors under stress and cause
* the ecc-error-counter register IPP_ECC to reach its
* maximum value in a few seconds. To avoid false alarm, do
* not report the error if it is port2.
*/
if (portn != 2) {
IPP_ECC_CNT_MASK)) {
"nxge_ipp_err_evnts: pkt_ecc_err_max\n"));
}
}
}
/*
* Making sure that error source is cleared if this is an injected
* error.
*/
if (rxport_fatal) {
" nxge_ipp_handle_sys_errors:"
" fatal Error on Port #%d\n", portn));
}
}
return (status);
}
/* ARGSUSED */
void
{
switch (err_id) {
break;
break;
if (err_id == NXGE_FM_EREPORT_IPP_EOP_MISS)
else if (err_id == NXGE_FM_EREPORT_IPP_SOP_MISS)
else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_UE)
else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_CE)
else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_PERR)
else if (err_id == NXGE_FM_EREPORT_IPP_ECC_ERR_MAX) {
/*
* Fill register IPP_ECC with max ECC-error-
* counter value (0xff) to set the ECC_ERR_MAX bit
* of the IPP_INT_STAT register and trigger an
* FMA ereport.
*/
} else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_OVER)
else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_UND)
else if (err_id == NXGE_FM_EREPORT_IPP_BAD_CS_MX) {
/*
* Fill IPP_BAD_CS_CNT with max bad-checksum-counter
* value (0x3fff) to set the BAD_CS_MX bit of
* IPP_INT_STAT and trigger an FMA ereport.
*/
} else if (err_id == NXGE_FM_EREPORT_IPP_PKT_DIS_MX) {
/*
* Fill IPP_PKT_DIS with max packet-discard-counter
* value (0x3fff) to set the PKT_DIS_MX bit of
* IPP_INT_STAT and trigger an FMA ereport.
*/
}
break;
}
}
/* ARGSUSED */
{
int i;
"Recovering from RxPort error..."));
/*
* Making sure that error source is cleared if this is an injected
* error.
*/
/* Disable RxMAC */
goto fail;
/* When recovering from IPP, RxDMA channel resets are not necessary */
/* Reset ZCP CFIFO */
goto fail;
/*
* Wait until ip read and write fifo pointers are equal
*/
try_count = 512;
try_count--;
}
if (try_count == 0) {
" nxge_ipp_reset: port%d IPP stalled..."
" rd_fifo_ptr = 0x%x wr_fifo_ptr = 0x%x",
/*
* This means the fatal error occurred on the first line of the
* fifo. In this case, just reset the IPP without draining the
* PFIFO.
*/
}
} else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
if (portn < 2)
else
} else {
goto fail;
}
/* Clean up DFIFO SRAM entries */
for (i = 0; i < dfifo_entries; i++) {
i, 0, 0, 0, 0, 0)) != NPI_SUCCESS)
goto fail;
goto fail;
}
/* Clear PFIFO DFIFO status bits */
goto fail;
goto fail;
/* Reset IPP */
goto fail;
goto fail;
goto fail;
goto fail;
"Recovery successful, RxPort restored"));
return (NXGE_OK);
fail:
}
/* ARGSUSED */
/*
* A hardware bug may cause fake ECCUEs (ECC Uncorrectable Error).
* This function checks if a ECCUE is real(valid) or not. It is not
* real if rd_ptr == wr_ptr.
* The hardware module that has the bug is used not only by the IPP
* FIFO but also by the ZCP FIFO, therefore this function is also
* called by nxge_zcp_handle_sys_errors for validating the ZCP FIFO
* error.
*/
{
!= NPI_SUCCESS)
goto fail;
!= NPI_SUCCESS)
goto fail;
} else {
stall_cnt = 0;
/*
* Check if the two pointers are moving, the ECCUE is invali
* if either pointer is moving, which indicates that the FIFO
* is functional.
*/
while (stall_cnt < 16) {
goto fail;
goto fail;
stall_cnt++;
} else {
break;
}
}
if (valid) {
/*
* Further check to see if the ECCUE is valid. The
* error is real if the LSB of d4 is 1, which
* indicates that the data that has set the ECC
* error flag is the 16-byte internal control word.
*/
goto fail;
}
}
return (NXGE_OK);
fail:
return (NXGE_ERROR | rs);
}