[openib-general] [PATCH 12 of 20] ipath - misc driver support code
Bryan O'Sullivan
bos at pathscale.com
Wed Dec 28 16:31:31 PST 2005
Signed-off-by: Bryan O'Sullivan <bos at pathscale.com>
diff -r e8af3873b0d9 -r 5e9b0b7876e2 drivers/infiniband/hw/ipath/ipath_ht400.c
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/drivers/infiniband/hw/ipath/ipath_ht400.c Wed Dec 28 14:19:43 2005 -0800
@@ -0,0 +1,1137 @@
+/*
+ * 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.
+ *
+ * Patent licenses, if any, provided herein do not apply to
+ * combinations of this program with other software, or any other
+ * product whatsoever.
+ */
+
+/*
+ * The first part of this file is shared with the diags, the second
+ * part is used only in the kernel.
+ */
+
+#include <stddef.h> /* for offsetof */
+
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include "ipath_kernel.h"
+
+#include "ipath_registers.h"
+#include "ipath_common.h"
+
+/*
+ * This lists the InfiniPath registers, in the actual chip layout. This
+ * structure should never be directly accessed. It is included by the
+ * user mode diags, and so must be able to be compiled in both user
+ * and kernel mode.
+ */
+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 DebugPort;
+ unsigned long long SendRegBase;
+ unsigned long long UserRegBase;
+ unsigned long long CounterRegBase;
+ unsigned long long Scratch;
+ unsigned long long ReservedMisc1;
+ unsigned long long InterruptConfig;
+ 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 ReservedRcv[10];
+ 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 ReservedSend[9];
+ unsigned long long SendBufferError;
+ unsigned long long SendBufferErrorCONT1;
+ unsigned long long SendBufferErrorCONT2;
+ unsigned long long SendBufferErrorCONT3;
+ unsigned long long ReservedSBE[4];
+ unsigned long long RcvHdrAddr0;
+ unsigned long long RcvHdrAddr1;
+ unsigned long long RcvHdrAddr2;
+ unsigned long long RcvHdrAddr3;
+ unsigned long long RcvHdrAddr4;
+ unsigned long long RcvHdrAddr5;
+ unsigned long long RcvHdrAddr6;
+ unsigned long long RcvHdrAddr7;
+ unsigned long long RcvHdrAddr8;
+ unsigned long long ReservedRHA[7];
+ unsigned long long RcvHdrTailAddr0;
+ unsigned long long RcvHdrTailAddr1;
+ unsigned long long RcvHdrTailAddr2;
+ unsigned long long RcvHdrTailAddr3;
+ unsigned long long RcvHdrTailAddr4;
+ unsigned long long RcvHdrTailAddr5;
+ unsigned long long RcvHdrTailAddr6;
+ unsigned long long RcvHdrTailAddr7;
+ unsigned long long RcvHdrTailAddr8;
+ unsigned long long ReservedRHTA[7];
+ unsigned long long Sync; /* Software only */
+ unsigned long long Dump; /* Software only */
+ unsigned long long SimVer; /* Software only */
+ unsigned long long ReservedSW[5];
+ unsigned long long SerdesConfig0;
+ unsigned long long SerdesConfig1;
+ unsigned long long SerdesStatus;
+ unsigned long long XGXSConfig;
+ unsigned long long ReservedSW2[4];
+};
+
+#define IPATH_KREG_OFFSET(field) (offsetof(struct \
+ _infinipath_do_not_use_kernel_regs, field) / sizeof(uint64_t))
+#define IPATH_CREG_OFFSET(field) (offsetof( \
+ struct infinipath_counters, field) / sizeof(uint64_t))
+
+ipath_kreg
+ kr_control = IPATH_KREG_OFFSET(Control),
+ kr_counterregbase = IPATH_KREG_OFFSET(CounterRegBase),
+ kr_debugport = IPATH_KREG_OFFSET(DebugPort),
+ 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_interruptconfig = IPATH_KREG_OFFSET(InterruptConfig),
+ 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_sendbuffererror1 = IPATH_KREG_OFFSET(SendBufferErrorCONT1),
+ kr_sendbuffererror2 = IPATH_KREG_OFFSET(SendBufferErrorCONT2),
+ kr_sendbuffererror3 = IPATH_KREG_OFFSET(SendBufferErrorCONT3),
+ 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),
+ /*
+ * last valid direct use register other than diag-only registers
+ */
+ __kr_lastvaliddirect = IPATH_KREG_OFFSET(ReservedSW2[0]),
+ /* always invalid for initializing */
+ __kr_invalid = IPATH_KREG_OFFSET(ReservedSW2[0]) + 1,
+ /*
+ * These should not be used directly via ipath_kget_kreg64(),
+ * use them with ipath_kget_kreg64_port()
+ */
+ kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0), /* not for direct use */
+ /* not for direct use */
+ kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0),
+ /* we define the full set for the diags, the kernel doesn't use them */
+ kr_rcvhdraddr1 = IPATH_KREG_OFFSET(RcvHdrAddr1),
+ kr_rcvhdraddr2 = IPATH_KREG_OFFSET(RcvHdrAddr2),
+ kr_rcvhdraddr3 = IPATH_KREG_OFFSET(RcvHdrAddr3),
+ kr_rcvhdraddr4 = IPATH_KREG_OFFSET(RcvHdrAddr4),
+ kr_rcvhdrtailaddr1 = IPATH_KREG_OFFSET(RcvHdrTailAddr1),
+ kr_rcvhdrtailaddr2 = IPATH_KREG_OFFSET(RcvHdrTailAddr2),
+ kr_rcvhdrtailaddr3 = IPATH_KREG_OFFSET(RcvHdrTailAddr3),
+ kr_rcvhdrtailaddr4 = IPATH_KREG_OFFSET(RcvHdrTailAddr4),
+ kr_rcvhdraddr5 = IPATH_KREG_OFFSET(RcvHdrAddr5),
+ kr_rcvhdraddr6 = IPATH_KREG_OFFSET(RcvHdrAddr6),
+ kr_rcvhdraddr7 = IPATH_KREG_OFFSET(RcvHdrAddr7),
+ kr_rcvhdraddr8 = IPATH_KREG_OFFSET(RcvHdrAddr8),
+ kr_rcvhdrtailaddr5 = IPATH_KREG_OFFSET(RcvHdrTailAddr5),
+ kr_rcvhdrtailaddr6 = IPATH_KREG_OFFSET(RcvHdrTailAddr6),
+ kr_rcvhdrtailaddr7 = IPATH_KREG_OFFSET(RcvHdrTailAddr7),
+ kr_rcvhdrtailaddr8 = IPATH_KREG_OFFSET(RcvHdrTailAddr8);
+
+/*
+ * first of the pioavail registers, the total number is
+ * (kr_sendpiobufcnt / 32); each buffer uses 2 bits
+ * More properly, it's:
+ * (kr_sendpiobufcnt / ((sizeof(uint64_t)*BITS_PER_BYTE)/2))
+ */
+ipath_sreg sr_sendpioavail = 0;
+
+ipath_creg
+ 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),
+ /* calc from Reg_CounterRegBase + offset */
+ 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_portovflcnt1 = IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt),
+ cr_portovflcnt2 = IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt),
+ cr_portovflcnt3 = IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt),
+ cr_portovflcnt4 = IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt),
+ cr_portovflcnt5 = IPATH_CREG_OFFSET(RxP5HdrEgrOvflCnt),
+ cr_portovflcnt6 = IPATH_CREG_OFFSET(RxP6HdrEgrOvflCnt),
+ cr_portovflcnt7 = IPATH_CREG_OFFSET(RxP7HdrEgrOvflCnt),
+ cr_portovflcnt8 = IPATH_CREG_OFFSET(RxP8HdrEgrOvflCnt),
+ 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_sendctrl bits */
+#define INFINIPATH_S_DISARMPIOBUF_MASK 0xFF
+
+/* kr_rcvctrl bits */
+#define INFINIPATH_R_PORTENABLE_MASK 0x1FF
+#define INFINIPATH_R_INTRAVAIL_MASK 0x1FF
+
+/* kr_intstatus, kr_intclear, kr_intmask bits */
+#define INFINIPATH_I_RCVURG_MASK 0x1FF
+#define INFINIPATH_I_RCVAVAIL_MASK 0x1FF
+
+/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
+#define INFINIPATH_HWE_HTCMEMPARITYERR_MASK 0x3FFFFFULL
+#define INFINIPATH_HWE_HTCLNKABYTE0CRCERR 0x0000000000800000ULL
+#define INFINIPATH_HWE_HTCLNKABYTE1CRCERR 0x0000000001000000ULL
+#define INFINIPATH_HWE_HTCLNKBBYTE0CRCERR 0x0000000002000000ULL
+#define INFINIPATH_HWE_HTCLNKBBYTE1CRCERR 0x0000000004000000ULL
+#define INFINIPATH_HWE_HTCMISCERR4 0x0000000008000000ULL
+#define INFINIPATH_HWE_HTCMISCERR5 0x0000000010000000ULL
+#define INFINIPATH_HWE_HTCMISCERR6 0x0000000020000000ULL
+#define INFINIPATH_HWE_HTCMISCERR7 0x0000000040000000ULL
+#define INFINIPATH_HWE_MEMBISTFAILED 0x0040000000000000ULL
+#define INFINIPATH_HWE_COREPLL_FBSLIP 0x0080000000000000ULL
+#define INFINIPATH_HWE_COREPLL_RFSLIP 0x0100000000000000ULL
+#define INFINIPATH_HWE_HTBPLL_FBSLIP 0x0200000000000000ULL
+#define INFINIPATH_HWE_HTBPLL_RFSLIP 0x0400000000000000ULL
+#define INFINIPATH_HWE_HTAPLL_FBSLIP 0x0800000000000000ULL
+#define INFINIPATH_HWE_HTAPLL_RFSLIP 0x1000000000000000ULL
+#define INFINIPATH_HWE_EXTSERDESPLLFAILED 0x2000000000000000ULL
+
+/* kr_hwdiagctrl bits */
+#define INFINIPATH_DC_NUMHTMEMS 22
+
+/* kr_extstatus bits */
+#define INFINIPATH_EXTS_FREQSEL 0x2
+#define INFINIPATH_EXTS_SERDESSEL 0x4
+#define INFINIPATH_EXTS_MEMBIST_ENDTEST 0x0000000000004000
+#define INFINIPATH_EXTS_MEMBIST_CORRECT 0x0000000000008000
+
+/* kr_extctrl bits */
+
+/*
+ * masks and bits that are different in different chips, or present only
+ * in one
+ */
+const uint32_t infinipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
+const uint32_t infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+const uint64_t infinipath_hwe_htcmemparityerr_mask =
+ INFINIPATH_HWE_HTCMEMPARITYERR_MASK;
+
+const uint64_t infinipath_hwe_spibdcmlockfailed_mask = 0ULL;
+const uint64_t infinipath_hwe_sphtdcmlockfailed_mask = 0ULL;
+const uint64_t infinipath_hwe_htcdcmlockfailed_mask = 0ULL;
+const uint64_t infinipath_hwe_htcdcmlockfailed_shift = 0ULL;
+const uint64_t infinipath_hwe_sphtdcmlockfailed_shift = 0ULL;
+const uint64_t infinipath_hwe_spibdcmlockfailed_shift = 0ULL;
+
+const uint64_t infinipath_hwe_htclnkabyte0crcerr =
+ INFINIPATH_HWE_HTCLNKABYTE0CRCERR;
+const uint64_t infinipath_hwe_htclnkabyte1crcerr =
+ INFINIPATH_HWE_HTCLNKABYTE1CRCERR;
+const uint64_t infinipath_hwe_htclnkbbyte0crcerr =
+ INFINIPATH_HWE_HTCLNKBBYTE0CRCERR;
+const uint64_t infinipath_hwe_htclnkbbyte1crcerr =
+ INFINIPATH_HWE_HTCLNKBBYTE1CRCERR;
+
+const uint64_t infinipath_c_bitsextant =
+ (INFINIPATH_C_FREEZEMODE | INFINIPATH_C_LINKENABLE);
+
+const uint64_t infinipath_s_bitsextant =
+ (INFINIPATH_S_ABORT | INFINIPATH_S_PIOINTBUFAVAIL |
+ INFINIPATH_S_PIOBUFAVAILUPD | INFINIPATH_S_PIOENABLE |
+ INFINIPATH_S_DISARM |
+ (INFINIPATH_S_DISARMPIOBUF_MASK << INFINIPATH_S_DISARMPIOBUF_SHIFT));
+
+const uint64_t infinipath_r_bitsextant =
+ ((INFINIPATH_R_PORTENABLE_MASK << INFINIPATH_R_PORTENABLE_SHIFT) |
+ (INFINIPATH_R_INTRAVAIL_MASK << INFINIPATH_R_INTRAVAIL_SHIFT) |
+ INFINIPATH_R_TAILUPD);
+
+const uint64_t infinipath_i_bitsextant =
+ ((INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
+ (INFINIPATH_I_RCVAVAIL_MASK << INFINIPATH_I_RCVAVAIL_SHIFT) |
+ INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
+ INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO);
+
+const uint64_t infinipath_e_bitsextant =
+ (INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC | INFINIPATH_E_RICRC |
+ INFINIPATH_E_RMINPKTLEN | INFINIPATH_E_RMAXPKTLEN |
+ INFINIPATH_E_RLONGPKTLEN | INFINIPATH_E_RSHORTPKTLEN |
+ INFINIPATH_E_RUNEXPCHAR | INFINIPATH_E_RUNSUPVL | INFINIPATH_E_REBP |
+ INFINIPATH_E_RIBFLOW | INFINIPATH_E_RBADVERSION |
+ INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
+ INFINIPATH_E_RBADTID | INFINIPATH_E_RHDRLEN |
+ INFINIPATH_E_RHDR | INFINIPATH_E_RIBLOSTLINK |
+ INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SMAXPKTLEN |
+ INFINIPATH_E_SUNDERRUN | INFINIPATH_E_SPKTLEN |
+ INFINIPATH_E_SDROPPEDSMPPKT | INFINIPATH_E_SDROPPEDDATAPKT |
+ INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM |
+ INFINIPATH_E_SUNSUPVL | INFINIPATH_E_IBSTATUSCHANGED |
+ INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET | INFINIPATH_E_HARDWARE);
+
+const uint64_t infinipath_hwe_bitsextant =
+ (INFINIPATH_HWE_HTCMEMPARITYERR_MASK <<
+ INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) |
+ (INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
+ INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) |
+ (INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
+ INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) |
+ INFINIPATH_HWE_HTCLNKABYTE0CRCERR |
+ INFINIPATH_HWE_HTCLNKABYTE1CRCERR | INFINIPATH_HWE_HTCLNKBBYTE0CRCERR |
+ INFINIPATH_HWE_HTCLNKBBYTE1CRCERR | INFINIPATH_HWE_HTCMISCERR4 |
+ INFINIPATH_HWE_HTCMISCERR5 | INFINIPATH_HWE_HTCMISCERR6 |
+ INFINIPATH_HWE_HTCMISCERR7 | INFINIPATH_HWE_HTCBUSTREQPARITYERR |
+ INFINIPATH_HWE_HTCBUSTRESPPARITYERR |
+ INFINIPATH_HWE_HTCBUSIREQPARITYERR |
+ INFINIPATH_HWE_RXDSYNCMEMPARITYERR | INFINIPATH_HWE_MEMBISTFAILED |
+ INFINIPATH_HWE_COREPLL_FBSLIP | INFINIPATH_HWE_COREPLL_RFSLIP |
+ INFINIPATH_HWE_HTBPLL_FBSLIP | INFINIPATH_HWE_HTBPLL_RFSLIP |
+ INFINIPATH_HWE_HTAPLL_FBSLIP | INFINIPATH_HWE_HTAPLL_RFSLIP |
+ INFINIPATH_HWE_EXTSERDESPLLFAILED |
+ INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
+ INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;
+
+const uint64_t infinipath_dc_bitsextant =
+ (INFINIPATH_DC_FORCEHTCMEMPARITYERR_MASK <<
+ INFINIPATH_DC_FORCEHTCMEMPARITYERR_SHIFT) |
+ (INFINIPATH_DC_FORCETXEMEMPARITYERR_MASK <<
+ INFINIPATH_DC_FORCETXEMEMPARITYERR_SHIFT) |
+ (INFINIPATH_DC_FORCERXEMEMPARITYERR_MASK <<
+ INFINIPATH_DC_FORCERXEMEMPARITYERR_SHIFT) |
+ INFINIPATH_DC_FORCEHTCBUSTREQPARITYERR |
+ INFINIPATH_DC_FORCEHTCBUSTRESPPARITYERR |
+ INFINIPATH_DC_FORCEHTCBUSIREQPARITYERR |
+ INFINIPATH_DC_FORCERXDSYNCMEMPARITYERR |
+ INFINIPATH_DC_COUNTERDISABLE | INFINIPATH_DC_COUNTERWREN |
+ INFINIPATH_DC_FORCEIBCBUSTOSPCPARITYERR |
+ INFINIPATH_DC_FORCEIBCBUSFRSPCPARITYERR;
+
+const uint64_t infinipath_ibcc_bitsextant =
+ (INFINIPATH_IBCC_FLOWCTRLPERIOD_MASK <<
+ INFINIPATH_IBCC_FLOWCTRLPERIOD_SHIFT) |
+ (INFINIPATH_IBCC_FLOWCTRLWATERMARK_MASK <<
+ INFINIPATH_IBCC_FLOWCTRLWATERMARK_SHIFT) |
+ (INFINIPATH_IBCC_LINKINITCMD_MASK <<
+ INFINIPATH_IBCC_LINKINITCMD_SHIFT) |
+ (INFINIPATH_IBCC_LINKCMD_MASK << INFINIPATH_IBCC_LINKCMD_SHIFT) |
+ (INFINIPATH_IBCC_MAXPKTLEN_MASK << INFINIPATH_IBCC_MAXPKTLEN_SHIFT) |
+ (INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK <<
+ INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) |
+ (INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK <<
+ INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) |
+ (INFINIPATH_IBCC_CREDITSCALE_MASK <<
+ INFINIPATH_IBCC_CREDITSCALE_SHIFT) |
+ INFINIPATH_IBCC_LOOPBACK | INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
+
+const uint64_t infinipath_mdio_bitsextant =
+ (INFINIPATH_MDIO_CLKDIV_MASK << INFINIPATH_MDIO_CLKDIV_SHIFT) |
+ (INFINIPATH_MDIO_COMMAND_MASK << INFINIPATH_MDIO_COMMAND_SHIFT) |
+ (INFINIPATH_MDIO_DEVADDR_MASK << INFINIPATH_MDIO_DEVADDR_SHIFT) |
+ (INFINIPATH_MDIO_REGADDR_MASK << INFINIPATH_MDIO_REGADDR_SHIFT) |
+ (INFINIPATH_MDIO_DATA_MASK << INFINIPATH_MDIO_DATA_SHIFT) |
+ INFINIPATH_MDIO_CMDVALID | INFINIPATH_MDIO_RDDATAVALID;
+
+const uint64_t infinipath_ibcs_bitsextant =
+ (INFINIPATH_IBCS_LINKTRAININGSTATE_MASK <<
+ INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+ (INFINIPATH_IBCS_LINKSTATE_MASK << INFINIPATH_IBCS_LINKSTATE_SHIFT) |
+ INFINIPATH_IBCS_TXREADY | INFINIPATH_IBCS_TXCREDITOK;
+
+const uint64_t infinipath_extc_bitsextant =
+ (INFINIPATH_EXTC_GPIOINVERT_MASK << INFINIPATH_EXTC_GPIOINVERT_SHIFT) |
+ (INFINIPATH_EXTC_GPIOOE_MASK << INFINIPATH_EXTC_GPIOOE_SHIFT) |
+ INFINIPATH_EXTC_SERDESENABLE | INFINIPATH_EXTC_SERDESCONNECT |
+ INFINIPATH_EXTC_SERDESENTRUNKING | INFINIPATH_EXTC_SERDESDISRXFIFO |
+ INFINIPATH_EXTC_SERDESENPLPBK1 | INFINIPATH_EXTC_SERDESENPLPBK2 |
+ INFINIPATH_EXTC_SERDESENENCDEC | INFINIPATH_EXTC_LEDSECPORTGREENON |
+ INFINIPATH_EXTC_LEDSECPORTYELLOWON | INFINIPATH_EXTC_LEDPRIPORTGREENON |
+ INFINIPATH_EXTC_LEDPRIPORTYELLOWON | INFINIPATH_EXTC_LEDGBLOKGREENON |
+ INFINIPATH_EXTC_LEDGBLERRREDOFF;
+
+/* Start of Documentation block for SerDes registers
+ * serdes and xgxs register bits; not all have defines,
+ * since I haven't yet needed them all, and I'm lazy. Those that I needed
+ * are in ipath_registers.h
+
+serdesConfig0Out (R/W)
+ Default Value
+bit[3:0] - ResetA/B/C/D (4'b1111)
+bit[7:4] -L1PwrdnA/B/C/D (4'b0000)
+bit[11:8] - RxIdleEnX (4'b0000)
+bit[15:12] - TxIdleEnX (4'b0000)
+bit[19:16] - RxDetectEnX (4'b0000)
+bit[23:20] - BeaconTxEnX (4'b0000)
+bit[27:24] - RxTermEnX (4'b0000)
+bit[28] - ResetPLL (1'b0)
+bit[29] -L2Pwrdn (1'b0)
+bit[37:30] - Offset[7:0] (8'b00000000)
+bit[38] -OffsetEn (1'b0)
+bit[39] -ParLBPK (1'b0)
+bit[40] -ParReset (1'b0)
+bit[42:41] - RefSel (2'b10)
+bit[43] - PW (1'b0)
+bit[47:44] - LPBKA/B/C/D (4'b0000)
+bit[49:48] - ClkBufTermAdj (2'b0)
+bit[51:50] - RxTermAdj (2'b0)
+bit[53:52] - TxTermAdj (2'b0)
+bit[55:54] - RxEqCtl (2'b0)
+bit[63:56] - Reserved
+
+cce_wip_serdesConfig1Out[63:0] (R/W)
+bit[3:0] - HiDrvX (4'b0000)
+bit[7:4] - LoDrvX (4'b0000)
+bit[12:11] - DtxA[3:0] (4'b0000)
+bit[15:12] - DtxB[3:0] (4'b0000)
+bit[19:16] - DtxC[3:0] (4'b0000)
+bit[23:20] - DtxD[3:0] (4'b0000)
+bit[27:24] - DeqA[3:0] (4'b0000)
+bit[31:28] - DeqB[3:0] (4'b0000)
+bit[35:32] - DeqC[3:0] (4'b0000)
+bit[39:36] - DeqD[3:0] (4'b0000)
+Framer interface, bits 40-59, not used
+bit[44:40] - FmOffsetA[4:0] (5'b00000)
+bit[49:45] - FmOffsetB[4:0] (5'b00000)
+bit[54:50] - FmOffsetC[4:0] (5'b00000)
+bit[59:55] - FmOffsetD[4:0] (5'b00000)
+bit[63:60] - FmOffsetEnA/B/C/D (4'b0000)
+
+SerdesStatus[63:0] (RO)
+bit[3:0] - TxIdleDetectA/B/C/D
+bit[7:4] - RxDetectA/B/C/D
+bit[11:8] - BeaconDetectA/B/C/D
+bit[63:12] - Reserved
+
+XGXSConfigOut[63:0]
+bit[2:0] - Resets, init to 1; bit 0 unused?
+bit[3] - MDIO, select register bank for vendor specific register
+ (0x1e if set, else 0x1f); vendor-specific status in register 8
+ bits 0-3 lanes0-3 signal detect, 1 if detected
+ bits 4-7 lanes0-3 CTC fifo errors, 1 if detected (latched until read)
+bit[8:4] - MDIO port address
+bit[18:9] - lnk_sync_mask
+bit[22:19] - polarity inv
+
+Documentation end */
+
+/*
+ *
+ * General specs:
+ * ExtCtrl[63:48] = EXTC_GPIOOE[15:0]
+ * ExtCtrl[47:32] = EXTC_GPIOInvert[15:0]
+ * ExtStatus[63:48] = GpioIn[15:0]
+ *
+ * GPIO[1] = EEPROM_SDA
+ * GPIO[0] = EEPROM_SCL
+ */
+
+#define _IPATH_GPIO_SDA_NUM 1
+#define _IPATH_GPIO_SCL_NUM 0
+
+#define IPATH_GPIO_SDA \
+ (1UL << (_IPATH_GPIO_SDA_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
+#define IPATH_GPIO_SCL \
+ (1UL << (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
+
+/*
+ * register bits for selecting i2c direction and values, used for I2C serial
+ * flash
+ */
+const uint16_t ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
+const uint16_t ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
+const uint64_t ipath_gpio_sda = IPATH_GPIO_SDA;
+const uint64_t ipath_gpio_scl = IPATH_GPIO_SCL;
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+
+/*
+ * This file contains all of the code that is specific to the InfiniPath
+ * HT-400 chip.
+ */
+
+/* we support up to 4 chips per system */
+const uint32_t infinipath_max = 4;
+struct ipath_devdata devdata[4];
+static const char *ipath_unit_names[4] = {
+ "infinipath0", "infinipath1", "infinipath2", "infinipath3"
+};
+
+const char *ipath_get_unit_name(int unit)
+{
+ return ipath_unit_names[unit];
+}
+
+static void ipath_check_htlink(ipath_type t);
+
+/*
+ * display hardware errors. 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_handle_hwerrors(const ipath_type t, char *msg, int msgl)
+{
+ uint64_t hwerrs = ipath_kget_kreg64(t, kr_hwerrstatus);
+ uint32_t bits, ctrl;
+ int isfatal = 0;
+ char bitsmsg[64];
+
+ if (!hwerrs) {
+ _IPATH_VDBG("Called but no hardware errors set\n");
+ /*
+ * better than printing cofusing messages
+ * This seems to be related to clearing the crc error, or
+ * the pll error during init.
+ */
+ return;
+ } else if (hwerrs == -1LL) {
+ _IPATH_UNIT_ERROR(t,
+ "Read of hardware error status failed (all bits set); ignoring\n");
+ return;
+ }
+ ipath_stats.sps_hwerrs++;
+
+ /*
+ * clear the error, regardless of whether we continue or stop using
+ * the chip.
+ */
+ ipath_kput_kreg(t, kr_hwerrclear, hwerrs);
+
+ hwerrs &= devdata[t].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 & ~devdata[t].ipath_lasthwerror) ||
+ (infinipath_debug & __IPATH_VERBDBG))
+ _IPATH_INFO("Hardware error: hwerr=0x%llx (cleared)\n", hwerrs);
+ devdata[t].ipath_lasthwerror |= hwerrs;
+
+ if (hwerrs & ~infinipath_hwe_bitsextant)
+ _IPATH_UNIT_ERROR(t,
+ "hwerror interrupt with unknown errors %llx set\n",
+ hwerrs & ~infinipath_hwe_bitsextant);
+
+ ctrl = ipath_kget_kreg32(t, 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 (devdata[t].ipath_flags & IPATH_INITTED) {
+ _IPATH_UNIT_ERROR(t,
+ "Fatal Error (freezemode), no longer usable\n");
+ isfatal = 1;
+ }
+ *devdata[t].ipath_statusp &= ~IPATH_STATUS_IB_READY;
+ /* mark as having had error */
+ *devdata[t].ipath_statusp |= IPATH_STATUS_HWERROR;
+ /*
+ * mark as not usable, at a minimum until driver
+ * is reloaded, probably until reboot, since no
+ * other reset is possible.
+ */
+ devdata[t].ipath_flags &= ~IPATH_INITTED;
+ } else {
+ _IPATH_DBG
+ ("Clearing freezemode on ignored hardware error\n");
+ ctrl &= ~INFINIPATH_C_FREEZEMODE;
+ ipath_kput_kreg(t, kr_control, ctrl);
+ }
+ }
+
+ *msg = '\0';
+
+ /*
+ * may someday want to decode into which bits are which
+ * functional area for parity errors, etc.
+ */
+ if (hwerrs & (infinipath_hwe_htcmemparityerr_mask
+ << INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT)) {
+ bits = (uint32_t) ((hwerrs >>
+ INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) &
+ INFINIPATH_HWE_HTCMEMPARITYERR_MASK);
+ snprintf(bitsmsg, sizeof bitsmsg, "[HTC Parity Errs %x] ",
+ bits);
+ strlcat(msg, bitsmsg, msgl);
+ }
+ if (hwerrs & (INFINIPATH_HWE_RXEMEMPARITYERR_MASK
+ << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)) {
+ bits = (uint32_t) ((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 = (uint32_t) ((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_IBCBUSTOSPCPARITYERR)
+ strlcat(msg, "[IB2IPATH Parity]", msgl);
+ if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR)
+ strlcat(msg, "[IPATH2IB Parity]", msgl);
+ if (hwerrs & INFINIPATH_HWE_HTCBUSIREQPARITYERR)
+ strlcat(msg, "[HTC Ireq Parity]", msgl);
+ if (hwerrs & INFINIPATH_HWE_HTCBUSTREQPARITYERR)
+ strlcat(msg, "[HTC Treq Parity]", msgl);
+ if (hwerrs & INFINIPATH_HWE_HTCBUSTRESPPARITYERR)
+ strlcat(msg, "[HTC Tresp Parity]", msgl);
+
+/* keep the code below somewhat more readonable; not used elsewhere */
+#define _IPATH_HTLINK0_CRCBITS (infinipath_hwe_htclnkabyte0crcerr | \
+ infinipath_hwe_htclnkabyte1crcerr)
+#define _IPATH_HTLINK1_CRCBITS (infinipath_hwe_htclnkbbyte0crcerr | \
+ infinipath_hwe_htclnkbbyte1crcerr)
+#define _IPATH_HTLANE0_CRCBITS (infinipath_hwe_htclnkabyte0crcerr | \
+ infinipath_hwe_htclnkbbyte0crcerr)
+#define _IPATH_HTLANE1_CRCBITS (infinipath_hwe_htclnkabyte1crcerr | \
+ infinipath_hwe_htclnkbbyte1crcerr)
+ if (hwerrs & (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS)) {
+ char bitsmsg[64];
+ uint64_t crcbits = hwerrs &
+ (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS);
+ /* don't check if 8bit HT */
+ if (devdata[t].ipath_flags & IPATH_8BIT_IN_HT0)
+ crcbits &= ~infinipath_hwe_htclnkabyte1crcerr;
+ /* don't check if 8bit HT */
+ if (devdata[t].ipath_flags & IPATH_8BIT_IN_HT1)
+ crcbits &= ~infinipath_hwe_htclnkbbyte1crcerr;
+ /*
+ * we'll want to ignore link errors on link that is
+ * not in use, if any. For now, complain about both
+ */
+ if (crcbits) {
+ uint16_t ctrl0, ctrl1;
+ snprintf(bitsmsg, sizeof bitsmsg,
+ "[HT%s lane %s CRC (%llx); ignore till reload]",
+ !(crcbits & _IPATH_HTLINK1_CRCBITS) ?
+ "0 (A)" : (!(crcbits & _IPATH_HTLINK0_CRCBITS)
+ ? "1 (B)" : "0+1 (A+B)"),
+ !(crcbits & _IPATH_HTLANE1_CRCBITS) ? "0"
+ : (!(crcbits & _IPATH_HTLANE0_CRCBITS) ? "1" :
+ "0+1"), crcbits);
+ strlcat(msg, bitsmsg, msgl);
+
+ /*
+ * print extra info for debugging.
+ * slave/primary config word 4, 8 (link control 0, 1)
+ */
+
+ if (pci_read_config_word(devdata[t].pcidev,
+ devdata[t].ipath_ht_slave_off +
+ 0x4, &ctrl0))
+ _IPATH_INFO
+ ("Couldn't read linkctrl0 of slave/primary config block\n");
+ else if (!(ctrl0 & 1 << 6)) /* not if EOC bit set */
+ _IPATH_DBG("HT linkctrl0 0x%x%s%s\n", ctrl0,
+ ((ctrl0 >> 8) & 7) ? " CRC" : "",
+ ((ctrl0 >> 4) & 1) ? "linkfail" :
+ "");
+ if (pci_read_config_word
+ (devdata[t].pcidev,
+ devdata[t].ipath_ht_slave_off + 0x8, &ctrl1))
+ _IPATH_INFO
+ ("Couldn't read linkctrl1 of slave/primary config block\n");
+ else if (!(ctrl1 & 1 << 6)) /* not if EOC bit set */
+ _IPATH_DBG("HT linkctrl1 0x%x%s%s\n", ctrl1,
+ ((ctrl1 >> 8) & 7) ? " CRC" : "",
+ ((ctrl1 >> 4) & 1) ? "linkfail" :
+ "");
+
+ /* disable until driver reloaded */
+ devdata[t].ipath_hwerrmask &= ~crcbits;
+ ipath_kput_kreg(t, kr_hwerrmask,
+ devdata[t].ipath_hwerrmask);
+ _IPATH_DBG("HT crc errs: %s\n", msg);
+ } else
+ _IPATH_DBG
+ ("ignoring HT crc errors 0x%llx, not in use\n",
+ hwerrs & (_IPATH_HTLINK0_CRCBITS |
+ _IPATH_HTLINK1_CRCBITS));
+ }
+
+ if (hwerrs & INFINIPATH_HWE_HTCMISCERR5)
+ strlcat(msg, "[HT core Misc5]", msgl);
+ if (hwerrs & INFINIPATH_HWE_HTCMISCERR6)
+ strlcat(msg, "[HT core Misc6]", msgl);
+ if (hwerrs & INFINIPATH_HWE_HTCMISCERR7)
+ strlcat(msg, "[HT core Misc7]", msgl);
+ if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
+ strlcat(msg, "[Memory BIST test failed, HT-400 unusable]",
+ msgl);
+ /* ignore from now on, so disable until driver reloaded */
+ devdata[t].ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED;
+ ipath_kput_kreg(t, kr_hwerrmask, devdata[t].ipath_hwerrmask);
+ }
+#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \
+ INFINIPATH_HWE_COREPLL_RFSLIP | \
+ INFINIPATH_HWE_HTBPLL_FBSLIP | \
+ INFINIPATH_HWE_HTBPLL_RFSLIP | \
+ INFINIPATH_HWE_HTAPLL_FBSLIP | \
+ INFINIPATH_HWE_HTAPLL_RFSLIP)
+
+ if (hwerrs & _IPATH_PLL_FAIL) {
+ snprintf(bitsmsg, sizeof bitsmsg,
+ "[PLL failed (%llx), HT-400 unusable]",
+ hwerrs & _IPATH_PLL_FAIL);
+ strlcat(msg, bitsmsg, msgl);
+ /* ignore from now on, so disable until driver reloaded */
+ devdata[t].ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL);
+ ipath_kput_kreg(t, kr_hwerrmask, devdata[t].ipath_hwerrmask);
+ }
+
+ if (hwerrs & INFINIPATH_HWE_EXTSERDESPLLFAILED) {
+ /*
+ * If it occurs, it is left masked since the eternal interface
+ * is unused
+ */
+ devdata[t].ipath_hwerrmask &=
+ ~INFINIPATH_HWE_EXTSERDESPLLFAILED;
+ ipath_kput_kreg(t, kr_hwerrmask, devdata[t].ipath_hwerrmask);
+ }
+
+ if (hwerrs & INFINIPATH_HWE_RXDSYNCMEMPARITYERR)
+ strlcat(msg, "[Rx Dsync]", msgl);
+ if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED)
+ strlcat(msg, "[SerDes PLL]", msgl);
+
+ _IPATH_UNIT_ERROR(t, "%s hardware error\n", msg);
+ if (isfatal && (!ipath_diags_enabled)) {
+ if (devdata[t].ipath_freezemsg) {
+ /*
+ * for proc status file ; if no trailing } is copied, we'll know
+ * it was truncated.
+ */
+ snprintf(devdata[t].ipath_freezemsg,
+ devdata[t].ipath_freezelen, "{%s}", msg);
+ }
+ }
+}
+
+/* fill in the board name, based on the board revision register */
+void ipath_ht_get_boardname(const ipath_type t, char *name, size_t namelen)
+{
+ char *n = NULL;
+ uint8_t boardrev = devdata[t].ipath_boardrev;
+
+ switch (boardrev) {
+ case 4: /* Ponderosa is one of the bringup boards */
+ n = "Ponderosa";
+ break;
+ case 5: /* HT-460 original production board */
+ n = "InfiniPath_HT-460";
+ break;
+ case 7: /* HT-460 small form factor production board */
+ n = "InfiniPath_HT-465";
+ break;
+ case 6:
+ n = "OEM_Board_3";
+ break;
+ case 8:
+ n = "LS/X-1";
+ break;
+ case 9: /* Comstock bringup test board */
+ n = "Comstock";
+ break;
+ case 10:
+ n = "OEM_Board_2";
+ break;
+ case 11:
+ n = "HT-470";
+ break;
+ default: /* don't know, just print the number */
+ _IPATH_ERROR("Don't yet know about board with ID %u\n",
+ boardrev);
+ snprintf(name, namelen, "UnknownBoardRev%u", boardrev);
+ break;
+ }
+ if (n)
+ snprintf(name, namelen, "%s", n);
+}
+
+int ipath_validate_rev(struct ipath_devdata * dd)
+{
+ if (dd->ipath_majrev != 3 || dd->ipath_minrev != 2) {
+ /*
+ * This version of the driver only supports the HT-400
+ * Rev 3.2
+ */
+ _IPATH_UNIT_ERROR(IPATH_UNIT(dd),
+ "Unsupported HT-400 revision %u.%u!\n",
+ dd->ipath_majrev, dd->ipath_minrev);
+ return 1;
+ }
+ if (dd->ipath_htspeed != 800)
+ _IPATH_UNIT_ERROR(IPATH_UNIT(dd),
+ "Incorrectly configured for HT @ %uMHz\n",
+ dd->ipath_htspeed);
+ if (dd->ipath_boardrev == 7 || dd->ipath_boardrev == 11 ||
+ dd->ipath_boardrev == 6)
+ dd->ipath_flags |= IPATH_GPIO_INTR;
+ else if (dd->ipath_boardrev == 8) { /* LS/X-1 */
+ uint64_t val;
+ val = ipath_kget_kreg64(dd->ipath_pd[0]->port_unit, kr_extstatus);
+ if (val & INFINIPATH_EXTS_SERDESSEL) { /* hardware disabled */
+ /* This means that the chip is hardware disabled, and will
+ * not be able to bring up the link, in any case. We special
+ * case this and abort early, to avoid later messages. We
+ * also set the DISABLED status bit
+ */
+ _IPATH_DBG("Unit %u is hardware-disabled\n",
+ dd->ipath_pd[0]->port_unit);
+ *dd->ipath_statusp |= IPATH_STATUS_DISABLED;
+ return 2; /* this value is handled differently */
+ }
+ }
+ return 0;
+}
+
+static void ipath_check_htlink(ipath_type t)
+{
+ uint8_t linkerr, link_off, i;
+
+ for (i = 0; i < 2; i++) {
+ link_off = devdata[t].ipath_ht_slave_off + i * 4 + 0xd;
+ if (pci_read_config_byte(devdata[t].pcidev, link_off, &linkerr))
+ _IPATH_INFO
+ ("Couldn't read linkerror%d of HT slave/primary block\n",
+ i);
+ else if (linkerr & 0xf0) {
+ _IPATH_VDBG("HT linkerr%d bits 0x%x set, clearing\n",
+ linkerr >> 4, i);
+ /*
+ * writing the linkerr bits that are set should
+ * clear them
+ */
+ if (pci_write_config_byte
+ (devdata[t].pcidev, link_off, linkerr))
+ _IPATH_DBG
+ ("Failed write to clear HT linkerror%d\n",
+ i);
+ if (pci_read_config_byte
+ (devdata[t].pcidev, link_off, &linkerr))
+ _IPATH_INFO
+ ("Couldn't reread linkerror%d of HT slave/primary block\n",
+ i);
+ else if (linkerr & 0xf0)
+ _IPATH_INFO
+ ("HT linkerror%d bits 0x%x couldn't be cleared\n",
+ i, linkerr >> 4);
+ }
+ }
+}
+
+/*
+ * 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_clear_init_hwerrs(ipath_type t)
+{
+ uint64_t val, extsval;
+
+ extsval = ipath_kget_kreg64(t, kr_extstatus);
+
+ if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST))
+ _IPATH_UNIT_ERROR(t, "MemBIST did not complete!\n");
+
+ ipath_check_htlink(t);
+
+ /* barring bugs, all hwerrors become interrupts, which can */
+ val = -1LL;
+ /* don't look at crc lane1 if 8 bit */
+ if (devdata[t].ipath_flags & IPATH_8BIT_IN_HT0)
+ val &= ~infinipath_hwe_htclnkabyte1crcerr;
+ /* don't look at crc lane1 if 8 bit */
+ if (devdata[t].ipath_flags & IPATH_8BIT_IN_HT1)
+ val &= ~infinipath_hwe_htclnkbbyte1crcerr;
+
+ /*
+ * disable RXDSYNCMEMPARITY because external serdes is unused,
+ * and therefore the logic will never be used or initialized,
+ * and uninitialized state will normally result in this error
+ * being asserted. Similarly for the external serdess pll
+ * lock signal.
+ */
+ val &=
+ ~(INFINIPATH_HWE_EXTSERDESPLLFAILED |
+ INFINIPATH_HWE_RXDSYNCMEMPARITYERR);
+
+ /*
+ * Disable MISCERR4 because of an inversion in the HT core
+ * logic checking for errors that cause this bit to be set.
+ * The errata can also cause the protocol error bit to be set
+ * in the HT config space linkerror register(s).
+ */
+ val &= ~INFINIPATH_HWE_HTCMISCERR4;
+
+ /*
+ * PLL ignored because MDIO interface has a logic problem for reads,
+ * on Comstock and Ponderosa. BRINGUP
+ */
+ if (devdata[t].ipath_boardrev == 4 || devdata[t].ipath_boardrev == 9)
+ val &= ~INFINIPATH_HWE_EXTSERDESPLLFAILED; /* BRINGUP */
+ devdata[t].ipath_hwerrmask = val;
+}
+
+/* bring up the serdes */
+int ipath_bringup_serdes(ipath_type t)
+{
+ uint64_t val, config1;
+ int ret = 0, change = 0;
+
+ _IPATH_DBG("Trying to bringup serdes\n");
+
+ if (ipath_kget_kreg64(t, kr_hwerrstatus) &
+ INFINIPATH_HWE_SERDESPLLFAILED) {
+ _IPATH_DBG
+ ("At start, serdes PLL failed bit set in hwerrstatus, clearing and continuing\n");
+ ipath_kput_kreg(t, kr_hwerrclear,
+ INFINIPATH_HWE_SERDESPLLFAILED);
+ }
+
+ val = ipath_kget_kreg64(t, kr_serdesconfig0);
+ config1 = ipath_kget_kreg64(t, kr_serdesconfig1);
+
+ _IPATH_VDBG
+ ("Initial serdes status is config0=%llx config1=%llx, sstatus=%llx xgxs %llx\n",
+ val, config1, ipath_kget_kreg64(t, kr_serdesstatus),
+ ipath_kget_kreg64(t, kr_xgxsconfig));
+
+ /* force reset on */
+ val |=
+ INFINIPATH_SERDC0_RESET_PLL /* | INFINIPATH_SERDC0_RESET_MASK */ ;
+ ipath_kput_kreg(t, kr_serdesconfig0, val);
+ udelay(15); /* need pll reset set at least for a bit */
+
+ if (val & INFINIPATH_SERDC0_RESET_PLL) {
+ uint64_t val2 = val &= ~INFINIPATH_SERDC0_RESET_PLL;
+ /* set lane resets, and tx idle, during pll reset */
+ val2 |= INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE;
+ _IPATH_VDBG("Clearing serdes PLL reset (writing %llx)\n", val2);
+ ipath_kput_kreg(t, kr_serdesconfig0, val2);
+ /* be sure chip saw it */
+ val = ipath_kget_kreg64(t, kr_scratch);
+ /*
+ * need pll reset clear at least 11 usec before lane resets
+ * cleared; give it a few more
+ */
+ udelay(15);
+ val = val2; /* for check below */
+ }
+
+ if (val & (INFINIPATH_SERDC0_RESET_PLL | INFINIPATH_SERDC0_RESET_MASK
+ | INFINIPATH_SERDC0_TXIDLE)) {
+ val &=
+ ~(INFINIPATH_SERDC0_RESET_PLL | INFINIPATH_SERDC0_RESET_MASK
+ | INFINIPATH_SERDC0_TXIDLE);
+ ipath_kput_kreg(t, kr_serdesconfig0, val); /* clear them */
+ }
+
+ val = ipath_kget_kreg64(t, kr_xgxsconfig);
+ if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
+ INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
+ val &=
+ ~(INFINIPATH_XGXS_MDIOADDR_MASK <<
+ INFINIPATH_XGXS_MDIOADDR_SHIFT);
+ /* we use address 3 */
+ val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
+ change = 1;
+ }
+ if (val & INFINIPATH_XGXS_RESET) { /* normally true after boot */
+ val &= ~INFINIPATH_XGXS_RESET;
+ change = 1;
+ }
+ if (change)
+ ipath_kput_kreg(t, kr_xgxsconfig, val);
+
+ val = ipath_kget_kreg64(t, kr_serdesconfig0);
+
+ config1 &= ~0x0ffffffff00ULL; /* clear current and de-emphasis bits */
+ config1 |= 0x00000000000ULL; /* set current to 20ma */
+ config1 |= 0x0cccc000000ULL; /* set de-emphasis to -5.68dB */
+ ipath_kput_kreg(t, kr_serdesconfig1, config1);
+
+ _IPATH_VDBG
+ ("After setup: serdes status is config0=%llx config1=%llx, sstatus=%llx xgxs %llx\n",
+ val, config1, ipath_kget_kreg64(t, kr_serdesstatus),
+ ipath_kget_kreg64(t, kr_xgxsconfig));
+
+ if ((!ipath_waitfor_mdio_cmdready(t))) {
+ ipath_kput_kreg(t, kr_mdio, IPATH_MDIO_REQ(IPATH_MDIO_CMD_READ,
+ 31,
+ IPATH_MDIO_CTRL_XGXS_REG_8,
+ 0));
+ if (ipath_waitfor_complete
+ (t, kr_mdio, IPATH_MDIO_DATAVALID, &val))
+ _IPATH_DBG
+ ("Never got MDIO data for XGXS status read\n");
+ else
+ _IPATH_VDBG("MDIO Read reg8, 'bank' 31 %x\n",
+ (uint32_t) val);
+ } else
+ _IPATH_DBG("Never got MDIO cmdready for XGXS status read\n");
+
+ return ret; /* for now, say we always succeeded */
+}
+
+/* set serdes to txidle; driver is being unloaded */
+void ipath_quiet_serdes(const ipath_type t)
+{
+ uint64_t val = ipath_kget_kreg64(t, kr_serdesconfig0);
+
+ val |= INFINIPATH_SERDC0_TXIDLE;
+ _IPATH_DBG("Setting TxIdleEn on serdes (config0 = %llx)\n", val);
+ ipath_kput_kreg(t, kr_serdesconfig0, val);
+}
+
+EXPORT_SYMBOL(ipath_get_unit_name);
+
diff -r e8af3873b0d9 -r 5e9b0b7876e2 drivers/infiniband/hw/ipath/ipath_i2c.c
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/drivers/infiniband/hw/ipath/ipath_i2c.c Wed Dec 28 14:19:43 2005 -0800
@@ -0,0 +1,473 @@
+/*
+ * 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.
+ *
+ * Patent licenses, if any, provided herein do not apply to
+ * combinations of this program with other software, or any other
+ * product whatsoever.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+
+#include "ipath_kernel.h"
+#include "ips_common.h"
+#include "ipath_layer.h"
+
+/*
+ * InfiniPath I2C Driver for a serial flash. Not a generic i2c
+ * interface. Requires software bitbanging, with readbacks from chip
+ * to ensure timing (simple udelay is not enough). Specialized enough
+ * that using the standard kernel i2c bitbanging interface appears as
+ * though it would make the code longer and harder to maintain, rather
+ * than simpler.
+ * Intended to work with parts similar to Atmel AT24C01 (a 1Kbit part,
+ * that uses no programmable address bits, with address 1010000b).
+ */
+
+typedef enum i2c_line_type_e {
+ i2c_line_scl = 0,
+ i2c_line_sda
+} ipath_i2c_type;
+
+typedef enum i2c_line_state_e {
+ i2c_line_low = 0,
+ i2c_line_high
+} ipath_i2c_state;
+
+#define READ_CMD 1
+#define WRITE_CMD 0
+
+static int ipath_eeprom_init;
+
+/*
+ * The gpioval manipulation really should be protected by spinlocks
+ * or be converted to use atomic operations (unfortunately, atomic.h
+ * doesn't cover 64 bit ops for some of them).
+ */
+
+int i2c_gpio_set(ipath_type dev, ipath_i2c_type line,
+ ipath_i2c_state new_line_state);
+int i2c_gpio_get(ipath_type dev, ipath_i2c_type line,
+ ipath_i2c_state * curr_statep);
+
+/*
+ * returns 0 if the line was set to the new state successfully, non-zero
+ * on error.
+ */
+int i2c_gpio_set(ipath_type dev, ipath_i2c_type line,
+ ipath_i2c_state new_line_state)
+{
+ uint64_t read_val, write_val, mask, *gpioval;
+
+ gpioval = &devdata[dev].ipath_gpio_out;
+ read_val = ipath_kget_kreg64(dev, kr_extctrl);
+ if (line == i2c_line_scl)
+ mask = ipath_gpio_scl;
+ else
+ mask = ipath_gpio_sda;
+
+ if (new_line_state == i2c_line_high)
+ /* tri-state the output rather than force high */
+ write_val = read_val & ~mask;
+ else
+ /* config line to be an output */
+ write_val = read_val | mask;
+ ipath_kput_kreg(dev, kr_extctrl, write_val);
+
+ /* set high and verify */
+ if (new_line_state == i2c_line_high)
+ write_val = 0x1UL;
+ else
+ write_val = 0x0UL;
+
+ if (line == i2c_line_scl) {
+ write_val <<= ipath_gpio_scl_num;
+ *gpioval = *gpioval & ~(1UL << ipath_gpio_scl_num);
+ *gpioval |= write_val;
+ } else {
+ write_val <<= ipath_gpio_sda_num;
+ *gpioval = *gpioval & ~(1UL << ipath_gpio_sda_num);
+ *gpioval |= write_val;
+ }
+ ipath_kput_kreg(dev, kr_gpio_out, *gpioval);
+
+ return 0;
+}
+
+/*
+ * returns 0 if the line was set to the new state successfully, non-zero
+ * on error. curr_state is not set on error.
+ */
+int i2c_gpio_get(ipath_type dev, ipath_i2c_type line,
+ ipath_i2c_state * curr_statep)
+{
+ uint64_t read_val, write_val, mask;
+
+ /* check args */
+ if (curr_statep == NULL)
+ return 1;
+
+ read_val = ipath_kget_kreg64(dev, kr_extctrl);
+ /* config line to be an input */
+ if (line == i2c_line_scl)
+ mask = ipath_gpio_scl;
+ else
+ mask = ipath_gpio_sda;
+ write_val = read_val & ~mask;
+ ipath_kput_kreg(dev, kr_extctrl, write_val);
+ read_val = ipath_kget_kreg64(dev, kr_extstatus);
+
+ if (read_val & mask)
+ *curr_statep = i2c_line_high;
+ else
+ *curr_statep = i2c_line_low;
+
+ return 0;
+}
+
+/*
+ * would prefer to not inline this, to avoid code bloat, and simplify debugging
+ * But when compiling against 2.6.10 kernel tree, it gets an error, so
+ * not for now.
+ */
+static void ipath_i2c_delay(ipath_type, int);
+
+/*
+ * we use this instead of udelay directly, so we can make sure
+ * that previous register writes have been flushed all the way
+ * to the chip. Since we are delaying anyway, the cost doesn't
+ * hurt, and makes the bit twiddling more regular
+ * If delay is negative, we'll do the chip read, to be sure write made it
+ * to our chip, but won't do udelay()
+ */
+static void ipath_i2c_delay(ipath_type dev, int dtime)
+{
+ /*
+ * This needs to be volatile, so that the compiler doesn't
+ * optimize away the read to the device's mapped memory.
+ */
+ volatile uint32_t read_val;
+ if (!dtime)
+ return;
+ read_val = ipath_kget_kreg32(dev, kr_scratch);
+ if (--dtime > 0) /* register read takes about .5 usec, itself */
+ udelay(dtime);
+}
+
+static void ipath_scl_out(ipath_type dev, uint8_t bit, int delay)
+{
+ i2c_gpio_set(dev, i2c_line_scl, bit ? i2c_line_high : i2c_line_low);
+
+ ipath_i2c_delay(dev, delay);
+}
+
+static void ipath_sda_out(ipath_type dev, uint8_t bit, int delay)
+{
+ i2c_gpio_set(dev, i2c_line_sda, bit ? i2c_line_high : i2c_line_low);
+
+ ipath_i2c_delay(dev, delay);
+}
+
+static uint8_t ipath_sda_in(ipath_type dev, int delay)
+{
+ ipath_i2c_state bit;
+
+ if (i2c_gpio_get(dev, i2c_line_sda, &bit))
+ _IPATH_DBG("get bit failed!\n");
+
+ ipath_i2c_delay(dev, delay);
+
+ return bit == i2c_line_high ? 1U : 0;
+}
+
+/* see if ack following write is true */
+static int ipath_i2c_ackrcv(ipath_type dev)
+{
+ uint8_t ack_received;
+
+ /* AT ENTRY SCL = LOW */
+ /* change direction, ignore data */
+ ack_received = ipath_sda_in(dev, 1);
+ ipath_scl_out(dev, i2c_line_high, 1);
+ ack_received = ipath_sda_in(dev, 1) == 0;
+ ipath_scl_out(dev, i2c_line_low, 1);
+ return ack_received;
+}
+
+/*
+ * write a byte, one bit at a time. Returns 0 if we got the following
+ * ack, otherwise 1
+ */
+static int ipath_wr_byte(ipath_type dev, uint8_t data)
+{
+ int bit_cntr;
+ uint8_t bit;
+
+ for (bit_cntr = 7; bit_cntr >= 0; bit_cntr--) {
+ bit = (data >> bit_cntr) & 1;
+ ipath_sda_out(dev, bit, 1);
+ ipath_scl_out(dev, i2c_line_high, 1);
+ ipath_scl_out(dev, i2c_line_low, 1);
+ }
+ if (!ipath_i2c_ackrcv(dev))
+ return 1;
+ return 0;
+}
+
+static void send_ack(ipath_type dev)
+{
+ ipath_sda_out(dev, i2c_line_low, 1);
+ ipath_scl_out(dev, i2c_line_high, 1);
+ ipath_scl_out(dev, i2c_line_low, 1);
+ ipath_sda_out(dev, i2c_line_high, 1);
+}
+
+/*
+ * ipath_i2c_startcmd - Transmit the start condition, followed by
+ * address/cmd
+ * (both clock/data high, clock high, data low while clock is high)
+ */
+static int ipath_i2c_startcmd(ipath_type dev, uint8_t offset_dir)
+{
+ int res;
+
+ /* issue start sequence */
+ ipath_sda_out(dev, i2c_line_high, 1);
+ ipath_scl_out(dev, i2c_line_high, 1);
+ ipath_sda_out(dev, i2c_line_low, 1);
+ ipath_scl_out(dev, i2c_line_low, 1);
+
+ /* issue length and direction byte */
+ res = ipath_wr_byte(dev, offset_dir);
+
+ if (res)
+ _IPATH_VDBG("No ack to complete start\n");
+ return res;
+}
+
+/*
+ * stop_cmd - Transmit the stop condition
+ * (both clock/data low, clock high, data high while clock is high)
+ */
+static void stop_cmd(ipath_type dev)
+{
+ ipath_scl_out(dev, i2c_line_low, 1);
+ ipath_sda_out(dev, i2c_line_low, 1);
+ ipath_scl_out(dev, i2c_line_high, 1);
+ ipath_sda_out(dev, i2c_line_high, 3);
+}
+
+/*
+ * ipath_eeprom_reset - reset I2C communication.
+ *
+ * eeprom: Atmel AT24C01
+ *
+ */
+
+static int ipath_eeprom_reset(ipath_type dev)
+{
+ int clock_cycles_left = 9;
+ uint64_t *gpioval = &devdata[dev].ipath_gpio_out;
+
+ ipath_eeprom_init = 1;
+ *gpioval = ipath_kget_kreg64(dev, kr_gpio_out);
+ _IPATH_VDBG("Resetting i2c flash; initial gpioout reg is %llx\n",
+ *gpioval);
+
+ /*
+ * This is to get the i2c into a known state, by first going low,
+ * then tristate sda (and then tristate scl as first thing in loop)
+ */
+ ipath_scl_out(dev, i2c_line_low, 1);
+ ipath_sda_out(dev, i2c_line_high, 1);
+
+ while (clock_cycles_left--) {
+ ipath_scl_out(dev, i2c_line_high, 1);
+
+ if (ipath_sda_in(dev, 0)) {
+ ipath_sda_out(dev, i2c_line_low, 1);
+ ipath_scl_out(dev, i2c_line_low, 1);
+ return 0;
+ }
+
+ ipath_scl_out(dev, i2c_line_low, 1);
+ }
+
+ return 1;
+}
+
+/*
+ * ipath_eeprom_read - Receives x # byte from the eeprom via I2C.
+ *
+ * eeprom: Atmel AT24C01
+ *
+ */
+
+int ipath_eeprom_read(ipath_type dev, uint8_t eeprom_offset, void *buffer,
+ int len)
+{
+ /* compiler complains unless initialized */
+ uint8_t single_byte = 0;
+ int bit_cntr;
+
+ if (!ipath_eeprom_init)
+ ipath_eeprom_reset(dev);
+
+ eeprom_offset = (eeprom_offset << 1) | READ_CMD;
+
+ if (ipath_i2c_startcmd(dev, eeprom_offset)) {
+ _IPATH_DBG("Failed startcmd\n");
+ stop_cmd(dev);
+ return 1;
+ }
+
+ /*
+ * flash keeps clocking data out as long as we ack, automatically
+ * incrementing the address.
+ */
+ while (len-- > 0) {
+ /* get data */
+ single_byte = 0;
+ for (bit_cntr = 8; bit_cntr; bit_cntr--) {
+ uint8_t bit;
+ ipath_scl_out(dev, i2c_line_high, 1);
+ bit = ipath_sda_in(dev, 0);
+ single_byte |= bit << (bit_cntr - 1);
+ ipath_scl_out(dev, i2c_line_low, 1);
+ }
+
+ /* send ack if not the last byte */
+ if (len)
+ send_ack(dev);
+
+ *((uint8_t *) buffer) = single_byte;
+ (uint8_t *) buffer++;
+ }
+
+ stop_cmd(dev);
+
+ return 0;
+}
+
+/*
+ * ipath_eeprom_write - writes data to the eeprom via I2C.
+ *
+*/
+int ipath_eeprom_write(ipath_type dev, uint8_t eeprom_offset, void *buffer,
+ int len)
+{
+ uint8_t single_byte;
+ int sub_len;
+ uint8_t *bp = buffer;
+ int max_wait_time, i;
+
+ if (!ipath_eeprom_init)
+ ipath_eeprom_reset(dev);
+
+ while (len > 0) {
+ if (ipath_i2c_startcmd(dev, (eeprom_offset << 1) | WRITE_CMD)) {
+ _IPATH_DBG("Failed to start cmd offset %u\n",
+ eeprom_offset);
+ goto failed_write;
+ }
+
+ sub_len = min(len, 4);
+ eeprom_offset += sub_len;
+ len -= sub_len;
+
+ for (i = 0; i < sub_len; i++) {
+ if (ipath_wr_byte(dev, *bp++)) {
+ _IPATH_DBG
+ ("no ack after byte %u/%u (%u total remain)\n",
+ i, sub_len, len + sub_len - i);
+ goto failed_write;
+ }
+ }
+
+ stop_cmd(dev);
+
+ /*
+ * wait for write complete by waiting for a successful
+ * read (the chip replies with a zero after the write
+ * cmd completes, and before it writes to the flash.
+ * The startcmd for the read will fail the ack until
+ * the writes have completed. We do this inline to avoid
+ * the debug prints that are in the real read routine
+ * if the startcmd fails.
+ */
+ max_wait_time = 100;
+ while (ipath_i2c_startcmd(dev, READ_CMD)) {
+ stop_cmd(dev);
+ if (!--max_wait_time) {
+ _IPATH_DBG
+ ("Did not get successful read to complete write\n");
+ goto failed_write;
+ }
+ }
+ /* now read the zero byte */
+ for (i = single_byte = 0; i < 8; i++) {
+ uint8_t bit;
+ ipath_scl_out(dev, i2c_line_high, 1);
+ bit = ipath_sda_in(dev, 0);
+ ipath_scl_out(dev, i2c_line_low, 1);
+ single_byte <<= 1;
+ single_byte |= bit;
+ }
+ stop_cmd(dev);
+ }
+
+ return 0;
+
+failed_write:
+ stop_cmd(dev);
+ return 1;
+}
+
+uint8_t ipath_flash_csum(struct ipath_flash * ifp, int adjust)
+{
+ uint8_t *ip = (uint8_t *) ifp;
+ uint8_t csum = 0, len;
+
+ for (len = 0; len < ifp->if_length; len++)
+ csum += *ip++;
+ csum -= ifp->if_csum;
+ csum = ~csum;
+ if (adjust)
+ ifp->if_csum = csum;
+ return csum;
+}
diff -r e8af3873b0d9 -r 5e9b0b7876e2 drivers/infiniband/hw/ipath/ipath_lib.c
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/drivers/infiniband/hw/ipath/ipath_lib.c Wed Dec 28 14:19:43 2005 -0800
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ *
+ * Patent licenses, if any, provided herein do not apply to
+ * combinations of this program with other software, or any other
+ * product whatsoever.
+ */
+
+/*
+ * This is library code for the driver, similar to what's in libinfinipath for
+ * usermode code.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include "ipath_kernel.h"
+
+unsigned infinipath_debug = __IPATH_INFO;
+
+uint32_t _ipath_pico_per_cycle; /* always present, for now */
+
+/*
+ * This isn't perfect, but it's close enough for timing work. We want this
+ * to work on systems where the cycle counter isn't the same as the clock
+ * frequency. The one msec spin is OK, since we execute this only once
+ * when first loaded. We don't use CURRENT_TIME because on some systems
+ * it only has jiffy resolution; we just assume udelay is well calibrated
+ * and that we aren't likely to be rescheduled. Do it multiple times,
+ * with a yield in between, to try to make sure we get the "true minimum"
+ * value.
+ * _ipath_pico_per_cycle isn't going to lead to completely accurate
+ * conversions from timestamps to nanoseconds, but it's close enough
+ * for our purposes, which is mainly to allow people to show events with
+ * nsecs or usecs if desired, rather than cycles.
+ */
+void ipath_init_picotime(void)
+{
+ int i;
+ u_int64_t ts, te, delta = -1ULL;
+
+ for (i = 0; i < 5; i++) {
+ ts = get_cycles();
+ udelay(250);
+ te = get_cycles();
+ if ((te - ts) < delta)
+ delta = te - ts;
+ yield();
+ }
+ _ipath_pico_per_cycle = 250000000 / delta;
+}
diff -r e8af3873b0d9 -r 5e9b0b7876e2 drivers/infiniband/hw/ipath/ipath_upages.c
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/drivers/infiniband/hw/ipath/ipath_upages.c Wed Dec 28 14:19:43 2005 -0800
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ *
+ * Patent licenses, if any, provided herein do not apply to
+ * combinations of this program with other software, or any other
+ * product whatsoever.
+ */
+
+#include <stddef.h>
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+
+#include <asm/page.h>
+#include <asm/io.h>
+
+#include "ipath_kernel.h"
+
+/*
+ * Our version of the kernel mlock function. This function is no longer
+ * exposed, so we need to do it ourselves. It takes a given start page
+ * (page aligned user virtual address) and pins it and the following specified
+ * number of pages.
+ * For now, num_pages is always 1, but that will probably change at some
+ * point (because caller is doing expected sends on a single virtually
+ * contiguous buffer, so we can do all pages at once).
+ */
+int ipath_get_upages(unsigned long start_page, size_t num_pages, struct page **p)
+{
+ int n;
+
+ _IPATH_VDBG("pin %lx pages from vaddr %lx\n", num_pages, start_page);
+ down_read(¤t->mm->mmap_sem);
+ n = get_user_pages(current, current->mm, start_page, num_pages, 1, 1,
+ p, NULL);
+ up_read(¤t->mm->mmap_sem);
+ if (n != num_pages) {
+ _IPATH_INFO
+ ("get_user_pages (0x%lx pages starting at 0x%lx failed with %d\n",
+ num_pages, start_page, n);
+ if (n < 0) /* it's an errno */
+ return n;
+ /*
+ * We may have gotten some pages, so unlock those.
+ * ipath_putpages() correctly handles n==0
+ */
+ ipath_putpages(n, p);
+ return -ENOMEM; /* no way to know actual error */
+ }
+
+ return 0;
+}
+
+/*
+ * this is similar to ipath_get_upages, but it's always one page, and we mark
+ * the page as locked for i/o, and shared. This is used for the user process
+ * page that contains the destination address for the rcvhdrq tail update,
+ * so we need to have the vma. If we don't do this, the page can be taken
+ * away from us on fork, even if the child never touches it, and then
+ * the user process never sees the tail register updates.
+ */
+int ipath_get_upages_nocopy(unsigned long start_page, struct page **p)
+{
+ int n;
+ struct vm_area_struct *vm = NULL;
+
+ down_read(¤t->mm->mmap_sem);
+ n = get_user_pages(current, current->mm, start_page, 1, 1, 1, p, &vm);
+ up_read(¤t->mm->mmap_sem);
+ if (n != 1) {
+ _IPATH_INFO("get_user_pages for 0x%lx failed with %d\n",
+ start_page, n);
+ if (n < 0) /* it's an errno */
+ return n;
+ /*
+ * If we ever ask for more than a single page, we will have to
+ * free the pages (if any) that we did get, via ipath_get_upages()
+ * or put_page() directly.
+ */
+ return -ENOMEM; /* no way to know actual error */
+ }
+ vm->vm_flags |= VM_SHM | VM_LOCKED;
+
+ return 0;
+}
+
+/*
+ * Unpins the start page (a page aligned full user virtual address, not a
+ * page number) and pins it and the following specified number of pages.
+ */
+void ipath_putpages(size_t num_pages, struct page **p)
+{
+ int i;
+
+ for (i = 0; i < num_pages; i++) {
+ _IPATH_MMDBG("%u/%lu put_page %p\n", i, num_pages, p[i]);
+ set_page_dirty_lock(p[i]);
+ put_page(p[i]);
+ }
+}
+
+/*
+ * This routine frees up all the allocations made in this file; it's a nop
+ * now, but I'm leaving it in case we go back to a more sophisticated
+ * implementation later.
+ */
+void ipath_upages_cleanup(struct ipath_portdata * pd)
+{
+}
More information about the general
mailing list