18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2013 - 2017 Intel Corporation. All rights reserved.
38c2ecf20Sopenharmony_ci * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
48c2ecf20Sopenharmony_ci * All rights reserved.
58c2ecf20Sopenharmony_ci * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
88c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
98c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
108c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
118c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
148c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
158c2ecf20Sopenharmony_ci *     conditions are met:
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
188c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
198c2ecf20Sopenharmony_ci *        disclaimer.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
228c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
238c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
248c2ecf20Sopenharmony_ci *        provided with the distribution.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
278c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
288c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
298c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
308c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
318c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
328c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
338c2ecf20Sopenharmony_ci * SOFTWARE.
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_ci/*
368c2ecf20Sopenharmony_ci * This file contains all of the code that is specific to the
378c2ecf20Sopenharmony_ci * QLogic_IB 6120 PCIe chip.
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
418c2ecf20Sopenharmony_ci#include <linux/pci.h>
428c2ecf20Sopenharmony_ci#include <linux/delay.h>
438c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h>
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#include "qib.h"
468c2ecf20Sopenharmony_ci#include "qib_6120_regs.h"
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic void qib_6120_setup_setextled(struct qib_pportdata *, u32);
498c2ecf20Sopenharmony_cistatic void sendctrl_6120_mod(struct qib_pportdata *ppd, u32 op);
508c2ecf20Sopenharmony_cistatic u8 qib_6120_phys_portstate(u64);
518c2ecf20Sopenharmony_cistatic u32 qib_6120_iblink_state(u64);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/*
548c2ecf20Sopenharmony_ci * This file contains all the chip-specific register information and
558c2ecf20Sopenharmony_ci * access functions for the Intel Intel_IB PCI-Express chip.
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci */
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/* KREG_IDX uses machine-generated #defines */
608c2ecf20Sopenharmony_ci#define KREG_IDX(regname) (QIB_6120_##regname##_OFFS / sizeof(u64))
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/* Use defines to tie machine-generated names to lower-case names */
638c2ecf20Sopenharmony_ci#define kr_extctrl KREG_IDX(EXTCtrl)
648c2ecf20Sopenharmony_ci#define kr_extstatus KREG_IDX(EXTStatus)
658c2ecf20Sopenharmony_ci#define kr_gpio_clear KREG_IDX(GPIOClear)
668c2ecf20Sopenharmony_ci#define kr_gpio_mask KREG_IDX(GPIOMask)
678c2ecf20Sopenharmony_ci#define kr_gpio_out KREG_IDX(GPIOOut)
688c2ecf20Sopenharmony_ci#define kr_gpio_status KREG_IDX(GPIOStatus)
698c2ecf20Sopenharmony_ci#define kr_rcvctrl KREG_IDX(RcvCtrl)
708c2ecf20Sopenharmony_ci#define kr_sendctrl KREG_IDX(SendCtrl)
718c2ecf20Sopenharmony_ci#define kr_partitionkey KREG_IDX(RcvPartitionKey)
728c2ecf20Sopenharmony_ci#define kr_hwdiagctrl KREG_IDX(HwDiagCtrl)
738c2ecf20Sopenharmony_ci#define kr_ibcstatus KREG_IDX(IBCStatus)
748c2ecf20Sopenharmony_ci#define kr_ibcctrl KREG_IDX(IBCCtrl)
758c2ecf20Sopenharmony_ci#define kr_sendbuffererror KREG_IDX(SendBufErr0)
768c2ecf20Sopenharmony_ci#define kr_rcvbthqp KREG_IDX(RcvBTHQP)
778c2ecf20Sopenharmony_ci#define kr_counterregbase KREG_IDX(CntrRegBase)
788c2ecf20Sopenharmony_ci#define kr_palign KREG_IDX(PageAlign)
798c2ecf20Sopenharmony_ci#define kr_rcvegrbase KREG_IDX(RcvEgrBase)
808c2ecf20Sopenharmony_ci#define kr_rcvegrcnt KREG_IDX(RcvEgrCnt)
818c2ecf20Sopenharmony_ci#define kr_rcvhdrcnt KREG_IDX(RcvHdrCnt)
828c2ecf20Sopenharmony_ci#define kr_rcvhdrentsize KREG_IDX(RcvHdrEntSize)
838c2ecf20Sopenharmony_ci#define kr_rcvhdrsize KREG_IDX(RcvHdrSize)
848c2ecf20Sopenharmony_ci#define kr_rcvtidbase KREG_IDX(RcvTIDBase)
858c2ecf20Sopenharmony_ci#define kr_rcvtidcnt KREG_IDX(RcvTIDCnt)
868c2ecf20Sopenharmony_ci#define kr_scratch KREG_IDX(Scratch)
878c2ecf20Sopenharmony_ci#define kr_sendctrl KREG_IDX(SendCtrl)
888c2ecf20Sopenharmony_ci#define kr_sendpioavailaddr KREG_IDX(SendPIOAvailAddr)
898c2ecf20Sopenharmony_ci#define kr_sendpiobufbase KREG_IDX(SendPIOBufBase)
908c2ecf20Sopenharmony_ci#define kr_sendpiobufcnt KREG_IDX(SendPIOBufCnt)
918c2ecf20Sopenharmony_ci#define kr_sendpiosize KREG_IDX(SendPIOSize)
928c2ecf20Sopenharmony_ci#define kr_sendregbase KREG_IDX(SendRegBase)
938c2ecf20Sopenharmony_ci#define kr_userregbase KREG_IDX(UserRegBase)
948c2ecf20Sopenharmony_ci#define kr_control KREG_IDX(Control)
958c2ecf20Sopenharmony_ci#define kr_intclear KREG_IDX(IntClear)
968c2ecf20Sopenharmony_ci#define kr_intmask KREG_IDX(IntMask)
978c2ecf20Sopenharmony_ci#define kr_intstatus KREG_IDX(IntStatus)
988c2ecf20Sopenharmony_ci#define kr_errclear KREG_IDX(ErrClear)
998c2ecf20Sopenharmony_ci#define kr_errmask KREG_IDX(ErrMask)
1008c2ecf20Sopenharmony_ci#define kr_errstatus KREG_IDX(ErrStatus)
1018c2ecf20Sopenharmony_ci#define kr_hwerrclear KREG_IDX(HwErrClear)
1028c2ecf20Sopenharmony_ci#define kr_hwerrmask KREG_IDX(HwErrMask)
1038c2ecf20Sopenharmony_ci#define kr_hwerrstatus KREG_IDX(HwErrStatus)
1048c2ecf20Sopenharmony_ci#define kr_revision KREG_IDX(Revision)
1058c2ecf20Sopenharmony_ci#define kr_portcnt KREG_IDX(PortCnt)
1068c2ecf20Sopenharmony_ci#define kr_serdes_cfg0 KREG_IDX(SerdesCfg0)
1078c2ecf20Sopenharmony_ci#define kr_serdes_cfg1 (kr_serdes_cfg0 + 1)
1088c2ecf20Sopenharmony_ci#define kr_serdes_stat KREG_IDX(SerdesStat)
1098c2ecf20Sopenharmony_ci#define kr_xgxs_cfg KREG_IDX(XGXSCfg)
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/* These must only be written via qib_write_kreg_ctxt() */
1128c2ecf20Sopenharmony_ci#define kr_rcvhdraddr KREG_IDX(RcvHdrAddr0)
1138c2ecf20Sopenharmony_ci#define kr_rcvhdrtailaddr KREG_IDX(RcvHdrTailAddr0)
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#define CREG_IDX(regname) ((QIB_6120_##regname##_OFFS - \
1168c2ecf20Sopenharmony_ci			QIB_6120_LBIntCnt_OFFS) / sizeof(u64))
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci#define cr_badformat CREG_IDX(RxBadFormatCnt)
1198c2ecf20Sopenharmony_ci#define cr_erricrc CREG_IDX(RxICRCErrCnt)
1208c2ecf20Sopenharmony_ci#define cr_errlink CREG_IDX(RxLinkProblemCnt)
1218c2ecf20Sopenharmony_ci#define cr_errlpcrc CREG_IDX(RxLPCRCErrCnt)
1228c2ecf20Sopenharmony_ci#define cr_errpkey CREG_IDX(RxPKeyMismatchCnt)
1238c2ecf20Sopenharmony_ci#define cr_rcvflowctrl_err CREG_IDX(RxFlowCtrlErrCnt)
1248c2ecf20Sopenharmony_ci#define cr_err_rlen CREG_IDX(RxLenErrCnt)
1258c2ecf20Sopenharmony_ci#define cr_errslen CREG_IDX(TxLenErrCnt)
1268c2ecf20Sopenharmony_ci#define cr_errtidfull CREG_IDX(RxTIDFullErrCnt)
1278c2ecf20Sopenharmony_ci#define cr_errtidvalid CREG_IDX(RxTIDValidErrCnt)
1288c2ecf20Sopenharmony_ci#define cr_errvcrc CREG_IDX(RxVCRCErrCnt)
1298c2ecf20Sopenharmony_ci#define cr_ibstatuschange CREG_IDX(IBStatusChangeCnt)
1308c2ecf20Sopenharmony_ci#define cr_lbint CREG_IDX(LBIntCnt)
1318c2ecf20Sopenharmony_ci#define cr_invalidrlen CREG_IDX(RxMaxMinLenErrCnt)
1328c2ecf20Sopenharmony_ci#define cr_invalidslen CREG_IDX(TxMaxMinLenErrCnt)
1338c2ecf20Sopenharmony_ci#define cr_lbflowstall CREG_IDX(LBFlowStallCnt)
1348c2ecf20Sopenharmony_ci#define cr_pktrcv CREG_IDX(RxDataPktCnt)
1358c2ecf20Sopenharmony_ci#define cr_pktrcvflowctrl CREG_IDX(RxFlowPktCnt)
1368c2ecf20Sopenharmony_ci#define cr_pktsend CREG_IDX(TxDataPktCnt)
1378c2ecf20Sopenharmony_ci#define cr_pktsendflow CREG_IDX(TxFlowPktCnt)
1388c2ecf20Sopenharmony_ci#define cr_portovfl CREG_IDX(RxP0HdrEgrOvflCnt)
1398c2ecf20Sopenharmony_ci#define cr_rcvebp CREG_IDX(RxEBPCnt)
1408c2ecf20Sopenharmony_ci#define cr_rcvovfl CREG_IDX(RxBufOvflCnt)
1418c2ecf20Sopenharmony_ci#define cr_senddropped CREG_IDX(TxDroppedPktCnt)
1428c2ecf20Sopenharmony_ci#define cr_sendstall CREG_IDX(TxFlowStallCnt)
1438c2ecf20Sopenharmony_ci#define cr_sendunderrun CREG_IDX(TxUnderrunCnt)
1448c2ecf20Sopenharmony_ci#define cr_wordrcv CREG_IDX(RxDwordCnt)
1458c2ecf20Sopenharmony_ci#define cr_wordsend CREG_IDX(TxDwordCnt)
1468c2ecf20Sopenharmony_ci#define cr_txunsupvl CREG_IDX(TxUnsupVLErrCnt)
1478c2ecf20Sopenharmony_ci#define cr_rxdroppkt CREG_IDX(RxDroppedPktCnt)
1488c2ecf20Sopenharmony_ci#define cr_iblinkerrrecov CREG_IDX(IBLinkErrRecoveryCnt)
1498c2ecf20Sopenharmony_ci#define cr_iblinkdown CREG_IDX(IBLinkDownedCnt)
1508c2ecf20Sopenharmony_ci#define cr_ibsymbolerr CREG_IDX(IBSymbolErrCnt)
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci#define SYM_RMASK(regname, fldname) ((u64)              \
1538c2ecf20Sopenharmony_ci	QIB_6120_##regname##_##fldname##_RMASK)
1548c2ecf20Sopenharmony_ci#define SYM_MASK(regname, fldname) ((u64)               \
1558c2ecf20Sopenharmony_ci	QIB_6120_##regname##_##fldname##_RMASK <<       \
1568c2ecf20Sopenharmony_ci	 QIB_6120_##regname##_##fldname##_LSB)
1578c2ecf20Sopenharmony_ci#define SYM_LSB(regname, fldname) (QIB_6120_##regname##_##fldname##_LSB)
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci#define SYM_FIELD(value, regname, fldname) ((u64) \
1608c2ecf20Sopenharmony_ci	(((value) >> SYM_LSB(regname, fldname)) & \
1618c2ecf20Sopenharmony_ci	 SYM_RMASK(regname, fldname)))
1628c2ecf20Sopenharmony_ci#define ERR_MASK(fldname) SYM_MASK(ErrMask, fldname##Mask)
1638c2ecf20Sopenharmony_ci#define HWE_MASK(fldname) SYM_MASK(HwErrMask, fldname##Mask)
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci/* link training states, from IBC */
1668c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_DISABLED        0x00
1678c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_LINKUP          0x01
1688c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_POLLACTIVE      0x02
1698c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_POLLQUIET       0x03
1708c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_SLEEPDELAY      0x04
1718c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_SLEEPQUIET      0x05
1728c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_CFGDEBOUNCE     0x08
1738c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_CFGRCVFCFG      0x09
1748c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_CFGWAITRMT      0x0a
1758c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_CFGIDLE 0x0b
1768c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_RECOVERRETRAIN  0x0c
1778c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_RECOVERWAITRMT  0x0e
1788c2ecf20Sopenharmony_ci#define IB_6120_LT_STATE_RECOVERIDLE     0x0f
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/* link state machine states from IBC */
1818c2ecf20Sopenharmony_ci#define IB_6120_L_STATE_DOWN             0x0
1828c2ecf20Sopenharmony_ci#define IB_6120_L_STATE_INIT             0x1
1838c2ecf20Sopenharmony_ci#define IB_6120_L_STATE_ARM              0x2
1848c2ecf20Sopenharmony_ci#define IB_6120_L_STATE_ACTIVE           0x3
1858c2ecf20Sopenharmony_ci#define IB_6120_L_STATE_ACT_DEFER        0x4
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic const u8 qib_6120_physportstate[0x20] = {
1888c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_DISABLED] = IB_PHYSPORTSTATE_DISABLED,
1898c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_LINKUP] = IB_PHYSPORTSTATE_LINKUP,
1908c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_POLLACTIVE] = IB_PHYSPORTSTATE_POLL,
1918c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_POLLQUIET] = IB_PHYSPORTSTATE_POLL,
1928c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_SLEEPDELAY] = IB_PHYSPORTSTATE_SLEEP,
1938c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_SLEEPQUIET] = IB_PHYSPORTSTATE_SLEEP,
1948c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_CFGDEBOUNCE] =
1958c2ecf20Sopenharmony_ci		IB_PHYSPORTSTATE_CFG_TRAIN,
1968c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_CFGRCVFCFG] =
1978c2ecf20Sopenharmony_ci		IB_PHYSPORTSTATE_CFG_TRAIN,
1988c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_CFGWAITRMT] =
1998c2ecf20Sopenharmony_ci		IB_PHYSPORTSTATE_CFG_TRAIN,
2008c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_CFGIDLE] = IB_PHYSPORTSTATE_CFG_TRAIN,
2018c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_RECOVERRETRAIN] =
2028c2ecf20Sopenharmony_ci		IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
2038c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_RECOVERWAITRMT] =
2048c2ecf20Sopenharmony_ci		IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
2058c2ecf20Sopenharmony_ci	[IB_6120_LT_STATE_RECOVERIDLE] =
2068c2ecf20Sopenharmony_ci		IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
2078c2ecf20Sopenharmony_ci	[0x10] = IB_PHYSPORTSTATE_CFG_TRAIN,
2088c2ecf20Sopenharmony_ci	[0x11] = IB_PHYSPORTSTATE_CFG_TRAIN,
2098c2ecf20Sopenharmony_ci	[0x12] = IB_PHYSPORTSTATE_CFG_TRAIN,
2108c2ecf20Sopenharmony_ci	[0x13] = IB_PHYSPORTSTATE_CFG_TRAIN,
2118c2ecf20Sopenharmony_ci	[0x14] = IB_PHYSPORTSTATE_CFG_TRAIN,
2128c2ecf20Sopenharmony_ci	[0x15] = IB_PHYSPORTSTATE_CFG_TRAIN,
2138c2ecf20Sopenharmony_ci	[0x16] = IB_PHYSPORTSTATE_CFG_TRAIN,
2148c2ecf20Sopenharmony_ci	[0x17] = IB_PHYSPORTSTATE_CFG_TRAIN
2158c2ecf20Sopenharmony_ci};
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistruct qib_chip_specific {
2198c2ecf20Sopenharmony_ci	u64 __iomem *cregbase;
2208c2ecf20Sopenharmony_ci	u64 *cntrs;
2218c2ecf20Sopenharmony_ci	u64 *portcntrs;
2228c2ecf20Sopenharmony_ci	void *dummy_hdrq;   /* used after ctxt close */
2238c2ecf20Sopenharmony_ci	dma_addr_t dummy_hdrq_phys;
2248c2ecf20Sopenharmony_ci	spinlock_t kernel_tid_lock; /* no back to back kernel TID writes */
2258c2ecf20Sopenharmony_ci	spinlock_t user_tid_lock; /* no back to back user TID writes */
2268c2ecf20Sopenharmony_ci	spinlock_t rcvmod_lock; /* protect rcvctrl shadow changes */
2278c2ecf20Sopenharmony_ci	spinlock_t gpio_lock; /* RMW of shadows/regs for ExtCtrl and GPIO */
2288c2ecf20Sopenharmony_ci	u64 hwerrmask;
2298c2ecf20Sopenharmony_ci	u64 errormask;
2308c2ecf20Sopenharmony_ci	u64 gpio_out; /* shadow of kr_gpio_out, for rmw ops */
2318c2ecf20Sopenharmony_ci	u64 gpio_mask; /* shadow the gpio mask register */
2328c2ecf20Sopenharmony_ci	u64 extctrl; /* shadow the gpio output enable, etc... */
2338c2ecf20Sopenharmony_ci	/*
2348c2ecf20Sopenharmony_ci	 * these 5 fields are used to establish deltas for IB symbol
2358c2ecf20Sopenharmony_ci	 * errors and linkrecovery errors.  They can be reported on
2368c2ecf20Sopenharmony_ci	 * some chips during link negotiation prior to INIT, and with
2378c2ecf20Sopenharmony_ci	 * DDR when faking DDR negotiations with non-IBTA switches.
2388c2ecf20Sopenharmony_ci	 * The chip counters are adjusted at driver unload if there is
2398c2ecf20Sopenharmony_ci	 * a non-zero delta.
2408c2ecf20Sopenharmony_ci	 */
2418c2ecf20Sopenharmony_ci	u64 ibdeltainprog;
2428c2ecf20Sopenharmony_ci	u64 ibsymdelta;
2438c2ecf20Sopenharmony_ci	u64 ibsymsnap;
2448c2ecf20Sopenharmony_ci	u64 iblnkerrdelta;
2458c2ecf20Sopenharmony_ci	u64 iblnkerrsnap;
2468c2ecf20Sopenharmony_ci	u64 ibcctrl; /* shadow for kr_ibcctrl */
2478c2ecf20Sopenharmony_ci	u32 lastlinkrecov; /* link recovery issue */
2488c2ecf20Sopenharmony_ci	u32 cntrnamelen;
2498c2ecf20Sopenharmony_ci	u32 portcntrnamelen;
2508c2ecf20Sopenharmony_ci	u32 ncntrs;
2518c2ecf20Sopenharmony_ci	u32 nportcntrs;
2528c2ecf20Sopenharmony_ci	/* used with gpio interrupts to implement IB counters */
2538c2ecf20Sopenharmony_ci	u32 rxfc_unsupvl_errs;
2548c2ecf20Sopenharmony_ci	u32 overrun_thresh_errs;
2558c2ecf20Sopenharmony_ci	/*
2568c2ecf20Sopenharmony_ci	 * these count only cases where _successive_ LocalLinkIntegrity
2578c2ecf20Sopenharmony_ci	 * errors were seen in the receive headers of IB standard packets
2588c2ecf20Sopenharmony_ci	 */
2598c2ecf20Sopenharmony_ci	u32 lli_errs;
2608c2ecf20Sopenharmony_ci	u32 lli_counter;
2618c2ecf20Sopenharmony_ci	u64 lli_thresh;
2628c2ecf20Sopenharmony_ci	u64 sword; /* total dwords sent (sample result) */
2638c2ecf20Sopenharmony_ci	u64 rword; /* total dwords received (sample result) */
2648c2ecf20Sopenharmony_ci	u64 spkts; /* total packets sent (sample result) */
2658c2ecf20Sopenharmony_ci	u64 rpkts; /* total packets received (sample result) */
2668c2ecf20Sopenharmony_ci	u64 xmit_wait; /* # of ticks no data sent (sample result) */
2678c2ecf20Sopenharmony_ci	struct timer_list pma_timer;
2688c2ecf20Sopenharmony_ci	struct qib_pportdata *ppd;
2698c2ecf20Sopenharmony_ci	char emsgbuf[128];
2708c2ecf20Sopenharmony_ci	char bitsmsgbuf[64];
2718c2ecf20Sopenharmony_ci	u8 pma_sample_status;
2728c2ecf20Sopenharmony_ci};
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci/* ibcctrl bits */
2758c2ecf20Sopenharmony_ci#define QLOGIC_IB_IBCC_LINKINITCMD_DISABLE 1
2768c2ecf20Sopenharmony_ci/* cycle through TS1/TS2 till OK */
2778c2ecf20Sopenharmony_ci#define QLOGIC_IB_IBCC_LINKINITCMD_POLL 2
2788c2ecf20Sopenharmony_ci/* wait for TS1, then go on */
2798c2ecf20Sopenharmony_ci#define QLOGIC_IB_IBCC_LINKINITCMD_SLEEP 3
2808c2ecf20Sopenharmony_ci#define QLOGIC_IB_IBCC_LINKINITCMD_SHIFT 16
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci#define QLOGIC_IB_IBCC_LINKCMD_DOWN 1           /* move to 0x11 */
2838c2ecf20Sopenharmony_ci#define QLOGIC_IB_IBCC_LINKCMD_ARMED 2          /* move to 0x21 */
2848c2ecf20Sopenharmony_ci#define QLOGIC_IB_IBCC_LINKCMD_ACTIVE 3 /* move to 0x31 */
2858c2ecf20Sopenharmony_ci#define QLOGIC_IB_IBCC_LINKCMD_SHIFT 18
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci/*
2888c2ecf20Sopenharmony_ci * We could have a single register get/put routine, that takes a group type,
2898c2ecf20Sopenharmony_ci * but this is somewhat clearer and cleaner.  It also gives us some error
2908c2ecf20Sopenharmony_ci * checking.  64 bit register reads should always work, but are inefficient
2918c2ecf20Sopenharmony_ci * on opteron (the northbridge always generates 2 separate HT 32 bit reads),
2928c2ecf20Sopenharmony_ci * so we use kreg32 wherever possible.  User register and counter register
2938c2ecf20Sopenharmony_ci * reads are always 32 bit reads, so only one form of those routines.
2948c2ecf20Sopenharmony_ci */
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci/**
2978c2ecf20Sopenharmony_ci * qib_read_ureg32 - read 32-bit virtualized per-context register
2988c2ecf20Sopenharmony_ci * @dd: device
2998c2ecf20Sopenharmony_ci * @regno: register number
3008c2ecf20Sopenharmony_ci * @ctxt: context number
3018c2ecf20Sopenharmony_ci *
3028c2ecf20Sopenharmony_ci * Return the contents of a register that is virtualized to be per context.
3038c2ecf20Sopenharmony_ci * Returns -1 on errors (not distinguishable from valid contents at
3048c2ecf20Sopenharmony_ci * runtime; we may add a separate error variable at some point).
3058c2ecf20Sopenharmony_ci */
3068c2ecf20Sopenharmony_cistatic inline u32 qib_read_ureg32(const struct qib_devdata *dd,
3078c2ecf20Sopenharmony_ci				  enum qib_ureg regno, int ctxt)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
3108c2ecf20Sopenharmony_ci		return 0;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (dd->userbase)
3138c2ecf20Sopenharmony_ci		return readl(regno + (u64 __iomem *)
3148c2ecf20Sopenharmony_ci			     ((char __iomem *)dd->userbase +
3158c2ecf20Sopenharmony_ci			      dd->ureg_align * ctxt));
3168c2ecf20Sopenharmony_ci	else
3178c2ecf20Sopenharmony_ci		return readl(regno + (u64 __iomem *)
3188c2ecf20Sopenharmony_ci			     (dd->uregbase +
3198c2ecf20Sopenharmony_ci			      (char __iomem *)dd->kregbase +
3208c2ecf20Sopenharmony_ci			      dd->ureg_align * ctxt));
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci/**
3248c2ecf20Sopenharmony_ci * qib_write_ureg - write 32-bit virtualized per-context register
3258c2ecf20Sopenharmony_ci * @dd: device
3268c2ecf20Sopenharmony_ci * @regno: register number
3278c2ecf20Sopenharmony_ci * @value: value
3288c2ecf20Sopenharmony_ci * @ctxt: context
3298c2ecf20Sopenharmony_ci *
3308c2ecf20Sopenharmony_ci * Write the contents of a register that is virtualized to be per context.
3318c2ecf20Sopenharmony_ci */
3328c2ecf20Sopenharmony_cistatic inline void qib_write_ureg(const struct qib_devdata *dd,
3338c2ecf20Sopenharmony_ci				  enum qib_ureg regno, u64 value, int ctxt)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	u64 __iomem *ubase;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (dd->userbase)
3388c2ecf20Sopenharmony_ci		ubase = (u64 __iomem *)
3398c2ecf20Sopenharmony_ci			((char __iomem *) dd->userbase +
3408c2ecf20Sopenharmony_ci			 dd->ureg_align * ctxt);
3418c2ecf20Sopenharmony_ci	else
3428c2ecf20Sopenharmony_ci		ubase = (u64 __iomem *)
3438c2ecf20Sopenharmony_ci			(dd->uregbase +
3448c2ecf20Sopenharmony_ci			 (char __iomem *) dd->kregbase +
3458c2ecf20Sopenharmony_ci			 dd->ureg_align * ctxt);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	if (dd->kregbase && (dd->flags & QIB_PRESENT))
3488c2ecf20Sopenharmony_ci		writeq(value, &ubase[regno]);
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic inline u32 qib_read_kreg32(const struct qib_devdata *dd,
3528c2ecf20Sopenharmony_ci				  const u16 regno)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
3558c2ecf20Sopenharmony_ci		return -1;
3568c2ecf20Sopenharmony_ci	return readl((u32 __iomem *)&dd->kregbase[regno]);
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic inline u64 qib_read_kreg64(const struct qib_devdata *dd,
3608c2ecf20Sopenharmony_ci				  const u16 regno)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	if (!dd->kregbase || !(dd->flags & QIB_PRESENT))
3638c2ecf20Sopenharmony_ci		return -1;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	return readq(&dd->kregbase[regno]);
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic inline void qib_write_kreg(const struct qib_devdata *dd,
3698c2ecf20Sopenharmony_ci				  const u16 regno, u64 value)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	if (dd->kregbase && (dd->flags & QIB_PRESENT))
3728c2ecf20Sopenharmony_ci		writeq(value, &dd->kregbase[regno]);
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci/**
3768c2ecf20Sopenharmony_ci * qib_write_kreg_ctxt - write a device's per-ctxt 64-bit kernel register
3778c2ecf20Sopenharmony_ci * @dd: the qlogic_ib device
3788c2ecf20Sopenharmony_ci * @regno: the register number to write
3798c2ecf20Sopenharmony_ci * @ctxt: the context containing the register
3808c2ecf20Sopenharmony_ci * @value: the value to write
3818c2ecf20Sopenharmony_ci */
3828c2ecf20Sopenharmony_cistatic inline void qib_write_kreg_ctxt(const struct qib_devdata *dd,
3838c2ecf20Sopenharmony_ci				       const u16 regno, unsigned ctxt,
3848c2ecf20Sopenharmony_ci				       u64 value)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	qib_write_kreg(dd, regno + ctxt, value);
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic inline void write_6120_creg(const struct qib_devdata *dd,
3908c2ecf20Sopenharmony_ci				   u16 regno, u64 value)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	if (dd->cspec->cregbase && (dd->flags & QIB_PRESENT))
3938c2ecf20Sopenharmony_ci		writeq(value, &dd->cspec->cregbase[regno]);
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic inline u64 read_6120_creg(const struct qib_devdata *dd, u16 regno)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	if (!dd->cspec->cregbase || !(dd->flags & QIB_PRESENT))
3998c2ecf20Sopenharmony_ci		return 0;
4008c2ecf20Sopenharmony_ci	return readq(&dd->cspec->cregbase[regno]);
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic inline u32 read_6120_creg32(const struct qib_devdata *dd, u16 regno)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	if (!dd->cspec->cregbase || !(dd->flags & QIB_PRESENT))
4068c2ecf20Sopenharmony_ci		return 0;
4078c2ecf20Sopenharmony_ci	return readl(&dd->cspec->cregbase[regno]);
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci/* kr_control bits */
4118c2ecf20Sopenharmony_ci#define QLOGIC_IB_C_RESET 1U
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci/* kr_intstatus, kr_intclear, kr_intmask bits */
4148c2ecf20Sopenharmony_ci#define QLOGIC_IB_I_RCVURG_MASK ((1U << 5) - 1)
4158c2ecf20Sopenharmony_ci#define QLOGIC_IB_I_RCVURG_SHIFT 0
4168c2ecf20Sopenharmony_ci#define QLOGIC_IB_I_RCVAVAIL_MASK ((1U << 5) - 1)
4178c2ecf20Sopenharmony_ci#define QLOGIC_IB_I_RCVAVAIL_SHIFT 12
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci#define QLOGIC_IB_C_FREEZEMODE 0x00000002
4208c2ecf20Sopenharmony_ci#define QLOGIC_IB_C_LINKENABLE 0x00000004
4218c2ecf20Sopenharmony_ci#define QLOGIC_IB_I_ERROR               0x0000000080000000ULL
4228c2ecf20Sopenharmony_ci#define QLOGIC_IB_I_SPIOSENT            0x0000000040000000ULL
4238c2ecf20Sopenharmony_ci#define QLOGIC_IB_I_SPIOBUFAVAIL        0x0000000020000000ULL
4248c2ecf20Sopenharmony_ci#define QLOGIC_IB_I_GPIO                0x0000000010000000ULL
4258c2ecf20Sopenharmony_ci#define QLOGIC_IB_I_BITSEXTANT \
4268c2ecf20Sopenharmony_ci		((QLOGIC_IB_I_RCVURG_MASK << QLOGIC_IB_I_RCVURG_SHIFT) | \
4278c2ecf20Sopenharmony_ci		(QLOGIC_IB_I_RCVAVAIL_MASK << \
4288c2ecf20Sopenharmony_ci		 QLOGIC_IB_I_RCVAVAIL_SHIFT) | \
4298c2ecf20Sopenharmony_ci		QLOGIC_IB_I_ERROR | QLOGIC_IB_I_SPIOSENT | \
4308c2ecf20Sopenharmony_ci		QLOGIC_IB_I_SPIOBUFAVAIL | QLOGIC_IB_I_GPIO)
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
4338c2ecf20Sopenharmony_ci#define QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK  0x000000000000003fULL
4348c2ecf20Sopenharmony_ci#define QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT 0
4358c2ecf20Sopenharmony_ci#define QLOGIC_IB_HWE_PCIEPOISONEDTLP      0x0000000010000000ULL
4368c2ecf20Sopenharmony_ci#define QLOGIC_IB_HWE_PCIECPLTIMEOUT       0x0000000020000000ULL
4378c2ecf20Sopenharmony_ci#define QLOGIC_IB_HWE_PCIEBUSPARITYXTLH    0x0000000040000000ULL
4388c2ecf20Sopenharmony_ci#define QLOGIC_IB_HWE_PCIEBUSPARITYXADM    0x0000000080000000ULL
4398c2ecf20Sopenharmony_ci#define QLOGIC_IB_HWE_PCIEBUSPARITYRADM    0x0000000100000000ULL
4408c2ecf20Sopenharmony_ci#define QLOGIC_IB_HWE_COREPLL_FBSLIP       0x0080000000000000ULL
4418c2ecf20Sopenharmony_ci#define QLOGIC_IB_HWE_COREPLL_RFSLIP       0x0100000000000000ULL
4428c2ecf20Sopenharmony_ci#define QLOGIC_IB_HWE_PCIE1PLLFAILED       0x0400000000000000ULL
4438c2ecf20Sopenharmony_ci#define QLOGIC_IB_HWE_PCIE0PLLFAILED       0x0800000000000000ULL
4448c2ecf20Sopenharmony_ci#define QLOGIC_IB_HWE_SERDESPLLFAILED      0x1000000000000000ULL
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci/* kr_extstatus bits */
4488c2ecf20Sopenharmony_ci#define QLOGIC_IB_EXTS_FREQSEL 0x2
4498c2ecf20Sopenharmony_ci#define QLOGIC_IB_EXTS_SERDESSEL 0x4
4508c2ecf20Sopenharmony_ci#define QLOGIC_IB_EXTS_MEMBIST_ENDTEST     0x0000000000004000
4518c2ecf20Sopenharmony_ci#define QLOGIC_IB_EXTS_MEMBIST_FOUND       0x0000000000008000
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci/* kr_xgxsconfig bits */
4548c2ecf20Sopenharmony_ci#define QLOGIC_IB_XGXS_RESET          0x5ULL
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci#define _QIB_GPIO_SDA_NUM 1
4578c2ecf20Sopenharmony_ci#define _QIB_GPIO_SCL_NUM 0
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci/* Bits in GPIO for the added IB link interrupts */
4608c2ecf20Sopenharmony_ci#define GPIO_RXUVL_BIT 3
4618c2ecf20Sopenharmony_ci#define GPIO_OVRUN_BIT 4
4628c2ecf20Sopenharmony_ci#define GPIO_LLI_BIT 5
4638c2ecf20Sopenharmony_ci#define GPIO_ERRINTR_MASK 0x38
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci#define QLOGIC_IB_RT_BUFSIZE_MASK 0xe0000000ULL
4678c2ecf20Sopenharmony_ci#define QLOGIC_IB_RT_BUFSIZE_SHIFTVAL(tid) \
4688c2ecf20Sopenharmony_ci	((((tid) & QLOGIC_IB_RT_BUFSIZE_MASK) >> 29) + 11 - 1)
4698c2ecf20Sopenharmony_ci#define QLOGIC_IB_RT_BUFSIZE(tid) (1 << QLOGIC_IB_RT_BUFSIZE_SHIFTVAL(tid))
4708c2ecf20Sopenharmony_ci#define QLOGIC_IB_RT_IS_VALID(tid) \
4718c2ecf20Sopenharmony_ci	(((tid) & QLOGIC_IB_RT_BUFSIZE_MASK) && \
4728c2ecf20Sopenharmony_ci	 ((((tid) & QLOGIC_IB_RT_BUFSIZE_MASK) != QLOGIC_IB_RT_BUFSIZE_MASK)))
4738c2ecf20Sopenharmony_ci#define QLOGIC_IB_RT_ADDR_MASK 0x1FFFFFFFULL /* 29 bits valid */
4748c2ecf20Sopenharmony_ci#define QLOGIC_IB_RT_ADDR_SHIFT 10
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci#define QLOGIC_IB_R_INTRAVAIL_SHIFT 16
4778c2ecf20Sopenharmony_ci#define QLOGIC_IB_R_TAILUPD_SHIFT 31
4788c2ecf20Sopenharmony_ci#define IBA6120_R_PKEY_DIS_SHIFT 30
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci#define PBC_6120_VL15_SEND_CTRL (1ULL << 31) /* pbc; VL15; link_buf only */
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci#define IBCBUSFRSPCPARITYERR HWE_MASK(IBCBusFromSPCParityErr)
4838c2ecf20Sopenharmony_ci#define IBCBUSTOSPCPARITYERR HWE_MASK(IBCBusToSPCParityErr)
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci#define SYM_MASK_BIT(regname, fldname, bit) ((u64) \
4868c2ecf20Sopenharmony_ci	((1ULL << (SYM_LSB(regname, fldname) + (bit)))))
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci#define TXEMEMPARITYERR_PIOBUF \
4898c2ecf20Sopenharmony_ci	SYM_MASK_BIT(HwErrMask, TXEMemParityErrMask, 0)
4908c2ecf20Sopenharmony_ci#define TXEMEMPARITYERR_PIOPBC \
4918c2ecf20Sopenharmony_ci	SYM_MASK_BIT(HwErrMask, TXEMemParityErrMask, 1)
4928c2ecf20Sopenharmony_ci#define TXEMEMPARITYERR_PIOLAUNCHFIFO \
4938c2ecf20Sopenharmony_ci	SYM_MASK_BIT(HwErrMask, TXEMemParityErrMask, 2)
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci#define RXEMEMPARITYERR_RCVBUF \
4968c2ecf20Sopenharmony_ci	SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 0)
4978c2ecf20Sopenharmony_ci#define RXEMEMPARITYERR_LOOKUPQ \
4988c2ecf20Sopenharmony_ci	SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 1)
4998c2ecf20Sopenharmony_ci#define RXEMEMPARITYERR_EXPTID \
5008c2ecf20Sopenharmony_ci	SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 2)
5018c2ecf20Sopenharmony_ci#define RXEMEMPARITYERR_EAGERTID \
5028c2ecf20Sopenharmony_ci	SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 3)
5038c2ecf20Sopenharmony_ci#define RXEMEMPARITYERR_FLAGBUF \
5048c2ecf20Sopenharmony_ci	SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 4)
5058c2ecf20Sopenharmony_ci#define RXEMEMPARITYERR_DATAINFO \
5068c2ecf20Sopenharmony_ci	SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 5)
5078c2ecf20Sopenharmony_ci#define RXEMEMPARITYERR_HDRINFO \
5088c2ecf20Sopenharmony_ci	SYM_MASK_BIT(HwErrMask, RXEMemParityErrMask, 6)
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci/* 6120 specific hardware errors... */
5118c2ecf20Sopenharmony_cistatic const struct qib_hwerror_msgs qib_6120_hwerror_msgs[] = {
5128c2ecf20Sopenharmony_ci	/* generic hardware errors */
5138c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(IBCBUSFRSPCPARITYERR, "QIB2IB Parity"),
5148c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(IBCBUSTOSPCPARITYERR, "IB2QIB Parity"),
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(TXEMEMPARITYERR_PIOBUF,
5178c2ecf20Sopenharmony_ci			  "TXE PIOBUF Memory Parity"),
5188c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(TXEMEMPARITYERR_PIOPBC,
5198c2ecf20Sopenharmony_ci			  "TXE PIOPBC Memory Parity"),
5208c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(TXEMEMPARITYERR_PIOLAUNCHFIFO,
5218c2ecf20Sopenharmony_ci			  "TXE PIOLAUNCHFIFO Memory Parity"),
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_RCVBUF,
5248c2ecf20Sopenharmony_ci			  "RXE RCVBUF Memory Parity"),
5258c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_LOOKUPQ,
5268c2ecf20Sopenharmony_ci			  "RXE LOOKUPQ Memory Parity"),
5278c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_EAGERTID,
5288c2ecf20Sopenharmony_ci			  "RXE EAGERTID Memory Parity"),
5298c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_EXPTID,
5308c2ecf20Sopenharmony_ci			  "RXE EXPTID Memory Parity"),
5318c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_FLAGBUF,
5328c2ecf20Sopenharmony_ci			  "RXE FLAGBUF Memory Parity"),
5338c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_DATAINFO,
5348c2ecf20Sopenharmony_ci			  "RXE DATAINFO Memory Parity"),
5358c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(RXEMEMPARITYERR_HDRINFO,
5368c2ecf20Sopenharmony_ci			  "RXE HDRINFO Memory Parity"),
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	/* chip-specific hardware errors */
5398c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIEPOISONEDTLP,
5408c2ecf20Sopenharmony_ci			  "PCIe Poisoned TLP"),
5418c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIECPLTIMEOUT,
5428c2ecf20Sopenharmony_ci			  "PCIe completion timeout"),
5438c2ecf20Sopenharmony_ci	/*
5448c2ecf20Sopenharmony_ci	 * In practice, it's unlikely wthat we'll see PCIe PLL, or bus
5458c2ecf20Sopenharmony_ci	 * parity or memory parity error failures, because most likely we
5468c2ecf20Sopenharmony_ci	 * won't be able to talk to the core of the chip.  Nonetheless, we
5478c2ecf20Sopenharmony_ci	 * might see them, if they are in parts of the PCIe core that aren't
5488c2ecf20Sopenharmony_ci	 * essential.
5498c2ecf20Sopenharmony_ci	 */
5508c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIE1PLLFAILED,
5518c2ecf20Sopenharmony_ci			  "PCIePLL1"),
5528c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIE0PLLFAILED,
5538c2ecf20Sopenharmony_ci			  "PCIePLL0"),
5548c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIEBUSPARITYXTLH,
5558c2ecf20Sopenharmony_ci			  "PCIe XTLH core parity"),
5568c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIEBUSPARITYXADM,
5578c2ecf20Sopenharmony_ci			  "PCIe ADM TX core parity"),
5588c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_PCIEBUSPARITYRADM,
5598c2ecf20Sopenharmony_ci			  "PCIe ADM RX core parity"),
5608c2ecf20Sopenharmony_ci	QLOGIC_IB_HWE_MSG(QLOGIC_IB_HWE_SERDESPLLFAILED,
5618c2ecf20Sopenharmony_ci			  "SerDes PLL"),
5628c2ecf20Sopenharmony_ci};
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci#define TXE_PIO_PARITY (TXEMEMPARITYERR_PIOBUF | TXEMEMPARITYERR_PIOPBC)
5658c2ecf20Sopenharmony_ci#define _QIB_PLL_FAIL (QLOGIC_IB_HWE_COREPLL_FBSLIP |   \
5668c2ecf20Sopenharmony_ci		QLOGIC_IB_HWE_COREPLL_RFSLIP)
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	/* variables for sanity checking interrupt and errors */
5698c2ecf20Sopenharmony_ci#define IB_HWE_BITSEXTANT \
5708c2ecf20Sopenharmony_ci	(HWE_MASK(RXEMemParityErr) |					\
5718c2ecf20Sopenharmony_ci	 HWE_MASK(TXEMemParityErr) |					\
5728c2ecf20Sopenharmony_ci	 (QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK <<			\
5738c2ecf20Sopenharmony_ci	  QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT) |			\
5748c2ecf20Sopenharmony_ci	 QLOGIC_IB_HWE_PCIE1PLLFAILED |					\
5758c2ecf20Sopenharmony_ci	 QLOGIC_IB_HWE_PCIE0PLLFAILED |					\
5768c2ecf20Sopenharmony_ci	 QLOGIC_IB_HWE_PCIEPOISONEDTLP |				\
5778c2ecf20Sopenharmony_ci	 QLOGIC_IB_HWE_PCIECPLTIMEOUT |					\
5788c2ecf20Sopenharmony_ci	 QLOGIC_IB_HWE_PCIEBUSPARITYXTLH |				\
5798c2ecf20Sopenharmony_ci	 QLOGIC_IB_HWE_PCIEBUSPARITYXADM |				\
5808c2ecf20Sopenharmony_ci	 QLOGIC_IB_HWE_PCIEBUSPARITYRADM |				\
5818c2ecf20Sopenharmony_ci	 HWE_MASK(PowerOnBISTFailed) |					\
5828c2ecf20Sopenharmony_ci	 QLOGIC_IB_HWE_COREPLL_FBSLIP |					\
5838c2ecf20Sopenharmony_ci	 QLOGIC_IB_HWE_COREPLL_RFSLIP |					\
5848c2ecf20Sopenharmony_ci	 QLOGIC_IB_HWE_SERDESPLLFAILED |				\
5858c2ecf20Sopenharmony_ci	 HWE_MASK(IBCBusToSPCParityErr) |				\
5868c2ecf20Sopenharmony_ci	 HWE_MASK(IBCBusFromSPCParityErr))
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci#define IB_E_BITSEXTANT \
5898c2ecf20Sopenharmony_ci	(ERR_MASK(RcvFormatErr) | ERR_MASK(RcvVCRCErr) |		\
5908c2ecf20Sopenharmony_ci	 ERR_MASK(RcvICRCErr) | ERR_MASK(RcvMinPktLenErr) |		\
5918c2ecf20Sopenharmony_ci	 ERR_MASK(RcvMaxPktLenErr) | ERR_MASK(RcvLongPktLenErr) |	\
5928c2ecf20Sopenharmony_ci	 ERR_MASK(RcvShortPktLenErr) | ERR_MASK(RcvUnexpectedCharErr) | \
5938c2ecf20Sopenharmony_ci	 ERR_MASK(RcvUnsupportedVLErr) | ERR_MASK(RcvEBPErr) |		\
5948c2ecf20Sopenharmony_ci	 ERR_MASK(RcvIBFlowErr) | ERR_MASK(RcvBadVersionErr) |		\
5958c2ecf20Sopenharmony_ci	 ERR_MASK(RcvEgrFullErr) | ERR_MASK(RcvHdrFullErr) |		\
5968c2ecf20Sopenharmony_ci	 ERR_MASK(RcvBadTidErr) | ERR_MASK(RcvHdrLenErr) |		\
5978c2ecf20Sopenharmony_ci	 ERR_MASK(RcvHdrErr) | ERR_MASK(RcvIBLostLinkErr) |		\
5988c2ecf20Sopenharmony_ci	 ERR_MASK(SendMinPktLenErr) | ERR_MASK(SendMaxPktLenErr) |	\
5998c2ecf20Sopenharmony_ci	 ERR_MASK(SendUnderRunErr) | ERR_MASK(SendPktLenErr) |		\
6008c2ecf20Sopenharmony_ci	 ERR_MASK(SendDroppedSmpPktErr) |				\
6018c2ecf20Sopenharmony_ci	 ERR_MASK(SendDroppedDataPktErr) |				\
6028c2ecf20Sopenharmony_ci	 ERR_MASK(SendPioArmLaunchErr) |				\
6038c2ecf20Sopenharmony_ci	 ERR_MASK(SendUnexpectedPktNumErr) |				\
6048c2ecf20Sopenharmony_ci	 ERR_MASK(SendUnsupportedVLErr) | ERR_MASK(IBStatusChanged) |	\
6058c2ecf20Sopenharmony_ci	 ERR_MASK(InvalidAddrErr) | ERR_MASK(ResetNegated) |		\
6068c2ecf20Sopenharmony_ci	 ERR_MASK(HardwareErr))
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci#define QLOGIC_IB_E_PKTERRS ( \
6098c2ecf20Sopenharmony_ci		ERR_MASK(SendPktLenErr) |				\
6108c2ecf20Sopenharmony_ci		ERR_MASK(SendDroppedDataPktErr) |			\
6118c2ecf20Sopenharmony_ci		ERR_MASK(RcvVCRCErr) |					\
6128c2ecf20Sopenharmony_ci		ERR_MASK(RcvICRCErr) |					\
6138c2ecf20Sopenharmony_ci		ERR_MASK(RcvShortPktLenErr) |				\
6148c2ecf20Sopenharmony_ci		ERR_MASK(RcvEBPErr))
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci/* These are all rcv-related errors which we want to count for stats */
6178c2ecf20Sopenharmony_ci#define E_SUM_PKTERRS						\
6188c2ecf20Sopenharmony_ci	(ERR_MASK(RcvHdrLenErr) | ERR_MASK(RcvBadTidErr) |		\
6198c2ecf20Sopenharmony_ci	 ERR_MASK(RcvBadVersionErr) | ERR_MASK(RcvHdrErr) |		\
6208c2ecf20Sopenharmony_ci	 ERR_MASK(RcvLongPktLenErr) | ERR_MASK(RcvShortPktLenErr) |	\
6218c2ecf20Sopenharmony_ci	 ERR_MASK(RcvMaxPktLenErr) | ERR_MASK(RcvMinPktLenErr) |	\
6228c2ecf20Sopenharmony_ci	 ERR_MASK(RcvFormatErr) | ERR_MASK(RcvUnsupportedVLErr) |	\
6238c2ecf20Sopenharmony_ci	 ERR_MASK(RcvUnexpectedCharErr) | ERR_MASK(RcvEBPErr))
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci/* These are all send-related errors which we want to count for stats */
6268c2ecf20Sopenharmony_ci#define E_SUM_ERRS							\
6278c2ecf20Sopenharmony_ci	(ERR_MASK(SendPioArmLaunchErr) |				\
6288c2ecf20Sopenharmony_ci	 ERR_MASK(SendUnexpectedPktNumErr) |				\
6298c2ecf20Sopenharmony_ci	 ERR_MASK(SendDroppedDataPktErr) |				\
6308c2ecf20Sopenharmony_ci	 ERR_MASK(SendDroppedSmpPktErr) |				\
6318c2ecf20Sopenharmony_ci	 ERR_MASK(SendMaxPktLenErr) | ERR_MASK(SendUnsupportedVLErr) |	\
6328c2ecf20Sopenharmony_ci	 ERR_MASK(SendMinPktLenErr) | ERR_MASK(SendPktLenErr) |		\
6338c2ecf20Sopenharmony_ci	 ERR_MASK(InvalidAddrErr))
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci/*
6368c2ecf20Sopenharmony_ci * this is similar to E_SUM_ERRS, but can't ignore armlaunch, don't ignore
6378c2ecf20Sopenharmony_ci * errors not related to freeze and cancelling buffers.  Can't ignore
6388c2ecf20Sopenharmony_ci * armlaunch because could get more while still cleaning up, and need
6398c2ecf20Sopenharmony_ci * to cancel those as they happen.
6408c2ecf20Sopenharmony_ci */
6418c2ecf20Sopenharmony_ci#define E_SPKT_ERRS_IGNORE \
6428c2ecf20Sopenharmony_ci	(ERR_MASK(SendDroppedDataPktErr) |				\
6438c2ecf20Sopenharmony_ci	 ERR_MASK(SendDroppedSmpPktErr) |				\
6448c2ecf20Sopenharmony_ci	 ERR_MASK(SendMaxPktLenErr) | ERR_MASK(SendMinPktLenErr) |	\
6458c2ecf20Sopenharmony_ci	 ERR_MASK(SendPktLenErr))
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci/*
6488c2ecf20Sopenharmony_ci * these are errors that can occur when the link changes state while
6498c2ecf20Sopenharmony_ci * a packet is being sent or received.  This doesn't cover things
6508c2ecf20Sopenharmony_ci * like EBP or VCRC that can be the result of a sending having the
6518c2ecf20Sopenharmony_ci * link change state, so we receive a "known bad" packet.
6528c2ecf20Sopenharmony_ci */
6538c2ecf20Sopenharmony_ci#define E_SUM_LINK_PKTERRS		\
6548c2ecf20Sopenharmony_ci	(ERR_MASK(SendDroppedDataPktErr) |				\
6558c2ecf20Sopenharmony_ci	 ERR_MASK(SendDroppedSmpPktErr) |				\
6568c2ecf20Sopenharmony_ci	 ERR_MASK(SendMinPktLenErr) | ERR_MASK(SendPktLenErr) |		\
6578c2ecf20Sopenharmony_ci	 ERR_MASK(RcvShortPktLenErr) | ERR_MASK(RcvMinPktLenErr) |	\
6588c2ecf20Sopenharmony_ci	 ERR_MASK(RcvUnexpectedCharErr))
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic void qib_6120_put_tid_2(struct qib_devdata *, u64 __iomem *,
6618c2ecf20Sopenharmony_ci			       u32, unsigned long);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci/*
6648c2ecf20Sopenharmony_ci * On platforms using this chip, and not having ordered WC stores, we
6658c2ecf20Sopenharmony_ci * can get TXE parity errors due to speculative reads to the PIO buffers,
6668c2ecf20Sopenharmony_ci * and this, due to a chip issue can result in (many) false parity error
6678c2ecf20Sopenharmony_ci * reports.  So it's a debug print on those, and an info print on systems
6688c2ecf20Sopenharmony_ci * where the speculative reads don't occur.
6698c2ecf20Sopenharmony_ci */
6708c2ecf20Sopenharmony_cistatic void qib_6120_txe_recover(struct qib_devdata *dd)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	if (!qib_unordered_wc())
6738c2ecf20Sopenharmony_ci		qib_devinfo(dd->pcidev,
6748c2ecf20Sopenharmony_ci			    "Recovering from TXE PIO parity error\n");
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci/* enable/disable chip from delivering interrupts */
6788c2ecf20Sopenharmony_cistatic void qib_6120_set_intr_state(struct qib_devdata *dd, u32 enable)
6798c2ecf20Sopenharmony_ci{
6808c2ecf20Sopenharmony_ci	if (enable) {
6818c2ecf20Sopenharmony_ci		if (dd->flags & QIB_BADINTR)
6828c2ecf20Sopenharmony_ci			return;
6838c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_intmask, ~0ULL);
6848c2ecf20Sopenharmony_ci		/* force re-interrupt of any pending interrupts. */
6858c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_intclear, 0ULL);
6868c2ecf20Sopenharmony_ci	} else
6878c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_intmask, 0ULL);
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci/*
6918c2ecf20Sopenharmony_ci * Try to cleanup as much as possible for anything that might have gone
6928c2ecf20Sopenharmony_ci * wrong while in freeze mode, such as pio buffers being written by user
6938c2ecf20Sopenharmony_ci * processes (causing armlaunch), send errors due to going into freeze mode,
6948c2ecf20Sopenharmony_ci * etc., and try to avoid causing extra interrupts while doing so.
6958c2ecf20Sopenharmony_ci * Forcibly update the in-memory pioavail register copies after cleanup
6968c2ecf20Sopenharmony_ci * because the chip won't do it while in freeze mode (the register values
6978c2ecf20Sopenharmony_ci * themselves are kept correct).
6988c2ecf20Sopenharmony_ci * Make sure that we don't lose any important interrupts by using the chip
6998c2ecf20Sopenharmony_ci * feature that says that writing 0 to a bit in *clear that is set in
7008c2ecf20Sopenharmony_ci * *status will cause an interrupt to be generated again (if allowed by
7018c2ecf20Sopenharmony_ci * the *mask value).
7028c2ecf20Sopenharmony_ci * This is in chip-specific code because of all of the register accesses,
7038c2ecf20Sopenharmony_ci * even though the details are similar on most chips
7048c2ecf20Sopenharmony_ci */
7058c2ecf20Sopenharmony_cistatic void qib_6120_clear_freeze(struct qib_devdata *dd)
7068c2ecf20Sopenharmony_ci{
7078c2ecf20Sopenharmony_ci	/* disable error interrupts, to avoid confusion */
7088c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_errmask, 0ULL);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	/* also disable interrupts; errormask is sometimes overwritten */
7118c2ecf20Sopenharmony_ci	qib_6120_set_intr_state(dd, 0);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	qib_cancel_sends(dd->pport);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	/* clear the freeze, and be sure chip saw it */
7168c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_control, dd->control);
7178c2ecf20Sopenharmony_ci	qib_read_kreg32(dd, kr_scratch);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	/* force in-memory update now we are out of freeze */
7208c2ecf20Sopenharmony_ci	qib_force_pio_avail_update(dd);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	/*
7238c2ecf20Sopenharmony_ci	 * force new interrupt if any hwerr, error or interrupt bits are
7248c2ecf20Sopenharmony_ci	 * still set, and clear "safe" send packet errors related to freeze
7258c2ecf20Sopenharmony_ci	 * and cancelling sends.  Re-enable error interrupts before possible
7268c2ecf20Sopenharmony_ci	 * force of re-interrupt on pending interrupts.
7278c2ecf20Sopenharmony_ci	 */
7288c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_hwerrclear, 0ULL);
7298c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_errclear, E_SPKT_ERRS_IGNORE);
7308c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_errmask, dd->cspec->errormask);
7318c2ecf20Sopenharmony_ci	qib_6120_set_intr_state(dd, 1);
7328c2ecf20Sopenharmony_ci}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci/**
7358c2ecf20Sopenharmony_ci * qib_handle_6120_hwerrors - display hardware errors.
7368c2ecf20Sopenharmony_ci * @dd: the qlogic_ib device
7378c2ecf20Sopenharmony_ci * @msg: the output buffer
7388c2ecf20Sopenharmony_ci * @msgl: the size of the output buffer
7398c2ecf20Sopenharmony_ci *
7408c2ecf20Sopenharmony_ci * Use same msg buffer as regular errors to avoid excessive stack
7418c2ecf20Sopenharmony_ci * use.  Most hardware errors are catastrophic, but for right now,
7428c2ecf20Sopenharmony_ci * we'll print them and continue.  Reuse the same message buffer as
7438c2ecf20Sopenharmony_ci * handle_6120_errors() to avoid excessive stack usage.
7448c2ecf20Sopenharmony_ci */
7458c2ecf20Sopenharmony_cistatic void qib_handle_6120_hwerrors(struct qib_devdata *dd, char *msg,
7468c2ecf20Sopenharmony_ci				     size_t msgl)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	u64 hwerrs;
7498c2ecf20Sopenharmony_ci	u32 bits, ctrl;
7508c2ecf20Sopenharmony_ci	int isfatal = 0;
7518c2ecf20Sopenharmony_ci	char *bitsmsg;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	hwerrs = qib_read_kreg64(dd, kr_hwerrstatus);
7548c2ecf20Sopenharmony_ci	if (!hwerrs)
7558c2ecf20Sopenharmony_ci		return;
7568c2ecf20Sopenharmony_ci	if (hwerrs == ~0ULL) {
7578c2ecf20Sopenharmony_ci		qib_dev_err(dd,
7588c2ecf20Sopenharmony_ci			"Read of hardware error status failed (all bits set); ignoring\n");
7598c2ecf20Sopenharmony_ci		return;
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci	qib_stats.sps_hwerrs++;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	/* Always clear the error status register, except MEMBISTFAIL,
7648c2ecf20Sopenharmony_ci	 * regardless of whether we continue or stop using the chip.
7658c2ecf20Sopenharmony_ci	 * We want that set so we know it failed, even across driver reload.
7668c2ecf20Sopenharmony_ci	 * We'll still ignore it in the hwerrmask.  We do this partly for
7678c2ecf20Sopenharmony_ci	 * diagnostics, but also for support */
7688c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_hwerrclear,
7698c2ecf20Sopenharmony_ci		       hwerrs & ~HWE_MASK(PowerOnBISTFailed));
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	hwerrs &= dd->cspec->hwerrmask;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	/*
7748c2ecf20Sopenharmony_ci	 * Make sure we get this much out, unless told to be quiet,
7758c2ecf20Sopenharmony_ci	 * or it's occurred within the last 5 seconds.
7768c2ecf20Sopenharmony_ci	 */
7778c2ecf20Sopenharmony_ci	if (hwerrs & ~(TXE_PIO_PARITY | RXEMEMPARITYERR_EAGERTID))
7788c2ecf20Sopenharmony_ci		qib_devinfo(dd->pcidev,
7798c2ecf20Sopenharmony_ci			"Hardware error: hwerr=0x%llx (cleared)\n",
7808c2ecf20Sopenharmony_ci			(unsigned long long) hwerrs);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	if (hwerrs & ~IB_HWE_BITSEXTANT)
7838c2ecf20Sopenharmony_ci		qib_dev_err(dd,
7848c2ecf20Sopenharmony_ci			"hwerror interrupt with unknown errors %llx set\n",
7858c2ecf20Sopenharmony_ci			(unsigned long long)(hwerrs & ~IB_HWE_BITSEXTANT));
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	ctrl = qib_read_kreg32(dd, kr_control);
7888c2ecf20Sopenharmony_ci	if ((ctrl & QLOGIC_IB_C_FREEZEMODE) && !dd->diag_client) {
7898c2ecf20Sopenharmony_ci		/*
7908c2ecf20Sopenharmony_ci		 * Parity errors in send memory are recoverable,
7918c2ecf20Sopenharmony_ci		 * just cancel the send (if indicated in * sendbuffererror),
7928c2ecf20Sopenharmony_ci		 * count the occurrence, unfreeze (if no other handled
7938c2ecf20Sopenharmony_ci		 * hardware error bits are set), and continue. They can
7948c2ecf20Sopenharmony_ci		 * occur if a processor speculative read is done to the PIO
7958c2ecf20Sopenharmony_ci		 * buffer while we are sending a packet, for example.
7968c2ecf20Sopenharmony_ci		 */
7978c2ecf20Sopenharmony_ci		if (hwerrs & TXE_PIO_PARITY) {
7988c2ecf20Sopenharmony_ci			qib_6120_txe_recover(dd);
7998c2ecf20Sopenharmony_ci			hwerrs &= ~TXE_PIO_PARITY;
8008c2ecf20Sopenharmony_ci		}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci		if (!hwerrs) {
8038c2ecf20Sopenharmony_ci			static u32 freeze_cnt;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci			freeze_cnt++;
8068c2ecf20Sopenharmony_ci			qib_6120_clear_freeze(dd);
8078c2ecf20Sopenharmony_ci		} else
8088c2ecf20Sopenharmony_ci			isfatal = 1;
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	*msg = '\0';
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	if (hwerrs & HWE_MASK(PowerOnBISTFailed)) {
8148c2ecf20Sopenharmony_ci		isfatal = 1;
8158c2ecf20Sopenharmony_ci		strlcat(msg,
8168c2ecf20Sopenharmony_ci			"[Memory BIST test failed, InfiniPath hardware unusable]",
8178c2ecf20Sopenharmony_ci			msgl);
8188c2ecf20Sopenharmony_ci		/* ignore from now on, so disable until driver reloaded */
8198c2ecf20Sopenharmony_ci		dd->cspec->hwerrmask &= ~HWE_MASK(PowerOnBISTFailed);
8208c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
8218c2ecf20Sopenharmony_ci	}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	qib_format_hwerrors(hwerrs, qib_6120_hwerror_msgs,
8248c2ecf20Sopenharmony_ci			    ARRAY_SIZE(qib_6120_hwerror_msgs), msg, msgl);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	bitsmsg = dd->cspec->bitsmsgbuf;
8278c2ecf20Sopenharmony_ci	if (hwerrs & (QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK <<
8288c2ecf20Sopenharmony_ci		      QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT)) {
8298c2ecf20Sopenharmony_ci		bits = (u32) ((hwerrs >>
8308c2ecf20Sopenharmony_ci			       QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT) &
8318c2ecf20Sopenharmony_ci			      QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK);
8328c2ecf20Sopenharmony_ci		snprintf(bitsmsg, sizeof(dd->cspec->bitsmsgbuf),
8338c2ecf20Sopenharmony_ci			 "[PCIe Mem Parity Errs %x] ", bits);
8348c2ecf20Sopenharmony_ci		strlcat(msg, bitsmsg, msgl);
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	if (hwerrs & _QIB_PLL_FAIL) {
8388c2ecf20Sopenharmony_ci		isfatal = 1;
8398c2ecf20Sopenharmony_ci		snprintf(bitsmsg, sizeof(dd->cspec->bitsmsgbuf),
8408c2ecf20Sopenharmony_ci			 "[PLL failed (%llx), InfiniPath hardware unusable]",
8418c2ecf20Sopenharmony_ci			 (unsigned long long) hwerrs & _QIB_PLL_FAIL);
8428c2ecf20Sopenharmony_ci		strlcat(msg, bitsmsg, msgl);
8438c2ecf20Sopenharmony_ci		/* ignore from now on, so disable until driver reloaded */
8448c2ecf20Sopenharmony_ci		dd->cspec->hwerrmask &= ~(hwerrs & _QIB_PLL_FAIL);
8458c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	if (hwerrs & QLOGIC_IB_HWE_SERDESPLLFAILED) {
8498c2ecf20Sopenharmony_ci		/*
8508c2ecf20Sopenharmony_ci		 * If it occurs, it is left masked since the external
8518c2ecf20Sopenharmony_ci		 * interface is unused
8528c2ecf20Sopenharmony_ci		 */
8538c2ecf20Sopenharmony_ci		dd->cspec->hwerrmask &= ~QLOGIC_IB_HWE_SERDESPLLFAILED;
8548c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
8558c2ecf20Sopenharmony_ci	}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	if (hwerrs)
8588c2ecf20Sopenharmony_ci		/*
8598c2ecf20Sopenharmony_ci		 * if any set that we aren't ignoring; only
8608c2ecf20Sopenharmony_ci		 * make the complaint once, in case it's stuck
8618c2ecf20Sopenharmony_ci		 * or recurring, and we get here multiple
8628c2ecf20Sopenharmony_ci		 * times.
8638c2ecf20Sopenharmony_ci		 */
8648c2ecf20Sopenharmony_ci		qib_dev_err(dd, "%s hardware error\n", msg);
8658c2ecf20Sopenharmony_ci	else
8668c2ecf20Sopenharmony_ci		*msg = 0; /* recovered from all of them */
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	if (isfatal && !dd->diag_client) {
8698c2ecf20Sopenharmony_ci		qib_dev_err(dd,
8708c2ecf20Sopenharmony_ci			"Fatal Hardware Error, no longer usable, SN %.16s\n",
8718c2ecf20Sopenharmony_ci			dd->serial);
8728c2ecf20Sopenharmony_ci		/*
8738c2ecf20Sopenharmony_ci		 * for /sys status file and user programs to print; if no
8748c2ecf20Sopenharmony_ci		 * trailing brace is copied, we'll know it was truncated.
8758c2ecf20Sopenharmony_ci		 */
8768c2ecf20Sopenharmony_ci		if (dd->freezemsg)
8778c2ecf20Sopenharmony_ci			snprintf(dd->freezemsg, dd->freezelen,
8788c2ecf20Sopenharmony_ci				 "{%s}", msg);
8798c2ecf20Sopenharmony_ci		qib_disable_after_error(dd);
8808c2ecf20Sopenharmony_ci	}
8818c2ecf20Sopenharmony_ci}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci/*
8848c2ecf20Sopenharmony_ci * Decode the error status into strings, deciding whether to always
8858c2ecf20Sopenharmony_ci * print * it or not depending on "normal packet errors" vs everything
8868c2ecf20Sopenharmony_ci * else.   Return 1 if "real" errors, otherwise 0 if only packet
8878c2ecf20Sopenharmony_ci * errors, so caller can decide what to print with the string.
8888c2ecf20Sopenharmony_ci */
8898c2ecf20Sopenharmony_cistatic int qib_decode_6120_err(struct qib_devdata *dd, char *buf, size_t blen,
8908c2ecf20Sopenharmony_ci			       u64 err)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	int iserr = 1;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	*buf = '\0';
8958c2ecf20Sopenharmony_ci	if (err & QLOGIC_IB_E_PKTERRS) {
8968c2ecf20Sopenharmony_ci		if (!(err & ~QLOGIC_IB_E_PKTERRS))
8978c2ecf20Sopenharmony_ci			iserr = 0;
8988c2ecf20Sopenharmony_ci		if ((err & ERR_MASK(RcvICRCErr)) &&
8998c2ecf20Sopenharmony_ci		    !(err&(ERR_MASK(RcvVCRCErr)|ERR_MASK(RcvEBPErr))))
9008c2ecf20Sopenharmony_ci			strlcat(buf, "CRC ", blen);
9018c2ecf20Sopenharmony_ci		if (!iserr)
9028c2ecf20Sopenharmony_ci			goto done;
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvHdrLenErr))
9058c2ecf20Sopenharmony_ci		strlcat(buf, "rhdrlen ", blen);
9068c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvBadTidErr))
9078c2ecf20Sopenharmony_ci		strlcat(buf, "rbadtid ", blen);
9088c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvBadVersionErr))
9098c2ecf20Sopenharmony_ci		strlcat(buf, "rbadversion ", blen);
9108c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvHdrErr))
9118c2ecf20Sopenharmony_ci		strlcat(buf, "rhdr ", blen);
9128c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvLongPktLenErr))
9138c2ecf20Sopenharmony_ci		strlcat(buf, "rlongpktlen ", blen);
9148c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvMaxPktLenErr))
9158c2ecf20Sopenharmony_ci		strlcat(buf, "rmaxpktlen ", blen);
9168c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvMinPktLenErr))
9178c2ecf20Sopenharmony_ci		strlcat(buf, "rminpktlen ", blen);
9188c2ecf20Sopenharmony_ci	if (err & ERR_MASK(SendMinPktLenErr))
9198c2ecf20Sopenharmony_ci		strlcat(buf, "sminpktlen ", blen);
9208c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvFormatErr))
9218c2ecf20Sopenharmony_ci		strlcat(buf, "rformaterr ", blen);
9228c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvUnsupportedVLErr))
9238c2ecf20Sopenharmony_ci		strlcat(buf, "runsupvl ", blen);
9248c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvUnexpectedCharErr))
9258c2ecf20Sopenharmony_ci		strlcat(buf, "runexpchar ", blen);
9268c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvIBFlowErr))
9278c2ecf20Sopenharmony_ci		strlcat(buf, "ribflow ", blen);
9288c2ecf20Sopenharmony_ci	if (err & ERR_MASK(SendUnderRunErr))
9298c2ecf20Sopenharmony_ci		strlcat(buf, "sunderrun ", blen);
9308c2ecf20Sopenharmony_ci	if (err & ERR_MASK(SendPioArmLaunchErr))
9318c2ecf20Sopenharmony_ci		strlcat(buf, "spioarmlaunch ", blen);
9328c2ecf20Sopenharmony_ci	if (err & ERR_MASK(SendUnexpectedPktNumErr))
9338c2ecf20Sopenharmony_ci		strlcat(buf, "sunexperrpktnum ", blen);
9348c2ecf20Sopenharmony_ci	if (err & ERR_MASK(SendDroppedSmpPktErr))
9358c2ecf20Sopenharmony_ci		strlcat(buf, "sdroppedsmppkt ", blen);
9368c2ecf20Sopenharmony_ci	if (err & ERR_MASK(SendMaxPktLenErr))
9378c2ecf20Sopenharmony_ci		strlcat(buf, "smaxpktlen ", blen);
9388c2ecf20Sopenharmony_ci	if (err & ERR_MASK(SendUnsupportedVLErr))
9398c2ecf20Sopenharmony_ci		strlcat(buf, "sunsupVL ", blen);
9408c2ecf20Sopenharmony_ci	if (err & ERR_MASK(InvalidAddrErr))
9418c2ecf20Sopenharmony_ci		strlcat(buf, "invalidaddr ", blen);
9428c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvEgrFullErr))
9438c2ecf20Sopenharmony_ci		strlcat(buf, "rcvegrfull ", blen);
9448c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvHdrFullErr))
9458c2ecf20Sopenharmony_ci		strlcat(buf, "rcvhdrfull ", blen);
9468c2ecf20Sopenharmony_ci	if (err & ERR_MASK(IBStatusChanged))
9478c2ecf20Sopenharmony_ci		strlcat(buf, "ibcstatuschg ", blen);
9488c2ecf20Sopenharmony_ci	if (err & ERR_MASK(RcvIBLostLinkErr))
9498c2ecf20Sopenharmony_ci		strlcat(buf, "riblostlink ", blen);
9508c2ecf20Sopenharmony_ci	if (err & ERR_MASK(HardwareErr))
9518c2ecf20Sopenharmony_ci		strlcat(buf, "hardware ", blen);
9528c2ecf20Sopenharmony_ci	if (err & ERR_MASK(ResetNegated))
9538c2ecf20Sopenharmony_ci		strlcat(buf, "reset ", blen);
9548c2ecf20Sopenharmony_cidone:
9558c2ecf20Sopenharmony_ci	return iserr;
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci/*
9598c2ecf20Sopenharmony_ci * Called when we might have an error that is specific to a particular
9608c2ecf20Sopenharmony_ci * PIO buffer, and may need to cancel that buffer, so it can be re-used.
9618c2ecf20Sopenharmony_ci */
9628c2ecf20Sopenharmony_cistatic void qib_disarm_6120_senderrbufs(struct qib_pportdata *ppd)
9638c2ecf20Sopenharmony_ci{
9648c2ecf20Sopenharmony_ci	unsigned long sbuf[2];
9658c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	/*
9688c2ecf20Sopenharmony_ci	 * It's possible that sendbuffererror could have bits set; might
9698c2ecf20Sopenharmony_ci	 * have already done this as a result of hardware error handling.
9708c2ecf20Sopenharmony_ci	 */
9718c2ecf20Sopenharmony_ci	sbuf[0] = qib_read_kreg64(dd, kr_sendbuffererror);
9728c2ecf20Sopenharmony_ci	sbuf[1] = qib_read_kreg64(dd, kr_sendbuffererror + 1);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	if (sbuf[0] || sbuf[1])
9758c2ecf20Sopenharmony_ci		qib_disarm_piobufs_set(dd, sbuf,
9768c2ecf20Sopenharmony_ci				       dd->piobcnt2k + dd->piobcnt4k);
9778c2ecf20Sopenharmony_ci}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_cistatic int chk_6120_linkrecovery(struct qib_devdata *dd, u64 ibcs)
9808c2ecf20Sopenharmony_ci{
9818c2ecf20Sopenharmony_ci	int ret = 1;
9828c2ecf20Sopenharmony_ci	u32 ibstate = qib_6120_iblink_state(ibcs);
9838c2ecf20Sopenharmony_ci	u32 linkrecov = read_6120_creg32(dd, cr_iblinkerrrecov);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (linkrecov != dd->cspec->lastlinkrecov) {
9868c2ecf20Sopenharmony_ci		/* and no more until active again */
9878c2ecf20Sopenharmony_ci		dd->cspec->lastlinkrecov = 0;
9888c2ecf20Sopenharmony_ci		qib_set_linkstate(dd->pport, QIB_IB_LINKDOWN);
9898c2ecf20Sopenharmony_ci		ret = 0;
9908c2ecf20Sopenharmony_ci	}
9918c2ecf20Sopenharmony_ci	if (ibstate == IB_PORT_ACTIVE)
9928c2ecf20Sopenharmony_ci		dd->cspec->lastlinkrecov =
9938c2ecf20Sopenharmony_ci			read_6120_creg32(dd, cr_iblinkerrrecov);
9948c2ecf20Sopenharmony_ci	return ret;
9958c2ecf20Sopenharmony_ci}
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_cistatic void handle_6120_errors(struct qib_devdata *dd, u64 errs)
9988c2ecf20Sopenharmony_ci{
9998c2ecf20Sopenharmony_ci	char *msg;
10008c2ecf20Sopenharmony_ci	u64 ignore_this_time = 0;
10018c2ecf20Sopenharmony_ci	u64 iserr = 0;
10028c2ecf20Sopenharmony_ci	struct qib_pportdata *ppd = dd->pport;
10038c2ecf20Sopenharmony_ci	u64 mask;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	/* don't report errors that are masked */
10068c2ecf20Sopenharmony_ci	errs &= dd->cspec->errormask;
10078c2ecf20Sopenharmony_ci	msg = dd->cspec->emsgbuf;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	/* do these first, they are most important */
10108c2ecf20Sopenharmony_ci	if (errs & ERR_MASK(HardwareErr))
10118c2ecf20Sopenharmony_ci		qib_handle_6120_hwerrors(dd, msg, sizeof(dd->cspec->emsgbuf));
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	if (errs & ~IB_E_BITSEXTANT)
10148c2ecf20Sopenharmony_ci		qib_dev_err(dd,
10158c2ecf20Sopenharmony_ci			"error interrupt with unknown errors %llx set\n",
10168c2ecf20Sopenharmony_ci			(unsigned long long) (errs & ~IB_E_BITSEXTANT));
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	if (errs & E_SUM_ERRS) {
10198c2ecf20Sopenharmony_ci		qib_disarm_6120_senderrbufs(ppd);
10208c2ecf20Sopenharmony_ci		if ((errs & E_SUM_LINK_PKTERRS) &&
10218c2ecf20Sopenharmony_ci		    !(ppd->lflags & QIBL_LINKACTIVE)) {
10228c2ecf20Sopenharmony_ci			/*
10238c2ecf20Sopenharmony_ci			 * This can happen when trying to bring the link
10248c2ecf20Sopenharmony_ci			 * up, but the IB link changes state at the "wrong"
10258c2ecf20Sopenharmony_ci			 * time. The IB logic then complains that the packet
10268c2ecf20Sopenharmony_ci			 * isn't valid.  We don't want to confuse people, so
10278c2ecf20Sopenharmony_ci			 * we just don't print them, except at debug
10288c2ecf20Sopenharmony_ci			 */
10298c2ecf20Sopenharmony_ci			ignore_this_time = errs & E_SUM_LINK_PKTERRS;
10308c2ecf20Sopenharmony_ci		}
10318c2ecf20Sopenharmony_ci	} else if ((errs & E_SUM_LINK_PKTERRS) &&
10328c2ecf20Sopenharmony_ci		   !(ppd->lflags & QIBL_LINKACTIVE)) {
10338c2ecf20Sopenharmony_ci		/*
10348c2ecf20Sopenharmony_ci		 * This can happen when SMA is trying to bring the link
10358c2ecf20Sopenharmony_ci		 * up, but the IB link changes state at the "wrong" time.
10368c2ecf20Sopenharmony_ci		 * The IB logic then complains that the packet isn't
10378c2ecf20Sopenharmony_ci		 * valid.  We don't want to confuse people, so we just
10388c2ecf20Sopenharmony_ci		 * don't print them, except at debug
10398c2ecf20Sopenharmony_ci		 */
10408c2ecf20Sopenharmony_ci		ignore_this_time = errs & E_SUM_LINK_PKTERRS;
10418c2ecf20Sopenharmony_ci	}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_errclear, errs);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	errs &= ~ignore_this_time;
10468c2ecf20Sopenharmony_ci	if (!errs)
10478c2ecf20Sopenharmony_ci		goto done;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	/*
10508c2ecf20Sopenharmony_ci	 * The ones we mask off are handled specially below
10518c2ecf20Sopenharmony_ci	 * or above.
10528c2ecf20Sopenharmony_ci	 */
10538c2ecf20Sopenharmony_ci	mask = ERR_MASK(IBStatusChanged) | ERR_MASK(RcvEgrFullErr) |
10548c2ecf20Sopenharmony_ci		ERR_MASK(RcvHdrFullErr) | ERR_MASK(HardwareErr);
10558c2ecf20Sopenharmony_ci	qib_decode_6120_err(dd, msg, sizeof(dd->cspec->emsgbuf), errs & ~mask);
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	if (errs & E_SUM_PKTERRS)
10588c2ecf20Sopenharmony_ci		qib_stats.sps_rcverrs++;
10598c2ecf20Sopenharmony_ci	if (errs & E_SUM_ERRS)
10608c2ecf20Sopenharmony_ci		qib_stats.sps_txerrs++;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	iserr = errs & ~(E_SUM_PKTERRS | QLOGIC_IB_E_PKTERRS);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	if (errs & ERR_MASK(IBStatusChanged)) {
10658c2ecf20Sopenharmony_ci		u64 ibcs = qib_read_kreg64(dd, kr_ibcstatus);
10668c2ecf20Sopenharmony_ci		u32 ibstate = qib_6120_iblink_state(ibcs);
10678c2ecf20Sopenharmony_ci		int handle = 1;
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci		if (ibstate != IB_PORT_INIT && dd->cspec->lastlinkrecov)
10708c2ecf20Sopenharmony_ci			handle = chk_6120_linkrecovery(dd, ibcs);
10718c2ecf20Sopenharmony_ci		/*
10728c2ecf20Sopenharmony_ci		 * Since going into a recovery state causes the link state
10738c2ecf20Sopenharmony_ci		 * to go down and since recovery is transitory, it is better
10748c2ecf20Sopenharmony_ci		 * if we "miss" ever seeing the link training state go into
10758c2ecf20Sopenharmony_ci		 * recovery (i.e., ignore this transition for link state
10768c2ecf20Sopenharmony_ci		 * special handling purposes) without updating lastibcstat.
10778c2ecf20Sopenharmony_ci		 */
10788c2ecf20Sopenharmony_ci		if (handle && qib_6120_phys_portstate(ibcs) ==
10798c2ecf20Sopenharmony_ci					    IB_PHYSPORTSTATE_LINK_ERR_RECOVER)
10808c2ecf20Sopenharmony_ci			handle = 0;
10818c2ecf20Sopenharmony_ci		if (handle)
10828c2ecf20Sopenharmony_ci			qib_handle_e_ibstatuschanged(ppd, ibcs);
10838c2ecf20Sopenharmony_ci	}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	if (errs & ERR_MASK(ResetNegated)) {
10868c2ecf20Sopenharmony_ci		qib_dev_err(dd,
10878c2ecf20Sopenharmony_ci			"Got reset, requires re-init (unload and reload driver)\n");
10888c2ecf20Sopenharmony_ci		dd->flags &= ~QIB_INITTED;  /* needs re-init */
10898c2ecf20Sopenharmony_ci		/* mark as having had error */
10908c2ecf20Sopenharmony_ci		*dd->devstatusp |= QIB_STATUS_HWERROR;
10918c2ecf20Sopenharmony_ci		*dd->pport->statusp &= ~QIB_STATUS_IB_CONF;
10928c2ecf20Sopenharmony_ci	}
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	if (*msg && iserr)
10958c2ecf20Sopenharmony_ci		qib_dev_porterr(dd, ppd->port, "%s error\n", msg);
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	if (ppd->state_wanted & ppd->lflags)
10988c2ecf20Sopenharmony_ci		wake_up_interruptible(&ppd->state_wait);
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	/*
11018c2ecf20Sopenharmony_ci	 * If there were hdrq or egrfull errors, wake up any processes
11028c2ecf20Sopenharmony_ci	 * waiting in poll.  We used to try to check which contexts had
11038c2ecf20Sopenharmony_ci	 * the overflow, but given the cost of that and the chip reads
11048c2ecf20Sopenharmony_ci	 * to support it, it's better to just wake everybody up if we
11058c2ecf20Sopenharmony_ci	 * get an overflow; waiters can poll again if it's not them.
11068c2ecf20Sopenharmony_ci	 */
11078c2ecf20Sopenharmony_ci	if (errs & (ERR_MASK(RcvEgrFullErr) | ERR_MASK(RcvHdrFullErr))) {
11088c2ecf20Sopenharmony_ci		qib_handle_urcv(dd, ~0U);
11098c2ecf20Sopenharmony_ci		if (errs & ERR_MASK(RcvEgrFullErr))
11108c2ecf20Sopenharmony_ci			qib_stats.sps_buffull++;
11118c2ecf20Sopenharmony_ci		else
11128c2ecf20Sopenharmony_ci			qib_stats.sps_hdrfull++;
11138c2ecf20Sopenharmony_ci	}
11148c2ecf20Sopenharmony_cidone:
11158c2ecf20Sopenharmony_ci	return;
11168c2ecf20Sopenharmony_ci}
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci/**
11198c2ecf20Sopenharmony_ci * qib_6120_init_hwerrors - enable hardware errors
11208c2ecf20Sopenharmony_ci * @dd: the qlogic_ib device
11218c2ecf20Sopenharmony_ci *
11228c2ecf20Sopenharmony_ci * now that we have finished initializing everything that might reasonably
11238c2ecf20Sopenharmony_ci * cause a hardware error, and cleared those errors bits as they occur,
11248c2ecf20Sopenharmony_ci * we can enable hardware errors in the mask (potentially enabling
11258c2ecf20Sopenharmony_ci * freeze mode), and enable hardware errors as errors (along with
11268c2ecf20Sopenharmony_ci * everything else) in errormask
11278c2ecf20Sopenharmony_ci */
11288c2ecf20Sopenharmony_cistatic void qib_6120_init_hwerrors(struct qib_devdata *dd)
11298c2ecf20Sopenharmony_ci{
11308c2ecf20Sopenharmony_ci	u64 val;
11318c2ecf20Sopenharmony_ci	u64 extsval;
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	extsval = qib_read_kreg64(dd, kr_extstatus);
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	if (!(extsval & QLOGIC_IB_EXTS_MEMBIST_ENDTEST))
11368c2ecf20Sopenharmony_ci		qib_dev_err(dd, "MemBIST did not complete!\n");
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	/* init so all hwerrors interrupt, and enter freeze, ajdust below */
11398c2ecf20Sopenharmony_ci	val = ~0ULL;
11408c2ecf20Sopenharmony_ci	if (dd->minrev < 2) {
11418c2ecf20Sopenharmony_ci		/*
11428c2ecf20Sopenharmony_ci		 * Avoid problem with internal interface bus parity
11438c2ecf20Sopenharmony_ci		 * checking. Fixed in Rev2.
11448c2ecf20Sopenharmony_ci		 */
11458c2ecf20Sopenharmony_ci		val &= ~QLOGIC_IB_HWE_PCIEBUSPARITYRADM;
11468c2ecf20Sopenharmony_ci	}
11478c2ecf20Sopenharmony_ci	/* avoid some intel cpu's speculative read freeze mode issue */
11488c2ecf20Sopenharmony_ci	val &= ~TXEMEMPARITYERR_PIOBUF;
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	dd->cspec->hwerrmask = val;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_hwerrclear, ~HWE_MASK(PowerOnBISTFailed));
11538c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask);
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	/* clear all */
11568c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_errclear, ~0ULL);
11578c2ecf20Sopenharmony_ci	/* enable errors that are masked, at least this first time. */
11588c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_errmask, ~0ULL);
11598c2ecf20Sopenharmony_ci	dd->cspec->errormask = qib_read_kreg64(dd, kr_errmask);
11608c2ecf20Sopenharmony_ci	/* clear any interrupts up to this point (ints still not enabled) */
11618c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_intclear, ~0ULL);
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_rcvbthqp,
11648c2ecf20Sopenharmony_ci		       dd->qpn_mask << (QIB_6120_RcvBTHQP_BTHQP_Mask_LSB - 1) |
11658c2ecf20Sopenharmony_ci		       QIB_KD_QP);
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci/*
11698c2ecf20Sopenharmony_ci * Disable and enable the armlaunch error.  Used for PIO bandwidth testing
11708c2ecf20Sopenharmony_ci * on chips that are count-based, rather than trigger-based.  There is no
11718c2ecf20Sopenharmony_ci * reference counting, but that's also fine, given the intended use.
11728c2ecf20Sopenharmony_ci * Only chip-specific because it's all register accesses
11738c2ecf20Sopenharmony_ci */
11748c2ecf20Sopenharmony_cistatic void qib_set_6120_armlaunch(struct qib_devdata *dd, u32 enable)
11758c2ecf20Sopenharmony_ci{
11768c2ecf20Sopenharmony_ci	if (enable) {
11778c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_errclear,
11788c2ecf20Sopenharmony_ci			       ERR_MASK(SendPioArmLaunchErr));
11798c2ecf20Sopenharmony_ci		dd->cspec->errormask |= ERR_MASK(SendPioArmLaunchErr);
11808c2ecf20Sopenharmony_ci	} else
11818c2ecf20Sopenharmony_ci		dd->cspec->errormask &= ~ERR_MASK(SendPioArmLaunchErr);
11828c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_errmask, dd->cspec->errormask);
11838c2ecf20Sopenharmony_ci}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci/*
11868c2ecf20Sopenharmony_ci * Formerly took parameter <which> in pre-shifted,
11878c2ecf20Sopenharmony_ci * pre-merged form with LinkCmd and LinkInitCmd
11888c2ecf20Sopenharmony_ci * together, and assuming the zero was NOP.
11898c2ecf20Sopenharmony_ci */
11908c2ecf20Sopenharmony_cistatic void qib_set_ib_6120_lstate(struct qib_pportdata *ppd, u16 linkcmd,
11918c2ecf20Sopenharmony_ci				   u16 linitcmd)
11928c2ecf20Sopenharmony_ci{
11938c2ecf20Sopenharmony_ci	u64 mod_wd;
11948c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
11958c2ecf20Sopenharmony_ci	unsigned long flags;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	if (linitcmd == QLOGIC_IB_IBCC_LINKINITCMD_DISABLE) {
11988c2ecf20Sopenharmony_ci		/*
11998c2ecf20Sopenharmony_ci		 * If we are told to disable, note that so link-recovery
12008c2ecf20Sopenharmony_ci		 * code does not attempt to bring us back up.
12018c2ecf20Sopenharmony_ci		 */
12028c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ppd->lflags_lock, flags);
12038c2ecf20Sopenharmony_ci		ppd->lflags |= QIBL_IB_LINK_DISABLED;
12048c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ppd->lflags_lock, flags);
12058c2ecf20Sopenharmony_ci	} else if (linitcmd || linkcmd == QLOGIC_IB_IBCC_LINKCMD_DOWN) {
12068c2ecf20Sopenharmony_ci		/*
12078c2ecf20Sopenharmony_ci		 * Any other linkinitcmd will lead to LINKDOWN and then
12088c2ecf20Sopenharmony_ci		 * to INIT (if all is well), so clear flag to let
12098c2ecf20Sopenharmony_ci		 * link-recovery code attempt to bring us back up.
12108c2ecf20Sopenharmony_ci		 */
12118c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ppd->lflags_lock, flags);
12128c2ecf20Sopenharmony_ci		ppd->lflags &= ~QIBL_IB_LINK_DISABLED;
12138c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ppd->lflags_lock, flags);
12148c2ecf20Sopenharmony_ci	}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	mod_wd = (linkcmd << QLOGIC_IB_IBCC_LINKCMD_SHIFT) |
12178c2ecf20Sopenharmony_ci		(linitcmd << QLOGIC_IB_IBCC_LINKINITCMD_SHIFT);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_ibcctrl, dd->cspec->ibcctrl | mod_wd);
12208c2ecf20Sopenharmony_ci	/* write to chip to prevent back-to-back writes of control reg */
12218c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_scratch, 0);
12228c2ecf20Sopenharmony_ci}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci/**
12258c2ecf20Sopenharmony_ci * qib_6120_bringup_serdes - bring up the serdes
12268c2ecf20Sopenharmony_ci * @dd: the qlogic_ib device
12278c2ecf20Sopenharmony_ci */
12288c2ecf20Sopenharmony_cistatic int qib_6120_bringup_serdes(struct qib_pportdata *ppd)
12298c2ecf20Sopenharmony_ci{
12308c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
12318c2ecf20Sopenharmony_ci	u64 val, config1, prev_val, hwstat, ibc;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	/* Put IBC in reset, sends disabled */
12348c2ecf20Sopenharmony_ci	dd->control &= ~QLOGIC_IB_C_LINKENABLE;
12358c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_control, 0ULL);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	dd->cspec->ibdeltainprog = 1;
12388c2ecf20Sopenharmony_ci	dd->cspec->ibsymsnap = read_6120_creg32(dd, cr_ibsymbolerr);
12398c2ecf20Sopenharmony_ci	dd->cspec->iblnkerrsnap = read_6120_creg32(dd, cr_iblinkerrrecov);
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	/* flowcontrolwatermark is in units of KBytes */
12428c2ecf20Sopenharmony_ci	ibc = 0x5ULL << SYM_LSB(IBCCtrl, FlowCtrlWaterMark);
12438c2ecf20Sopenharmony_ci	/*
12448c2ecf20Sopenharmony_ci	 * How often flowctrl sent.  More or less in usecs; balance against
12458c2ecf20Sopenharmony_ci	 * watermark value, so that in theory senders always get a flow
12468c2ecf20Sopenharmony_ci	 * control update in time to not let the IB link go idle.
12478c2ecf20Sopenharmony_ci	 */
12488c2ecf20Sopenharmony_ci	ibc |= 0x3ULL << SYM_LSB(IBCCtrl, FlowCtrlPeriod);
12498c2ecf20Sopenharmony_ci	/* max error tolerance */
12508c2ecf20Sopenharmony_ci	dd->cspec->lli_thresh = 0xf;
12518c2ecf20Sopenharmony_ci	ibc |= (u64) dd->cspec->lli_thresh << SYM_LSB(IBCCtrl, PhyerrThreshold);
12528c2ecf20Sopenharmony_ci	/* use "real" buffer space for */
12538c2ecf20Sopenharmony_ci	ibc |= 4ULL << SYM_LSB(IBCCtrl, CreditScale);
12548c2ecf20Sopenharmony_ci	/* IB credit flow control. */
12558c2ecf20Sopenharmony_ci	ibc |= 0xfULL << SYM_LSB(IBCCtrl, OverrunThreshold);
12568c2ecf20Sopenharmony_ci	/*
12578c2ecf20Sopenharmony_ci	 * set initial max size pkt IBC will send, including ICRC; it's the
12588c2ecf20Sopenharmony_ci	 * PIO buffer size in dwords, less 1; also see qib_set_mtu()
12598c2ecf20Sopenharmony_ci	 */
12608c2ecf20Sopenharmony_ci	ibc |= ((u64)(ppd->ibmaxlen >> 2) + 1) << SYM_LSB(IBCCtrl, MaxPktLen);
12618c2ecf20Sopenharmony_ci	dd->cspec->ibcctrl = ibc; /* without linkcmd or linkinitcmd! */
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	/* initially come up waiting for TS1, without sending anything. */
12648c2ecf20Sopenharmony_ci	val = dd->cspec->ibcctrl | (QLOGIC_IB_IBCC_LINKINITCMD_DISABLE <<
12658c2ecf20Sopenharmony_ci		QLOGIC_IB_IBCC_LINKINITCMD_SHIFT);
12668c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_ibcctrl, val);
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	val = qib_read_kreg64(dd, kr_serdes_cfg0);
12698c2ecf20Sopenharmony_ci	config1 = qib_read_kreg64(dd, kr_serdes_cfg1);
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	/*
12728c2ecf20Sopenharmony_ci	 * Force reset on, also set rxdetect enable.  Must do before reading
12738c2ecf20Sopenharmony_ci	 * serdesstatus at least for simulation, or some of the bits in
12748c2ecf20Sopenharmony_ci	 * serdes status will come back as undefined and cause simulation
12758c2ecf20Sopenharmony_ci	 * failures
12768c2ecf20Sopenharmony_ci	 */
12778c2ecf20Sopenharmony_ci	val |= SYM_MASK(SerdesCfg0, ResetPLL) |
12788c2ecf20Sopenharmony_ci		SYM_MASK(SerdesCfg0, RxDetEnX) |
12798c2ecf20Sopenharmony_ci		(SYM_MASK(SerdesCfg0, L1PwrDnA) |
12808c2ecf20Sopenharmony_ci		 SYM_MASK(SerdesCfg0, L1PwrDnB) |
12818c2ecf20Sopenharmony_ci		 SYM_MASK(SerdesCfg0, L1PwrDnC) |
12828c2ecf20Sopenharmony_ci		 SYM_MASK(SerdesCfg0, L1PwrDnD));
12838c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_serdes_cfg0, val);
12848c2ecf20Sopenharmony_ci	/* be sure chip saw it */
12858c2ecf20Sopenharmony_ci	qib_read_kreg64(dd, kr_scratch);
12868c2ecf20Sopenharmony_ci	udelay(5);              /* need pll reset set at least for a bit */
12878c2ecf20Sopenharmony_ci	/*
12888c2ecf20Sopenharmony_ci	 * after PLL is reset, set the per-lane Resets and TxIdle and
12898c2ecf20Sopenharmony_ci	 * clear the PLL reset and rxdetect (to get falling edge).
12908c2ecf20Sopenharmony_ci	 * Leave L1PWR bits set (permanently)
12918c2ecf20Sopenharmony_ci	 */
12928c2ecf20Sopenharmony_ci	val &= ~(SYM_MASK(SerdesCfg0, RxDetEnX) |
12938c2ecf20Sopenharmony_ci		 SYM_MASK(SerdesCfg0, ResetPLL) |
12948c2ecf20Sopenharmony_ci		 (SYM_MASK(SerdesCfg0, L1PwrDnA) |
12958c2ecf20Sopenharmony_ci		  SYM_MASK(SerdesCfg0, L1PwrDnB) |
12968c2ecf20Sopenharmony_ci		  SYM_MASK(SerdesCfg0, L1PwrDnC) |
12978c2ecf20Sopenharmony_ci		  SYM_MASK(SerdesCfg0, L1PwrDnD)));
12988c2ecf20Sopenharmony_ci	val |= (SYM_MASK(SerdesCfg0, ResetA) |
12998c2ecf20Sopenharmony_ci		SYM_MASK(SerdesCfg0, ResetB) |
13008c2ecf20Sopenharmony_ci		SYM_MASK(SerdesCfg0, ResetC) |
13018c2ecf20Sopenharmony_ci		SYM_MASK(SerdesCfg0, ResetD)) |
13028c2ecf20Sopenharmony_ci		SYM_MASK(SerdesCfg0, TxIdeEnX);
13038c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_serdes_cfg0, val);
13048c2ecf20Sopenharmony_ci	/* be sure chip saw it */
13058c2ecf20Sopenharmony_ci	(void) qib_read_kreg64(dd, kr_scratch);
13068c2ecf20Sopenharmony_ci	/* need PLL reset clear for at least 11 usec before lane
13078c2ecf20Sopenharmony_ci	 * resets cleared; give it a few more to be sure */
13088c2ecf20Sopenharmony_ci	udelay(15);
13098c2ecf20Sopenharmony_ci	val &= ~((SYM_MASK(SerdesCfg0, ResetA) |
13108c2ecf20Sopenharmony_ci		  SYM_MASK(SerdesCfg0, ResetB) |
13118c2ecf20Sopenharmony_ci		  SYM_MASK(SerdesCfg0, ResetC) |
13128c2ecf20Sopenharmony_ci		  SYM_MASK(SerdesCfg0, ResetD)) |
13138c2ecf20Sopenharmony_ci		 SYM_MASK(SerdesCfg0, TxIdeEnX));
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_serdes_cfg0, val);
13168c2ecf20Sopenharmony_ci	/* be sure chip saw it */
13178c2ecf20Sopenharmony_ci	(void) qib_read_kreg64(dd, kr_scratch);
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	val = qib_read_kreg64(dd, kr_xgxs_cfg);
13208c2ecf20Sopenharmony_ci	prev_val = val;
13218c2ecf20Sopenharmony_ci	if (val & QLOGIC_IB_XGXS_RESET)
13228c2ecf20Sopenharmony_ci		val &= ~QLOGIC_IB_XGXS_RESET;
13238c2ecf20Sopenharmony_ci	if (SYM_FIELD(val, XGXSCfg, polarity_inv) != ppd->rx_pol_inv) {
13248c2ecf20Sopenharmony_ci		/* need to compensate for Tx inversion in partner */
13258c2ecf20Sopenharmony_ci		val &= ~SYM_MASK(XGXSCfg, polarity_inv);
13268c2ecf20Sopenharmony_ci		val |= (u64)ppd->rx_pol_inv << SYM_LSB(XGXSCfg, polarity_inv);
13278c2ecf20Sopenharmony_ci	}
13288c2ecf20Sopenharmony_ci	if (val != prev_val)
13298c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_xgxs_cfg, val);
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	val = qib_read_kreg64(dd, kr_serdes_cfg0);
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	/* clear current and de-emphasis bits */
13348c2ecf20Sopenharmony_ci	config1 &= ~0x0ffffffff00ULL;
13358c2ecf20Sopenharmony_ci	/* set current to 20ma */
13368c2ecf20Sopenharmony_ci	config1 |= 0x00000000000ULL;
13378c2ecf20Sopenharmony_ci	/* set de-emphasis to -5.68dB */
13388c2ecf20Sopenharmony_ci	config1 |= 0x0cccc000000ULL;
13398c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_serdes_cfg1, config1);
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	/* base and port guid same for single port */
13428c2ecf20Sopenharmony_ci	ppd->guid = dd->base_guid;
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	/*
13458c2ecf20Sopenharmony_ci	 * the process of setting and un-resetting the serdes normally
13468c2ecf20Sopenharmony_ci	 * causes a serdes PLL error, so check for that and clear it
13478c2ecf20Sopenharmony_ci	 * here.  Also clearr hwerr bit in errstatus, but not others.
13488c2ecf20Sopenharmony_ci	 */
13498c2ecf20Sopenharmony_ci	hwstat = qib_read_kreg64(dd, kr_hwerrstatus);
13508c2ecf20Sopenharmony_ci	if (hwstat) {
13518c2ecf20Sopenharmony_ci		/* should just have PLL, clear all set, in an case */
13528c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_hwerrclear, hwstat);
13538c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_errclear, ERR_MASK(HardwareErr));
13548c2ecf20Sopenharmony_ci	}
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	dd->control |= QLOGIC_IB_C_LINKENABLE;
13578c2ecf20Sopenharmony_ci	dd->control &= ~QLOGIC_IB_C_FREEZEMODE;
13588c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_control, dd->control);
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	return 0;
13618c2ecf20Sopenharmony_ci}
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci/**
13648c2ecf20Sopenharmony_ci * qib_6120_quiet_serdes - set serdes to txidle
13658c2ecf20Sopenharmony_ci * @ppd: physical port of the qlogic_ib device
13668c2ecf20Sopenharmony_ci * Called when driver is being unloaded
13678c2ecf20Sopenharmony_ci */
13688c2ecf20Sopenharmony_cistatic void qib_6120_quiet_serdes(struct qib_pportdata *ppd)
13698c2ecf20Sopenharmony_ci{
13708c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
13718c2ecf20Sopenharmony_ci	u64 val;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	qib_set_ib_6120_lstate(ppd, 0, QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	/* disable IBC */
13768c2ecf20Sopenharmony_ci	dd->control &= ~QLOGIC_IB_C_LINKENABLE;
13778c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_control,
13788c2ecf20Sopenharmony_ci		       dd->control | QLOGIC_IB_C_FREEZEMODE);
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	if (dd->cspec->ibsymdelta || dd->cspec->iblnkerrdelta ||
13818c2ecf20Sopenharmony_ci	    dd->cspec->ibdeltainprog) {
13828c2ecf20Sopenharmony_ci		u64 diagc;
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci		/* enable counter writes */
13858c2ecf20Sopenharmony_ci		diagc = qib_read_kreg64(dd, kr_hwdiagctrl);
13868c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_hwdiagctrl,
13878c2ecf20Sopenharmony_ci			       diagc | SYM_MASK(HwDiagCtrl, CounterWrEnable));
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci		if (dd->cspec->ibsymdelta || dd->cspec->ibdeltainprog) {
13908c2ecf20Sopenharmony_ci			val = read_6120_creg32(dd, cr_ibsymbolerr);
13918c2ecf20Sopenharmony_ci			if (dd->cspec->ibdeltainprog)
13928c2ecf20Sopenharmony_ci				val -= val - dd->cspec->ibsymsnap;
13938c2ecf20Sopenharmony_ci			val -= dd->cspec->ibsymdelta;
13948c2ecf20Sopenharmony_ci			write_6120_creg(dd, cr_ibsymbolerr, val);
13958c2ecf20Sopenharmony_ci		}
13968c2ecf20Sopenharmony_ci		if (dd->cspec->iblnkerrdelta || dd->cspec->ibdeltainprog) {
13978c2ecf20Sopenharmony_ci			val = read_6120_creg32(dd, cr_iblinkerrrecov);
13988c2ecf20Sopenharmony_ci			if (dd->cspec->ibdeltainprog)
13998c2ecf20Sopenharmony_ci				val -= val - dd->cspec->iblnkerrsnap;
14008c2ecf20Sopenharmony_ci			val -= dd->cspec->iblnkerrdelta;
14018c2ecf20Sopenharmony_ci			write_6120_creg(dd, cr_iblinkerrrecov, val);
14028c2ecf20Sopenharmony_ci		}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci		/* and disable counter writes */
14058c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_hwdiagctrl, diagc);
14068c2ecf20Sopenharmony_ci	}
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	val = qib_read_kreg64(dd, kr_serdes_cfg0);
14098c2ecf20Sopenharmony_ci	val |= SYM_MASK(SerdesCfg0, TxIdeEnX);
14108c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_serdes_cfg0, val);
14118c2ecf20Sopenharmony_ci}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci/**
14148c2ecf20Sopenharmony_ci * qib_6120_setup_setextled - set the state of the two external LEDs
14158c2ecf20Sopenharmony_ci * @dd: the qlogic_ib device
14168c2ecf20Sopenharmony_ci * @on: whether the link is up or not
14178c2ecf20Sopenharmony_ci *
14188c2ecf20Sopenharmony_ci * The exact combo of LEDs if on is true is determined by looking
14198c2ecf20Sopenharmony_ci * at the ibcstatus.
14208c2ecf20Sopenharmony_ci * These LEDs indicate the physical and logical state of IB link.
14218c2ecf20Sopenharmony_ci * For this chip (at least with recommended board pinouts), LED1
14228c2ecf20Sopenharmony_ci * is Yellow (logical state) and LED2 is Green (physical state),
14238c2ecf20Sopenharmony_ci *
14248c2ecf20Sopenharmony_ci * Note:  We try to match the Mellanox HCA LED behavior as best
14258c2ecf20Sopenharmony_ci * we can.  Green indicates physical link state is OK (something is
14268c2ecf20Sopenharmony_ci * plugged in, and we can train).
14278c2ecf20Sopenharmony_ci * Amber indicates the link is logically up (ACTIVE).
14288c2ecf20Sopenharmony_ci * Mellanox further blinks the amber LED to indicate data packet
14298c2ecf20Sopenharmony_ci * activity, but we have no hardware support for that, so it would
14308c2ecf20Sopenharmony_ci * require waking up every 10-20 msecs and checking the counters
14318c2ecf20Sopenharmony_ci * on the chip, and then turning the LED off if appropriate.  That's
14328c2ecf20Sopenharmony_ci * visible overhead, so not something we will do.
14338c2ecf20Sopenharmony_ci *
14348c2ecf20Sopenharmony_ci */
14358c2ecf20Sopenharmony_cistatic void qib_6120_setup_setextled(struct qib_pportdata *ppd, u32 on)
14368c2ecf20Sopenharmony_ci{
14378c2ecf20Sopenharmony_ci	u64 extctl, val, lst, ltst;
14388c2ecf20Sopenharmony_ci	unsigned long flags;
14398c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	/*
14428c2ecf20Sopenharmony_ci	 * The diags use the LED to indicate diag info, so we leave
14438c2ecf20Sopenharmony_ci	 * the external LED alone when the diags are running.
14448c2ecf20Sopenharmony_ci	 */
14458c2ecf20Sopenharmony_ci	if (dd->diag_client)
14468c2ecf20Sopenharmony_ci		return;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	/* Allow override of LED display for, e.g. Locating system in rack */
14498c2ecf20Sopenharmony_ci	if (ppd->led_override) {
14508c2ecf20Sopenharmony_ci		ltst = (ppd->led_override & QIB_LED_PHYS) ?
14518c2ecf20Sopenharmony_ci			IB_PHYSPORTSTATE_LINKUP : IB_PHYSPORTSTATE_DISABLED,
14528c2ecf20Sopenharmony_ci		lst = (ppd->led_override & QIB_LED_LOG) ?
14538c2ecf20Sopenharmony_ci			IB_PORT_ACTIVE : IB_PORT_DOWN;
14548c2ecf20Sopenharmony_ci	} else if (on) {
14558c2ecf20Sopenharmony_ci		val = qib_read_kreg64(dd, kr_ibcstatus);
14568c2ecf20Sopenharmony_ci		ltst = qib_6120_phys_portstate(val);
14578c2ecf20Sopenharmony_ci		lst = qib_6120_iblink_state(val);
14588c2ecf20Sopenharmony_ci	} else {
14598c2ecf20Sopenharmony_ci		ltst = 0;
14608c2ecf20Sopenharmony_ci		lst = 0;
14618c2ecf20Sopenharmony_ci	}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dd->cspec->gpio_lock, flags);
14648c2ecf20Sopenharmony_ci	extctl = dd->cspec->extctrl & ~(SYM_MASK(EXTCtrl, LEDPriPortGreenOn) |
14658c2ecf20Sopenharmony_ci				 SYM_MASK(EXTCtrl, LEDPriPortYellowOn));
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	if (ltst == IB_PHYSPORTSTATE_LINKUP)
14688c2ecf20Sopenharmony_ci		extctl |= SYM_MASK(EXTCtrl, LEDPriPortYellowOn);
14698c2ecf20Sopenharmony_ci	if (lst == IB_PORT_ACTIVE)
14708c2ecf20Sopenharmony_ci		extctl |= SYM_MASK(EXTCtrl, LEDPriPortGreenOn);
14718c2ecf20Sopenharmony_ci	dd->cspec->extctrl = extctl;
14728c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_extctrl, extctl);
14738c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dd->cspec->gpio_lock, flags);
14748c2ecf20Sopenharmony_ci}
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci/**
14778c2ecf20Sopenharmony_ci * qib_6120_setup_cleanup - clean up any per-chip chip-specific stuff
14788c2ecf20Sopenharmony_ci * @dd: the qlogic_ib device
14798c2ecf20Sopenharmony_ci *
14808c2ecf20Sopenharmony_ci * This is called during driver unload.
14818c2ecf20Sopenharmony_ci*/
14828c2ecf20Sopenharmony_cistatic void qib_6120_setup_cleanup(struct qib_devdata *dd)
14838c2ecf20Sopenharmony_ci{
14848c2ecf20Sopenharmony_ci	qib_free_irq(dd);
14858c2ecf20Sopenharmony_ci	kfree(dd->cspec->cntrs);
14868c2ecf20Sopenharmony_ci	kfree(dd->cspec->portcntrs);
14878c2ecf20Sopenharmony_ci	if (dd->cspec->dummy_hdrq) {
14888c2ecf20Sopenharmony_ci		dma_free_coherent(&dd->pcidev->dev,
14898c2ecf20Sopenharmony_ci				  ALIGN(dd->rcvhdrcnt *
14908c2ecf20Sopenharmony_ci					dd->rcvhdrentsize *
14918c2ecf20Sopenharmony_ci					sizeof(u32), PAGE_SIZE),
14928c2ecf20Sopenharmony_ci				  dd->cspec->dummy_hdrq,
14938c2ecf20Sopenharmony_ci				  dd->cspec->dummy_hdrq_phys);
14948c2ecf20Sopenharmony_ci		dd->cspec->dummy_hdrq = NULL;
14958c2ecf20Sopenharmony_ci	}
14968c2ecf20Sopenharmony_ci}
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_cistatic void qib_wantpiobuf_6120_intr(struct qib_devdata *dd, u32 needint)
14998c2ecf20Sopenharmony_ci{
15008c2ecf20Sopenharmony_ci	unsigned long flags;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dd->sendctrl_lock, flags);
15038c2ecf20Sopenharmony_ci	if (needint)
15048c2ecf20Sopenharmony_ci		dd->sendctrl |= SYM_MASK(SendCtrl, PIOIntBufAvail);
15058c2ecf20Sopenharmony_ci	else
15068c2ecf20Sopenharmony_ci		dd->sendctrl &= ~SYM_MASK(SendCtrl, PIOIntBufAvail);
15078c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_sendctrl, dd->sendctrl);
15088c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_scratch, 0ULL);
15098c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
15108c2ecf20Sopenharmony_ci}
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci/*
15138c2ecf20Sopenharmony_ci * handle errors and unusual events first, separate function
15148c2ecf20Sopenharmony_ci * to improve cache hits for fast path interrupt handling
15158c2ecf20Sopenharmony_ci */
15168c2ecf20Sopenharmony_cistatic noinline void unlikely_6120_intr(struct qib_devdata *dd, u64 istat)
15178c2ecf20Sopenharmony_ci{
15188c2ecf20Sopenharmony_ci	if (unlikely(istat & ~QLOGIC_IB_I_BITSEXTANT))
15198c2ecf20Sopenharmony_ci		qib_dev_err(dd, "interrupt with unknown interrupts %Lx set\n",
15208c2ecf20Sopenharmony_ci			    istat & ~QLOGIC_IB_I_BITSEXTANT);
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	if (istat & QLOGIC_IB_I_ERROR) {
15238c2ecf20Sopenharmony_ci		u64 estat = 0;
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci		qib_stats.sps_errints++;
15268c2ecf20Sopenharmony_ci		estat = qib_read_kreg64(dd, kr_errstatus);
15278c2ecf20Sopenharmony_ci		if (!estat)
15288c2ecf20Sopenharmony_ci			qib_devinfo(dd->pcidev,
15298c2ecf20Sopenharmony_ci				"error interrupt (%Lx), but no error bits set!\n",
15308c2ecf20Sopenharmony_ci				istat);
15318c2ecf20Sopenharmony_ci		handle_6120_errors(dd, estat);
15328c2ecf20Sopenharmony_ci	}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	if (istat & QLOGIC_IB_I_GPIO) {
15358c2ecf20Sopenharmony_ci		u32 gpiostatus;
15368c2ecf20Sopenharmony_ci		u32 to_clear = 0;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci		/*
15398c2ecf20Sopenharmony_ci		 * GPIO_3..5 on IBA6120 Rev2 chips indicate
15408c2ecf20Sopenharmony_ci		 * errors that we need to count.
15418c2ecf20Sopenharmony_ci		 */
15428c2ecf20Sopenharmony_ci		gpiostatus = qib_read_kreg32(dd, kr_gpio_status);
15438c2ecf20Sopenharmony_ci		/* First the error-counter case. */
15448c2ecf20Sopenharmony_ci		if (gpiostatus & GPIO_ERRINTR_MASK) {
15458c2ecf20Sopenharmony_ci			/* want to clear the bits we see asserted. */
15468c2ecf20Sopenharmony_ci			to_clear |= (gpiostatus & GPIO_ERRINTR_MASK);
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci			/*
15498c2ecf20Sopenharmony_ci			 * Count appropriately, clear bits out of our copy,
15508c2ecf20Sopenharmony_ci			 * as they have been "handled".
15518c2ecf20Sopenharmony_ci			 */
15528c2ecf20Sopenharmony_ci			if (gpiostatus & (1 << GPIO_RXUVL_BIT))
15538c2ecf20Sopenharmony_ci				dd->cspec->rxfc_unsupvl_errs++;
15548c2ecf20Sopenharmony_ci			if (gpiostatus & (1 << GPIO_OVRUN_BIT))
15558c2ecf20Sopenharmony_ci				dd->cspec->overrun_thresh_errs++;
15568c2ecf20Sopenharmony_ci			if (gpiostatus & (1 << GPIO_LLI_BIT))
15578c2ecf20Sopenharmony_ci				dd->cspec->lli_errs++;
15588c2ecf20Sopenharmony_ci			gpiostatus &= ~GPIO_ERRINTR_MASK;
15598c2ecf20Sopenharmony_ci		}
15608c2ecf20Sopenharmony_ci		if (gpiostatus) {
15618c2ecf20Sopenharmony_ci			/*
15628c2ecf20Sopenharmony_ci			 * Some unexpected bits remain. If they could have
15638c2ecf20Sopenharmony_ci			 * caused the interrupt, complain and clear.
15648c2ecf20Sopenharmony_ci			 * To avoid repetition of this condition, also clear
15658c2ecf20Sopenharmony_ci			 * the mask. It is almost certainly due to error.
15668c2ecf20Sopenharmony_ci			 */
15678c2ecf20Sopenharmony_ci			const u32 mask = qib_read_kreg32(dd, kr_gpio_mask);
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci			/*
15708c2ecf20Sopenharmony_ci			 * Also check that the chip reflects our shadow,
15718c2ecf20Sopenharmony_ci			 * and report issues, If they caused the interrupt.
15728c2ecf20Sopenharmony_ci			 * we will suppress by refreshing from the shadow.
15738c2ecf20Sopenharmony_ci			 */
15748c2ecf20Sopenharmony_ci			if (mask & gpiostatus) {
15758c2ecf20Sopenharmony_ci				to_clear |= (gpiostatus & mask);
15768c2ecf20Sopenharmony_ci				dd->cspec->gpio_mask &= ~(gpiostatus & mask);
15778c2ecf20Sopenharmony_ci				qib_write_kreg(dd, kr_gpio_mask,
15788c2ecf20Sopenharmony_ci					       dd->cspec->gpio_mask);
15798c2ecf20Sopenharmony_ci			}
15808c2ecf20Sopenharmony_ci		}
15818c2ecf20Sopenharmony_ci		if (to_clear)
15828c2ecf20Sopenharmony_ci			qib_write_kreg(dd, kr_gpio_clear, (u64) to_clear);
15838c2ecf20Sopenharmony_ci	}
15848c2ecf20Sopenharmony_ci}
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_cistatic irqreturn_t qib_6120intr(int irq, void *data)
15878c2ecf20Sopenharmony_ci{
15888c2ecf20Sopenharmony_ci	struct qib_devdata *dd = data;
15898c2ecf20Sopenharmony_ci	irqreturn_t ret;
15908c2ecf20Sopenharmony_ci	u32 istat, ctxtrbits, rmask, crcs = 0;
15918c2ecf20Sopenharmony_ci	unsigned i;
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	if ((dd->flags & (QIB_PRESENT | QIB_BADINTR)) != QIB_PRESENT) {
15948c2ecf20Sopenharmony_ci		/*
15958c2ecf20Sopenharmony_ci		 * This return value is not great, but we do not want the
15968c2ecf20Sopenharmony_ci		 * interrupt core code to remove our interrupt handler
15978c2ecf20Sopenharmony_ci		 * because we don't appear to be handling an interrupt
15988c2ecf20Sopenharmony_ci		 * during a chip reset.
15998c2ecf20Sopenharmony_ci		 */
16008c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
16018c2ecf20Sopenharmony_ci		goto bail;
16028c2ecf20Sopenharmony_ci	}
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	istat = qib_read_kreg32(dd, kr_intstatus);
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	if (unlikely(!istat)) {
16078c2ecf20Sopenharmony_ci		ret = IRQ_NONE; /* not our interrupt, or already handled */
16088c2ecf20Sopenharmony_ci		goto bail;
16098c2ecf20Sopenharmony_ci	}
16108c2ecf20Sopenharmony_ci	if (unlikely(istat == -1)) {
16118c2ecf20Sopenharmony_ci		qib_bad_intrstatus(dd);
16128c2ecf20Sopenharmony_ci		/* don't know if it was our interrupt or not */
16138c2ecf20Sopenharmony_ci		ret = IRQ_NONE;
16148c2ecf20Sopenharmony_ci		goto bail;
16158c2ecf20Sopenharmony_ci	}
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	this_cpu_inc(*dd->int_counter);
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	if (unlikely(istat & (~QLOGIC_IB_I_BITSEXTANT |
16208c2ecf20Sopenharmony_ci			      QLOGIC_IB_I_GPIO | QLOGIC_IB_I_ERROR)))
16218c2ecf20Sopenharmony_ci		unlikely_6120_intr(dd, istat);
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	/*
16248c2ecf20Sopenharmony_ci	 * Clear the interrupt bits we found set, relatively early, so we
16258c2ecf20Sopenharmony_ci	 * "know" know the chip will have seen this by the time we process
16268c2ecf20Sopenharmony_ci	 * the queue, and will re-interrupt if necessary.  The processor
16278c2ecf20Sopenharmony_ci	 * itself won't take the interrupt again until we return.
16288c2ecf20Sopenharmony_ci	 */
16298c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_intclear, istat);
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	/*
16328c2ecf20Sopenharmony_ci	 * Handle kernel receive queues before checking for pio buffers
16338c2ecf20Sopenharmony_ci	 * available since receives can overflow; piobuf waiters can afford
16348c2ecf20Sopenharmony_ci	 * a few extra cycles, since they were waiting anyway.
16358c2ecf20Sopenharmony_ci	 */
16368c2ecf20Sopenharmony_ci	ctxtrbits = istat &
16378c2ecf20Sopenharmony_ci		((QLOGIC_IB_I_RCVAVAIL_MASK << QLOGIC_IB_I_RCVAVAIL_SHIFT) |
16388c2ecf20Sopenharmony_ci		 (QLOGIC_IB_I_RCVURG_MASK << QLOGIC_IB_I_RCVURG_SHIFT));
16398c2ecf20Sopenharmony_ci	if (ctxtrbits) {
16408c2ecf20Sopenharmony_ci		rmask = (1U << QLOGIC_IB_I_RCVAVAIL_SHIFT) |
16418c2ecf20Sopenharmony_ci			(1U << QLOGIC_IB_I_RCVURG_SHIFT);
16428c2ecf20Sopenharmony_ci		for (i = 0; i < dd->first_user_ctxt; i++) {
16438c2ecf20Sopenharmony_ci			if (ctxtrbits & rmask) {
16448c2ecf20Sopenharmony_ci				ctxtrbits &= ~rmask;
16458c2ecf20Sopenharmony_ci				crcs += qib_kreceive(dd->rcd[i],
16468c2ecf20Sopenharmony_ci						     &dd->cspec->lli_counter,
16478c2ecf20Sopenharmony_ci						     NULL);
16488c2ecf20Sopenharmony_ci			}
16498c2ecf20Sopenharmony_ci			rmask <<= 1;
16508c2ecf20Sopenharmony_ci		}
16518c2ecf20Sopenharmony_ci		if (crcs) {
16528c2ecf20Sopenharmony_ci			u32 cntr = dd->cspec->lli_counter;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci			cntr += crcs;
16558c2ecf20Sopenharmony_ci			if (cntr) {
16568c2ecf20Sopenharmony_ci				if (cntr > dd->cspec->lli_thresh) {
16578c2ecf20Sopenharmony_ci					dd->cspec->lli_counter = 0;
16588c2ecf20Sopenharmony_ci					dd->cspec->lli_errs++;
16598c2ecf20Sopenharmony_ci				} else
16608c2ecf20Sopenharmony_ci					dd->cspec->lli_counter += cntr;
16618c2ecf20Sopenharmony_ci			}
16628c2ecf20Sopenharmony_ci		}
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_ci		if (ctxtrbits) {
16668c2ecf20Sopenharmony_ci			ctxtrbits =
16678c2ecf20Sopenharmony_ci				(ctxtrbits >> QLOGIC_IB_I_RCVAVAIL_SHIFT) |
16688c2ecf20Sopenharmony_ci				(ctxtrbits >> QLOGIC_IB_I_RCVURG_SHIFT);
16698c2ecf20Sopenharmony_ci			qib_handle_urcv(dd, ctxtrbits);
16708c2ecf20Sopenharmony_ci		}
16718c2ecf20Sopenharmony_ci	}
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	if ((istat & QLOGIC_IB_I_SPIOBUFAVAIL) && (dd->flags & QIB_INITTED))
16748c2ecf20Sopenharmony_ci		qib_ib_piobufavail(dd);
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	ret = IRQ_HANDLED;
16778c2ecf20Sopenharmony_cibail:
16788c2ecf20Sopenharmony_ci	return ret;
16798c2ecf20Sopenharmony_ci}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci/*
16828c2ecf20Sopenharmony_ci * Set up our chip-specific interrupt handler
16838c2ecf20Sopenharmony_ci * The interrupt type has already been setup, so
16848c2ecf20Sopenharmony_ci * we just need to do the registration and error checking.
16858c2ecf20Sopenharmony_ci */
16868c2ecf20Sopenharmony_cistatic void qib_setup_6120_interrupt(struct qib_devdata *dd)
16878c2ecf20Sopenharmony_ci{
16888c2ecf20Sopenharmony_ci	int ret;
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci	/*
16918c2ecf20Sopenharmony_ci	 * If the chip supports added error indication via GPIO pins,
16928c2ecf20Sopenharmony_ci	 * enable interrupts on those bits so the interrupt routine
16938c2ecf20Sopenharmony_ci	 * can count the events. Also set flag so interrupt routine
16948c2ecf20Sopenharmony_ci	 * can know they are expected.
16958c2ecf20Sopenharmony_ci	 */
16968c2ecf20Sopenharmony_ci	if (SYM_FIELD(dd->revision, Revision_R,
16978c2ecf20Sopenharmony_ci		      ChipRevMinor) > 1) {
16988c2ecf20Sopenharmony_ci		/* Rev2+ reports extra errors via internal GPIO pins */
16998c2ecf20Sopenharmony_ci		dd->cspec->gpio_mask |= GPIO_ERRINTR_MASK;
17008c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_gpio_mask, dd->cspec->gpio_mask);
17018c2ecf20Sopenharmony_ci	}
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	ret = pci_request_irq(dd->pcidev, 0, qib_6120intr, NULL, dd,
17048c2ecf20Sopenharmony_ci			      QIB_DRV_NAME);
17058c2ecf20Sopenharmony_ci	if (ret)
17068c2ecf20Sopenharmony_ci		qib_dev_err(dd,
17078c2ecf20Sopenharmony_ci			    "Couldn't setup interrupt (irq=%d): %d\n",
17088c2ecf20Sopenharmony_ci			    pci_irq_vector(dd->pcidev, 0), ret);
17098c2ecf20Sopenharmony_ci}
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci/**
17128c2ecf20Sopenharmony_ci * pe_boardname - fill in the board name
17138c2ecf20Sopenharmony_ci * @dd: the qlogic_ib device
17148c2ecf20Sopenharmony_ci *
17158c2ecf20Sopenharmony_ci * info is based on the board revision register
17168c2ecf20Sopenharmony_ci */
17178c2ecf20Sopenharmony_cistatic void pe_boardname(struct qib_devdata *dd)
17188c2ecf20Sopenharmony_ci{
17198c2ecf20Sopenharmony_ci	u32 boardid;
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	boardid = SYM_FIELD(dd->revision, Revision,
17228c2ecf20Sopenharmony_ci			    BoardID);
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	switch (boardid) {
17258c2ecf20Sopenharmony_ci	case 2:
17268c2ecf20Sopenharmony_ci		dd->boardname = "InfiniPath_QLE7140";
17278c2ecf20Sopenharmony_ci		break;
17288c2ecf20Sopenharmony_ci	default:
17298c2ecf20Sopenharmony_ci		qib_dev_err(dd, "Unknown 6120 board with ID %u\n", boardid);
17308c2ecf20Sopenharmony_ci		dd->boardname = "Unknown_InfiniPath_6120";
17318c2ecf20Sopenharmony_ci		break;
17328c2ecf20Sopenharmony_ci	}
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	if (dd->majrev != 4 || !dd->minrev || dd->minrev > 2)
17358c2ecf20Sopenharmony_ci		qib_dev_err(dd,
17368c2ecf20Sopenharmony_ci			    "Unsupported InfiniPath hardware revision %u.%u!\n",
17378c2ecf20Sopenharmony_ci			    dd->majrev, dd->minrev);
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	snprintf(dd->boardversion, sizeof(dd->boardversion),
17408c2ecf20Sopenharmony_ci		 "ChipABI %u.%u, %s, InfiniPath%u %u.%u, SW Compat %u\n",
17418c2ecf20Sopenharmony_ci		 QIB_CHIP_VERS_MAJ, QIB_CHIP_VERS_MIN, dd->boardname,
17428c2ecf20Sopenharmony_ci		 (unsigned int)SYM_FIELD(dd->revision, Revision_R, Arch),
17438c2ecf20Sopenharmony_ci		 dd->majrev, dd->minrev,
17448c2ecf20Sopenharmony_ci		 (unsigned int)SYM_FIELD(dd->revision, Revision_R, SW));
17458c2ecf20Sopenharmony_ci}
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci/*
17488c2ecf20Sopenharmony_ci * This routine sleeps, so it can only be called from user context, not
17498c2ecf20Sopenharmony_ci * from interrupt context.  If we need interrupt context, we can split
17508c2ecf20Sopenharmony_ci * it into two routines.
17518c2ecf20Sopenharmony_ci */
17528c2ecf20Sopenharmony_cistatic int qib_6120_setup_reset(struct qib_devdata *dd)
17538c2ecf20Sopenharmony_ci{
17548c2ecf20Sopenharmony_ci	u64 val;
17558c2ecf20Sopenharmony_ci	int i;
17568c2ecf20Sopenharmony_ci	int ret;
17578c2ecf20Sopenharmony_ci	u16 cmdval;
17588c2ecf20Sopenharmony_ci	u8 int_line, clinesz;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	qib_pcie_getcmd(dd, &cmdval, &int_line, &clinesz);
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci	/* Use ERROR so it shows up in logs, etc. */
17638c2ecf20Sopenharmony_ci	qib_dev_err(dd, "Resetting InfiniPath unit %u\n", dd->unit);
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	/* no interrupts till re-initted */
17668c2ecf20Sopenharmony_ci	qib_6120_set_intr_state(dd, 0);
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	dd->cspec->ibdeltainprog = 0;
17698c2ecf20Sopenharmony_ci	dd->cspec->ibsymdelta = 0;
17708c2ecf20Sopenharmony_ci	dd->cspec->iblnkerrdelta = 0;
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	/*
17738c2ecf20Sopenharmony_ci	 * Keep chip from being accessed until we are ready.  Use
17748c2ecf20Sopenharmony_ci	 * writeq() directly, to allow the write even though QIB_PRESENT
17758c2ecf20Sopenharmony_ci	 * isn't set.
17768c2ecf20Sopenharmony_ci	 */
17778c2ecf20Sopenharmony_ci	dd->flags &= ~(QIB_INITTED | QIB_PRESENT);
17788c2ecf20Sopenharmony_ci	/* so we check interrupts work again */
17798c2ecf20Sopenharmony_ci	dd->z_int_counter = qib_int_counter(dd);
17808c2ecf20Sopenharmony_ci	val = dd->control | QLOGIC_IB_C_RESET;
17818c2ecf20Sopenharmony_ci	writeq(val, &dd->kregbase[kr_control]);
17828c2ecf20Sopenharmony_ci	mb(); /* prevent compiler re-ordering around actual reset */
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	for (i = 1; i <= 5; i++) {
17858c2ecf20Sopenharmony_ci		/*
17868c2ecf20Sopenharmony_ci		 * Allow MBIST, etc. to complete; longer on each retry.
17878c2ecf20Sopenharmony_ci		 * We sometimes get machine checks from bus timeout if no
17888c2ecf20Sopenharmony_ci		 * response, so for now, make it *really* long.
17898c2ecf20Sopenharmony_ci		 */
17908c2ecf20Sopenharmony_ci		msleep(1000 + (1 + i) * 2000);
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci		qib_pcie_reenable(dd, cmdval, int_line, clinesz);
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci		/*
17958c2ecf20Sopenharmony_ci		 * Use readq directly, so we don't need to mark it as PRESENT
17968c2ecf20Sopenharmony_ci		 * until we get a successful indication that all is well.
17978c2ecf20Sopenharmony_ci		 */
17988c2ecf20Sopenharmony_ci		val = readq(&dd->kregbase[kr_revision]);
17998c2ecf20Sopenharmony_ci		if (val == dd->revision) {
18008c2ecf20Sopenharmony_ci			dd->flags |= QIB_PRESENT; /* it's back */
18018c2ecf20Sopenharmony_ci			ret = qib_reinit_intr(dd);
18028c2ecf20Sopenharmony_ci			goto bail;
18038c2ecf20Sopenharmony_ci		}
18048c2ecf20Sopenharmony_ci	}
18058c2ecf20Sopenharmony_ci	ret = 0; /* failed */
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_cibail:
18088c2ecf20Sopenharmony_ci	if (ret) {
18098c2ecf20Sopenharmony_ci		if (qib_pcie_params(dd, dd->lbus_width, NULL))
18108c2ecf20Sopenharmony_ci			qib_dev_err(dd,
18118c2ecf20Sopenharmony_ci				"Reset failed to setup PCIe or interrupts; continuing anyway\n");
18128c2ecf20Sopenharmony_ci		/* clear the reset error, init error/hwerror mask */
18138c2ecf20Sopenharmony_ci		qib_6120_init_hwerrors(dd);
18148c2ecf20Sopenharmony_ci		/* for Rev2 error interrupts; nop for rev 1 */
18158c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_gpio_mask, dd->cspec->gpio_mask);
18168c2ecf20Sopenharmony_ci		/* clear the reset error, init error/hwerror mask */
18178c2ecf20Sopenharmony_ci		qib_6120_init_hwerrors(dd);
18188c2ecf20Sopenharmony_ci	}
18198c2ecf20Sopenharmony_ci	return ret;
18208c2ecf20Sopenharmony_ci}
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci/**
18238c2ecf20Sopenharmony_ci * qib_6120_put_tid - write a TID in chip
18248c2ecf20Sopenharmony_ci * @dd: the qlogic_ib device
18258c2ecf20Sopenharmony_ci * @tidptr: pointer to the expected TID (in chip) to update
18268c2ecf20Sopenharmony_ci * @tidtype: RCVHQ_RCV_TYPE_EAGER (1) for eager, RCVHQ_RCV_TYPE_EXPECTED (0)
18278c2ecf20Sopenharmony_ci * for expected
18288c2ecf20Sopenharmony_ci * @pa: physical address of in memory buffer; tidinvalid if freeing
18298c2ecf20Sopenharmony_ci *
18308c2ecf20Sopenharmony_ci * This exists as a separate routine to allow for special locking etc.
18318c2ecf20Sopenharmony_ci * It's used for both the full cleanup on exit, as well as the normal
18328c2ecf20Sopenharmony_ci * setup and teardown.
18338c2ecf20Sopenharmony_ci */
18348c2ecf20Sopenharmony_cistatic void qib_6120_put_tid(struct qib_devdata *dd, u64 __iomem *tidptr,
18358c2ecf20Sopenharmony_ci			     u32 type, unsigned long pa)
18368c2ecf20Sopenharmony_ci{
18378c2ecf20Sopenharmony_ci	u32 __iomem *tidp32 = (u32 __iomem *)tidptr;
18388c2ecf20Sopenharmony_ci	unsigned long flags;
18398c2ecf20Sopenharmony_ci	int tidx;
18408c2ecf20Sopenharmony_ci	spinlock_t *tidlockp; /* select appropriate spinlock */
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	if (!dd->kregbase)
18438c2ecf20Sopenharmony_ci		return;
18448c2ecf20Sopenharmony_ci
18458c2ecf20Sopenharmony_ci	if (pa != dd->tidinvalid) {
18468c2ecf20Sopenharmony_ci		if (pa & ((1U << 11) - 1)) {
18478c2ecf20Sopenharmony_ci			qib_dev_err(dd, "Physaddr %lx not 2KB aligned!\n",
18488c2ecf20Sopenharmony_ci				    pa);
18498c2ecf20Sopenharmony_ci			return;
18508c2ecf20Sopenharmony_ci		}
18518c2ecf20Sopenharmony_ci		pa >>= 11;
18528c2ecf20Sopenharmony_ci		if (pa & ~QLOGIC_IB_RT_ADDR_MASK) {
18538c2ecf20Sopenharmony_ci			qib_dev_err(dd,
18548c2ecf20Sopenharmony_ci				"Physical page address 0x%lx larger than supported\n",
18558c2ecf20Sopenharmony_ci				pa);
18568c2ecf20Sopenharmony_ci			return;
18578c2ecf20Sopenharmony_ci		}
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci		if (type == RCVHQ_RCV_TYPE_EAGER)
18608c2ecf20Sopenharmony_ci			pa |= dd->tidtemplate;
18618c2ecf20Sopenharmony_ci		else /* for now, always full 4KB page */
18628c2ecf20Sopenharmony_ci			pa |= 2 << 29;
18638c2ecf20Sopenharmony_ci	}
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	/*
18668c2ecf20Sopenharmony_ci	 * Avoid chip issue by writing the scratch register
18678c2ecf20Sopenharmony_ci	 * before and after the TID, and with an io write barrier.
18688c2ecf20Sopenharmony_ci	 * We use a spinlock around the writes, so they can't intermix
18698c2ecf20Sopenharmony_ci	 * with other TID (eager or expected) writes (the chip problem
18708c2ecf20Sopenharmony_ci	 * is triggered by back to back TID writes). Unfortunately, this
18718c2ecf20Sopenharmony_ci	 * call can be done from interrupt level for the ctxt 0 eager TIDs,
18728c2ecf20Sopenharmony_ci	 * so we have to use irqsave locks.
18738c2ecf20Sopenharmony_ci	 */
18748c2ecf20Sopenharmony_ci	/*
18758c2ecf20Sopenharmony_ci	 * Assumes tidptr always > egrtidbase
18768c2ecf20Sopenharmony_ci	 * if type == RCVHQ_RCV_TYPE_EAGER.
18778c2ecf20Sopenharmony_ci	 */
18788c2ecf20Sopenharmony_ci	tidx = tidptr - dd->egrtidbase;
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci	tidlockp = (type == RCVHQ_RCV_TYPE_EAGER && tidx < dd->rcvhdrcnt)
18818c2ecf20Sopenharmony_ci		? &dd->cspec->kernel_tid_lock : &dd->cspec->user_tid_lock;
18828c2ecf20Sopenharmony_ci	spin_lock_irqsave(tidlockp, flags);
18838c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_scratch, 0xfeeddeaf);
18848c2ecf20Sopenharmony_ci	writel(pa, tidp32);
18858c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_scratch, 0xdeadbeef);
18868c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(tidlockp, flags);
18878c2ecf20Sopenharmony_ci}
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci/**
18908c2ecf20Sopenharmony_ci * qib_6120_put_tid_2 - write a TID in chip, Revision 2 or higher
18918c2ecf20Sopenharmony_ci * @dd: the qlogic_ib device
18928c2ecf20Sopenharmony_ci * @tidptr: pointer to the expected TID (in chip) to update
18938c2ecf20Sopenharmony_ci * @tidtype: RCVHQ_RCV_TYPE_EAGER (1) for eager, RCVHQ_RCV_TYPE_EXPECTED (0)
18948c2ecf20Sopenharmony_ci * for expected
18958c2ecf20Sopenharmony_ci * @pa: physical address of in memory buffer; tidinvalid if freeing
18968c2ecf20Sopenharmony_ci *
18978c2ecf20Sopenharmony_ci * This exists as a separate routine to allow for selection of the
18988c2ecf20Sopenharmony_ci * appropriate "flavor". The static calls in cleanup just use the
18998c2ecf20Sopenharmony_ci * revision-agnostic form, as they are not performance critical.
19008c2ecf20Sopenharmony_ci */
19018c2ecf20Sopenharmony_cistatic void qib_6120_put_tid_2(struct qib_devdata *dd, u64 __iomem *tidptr,
19028c2ecf20Sopenharmony_ci			       u32 type, unsigned long pa)
19038c2ecf20Sopenharmony_ci{
19048c2ecf20Sopenharmony_ci	u32 __iomem *tidp32 = (u32 __iomem *)tidptr;
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci	if (!dd->kregbase)
19078c2ecf20Sopenharmony_ci		return;
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	if (pa != dd->tidinvalid) {
19108c2ecf20Sopenharmony_ci		if (pa & ((1U << 11) - 1)) {
19118c2ecf20Sopenharmony_ci			qib_dev_err(dd, "Physaddr %lx not 2KB aligned!\n",
19128c2ecf20Sopenharmony_ci				    pa);
19138c2ecf20Sopenharmony_ci			return;
19148c2ecf20Sopenharmony_ci		}
19158c2ecf20Sopenharmony_ci		pa >>= 11;
19168c2ecf20Sopenharmony_ci		if (pa & ~QLOGIC_IB_RT_ADDR_MASK) {
19178c2ecf20Sopenharmony_ci			qib_dev_err(dd,
19188c2ecf20Sopenharmony_ci				"Physical page address 0x%lx larger than supported\n",
19198c2ecf20Sopenharmony_ci				pa);
19208c2ecf20Sopenharmony_ci			return;
19218c2ecf20Sopenharmony_ci		}
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci		if (type == RCVHQ_RCV_TYPE_EAGER)
19248c2ecf20Sopenharmony_ci			pa |= dd->tidtemplate;
19258c2ecf20Sopenharmony_ci		else /* for now, always full 4KB page */
19268c2ecf20Sopenharmony_ci			pa |= 2 << 29;
19278c2ecf20Sopenharmony_ci	}
19288c2ecf20Sopenharmony_ci	writel(pa, tidp32);
19298c2ecf20Sopenharmony_ci}
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci/**
19338c2ecf20Sopenharmony_ci * qib_6120_clear_tids - clear all TID entries for a context, expected and eager
19348c2ecf20Sopenharmony_ci * @dd: the qlogic_ib device
19358c2ecf20Sopenharmony_ci * @ctxt: the context
19368c2ecf20Sopenharmony_ci *
19378c2ecf20Sopenharmony_ci * clear all TID entries for a context, expected and eager.
19388c2ecf20Sopenharmony_ci * Used from qib_close().  On this chip, TIDs are only 32 bits,
19398c2ecf20Sopenharmony_ci * not 64, but they are still on 64 bit boundaries, so tidbase
19408c2ecf20Sopenharmony_ci * is declared as u64 * for the pointer math, even though we write 32 bits
19418c2ecf20Sopenharmony_ci */
19428c2ecf20Sopenharmony_cistatic void qib_6120_clear_tids(struct qib_devdata *dd,
19438c2ecf20Sopenharmony_ci				struct qib_ctxtdata *rcd)
19448c2ecf20Sopenharmony_ci{
19458c2ecf20Sopenharmony_ci	u64 __iomem *tidbase;
19468c2ecf20Sopenharmony_ci	unsigned long tidinv;
19478c2ecf20Sopenharmony_ci	u32 ctxt;
19488c2ecf20Sopenharmony_ci	int i;
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	if (!dd->kregbase || !rcd)
19518c2ecf20Sopenharmony_ci		return;
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	ctxt = rcd->ctxt;
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	tidinv = dd->tidinvalid;
19568c2ecf20Sopenharmony_ci	tidbase = (u64 __iomem *)
19578c2ecf20Sopenharmony_ci		((char __iomem *)(dd->kregbase) +
19588c2ecf20Sopenharmony_ci		 dd->rcvtidbase +
19598c2ecf20Sopenharmony_ci		 ctxt * dd->rcvtidcnt * sizeof(*tidbase));
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	for (i = 0; i < dd->rcvtidcnt; i++)
19628c2ecf20Sopenharmony_ci		/* use func pointer because could be one of two funcs */
19638c2ecf20Sopenharmony_ci		dd->f_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
19648c2ecf20Sopenharmony_ci				  tidinv);
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci	tidbase = (u64 __iomem *)
19678c2ecf20Sopenharmony_ci		((char __iomem *)(dd->kregbase) +
19688c2ecf20Sopenharmony_ci		 dd->rcvegrbase +
19698c2ecf20Sopenharmony_ci		 rcd->rcvegr_tid_base * sizeof(*tidbase));
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	for (i = 0; i < rcd->rcvegrcnt; i++)
19728c2ecf20Sopenharmony_ci		/* use func pointer because could be one of two funcs */
19738c2ecf20Sopenharmony_ci		dd->f_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,
19748c2ecf20Sopenharmony_ci				  tidinv);
19758c2ecf20Sopenharmony_ci}
19768c2ecf20Sopenharmony_ci
19778c2ecf20Sopenharmony_ci/**
19788c2ecf20Sopenharmony_ci * qib_6120_tidtemplate - setup constants for TID updates
19798c2ecf20Sopenharmony_ci * @dd: the qlogic_ib device
19808c2ecf20Sopenharmony_ci *
19818c2ecf20Sopenharmony_ci * We setup stuff that we use a lot, to avoid calculating each time
19828c2ecf20Sopenharmony_ci */
19838c2ecf20Sopenharmony_cistatic void qib_6120_tidtemplate(struct qib_devdata *dd)
19848c2ecf20Sopenharmony_ci{
19858c2ecf20Sopenharmony_ci	u32 egrsize = dd->rcvegrbufsize;
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	/*
19888c2ecf20Sopenharmony_ci	 * For now, we always allocate 4KB buffers (at init) so we can
19898c2ecf20Sopenharmony_ci	 * receive max size packets.  We may want a module parameter to
19908c2ecf20Sopenharmony_ci	 * specify 2KB or 4KB and/or make be per ctxt instead of per device
19918c2ecf20Sopenharmony_ci	 * for those who want to reduce memory footprint.  Note that the
19928c2ecf20Sopenharmony_ci	 * rcvhdrentsize size must be large enough to hold the largest
19938c2ecf20Sopenharmony_ci	 * IB header (currently 96 bytes) that we expect to handle (plus of
19948c2ecf20Sopenharmony_ci	 * course the 2 dwords of RHF).
19958c2ecf20Sopenharmony_ci	 */
19968c2ecf20Sopenharmony_ci	if (egrsize == 2048)
19978c2ecf20Sopenharmony_ci		dd->tidtemplate = 1U << 29;
19988c2ecf20Sopenharmony_ci	else if (egrsize == 4096)
19998c2ecf20Sopenharmony_ci		dd->tidtemplate = 2U << 29;
20008c2ecf20Sopenharmony_ci	dd->tidinvalid = 0;
20018c2ecf20Sopenharmony_ci}
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ciint __attribute__((weak)) qib_unordered_wc(void)
20048c2ecf20Sopenharmony_ci{
20058c2ecf20Sopenharmony_ci	return 0;
20068c2ecf20Sopenharmony_ci}
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci/**
20098c2ecf20Sopenharmony_ci * qib_6120_get_base_info - set chip-specific flags for user code
20108c2ecf20Sopenharmony_ci * @rcd: the qlogic_ib ctxt
20118c2ecf20Sopenharmony_ci * @kbase: qib_base_info pointer
20128c2ecf20Sopenharmony_ci *
20138c2ecf20Sopenharmony_ci * We set the PCIE flag because the lower bandwidth on PCIe vs
20148c2ecf20Sopenharmony_ci * HyperTransport can affect some user packet algorithms.
20158c2ecf20Sopenharmony_ci */
20168c2ecf20Sopenharmony_cistatic int qib_6120_get_base_info(struct qib_ctxtdata *rcd,
20178c2ecf20Sopenharmony_ci				  struct qib_base_info *kinfo)
20188c2ecf20Sopenharmony_ci{
20198c2ecf20Sopenharmony_ci	if (qib_unordered_wc())
20208c2ecf20Sopenharmony_ci		kinfo->spi_runtime_flags |= QIB_RUNTIME_FORCE_WC_ORDER;
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	kinfo->spi_runtime_flags |= QIB_RUNTIME_PCIE |
20238c2ecf20Sopenharmony_ci		QIB_RUNTIME_FORCE_PIOAVAIL | QIB_RUNTIME_PIO_REGSWAPPED;
20248c2ecf20Sopenharmony_ci	return 0;
20258c2ecf20Sopenharmony_ci}
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_cistatic struct qib_message_header *
20298c2ecf20Sopenharmony_ciqib_6120_get_msgheader(struct qib_devdata *dd, __le32 *rhf_addr)
20308c2ecf20Sopenharmony_ci{
20318c2ecf20Sopenharmony_ci	return (struct qib_message_header *)
20328c2ecf20Sopenharmony_ci		&rhf_addr[sizeof(u64) / sizeof(u32)];
20338c2ecf20Sopenharmony_ci}
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_cistatic void qib_6120_config_ctxts(struct qib_devdata *dd)
20368c2ecf20Sopenharmony_ci{
20378c2ecf20Sopenharmony_ci	dd->ctxtcnt = qib_read_kreg32(dd, kr_portcnt);
20388c2ecf20Sopenharmony_ci	if (qib_n_krcv_queues > 1) {
20398c2ecf20Sopenharmony_ci		dd->first_user_ctxt = qib_n_krcv_queues * dd->num_pports;
20408c2ecf20Sopenharmony_ci		if (dd->first_user_ctxt > dd->ctxtcnt)
20418c2ecf20Sopenharmony_ci			dd->first_user_ctxt = dd->ctxtcnt;
20428c2ecf20Sopenharmony_ci		dd->qpn_mask = dd->first_user_ctxt <= 2 ? 2 : 6;
20438c2ecf20Sopenharmony_ci	} else
20448c2ecf20Sopenharmony_ci		dd->first_user_ctxt = dd->num_pports;
20458c2ecf20Sopenharmony_ci	dd->n_krcv_queues = dd->first_user_ctxt;
20468c2ecf20Sopenharmony_ci}
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_cistatic void qib_update_6120_usrhead(struct qib_ctxtdata *rcd, u64 hd,
20498c2ecf20Sopenharmony_ci				    u32 updegr, u32 egrhd, u32 npkts)
20508c2ecf20Sopenharmony_ci{
20518c2ecf20Sopenharmony_ci	if (updegr)
20528c2ecf20Sopenharmony_ci		qib_write_ureg(rcd->dd, ur_rcvegrindexhead, egrhd, rcd->ctxt);
20538c2ecf20Sopenharmony_ci	qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
20548c2ecf20Sopenharmony_ci}
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_cistatic u32 qib_6120_hdrqempty(struct qib_ctxtdata *rcd)
20578c2ecf20Sopenharmony_ci{
20588c2ecf20Sopenharmony_ci	u32 head, tail;
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	head = qib_read_ureg32(rcd->dd, ur_rcvhdrhead, rcd->ctxt);
20618c2ecf20Sopenharmony_ci	if (rcd->rcvhdrtail_kvaddr)
20628c2ecf20Sopenharmony_ci		tail = qib_get_rcvhdrtail(rcd);
20638c2ecf20Sopenharmony_ci	else
20648c2ecf20Sopenharmony_ci		tail = qib_read_ureg32(rcd->dd, ur_rcvhdrtail, rcd->ctxt);
20658c2ecf20Sopenharmony_ci	return head == tail;
20668c2ecf20Sopenharmony_ci}
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci/*
20698c2ecf20Sopenharmony_ci * Used when we close any ctxt, for DMA already in flight
20708c2ecf20Sopenharmony_ci * at close.  Can't be done until we know hdrq size, so not
20718c2ecf20Sopenharmony_ci * early in chip init.
20728c2ecf20Sopenharmony_ci */
20738c2ecf20Sopenharmony_cistatic void alloc_dummy_hdrq(struct qib_devdata *dd)
20748c2ecf20Sopenharmony_ci{
20758c2ecf20Sopenharmony_ci	dd->cspec->dummy_hdrq = dma_alloc_coherent(&dd->pcidev->dev,
20768c2ecf20Sopenharmony_ci					dd->rcd[0]->rcvhdrq_size,
20778c2ecf20Sopenharmony_ci					&dd->cspec->dummy_hdrq_phys,
20788c2ecf20Sopenharmony_ci					GFP_ATOMIC | __GFP_COMP);
20798c2ecf20Sopenharmony_ci	if (!dd->cspec->dummy_hdrq) {
20808c2ecf20Sopenharmony_ci		qib_devinfo(dd->pcidev, "Couldn't allocate dummy hdrq\n");
20818c2ecf20Sopenharmony_ci		/* fallback to just 0'ing */
20828c2ecf20Sopenharmony_ci		dd->cspec->dummy_hdrq_phys = 0UL;
20838c2ecf20Sopenharmony_ci	}
20848c2ecf20Sopenharmony_ci}
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci/*
20878c2ecf20Sopenharmony_ci * Modify the RCVCTRL register in chip-specific way. This
20888c2ecf20Sopenharmony_ci * is a function because bit positions and (future) register
20898c2ecf20Sopenharmony_ci * location is chip-specific, but the needed operations are
20908c2ecf20Sopenharmony_ci * generic. <op> is a bit-mask because we often want to
20918c2ecf20Sopenharmony_ci * do multiple modifications.
20928c2ecf20Sopenharmony_ci */
20938c2ecf20Sopenharmony_cistatic void rcvctrl_6120_mod(struct qib_pportdata *ppd, unsigned int op,
20948c2ecf20Sopenharmony_ci			     int ctxt)
20958c2ecf20Sopenharmony_ci{
20968c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
20978c2ecf20Sopenharmony_ci	u64 mask, val;
20988c2ecf20Sopenharmony_ci	unsigned long flags;
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dd->cspec->rcvmod_lock, flags);
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci	if (op & QIB_RCVCTRL_TAILUPD_ENB)
21038c2ecf20Sopenharmony_ci		dd->rcvctrl |= (1ULL << QLOGIC_IB_R_TAILUPD_SHIFT);
21048c2ecf20Sopenharmony_ci	if (op & QIB_RCVCTRL_TAILUPD_DIS)
21058c2ecf20Sopenharmony_ci		dd->rcvctrl &= ~(1ULL << QLOGIC_IB_R_TAILUPD_SHIFT);
21068c2ecf20Sopenharmony_ci	if (op & QIB_RCVCTRL_PKEY_ENB)
21078c2ecf20Sopenharmony_ci		dd->rcvctrl &= ~(1ULL << IBA6120_R_PKEY_DIS_SHIFT);
21088c2ecf20Sopenharmony_ci	if (op & QIB_RCVCTRL_PKEY_DIS)
21098c2ecf20Sopenharmony_ci		dd->rcvctrl |= (1ULL << IBA6120_R_PKEY_DIS_SHIFT);
21108c2ecf20Sopenharmony_ci	if (ctxt < 0)
21118c2ecf20Sopenharmony_ci		mask = (1ULL << dd->ctxtcnt) - 1;
21128c2ecf20Sopenharmony_ci	else
21138c2ecf20Sopenharmony_ci		mask = (1ULL << ctxt);
21148c2ecf20Sopenharmony_ci	if (op & QIB_RCVCTRL_CTXT_ENB) {
21158c2ecf20Sopenharmony_ci		/* always done for specific ctxt */
21168c2ecf20Sopenharmony_ci		dd->rcvctrl |= (mask << SYM_LSB(RcvCtrl, PortEnable));
21178c2ecf20Sopenharmony_ci		if (!(dd->flags & QIB_NODMA_RTAIL))
21188c2ecf20Sopenharmony_ci			dd->rcvctrl |= 1ULL << QLOGIC_IB_R_TAILUPD_SHIFT;
21198c2ecf20Sopenharmony_ci		/* Write these registers before the context is enabled. */
21208c2ecf20Sopenharmony_ci		qib_write_kreg_ctxt(dd, kr_rcvhdrtailaddr, ctxt,
21218c2ecf20Sopenharmony_ci			dd->rcd[ctxt]->rcvhdrqtailaddr_phys);
21228c2ecf20Sopenharmony_ci		qib_write_kreg_ctxt(dd, kr_rcvhdraddr, ctxt,
21238c2ecf20Sopenharmony_ci			dd->rcd[ctxt]->rcvhdrq_phys);
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci		if (ctxt == 0 && !dd->cspec->dummy_hdrq)
21268c2ecf20Sopenharmony_ci			alloc_dummy_hdrq(dd);
21278c2ecf20Sopenharmony_ci	}
21288c2ecf20Sopenharmony_ci	if (op & QIB_RCVCTRL_CTXT_DIS)
21298c2ecf20Sopenharmony_ci		dd->rcvctrl &= ~(mask << SYM_LSB(RcvCtrl, PortEnable));
21308c2ecf20Sopenharmony_ci	if (op & QIB_RCVCTRL_INTRAVAIL_ENB)
21318c2ecf20Sopenharmony_ci		dd->rcvctrl |= (mask << QLOGIC_IB_R_INTRAVAIL_SHIFT);
21328c2ecf20Sopenharmony_ci	if (op & QIB_RCVCTRL_INTRAVAIL_DIS)
21338c2ecf20Sopenharmony_ci		dd->rcvctrl &= ~(mask << QLOGIC_IB_R_INTRAVAIL_SHIFT);
21348c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_rcvctrl, dd->rcvctrl);
21358c2ecf20Sopenharmony_ci	if ((op & QIB_RCVCTRL_INTRAVAIL_ENB) && dd->rhdrhead_intr_off) {
21368c2ecf20Sopenharmony_ci		/* arm rcv interrupt */
21378c2ecf20Sopenharmony_ci		val = qib_read_ureg32(dd, ur_rcvhdrhead, ctxt) |
21388c2ecf20Sopenharmony_ci			dd->rhdrhead_intr_off;
21398c2ecf20Sopenharmony_ci		qib_write_ureg(dd, ur_rcvhdrhead, val, ctxt);
21408c2ecf20Sopenharmony_ci	}
21418c2ecf20Sopenharmony_ci	if (op & QIB_RCVCTRL_CTXT_ENB) {
21428c2ecf20Sopenharmony_ci		/*
21438c2ecf20Sopenharmony_ci		 * Init the context registers also; if we were
21448c2ecf20Sopenharmony_ci		 * disabled, tail and head should both be zero
21458c2ecf20Sopenharmony_ci		 * already from the enable, but since we don't
21468c2ecf20Sopenharmony_ci		 * know, we have to do it explicitly.
21478c2ecf20Sopenharmony_ci		 */
21488c2ecf20Sopenharmony_ci		val = qib_read_ureg32(dd, ur_rcvegrindextail, ctxt);
21498c2ecf20Sopenharmony_ci		qib_write_ureg(dd, ur_rcvegrindexhead, val, ctxt);
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci		val = qib_read_ureg32(dd, ur_rcvhdrtail, ctxt);
21528c2ecf20Sopenharmony_ci		dd->rcd[ctxt]->head = val;
21538c2ecf20Sopenharmony_ci		/* If kctxt, interrupt on next receive. */
21548c2ecf20Sopenharmony_ci		if (ctxt < dd->first_user_ctxt)
21558c2ecf20Sopenharmony_ci			val |= dd->rhdrhead_intr_off;
21568c2ecf20Sopenharmony_ci		qib_write_ureg(dd, ur_rcvhdrhead, val, ctxt);
21578c2ecf20Sopenharmony_ci	}
21588c2ecf20Sopenharmony_ci	if (op & QIB_RCVCTRL_CTXT_DIS) {
21598c2ecf20Sopenharmony_ci		/*
21608c2ecf20Sopenharmony_ci		 * Be paranoid, and never write 0's to these, just use an
21618c2ecf20Sopenharmony_ci		 * unused page.  Of course,
21628c2ecf20Sopenharmony_ci		 * rcvhdraddr points to a large chunk of memory, so this
21638c2ecf20Sopenharmony_ci		 * could still trash things, but at least it won't trash
21648c2ecf20Sopenharmony_ci		 * page 0, and by disabling the ctxt, it should stop "soon",
21658c2ecf20Sopenharmony_ci		 * even if a packet or two is in already in flight after we
21668c2ecf20Sopenharmony_ci		 * disabled the ctxt.  Only 6120 has this issue.
21678c2ecf20Sopenharmony_ci		 */
21688c2ecf20Sopenharmony_ci		if (ctxt >= 0) {
21698c2ecf20Sopenharmony_ci			qib_write_kreg_ctxt(dd, kr_rcvhdrtailaddr, ctxt,
21708c2ecf20Sopenharmony_ci					    dd->cspec->dummy_hdrq_phys);
21718c2ecf20Sopenharmony_ci			qib_write_kreg_ctxt(dd, kr_rcvhdraddr, ctxt,
21728c2ecf20Sopenharmony_ci					    dd->cspec->dummy_hdrq_phys);
21738c2ecf20Sopenharmony_ci		} else {
21748c2ecf20Sopenharmony_ci			unsigned i;
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci			for (i = 0; i < dd->cfgctxts; i++) {
21778c2ecf20Sopenharmony_ci				qib_write_kreg_ctxt(dd, kr_rcvhdrtailaddr,
21788c2ecf20Sopenharmony_ci					    i, dd->cspec->dummy_hdrq_phys);
21798c2ecf20Sopenharmony_ci				qib_write_kreg_ctxt(dd, kr_rcvhdraddr,
21808c2ecf20Sopenharmony_ci					    i, dd->cspec->dummy_hdrq_phys);
21818c2ecf20Sopenharmony_ci			}
21828c2ecf20Sopenharmony_ci		}
21838c2ecf20Sopenharmony_ci	}
21848c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags);
21858c2ecf20Sopenharmony_ci}
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci/*
21888c2ecf20Sopenharmony_ci * Modify the SENDCTRL register in chip-specific way. This
21898c2ecf20Sopenharmony_ci * is a function there may be multiple such registers with
21908c2ecf20Sopenharmony_ci * slightly different layouts. Only operations actually used
21918c2ecf20Sopenharmony_ci * are implemented yet.
21928c2ecf20Sopenharmony_ci * Chip requires no back-back sendctrl writes, so write
21938c2ecf20Sopenharmony_ci * scratch register after writing sendctrl
21948c2ecf20Sopenharmony_ci */
21958c2ecf20Sopenharmony_cistatic void sendctrl_6120_mod(struct qib_pportdata *ppd, u32 op)
21968c2ecf20Sopenharmony_ci{
21978c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
21988c2ecf20Sopenharmony_ci	u64 tmp_dd_sendctrl;
21998c2ecf20Sopenharmony_ci	unsigned long flags;
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dd->sendctrl_lock, flags);
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	/* First the ones that are "sticky", saved in shadow */
22048c2ecf20Sopenharmony_ci	if (op & QIB_SENDCTRL_CLEAR)
22058c2ecf20Sopenharmony_ci		dd->sendctrl = 0;
22068c2ecf20Sopenharmony_ci	if (op & QIB_SENDCTRL_SEND_DIS)
22078c2ecf20Sopenharmony_ci		dd->sendctrl &= ~SYM_MASK(SendCtrl, PIOEnable);
22088c2ecf20Sopenharmony_ci	else if (op & QIB_SENDCTRL_SEND_ENB)
22098c2ecf20Sopenharmony_ci		dd->sendctrl |= SYM_MASK(SendCtrl, PIOEnable);
22108c2ecf20Sopenharmony_ci	if (op & QIB_SENDCTRL_AVAIL_DIS)
22118c2ecf20Sopenharmony_ci		dd->sendctrl &= ~SYM_MASK(SendCtrl, PIOBufAvailUpd);
22128c2ecf20Sopenharmony_ci	else if (op & QIB_SENDCTRL_AVAIL_ENB)
22138c2ecf20Sopenharmony_ci		dd->sendctrl |= SYM_MASK(SendCtrl, PIOBufAvailUpd);
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci	if (op & QIB_SENDCTRL_DISARM_ALL) {
22168c2ecf20Sopenharmony_ci		u32 i, last;
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci		tmp_dd_sendctrl = dd->sendctrl;
22198c2ecf20Sopenharmony_ci		/*
22208c2ecf20Sopenharmony_ci		 * disarm any that are not yet launched, disabling sends
22218c2ecf20Sopenharmony_ci		 * and updates until done.
22228c2ecf20Sopenharmony_ci		 */
22238c2ecf20Sopenharmony_ci		last = dd->piobcnt2k + dd->piobcnt4k;
22248c2ecf20Sopenharmony_ci		tmp_dd_sendctrl &=
22258c2ecf20Sopenharmony_ci			~(SYM_MASK(SendCtrl, PIOEnable) |
22268c2ecf20Sopenharmony_ci			  SYM_MASK(SendCtrl, PIOBufAvailUpd));
22278c2ecf20Sopenharmony_ci		for (i = 0; i < last; i++) {
22288c2ecf20Sopenharmony_ci			qib_write_kreg(dd, kr_sendctrl, tmp_dd_sendctrl |
22298c2ecf20Sopenharmony_ci				       SYM_MASK(SendCtrl, Disarm) | i);
22308c2ecf20Sopenharmony_ci			qib_write_kreg(dd, kr_scratch, 0);
22318c2ecf20Sopenharmony_ci		}
22328c2ecf20Sopenharmony_ci	}
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	tmp_dd_sendctrl = dd->sendctrl;
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci	if (op & QIB_SENDCTRL_FLUSH)
22378c2ecf20Sopenharmony_ci		tmp_dd_sendctrl |= SYM_MASK(SendCtrl, Abort);
22388c2ecf20Sopenharmony_ci	if (op & QIB_SENDCTRL_DISARM)
22398c2ecf20Sopenharmony_ci		tmp_dd_sendctrl |= SYM_MASK(SendCtrl, Disarm) |
22408c2ecf20Sopenharmony_ci			((op & QIB_6120_SendCtrl_DisarmPIOBuf_RMASK) <<
22418c2ecf20Sopenharmony_ci			 SYM_LSB(SendCtrl, DisarmPIOBuf));
22428c2ecf20Sopenharmony_ci	if (op & QIB_SENDCTRL_AVAIL_BLIP)
22438c2ecf20Sopenharmony_ci		tmp_dd_sendctrl &= ~SYM_MASK(SendCtrl, PIOBufAvailUpd);
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_sendctrl, tmp_dd_sendctrl);
22468c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_scratch, 0);
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	if (op & QIB_SENDCTRL_AVAIL_BLIP) {
22498c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_sendctrl, dd->sendctrl);
22508c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_scratch, 0);
22518c2ecf20Sopenharmony_ci	}
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dd->sendctrl_lock, flags);
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	if (op & QIB_SENDCTRL_FLUSH) {
22568c2ecf20Sopenharmony_ci		u32 v;
22578c2ecf20Sopenharmony_ci		/*
22588c2ecf20Sopenharmony_ci		 * ensure writes have hit chip, then do a few
22598c2ecf20Sopenharmony_ci		 * more reads, to allow DMA of pioavail registers
22608c2ecf20Sopenharmony_ci		 * to occur, so in-memory copy is in sync with
22618c2ecf20Sopenharmony_ci		 * the chip.  Not always safe to sleep.
22628c2ecf20Sopenharmony_ci		 */
22638c2ecf20Sopenharmony_ci		v = qib_read_kreg32(dd, kr_scratch);
22648c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_scratch, v);
22658c2ecf20Sopenharmony_ci		v = qib_read_kreg32(dd, kr_scratch);
22668c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_scratch, v);
22678c2ecf20Sopenharmony_ci		qib_read_kreg32(dd, kr_scratch);
22688c2ecf20Sopenharmony_ci	}
22698c2ecf20Sopenharmony_ci}
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci/**
22728c2ecf20Sopenharmony_ci * qib_portcntr_6120 - read a per-port counter
22738c2ecf20Sopenharmony_ci * @dd: the qlogic_ib device
22748c2ecf20Sopenharmony_ci * @creg: the counter to snapshot
22758c2ecf20Sopenharmony_ci */
22768c2ecf20Sopenharmony_cistatic u64 qib_portcntr_6120(struct qib_pportdata *ppd, u32 reg)
22778c2ecf20Sopenharmony_ci{
22788c2ecf20Sopenharmony_ci	u64 ret = 0ULL;
22798c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
22808c2ecf20Sopenharmony_ci	u16 creg;
22818c2ecf20Sopenharmony_ci	/* 0xffff for unimplemented or synthesized counters */
22828c2ecf20Sopenharmony_ci	static const u16 xlator[] = {
22838c2ecf20Sopenharmony_ci		[QIBPORTCNTR_PKTSEND] = cr_pktsend,
22848c2ecf20Sopenharmony_ci		[QIBPORTCNTR_WORDSEND] = cr_wordsend,
22858c2ecf20Sopenharmony_ci		[QIBPORTCNTR_PSXMITDATA] = 0xffff,
22868c2ecf20Sopenharmony_ci		[QIBPORTCNTR_PSXMITPKTS] = 0xffff,
22878c2ecf20Sopenharmony_ci		[QIBPORTCNTR_PSXMITWAIT] = 0xffff,
22888c2ecf20Sopenharmony_ci		[QIBPORTCNTR_SENDSTALL] = cr_sendstall,
22898c2ecf20Sopenharmony_ci		[QIBPORTCNTR_PKTRCV] = cr_pktrcv,
22908c2ecf20Sopenharmony_ci		[QIBPORTCNTR_PSRCVDATA] = 0xffff,
22918c2ecf20Sopenharmony_ci		[QIBPORTCNTR_PSRCVPKTS] = 0xffff,
22928c2ecf20Sopenharmony_ci		[QIBPORTCNTR_RCVEBP] = cr_rcvebp,
22938c2ecf20Sopenharmony_ci		[QIBPORTCNTR_RCVOVFL] = cr_rcvovfl,
22948c2ecf20Sopenharmony_ci		[QIBPORTCNTR_WORDRCV] = cr_wordrcv,
22958c2ecf20Sopenharmony_ci		[QIBPORTCNTR_RXDROPPKT] = cr_rxdroppkt,
22968c2ecf20Sopenharmony_ci		[QIBPORTCNTR_RXLOCALPHYERR] = 0xffff,
22978c2ecf20Sopenharmony_ci		[QIBPORTCNTR_RXVLERR] = 0xffff,
22988c2ecf20Sopenharmony_ci		[QIBPORTCNTR_ERRICRC] = cr_erricrc,
22998c2ecf20Sopenharmony_ci		[QIBPORTCNTR_ERRVCRC] = cr_errvcrc,
23008c2ecf20Sopenharmony_ci		[QIBPORTCNTR_ERRLPCRC] = cr_errlpcrc,
23018c2ecf20Sopenharmony_ci		[QIBPORTCNTR_BADFORMAT] = cr_badformat,
23028c2ecf20Sopenharmony_ci		[QIBPORTCNTR_ERR_RLEN] = cr_err_rlen,
23038c2ecf20Sopenharmony_ci		[QIBPORTCNTR_IBSYMBOLERR] = cr_ibsymbolerr,
23048c2ecf20Sopenharmony_ci		[QIBPORTCNTR_INVALIDRLEN] = cr_invalidrlen,
23058c2ecf20Sopenharmony_ci		[QIBPORTCNTR_UNSUPVL] = cr_txunsupvl,
23068c2ecf20Sopenharmony_ci		[QIBPORTCNTR_EXCESSBUFOVFL] = 0xffff,
23078c2ecf20Sopenharmony_ci		[QIBPORTCNTR_ERRLINK] = cr_errlink,
23088c2ecf20Sopenharmony_ci		[QIBPORTCNTR_IBLINKDOWN] = cr_iblinkdown,
23098c2ecf20Sopenharmony_ci		[QIBPORTCNTR_IBLINKERRRECOV] = cr_iblinkerrrecov,
23108c2ecf20Sopenharmony_ci		[QIBPORTCNTR_LLI] = 0xffff,
23118c2ecf20Sopenharmony_ci		[QIBPORTCNTR_PSINTERVAL] = 0xffff,
23128c2ecf20Sopenharmony_ci		[QIBPORTCNTR_PSSTART] = 0xffff,
23138c2ecf20Sopenharmony_ci		[QIBPORTCNTR_PSSTAT] = 0xffff,
23148c2ecf20Sopenharmony_ci		[QIBPORTCNTR_VL15PKTDROP] = 0xffff,
23158c2ecf20Sopenharmony_ci		[QIBPORTCNTR_ERRPKEY] = cr_errpkey,
23168c2ecf20Sopenharmony_ci		[QIBPORTCNTR_KHDROVFL] = 0xffff,
23178c2ecf20Sopenharmony_ci	};
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci	if (reg >= ARRAY_SIZE(xlator)) {
23208c2ecf20Sopenharmony_ci		qib_devinfo(ppd->dd->pcidev,
23218c2ecf20Sopenharmony_ci			 "Unimplemented portcounter %u\n", reg);
23228c2ecf20Sopenharmony_ci		goto done;
23238c2ecf20Sopenharmony_ci	}
23248c2ecf20Sopenharmony_ci	creg = xlator[reg];
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci	/* handle counters requests not implemented as chip counters */
23278c2ecf20Sopenharmony_ci	if (reg == QIBPORTCNTR_LLI)
23288c2ecf20Sopenharmony_ci		ret = dd->cspec->lli_errs;
23298c2ecf20Sopenharmony_ci	else if (reg == QIBPORTCNTR_EXCESSBUFOVFL)
23308c2ecf20Sopenharmony_ci		ret = dd->cspec->overrun_thresh_errs;
23318c2ecf20Sopenharmony_ci	else if (reg == QIBPORTCNTR_KHDROVFL) {
23328c2ecf20Sopenharmony_ci		int i;
23338c2ecf20Sopenharmony_ci
23348c2ecf20Sopenharmony_ci		/* sum over all kernel contexts */
23358c2ecf20Sopenharmony_ci		for (i = 0; i < dd->first_user_ctxt; i++)
23368c2ecf20Sopenharmony_ci			ret += read_6120_creg32(dd, cr_portovfl + i);
23378c2ecf20Sopenharmony_ci	} else if (reg == QIBPORTCNTR_PSSTAT)
23388c2ecf20Sopenharmony_ci		ret = dd->cspec->pma_sample_status;
23398c2ecf20Sopenharmony_ci	if (creg == 0xffff)
23408c2ecf20Sopenharmony_ci		goto done;
23418c2ecf20Sopenharmony_ci
23428c2ecf20Sopenharmony_ci	/*
23438c2ecf20Sopenharmony_ci	 * only fast incrementing counters are 64bit; use 32 bit reads to
23448c2ecf20Sopenharmony_ci	 * avoid two independent reads when on opteron
23458c2ecf20Sopenharmony_ci	 */
23468c2ecf20Sopenharmony_ci	if (creg == cr_wordsend || creg == cr_wordrcv ||
23478c2ecf20Sopenharmony_ci	    creg == cr_pktsend || creg == cr_pktrcv)
23488c2ecf20Sopenharmony_ci		ret = read_6120_creg(dd, creg);
23498c2ecf20Sopenharmony_ci	else
23508c2ecf20Sopenharmony_ci		ret = read_6120_creg32(dd, creg);
23518c2ecf20Sopenharmony_ci	if (creg == cr_ibsymbolerr) {
23528c2ecf20Sopenharmony_ci		if (dd->cspec->ibdeltainprog)
23538c2ecf20Sopenharmony_ci			ret -= ret - dd->cspec->ibsymsnap;
23548c2ecf20Sopenharmony_ci		ret -= dd->cspec->ibsymdelta;
23558c2ecf20Sopenharmony_ci	} else if (creg == cr_iblinkerrrecov) {
23568c2ecf20Sopenharmony_ci		if (dd->cspec->ibdeltainprog)
23578c2ecf20Sopenharmony_ci			ret -= ret - dd->cspec->iblnkerrsnap;
23588c2ecf20Sopenharmony_ci		ret -= dd->cspec->iblnkerrdelta;
23598c2ecf20Sopenharmony_ci	}
23608c2ecf20Sopenharmony_ci	if (reg == QIBPORTCNTR_RXDROPPKT) /* add special cased count */
23618c2ecf20Sopenharmony_ci		ret += dd->cspec->rxfc_unsupvl_errs;
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_cidone:
23648c2ecf20Sopenharmony_ci	return ret;
23658c2ecf20Sopenharmony_ci}
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci/*
23688c2ecf20Sopenharmony_ci * Device counter names (not port-specific), one line per stat,
23698c2ecf20Sopenharmony_ci * single string.  Used by utilities like ipathstats to print the stats
23708c2ecf20Sopenharmony_ci * in a way which works for different versions of drivers, without changing
23718c2ecf20Sopenharmony_ci * the utility.  Names need to be 12 chars or less (w/o newline), for proper
23728c2ecf20Sopenharmony_ci * display by utility.
23738c2ecf20Sopenharmony_ci * Non-error counters are first.
23748c2ecf20Sopenharmony_ci * Start of "error" conters is indicated by a leading "E " on the first
23758c2ecf20Sopenharmony_ci * "error" counter, and doesn't count in label length.
23768c2ecf20Sopenharmony_ci * The EgrOvfl list needs to be last so we truncate them at the configured
23778c2ecf20Sopenharmony_ci * context count for the device.
23788c2ecf20Sopenharmony_ci * cntr6120indices contains the corresponding register indices.
23798c2ecf20Sopenharmony_ci */
23808c2ecf20Sopenharmony_cistatic const char cntr6120names[] =
23818c2ecf20Sopenharmony_ci	"Interrupts\n"
23828c2ecf20Sopenharmony_ci	"HostBusStall\n"
23838c2ecf20Sopenharmony_ci	"E RxTIDFull\n"
23848c2ecf20Sopenharmony_ci	"RxTIDInvalid\n"
23858c2ecf20Sopenharmony_ci	"Ctxt0EgrOvfl\n"
23868c2ecf20Sopenharmony_ci	"Ctxt1EgrOvfl\n"
23878c2ecf20Sopenharmony_ci	"Ctxt2EgrOvfl\n"
23888c2ecf20Sopenharmony_ci	"Ctxt3EgrOvfl\n"
23898c2ecf20Sopenharmony_ci	"Ctxt4EgrOvfl\n";
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_cistatic const size_t cntr6120indices[] = {
23928c2ecf20Sopenharmony_ci	cr_lbint,
23938c2ecf20Sopenharmony_ci	cr_lbflowstall,
23948c2ecf20Sopenharmony_ci	cr_errtidfull,
23958c2ecf20Sopenharmony_ci	cr_errtidvalid,
23968c2ecf20Sopenharmony_ci	cr_portovfl + 0,
23978c2ecf20Sopenharmony_ci	cr_portovfl + 1,
23988c2ecf20Sopenharmony_ci	cr_portovfl + 2,
23998c2ecf20Sopenharmony_ci	cr_portovfl + 3,
24008c2ecf20Sopenharmony_ci	cr_portovfl + 4,
24018c2ecf20Sopenharmony_ci};
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci/*
24048c2ecf20Sopenharmony_ci * same as cntr6120names and cntr6120indices, but for port-specific counters.
24058c2ecf20Sopenharmony_ci * portcntr6120indices is somewhat complicated by some registers needing
24068c2ecf20Sopenharmony_ci * adjustments of various kinds, and those are ORed with _PORT_VIRT_FLAG
24078c2ecf20Sopenharmony_ci */
24088c2ecf20Sopenharmony_cistatic const char portcntr6120names[] =
24098c2ecf20Sopenharmony_ci	"TxPkt\n"
24108c2ecf20Sopenharmony_ci	"TxFlowPkt\n"
24118c2ecf20Sopenharmony_ci	"TxWords\n"
24128c2ecf20Sopenharmony_ci	"RxPkt\n"
24138c2ecf20Sopenharmony_ci	"RxFlowPkt\n"
24148c2ecf20Sopenharmony_ci	"RxWords\n"
24158c2ecf20Sopenharmony_ci	"TxFlowStall\n"
24168c2ecf20Sopenharmony_ci	"E IBStatusChng\n"
24178c2ecf20Sopenharmony_ci	"IBLinkDown\n"
24188c2ecf20Sopenharmony_ci	"IBLnkRecov\n"
24198c2ecf20Sopenharmony_ci	"IBRxLinkErr\n"
24208c2ecf20Sopenharmony_ci	"IBSymbolErr\n"
24218c2ecf20Sopenharmony_ci	"RxLLIErr\n"
24228c2ecf20Sopenharmony_ci	"RxBadFormat\n"
24238c2ecf20Sopenharmony_ci	"RxBadLen\n"
24248c2ecf20Sopenharmony_ci	"RxBufOvrfl\n"
24258c2ecf20Sopenharmony_ci	"RxEBP\n"
24268c2ecf20Sopenharmony_ci	"RxFlowCtlErr\n"
24278c2ecf20Sopenharmony_ci	"RxICRCerr\n"
24288c2ecf20Sopenharmony_ci	"RxLPCRCerr\n"
24298c2ecf20Sopenharmony_ci	"RxVCRCerr\n"
24308c2ecf20Sopenharmony_ci	"RxInvalLen\n"
24318c2ecf20Sopenharmony_ci	"RxInvalPKey\n"
24328c2ecf20Sopenharmony_ci	"RxPktDropped\n"
24338c2ecf20Sopenharmony_ci	"TxBadLength\n"
24348c2ecf20Sopenharmony_ci	"TxDropped\n"
24358c2ecf20Sopenharmony_ci	"TxInvalLen\n"
24368c2ecf20Sopenharmony_ci	"TxUnderrun\n"
24378c2ecf20Sopenharmony_ci	"TxUnsupVL\n"
24388c2ecf20Sopenharmony_ci	;
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci#define _PORT_VIRT_FLAG 0x8000 /* "virtual", need adjustments */
24418c2ecf20Sopenharmony_cistatic const size_t portcntr6120indices[] = {
24428c2ecf20Sopenharmony_ci	QIBPORTCNTR_PKTSEND | _PORT_VIRT_FLAG,
24438c2ecf20Sopenharmony_ci	cr_pktsendflow,
24448c2ecf20Sopenharmony_ci	QIBPORTCNTR_WORDSEND | _PORT_VIRT_FLAG,
24458c2ecf20Sopenharmony_ci	QIBPORTCNTR_PKTRCV | _PORT_VIRT_FLAG,
24468c2ecf20Sopenharmony_ci	cr_pktrcvflowctrl,
24478c2ecf20Sopenharmony_ci	QIBPORTCNTR_WORDRCV | _PORT_VIRT_FLAG,
24488c2ecf20Sopenharmony_ci	QIBPORTCNTR_SENDSTALL | _PORT_VIRT_FLAG,
24498c2ecf20Sopenharmony_ci	cr_ibstatuschange,
24508c2ecf20Sopenharmony_ci	QIBPORTCNTR_IBLINKDOWN | _PORT_VIRT_FLAG,
24518c2ecf20Sopenharmony_ci	QIBPORTCNTR_IBLINKERRRECOV | _PORT_VIRT_FLAG,
24528c2ecf20Sopenharmony_ci	QIBPORTCNTR_ERRLINK | _PORT_VIRT_FLAG,
24538c2ecf20Sopenharmony_ci	QIBPORTCNTR_IBSYMBOLERR | _PORT_VIRT_FLAG,
24548c2ecf20Sopenharmony_ci	QIBPORTCNTR_LLI | _PORT_VIRT_FLAG,
24558c2ecf20Sopenharmony_ci	QIBPORTCNTR_BADFORMAT | _PORT_VIRT_FLAG,
24568c2ecf20Sopenharmony_ci	QIBPORTCNTR_ERR_RLEN | _PORT_VIRT_FLAG,
24578c2ecf20Sopenharmony_ci	QIBPORTCNTR_RCVOVFL | _PORT_VIRT_FLAG,
24588c2ecf20Sopenharmony_ci	QIBPORTCNTR_RCVEBP | _PORT_VIRT_FLAG,
24598c2ecf20Sopenharmony_ci	cr_rcvflowctrl_err,
24608c2ecf20Sopenharmony_ci	QIBPORTCNTR_ERRICRC | _PORT_VIRT_FLAG,
24618c2ecf20Sopenharmony_ci	QIBPORTCNTR_ERRLPCRC | _PORT_VIRT_FLAG,
24628c2ecf20Sopenharmony_ci	QIBPORTCNTR_ERRVCRC | _PORT_VIRT_FLAG,
24638c2ecf20Sopenharmony_ci	QIBPORTCNTR_INVALIDRLEN | _PORT_VIRT_FLAG,
24648c2ecf20Sopenharmony_ci	QIBPORTCNTR_ERRPKEY | _PORT_VIRT_FLAG,
24658c2ecf20Sopenharmony_ci	QIBPORTCNTR_RXDROPPKT | _PORT_VIRT_FLAG,
24668c2ecf20Sopenharmony_ci	cr_invalidslen,
24678c2ecf20Sopenharmony_ci	cr_senddropped,
24688c2ecf20Sopenharmony_ci	cr_errslen,
24698c2ecf20Sopenharmony_ci	cr_sendunderrun,
24708c2ecf20Sopenharmony_ci	cr_txunsupvl,
24718c2ecf20Sopenharmony_ci};
24728c2ecf20Sopenharmony_ci
24738c2ecf20Sopenharmony_ci/* do all the setup to make the counter reads efficient later */
24748c2ecf20Sopenharmony_cistatic void init_6120_cntrnames(struct qib_devdata *dd)
24758c2ecf20Sopenharmony_ci{
24768c2ecf20Sopenharmony_ci	int i, j = 0;
24778c2ecf20Sopenharmony_ci	char *s;
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci	for (i = 0, s = (char *)cntr6120names; s && j <= dd->cfgctxts;
24808c2ecf20Sopenharmony_ci	     i++) {
24818c2ecf20Sopenharmony_ci		/* we always have at least one counter before the egrovfl */
24828c2ecf20Sopenharmony_ci		if (!j && !strncmp("Ctxt0EgrOvfl", s + 1, 12))
24838c2ecf20Sopenharmony_ci			j = 1;
24848c2ecf20Sopenharmony_ci		s = strchr(s + 1, '\n');
24858c2ecf20Sopenharmony_ci		if (s && j)
24868c2ecf20Sopenharmony_ci			j++;
24878c2ecf20Sopenharmony_ci	}
24888c2ecf20Sopenharmony_ci	dd->cspec->ncntrs = i;
24898c2ecf20Sopenharmony_ci	if (!s)
24908c2ecf20Sopenharmony_ci		/* full list; size is without terminating null */
24918c2ecf20Sopenharmony_ci		dd->cspec->cntrnamelen = sizeof(cntr6120names) - 1;
24928c2ecf20Sopenharmony_ci	else
24938c2ecf20Sopenharmony_ci		dd->cspec->cntrnamelen = 1 + s - cntr6120names;
24948c2ecf20Sopenharmony_ci	dd->cspec->cntrs = kmalloc_array(dd->cspec->ncntrs, sizeof(u64),
24958c2ecf20Sopenharmony_ci					 GFP_KERNEL);
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci	for (i = 0, s = (char *)portcntr6120names; s; i++)
24988c2ecf20Sopenharmony_ci		s = strchr(s + 1, '\n');
24998c2ecf20Sopenharmony_ci	dd->cspec->nportcntrs = i - 1;
25008c2ecf20Sopenharmony_ci	dd->cspec->portcntrnamelen = sizeof(portcntr6120names) - 1;
25018c2ecf20Sopenharmony_ci	dd->cspec->portcntrs = kmalloc_array(dd->cspec->nportcntrs,
25028c2ecf20Sopenharmony_ci					     sizeof(u64),
25038c2ecf20Sopenharmony_ci					     GFP_KERNEL);
25048c2ecf20Sopenharmony_ci}
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_cistatic u32 qib_read_6120cntrs(struct qib_devdata *dd, loff_t pos, char **namep,
25078c2ecf20Sopenharmony_ci			      u64 **cntrp)
25088c2ecf20Sopenharmony_ci{
25098c2ecf20Sopenharmony_ci	u32 ret;
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_ci	if (namep) {
25128c2ecf20Sopenharmony_ci		ret = dd->cspec->cntrnamelen;
25138c2ecf20Sopenharmony_ci		if (pos >= ret)
25148c2ecf20Sopenharmony_ci			ret = 0; /* final read after getting everything */
25158c2ecf20Sopenharmony_ci		else
25168c2ecf20Sopenharmony_ci			*namep = (char *)cntr6120names;
25178c2ecf20Sopenharmony_ci	} else {
25188c2ecf20Sopenharmony_ci		u64 *cntr = dd->cspec->cntrs;
25198c2ecf20Sopenharmony_ci		int i;
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci		ret = dd->cspec->ncntrs * sizeof(u64);
25228c2ecf20Sopenharmony_ci		if (!cntr || pos >= ret) {
25238c2ecf20Sopenharmony_ci			/* everything read, or couldn't get memory */
25248c2ecf20Sopenharmony_ci			ret = 0;
25258c2ecf20Sopenharmony_ci			goto done;
25268c2ecf20Sopenharmony_ci		}
25278c2ecf20Sopenharmony_ci		if (pos >= ret) {
25288c2ecf20Sopenharmony_ci			ret = 0; /* final read after getting everything */
25298c2ecf20Sopenharmony_ci			goto done;
25308c2ecf20Sopenharmony_ci		}
25318c2ecf20Sopenharmony_ci		*cntrp = cntr;
25328c2ecf20Sopenharmony_ci		for (i = 0; i < dd->cspec->ncntrs; i++)
25338c2ecf20Sopenharmony_ci			*cntr++ = read_6120_creg32(dd, cntr6120indices[i]);
25348c2ecf20Sopenharmony_ci	}
25358c2ecf20Sopenharmony_cidone:
25368c2ecf20Sopenharmony_ci	return ret;
25378c2ecf20Sopenharmony_ci}
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_cistatic u32 qib_read_6120portcntrs(struct qib_devdata *dd, loff_t pos, u32 port,
25408c2ecf20Sopenharmony_ci				  char **namep, u64 **cntrp)
25418c2ecf20Sopenharmony_ci{
25428c2ecf20Sopenharmony_ci	u32 ret;
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci	if (namep) {
25458c2ecf20Sopenharmony_ci		ret = dd->cspec->portcntrnamelen;
25468c2ecf20Sopenharmony_ci		if (pos >= ret)
25478c2ecf20Sopenharmony_ci			ret = 0; /* final read after getting everything */
25488c2ecf20Sopenharmony_ci		else
25498c2ecf20Sopenharmony_ci			*namep = (char *)portcntr6120names;
25508c2ecf20Sopenharmony_ci	} else {
25518c2ecf20Sopenharmony_ci		u64 *cntr = dd->cspec->portcntrs;
25528c2ecf20Sopenharmony_ci		struct qib_pportdata *ppd = &dd->pport[port];
25538c2ecf20Sopenharmony_ci		int i;
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci		ret = dd->cspec->nportcntrs * sizeof(u64);
25568c2ecf20Sopenharmony_ci		if (!cntr || pos >= ret) {
25578c2ecf20Sopenharmony_ci			/* everything read, or couldn't get memory */
25588c2ecf20Sopenharmony_ci			ret = 0;
25598c2ecf20Sopenharmony_ci			goto done;
25608c2ecf20Sopenharmony_ci		}
25618c2ecf20Sopenharmony_ci		*cntrp = cntr;
25628c2ecf20Sopenharmony_ci		for (i = 0; i < dd->cspec->nportcntrs; i++) {
25638c2ecf20Sopenharmony_ci			if (portcntr6120indices[i] & _PORT_VIRT_FLAG)
25648c2ecf20Sopenharmony_ci				*cntr++ = qib_portcntr_6120(ppd,
25658c2ecf20Sopenharmony_ci					portcntr6120indices[i] &
25668c2ecf20Sopenharmony_ci					~_PORT_VIRT_FLAG);
25678c2ecf20Sopenharmony_ci			else
25688c2ecf20Sopenharmony_ci				*cntr++ = read_6120_creg32(dd,
25698c2ecf20Sopenharmony_ci					   portcntr6120indices[i]);
25708c2ecf20Sopenharmony_ci		}
25718c2ecf20Sopenharmony_ci	}
25728c2ecf20Sopenharmony_cidone:
25738c2ecf20Sopenharmony_ci	return ret;
25748c2ecf20Sopenharmony_ci}
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_cistatic void qib_chk_6120_errormask(struct qib_devdata *dd)
25778c2ecf20Sopenharmony_ci{
25788c2ecf20Sopenharmony_ci	static u32 fixed;
25798c2ecf20Sopenharmony_ci	u32 ctrl;
25808c2ecf20Sopenharmony_ci	unsigned long errormask;
25818c2ecf20Sopenharmony_ci	unsigned long hwerrs;
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci	if (!dd->cspec->errormask || !(dd->flags & QIB_INITTED))
25848c2ecf20Sopenharmony_ci		return;
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci	errormask = qib_read_kreg64(dd, kr_errmask);
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci	if (errormask == dd->cspec->errormask)
25898c2ecf20Sopenharmony_ci		return;
25908c2ecf20Sopenharmony_ci	fixed++;
25918c2ecf20Sopenharmony_ci
25928c2ecf20Sopenharmony_ci	hwerrs = qib_read_kreg64(dd, kr_hwerrstatus);
25938c2ecf20Sopenharmony_ci	ctrl = qib_read_kreg32(dd, kr_control);
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_errmask,
25968c2ecf20Sopenharmony_ci		dd->cspec->errormask);
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci	if ((hwerrs & dd->cspec->hwerrmask) ||
25998c2ecf20Sopenharmony_ci	    (ctrl & QLOGIC_IB_C_FREEZEMODE)) {
26008c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_hwerrclear, 0ULL);
26018c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_errclear, 0ULL);
26028c2ecf20Sopenharmony_ci		/* force re-interrupt of pending events, just in case */
26038c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_intclear, 0ULL);
26048c2ecf20Sopenharmony_ci		qib_devinfo(dd->pcidev,
26058c2ecf20Sopenharmony_ci			 "errormask fixed(%u) %lx->%lx, ctrl %x hwerr %lx\n",
26068c2ecf20Sopenharmony_ci			 fixed, errormask, (unsigned long)dd->cspec->errormask,
26078c2ecf20Sopenharmony_ci			 ctrl, hwerrs);
26088c2ecf20Sopenharmony_ci	}
26098c2ecf20Sopenharmony_ci}
26108c2ecf20Sopenharmony_ci
26118c2ecf20Sopenharmony_ci/**
26128c2ecf20Sopenharmony_ci * qib_get_faststats - get word counters from chip before they overflow
26138c2ecf20Sopenharmony_ci * @opaque - contains a pointer to the qlogic_ib device qib_devdata
26148c2ecf20Sopenharmony_ci *
26158c2ecf20Sopenharmony_ci * This needs more work; in particular, decision on whether we really
26168c2ecf20Sopenharmony_ci * need traffic_wds done the way it is
26178c2ecf20Sopenharmony_ci * called from add_timer
26188c2ecf20Sopenharmony_ci */
26198c2ecf20Sopenharmony_cistatic void qib_get_6120_faststats(struct timer_list *t)
26208c2ecf20Sopenharmony_ci{
26218c2ecf20Sopenharmony_ci	struct qib_devdata *dd = from_timer(dd, t, stats_timer);
26228c2ecf20Sopenharmony_ci	struct qib_pportdata *ppd = dd->pport;
26238c2ecf20Sopenharmony_ci	unsigned long flags;
26248c2ecf20Sopenharmony_ci	u64 traffic_wds;
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_ci	/*
26278c2ecf20Sopenharmony_ci	 * don't access the chip while running diags, or memory diags can
26288c2ecf20Sopenharmony_ci	 * fail
26298c2ecf20Sopenharmony_ci	 */
26308c2ecf20Sopenharmony_ci	if (!(dd->flags & QIB_INITTED) || dd->diag_client)
26318c2ecf20Sopenharmony_ci		/* but re-arm the timer, for diags case; won't hurt other */
26328c2ecf20Sopenharmony_ci		goto done;
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ci	/*
26358c2ecf20Sopenharmony_ci	 * We now try to maintain an activity timer, based on traffic
26368c2ecf20Sopenharmony_ci	 * exceeding a threshold, so we need to check the word-counts
26378c2ecf20Sopenharmony_ci	 * even if they are 64-bit.
26388c2ecf20Sopenharmony_ci	 */
26398c2ecf20Sopenharmony_ci	traffic_wds = qib_portcntr_6120(ppd, cr_wordsend) +
26408c2ecf20Sopenharmony_ci		qib_portcntr_6120(ppd, cr_wordrcv);
26418c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dd->eep_st_lock, flags);
26428c2ecf20Sopenharmony_ci	traffic_wds -= dd->traffic_wds;
26438c2ecf20Sopenharmony_ci	dd->traffic_wds += traffic_wds;
26448c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dd->eep_st_lock, flags);
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_ci	qib_chk_6120_errormask(dd);
26478c2ecf20Sopenharmony_cidone:
26488c2ecf20Sopenharmony_ci	mod_timer(&dd->stats_timer, jiffies + HZ * ACTIVITY_TIMER);
26498c2ecf20Sopenharmony_ci}
26508c2ecf20Sopenharmony_ci
26518c2ecf20Sopenharmony_ci/* no interrupt fallback for these chips */
26528c2ecf20Sopenharmony_cistatic int qib_6120_nointr_fallback(struct qib_devdata *dd)
26538c2ecf20Sopenharmony_ci{
26548c2ecf20Sopenharmony_ci	return 0;
26558c2ecf20Sopenharmony_ci}
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_ci/*
26588c2ecf20Sopenharmony_ci * reset the XGXS (between serdes and IBC).  Slightly less intrusive
26598c2ecf20Sopenharmony_ci * than resetting the IBC or external link state, and useful in some
26608c2ecf20Sopenharmony_ci * cases to cause some retraining.  To do this right, we reset IBC
26618c2ecf20Sopenharmony_ci * as well.
26628c2ecf20Sopenharmony_ci */
26638c2ecf20Sopenharmony_cistatic void qib_6120_xgxs_reset(struct qib_pportdata *ppd)
26648c2ecf20Sopenharmony_ci{
26658c2ecf20Sopenharmony_ci	u64 val, prev_val;
26668c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci	prev_val = qib_read_kreg64(dd, kr_xgxs_cfg);
26698c2ecf20Sopenharmony_ci	val = prev_val | QLOGIC_IB_XGXS_RESET;
26708c2ecf20Sopenharmony_ci	prev_val &= ~QLOGIC_IB_XGXS_RESET; /* be sure */
26718c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_control,
26728c2ecf20Sopenharmony_ci		       dd->control & ~QLOGIC_IB_C_LINKENABLE);
26738c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_xgxs_cfg, val);
26748c2ecf20Sopenharmony_ci	qib_read_kreg32(dd, kr_scratch);
26758c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_xgxs_cfg, prev_val);
26768c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_control, dd->control);
26778c2ecf20Sopenharmony_ci}
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_cistatic int qib_6120_get_ib_cfg(struct qib_pportdata *ppd, int which)
26808c2ecf20Sopenharmony_ci{
26818c2ecf20Sopenharmony_ci	int ret;
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	switch (which) {
26848c2ecf20Sopenharmony_ci	case QIB_IB_CFG_LWID:
26858c2ecf20Sopenharmony_ci		ret = ppd->link_width_active;
26868c2ecf20Sopenharmony_ci		break;
26878c2ecf20Sopenharmony_ci
26888c2ecf20Sopenharmony_ci	case QIB_IB_CFG_SPD:
26898c2ecf20Sopenharmony_ci		ret = ppd->link_speed_active;
26908c2ecf20Sopenharmony_ci		break;
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci	case QIB_IB_CFG_LWID_ENB:
26938c2ecf20Sopenharmony_ci		ret = ppd->link_width_enabled;
26948c2ecf20Sopenharmony_ci		break;
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci	case QIB_IB_CFG_SPD_ENB:
26978c2ecf20Sopenharmony_ci		ret = ppd->link_speed_enabled;
26988c2ecf20Sopenharmony_ci		break;
26998c2ecf20Sopenharmony_ci
27008c2ecf20Sopenharmony_ci	case QIB_IB_CFG_OP_VLS:
27018c2ecf20Sopenharmony_ci		ret = ppd->vls_operational;
27028c2ecf20Sopenharmony_ci		break;
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci	case QIB_IB_CFG_VL_HIGH_CAP:
27058c2ecf20Sopenharmony_ci		ret = 0;
27068c2ecf20Sopenharmony_ci		break;
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci	case QIB_IB_CFG_VL_LOW_CAP:
27098c2ecf20Sopenharmony_ci		ret = 0;
27108c2ecf20Sopenharmony_ci		break;
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_ci	case QIB_IB_CFG_OVERRUN_THRESH: /* IB overrun threshold */
27138c2ecf20Sopenharmony_ci		ret = SYM_FIELD(ppd->dd->cspec->ibcctrl, IBCCtrl,
27148c2ecf20Sopenharmony_ci				OverrunThreshold);
27158c2ecf20Sopenharmony_ci		break;
27168c2ecf20Sopenharmony_ci
27178c2ecf20Sopenharmony_ci	case QIB_IB_CFG_PHYERR_THRESH: /* IB PHY error threshold */
27188c2ecf20Sopenharmony_ci		ret = SYM_FIELD(ppd->dd->cspec->ibcctrl, IBCCtrl,
27198c2ecf20Sopenharmony_ci				PhyerrThreshold);
27208c2ecf20Sopenharmony_ci		break;
27218c2ecf20Sopenharmony_ci
27228c2ecf20Sopenharmony_ci	case QIB_IB_CFG_LINKDEFAULT: /* IB link default (sleep/poll) */
27238c2ecf20Sopenharmony_ci		/* will only take effect when the link state changes */
27248c2ecf20Sopenharmony_ci		ret = (ppd->dd->cspec->ibcctrl &
27258c2ecf20Sopenharmony_ci		       SYM_MASK(IBCCtrl, LinkDownDefaultState)) ?
27268c2ecf20Sopenharmony_ci			IB_LINKINITCMD_SLEEP : IB_LINKINITCMD_POLL;
27278c2ecf20Sopenharmony_ci		break;
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci	case QIB_IB_CFG_HRTBT: /* Get Heartbeat off/enable/auto */
27308c2ecf20Sopenharmony_ci		ret = 0; /* no heartbeat on this chip */
27318c2ecf20Sopenharmony_ci		break;
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci	case QIB_IB_CFG_PMA_TICKS:
27348c2ecf20Sopenharmony_ci		ret = 250; /* 1 usec. */
27358c2ecf20Sopenharmony_ci		break;
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_ci	default:
27388c2ecf20Sopenharmony_ci		ret =  -EINVAL;
27398c2ecf20Sopenharmony_ci		break;
27408c2ecf20Sopenharmony_ci	}
27418c2ecf20Sopenharmony_ci	return ret;
27428c2ecf20Sopenharmony_ci}
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci/*
27458c2ecf20Sopenharmony_ci * We assume range checking is already done, if needed.
27468c2ecf20Sopenharmony_ci */
27478c2ecf20Sopenharmony_cistatic int qib_6120_set_ib_cfg(struct qib_pportdata *ppd, int which, u32 val)
27488c2ecf20Sopenharmony_ci{
27498c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
27508c2ecf20Sopenharmony_ci	int ret = 0;
27518c2ecf20Sopenharmony_ci	u64 val64;
27528c2ecf20Sopenharmony_ci	u16 lcmd, licmd;
27538c2ecf20Sopenharmony_ci
27548c2ecf20Sopenharmony_ci	switch (which) {
27558c2ecf20Sopenharmony_ci	case QIB_IB_CFG_LWID_ENB:
27568c2ecf20Sopenharmony_ci		ppd->link_width_enabled = val;
27578c2ecf20Sopenharmony_ci		break;
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_ci	case QIB_IB_CFG_SPD_ENB:
27608c2ecf20Sopenharmony_ci		ppd->link_speed_enabled = val;
27618c2ecf20Sopenharmony_ci		break;
27628c2ecf20Sopenharmony_ci
27638c2ecf20Sopenharmony_ci	case QIB_IB_CFG_OVERRUN_THRESH: /* IB overrun threshold */
27648c2ecf20Sopenharmony_ci		val64 = SYM_FIELD(dd->cspec->ibcctrl, IBCCtrl,
27658c2ecf20Sopenharmony_ci				  OverrunThreshold);
27668c2ecf20Sopenharmony_ci		if (val64 != val) {
27678c2ecf20Sopenharmony_ci			dd->cspec->ibcctrl &=
27688c2ecf20Sopenharmony_ci				~SYM_MASK(IBCCtrl, OverrunThreshold);
27698c2ecf20Sopenharmony_ci			dd->cspec->ibcctrl |= (u64) val <<
27708c2ecf20Sopenharmony_ci				SYM_LSB(IBCCtrl, OverrunThreshold);
27718c2ecf20Sopenharmony_ci			qib_write_kreg(dd, kr_ibcctrl, dd->cspec->ibcctrl);
27728c2ecf20Sopenharmony_ci			qib_write_kreg(dd, kr_scratch, 0);
27738c2ecf20Sopenharmony_ci		}
27748c2ecf20Sopenharmony_ci		break;
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	case QIB_IB_CFG_PHYERR_THRESH: /* IB PHY error threshold */
27778c2ecf20Sopenharmony_ci		val64 = SYM_FIELD(dd->cspec->ibcctrl, IBCCtrl,
27788c2ecf20Sopenharmony_ci				  PhyerrThreshold);
27798c2ecf20Sopenharmony_ci		if (val64 != val) {
27808c2ecf20Sopenharmony_ci			dd->cspec->ibcctrl &=
27818c2ecf20Sopenharmony_ci				~SYM_MASK(IBCCtrl, PhyerrThreshold);
27828c2ecf20Sopenharmony_ci			dd->cspec->ibcctrl |= (u64) val <<
27838c2ecf20Sopenharmony_ci				SYM_LSB(IBCCtrl, PhyerrThreshold);
27848c2ecf20Sopenharmony_ci			qib_write_kreg(dd, kr_ibcctrl, dd->cspec->ibcctrl);
27858c2ecf20Sopenharmony_ci			qib_write_kreg(dd, kr_scratch, 0);
27868c2ecf20Sopenharmony_ci		}
27878c2ecf20Sopenharmony_ci		break;
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci	case QIB_IB_CFG_PKEYS: /* update pkeys */
27908c2ecf20Sopenharmony_ci		val64 = (u64) ppd->pkeys[0] | ((u64) ppd->pkeys[1] << 16) |
27918c2ecf20Sopenharmony_ci			((u64) ppd->pkeys[2] << 32) |
27928c2ecf20Sopenharmony_ci			((u64) ppd->pkeys[3] << 48);
27938c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_partitionkey, val64);
27948c2ecf20Sopenharmony_ci		break;
27958c2ecf20Sopenharmony_ci
27968c2ecf20Sopenharmony_ci	case QIB_IB_CFG_LINKDEFAULT: /* IB link default (sleep/poll) */
27978c2ecf20Sopenharmony_ci		/* will only take effect when the link state changes */
27988c2ecf20Sopenharmony_ci		if (val == IB_LINKINITCMD_POLL)
27998c2ecf20Sopenharmony_ci			dd->cspec->ibcctrl &=
28008c2ecf20Sopenharmony_ci				~SYM_MASK(IBCCtrl, LinkDownDefaultState);
28018c2ecf20Sopenharmony_ci		else /* SLEEP */
28028c2ecf20Sopenharmony_ci			dd->cspec->ibcctrl |=
28038c2ecf20Sopenharmony_ci				SYM_MASK(IBCCtrl, LinkDownDefaultState);
28048c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_ibcctrl, dd->cspec->ibcctrl);
28058c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_scratch, 0);
28068c2ecf20Sopenharmony_ci		break;
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_ci	case QIB_IB_CFG_MTU: /* update the MTU in IBC */
28098c2ecf20Sopenharmony_ci		/*
28108c2ecf20Sopenharmony_ci		 * Update our housekeeping variables, and set IBC max
28118c2ecf20Sopenharmony_ci		 * size, same as init code; max IBC is max we allow in
28128c2ecf20Sopenharmony_ci		 * buffer, less the qword pbc, plus 1 for ICRC, in dwords
28138c2ecf20Sopenharmony_ci		 * Set even if it's unchanged, print debug message only
28148c2ecf20Sopenharmony_ci		 * on changes.
28158c2ecf20Sopenharmony_ci		 */
28168c2ecf20Sopenharmony_ci		val = (ppd->ibmaxlen >> 2) + 1;
28178c2ecf20Sopenharmony_ci		dd->cspec->ibcctrl &= ~SYM_MASK(IBCCtrl, MaxPktLen);
28188c2ecf20Sopenharmony_ci		dd->cspec->ibcctrl |= (u64)val <<
28198c2ecf20Sopenharmony_ci			SYM_LSB(IBCCtrl, MaxPktLen);
28208c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_ibcctrl, dd->cspec->ibcctrl);
28218c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_scratch, 0);
28228c2ecf20Sopenharmony_ci		break;
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci	case QIB_IB_CFG_LSTATE: /* set the IB link state */
28258c2ecf20Sopenharmony_ci		switch (val & 0xffff0000) {
28268c2ecf20Sopenharmony_ci		case IB_LINKCMD_DOWN:
28278c2ecf20Sopenharmony_ci			lcmd = QLOGIC_IB_IBCC_LINKCMD_DOWN;
28288c2ecf20Sopenharmony_ci			if (!dd->cspec->ibdeltainprog) {
28298c2ecf20Sopenharmony_ci				dd->cspec->ibdeltainprog = 1;
28308c2ecf20Sopenharmony_ci				dd->cspec->ibsymsnap =
28318c2ecf20Sopenharmony_ci					read_6120_creg32(dd, cr_ibsymbolerr);
28328c2ecf20Sopenharmony_ci				dd->cspec->iblnkerrsnap =
28338c2ecf20Sopenharmony_ci					read_6120_creg32(dd, cr_iblinkerrrecov);
28348c2ecf20Sopenharmony_ci			}
28358c2ecf20Sopenharmony_ci			break;
28368c2ecf20Sopenharmony_ci
28378c2ecf20Sopenharmony_ci		case IB_LINKCMD_ARMED:
28388c2ecf20Sopenharmony_ci			lcmd = QLOGIC_IB_IBCC_LINKCMD_ARMED;
28398c2ecf20Sopenharmony_ci			break;
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci		case IB_LINKCMD_ACTIVE:
28428c2ecf20Sopenharmony_ci			lcmd = QLOGIC_IB_IBCC_LINKCMD_ACTIVE;
28438c2ecf20Sopenharmony_ci			break;
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_ci		default:
28468c2ecf20Sopenharmony_ci			ret = -EINVAL;
28478c2ecf20Sopenharmony_ci			qib_dev_err(dd, "bad linkcmd req 0x%x\n", val >> 16);
28488c2ecf20Sopenharmony_ci			goto bail;
28498c2ecf20Sopenharmony_ci		}
28508c2ecf20Sopenharmony_ci		switch (val & 0xffff) {
28518c2ecf20Sopenharmony_ci		case IB_LINKINITCMD_NOP:
28528c2ecf20Sopenharmony_ci			licmd = 0;
28538c2ecf20Sopenharmony_ci			break;
28548c2ecf20Sopenharmony_ci
28558c2ecf20Sopenharmony_ci		case IB_LINKINITCMD_POLL:
28568c2ecf20Sopenharmony_ci			licmd = QLOGIC_IB_IBCC_LINKINITCMD_POLL;
28578c2ecf20Sopenharmony_ci			break;
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_ci		case IB_LINKINITCMD_SLEEP:
28608c2ecf20Sopenharmony_ci			licmd = QLOGIC_IB_IBCC_LINKINITCMD_SLEEP;
28618c2ecf20Sopenharmony_ci			break;
28628c2ecf20Sopenharmony_ci
28638c2ecf20Sopenharmony_ci		case IB_LINKINITCMD_DISABLE:
28648c2ecf20Sopenharmony_ci			licmd = QLOGIC_IB_IBCC_LINKINITCMD_DISABLE;
28658c2ecf20Sopenharmony_ci			break;
28668c2ecf20Sopenharmony_ci
28678c2ecf20Sopenharmony_ci		default:
28688c2ecf20Sopenharmony_ci			ret = -EINVAL;
28698c2ecf20Sopenharmony_ci			qib_dev_err(dd, "bad linkinitcmd req 0x%x\n",
28708c2ecf20Sopenharmony_ci				    val & 0xffff);
28718c2ecf20Sopenharmony_ci			goto bail;
28728c2ecf20Sopenharmony_ci		}
28738c2ecf20Sopenharmony_ci		qib_set_ib_6120_lstate(ppd, lcmd, licmd);
28748c2ecf20Sopenharmony_ci		goto bail;
28758c2ecf20Sopenharmony_ci
28768c2ecf20Sopenharmony_ci	case QIB_IB_CFG_HRTBT:
28778c2ecf20Sopenharmony_ci		ret = -EINVAL;
28788c2ecf20Sopenharmony_ci		break;
28798c2ecf20Sopenharmony_ci
28808c2ecf20Sopenharmony_ci	default:
28818c2ecf20Sopenharmony_ci		ret = -EINVAL;
28828c2ecf20Sopenharmony_ci	}
28838c2ecf20Sopenharmony_cibail:
28848c2ecf20Sopenharmony_ci	return ret;
28858c2ecf20Sopenharmony_ci}
28868c2ecf20Sopenharmony_ci
28878c2ecf20Sopenharmony_cistatic int qib_6120_set_loopback(struct qib_pportdata *ppd, const char *what)
28888c2ecf20Sopenharmony_ci{
28898c2ecf20Sopenharmony_ci	int ret = 0;
28908c2ecf20Sopenharmony_ci
28918c2ecf20Sopenharmony_ci	if (!strncmp(what, "ibc", 3)) {
28928c2ecf20Sopenharmony_ci		ppd->dd->cspec->ibcctrl |= SYM_MASK(IBCCtrl, Loopback);
28938c2ecf20Sopenharmony_ci		qib_devinfo(ppd->dd->pcidev, "Enabling IB%u:%u IBC loopback\n",
28948c2ecf20Sopenharmony_ci			 ppd->dd->unit, ppd->port);
28958c2ecf20Sopenharmony_ci	} else if (!strncmp(what, "off", 3)) {
28968c2ecf20Sopenharmony_ci		ppd->dd->cspec->ibcctrl &= ~SYM_MASK(IBCCtrl, Loopback);
28978c2ecf20Sopenharmony_ci		qib_devinfo(ppd->dd->pcidev,
28988c2ecf20Sopenharmony_ci			"Disabling IB%u:%u IBC loopback (normal)\n",
28998c2ecf20Sopenharmony_ci			ppd->dd->unit, ppd->port);
29008c2ecf20Sopenharmony_ci	} else
29018c2ecf20Sopenharmony_ci		ret = -EINVAL;
29028c2ecf20Sopenharmony_ci	if (!ret) {
29038c2ecf20Sopenharmony_ci		qib_write_kreg(ppd->dd, kr_ibcctrl, ppd->dd->cspec->ibcctrl);
29048c2ecf20Sopenharmony_ci		qib_write_kreg(ppd->dd, kr_scratch, 0);
29058c2ecf20Sopenharmony_ci	}
29068c2ecf20Sopenharmony_ci	return ret;
29078c2ecf20Sopenharmony_ci}
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_cistatic void pma_6120_timer(struct timer_list *t)
29108c2ecf20Sopenharmony_ci{
29118c2ecf20Sopenharmony_ci	struct qib_chip_specific *cs = from_timer(cs, t, pma_timer);
29128c2ecf20Sopenharmony_ci	struct qib_pportdata *ppd = cs->ppd;
29138c2ecf20Sopenharmony_ci	struct qib_ibport *ibp = &ppd->ibport_data;
29148c2ecf20Sopenharmony_ci	unsigned long flags;
29158c2ecf20Sopenharmony_ci
29168c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ibp->rvp.lock, flags);
29178c2ecf20Sopenharmony_ci	if (cs->pma_sample_status == IB_PMA_SAMPLE_STATUS_STARTED) {
29188c2ecf20Sopenharmony_ci		cs->pma_sample_status = IB_PMA_SAMPLE_STATUS_RUNNING;
29198c2ecf20Sopenharmony_ci		qib_snapshot_counters(ppd, &cs->sword, &cs->rword,
29208c2ecf20Sopenharmony_ci				      &cs->spkts, &cs->rpkts, &cs->xmit_wait);
29218c2ecf20Sopenharmony_ci		mod_timer(&cs->pma_timer,
29228c2ecf20Sopenharmony_ci		      jiffies + usecs_to_jiffies(ibp->rvp.pma_sample_interval));
29238c2ecf20Sopenharmony_ci	} else if (cs->pma_sample_status == IB_PMA_SAMPLE_STATUS_RUNNING) {
29248c2ecf20Sopenharmony_ci		u64 ta, tb, tc, td, te;
29258c2ecf20Sopenharmony_ci
29268c2ecf20Sopenharmony_ci		cs->pma_sample_status = IB_PMA_SAMPLE_STATUS_DONE;
29278c2ecf20Sopenharmony_ci		qib_snapshot_counters(ppd, &ta, &tb, &tc, &td, &te);
29288c2ecf20Sopenharmony_ci
29298c2ecf20Sopenharmony_ci		cs->sword = ta - cs->sword;
29308c2ecf20Sopenharmony_ci		cs->rword = tb - cs->rword;
29318c2ecf20Sopenharmony_ci		cs->spkts = tc - cs->spkts;
29328c2ecf20Sopenharmony_ci		cs->rpkts = td - cs->rpkts;
29338c2ecf20Sopenharmony_ci		cs->xmit_wait = te - cs->xmit_wait;
29348c2ecf20Sopenharmony_ci	}
29358c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ibp->rvp.lock, flags);
29368c2ecf20Sopenharmony_ci}
29378c2ecf20Sopenharmony_ci
29388c2ecf20Sopenharmony_ci/*
29398c2ecf20Sopenharmony_ci * Note that the caller has the ibp->rvp.lock held.
29408c2ecf20Sopenharmony_ci */
29418c2ecf20Sopenharmony_cistatic void qib_set_cntr_6120_sample(struct qib_pportdata *ppd, u32 intv,
29428c2ecf20Sopenharmony_ci				     u32 start)
29438c2ecf20Sopenharmony_ci{
29448c2ecf20Sopenharmony_ci	struct qib_chip_specific *cs = ppd->dd->cspec;
29458c2ecf20Sopenharmony_ci
29468c2ecf20Sopenharmony_ci	if (start && intv) {
29478c2ecf20Sopenharmony_ci		cs->pma_sample_status = IB_PMA_SAMPLE_STATUS_STARTED;
29488c2ecf20Sopenharmony_ci		mod_timer(&cs->pma_timer, jiffies + usecs_to_jiffies(start));
29498c2ecf20Sopenharmony_ci	} else if (intv) {
29508c2ecf20Sopenharmony_ci		cs->pma_sample_status = IB_PMA_SAMPLE_STATUS_RUNNING;
29518c2ecf20Sopenharmony_ci		qib_snapshot_counters(ppd, &cs->sword, &cs->rword,
29528c2ecf20Sopenharmony_ci				      &cs->spkts, &cs->rpkts, &cs->xmit_wait);
29538c2ecf20Sopenharmony_ci		mod_timer(&cs->pma_timer, jiffies + usecs_to_jiffies(intv));
29548c2ecf20Sopenharmony_ci	} else {
29558c2ecf20Sopenharmony_ci		cs->pma_sample_status = IB_PMA_SAMPLE_STATUS_DONE;
29568c2ecf20Sopenharmony_ci		cs->sword = 0;
29578c2ecf20Sopenharmony_ci		cs->rword = 0;
29588c2ecf20Sopenharmony_ci		cs->spkts = 0;
29598c2ecf20Sopenharmony_ci		cs->rpkts = 0;
29608c2ecf20Sopenharmony_ci		cs->xmit_wait = 0;
29618c2ecf20Sopenharmony_ci	}
29628c2ecf20Sopenharmony_ci}
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_cistatic u32 qib_6120_iblink_state(u64 ibcs)
29658c2ecf20Sopenharmony_ci{
29668c2ecf20Sopenharmony_ci	u32 state = (u32)SYM_FIELD(ibcs, IBCStatus, LinkState);
29678c2ecf20Sopenharmony_ci
29688c2ecf20Sopenharmony_ci	switch (state) {
29698c2ecf20Sopenharmony_ci	case IB_6120_L_STATE_INIT:
29708c2ecf20Sopenharmony_ci		state = IB_PORT_INIT;
29718c2ecf20Sopenharmony_ci		break;
29728c2ecf20Sopenharmony_ci	case IB_6120_L_STATE_ARM:
29738c2ecf20Sopenharmony_ci		state = IB_PORT_ARMED;
29748c2ecf20Sopenharmony_ci		break;
29758c2ecf20Sopenharmony_ci	case IB_6120_L_STATE_ACTIVE:
29768c2ecf20Sopenharmony_ci	case IB_6120_L_STATE_ACT_DEFER:
29778c2ecf20Sopenharmony_ci		state = IB_PORT_ACTIVE;
29788c2ecf20Sopenharmony_ci		break;
29798c2ecf20Sopenharmony_ci	default:
29808c2ecf20Sopenharmony_ci		fallthrough;
29818c2ecf20Sopenharmony_ci	case IB_6120_L_STATE_DOWN:
29828c2ecf20Sopenharmony_ci		state = IB_PORT_DOWN;
29838c2ecf20Sopenharmony_ci		break;
29848c2ecf20Sopenharmony_ci	}
29858c2ecf20Sopenharmony_ci	return state;
29868c2ecf20Sopenharmony_ci}
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_ci/* returns the IBTA port state, rather than the IBC link training state */
29898c2ecf20Sopenharmony_cistatic u8 qib_6120_phys_portstate(u64 ibcs)
29908c2ecf20Sopenharmony_ci{
29918c2ecf20Sopenharmony_ci	u8 state = (u8)SYM_FIELD(ibcs, IBCStatus, LinkTrainingState);
29928c2ecf20Sopenharmony_ci	return qib_6120_physportstate[state];
29938c2ecf20Sopenharmony_ci}
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_cistatic int qib_6120_ib_updown(struct qib_pportdata *ppd, int ibup, u64 ibcs)
29968c2ecf20Sopenharmony_ci{
29978c2ecf20Sopenharmony_ci	unsigned long flags;
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ppd->lflags_lock, flags);
30008c2ecf20Sopenharmony_ci	ppd->lflags &= ~QIBL_IB_FORCE_NOTIFY;
30018c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ppd->lflags_lock, flags);
30028c2ecf20Sopenharmony_ci
30038c2ecf20Sopenharmony_ci	if (ibup) {
30048c2ecf20Sopenharmony_ci		if (ppd->dd->cspec->ibdeltainprog) {
30058c2ecf20Sopenharmony_ci			ppd->dd->cspec->ibdeltainprog = 0;
30068c2ecf20Sopenharmony_ci			ppd->dd->cspec->ibsymdelta +=
30078c2ecf20Sopenharmony_ci				read_6120_creg32(ppd->dd, cr_ibsymbolerr) -
30088c2ecf20Sopenharmony_ci					ppd->dd->cspec->ibsymsnap;
30098c2ecf20Sopenharmony_ci			ppd->dd->cspec->iblnkerrdelta +=
30108c2ecf20Sopenharmony_ci				read_6120_creg32(ppd->dd, cr_iblinkerrrecov) -
30118c2ecf20Sopenharmony_ci					ppd->dd->cspec->iblnkerrsnap;
30128c2ecf20Sopenharmony_ci		}
30138c2ecf20Sopenharmony_ci		qib_hol_init(ppd);
30148c2ecf20Sopenharmony_ci	} else {
30158c2ecf20Sopenharmony_ci		ppd->dd->cspec->lli_counter = 0;
30168c2ecf20Sopenharmony_ci		if (!ppd->dd->cspec->ibdeltainprog) {
30178c2ecf20Sopenharmony_ci			ppd->dd->cspec->ibdeltainprog = 1;
30188c2ecf20Sopenharmony_ci			ppd->dd->cspec->ibsymsnap =
30198c2ecf20Sopenharmony_ci				read_6120_creg32(ppd->dd, cr_ibsymbolerr);
30208c2ecf20Sopenharmony_ci			ppd->dd->cspec->iblnkerrsnap =
30218c2ecf20Sopenharmony_ci				read_6120_creg32(ppd->dd, cr_iblinkerrrecov);
30228c2ecf20Sopenharmony_ci		}
30238c2ecf20Sopenharmony_ci		qib_hol_down(ppd);
30248c2ecf20Sopenharmony_ci	}
30258c2ecf20Sopenharmony_ci
30268c2ecf20Sopenharmony_ci	qib_6120_setup_setextled(ppd, ibup);
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci	return 0;
30298c2ecf20Sopenharmony_ci}
30308c2ecf20Sopenharmony_ci
30318c2ecf20Sopenharmony_ci/* Does read/modify/write to appropriate registers to
30328c2ecf20Sopenharmony_ci * set output and direction bits selected by mask.
30338c2ecf20Sopenharmony_ci * these are in their canonical postions (e.g. lsb of
30348c2ecf20Sopenharmony_ci * dir will end up in D48 of extctrl on existing chips).
30358c2ecf20Sopenharmony_ci * returns contents of GP Inputs.
30368c2ecf20Sopenharmony_ci */
30378c2ecf20Sopenharmony_cistatic int gpio_6120_mod(struct qib_devdata *dd, u32 out, u32 dir, u32 mask)
30388c2ecf20Sopenharmony_ci{
30398c2ecf20Sopenharmony_ci	u64 read_val, new_out;
30408c2ecf20Sopenharmony_ci	unsigned long flags;
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci	if (mask) {
30438c2ecf20Sopenharmony_ci		/* some bits being written, lock access to GPIO */
30448c2ecf20Sopenharmony_ci		dir &= mask;
30458c2ecf20Sopenharmony_ci		out &= mask;
30468c2ecf20Sopenharmony_ci		spin_lock_irqsave(&dd->cspec->gpio_lock, flags);
30478c2ecf20Sopenharmony_ci		dd->cspec->extctrl &= ~((u64)mask << SYM_LSB(EXTCtrl, GPIOOe));
30488c2ecf20Sopenharmony_ci		dd->cspec->extctrl |= ((u64) dir << SYM_LSB(EXTCtrl, GPIOOe));
30498c2ecf20Sopenharmony_ci		new_out = (dd->cspec->gpio_out & ~mask) | out;
30508c2ecf20Sopenharmony_ci
30518c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_extctrl, dd->cspec->extctrl);
30528c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_gpio_out, new_out);
30538c2ecf20Sopenharmony_ci		dd->cspec->gpio_out = new_out;
30548c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&dd->cspec->gpio_lock, flags);
30558c2ecf20Sopenharmony_ci	}
30568c2ecf20Sopenharmony_ci	/*
30578c2ecf20Sopenharmony_ci	 * It is unlikely that a read at this time would get valid
30588c2ecf20Sopenharmony_ci	 * data on a pin whose direction line was set in the same
30598c2ecf20Sopenharmony_ci	 * call to this function. We include the read here because
30608c2ecf20Sopenharmony_ci	 * that allows us to potentially combine a change on one pin with
30618c2ecf20Sopenharmony_ci	 * a read on another, and because the old code did something like
30628c2ecf20Sopenharmony_ci	 * this.
30638c2ecf20Sopenharmony_ci	 */
30648c2ecf20Sopenharmony_ci	read_val = qib_read_kreg64(dd, kr_extstatus);
30658c2ecf20Sopenharmony_ci	return SYM_FIELD(read_val, EXTStatus, GPIOIn);
30668c2ecf20Sopenharmony_ci}
30678c2ecf20Sopenharmony_ci
30688c2ecf20Sopenharmony_ci/*
30698c2ecf20Sopenharmony_ci * Read fundamental info we need to use the chip.  These are
30708c2ecf20Sopenharmony_ci * the registers that describe chip capabilities, and are
30718c2ecf20Sopenharmony_ci * saved in shadow registers.
30728c2ecf20Sopenharmony_ci */
30738c2ecf20Sopenharmony_cistatic void get_6120_chip_params(struct qib_devdata *dd)
30748c2ecf20Sopenharmony_ci{
30758c2ecf20Sopenharmony_ci	u64 val;
30768c2ecf20Sopenharmony_ci	u32 piobufs;
30778c2ecf20Sopenharmony_ci	int mtu;
30788c2ecf20Sopenharmony_ci
30798c2ecf20Sopenharmony_ci	dd->uregbase = qib_read_kreg32(dd, kr_userregbase);
30808c2ecf20Sopenharmony_ci
30818c2ecf20Sopenharmony_ci	dd->rcvtidcnt = qib_read_kreg32(dd, kr_rcvtidcnt);
30828c2ecf20Sopenharmony_ci	dd->rcvtidbase = qib_read_kreg32(dd, kr_rcvtidbase);
30838c2ecf20Sopenharmony_ci	dd->rcvegrbase = qib_read_kreg32(dd, kr_rcvegrbase);
30848c2ecf20Sopenharmony_ci	dd->palign = qib_read_kreg32(dd, kr_palign);
30858c2ecf20Sopenharmony_ci	dd->piobufbase = qib_read_kreg64(dd, kr_sendpiobufbase);
30868c2ecf20Sopenharmony_ci	dd->pio2k_bufbase = dd->piobufbase & 0xffffffff;
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_ci	dd->rcvhdrcnt = qib_read_kreg32(dd, kr_rcvegrcnt);
30898c2ecf20Sopenharmony_ci
30908c2ecf20Sopenharmony_ci	val = qib_read_kreg64(dd, kr_sendpiosize);
30918c2ecf20Sopenharmony_ci	dd->piosize2k = val & ~0U;
30928c2ecf20Sopenharmony_ci	dd->piosize4k = val >> 32;
30938c2ecf20Sopenharmony_ci
30948c2ecf20Sopenharmony_ci	mtu = ib_mtu_enum_to_int(qib_ibmtu);
30958c2ecf20Sopenharmony_ci	if (mtu == -1)
30968c2ecf20Sopenharmony_ci		mtu = QIB_DEFAULT_MTU;
30978c2ecf20Sopenharmony_ci	dd->pport->ibmtu = (u32)mtu;
30988c2ecf20Sopenharmony_ci
30998c2ecf20Sopenharmony_ci	val = qib_read_kreg64(dd, kr_sendpiobufcnt);
31008c2ecf20Sopenharmony_ci	dd->piobcnt2k = val & ~0U;
31018c2ecf20Sopenharmony_ci	dd->piobcnt4k = val >> 32;
31028c2ecf20Sopenharmony_ci	dd->last_pio = dd->piobcnt4k + dd->piobcnt2k - 1;
31038c2ecf20Sopenharmony_ci	/* these may be adjusted in init_chip_wc_pat() */
31048c2ecf20Sopenharmony_ci	dd->pio2kbase = (u32 __iomem *)
31058c2ecf20Sopenharmony_ci		(((char __iomem *)dd->kregbase) + dd->pio2k_bufbase);
31068c2ecf20Sopenharmony_ci	if (dd->piobcnt4k) {
31078c2ecf20Sopenharmony_ci		dd->pio4kbase = (u32 __iomem *)
31088c2ecf20Sopenharmony_ci			(((char __iomem *) dd->kregbase) +
31098c2ecf20Sopenharmony_ci			 (dd->piobufbase >> 32));
31108c2ecf20Sopenharmony_ci		/*
31118c2ecf20Sopenharmony_ci		 * 4K buffers take 2 pages; we use roundup just to be
31128c2ecf20Sopenharmony_ci		 * paranoid; we calculate it once here, rather than on
31138c2ecf20Sopenharmony_ci		 * ever buf allocate
31148c2ecf20Sopenharmony_ci		 */
31158c2ecf20Sopenharmony_ci		dd->align4k = ALIGN(dd->piosize4k, dd->palign);
31168c2ecf20Sopenharmony_ci	}
31178c2ecf20Sopenharmony_ci
31188c2ecf20Sopenharmony_ci	piobufs = dd->piobcnt4k + dd->piobcnt2k;
31198c2ecf20Sopenharmony_ci
31208c2ecf20Sopenharmony_ci	dd->pioavregs = ALIGN(piobufs, sizeof(u64) * BITS_PER_BYTE / 2) /
31218c2ecf20Sopenharmony_ci		(sizeof(u64) * BITS_PER_BYTE / 2);
31228c2ecf20Sopenharmony_ci}
31238c2ecf20Sopenharmony_ci
31248c2ecf20Sopenharmony_ci/*
31258c2ecf20Sopenharmony_ci * The chip base addresses in cspec and cpspec have to be set
31268c2ecf20Sopenharmony_ci * after possible init_chip_wc_pat(), rather than in
31278c2ecf20Sopenharmony_ci * get_6120_chip_params(), so split out as separate function
31288c2ecf20Sopenharmony_ci */
31298c2ecf20Sopenharmony_cistatic void set_6120_baseaddrs(struct qib_devdata *dd)
31308c2ecf20Sopenharmony_ci{
31318c2ecf20Sopenharmony_ci	u32 cregbase;
31328c2ecf20Sopenharmony_ci
31338c2ecf20Sopenharmony_ci	cregbase = qib_read_kreg32(dd, kr_counterregbase);
31348c2ecf20Sopenharmony_ci	dd->cspec->cregbase = (u64 __iomem *)
31358c2ecf20Sopenharmony_ci		((char __iomem *) dd->kregbase + cregbase);
31368c2ecf20Sopenharmony_ci
31378c2ecf20Sopenharmony_ci	dd->egrtidbase = (u64 __iomem *)
31388c2ecf20Sopenharmony_ci		((char __iomem *) dd->kregbase + dd->rcvegrbase);
31398c2ecf20Sopenharmony_ci}
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci/*
31428c2ecf20Sopenharmony_ci * Write the final few registers that depend on some of the
31438c2ecf20Sopenharmony_ci * init setup.  Done late in init, just before bringing up
31448c2ecf20Sopenharmony_ci * the serdes.
31458c2ecf20Sopenharmony_ci */
31468c2ecf20Sopenharmony_cistatic int qib_late_6120_initreg(struct qib_devdata *dd)
31478c2ecf20Sopenharmony_ci{
31488c2ecf20Sopenharmony_ci	int ret = 0;
31498c2ecf20Sopenharmony_ci	u64 val;
31508c2ecf20Sopenharmony_ci
31518c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_rcvhdrentsize, dd->rcvhdrentsize);
31528c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_rcvhdrsize, dd->rcvhdrsize);
31538c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_rcvhdrcnt, dd->rcvhdrcnt);
31548c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_sendpioavailaddr, dd->pioavailregs_phys);
31558c2ecf20Sopenharmony_ci	val = qib_read_kreg64(dd, kr_sendpioavailaddr);
31568c2ecf20Sopenharmony_ci	if (val != dd->pioavailregs_phys) {
31578c2ecf20Sopenharmony_ci		qib_dev_err(dd,
31588c2ecf20Sopenharmony_ci			"Catastrophic software error, SendPIOAvailAddr written as %lx, read back as %llx\n",
31598c2ecf20Sopenharmony_ci			(unsigned long) dd->pioavailregs_phys,
31608c2ecf20Sopenharmony_ci			(unsigned long long) val);
31618c2ecf20Sopenharmony_ci		ret = -EINVAL;
31628c2ecf20Sopenharmony_ci	}
31638c2ecf20Sopenharmony_ci	return ret;
31648c2ecf20Sopenharmony_ci}
31658c2ecf20Sopenharmony_ci
31668c2ecf20Sopenharmony_cistatic int init_6120_variables(struct qib_devdata *dd)
31678c2ecf20Sopenharmony_ci{
31688c2ecf20Sopenharmony_ci	int ret = 0;
31698c2ecf20Sopenharmony_ci	struct qib_pportdata *ppd;
31708c2ecf20Sopenharmony_ci	u32 sbufs;
31718c2ecf20Sopenharmony_ci
31728c2ecf20Sopenharmony_ci	ppd = (struct qib_pportdata *)(dd + 1);
31738c2ecf20Sopenharmony_ci	dd->pport = ppd;
31748c2ecf20Sopenharmony_ci	dd->num_pports = 1;
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	dd->cspec = (struct qib_chip_specific *)(ppd + dd->num_pports);
31778c2ecf20Sopenharmony_ci	dd->cspec->ppd = ppd;
31788c2ecf20Sopenharmony_ci	ppd->cpspec = NULL; /* not used in this chip */
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci	spin_lock_init(&dd->cspec->kernel_tid_lock);
31818c2ecf20Sopenharmony_ci	spin_lock_init(&dd->cspec->user_tid_lock);
31828c2ecf20Sopenharmony_ci	spin_lock_init(&dd->cspec->rcvmod_lock);
31838c2ecf20Sopenharmony_ci	spin_lock_init(&dd->cspec->gpio_lock);
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_ci	/* we haven't yet set QIB_PRESENT, so use read directly */
31868c2ecf20Sopenharmony_ci	dd->revision = readq(&dd->kregbase[kr_revision]);
31878c2ecf20Sopenharmony_ci
31888c2ecf20Sopenharmony_ci	if ((dd->revision & 0xffffffffU) == 0xffffffffU) {
31898c2ecf20Sopenharmony_ci		qib_dev_err(dd,
31908c2ecf20Sopenharmony_ci			"Revision register read failure, giving up initialization\n");
31918c2ecf20Sopenharmony_ci		ret = -ENODEV;
31928c2ecf20Sopenharmony_ci		goto bail;
31938c2ecf20Sopenharmony_ci	}
31948c2ecf20Sopenharmony_ci	dd->flags |= QIB_PRESENT;  /* now register routines work */
31958c2ecf20Sopenharmony_ci
31968c2ecf20Sopenharmony_ci	dd->majrev = (u8) SYM_FIELD(dd->revision, Revision_R,
31978c2ecf20Sopenharmony_ci				    ChipRevMajor);
31988c2ecf20Sopenharmony_ci	dd->minrev = (u8) SYM_FIELD(dd->revision, Revision_R,
31998c2ecf20Sopenharmony_ci				    ChipRevMinor);
32008c2ecf20Sopenharmony_ci
32018c2ecf20Sopenharmony_ci	get_6120_chip_params(dd);
32028c2ecf20Sopenharmony_ci	pe_boardname(dd); /* fill in boardname */
32038c2ecf20Sopenharmony_ci
32048c2ecf20Sopenharmony_ci	/*
32058c2ecf20Sopenharmony_ci	 * GPIO bits for TWSI data and clock,
32068c2ecf20Sopenharmony_ci	 * used for serial EEPROM.
32078c2ecf20Sopenharmony_ci	 */
32088c2ecf20Sopenharmony_ci	dd->gpio_sda_num = _QIB_GPIO_SDA_NUM;
32098c2ecf20Sopenharmony_ci	dd->gpio_scl_num = _QIB_GPIO_SCL_NUM;
32108c2ecf20Sopenharmony_ci	dd->twsi_eeprom_dev = QIB_TWSI_NO_DEV;
32118c2ecf20Sopenharmony_ci
32128c2ecf20Sopenharmony_ci	if (qib_unordered_wc())
32138c2ecf20Sopenharmony_ci		dd->flags |= QIB_PIO_FLUSH_WC;
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci	ret = qib_init_pportdata(ppd, dd, 0, 1);
32168c2ecf20Sopenharmony_ci	if (ret)
32178c2ecf20Sopenharmony_ci		goto bail;
32188c2ecf20Sopenharmony_ci	ppd->link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
32198c2ecf20Sopenharmony_ci	ppd->link_speed_supported = QIB_IB_SDR;
32208c2ecf20Sopenharmony_ci	ppd->link_width_enabled = IB_WIDTH_4X;
32218c2ecf20Sopenharmony_ci	ppd->link_speed_enabled = ppd->link_speed_supported;
32228c2ecf20Sopenharmony_ci	/* these can't change for this chip, so set once */
32238c2ecf20Sopenharmony_ci	ppd->link_width_active = ppd->link_width_enabled;
32248c2ecf20Sopenharmony_ci	ppd->link_speed_active = ppd->link_speed_enabled;
32258c2ecf20Sopenharmony_ci	ppd->vls_supported = IB_VL_VL0;
32268c2ecf20Sopenharmony_ci	ppd->vls_operational = ppd->vls_supported;
32278c2ecf20Sopenharmony_ci
32288c2ecf20Sopenharmony_ci	dd->rcvhdrentsize = QIB_RCVHDR_ENTSIZE;
32298c2ecf20Sopenharmony_ci	dd->rcvhdrsize = QIB_DFLT_RCVHDRSIZE;
32308c2ecf20Sopenharmony_ci	dd->rhf_offset = 0;
32318c2ecf20Sopenharmony_ci
32328c2ecf20Sopenharmony_ci	/* we always allocate at least 2048 bytes for eager buffers */
32338c2ecf20Sopenharmony_ci	ret = ib_mtu_enum_to_int(qib_ibmtu);
32348c2ecf20Sopenharmony_ci	dd->rcvegrbufsize = ret != -1 ? max(ret, 2048) : QIB_DEFAULT_MTU;
32358c2ecf20Sopenharmony_ci	dd->rcvegrbufsize_shift = ilog2(dd->rcvegrbufsize);
32368c2ecf20Sopenharmony_ci
32378c2ecf20Sopenharmony_ci	qib_6120_tidtemplate(dd);
32388c2ecf20Sopenharmony_ci
32398c2ecf20Sopenharmony_ci	/*
32408c2ecf20Sopenharmony_ci	 * We can request a receive interrupt for 1 or
32418c2ecf20Sopenharmony_ci	 * more packets from current offset.  For now, we set this
32428c2ecf20Sopenharmony_ci	 * up for a single packet.
32438c2ecf20Sopenharmony_ci	 */
32448c2ecf20Sopenharmony_ci	dd->rhdrhead_intr_off = 1ULL << 32;
32458c2ecf20Sopenharmony_ci
32468c2ecf20Sopenharmony_ci	/* setup the stats timer; the add_timer is done at end of init */
32478c2ecf20Sopenharmony_ci	timer_setup(&dd->stats_timer, qib_get_6120_faststats, 0);
32488c2ecf20Sopenharmony_ci	timer_setup(&dd->cspec->pma_timer, pma_6120_timer, 0);
32498c2ecf20Sopenharmony_ci
32508c2ecf20Sopenharmony_ci	dd->ureg_align = qib_read_kreg32(dd, kr_palign);
32518c2ecf20Sopenharmony_ci
32528c2ecf20Sopenharmony_ci	dd->piosize2kmax_dwords = dd->piosize2k >> 2;
32538c2ecf20Sopenharmony_ci	qib_6120_config_ctxts(dd);
32548c2ecf20Sopenharmony_ci	qib_set_ctxtcnt(dd);
32558c2ecf20Sopenharmony_ci
32568c2ecf20Sopenharmony_ci	ret = init_chip_wc_pat(dd, 0);
32578c2ecf20Sopenharmony_ci	if (ret)
32588c2ecf20Sopenharmony_ci		goto bail;
32598c2ecf20Sopenharmony_ci	set_6120_baseaddrs(dd); /* set chip access pointers now */
32608c2ecf20Sopenharmony_ci
32618c2ecf20Sopenharmony_ci	ret = 0;
32628c2ecf20Sopenharmony_ci	if (qib_mini_init)
32638c2ecf20Sopenharmony_ci		goto bail;
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_ci	qib_num_cfg_vls = 1; /* if any 6120's, only one VL */
32668c2ecf20Sopenharmony_ci
32678c2ecf20Sopenharmony_ci	ret = qib_create_ctxts(dd);
32688c2ecf20Sopenharmony_ci	init_6120_cntrnames(dd);
32698c2ecf20Sopenharmony_ci
32708c2ecf20Sopenharmony_ci	/* use all of 4KB buffers for the kernel, otherwise 16 */
32718c2ecf20Sopenharmony_ci	sbufs = dd->piobcnt4k ?  dd->piobcnt4k : 16;
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	dd->lastctxt_piobuf = dd->piobcnt2k + dd->piobcnt4k - sbufs;
32748c2ecf20Sopenharmony_ci	dd->pbufsctxt = dd->lastctxt_piobuf /
32758c2ecf20Sopenharmony_ci		(dd->cfgctxts - dd->first_user_ctxt);
32768c2ecf20Sopenharmony_ci
32778c2ecf20Sopenharmony_ci	if (ret)
32788c2ecf20Sopenharmony_ci		goto bail;
32798c2ecf20Sopenharmony_cibail:
32808c2ecf20Sopenharmony_ci	return ret;
32818c2ecf20Sopenharmony_ci}
32828c2ecf20Sopenharmony_ci
32838c2ecf20Sopenharmony_ci/*
32848c2ecf20Sopenharmony_ci * For this chip, we want to use the same buffer every time
32858c2ecf20Sopenharmony_ci * when we are trying to bring the link up (they are always VL15
32868c2ecf20Sopenharmony_ci * packets).  At that link state the packet should always go out immediately
32878c2ecf20Sopenharmony_ci * (or at least be discarded at the tx interface if the link is down).
32888c2ecf20Sopenharmony_ci * If it doesn't, and the buffer isn't available, that means some other
32898c2ecf20Sopenharmony_ci * sender has gotten ahead of us, and is preventing our packet from going
32908c2ecf20Sopenharmony_ci * out.  In that case, we flush all packets, and try again.  If that still
32918c2ecf20Sopenharmony_ci * fails, we fail the request, and hope things work the next time around.
32928c2ecf20Sopenharmony_ci *
32938c2ecf20Sopenharmony_ci * We don't need very complicated heuristics on whether the packet had
32948c2ecf20Sopenharmony_ci * time to go out or not, since even at SDR 1X, it goes out in very short
32958c2ecf20Sopenharmony_ci * time periods, covered by the chip reads done here and as part of the
32968c2ecf20Sopenharmony_ci * flush.
32978c2ecf20Sopenharmony_ci */
32988c2ecf20Sopenharmony_cistatic u32 __iomem *get_6120_link_buf(struct qib_pportdata *ppd, u32 *bnum)
32998c2ecf20Sopenharmony_ci{
33008c2ecf20Sopenharmony_ci	u32 __iomem *buf;
33018c2ecf20Sopenharmony_ci	u32 lbuf = ppd->dd->piobcnt2k + ppd->dd->piobcnt4k - 1;
33028c2ecf20Sopenharmony_ci
33038c2ecf20Sopenharmony_ci	/*
33048c2ecf20Sopenharmony_ci	 * always blip to get avail list updated, since it's almost
33058c2ecf20Sopenharmony_ci	 * always needed, and is fairly cheap.
33068c2ecf20Sopenharmony_ci	 */
33078c2ecf20Sopenharmony_ci	sendctrl_6120_mod(ppd->dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
33088c2ecf20Sopenharmony_ci	qib_read_kreg64(ppd->dd, kr_scratch); /* extra chip flush */
33098c2ecf20Sopenharmony_ci	buf = qib_getsendbuf_range(ppd->dd, bnum, lbuf, lbuf);
33108c2ecf20Sopenharmony_ci	if (buf)
33118c2ecf20Sopenharmony_ci		goto done;
33128c2ecf20Sopenharmony_ci
33138c2ecf20Sopenharmony_ci	sendctrl_6120_mod(ppd, QIB_SENDCTRL_DISARM_ALL | QIB_SENDCTRL_FLUSH |
33148c2ecf20Sopenharmony_ci			  QIB_SENDCTRL_AVAIL_BLIP);
33158c2ecf20Sopenharmony_ci	ppd->dd->upd_pio_shadow  = 1; /* update our idea of what's busy */
33168c2ecf20Sopenharmony_ci	qib_read_kreg64(ppd->dd, kr_scratch); /* extra chip flush */
33178c2ecf20Sopenharmony_ci	buf = qib_getsendbuf_range(ppd->dd, bnum, lbuf, lbuf);
33188c2ecf20Sopenharmony_cidone:
33198c2ecf20Sopenharmony_ci	return buf;
33208c2ecf20Sopenharmony_ci}
33218c2ecf20Sopenharmony_ci
33228c2ecf20Sopenharmony_cistatic u32 __iomem *qib_6120_getsendbuf(struct qib_pportdata *ppd, u64 pbc,
33238c2ecf20Sopenharmony_ci					u32 *pbufnum)
33248c2ecf20Sopenharmony_ci{
33258c2ecf20Sopenharmony_ci	u32 first, last, plen = pbc & QIB_PBC_LENGTH_MASK;
33268c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
33278c2ecf20Sopenharmony_ci	u32 __iomem *buf;
33288c2ecf20Sopenharmony_ci
33298c2ecf20Sopenharmony_ci	if (((pbc >> 32) & PBC_6120_VL15_SEND_CTRL) &&
33308c2ecf20Sopenharmony_ci		!(ppd->lflags & (QIBL_IB_AUTONEG_INPROG | QIBL_LINKACTIVE)))
33318c2ecf20Sopenharmony_ci		buf = get_6120_link_buf(ppd, pbufnum);
33328c2ecf20Sopenharmony_ci	else {
33338c2ecf20Sopenharmony_ci
33348c2ecf20Sopenharmony_ci		if ((plen + 1) > dd->piosize2kmax_dwords)
33358c2ecf20Sopenharmony_ci			first = dd->piobcnt2k;
33368c2ecf20Sopenharmony_ci		else
33378c2ecf20Sopenharmony_ci			first = 0;
33388c2ecf20Sopenharmony_ci		/* try 4k if all 2k busy, so same last for both sizes */
33398c2ecf20Sopenharmony_ci		last = dd->piobcnt2k + dd->piobcnt4k - 1;
33408c2ecf20Sopenharmony_ci		buf = qib_getsendbuf_range(dd, pbufnum, first, last);
33418c2ecf20Sopenharmony_ci	}
33428c2ecf20Sopenharmony_ci	return buf;
33438c2ecf20Sopenharmony_ci}
33448c2ecf20Sopenharmony_ci
33458c2ecf20Sopenharmony_cistatic int init_sdma_6120_regs(struct qib_pportdata *ppd)
33468c2ecf20Sopenharmony_ci{
33478c2ecf20Sopenharmony_ci	return -ENODEV;
33488c2ecf20Sopenharmony_ci}
33498c2ecf20Sopenharmony_ci
33508c2ecf20Sopenharmony_cistatic u16 qib_sdma_6120_gethead(struct qib_pportdata *ppd)
33518c2ecf20Sopenharmony_ci{
33528c2ecf20Sopenharmony_ci	return 0;
33538c2ecf20Sopenharmony_ci}
33548c2ecf20Sopenharmony_ci
33558c2ecf20Sopenharmony_cistatic int qib_sdma_6120_busy(struct qib_pportdata *ppd)
33568c2ecf20Sopenharmony_ci{
33578c2ecf20Sopenharmony_ci	return 0;
33588c2ecf20Sopenharmony_ci}
33598c2ecf20Sopenharmony_ci
33608c2ecf20Sopenharmony_cistatic void qib_sdma_update_6120_tail(struct qib_pportdata *ppd, u16 tail)
33618c2ecf20Sopenharmony_ci{
33628c2ecf20Sopenharmony_ci}
33638c2ecf20Sopenharmony_ci
33648c2ecf20Sopenharmony_cistatic void qib_6120_sdma_sendctrl(struct qib_pportdata *ppd, unsigned op)
33658c2ecf20Sopenharmony_ci{
33668c2ecf20Sopenharmony_ci}
33678c2ecf20Sopenharmony_ci
33688c2ecf20Sopenharmony_cistatic void qib_sdma_set_6120_desc_cnt(struct qib_pportdata *ppd, unsigned cnt)
33698c2ecf20Sopenharmony_ci{
33708c2ecf20Sopenharmony_ci}
33718c2ecf20Sopenharmony_ci
33728c2ecf20Sopenharmony_ci/*
33738c2ecf20Sopenharmony_ci * the pbc doesn't need a VL15 indicator, but we need it for link_buf.
33748c2ecf20Sopenharmony_ci * The chip ignores the bit if set.
33758c2ecf20Sopenharmony_ci */
33768c2ecf20Sopenharmony_cistatic u32 qib_6120_setpbc_control(struct qib_pportdata *ppd, u32 plen,
33778c2ecf20Sopenharmony_ci				   u8 srate, u8 vl)
33788c2ecf20Sopenharmony_ci{
33798c2ecf20Sopenharmony_ci	return vl == 15 ? PBC_6120_VL15_SEND_CTRL : 0;
33808c2ecf20Sopenharmony_ci}
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_cistatic void qib_6120_initvl15_bufs(struct qib_devdata *dd)
33838c2ecf20Sopenharmony_ci{
33848c2ecf20Sopenharmony_ci}
33858c2ecf20Sopenharmony_ci
33868c2ecf20Sopenharmony_cistatic void qib_6120_init_ctxt(struct qib_ctxtdata *rcd)
33878c2ecf20Sopenharmony_ci{
33888c2ecf20Sopenharmony_ci	rcd->rcvegrcnt = rcd->dd->rcvhdrcnt;
33898c2ecf20Sopenharmony_ci	rcd->rcvegr_tid_base = rcd->ctxt * rcd->rcvegrcnt;
33908c2ecf20Sopenharmony_ci}
33918c2ecf20Sopenharmony_ci
33928c2ecf20Sopenharmony_cistatic void qib_6120_txchk_change(struct qib_devdata *dd, u32 start,
33938c2ecf20Sopenharmony_ci	u32 len, u32 avail, struct qib_ctxtdata *rcd)
33948c2ecf20Sopenharmony_ci{
33958c2ecf20Sopenharmony_ci}
33968c2ecf20Sopenharmony_ci
33978c2ecf20Sopenharmony_cistatic void writescratch(struct qib_devdata *dd, u32 val)
33988c2ecf20Sopenharmony_ci{
33998c2ecf20Sopenharmony_ci	(void) qib_write_kreg(dd, kr_scratch, val);
34008c2ecf20Sopenharmony_ci}
34018c2ecf20Sopenharmony_ci
34028c2ecf20Sopenharmony_cistatic int qib_6120_tempsense_rd(struct qib_devdata *dd, int regnum)
34038c2ecf20Sopenharmony_ci{
34048c2ecf20Sopenharmony_ci	return -ENXIO;
34058c2ecf20Sopenharmony_ci}
34068c2ecf20Sopenharmony_ci
34078c2ecf20Sopenharmony_ci#ifdef CONFIG_INFINIBAND_QIB_DCA
34088c2ecf20Sopenharmony_cistatic int qib_6120_notify_dca(struct qib_devdata *dd, unsigned long event)
34098c2ecf20Sopenharmony_ci{
34108c2ecf20Sopenharmony_ci	return 0;
34118c2ecf20Sopenharmony_ci}
34128c2ecf20Sopenharmony_ci#endif
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_ci/* Dummy function, as 6120 boards never disable EEPROM Write */
34158c2ecf20Sopenharmony_cistatic int qib_6120_eeprom_wen(struct qib_devdata *dd, int wen)
34168c2ecf20Sopenharmony_ci{
34178c2ecf20Sopenharmony_ci	return 1;
34188c2ecf20Sopenharmony_ci}
34198c2ecf20Sopenharmony_ci
34208c2ecf20Sopenharmony_ci/**
34218c2ecf20Sopenharmony_ci * qib_init_iba6120_funcs - set up the chip-specific function pointers
34228c2ecf20Sopenharmony_ci * @pdev: pci_dev of the qlogic_ib device
34238c2ecf20Sopenharmony_ci * @ent: pci_device_id matching this chip
34248c2ecf20Sopenharmony_ci *
34258c2ecf20Sopenharmony_ci * This is global, and is called directly at init to set up the
34268c2ecf20Sopenharmony_ci * chip-specific function pointers for later use.
34278c2ecf20Sopenharmony_ci *
34288c2ecf20Sopenharmony_ci * It also allocates/partially-inits the qib_devdata struct for
34298c2ecf20Sopenharmony_ci * this device.
34308c2ecf20Sopenharmony_ci */
34318c2ecf20Sopenharmony_cistruct qib_devdata *qib_init_iba6120_funcs(struct pci_dev *pdev,
34328c2ecf20Sopenharmony_ci					   const struct pci_device_id *ent)
34338c2ecf20Sopenharmony_ci{
34348c2ecf20Sopenharmony_ci	struct qib_devdata *dd;
34358c2ecf20Sopenharmony_ci	int ret;
34368c2ecf20Sopenharmony_ci
34378c2ecf20Sopenharmony_ci	dd = qib_alloc_devdata(pdev, sizeof(struct qib_pportdata) +
34388c2ecf20Sopenharmony_ci			       sizeof(struct qib_chip_specific));
34398c2ecf20Sopenharmony_ci	if (IS_ERR(dd))
34408c2ecf20Sopenharmony_ci		goto bail;
34418c2ecf20Sopenharmony_ci
34428c2ecf20Sopenharmony_ci	dd->f_bringup_serdes    = qib_6120_bringup_serdes;
34438c2ecf20Sopenharmony_ci	dd->f_cleanup           = qib_6120_setup_cleanup;
34448c2ecf20Sopenharmony_ci	dd->f_clear_tids        = qib_6120_clear_tids;
34458c2ecf20Sopenharmony_ci	dd->f_free_irq          = qib_free_irq;
34468c2ecf20Sopenharmony_ci	dd->f_get_base_info     = qib_6120_get_base_info;
34478c2ecf20Sopenharmony_ci	dd->f_get_msgheader     = qib_6120_get_msgheader;
34488c2ecf20Sopenharmony_ci	dd->f_getsendbuf        = qib_6120_getsendbuf;
34498c2ecf20Sopenharmony_ci	dd->f_gpio_mod          = gpio_6120_mod;
34508c2ecf20Sopenharmony_ci	dd->f_eeprom_wen	= qib_6120_eeprom_wen;
34518c2ecf20Sopenharmony_ci	dd->f_hdrqempty         = qib_6120_hdrqempty;
34528c2ecf20Sopenharmony_ci	dd->f_ib_updown         = qib_6120_ib_updown;
34538c2ecf20Sopenharmony_ci	dd->f_init_ctxt         = qib_6120_init_ctxt;
34548c2ecf20Sopenharmony_ci	dd->f_initvl15_bufs     = qib_6120_initvl15_bufs;
34558c2ecf20Sopenharmony_ci	dd->f_intr_fallback     = qib_6120_nointr_fallback;
34568c2ecf20Sopenharmony_ci	dd->f_late_initreg      = qib_late_6120_initreg;
34578c2ecf20Sopenharmony_ci	dd->f_setpbc_control    = qib_6120_setpbc_control;
34588c2ecf20Sopenharmony_ci	dd->f_portcntr          = qib_portcntr_6120;
34598c2ecf20Sopenharmony_ci	dd->f_put_tid           = (dd->minrev >= 2) ?
34608c2ecf20Sopenharmony_ci				      qib_6120_put_tid_2 :
34618c2ecf20Sopenharmony_ci				      qib_6120_put_tid;
34628c2ecf20Sopenharmony_ci	dd->f_quiet_serdes      = qib_6120_quiet_serdes;
34638c2ecf20Sopenharmony_ci	dd->f_rcvctrl           = rcvctrl_6120_mod;
34648c2ecf20Sopenharmony_ci	dd->f_read_cntrs        = qib_read_6120cntrs;
34658c2ecf20Sopenharmony_ci	dd->f_read_portcntrs    = qib_read_6120portcntrs;
34668c2ecf20Sopenharmony_ci	dd->f_reset             = qib_6120_setup_reset;
34678c2ecf20Sopenharmony_ci	dd->f_init_sdma_regs    = init_sdma_6120_regs;
34688c2ecf20Sopenharmony_ci	dd->f_sdma_busy         = qib_sdma_6120_busy;
34698c2ecf20Sopenharmony_ci	dd->f_sdma_gethead      = qib_sdma_6120_gethead;
34708c2ecf20Sopenharmony_ci	dd->f_sdma_sendctrl     = qib_6120_sdma_sendctrl;
34718c2ecf20Sopenharmony_ci	dd->f_sdma_set_desc_cnt = qib_sdma_set_6120_desc_cnt;
34728c2ecf20Sopenharmony_ci	dd->f_sdma_update_tail  = qib_sdma_update_6120_tail;
34738c2ecf20Sopenharmony_ci	dd->f_sendctrl          = sendctrl_6120_mod;
34748c2ecf20Sopenharmony_ci	dd->f_set_armlaunch     = qib_set_6120_armlaunch;
34758c2ecf20Sopenharmony_ci	dd->f_set_cntr_sample   = qib_set_cntr_6120_sample;
34768c2ecf20Sopenharmony_ci	dd->f_iblink_state      = qib_6120_iblink_state;
34778c2ecf20Sopenharmony_ci	dd->f_ibphys_portstate  = qib_6120_phys_portstate;
34788c2ecf20Sopenharmony_ci	dd->f_get_ib_cfg        = qib_6120_get_ib_cfg;
34798c2ecf20Sopenharmony_ci	dd->f_set_ib_cfg        = qib_6120_set_ib_cfg;
34808c2ecf20Sopenharmony_ci	dd->f_set_ib_loopback   = qib_6120_set_loopback;
34818c2ecf20Sopenharmony_ci	dd->f_set_intr_state    = qib_6120_set_intr_state;
34828c2ecf20Sopenharmony_ci	dd->f_setextled         = qib_6120_setup_setextled;
34838c2ecf20Sopenharmony_ci	dd->f_txchk_change      = qib_6120_txchk_change;
34848c2ecf20Sopenharmony_ci	dd->f_update_usrhead    = qib_update_6120_usrhead;
34858c2ecf20Sopenharmony_ci	dd->f_wantpiobuf_intr   = qib_wantpiobuf_6120_intr;
34868c2ecf20Sopenharmony_ci	dd->f_xgxs_reset        = qib_6120_xgxs_reset;
34878c2ecf20Sopenharmony_ci	dd->f_writescratch      = writescratch;
34888c2ecf20Sopenharmony_ci	dd->f_tempsense_rd	= qib_6120_tempsense_rd;
34898c2ecf20Sopenharmony_ci#ifdef CONFIG_INFINIBAND_QIB_DCA
34908c2ecf20Sopenharmony_ci	dd->f_notify_dca = qib_6120_notify_dca;
34918c2ecf20Sopenharmony_ci#endif
34928c2ecf20Sopenharmony_ci	/*
34938c2ecf20Sopenharmony_ci	 * Do remaining pcie setup and save pcie values in dd.
34948c2ecf20Sopenharmony_ci	 * Any error printing is already done by the init code.
34958c2ecf20Sopenharmony_ci	 * On return, we have the chip mapped and accessible,
34968c2ecf20Sopenharmony_ci	 * but chip registers are not set up until start of
34978c2ecf20Sopenharmony_ci	 * init_6120_variables.
34988c2ecf20Sopenharmony_ci	 */
34998c2ecf20Sopenharmony_ci	ret = qib_pcie_ddinit(dd, pdev, ent);
35008c2ecf20Sopenharmony_ci	if (ret < 0)
35018c2ecf20Sopenharmony_ci		goto bail_free;
35028c2ecf20Sopenharmony_ci
35038c2ecf20Sopenharmony_ci	/* initialize chip-specific variables */
35048c2ecf20Sopenharmony_ci	ret = init_6120_variables(dd);
35058c2ecf20Sopenharmony_ci	if (ret)
35068c2ecf20Sopenharmony_ci		goto bail_cleanup;
35078c2ecf20Sopenharmony_ci
35088c2ecf20Sopenharmony_ci	if (qib_mini_init)
35098c2ecf20Sopenharmony_ci		goto bail;
35108c2ecf20Sopenharmony_ci
35118c2ecf20Sopenharmony_ci	if (qib_pcie_params(dd, 8, NULL))
35128c2ecf20Sopenharmony_ci		qib_dev_err(dd,
35138c2ecf20Sopenharmony_ci			"Failed to setup PCIe or interrupts; continuing anyway\n");
35148c2ecf20Sopenharmony_ci	/* clear diagctrl register, in case diags were running and crashed */
35158c2ecf20Sopenharmony_ci	qib_write_kreg(dd, kr_hwdiagctrl, 0);
35168c2ecf20Sopenharmony_ci
35178c2ecf20Sopenharmony_ci	if (qib_read_kreg64(dd, kr_hwerrstatus) &
35188c2ecf20Sopenharmony_ci	    QLOGIC_IB_HWE_SERDESPLLFAILED)
35198c2ecf20Sopenharmony_ci		qib_write_kreg(dd, kr_hwerrclear,
35208c2ecf20Sopenharmony_ci			       QLOGIC_IB_HWE_SERDESPLLFAILED);
35218c2ecf20Sopenharmony_ci
35228c2ecf20Sopenharmony_ci	/* setup interrupt handler (interrupt type handled above) */
35238c2ecf20Sopenharmony_ci	qib_setup_6120_interrupt(dd);
35248c2ecf20Sopenharmony_ci	/* Note that qpn_mask is set by qib_6120_config_ctxts() first */
35258c2ecf20Sopenharmony_ci	qib_6120_init_hwerrors(dd);
35268c2ecf20Sopenharmony_ci
35278c2ecf20Sopenharmony_ci	goto bail;
35288c2ecf20Sopenharmony_ci
35298c2ecf20Sopenharmony_cibail_cleanup:
35308c2ecf20Sopenharmony_ci	qib_pcie_ddcleanup(dd);
35318c2ecf20Sopenharmony_cibail_free:
35328c2ecf20Sopenharmony_ci	qib_free_devdata(dd);
35338c2ecf20Sopenharmony_ci	dd = ERR_PTR(ret);
35348c2ecf20Sopenharmony_cibail:
35358c2ecf20Sopenharmony_ci	return dd;
35368c2ecf20Sopenharmony_ci}
3537