nxge_txc.c revision adfcba552dfc70ff685a2e8703fe1761b244f3e8
/*
* 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
* or http://www.opensolaris.org/os/licensing.
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/nxge/nxge_impl.h>
#include <sys/nxge/nxge_txc.h>
static nxge_status_t
nxge_txc_handle_port_errors(p_nxge_t, uint32_t);
static void
nxge_txc_inject_port_err(uint8_t, txc_int_stat_dbg_t *,
uint8_t istats);
extern nxge_status_t nxge_tx_port_fatal_err_recover(p_nxge_t);
nxge_status_t
nxge_txc_init(p_nxge_t nxgep)
{
uint8_t port;
npi_handle_t handle;
npi_status_t rs = NPI_SUCCESS;
handle = NXGE_DEV_NPI_HANDLE(nxgep);
port = NXGE_GET_PORT_NUM(nxgep->function_num);
NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txc_init: portn %d", port));
/*
* Enable the TXC controller.
*/
if ((rs = npi_txc_global_enable(handle)) != NPI_SUCCESS) {
goto fail;
}
/* Enable this port within the TXC. */
if ((rs = npi_txc_port_enable(handle, port)) != NPI_SUCCESS) {
goto fail;
}
/* Bind DMA channels to this port. */
if ((rs = npi_txc_port_dma_enable(handle, port,
TXDMA_PORT_BITMAP(nxgep))) != NPI_SUCCESS) {
goto fail;
}
/* Unmask all TXC interrupts */
npi_txc_global_imask_set(handle, port, 0);
NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txc_init: portn %d", port));
return (NXGE_OK);
fail:
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_txc_init: Failed to initialize txc on port %d",
port));
return (NXGE_ERROR | rs);
}
nxge_status_t
nxge_txc_uninit(p_nxge_t nxgep)
{
uint8_t port;
npi_handle_t handle;
npi_status_t rs = NPI_SUCCESS;
handle = NXGE_DEV_NPI_HANDLE(nxgep);
port = NXGE_GET_PORT_NUM(nxgep->function_num);
NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txc_uninit: portn %d", port));
/*
* disable the TXC controller.
*/
if ((rs = npi_txc_global_disable(handle)) != NPI_SUCCESS) {
goto fail;
}
/* disable this port within the TXC. */
if ((rs = npi_txc_port_disable(handle, port)) != NPI_SUCCESS) {
goto fail;
}
/* unbind DMA channels to this port. */
if ((rs = npi_txc_port_dma_enable(handle, port, 0)) != NPI_SUCCESS) {
goto fail;
}
NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txc_uninit: portn %d", port));
return (NXGE_OK);
fail:
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_txc_init: Failed to initialize txc on port %d",
port));
return (NXGE_ERROR | rs);
}
void
nxge_txc_regs_dump(p_nxge_t nxgep)
{
uint32_t cnt1, cnt2;
npi_handle_t handle;
txc_control_t control;
uint32_t bitmap = 0;
NXGE_DEBUG_MSG((nxgep, TX_CTL, "\nTXC dump: func # %d:\n",
nxgep->function_num));
handle = NXGE_DEV_NPI_HANDLE(nxgep);
(void) npi_txc_control(handle, OP_GET, &control);
(void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap);
NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC port control 0x%0llx",
(long long)control.value));
NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC port bitmap 0x%x", bitmap));
(void) npi_txc_pkt_xmt_to_mac_get(handle, nxgep->function_num,
&cnt1, &cnt2);
NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC bytes to MAC %d "
"packets to MAC %d",
cnt1, cnt2));
(void) npi_txc_pkt_stuffed_get(handle, nxgep->function_num,
&cnt1, &cnt2);
NXGE_DEBUG_MSG((nxgep, TX_CTL,
"\n\tTXC ass packets %d reorder packets %d",
cnt1 & 0xffff, cnt2 & 0xffff));
(void) npi_txc_reorder_get(handle, nxgep->function_num, &cnt1);
NXGE_DEBUG_MSG((nxgep, TX_CTL,
"\n\tTXC reorder resource %d", cnt1 & 0xff));
}
nxge_status_t
nxge_txc_handle_sys_errors(p_nxge_t nxgep)
{
npi_handle_t handle;
txc_int_stat_t istatus;
uint32_t err_status;
uint8_t err_portn;
boolean_t my_err = B_FALSE;
nxge_status_t status = NXGE_OK;
handle = nxgep->npi_handle;
npi_txc_global_istatus_get(handle, (txc_int_stat_t *)&istatus.value);
switch (nxgep->mac.portnum) {
case 0:
if (istatus.bits.ldw.port0_int_status) {
my_err = B_TRUE;
err_portn = 0;
err_status = istatus.bits.ldw.port0_int_status;
}
break;
case 1:
if (istatus.bits.ldw.port1_int_status) {
my_err = B_TRUE;
err_portn = 1;
err_status = istatus.bits.ldw.port1_int_status;
}
break;
case 2:
if (istatus.bits.ldw.port2_int_status) {
my_err = B_TRUE;
err_portn = 2;
err_status = istatus.bits.ldw.port2_int_status;
}
break;
case 3:
if (istatus.bits.ldw.port3_int_status) {
my_err = B_TRUE;
err_portn = 3;
err_status = istatus.bits.ldw.port3_int_status;
}
break;
default:
return (NXGE_ERROR);
}
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_txc_handle_sys_errors: errored port %d",
err_portn));
if (my_err) {
status = nxge_txc_handle_port_errors(nxgep, err_status);
}
return (status);
}
static nxge_status_t
nxge_txc_handle_port_errors(p_nxge_t nxgep, uint32_t err_status)
{
npi_handle_t handle;
npi_status_t rs = NPI_SUCCESS;
p_nxge_txc_stats_t statsp;
txc_int_stat_t istatus;
boolean_t txport_fatal = B_FALSE;
uint8_t portn;
nxge_status_t status = NXGE_OK;
handle = nxgep->npi_handle;
statsp = (p_nxge_txc_stats_t)&nxgep->statsp->txc_stats;
portn = nxgep->mac.portnum;
istatus.value = 0;
if ((err_status & TXC_INT_STAT_RO_CORR_ERR) ||
(err_status & TXC_INT_STAT_RO_CORR_ERR) ||
(err_status & TXC_INT_STAT_RO_UNCORR_ERR) ||
(err_status & TXC_INT_STAT_REORDER_ERR)) {
if ((rs = npi_txc_ro_states_get(handle, portn,
&statsp->errlog.ro_st)) != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
if (err_status & TXC_INT_STAT_RO_CORR_ERR) {
statsp->ro_correct_err++;
NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_txc_err_evnts: "
"RO FIFO correctable error"));
}
if (err_status & TXC_INT_STAT_RO_UNCORR_ERR) {
statsp->ro_uncorrect_err++;
NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
NXGE_FM_EREPORT_TXC_RO_UNCORRECT_ERR);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_txc_err_evnts: "
"RO FIFO uncorrectable error"));
}
if (err_status & TXC_INT_STAT_REORDER_ERR) {
statsp->reorder_err++;
NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
NXGE_FM_EREPORT_TXC_REORDER_ERR);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_txc_err_evnts: "
"fatal error: Reorder error"));
txport_fatal = B_TRUE;
}
if ((err_status & TXC_INT_STAT_RO_CORR_ERR) ||
(err_status & TXC_INT_STAT_RO_CORR_ERR) ||
(err_status & TXC_INT_STAT_RO_UNCORR_ERR)) {
if ((rs = npi_txc_ro_ecc_state_clr(handle, portn))
!= NPI_SUCCESS)
return (NXGE_ERROR | rs);
/*
* Making sure that error source is cleared if this is
* an injected error.
*/
TXC_FZC_CNTL_REG_WRITE64(handle, TXC_ROECC_CTL_REG,
portn, 0);
}
}
if ((err_status & TXC_INT_STAT_SF_CORR_ERR) ||
(err_status & TXC_INT_STAT_SF_UNCORR_ERR)) {
if ((rs = npi_txc_sf_states_get(handle, portn,
&statsp->errlog.sf_st)) != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
if (err_status & TXC_INT_STAT_SF_CORR_ERR) {
statsp->sf_correct_err++;
NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_txc_err_evnts: "
"SF FIFO correctable error"));
}
if (err_status & TXC_INT_STAT_SF_UNCORR_ERR) {
statsp->sf_uncorrect_err++;
NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
NXGE_FM_EREPORT_TXC_SF_UNCORRECT_ERR);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_txc_err_evnts: "
"SF FIFO uncorrectable error"));
}
if ((rs = npi_txc_sf_ecc_state_clr(handle, portn))
!= NPI_SUCCESS)
return (NXGE_ERROR | rs);
/*
* Making sure that error source is cleared if this is
* an injected error.
*/
TXC_FZC_CNTL_REG_WRITE64(handle, TXC_SFECC_CTL_REG, portn, 0);
}
/* Clear corresponding errors */
switch (portn) {
case 0:
istatus.bits.ldw.port0_int_status = err_status;
break;
case 1:
istatus.bits.ldw.port1_int_status = err_status;
break;
case 2:
istatus.bits.ldw.port2_int_status = err_status;
break;
case 3:
istatus.bits.ldw.port3_int_status = err_status;
break;
default:
return (NXGE_ERROR);
}
npi_txc_global_istatus_clear(handle, istatus.value);
if (txport_fatal) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_txc_handle_port_errors:"
" fatal Error on Port#%d\n",
portn));
status = nxge_tx_port_fatal_err_recover(nxgep);
if (status == NXGE_OK) {
FM_SERVICE_RESTORED(nxgep);
}
}
return (status);
}
void
nxge_txc_inject_err(p_nxge_t nxgep, uint32_t err_id)
{
txc_int_stat_dbg_t txcs;
txc_roecc_ctl_t ro_ecc_ctl;
txc_sfecc_ctl_t sf_ecc_ctl;
uint8_t portn = nxgep->mac.portnum;
cmn_err(CE_NOTE, "!TXC error Inject\n");
switch (err_id) {
case NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR:
case NXGE_FM_EREPORT_TXC_RO_UNCORRECT_ERR:
ro_ecc_ctl.value = 0;
ro_ecc_ctl.bits.ldw.all_pkts = 1;
ro_ecc_ctl.bits.ldw.second_line_pkt = 1;
if (err_id == NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR)
ro_ecc_ctl.bits.ldw.single_bit_err = 1;
else
ro_ecc_ctl.bits.ldw.double_bit_err = 1;
#if defined(__i386)
cmn_err(CE_NOTE, "!Write 0x%llx to TXC_ROECC_CTL_REG\n",
ro_ecc_ctl.value);
#else
cmn_err(CE_NOTE, "!Write 0x%lx to TXC_ROECC_CTL_REG\n",
ro_ecc_ctl.value);
#endif
TXC_FZC_CNTL_REG_WRITE64(nxgep->npi_handle, TXC_ROECC_CTL_REG,
portn, ro_ecc_ctl.value);
break;
case NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR:
case NXGE_FM_EREPORT_TXC_SF_UNCORRECT_ERR:
sf_ecc_ctl.value = 0;
sf_ecc_ctl.bits.ldw.all_pkts = 1;
sf_ecc_ctl.bits.ldw.second_line_pkt = 1;
if (err_id == NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR)
sf_ecc_ctl.bits.ldw.single_bit_err = 1;
else
sf_ecc_ctl.bits.ldw.double_bit_err = 1;
#if defined(__i386)
cmn_err(CE_NOTE, "!Write 0x%llx to TXC_SFECC_CTL_REG\n",
sf_ecc_ctl.value);
#else
cmn_err(CE_NOTE, "!Write 0x%lx to TXC_SFECC_CTL_REG\n",
sf_ecc_ctl.value);
#endif
TXC_FZC_CNTL_REG_WRITE64(nxgep->npi_handle, TXC_SFECC_CTL_REG,
portn, sf_ecc_ctl.value);
break;
case NXGE_FM_EREPORT_TXC_REORDER_ERR:
NXGE_REG_RD64(nxgep->npi_handle, TXC_INT_STAT_DBG_REG,
&txcs.value);
nxge_txc_inject_port_err(portn, &txcs,
TXC_INT_STAT_REORDER_ERR);
#if defined(__i386)
cmn_err(CE_NOTE, "!Write 0x%llx to TXC_INT_STAT_DBG_REG\n",
txcs.value);
#else
cmn_err(CE_NOTE, "!Write 0x%lx to TXC_INT_STAT_DBG_REG\n",
txcs.value);
#endif
NXGE_REG_WR64(nxgep->npi_handle, TXC_INT_STAT_DBG_REG,
txcs.value);
break;
default:
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_txc_inject_err: Unknown err_id"));
}
}
static void
nxge_txc_inject_port_err(uint8_t portn, txc_int_stat_dbg_t *txcs,
uint8_t istats)
{
switch (portn) {
case 0:
txcs->bits.ldw.port0_int_status |= istats;
break;
case 1:
txcs->bits.ldw.port1_int_status |= istats;
break;
case 2:
txcs->bits.ldw.port2_int_status |= istats;
break;
case 3:
txcs->bits.ldw.port3_int_status |= istats;
break;
default:
;
}
}