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