diff options
author | Ralph Campbell <ralph.campbell@qlogic.com> | 2008-04-16 21:09:30 -0700 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-04-16 21:09:30 -0700 |
commit | 843e6ab489cb5a2fd5df45bed1254812bc8ed8fa (patch) | |
tree | c7d1ab98ee0039ae2aa097874958a806c1352b25 /drivers/infiniband/hw | |
parent | dd042d59c18b2f26375494af7f5b6d1499acd2bb (diff) |
IB/ipath: HCA-specific code to support IBA7220
This patch adds the HCA-specific code for the IBA7220 HCA.
Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_iba7220.c | 2571 |
1 files changed, 2571 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_iba7220.c b/drivers/infiniband/hw/ipath/ipath_iba7220.c new file mode 100644 index 00000000000..1b2de2cfb69 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_iba7220.c @@ -0,0 +1,2571 @@ +/* + * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved. + * 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 7220 chip (except that specific to the SerDes) + */ + +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <rdma/ib_verbs.h> + +#include "ipath_kernel.h" +#include "ipath_registers.h" +#include "ipath_7220.h" + +static void ipath_setup_7220_setextled(struct ipath_devdata *, u64, u64); + +static unsigned ipath_compat_ddr_negotiate = 1; + +module_param_named(compat_ddr_negotiate, ipath_compat_ddr_negotiate, uint, + S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(compat_ddr_negotiate, + "Attempt pre-IBTA 1.2 DDR speed negotiation"); + +static unsigned ipath_sdma_fetch_arb = 1; +module_param_named(fetch_arb, ipath_sdma_fetch_arb, uint, S_IRUGO); +MODULE_PARM_DESC(fetch_arb, "IBA7220: change SDMA descriptor arbitration"); + +/* + * This file contains almost all the chip-specific register information and + * access functions for the QLogic InfiniPath 7220 PCI-Express chip, with the + * exception of SerDes support, which in in ipath_sd7220.c. + * + * This lists the InfiniPath 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 DebugSigsIntSel; /* was Reserved0;*/ + unsigned long long SendRegBase; + unsigned long long UserRegBase; + unsigned long long CounterRegBase; + unsigned long long Scratch; + unsigned long long EEPROMAddrCmd; /* was Reserved1; */ + unsigned long long EEPROMData; /* was 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 RcvQPMulticastPort; + unsigned long long RcvPktLEDCnt; + unsigned long long IBCDDRCtrl; + unsigned long long HRTBT_GUID; + unsigned long long IB_SDTEST_IF_TX; + unsigned long long IB_SDTEST_IF_RX; + unsigned long long IBCDDRCtrl2; + unsigned long long IBCDDRStatus; + unsigned long long JIntReload; + unsigned long long IBNCModeCtrl; + unsigned long long SendCtrl; + unsigned long long SendBufBase; + unsigned long long SendBufSize; + unsigned long long SendBufCnt; + unsigned long long SendAvailAddr; + unsigned long long TxIntMemBase; + unsigned long long TxIntMemSize; + unsigned long long SendDmaBase; + unsigned long long SendDmaLenGen; + unsigned long long SendDmaTail; + unsigned long long SendDmaHead; + unsigned long long SendDmaHeadAddr; + unsigned long long SendDmaBufMask0; + unsigned long long SendDmaBufMask1; + unsigned long long SendDmaBufMask2; + unsigned long long SendDmaStatus; + unsigned long long SendBufferError; + unsigned long long SendBufferErrorCONT1; + unsigned long long SendBufErr2; /* was Reserved6SBE[0/6] */ + unsigned long long Reserved6L[2]; + unsigned long long AvailUpdCount; + unsigned long long RcvHdrAddr0; + unsigned long long RcvHdrAddrs[16]; /* Why enumerate? */ + unsigned long long Reserved7hdtl; /* Align next to 300 */ + unsigned long long RcvHdrTailAddr0; /* 300, like others */ + unsigned long long RcvHdrTailAddrs[16]; + unsigned long long Reserved9SW[7]; /* was [8]; we have 17 ports */ + unsigned long long IbsdEpbAccCtl; /* IB Serdes EPB access control */ + unsigned long long IbsdEpbTransReg; /* IB Serdes EPB Transaction */ + unsigned long long Reserved10sds; /* was SerdesStatus on */ + unsigned long long XGXSConfig; + unsigned long long IBSerDesCtrl; /* Was IBPLLCfg on Monty */ + unsigned long long EEPCtlStat; /* for "boot" EEPROM/FLASH */ + unsigned long long EEPAddrCmd; + unsigned long long EEPData; + unsigned long long PcieEpbAccCtl; + unsigned long long PcieEpbTransCtl; + unsigned long long EfuseCtl; /* E-Fuse control */ + unsigned long long EfuseData[4]; + unsigned long long ProcMon; + /* this chip moves following two from previous 200, 208 */ + unsigned long long PCIeRBufTestReg0; + unsigned long long PCIeRBufTestReg1; + /* added for this chip */ + unsigned long long PCIeRBufTestReg2; + unsigned long long PCIeRBufTestReg3; + /* added for this chip, debug only */ + unsigned long long SPC_JTAG_ACCESS_REG; + unsigned long long LAControlReg; + unsigned long long GPIODebugSelReg; + unsigned long long DebugPortValueReg; + /* added for this chip, DMA */ + unsigned long long SendDmaBufUsed[3]; + unsigned long long SendDmaReqTagUsed; + /* + * added for this chip, EFUSE: note that these program 64-bit + * words 2 and 3 */ + unsigned long long efuse_pgm_data[2]; + unsigned long long Reserved11LAalign[10]; /* Skip 4B0..4F8 */ + /* we have 30 regs for DDS and RXEQ in IB SERDES */ + unsigned long long SerDesDDSRXEQ[30]; + unsigned long long Reserved12LAalign[2]; /* Skip 5F0, 5F8 */ + /* added for LA debug support */ + unsigned long long LAMemory[32]; +}; + +struct _infinipath_do_not_use_counters { + __u64 LBIntCnt; + __u64 LBFlowStallCnt; + __u64 TxSDmaDescCnt; /* was Reserved1 */ + __u64 TxUnsupVLErrCnt; + __u64 TxDataPktCnt; + __u64 TxFlowPktCnt; + __u64 TxDwordCnt; + __u64 TxLenErrCnt; + __u64 TxMaxMinLenErrCnt; + __u64 TxUnderrunCnt; + __u64 TxFlowStallCnt; + __u64 TxDroppedPktCnt; + __u64 RxDroppedPktCnt; + __u64 RxDataPktCnt; + __u64 RxFlowPktCnt; + __u64 RxDwordCnt; + __u64 RxLenErrCnt; + __u64 RxMaxMinLenErrCnt; + __u64 RxICRCErrCnt; + __u64 RxVCRCErrCnt; + __u64 RxFlowCtrlErrCnt; + __u64 RxBadFormatCnt; + __u64 RxLinkProblemCnt; + __u64 RxEBPCnt; + __u64 RxLPCRCErrCnt; + __u64 RxBufOvflCnt; + __u64 RxTIDFullErrCnt; + __u64 RxTIDValidErrCnt; + __u64 RxPKeyMismatchCnt; + __u64 RxP0HdrEgrOvflCnt; + __u64 RxP1HdrEgrOvflCnt; + __u64 RxP2HdrEgrOvflCnt; + __u64 RxP3HdrEgrOvflCnt; + __u64 RxP4HdrEgrOvflCnt; + __u64 RxP5HdrEgrOvflCnt; + __u64 RxP6HdrEgrOvflCnt; + __u64 RxP7HdrEgrOvflCnt; + __u64 RxP8HdrEgrOvflCnt; + __u64 RxP9HdrEgrOvflCnt; /* was Reserved6 */ + __u64 RxP10HdrEgrOvflCnt; /* was Reserved7 */ + __u64 RxP11HdrEgrOvflCnt; /* new for IBA7220 */ + __u64 RxP12HdrEgrOvflCnt; /* new for IBA7220 */ + __u64 RxP13HdrEgrOvflCnt; /* new for IBA7220 */ + __u64 RxP14HdrEgrOvflCnt; /* new for IBA7220 */ + __u64 RxP15HdrEgrOvflCnt; /* new for IBA7220 */ + __u64 RxP16HdrEgrOvflCnt; /* new for IBA7220 */ + __u64 IBStatusChangeCnt; + __u64 IBLinkErrRecoveryCnt; + __u64 IBLinkDownedCnt; + __u64 IBSymbolErrCnt; + /* The following are new for IBA7220 */ + __u64 RxVL15DroppedPktCnt; + __u64 RxOtherLocalPhyErrCnt; + __u64 PcieRetryBufDiagQwordCnt; + __u64 ExcessBufferOvflCnt; + __u64 LocalLinkIntegrityErrCnt; + __u64 RxVlErrCnt; + __u64 RxDlidFltrCnt; + __u64 Reserved8[7]; + __u64 PSStat; + __u64 PSStart; + __u64 PSInterval; + __u64 PSRcvDataCount; + __u64 PSRcvPktsCount; + __u64 PSXmitDataCount; + __u64 PSXmitPktsCount; + __u64 PSXmitWaitCount; +}; + +#define IPATH_KREG_OFFSET(field) (offsetof( \ + struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64)) +#define IPATH_CREG_OFFSET(field) (offsetof( \ + struct _infinipath_do_not_use_counters, field) / sizeof(u64)) + +static const struct ipath_kregs ipath_7220_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(SendAvailAddr), + .kr_sendpiobufbase = IPATH_KREG_OFFSET(SendBufBase), + .kr_sendpiobufcnt = IPATH_KREG_OFFSET(SendBufCnt), + .kr_sendpiosize = IPATH_KREG_OFFSET(SendBufSize), + .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_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig), + + /* send dma related regs */ + .kr_senddmabase = IPATH_KREG_OFFSET(SendDmaBase), + .kr_senddmalengen = IPATH_KREG_OFFSET(SendDmaLenGen), + .kr_senddmatail = IPATH_KREG_OFFSET(SendDmaTail), + .kr_senddmahead = IPATH_KREG_OFFSET(SendDmaHead), + .kr_senddmaheadaddr = IPATH_KREG_OFFSET(SendDmaHeadAddr), + .kr_senddmabufmask0 = IPATH_KREG_OFFSET(SendDmaBufMask0), + .kr_senddmabufmask1 = IPATH_KREG_OFFSET(SendDmaBufMask1), + .kr_senddmabufmask2 = IPATH_KREG_OFFSET(SendDmaBufMask2), + .kr_senddmastatus = IPATH_KREG_OFFSET(SendDmaStatus), + + /* SerDes related regs */ + .kr_ibserdesctrl = IPATH_KREG_OFFSET(IBSerDesCtrl), + .kr_ib_epbacc = IPATH_KREG_OFFSET(IbsdEpbAccCtl), + .kr_ib_epbtrans = IPATH_KREG_OFFSET(IbsdEpbTransReg), + .kr_pcie_epbacc = IPATH_KREG_OFFSET(PcieEpbAccCtl), + .kr_pcie_epbtrans = IPATH_KREG_OFFSET(PcieEpbTransCtl), + .kr_ib_ddsrxeq = IPATH_KREG_OFFSET(SerDesDDSRXEQ), + + /* + * 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), + + /* + * 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_hrtbt_guid = IPATH_KREG_OFFSET(HRTBT_GUID), + .kr_ibcddrctrl = IPATH_KREG_OFFSET(IBCDDRCtrl), + .kr_ibcddrstatus = IPATH_KREG_OFFSET(IBCDDRStatus), + .kr_jintreload = IPATH_KREG_OFFSET(JIntReload) +}; + +static const struct ipath_cregs ipath_7220_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), + .cr_vl15droppedpktcnt = IPATH_CREG_OFFSET(RxVL15DroppedPktCnt), + .cr_rxotherlocalphyerrcnt = + IPATH_CREG_OFFSET(RxOtherLocalPhyErrCnt), + .cr_excessbufferovflcnt = IPATH_CREG_OFFSET(ExcessBufferOvflCnt), + .cr_locallinkintegrityerrcnt = + IPATH_CREG_OFFSET(LocalLinkIntegrityErrCnt), + .cr_rxvlerrcnt = IPATH_CREG_OFFSET(RxVlErrCnt), + .cr_rxdlidfltrcnt = IPATH_CREG_OFFSET(RxDlidFltrCnt), + .cr_psstat = IPATH_CREG_OFFSET(PSStat), + .cr_psstart = IPATH_CREG_OFFSET(PSStart), + .cr_psinterval = IPATH_CREG_OFFSET(PSInterval), + .cr_psrcvdatacount = IPATH_CREG_OFFSET(PSRcvDataCount), + .cr_psrcvpktscount = IPATH_CREG_OFFSET(PSRcvPktsCount), + .cr_psxmitdatacount = IPATH_CREG_OFFSET(PSXmitDataCount), + .cr_psxmitpktscount = IPATH_CREG_OFFSET(PSXmitPktsCount), + .cr_psxmitwaitcount = IPATH_CREG_OFFSET(PSXmitWaitCount), +}; + +/* kr_control bits */ +#define INFINIPATH_C_RESET (1U<<7) + +/* kr_intstatus, kr_intclear, kr_intmask bits */ +#define INFINIPATH_I_RCVURG_MASK ((1ULL<<17)-1) +#define INFINIPATH_I_RCVURG_SHIFT 32 +#define INFINIPATH_I_RCVAVAIL_MASK ((1ULL<<17)-1) +#define INFINIPATH_I_RCVAVAIL_SHIFT 0 +#define INFINIPATH_I_SERDESTRIMDONE (1ULL<<27) + +/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */ +#define INFINIPATH_HWE_PCIEMEMPARITYERR_MASK 0x00000000000000ffULL +#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 +/* specific to this chip */ +#define INFINIPATH_HWE_PCIECPLDATAQUEUEERR 0x0000000000000040ULL +#define INFINIPATH_HWE_PCIECPLHDRQUEUEERR 0x0000000000000080ULL +#define INFINIPATH_HWE_SDMAMEMREADERR 0x0000000010000000ULL +#define INFINIPATH_HWE_CLK_UC_PLLNOTLOCKED 0x2000000000000000ULL +#define INFINIPATH_HWE_PCIESERDESQ0PCLKNOTDETECT 0x0100000000000000ULL +#define INFINIPATH_HWE_PCIESERDESQ1PCLKNOTDETECT 0x0200000000000000ULL +#define INFINIPATH_HWE_PCIESERDESQ2PCLKNOTDETECT 0x0400000000000000ULL +#define INFINIPATH_HWE_PCIESERDESQ3PCLKNOTDETECT 0x0800000000000000ULL +#define INFINIPATH_HWE_DDSRXEQMEMORYPARITYERR 0x0000008000000000ULL +#define INFINIPATH_HWE_IB_UC_MEMORYPARITYERR 0x0000004000000000ULL +#define INFINIPATH_HWE_PCIE_UC_OCT0MEMORYPARITYERR 0x0000001000000000ULL +#define INFINIPATH_HWE_PCIE_UC_OCT1MEMORYPARITYERR 0x0000002000000000ULL + +#define IBA7220_IBCS_LINKTRAININGSTATE_MASK 0x1F +#define IBA7220_IBCS_LINKSTATE_SHIFT 5 +#define IBA7220_IBCS_LINKSPEED_SHIFT 8 +#define IBA7220_IBCS_LINKWIDTH_SHIFT 9 + +#define IBA7220_IBCC_LINKINITCMD_MASK 0x7ULL +#define IBA7220_IBCC_LINKCMD_SHIFT 19 +#define IBA7220_IBCC_MAXPKTLEN_SHIFT 21 + +/* kr_ibcddrctrl bits */ +#define IBA7220_IBC_DLIDLMC_MASK 0xFFFFFFFFUL +#define IBA7220_IBC_DLIDLMC_SHIFT 32 +#define IBA7220_IBC_HRTBT_MASK 3 +#define IBA7220_IBC_HRTBT_SHIFT 16 +#define IBA7220_IBC_HRTBT_ENB 0x10000UL +#define IBA7220_IBC_LANE_REV_SUPPORTED (1<<8) +#define IBA7220_IBC_LREV_MASK 1 +#define IBA7220_IBC_LREV_SHIFT 8 +#define IBA7220_IBC_RXPOL_MASK 1 +#define IBA7220_IBC_RXPOL_SHIFT 7 +#define IBA7220_IBC_WIDTH_SHIFT 5 +#define IBA7220_IBC_WIDTH_MASK 0x3 +#define IBA7220_IBC_WIDTH_1X_ONLY (0<<IBA7220_IBC_WIDTH_SHIFT) +#define IBA7220_IBC_WIDTH_4X_ONLY (1<<IBA7220_IBC_WIDTH_SHIFT) +#define IBA7220_IBC_WIDTH_AUTONEG (2<<IBA7220_IBC_WIDTH_SHIFT) +#define IBA7220_IBC_SPEED_AUTONEG (1<<1) +#define IBA7220_IBC_SPEED_SDR (1<<2) +#define IBA7220_IBC_SPEED_DDR (1<<3) +#define IBA7220_IBC_SPEED_AUTONEG_MASK (0x7<<1) +#define IBA7220_IBC_IBTA_1_2_MASK (1) + +/* kr_ibcddrstatus */ +/* link latency shift is 0, don't bother defining */ +#define IBA7220_DDRSTAT_LINKLAT_MASK 0x3ffffff + +/* kr_extstatus bits */ +#define INFINIPATH_EXTS_FREQSEL 0x2 +#define INFINIPATH_EXTS_SERDESSEL 0x4 +#define INFINIPATH_EXTS_MEMBIST_ENDTEST 0x0000000000004000 +#define INFINIPATH_EXTS_MEMBIST_DISABLED 0x0000000000008000 + +/* kr_xgxsconfig bits */ +#define INFINIPATH_XGXS_RESET 0x5ULL +#define INFINIPATH_XGXS_FC_SAFE (1ULL<<63) + +/* kr_rcvpktledcnt */ +#define IBA7220_LEDBLINK_ON_SHIFT 32 /* 4ns period on after packet */ +#define IBA7220_LEDBLINK_OFF_SHIFT 0 /* 4ns period off before next on */ + +#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)) + +#define IBA7220_R_INTRAVAIL_SHIFT 17 +#define IBA7220_R_TAILUPD_SHIFT 35 +#define IBA7220_R_PORTCFG_SHIFT 36 + +#define INFINIPATH_JINT_PACKETSHIFT 16 +#define INFINIPATH_JINT_DEFAULT_IDLE_TICKS 0 +#define INFINIPATH_JINT_DEFAULT_MAX_PACKETS 0 + +#define IBA7220_HDRHEAD_PKTINT_SHIFT 32 /* interrupt cnt in upper 32 bits */ + +/* + * the size bits give us 2^N, in KB units. 0 marks as invalid, + * and 7 is reserved. We currently use only 2KB and 4KB + */ +#define IBA7220_TID_SZ_SHIFT 37 /* shift to 3bit size selector */ +#define IBA7220_TID_SZ_2K (1UL<<IBA7220_TID_SZ_SHIFT) /* 2KB */ +#define IBA7220_TID_SZ_4K (2UL<<IBA7220_TID_SZ_SHIFT) /* 4KB */ +#define IBA7220_TID_PA_SHIFT 11U /* TID addr in chip stored w/o low bits */ + +#define IPATH_AUTONEG_TRIES 5 /* sequential retries to negotiate DDR */ + +static char int_type[16] = "auto"; +module_param_string(interrupt_type, int_type, sizeof(int_type), 0444); +MODULE_PARM_DESC(int_type, " interrupt_type=auto|force_msi|force_intx\n"); + +/* packet rate matching delay; chip has support */ +static u8 rate_to_delay[2][2] = { + /* 1x, 4x */ + { 8, 2 }, /* SDR */ + { 4, 1 } /* DDR */ +}; + +/* 7220 specific hardware errors... */ +static const struct ipath_hwerror_msgs ipath_7220_hwerror_msgs[] = { + INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"), + INFINIPATH_HWE_MSG(PCIECPLTIMEOUT, "PCIe completion timeout"), + /* + * 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. + */ + INFINIPATH_HWE_MSG(PCIE1PLLFAILED, "PCIePLL1"), + INFINIPATH_HWE_MSG(PCIE0PLLFAILED, "PCIePLL0"), + INFINIPATH_HWE_MSG(PCIEBUSPARITYXTLH, "PCIe XTLH core parity"), + INFINIPATH_HWE_MSG(PCIEBUSPARITYXADM, "PCIe ADM TX core parity"), + INFINIPATH_HWE_MSG(PCIEBUSPARITYRADM, "PCIe ADM RX core parity"), + INFINIPATH_HWE_MSG(RXDSYNCMEMPARITYERR, "Rx Dsync"), + INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"), + INFINIPATH_HWE_MSG(PCIECPLDATAQUEUEERR, "PCIe cpl header queue"), + INFINIPATH_HWE_MSG(PCIECPLHDRQUEUEERR, "PCIe cpl data queue"), + INFINIPATH_HWE_MSG(SDMAMEMREADERR, "Send DMA memory read"), + INFINIPATH_HWE_MSG(CLK_UC_PLLNOTLOCKED, "uC PLL clock not locked"), + INFINIPATH_HWE_MSG(PCIESERDESQ0PCLKNOTDETECT, + "PCIe serdes Q0 no clock"), + INFINIPATH_HWE_MSG(PCIESERDESQ1PCLKNOTDETECT, + "PCIe serdes Q1 no clock"), + INFINIPATH_HWE_MSG(PCIESERDESQ2PCLKNOTDETECT, + "PCIe serdes Q2 no clock"), + INFINIPATH_HWE_MSG(PCIESERDESQ3PCLKNOTDETECT, + "PCIe serdes Q3 no clock"), + INFINIPATH_HWE_MSG(DDSRXEQMEMORYPARITYERR, + "DDS RXEQ memory parity"), + INFINIPATH_HWE_MSG(IB_UC_MEMORYPARITYERR, "IB uC memory parity"), + INFINIPATH_HWE_MSG(PCIE_UC_OCT0MEMORYPARITYERR, + "PCIe uC oct0 memory parity"), + INFINIPATH_HWE_MSG(PCIE_UC_OCT1MEMORYPARITYERR, + "PCIe uC oct1 memory parity"), +}; + +static void autoneg_work(struct work_struct *); + +/* + * the offset is different for different configured port numbers, since + * port0 is fixed in size, but others can vary. Make it a function to + * make the issue more obvious. +*/ +static inline u32 port_egrtid_idx(struct ipath_devdata *dd, unsigned port) +{ + return port ? dd->ipath_p0_rcvegrcnt + + (port-1) * dd->ipath_rcvegrcnt : 0; +} + +static void ipath_7220_txe_recover(struct ipath_devdata *dd) +{ + ++ipath_stats.sps_txeparity; + + dev_info(&dd->pcidev->dev, + "Recovering from TXE PIO parity error\n"); + ipath_disarm_senderrbufs(dd, 1); +} + + +/** + * ipath_7220_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. + */ +static void ipath_7220_handle_hwerrors(struct ipath_devdata *dd, char *msg, + size_t msgl) +{ + ipath_err_t hwerrs; + u32 bits, ctrl; + int isfatal = 0; + char bitsmsg[64]; + int log_idx; + + 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"); + goto bail; + } else if (hwerrs == ~0ULL) { + ipath_dev_err(dd, "Read of hardware error status failed " + "(all bits set); ignoring\n"); + goto bail; + } + 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; + + /* We log some errors to EEPROM, check if we have any of those. */ + for (log_idx = 0; log_idx < IPATH_EEP_LOG_CNT; ++log_idx) + if (hwerrs & dd->ipath_eep_st_masks[log_idx].hwerrs_to_log) + ipath_inc_eeprom_err(dd, log_idx, 1); + /* + * 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 | + ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | + INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) + << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT))) || + (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 & ~dd->ipath_hwe_bitsextant) + ipath_dev_err(dd, "hwerror interrupt with unknown errors " + "%llx set\n", (unsigned long long) + (hwerrs & ~dd->ipath_hwe_bitsextant)); + + if (hwerrs & INFINIPATH_HWE_IB_UC_MEMORYPARITYERR) + ipath_sd7220_clr_ibpar(dd); + + ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control); + if ((ctrl & INFINIPATH_C_FREEZEMODE) && !ipath_diag_inuse) { + /* + * Parity errors in send memory are recoverable, + * just cancel the send (if indicated in * sendbuffererror), + * count the occurrence, unfreeze (if no other handled + * hardware error bits are set), and continue. + */ + if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | + INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) + << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) { + ipath_7220_txe_recover(dd); + hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | + INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) + << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT); + if (!hwerrs) { + /* else leave in freeze mode */ + ipath_write_kreg(dd, + dd->ipath_kregs->kr_control, + dd->ipath_control); + goto bail; + } + } + 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 + * Force link down, so switch knows, and + * LEDs are turned off. + */ + if (dd->ipath_flags & IPATH_INITTED) { + ipath_set_linkstate(dd, IPATH_IB_LINKDOWN); + ipath_setup_7220_setextled(dd, + INFINIPATH_IBCS_L_STATE_DOWN, + INFINIPATH_IBCS_LT_STATE_DISABLED); + ipath_dev_err(dd, "Fatal Hardware Error " + "(freeze mode), no longer" + " usable, SN %.16s\n", + dd->ipath_serial); + 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"); + ipath_clear_freeze(dd); + } + } + + *msg = '\0'; + + if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) { + strlcat(msg, "[Memory BIST test failed, " + "InfiniPath hardware 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); + } + + ipath_format_hwerrors(hwerrs, + ipath_7220_hwerror_msgs, + ARRAY_SIZE(ipath_7220_hwerror_msgs), + msg, 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); + } + +#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \ + INFINIPATH_HWE_COREPLL_RFSLIP) + + if (hwerrs & _IPATH_PLL_FAIL) { + snprintf(bitsmsg, sizeof bitsmsg, + "[PLL failed (%llx), InfiniPath hardware 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); + } + + ipath_dev_err(dd, "%s hardware error\n", msg); + /* + * For /sys status file. if no trailing } is copied, we'll + * know it was truncated. + */ + if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) + snprintf(dd->ipath_freezemsg, dd->ipath_freezelen, + "{%s}", msg); +bail:; +} + +/** + * ipath_7220_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_7220_boardname(struct ipath_devdata *dd, char *name, + size_t namelen) +{ + char *n = NULL; + u8 boardrev = dd->ipath_boardrev; + int ret; + + if (boardrev == 15) { + /* + * Emulator sometimes comes up all-ones, rather than zero. + */ + boardrev = 0; + dd->ipath_boardrev = boardrev; + } + switch (boardrev) { + case 0: + n = "InfiniPath_7220_Emulation"; + break; + case 1: + n = "InfiniPath_QLE7240"; + break; + case 2: + n = "InfiniPath_QLE7280"; + break; + case 3: + n = "InfiniPath_QLE7242"; + break; + case 4: + n = "InfiniPath_QEM7240"; + break; + case 5: + n = "InfiniPath_QMI7240"; + break; + case 6: + n = "InfiniPath_QMI7264"; + break; + case 7: + n = "InfiniPath_QMH7240"; + break; + case 8: + n = "InfiniPath_QME7240"; + break; + case 9: + n = "InfiniPath_QLE7250"; + break; + case 10: + n = "InfiniPath_QLE7290"; + break; + case 11: + n = "InfiniPath_QEM7250"; + break; + case 12: + n = "InfiniPath_QLE-Bringup"; + break; + default: + ipath_dev_err(dd, + "Don't yet know about board with ID %u\n", + boardrev); + snprintf(name, namelen, "Unknown_InfiniPath_PCIe_%u", + boardrev); + break; + } + if (n) + snprintf(name, namelen, "%s", n); + + if (dd->ipath_majrev != 5 || !dd->ipath_minrev || + dd->ipath_minrev > 2) { + ipath_dev_err(dd, "Unsupported InfiniPath hardware " + "revision %u.%u!\n", + dd->ipath_majrev, dd->ipath_minrev); + ret = 1; + } else if (dd->ipath_minrev == 1) { + /* Rev1 chips are prototype. Complain, but allow use */ + ipath_dev_err(dd, "Unsupported hardware " + "revision %u.%u, Contact support@qlogic.com\n", + dd->ipath_majrev, dd->ipath_minrev); + ret = 0; + } else + ret = 0; + + /* + * Set here not in ipath_init_*_funcs because we have to do + * it after we can read chip registers. + */ + dd->ipath_ureg_align = 0x10000; /* 64KB alignment */ + + return ret; +} + +/** + * ipath_7220_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 + */ +static void ipath_7220_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 | + INFINIPATH_EXTS_MEMBIST_DISABLED))) + ipath_dev_err(dd, "MemBIST did not complete!\n"); + if (extsval & INFINIPATH_EXTS_MEMBIST_DISABLED) + dev_info(&dd->pcidev->dev, "MemBIST is disabled.\n"); + + val = ~0ULL; /* barring bugs, all hwerrors become interrupts, */ + + if (!dd->ipath_boardrev) /* no PLL for Emulator */ + val &= ~INFINIPATH_HWE_SERDESPLLFAILED; + + if (dd->ipath_minrev == 1) + val &= ~(1ULL << 42); /* TXE LaunchFIFO Parity rev1 issue */ + + val &= ~INFINIPATH_HWE_IB_UC_MEMORYPARITYERR; + dd->ipath_hwerrmask = val; + + /* + * special trigger "error" is for debugging purposes. It + * works around a processor/chipset problem. The error + * interrupt allows us to count occurrences, but we don't + * want to pay the overhead for normal use. Emulation only + */ + if (!dd->ipath_boardrev) + dd->ipath_maskederrs = INFINIPATH_E_SENDSPECIALTRIGGER; +} + +/* + * All detailed interaction with the SerDes has been moved to ipath_sd7220.c + * + * The portion of IBA7220-specific bringup_serdes() that actually deals with + * registers and memory within the SerDes itself is ipath_sd7220_init(). + */ + +/** + * ipath_7220_bringup_serdes - bring up the serdes + * @dd: the infinipath device + */ +static int ipath_7220_bringup_serdes(struct ipath_devdata *dd) +{ + int ret = 0; + u64 val, prev_val, guid; + int was_reset; /* Note whether uC was reset */ + + 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); + } + + if (!dd->ipath_ibcddrctrl) { + /* not on re-init after reset */ + dd->ipath_ibcddrctrl = + ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcddrctrl); + + if (dd->ipath_link_speed_enabled == + (IPATH_IB_SDR | IPATH_IB_DDR)) + dd->ipath_ibcddrctrl |= + IBA7220_IBC_SPEED_AUTONEG_MASK | + IBA7220_IBC_IBTA_1_2_MASK; + else + dd->ipath_ibcddrctrl |= + dd->ipath_link_speed_enabled == IPATH_IB_DDR + ? IBA7220_IBC_SPEED_DDR : + IBA7220_IBC_SPEED_SDR; + if ((dd->ipath_link_width_enabled & (IB_WIDTH_1X | + IB_WIDTH_4X)) == (IB_WIDTH_1X | IB_WIDTH_4X)) + dd->ipath_ibcddrctrl |= IBA7220_IBC_WIDTH_AUTONEG; + else + dd->ipath_ibcddrctrl |= |