18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci#include <linux/slab.h> 338c2ecf20Sopenharmony_ci#include <linux/mman.h> 348c2ecf20Sopenharmony_ci#include <net/sock.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include "iw_cxgb4.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic void print_tpte(struct c4iw_dev *dev, u32 stag) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci int ret; 418c2ecf20Sopenharmony_ci struct fw_ri_tpte tpte; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci ret = cxgb4_read_tpte(dev->rdev.lldi.ports[0], stag, 448c2ecf20Sopenharmony_ci (__be32 *)&tpte); 458c2ecf20Sopenharmony_ci if (ret) { 468c2ecf20Sopenharmony_ci dev_err(&dev->rdev.lldi.pdev->dev, 478c2ecf20Sopenharmony_ci "%s cxgb4_read_tpte err %d\n", __func__, ret); 488c2ecf20Sopenharmony_ci return; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci pr_debug("stag idx 0x%x valid %d key 0x%x state %d pdid %d perm 0x%x ps %d len 0x%llx va 0x%llx\n", 518c2ecf20Sopenharmony_ci stag & 0xffffff00, 528c2ecf20Sopenharmony_ci FW_RI_TPTE_VALID_G(ntohl(tpte.valid_to_pdid)), 538c2ecf20Sopenharmony_ci FW_RI_TPTE_STAGKEY_G(ntohl(tpte.valid_to_pdid)), 548c2ecf20Sopenharmony_ci FW_RI_TPTE_STAGSTATE_G(ntohl(tpte.valid_to_pdid)), 558c2ecf20Sopenharmony_ci FW_RI_TPTE_PDID_G(ntohl(tpte.valid_to_pdid)), 568c2ecf20Sopenharmony_ci FW_RI_TPTE_PERM_G(ntohl(tpte.locread_to_qpid)), 578c2ecf20Sopenharmony_ci FW_RI_TPTE_PS_G(ntohl(tpte.locread_to_qpid)), 588c2ecf20Sopenharmony_ci ((u64)ntohl(tpte.len_hi) << 32) | ntohl(tpte.len_lo), 598c2ecf20Sopenharmony_ci ((u64)ntohl(tpte.va_hi) << 32) | ntohl(tpte.va_lo_fbo)); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void dump_err_cqe(struct c4iw_dev *dev, struct t4_cqe *err_cqe) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci __be64 *p = (void *)err_cqe; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci dev_err(&dev->rdev.lldi.pdev->dev, 678c2ecf20Sopenharmony_ci "AE qpid %d opcode %d status 0x%x " 688c2ecf20Sopenharmony_ci "type %d len 0x%x wrid.hi 0x%x wrid.lo 0x%x\n", 698c2ecf20Sopenharmony_ci CQE_QPID(err_cqe), CQE_OPCODE(err_cqe), 708c2ecf20Sopenharmony_ci CQE_STATUS(err_cqe), CQE_TYPE(err_cqe), ntohl(err_cqe->len), 718c2ecf20Sopenharmony_ci CQE_WRID_HI(err_cqe), CQE_WRID_LOW(err_cqe)); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci pr_debug("%016llx %016llx %016llx %016llx - %016llx %016llx %016llx %016llx\n", 748c2ecf20Sopenharmony_ci be64_to_cpu(p[0]), be64_to_cpu(p[1]), be64_to_cpu(p[2]), 758c2ecf20Sopenharmony_ci be64_to_cpu(p[3]), be64_to_cpu(p[4]), be64_to_cpu(p[5]), 768c2ecf20Sopenharmony_ci be64_to_cpu(p[6]), be64_to_cpu(p[7])); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* 798c2ecf20Sopenharmony_ci * Ingress WRITE and READ_RESP errors provide 808c2ecf20Sopenharmony_ci * the offending stag, so parse and log it. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci if (RQ_TYPE(err_cqe) && (CQE_OPCODE(err_cqe) == FW_RI_RDMA_WRITE || 838c2ecf20Sopenharmony_ci CQE_OPCODE(err_cqe) == FW_RI_READ_RESP)) 848c2ecf20Sopenharmony_ci print_tpte(dev, CQE_WRID_STAG(err_cqe)); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp, 888c2ecf20Sopenharmony_ci struct c4iw_qp *qhp, 898c2ecf20Sopenharmony_ci struct t4_cqe *err_cqe, 908c2ecf20Sopenharmony_ci enum ib_event_type ib_event) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct ib_event event; 938c2ecf20Sopenharmony_ci struct c4iw_qp_attributes attrs; 948c2ecf20Sopenharmony_ci unsigned long flag; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci dump_err_cqe(dev, err_cqe); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (qhp->attr.state == C4IW_QP_STATE_RTS) { 998c2ecf20Sopenharmony_ci attrs.next_state = C4IW_QP_STATE_TERMINATE; 1008c2ecf20Sopenharmony_ci c4iw_modify_qp(qhp->rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, 1018c2ecf20Sopenharmony_ci &attrs, 0); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci event.event = ib_event; 1058c2ecf20Sopenharmony_ci event.device = chp->ibcq.device; 1068c2ecf20Sopenharmony_ci if (ib_event == IB_EVENT_CQ_ERR) 1078c2ecf20Sopenharmony_ci event.element.cq = &chp->ibcq; 1088c2ecf20Sopenharmony_ci else 1098c2ecf20Sopenharmony_ci event.element.qp = &qhp->ibqp; 1108c2ecf20Sopenharmony_ci if (qhp->ibqp.event_handler) 1118c2ecf20Sopenharmony_ci (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (t4_clear_cq_armed(&chp->cq)) { 1148c2ecf20Sopenharmony_ci spin_lock_irqsave(&chp->comp_handler_lock, flag); 1158c2ecf20Sopenharmony_ci (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context); 1168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chp->comp_handler_lock, flag); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_civoid c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct c4iw_cq *chp; 1238c2ecf20Sopenharmony_ci struct c4iw_qp *qhp; 1248c2ecf20Sopenharmony_ci u32 cqid; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci xa_lock_irq(&dev->qps); 1278c2ecf20Sopenharmony_ci qhp = xa_load(&dev->qps, CQE_QPID(err_cqe)); 1288c2ecf20Sopenharmony_ci if (!qhp) { 1298c2ecf20Sopenharmony_ci pr_err("BAD AE qpid 0x%x opcode %d status 0x%x type %d wrid.hi 0x%x wrid.lo 0x%x\n", 1308c2ecf20Sopenharmony_ci CQE_QPID(err_cqe), 1318c2ecf20Sopenharmony_ci CQE_OPCODE(err_cqe), CQE_STATUS(err_cqe), 1328c2ecf20Sopenharmony_ci CQE_TYPE(err_cqe), CQE_WRID_HI(err_cqe), 1338c2ecf20Sopenharmony_ci CQE_WRID_LOW(err_cqe)); 1348c2ecf20Sopenharmony_ci xa_unlock_irq(&dev->qps); 1358c2ecf20Sopenharmony_ci goto out; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (SQ_TYPE(err_cqe)) 1398c2ecf20Sopenharmony_ci cqid = qhp->attr.scq; 1408c2ecf20Sopenharmony_ci else 1418c2ecf20Sopenharmony_ci cqid = qhp->attr.rcq; 1428c2ecf20Sopenharmony_ci chp = get_chp(dev, cqid); 1438c2ecf20Sopenharmony_ci if (!chp) { 1448c2ecf20Sopenharmony_ci pr_err("BAD AE cqid 0x%x qpid 0x%x opcode %d status 0x%x type %d wrid.hi 0x%x wrid.lo 0x%x\n", 1458c2ecf20Sopenharmony_ci cqid, CQE_QPID(err_cqe), 1468c2ecf20Sopenharmony_ci CQE_OPCODE(err_cqe), CQE_STATUS(err_cqe), 1478c2ecf20Sopenharmony_ci CQE_TYPE(err_cqe), CQE_WRID_HI(err_cqe), 1488c2ecf20Sopenharmony_ci CQE_WRID_LOW(err_cqe)); 1498c2ecf20Sopenharmony_ci xa_unlock_irq(&dev->qps); 1508c2ecf20Sopenharmony_ci goto out; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci c4iw_qp_add_ref(&qhp->ibqp); 1548c2ecf20Sopenharmony_ci atomic_inc(&chp->refcnt); 1558c2ecf20Sopenharmony_ci xa_unlock_irq(&dev->qps); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* Bad incoming write */ 1588c2ecf20Sopenharmony_ci if (RQ_TYPE(err_cqe) && 1598c2ecf20Sopenharmony_ci (CQE_OPCODE(err_cqe) == FW_RI_RDMA_WRITE)) { 1608c2ecf20Sopenharmony_ci post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_REQ_ERR); 1618c2ecf20Sopenharmony_ci goto done; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci switch (CQE_STATUS(err_cqe)) { 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* Completion Events */ 1678c2ecf20Sopenharmony_ci case T4_ERR_SUCCESS: 1688c2ecf20Sopenharmony_ci pr_err("AE with status 0!\n"); 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci case T4_ERR_STAG: 1728c2ecf20Sopenharmony_ci case T4_ERR_PDID: 1738c2ecf20Sopenharmony_ci case T4_ERR_QPID: 1748c2ecf20Sopenharmony_ci case T4_ERR_ACCESS: 1758c2ecf20Sopenharmony_ci case T4_ERR_WRAP: 1768c2ecf20Sopenharmony_ci case T4_ERR_BOUND: 1778c2ecf20Sopenharmony_ci case T4_ERR_INVALIDATE_SHARED_MR: 1788c2ecf20Sopenharmony_ci case T4_ERR_INVALIDATE_MR_WITH_MW_BOUND: 1798c2ecf20Sopenharmony_ci post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_ACCESS_ERR); 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* Device Fatal Errors */ 1838c2ecf20Sopenharmony_ci case T4_ERR_ECC: 1848c2ecf20Sopenharmony_ci case T4_ERR_ECC_PSTAG: 1858c2ecf20Sopenharmony_ci case T4_ERR_INTERNAL_ERR: 1868c2ecf20Sopenharmony_ci post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_DEVICE_FATAL); 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* QP Fatal Errors */ 1908c2ecf20Sopenharmony_ci case T4_ERR_OUT_OF_RQE: 1918c2ecf20Sopenharmony_ci case T4_ERR_PBL_ADDR_BOUND: 1928c2ecf20Sopenharmony_ci case T4_ERR_CRC: 1938c2ecf20Sopenharmony_ci case T4_ERR_MARKER: 1948c2ecf20Sopenharmony_ci case T4_ERR_PDU_LEN_ERR: 1958c2ecf20Sopenharmony_ci case T4_ERR_DDP_VERSION: 1968c2ecf20Sopenharmony_ci case T4_ERR_RDMA_VERSION: 1978c2ecf20Sopenharmony_ci case T4_ERR_OPCODE: 1988c2ecf20Sopenharmony_ci case T4_ERR_DDP_QUEUE_NUM: 1998c2ecf20Sopenharmony_ci case T4_ERR_MSN: 2008c2ecf20Sopenharmony_ci case T4_ERR_TBIT: 2018c2ecf20Sopenharmony_ci case T4_ERR_MO: 2028c2ecf20Sopenharmony_ci case T4_ERR_MSN_GAP: 2038c2ecf20Sopenharmony_ci case T4_ERR_MSN_RANGE: 2048c2ecf20Sopenharmony_ci case T4_ERR_RQE_ADDR_BOUND: 2058c2ecf20Sopenharmony_ci case T4_ERR_IRD_OVERFLOW: 2068c2ecf20Sopenharmony_ci post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_FATAL); 2078c2ecf20Sopenharmony_ci break; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci default: 2108c2ecf20Sopenharmony_ci pr_err("Unknown T4 status 0x%x QPID 0x%x\n", 2118c2ecf20Sopenharmony_ci CQE_STATUS(err_cqe), qhp->wq.sq.qid); 2128c2ecf20Sopenharmony_ci post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_FATAL); 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_cidone: 2168c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&chp->refcnt)) 2178c2ecf20Sopenharmony_ci wake_up(&chp->wait); 2188c2ecf20Sopenharmony_ci c4iw_qp_rem_ref(&qhp->ibqp); 2198c2ecf20Sopenharmony_ciout: 2208c2ecf20Sopenharmony_ci return; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ciint c4iw_ev_handler(struct c4iw_dev *dev, u32 qid) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct c4iw_cq *chp; 2268c2ecf20Sopenharmony_ci unsigned long flag; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci xa_lock_irqsave(&dev->cqs, flag); 2298c2ecf20Sopenharmony_ci chp = xa_load(&dev->cqs, qid); 2308c2ecf20Sopenharmony_ci if (chp) { 2318c2ecf20Sopenharmony_ci atomic_inc(&chp->refcnt); 2328c2ecf20Sopenharmony_ci xa_unlock_irqrestore(&dev->cqs, flag); 2338c2ecf20Sopenharmony_ci t4_clear_cq_armed(&chp->cq); 2348c2ecf20Sopenharmony_ci spin_lock_irqsave(&chp->comp_handler_lock, flag); 2358c2ecf20Sopenharmony_ci (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context); 2368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chp->comp_handler_lock, flag); 2378c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&chp->refcnt)) 2388c2ecf20Sopenharmony_ci wake_up(&chp->wait); 2398c2ecf20Sopenharmony_ci } else { 2408c2ecf20Sopenharmony_ci pr_debug("unknown cqid 0x%x\n", qid); 2418c2ecf20Sopenharmony_ci xa_unlock_irqrestore(&dev->cqs, flag); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci} 245