Commit dc741bbd authored by Bryan O'Sullivan's avatar Bryan O'Sullivan Committed by Roland Dreier
Browse files

IB/ipath: support for PCI Express devices



This file contains routines and definitions specific to InfiniPath
devices that have PCI Express interfaces.
Signed-off-by: default avatarBryan O'Sullivan <bos@pathscale.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent cc533a57
/*
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* This file contains all of the code that is specific to the
* InfiniPath PE-800 chip.
*/
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include "ipath_kernel.h"
#include "ipath_registers.h"
/*
* This file contains all the chip-specific register information and
* access functions for the PathScale PE800, the PCI-Express chip.
*
* This lists the InfiniPath PE800 registers, in the actual chip layout.
* This structure should never be directly accessed.
*/
struct _infinipath_do_not_use_kernel_regs {
unsigned long long Revision;
unsigned long long Control;
unsigned long long PageAlign;
unsigned long long PortCnt;
unsigned long long DebugPortSelect;
unsigned long long Reserved0;
unsigned long long SendRegBase;
unsigned long long UserRegBase;
unsigned long long CounterRegBase;
unsigned long long Scratch;
unsigned long long Reserved1;
unsigned long long Reserved2;
unsigned long long IntBlocked;
unsigned long long IntMask;
unsigned long long IntStatus;
unsigned long long IntClear;
unsigned long long ErrorMask;
unsigned long long ErrorStatus;
unsigned long long ErrorClear;
unsigned long long HwErrMask;
unsigned long long HwErrStatus;
unsigned long long HwErrClear;
unsigned long long HwDiagCtrl;
unsigned long long MDIO;
unsigned long long IBCStatus;
unsigned long long IBCCtrl;
unsigned long long ExtStatus;
unsigned long long ExtCtrl;
unsigned long long GPIOOut;
unsigned long long GPIOMask;
unsigned long long GPIOStatus;
unsigned long long GPIOClear;
unsigned long long RcvCtrl;
unsigned long long RcvBTHQP;
unsigned long long RcvHdrSize;
unsigned long long RcvHdrCnt;
unsigned long long RcvHdrEntSize;
unsigned long long RcvTIDBase;
unsigned long long RcvTIDCnt;
unsigned long long RcvEgrBase;
unsigned long long RcvEgrCnt;
unsigned long long RcvBufBase;
unsigned long long RcvBufSize;
unsigned long long RxIntMemBase;
unsigned long long RxIntMemSize;
unsigned long long RcvPartitionKey;
unsigned long long Reserved3;
unsigned long long RcvPktLEDCnt;
unsigned long long Reserved4[8];
unsigned long long SendCtrl;
unsigned long long SendPIOBufBase;
unsigned long long SendPIOSize;
unsigned long long SendPIOBufCnt;
unsigned long long SendPIOAvailAddr;
unsigned long long TxIntMemBase;
unsigned long long TxIntMemSize;
unsigned long long Reserved5;
unsigned long long PCIeRBufTestReg0;
unsigned long long PCIeRBufTestReg1;
unsigned long long Reserved51[6];
unsigned long long SendBufferError;
unsigned long long SendBufferErrorCONT1;
unsigned long long Reserved6SBE[6];
unsigned long long RcvHdrAddr0;
unsigned long long RcvHdrAddr1;
unsigned long long RcvHdrAddr2;
unsigned long long RcvHdrAddr3;
unsigned long long RcvHdrAddr4;
unsigned long long Reserved7RHA[11];
unsigned long long RcvHdrTailAddr0;
unsigned long long RcvHdrTailAddr1;
unsigned long long RcvHdrTailAddr2;
unsigned long long RcvHdrTailAddr3;
unsigned long long RcvHdrTailAddr4;
unsigned long long Reserved8RHTA[11];
unsigned long long Reserved9SW[8];
unsigned long long SerdesConfig0;
unsigned long long SerdesConfig1;
unsigned long long SerdesStatus;
unsigned long long XGXSConfig;
unsigned long long IBPLLCfg;
unsigned long long Reserved10SW2[3];
unsigned long long PCIEQ0SerdesConfig0;
unsigned long long PCIEQ0SerdesConfig1;
unsigned long long PCIEQ0SerdesStatus;
unsigned long long Reserved11;
unsigned long long PCIEQ1SerdesConfig0;
unsigned long long PCIEQ1SerdesConfig1;
unsigned long long PCIEQ1SerdesStatus;
unsigned long long Reserved12;
};
#define IPATH_KREG_OFFSET(field) (offsetof(struct \
_infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
#define IPATH_CREG_OFFSET(field) (offsetof( \
struct infinipath_counters, field) / sizeof(u64))
static const struct ipath_kregs ipath_pe_kregs = {
.kr_control = IPATH_KREG_OFFSET(Control),
.kr_counterregbase = IPATH_KREG_OFFSET(CounterRegBase),
.kr_debugportselect = IPATH_KREG_OFFSET(DebugPortSelect),
.kr_errorclear = IPATH_KREG_OFFSET(ErrorClear),
.kr_errormask = IPATH_KREG_OFFSET(ErrorMask),
.kr_errorstatus = IPATH_KREG_OFFSET(ErrorStatus),
.kr_extctrl = IPATH_KREG_OFFSET(ExtCtrl),
.kr_extstatus = IPATH_KREG_OFFSET(ExtStatus),
.kr_gpio_clear = IPATH_KREG_OFFSET(GPIOClear),
.kr_gpio_mask = IPATH_KREG_OFFSET(GPIOMask),
.kr_gpio_out = IPATH_KREG_OFFSET(GPIOOut),
.kr_gpio_status = IPATH_KREG_OFFSET(GPIOStatus),
.kr_hwdiagctrl = IPATH_KREG_OFFSET(HwDiagCtrl),
.kr_hwerrclear = IPATH_KREG_OFFSET(HwErrClear),
.kr_hwerrmask = IPATH_KREG_OFFSET(HwErrMask),
.kr_hwerrstatus = IPATH_KREG_OFFSET(HwErrStatus),
.kr_ibcctrl = IPATH_KREG_OFFSET(IBCCtrl),
.kr_ibcstatus = IPATH_KREG_OFFSET(IBCStatus),
.kr_intblocked = IPATH_KREG_OFFSET(IntBlocked),
.kr_intclear = IPATH_KREG_OFFSET(IntClear),
.kr_intmask = IPATH_KREG_OFFSET(IntMask),
.kr_intstatus = IPATH_KREG_OFFSET(IntStatus),
.kr_mdio = IPATH_KREG_OFFSET(MDIO),
.kr_pagealign = IPATH_KREG_OFFSET(PageAlign),
.kr_partitionkey = IPATH_KREG_OFFSET(RcvPartitionKey),
.kr_portcnt = IPATH_KREG_OFFSET(PortCnt),
.kr_rcvbthqp = IPATH_KREG_OFFSET(RcvBTHQP),
.kr_rcvbufbase = IPATH_KREG_OFFSET(RcvBufBase),
.kr_rcvbufsize = IPATH_KREG_OFFSET(RcvBufSize),
.kr_rcvctrl = IPATH_KREG_OFFSET(RcvCtrl),
.kr_rcvegrbase = IPATH_KREG_OFFSET(RcvEgrBase),
.kr_rcvegrcnt = IPATH_KREG_OFFSET(RcvEgrCnt),
.kr_rcvhdrcnt = IPATH_KREG_OFFSET(RcvHdrCnt),
.kr_rcvhdrentsize = IPATH_KREG_OFFSET(RcvHdrEntSize),
.kr_rcvhdrsize = IPATH_KREG_OFFSET(RcvHdrSize),
.kr_rcvintmembase = IPATH_KREG_OFFSET(RxIntMemBase),
.kr_rcvintmemsize = IPATH_KREG_OFFSET(RxIntMemSize),
.kr_rcvtidbase = IPATH_KREG_OFFSET(RcvTIDBase),
.kr_rcvtidcnt = IPATH_KREG_OFFSET(RcvTIDCnt),
.kr_revision = IPATH_KREG_OFFSET(Revision),
.kr_scratch = IPATH_KREG_OFFSET(Scratch),
.kr_sendbuffererror = IPATH_KREG_OFFSET(SendBufferError),
.kr_sendctrl = IPATH_KREG_OFFSET(SendCtrl),
.kr_sendpioavailaddr = IPATH_KREG_OFFSET(SendPIOAvailAddr),
.kr_sendpiobufbase = IPATH_KREG_OFFSET(SendPIOBufBase),
.kr_sendpiobufcnt = IPATH_KREG_OFFSET(SendPIOBufCnt),
.kr_sendpiosize = IPATH_KREG_OFFSET(SendPIOSize),
.kr_sendregbase = IPATH_KREG_OFFSET(SendRegBase),
.kr_txintmembase = IPATH_KREG_OFFSET(TxIntMemBase),
.kr_txintmemsize = IPATH_KREG_OFFSET(TxIntMemSize),
.kr_userregbase = IPATH_KREG_OFFSET(UserRegBase),
.kr_serdesconfig0 = IPATH_KREG_OFFSET(SerdesConfig0),
.kr_serdesconfig1 = IPATH_KREG_OFFSET(SerdesConfig1),
.kr_serdesstatus = IPATH_KREG_OFFSET(SerdesStatus),
.kr_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig),
.kr_ibpllcfg = IPATH_KREG_OFFSET(IBPLLCfg),
/*
* These should not be used directly via ipath_read_kreg64(),
* use them with ipath_read_kreg64_port()
*/
.kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0),
.kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0),
/* This group is pe-800-specific; and used only in this file */
/* The rcvpktled register controls one of the debug port signals, so
* a packet activity LED can be connected to it. */
.kr_rcvpktledcnt = IPATH_KREG_OFFSET(RcvPktLEDCnt),
.kr_pcierbuftestreg0 = IPATH_KREG_OFFSET(PCIeRBufTestReg0),
.kr_pcierbuftestreg1 = IPATH_KREG_OFFSET(PCIeRBufTestReg1),
.kr_pcieq0serdesconfig0 = IPATH_KREG_OFFSET(PCIEQ0SerdesConfig0),
.kr_pcieq0serdesconfig1 = IPATH_KREG_OFFSET(PCIEQ0SerdesConfig1),
.kr_pcieq0serdesstatus = IPATH_KREG_OFFSET(PCIEQ0SerdesStatus),
.kr_pcieq1serdesconfig0 = IPATH_KREG_OFFSET(PCIEQ1SerdesConfig0),
.kr_pcieq1serdesconfig1 = IPATH_KREG_OFFSET(PCIEQ1SerdesConfig1),
.kr_pcieq1serdesstatus = IPATH_KREG_OFFSET(PCIEQ1SerdesStatus)
};
static const struct ipath_cregs ipath_pe_cregs = {
.cr_badformatcnt = IPATH_CREG_OFFSET(RxBadFormatCnt),
.cr_erricrccnt = IPATH_CREG_OFFSET(RxICRCErrCnt),
.cr_errlinkcnt = IPATH_CREG_OFFSET(RxLinkProblemCnt),
.cr_errlpcrccnt = IPATH_CREG_OFFSET(RxLPCRCErrCnt),
.cr_errpkey = IPATH_CREG_OFFSET(RxPKeyMismatchCnt),
.cr_errrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowCtrlErrCnt),
.cr_err_rlencnt = IPATH_CREG_OFFSET(RxLenErrCnt),
.cr_errslencnt = IPATH_CREG_OFFSET(TxLenErrCnt),
.cr_errtidfull = IPATH_CREG_OFFSET(RxTIDFullErrCnt),
.cr_errtidvalid = IPATH_CREG_OFFSET(RxTIDValidErrCnt),
.cr_errvcrccnt = IPATH_CREG_OFFSET(RxVCRCErrCnt),
.cr_ibstatuschange = IPATH_CREG_OFFSET(IBStatusChangeCnt),
.cr_intcnt = IPATH_CREG_OFFSET(LBIntCnt),
.cr_invalidrlencnt = IPATH_CREG_OFFSET(RxMaxMinLenErrCnt),
.cr_invalidslencnt = IPATH_CREG_OFFSET(TxMaxMinLenErrCnt),
.cr_lbflowstallcnt = IPATH_CREG_OFFSET(LBFlowStallCnt),
.cr_pktrcvcnt = IPATH_CREG_OFFSET(RxDataPktCnt),
.cr_pktrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowPktCnt),
.cr_pktsendcnt = IPATH_CREG_OFFSET(TxDataPktCnt),
.cr_pktsendflowcnt = IPATH_CREG_OFFSET(TxFlowPktCnt),
.cr_portovflcnt = IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt),
.cr_rcvebpcnt = IPATH_CREG_OFFSET(RxEBPCnt),
.cr_rcvovflcnt = IPATH_CREG_OFFSET(RxBufOvflCnt),
.cr_senddropped = IPATH_CREG_OFFSET(TxDroppedPktCnt),
.cr_sendstallcnt = IPATH_CREG_OFFSET(TxFlowStallCnt),
.cr_sendunderruncnt = IPATH_CREG_OFFSET(TxUnderrunCnt),
.cr_wordrcvcnt = IPATH_CREG_OFFSET(RxDwordCnt),
.cr_wordsendcnt = IPATH_CREG_OFFSET(TxDwordCnt),
.cr_unsupvlcnt = IPATH_CREG_OFFSET(TxUnsupVLErrCnt),
.cr_rxdroppktcnt = IPATH_CREG_OFFSET(RxDroppedPktCnt),
.cr_iblinkerrrecovcnt = IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt),
.cr_iblinkdowncnt = IPATH_CREG_OFFSET(IBLinkDownedCnt),
.cr_ibsymbolerrcnt = IPATH_CREG_OFFSET(IBSymbolErrCnt)
};
/* kr_intstatus, kr_intclear, kr_intmask bits */
#define INFINIPATH_I_RCVURG_MASK 0x1F
#define INFINIPATH_I_RCVAVAIL_MASK 0x1F
/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
#define INFINIPATH_HWE_PCIEMEMPARITYERR_MASK 0x000000000000003fULL
#define INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT 0
#define INFINIPATH_HWE_PCIEPOISONEDTLP 0x0000000010000000ULL
#define INFINIPATH_HWE_PCIECPLTIMEOUT 0x0000000020000000ULL
#define INFINIPATH_HWE_PCIEBUSPARITYXTLH 0x0000000040000000ULL
#define INFINIPATH_HWE_PCIEBUSPARITYXADM 0x0000000080000000ULL
#define INFINIPATH_HWE_PCIEBUSPARITYRADM 0x0000000100000000ULL
#define INFINIPATH_HWE_COREPLL_FBSLIP 0x0080000000000000ULL
#define INFINIPATH_HWE_COREPLL_RFSLIP 0x0100000000000000ULL
#define INFINIPATH_HWE_PCIE1PLLFAILED 0x0400000000000000ULL
#define INFINIPATH_HWE_PCIE0PLLFAILED 0x0800000000000000ULL
#define INFINIPATH_HWE_SERDESPLLFAILED 0x1000000000000000ULL
/* kr_extstatus bits */
#define INFINIPATH_EXTS_FREQSEL 0x2
#define INFINIPATH_EXTS_SERDESSEL 0x4
#define INFINIPATH_EXTS_MEMBIST_ENDTEST 0x0000000000004000
#define INFINIPATH_EXTS_MEMBIST_FOUND 0x0000000000008000
#define _IPATH_GPIO_SDA_NUM 1
#define _IPATH_GPIO_SCL_NUM 0
#define IPATH_GPIO_SDA (1ULL << \
(_IPATH_GPIO_SDA_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
#define IPATH_GPIO_SCL (1ULL << \
(_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
/**
* ipath_pe_handle_hwerrors - display hardware errors.
* @dd: the infinipath device
* @msg: the output buffer
* @msgl: the size of the output buffer
*
* Use same msg buffer as regular errors to avoid excessive stack
* use. Most hardware errors are catastrophic, but for right now,
* we'll print them and continue. We reuse the same message buffer as
* ipath_handle_errors() to avoid excessive stack usage.
*/
void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
size_t msgl)
{
ipath_err_t hwerrs;
u32 bits, ctrl;
int isfatal = 0;
char bitsmsg[64];
hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
if (!hwerrs) {
/*
* better than printing cofusing messages
* This seems to be related to clearing the crc error, or
* the pll error during init.
*/
ipath_cdbg(VERBOSE, "Called but no hardware errors set\n");
return;
} else if (hwerrs == ~0ULL) {
ipath_dev_err(dd, "Read of hardware error status failed "
"(all bits set); ignoring\n");
return;
}
ipath_stats.sps_hwerrs++;
/* Always clear the error status register, except MEMBISTFAIL,
* regardless of whether we continue or stop using the chip.
* We want that set so we know it failed, even across driver reload.
* We'll still ignore it in the hwerrmask. We do this partly for
* diagnostics, but also for support */
ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
hwerrs&~INFINIPATH_HWE_MEMBISTFAILED);
hwerrs &= dd->ipath_hwerrmask;
/*
* make sure we get this much out, unless told to be quiet,
* or it's occurred within the last 5 seconds
*/
if ((hwerrs & ~dd->ipath_lasthwerror) ||
(ipath_debug & __IPATH_VERBDBG))
dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
"(cleared)\n", (unsigned long long) hwerrs);
dd->ipath_lasthwerror |= hwerrs;
if (hwerrs & ~infinipath_hwe_bitsextant)
ipath_dev_err(dd, "hwerror interrupt with unknown errors "
"%llx set\n", (unsigned long long)
(hwerrs & ~infinipath_hwe_bitsextant));
ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
if (ctrl & INFINIPATH_C_FREEZEMODE) {
if (hwerrs) {
/*
* if any set that we aren't ignoring only make the
* complaint once, in case it's stuck or recurring,
* and we get here multiple times
*/
if (dd->ipath_flags & IPATH_INITTED) {
ipath_dev_err(dd, "Fatal Error (freeze "
"mode), no longer usable\n");
isfatal = 1;
}
/*
* Mark as having had an error for driver, and also
* for /sys and status word mapped to user programs.
* This marks unit as not usable, until reset
*/
*dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
*dd->ipath_statusp |= IPATH_STATUS_HWERROR;
dd->ipath_flags &= ~IPATH_INITTED;
} else {
ipath_dbg("Clearing freezemode on ignored hardware "
"error\n");
ctrl &= ~INFINIPATH_C_FREEZEMODE;
ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
ctrl);
}
}
*msg = '\0';
if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
strlcat(msg, "[Memory BIST test failed, PE-800 unusable]",
msgl);
/* ignore from now on, so disable until driver reloaded */
*dd->ipath_statusp |= IPATH_STATUS_HWERROR;
dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED;
ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
dd->ipath_hwerrmask);
}
if (hwerrs & (INFINIPATH_HWE_RXEMEMPARITYERR_MASK
<< INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)) {
bits = (u32) ((hwerrs >>
INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) &
INFINIPATH_HWE_RXEMEMPARITYERR_MASK);
snprintf(bitsmsg, sizeof bitsmsg, "[RXE Parity Errs %x] ",
bits);
strlcat(msg, bitsmsg, msgl);
}
if (hwerrs & (INFINIPATH_HWE_TXEMEMPARITYERR_MASK
<< INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
bits = (u32) ((hwerrs >>
INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) &
INFINIPATH_HWE_TXEMEMPARITYERR_MASK);
snprintf(bitsmsg, sizeof bitsmsg, "[TXE Parity Errs %x] ",
bits);
strlcat(msg, bitsmsg, msgl);
}
if (hwerrs & (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK
<< INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT)) {
bits = (u32) ((hwerrs >>
INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) &
INFINIPATH_HWE_PCIEMEMPARITYERR_MASK);
snprintf(bitsmsg, sizeof bitsmsg,
"[PCIe Mem Parity Errs %x] ", bits);
strlcat(msg, bitsmsg, msgl);
}
if (hwerrs & INFINIPATH_HWE_IBCBUSTOSPCPARITYERR)
strlcat(msg, "[IB2IPATH Parity]", msgl);
if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR)
strlcat(msg, "[IPATH2IB Parity]", msgl);
#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \
INFINIPATH_HWE_COREPLL_RFSLIP )
if (hwerrs & _IPATH_PLL_FAIL) {
snprintf(bitsmsg, sizeof bitsmsg,
"[PLL failed (%llx), PE-800 unusable]",
(unsigned long long) hwerrs & _IPATH_PLL_FAIL);
strlcat(msg, bitsmsg, msgl);
/* ignore from now on, so disable until driver reloaded */
dd->ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL);
ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
dd->ipath_hwerrmask);
}
if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
/*
* If it occurs, it is left masked since the eternal
* interface is unused
*/
dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
dd->ipath_hwerrmask);
}
if (hwerrs & INFINIPATH_HWE_PCIEPOISONEDTLP)
strlcat(msg, "[PCIe Poisoned TLP]", msgl);
if (hwerrs & INFINIPATH_HWE_PCIECPLTIMEOUT)
strlcat(msg, "[PCIe completion timeout]", msgl);
/*
* In practice, it's unlikely wthat we'll see PCIe PLL, or bus
* parity or memory parity error failures, because most likely we
* won't be able to talk to the core of the chip. Nonetheless, we
* might see them, if they are in parts of the PCIe core that aren't
* essential.
*/
if (hwerrs & INFINIPATH_HWE_PCIE1PLLFAILED)
strlcat(msg, "[PCIePLL1]", msgl);
if (hwerrs & INFINIPATH_HWE_PCIE0PLLFAILED)
strlcat(msg, "[PCIePLL0]", msgl);
if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXTLH)
strlcat(msg, "[PCIe XTLH core parity]", msgl);
if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXADM)
strlcat(msg, "[PCIe ADM TX core parity]", msgl);
if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYRADM)
strlcat(msg, "[PCIe ADM RX core parity]", msgl);
if (hwerrs & INFINIPATH_HWE_RXDSYNCMEMPARITYERR)
strlcat(msg, "[Rx Dsync]", msgl);
if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED)
strlcat(msg, "[SerDes PLL]", msgl);
ipath_dev_err(dd, "%s hardware error\n", msg);
if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) {
/*
* for /sys status file ; if no trailing } is copied, we'll
* know it was truncated.
*/
snprintf(dd->ipath_freezemsg, dd->ipath_freezelen,
"{%s}", msg);
}
}
/**
* ipath_pe_boardname - fill in the board name
* @dd: the infinipath device
* @name: the output buffer
* @namelen: the size of the output buffer
*
* info is based on the board revision register
*/
static int ipath_pe_boardname(struct ipath_devdata *dd, char *name,
size_t namelen)
{
char *n = NULL;
u8 boardrev = dd->ipath_boardrev;
int ret;
switch (boardrev) {
case 0:
n = "InfiniPath_Emulation";
break;
case 1:
n = "InfiniPath_PE-800-Bringup";
break;
case 2:
n = "InfiniPath_PE-880";
break;
case 3:
n = "InfiniPath_PE-850";
break;
case 4:
n = "InfiniPath_PE-860";
break;
default:
ipath_dev_err(dd,
"Don't yet know about board with ID %u\n",
boardrev);
snprintf(name, namelen, "Unknown_InfiniPath_PE-8xx_%u",
boardrev);
break;
}
if (n)
snprintf(name, namelen, "%s", n);
if (dd->ipath_majrev != 4 || dd->ipath_minrev != 1) {
ipath_dev_err(dd, "Unsupported PE-800 revision %u.%u!\n",
dd->ipath_majrev, dd->ipath_minrev);
ret = 1;
} else
ret = 0;
return ret;
}
/**
* ipath_pe_init_hwerrors - enable hardware errors
* @dd: the infinipath device
*
* now that we have finished initializing everything that might reasonably
* cause a hardware error, and cleared those errors bits as they occur,
* we can enable hardware errors in the mask (potentially enabling
* freeze mode), and enable hardware errors as errors (along with
* everything else) in errormask
*/
void ipath_pe_init_hwerrors(struct ipath_devdata *dd)
{
ipath_err_t val;
u64 extsval;
extsval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST))
ipath_dev_err(dd, "MemBIST did not complete!\n");
val = ~0ULL; /* barring bugs, all hwerrors become interrupts, */
if (!dd->ipath_boardrev) // no PLL for Emulator
val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
/* workaround bug 9460 in internal interface bus parity checking */
val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM;
dd->ipath_hwerrmask = val;
}
/**
* ipath_pe_bringup_serdes - bring up the serdes
* @dd: the infinipath device
*/
int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
{
u64 val, tmp, config1;
int ret = 0, change = 0;
ipath_dbg("Trying to bringup serdes\n");
if (ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus) &
INFINIPATH_HWE_SERDESPLLFAILED) {
ipath_dbg("At start, serdes PLL failed bit set "
"in hwerrstatus, clearing and continuing\n");
ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
INFINIPATH_HWE_SERDESPLLFAILED);
}
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1);
ipath_cdbg(VERBOSE, "SerDes status config0=%llx config1=%llx, "
"xgxsconfig %llx\n", (unsigned long long) val,
(unsigned long long) config1, (unsigned long long)
ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
/*
* Force reset on, also set rxdetect enable. Must do before reading
* serdesstatus at least for simulation, or some of the bits in
* serdes status will come back as undefined and cause simulation