18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. 48c2ecf20Sopenharmony_ci * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "rxe.h" 108c2ecf20Sopenharmony_ci#include "rxe_loc.h" 118c2ecf20Sopenharmony_ci#include "rxe_queue.h" 128c2ecf20Sopenharmony_ci#include "rxe_task.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cienum comp_state { 158c2ecf20Sopenharmony_ci COMPST_GET_ACK, 168c2ecf20Sopenharmony_ci COMPST_GET_WQE, 178c2ecf20Sopenharmony_ci COMPST_COMP_WQE, 188c2ecf20Sopenharmony_ci COMPST_COMP_ACK, 198c2ecf20Sopenharmony_ci COMPST_CHECK_PSN, 208c2ecf20Sopenharmony_ci COMPST_CHECK_ACK, 218c2ecf20Sopenharmony_ci COMPST_READ, 228c2ecf20Sopenharmony_ci COMPST_ATOMIC, 238c2ecf20Sopenharmony_ci COMPST_WRITE_SEND, 248c2ecf20Sopenharmony_ci COMPST_UPDATE_COMP, 258c2ecf20Sopenharmony_ci COMPST_ERROR_RETRY, 268c2ecf20Sopenharmony_ci COMPST_RNR_RETRY, 278c2ecf20Sopenharmony_ci COMPST_ERROR, 288c2ecf20Sopenharmony_ci COMPST_EXIT, /* We have an issue, and we want to rerun the completer */ 298c2ecf20Sopenharmony_ci COMPST_DONE, /* The completer finished successflly */ 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic char *comp_state_name[] = { 338c2ecf20Sopenharmony_ci [COMPST_GET_ACK] = "GET ACK", 348c2ecf20Sopenharmony_ci [COMPST_GET_WQE] = "GET WQE", 358c2ecf20Sopenharmony_ci [COMPST_COMP_WQE] = "COMP WQE", 368c2ecf20Sopenharmony_ci [COMPST_COMP_ACK] = "COMP ACK", 378c2ecf20Sopenharmony_ci [COMPST_CHECK_PSN] = "CHECK PSN", 388c2ecf20Sopenharmony_ci [COMPST_CHECK_ACK] = "CHECK ACK", 398c2ecf20Sopenharmony_ci [COMPST_READ] = "READ", 408c2ecf20Sopenharmony_ci [COMPST_ATOMIC] = "ATOMIC", 418c2ecf20Sopenharmony_ci [COMPST_WRITE_SEND] = "WRITE/SEND", 428c2ecf20Sopenharmony_ci [COMPST_UPDATE_COMP] = "UPDATE COMP", 438c2ecf20Sopenharmony_ci [COMPST_ERROR_RETRY] = "ERROR RETRY", 448c2ecf20Sopenharmony_ci [COMPST_RNR_RETRY] = "RNR RETRY", 458c2ecf20Sopenharmony_ci [COMPST_ERROR] = "ERROR", 468c2ecf20Sopenharmony_ci [COMPST_EXIT] = "EXIT", 478c2ecf20Sopenharmony_ci [COMPST_DONE] = "DONE", 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic unsigned long rnrnak_usec[32] = { 518c2ecf20Sopenharmony_ci [IB_RNR_TIMER_655_36] = 655360, 528c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_01] = 10, 538c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_02] = 20, 548c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_03] = 30, 558c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_04] = 40, 568c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_06] = 60, 578c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_08] = 80, 588c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_12] = 120, 598c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_16] = 160, 608c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_24] = 240, 618c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_32] = 320, 628c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_48] = 480, 638c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_64] = 640, 648c2ecf20Sopenharmony_ci [IB_RNR_TIMER_000_96] = 960, 658c2ecf20Sopenharmony_ci [IB_RNR_TIMER_001_28] = 1280, 668c2ecf20Sopenharmony_ci [IB_RNR_TIMER_001_92] = 1920, 678c2ecf20Sopenharmony_ci [IB_RNR_TIMER_002_56] = 2560, 688c2ecf20Sopenharmony_ci [IB_RNR_TIMER_003_84] = 3840, 698c2ecf20Sopenharmony_ci [IB_RNR_TIMER_005_12] = 5120, 708c2ecf20Sopenharmony_ci [IB_RNR_TIMER_007_68] = 7680, 718c2ecf20Sopenharmony_ci [IB_RNR_TIMER_010_24] = 10240, 728c2ecf20Sopenharmony_ci [IB_RNR_TIMER_015_36] = 15360, 738c2ecf20Sopenharmony_ci [IB_RNR_TIMER_020_48] = 20480, 748c2ecf20Sopenharmony_ci [IB_RNR_TIMER_030_72] = 30720, 758c2ecf20Sopenharmony_ci [IB_RNR_TIMER_040_96] = 40960, 768c2ecf20Sopenharmony_ci [IB_RNR_TIMER_061_44] = 61410, 778c2ecf20Sopenharmony_ci [IB_RNR_TIMER_081_92] = 81920, 788c2ecf20Sopenharmony_ci [IB_RNR_TIMER_122_88] = 122880, 798c2ecf20Sopenharmony_ci [IB_RNR_TIMER_163_84] = 163840, 808c2ecf20Sopenharmony_ci [IB_RNR_TIMER_245_76] = 245760, 818c2ecf20Sopenharmony_ci [IB_RNR_TIMER_327_68] = 327680, 828c2ecf20Sopenharmony_ci [IB_RNR_TIMER_491_52] = 491520, 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic inline unsigned long rnrnak_jiffies(u8 timeout) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci return max_t(unsigned long, 888c2ecf20Sopenharmony_ci usecs_to_jiffies(rnrnak_usec[timeout]), 1); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic enum ib_wc_opcode wr_to_wc_opcode(enum ib_wr_opcode opcode) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci switch (opcode) { 948c2ecf20Sopenharmony_ci case IB_WR_RDMA_WRITE: return IB_WC_RDMA_WRITE; 958c2ecf20Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: return IB_WC_RDMA_WRITE; 968c2ecf20Sopenharmony_ci case IB_WR_SEND: return IB_WC_SEND; 978c2ecf20Sopenharmony_ci case IB_WR_SEND_WITH_IMM: return IB_WC_SEND; 988c2ecf20Sopenharmony_ci case IB_WR_RDMA_READ: return IB_WC_RDMA_READ; 998c2ecf20Sopenharmony_ci case IB_WR_ATOMIC_CMP_AND_SWP: return IB_WC_COMP_SWAP; 1008c2ecf20Sopenharmony_ci case IB_WR_ATOMIC_FETCH_AND_ADD: return IB_WC_FETCH_ADD; 1018c2ecf20Sopenharmony_ci case IB_WR_LSO: return IB_WC_LSO; 1028c2ecf20Sopenharmony_ci case IB_WR_SEND_WITH_INV: return IB_WC_SEND; 1038c2ecf20Sopenharmony_ci case IB_WR_RDMA_READ_WITH_INV: return IB_WC_RDMA_READ; 1048c2ecf20Sopenharmony_ci case IB_WR_LOCAL_INV: return IB_WC_LOCAL_INV; 1058c2ecf20Sopenharmony_ci case IB_WR_REG_MR: return IB_WC_REG_MR; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci default: 1088c2ecf20Sopenharmony_ci return 0xff; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_civoid retransmit_timer(struct timer_list *t) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct rxe_qp *qp = from_timer(qp, t, retrans_timer); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (qp->valid) { 1178c2ecf20Sopenharmony_ci qp->comp.timeout = 1; 1188c2ecf20Sopenharmony_ci rxe_run_task(&qp->comp.task, 1); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_civoid rxe_comp_queue_pkt(struct rxe_qp *qp, struct sk_buff *skb) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci int must_sched; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci skb_queue_tail(&qp->resp_pkts, skb); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci must_sched = skb_queue_len(&qp->resp_pkts) > 1; 1298c2ecf20Sopenharmony_ci if (must_sched != 0) 1308c2ecf20Sopenharmony_ci rxe_counter_inc(SKB_TO_PKT(skb)->rxe, RXE_CNT_COMPLETER_SCHED); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci rxe_run_task(&qp->comp.task, must_sched); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic inline enum comp_state get_wqe(struct rxe_qp *qp, 1368c2ecf20Sopenharmony_ci struct rxe_pkt_info *pkt, 1378c2ecf20Sopenharmony_ci struct rxe_send_wqe **wqe_p) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct rxe_send_wqe *wqe; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* we come here whether or not we found a response packet to see if 1428c2ecf20Sopenharmony_ci * there are any posted WQEs 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci wqe = queue_head(qp->sq.queue); 1458c2ecf20Sopenharmony_ci *wqe_p = wqe; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* no WQE or requester has not started it yet */ 1488c2ecf20Sopenharmony_ci if (!wqe || wqe->state == wqe_state_posted) 1498c2ecf20Sopenharmony_ci return pkt ? COMPST_DONE : COMPST_EXIT; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* WQE does not require an ack */ 1528c2ecf20Sopenharmony_ci if (wqe->state == wqe_state_done) 1538c2ecf20Sopenharmony_ci return COMPST_COMP_WQE; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* WQE caused an error */ 1568c2ecf20Sopenharmony_ci if (wqe->state == wqe_state_error) 1578c2ecf20Sopenharmony_ci return COMPST_ERROR; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* we have a WQE, if we also have an ack check its PSN */ 1608c2ecf20Sopenharmony_ci return pkt ? COMPST_CHECK_PSN : COMPST_EXIT; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic inline void reset_retry_counters(struct rxe_qp *qp) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci qp->comp.retry_cnt = qp->attr.retry_cnt; 1668c2ecf20Sopenharmony_ci qp->comp.rnr_retry = qp->attr.rnr_retry; 1678c2ecf20Sopenharmony_ci qp->comp.started_retry = 0; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic inline enum comp_state check_psn(struct rxe_qp *qp, 1718c2ecf20Sopenharmony_ci struct rxe_pkt_info *pkt, 1728c2ecf20Sopenharmony_ci struct rxe_send_wqe *wqe) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci s32 diff; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* check to see if response is past the oldest WQE. if it is, complete 1778c2ecf20Sopenharmony_ci * send/write or error read/atomic 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci diff = psn_compare(pkt->psn, wqe->last_psn); 1808c2ecf20Sopenharmony_ci if (diff > 0) { 1818c2ecf20Sopenharmony_ci if (wqe->state == wqe_state_pending) { 1828c2ecf20Sopenharmony_ci if (wqe->mask & WR_ATOMIC_OR_READ_MASK) 1838c2ecf20Sopenharmony_ci return COMPST_ERROR_RETRY; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci reset_retry_counters(qp); 1868c2ecf20Sopenharmony_ci return COMPST_COMP_WQE; 1878c2ecf20Sopenharmony_ci } else { 1888c2ecf20Sopenharmony_ci return COMPST_DONE; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* compare response packet to expected response */ 1938c2ecf20Sopenharmony_ci diff = psn_compare(pkt->psn, qp->comp.psn); 1948c2ecf20Sopenharmony_ci if (diff < 0) { 1958c2ecf20Sopenharmony_ci /* response is most likely a retried packet if it matches an 1968c2ecf20Sopenharmony_ci * uncompleted WQE go complete it else ignore it 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci if (pkt->psn == wqe->last_psn) 1998c2ecf20Sopenharmony_ci return COMPST_COMP_ACK; 2008c2ecf20Sopenharmony_ci else 2018c2ecf20Sopenharmony_ci return COMPST_DONE; 2028c2ecf20Sopenharmony_ci } else if ((diff > 0) && (wqe->mask & WR_ATOMIC_OR_READ_MASK)) { 2038c2ecf20Sopenharmony_ci return COMPST_DONE; 2048c2ecf20Sopenharmony_ci } else { 2058c2ecf20Sopenharmony_ci return COMPST_CHECK_ACK; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic inline enum comp_state check_ack(struct rxe_qp *qp, 2108c2ecf20Sopenharmony_ci struct rxe_pkt_info *pkt, 2118c2ecf20Sopenharmony_ci struct rxe_send_wqe *wqe) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci unsigned int mask = pkt->mask; 2148c2ecf20Sopenharmony_ci u8 syn; 2158c2ecf20Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* Check the sequence only */ 2188c2ecf20Sopenharmony_ci switch (qp->comp.opcode) { 2198c2ecf20Sopenharmony_ci case -1: 2208c2ecf20Sopenharmony_ci /* Will catch all *_ONLY cases. */ 2218c2ecf20Sopenharmony_ci if (!(mask & RXE_START_MASK)) 2228c2ecf20Sopenharmony_ci return COMPST_ERROR; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci case IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST: 2278c2ecf20Sopenharmony_ci case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE: 2288c2ecf20Sopenharmony_ci if (pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE && 2298c2ecf20Sopenharmony_ci pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST) { 2308c2ecf20Sopenharmony_ci /* read retries of partial data may restart from 2318c2ecf20Sopenharmony_ci * read response first or response only. 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ci if ((pkt->psn == wqe->first_psn && 2348c2ecf20Sopenharmony_ci pkt->opcode == 2358c2ecf20Sopenharmony_ci IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST) || 2368c2ecf20Sopenharmony_ci (wqe->first_psn == wqe->last_psn && 2378c2ecf20Sopenharmony_ci pkt->opcode == 2388c2ecf20Sopenharmony_ci IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY)) 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return COMPST_ERROR; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci default: 2458c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Check operation validity. */ 2498c2ecf20Sopenharmony_ci switch (pkt->opcode) { 2508c2ecf20Sopenharmony_ci case IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST: 2518c2ecf20Sopenharmony_ci case IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST: 2528c2ecf20Sopenharmony_ci case IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY: 2538c2ecf20Sopenharmony_ci syn = aeth_syn(pkt); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if ((syn & AETH_TYPE_MASK) != AETH_ACK) 2568c2ecf20Sopenharmony_ci return COMPST_ERROR; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci fallthrough; 2598c2ecf20Sopenharmony_ci /* (IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE doesn't have an AETH) 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ci case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE: 2628c2ecf20Sopenharmony_ci if (wqe->wr.opcode != IB_WR_RDMA_READ && 2638c2ecf20Sopenharmony_ci wqe->wr.opcode != IB_WR_RDMA_READ_WITH_INV) { 2648c2ecf20Sopenharmony_ci wqe->status = IB_WC_FATAL_ERR; 2658c2ecf20Sopenharmony_ci return COMPST_ERROR; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci reset_retry_counters(qp); 2688c2ecf20Sopenharmony_ci return COMPST_READ; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci case IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE: 2718c2ecf20Sopenharmony_ci syn = aeth_syn(pkt); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if ((syn & AETH_TYPE_MASK) != AETH_ACK) 2748c2ecf20Sopenharmony_ci return COMPST_ERROR; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (wqe->wr.opcode != IB_WR_ATOMIC_CMP_AND_SWP && 2778c2ecf20Sopenharmony_ci wqe->wr.opcode != IB_WR_ATOMIC_FETCH_AND_ADD) 2788c2ecf20Sopenharmony_ci return COMPST_ERROR; 2798c2ecf20Sopenharmony_ci reset_retry_counters(qp); 2808c2ecf20Sopenharmony_ci return COMPST_ATOMIC; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci case IB_OPCODE_RC_ACKNOWLEDGE: 2838c2ecf20Sopenharmony_ci syn = aeth_syn(pkt); 2848c2ecf20Sopenharmony_ci switch (syn & AETH_TYPE_MASK) { 2858c2ecf20Sopenharmony_ci case AETH_ACK: 2868c2ecf20Sopenharmony_ci reset_retry_counters(qp); 2878c2ecf20Sopenharmony_ci return COMPST_WRITE_SEND; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci case AETH_RNR_NAK: 2908c2ecf20Sopenharmony_ci rxe_counter_inc(rxe, RXE_CNT_RCV_RNR); 2918c2ecf20Sopenharmony_ci return COMPST_RNR_RETRY; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci case AETH_NAK: 2948c2ecf20Sopenharmony_ci switch (syn) { 2958c2ecf20Sopenharmony_ci case AETH_NAK_PSN_SEQ_ERROR: 2968c2ecf20Sopenharmony_ci /* a nak implicitly acks all packets with psns 2978c2ecf20Sopenharmony_ci * before 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci if (psn_compare(pkt->psn, qp->comp.psn) > 0) { 3008c2ecf20Sopenharmony_ci rxe_counter_inc(rxe, 3018c2ecf20Sopenharmony_ci RXE_CNT_RCV_SEQ_ERR); 3028c2ecf20Sopenharmony_ci qp->comp.psn = pkt->psn; 3038c2ecf20Sopenharmony_ci if (qp->req.wait_psn) { 3048c2ecf20Sopenharmony_ci qp->req.wait_psn = 0; 3058c2ecf20Sopenharmony_ci rxe_run_task(&qp->req.task, 0); 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci return COMPST_ERROR_RETRY; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci case AETH_NAK_INVALID_REQ: 3118c2ecf20Sopenharmony_ci wqe->status = IB_WC_REM_INV_REQ_ERR; 3128c2ecf20Sopenharmony_ci return COMPST_ERROR; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci case AETH_NAK_REM_ACC_ERR: 3158c2ecf20Sopenharmony_ci wqe->status = IB_WC_REM_ACCESS_ERR; 3168c2ecf20Sopenharmony_ci return COMPST_ERROR; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci case AETH_NAK_REM_OP_ERR: 3198c2ecf20Sopenharmony_ci wqe->status = IB_WC_REM_OP_ERR; 3208c2ecf20Sopenharmony_ci return COMPST_ERROR; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci default: 3238c2ecf20Sopenharmony_ci pr_warn("unexpected nak %x\n", syn); 3248c2ecf20Sopenharmony_ci wqe->status = IB_WC_REM_OP_ERR; 3258c2ecf20Sopenharmony_ci return COMPST_ERROR; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci default: 3298c2ecf20Sopenharmony_ci return COMPST_ERROR; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci default: 3348c2ecf20Sopenharmony_ci pr_warn("unexpected opcode\n"); 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return COMPST_ERROR; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic inline enum comp_state do_read(struct rxe_qp *qp, 3418c2ecf20Sopenharmony_ci struct rxe_pkt_info *pkt, 3428c2ecf20Sopenharmony_ci struct rxe_send_wqe *wqe) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci int ret; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci ret = copy_data(qp->pd, IB_ACCESS_LOCAL_WRITE, 3478c2ecf20Sopenharmony_ci &wqe->dma, payload_addr(pkt), 3488c2ecf20Sopenharmony_ci payload_size(pkt), to_mem_obj, NULL); 3498c2ecf20Sopenharmony_ci if (ret) 3508c2ecf20Sopenharmony_ci return COMPST_ERROR; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (wqe->dma.resid == 0 && (pkt->mask & RXE_END_MASK)) 3538c2ecf20Sopenharmony_ci return COMPST_COMP_ACK; 3548c2ecf20Sopenharmony_ci else 3558c2ecf20Sopenharmony_ci return COMPST_UPDATE_COMP; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic inline enum comp_state do_atomic(struct rxe_qp *qp, 3598c2ecf20Sopenharmony_ci struct rxe_pkt_info *pkt, 3608c2ecf20Sopenharmony_ci struct rxe_send_wqe *wqe) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci int ret; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci u64 atomic_orig = atmack_orig(pkt); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci ret = copy_data(qp->pd, IB_ACCESS_LOCAL_WRITE, 3678c2ecf20Sopenharmony_ci &wqe->dma, &atomic_orig, 3688c2ecf20Sopenharmony_ci sizeof(u64), to_mem_obj, NULL); 3698c2ecf20Sopenharmony_ci if (ret) 3708c2ecf20Sopenharmony_ci return COMPST_ERROR; 3718c2ecf20Sopenharmony_ci else 3728c2ecf20Sopenharmony_ci return COMPST_COMP_ACK; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic void make_send_cqe(struct rxe_qp *qp, struct rxe_send_wqe *wqe, 3768c2ecf20Sopenharmony_ci struct rxe_cqe *cqe) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci memset(cqe, 0, sizeof(*cqe)); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (!qp->is_user) { 3818c2ecf20Sopenharmony_ci struct ib_wc *wc = &cqe->ibwc; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci wc->wr_id = wqe->wr.wr_id; 3848c2ecf20Sopenharmony_ci wc->status = wqe->status; 3858c2ecf20Sopenharmony_ci wc->opcode = wr_to_wc_opcode(wqe->wr.opcode); 3868c2ecf20Sopenharmony_ci if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM || 3878c2ecf20Sopenharmony_ci wqe->wr.opcode == IB_WR_SEND_WITH_IMM) 3888c2ecf20Sopenharmony_ci wc->wc_flags = IB_WC_WITH_IMM; 3898c2ecf20Sopenharmony_ci wc->byte_len = wqe->dma.length; 3908c2ecf20Sopenharmony_ci wc->qp = &qp->ibqp; 3918c2ecf20Sopenharmony_ci } else { 3928c2ecf20Sopenharmony_ci struct ib_uverbs_wc *uwc = &cqe->uibwc; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci uwc->wr_id = wqe->wr.wr_id; 3958c2ecf20Sopenharmony_ci uwc->status = wqe->status; 3968c2ecf20Sopenharmony_ci uwc->opcode = wr_to_wc_opcode(wqe->wr.opcode); 3978c2ecf20Sopenharmony_ci if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM || 3988c2ecf20Sopenharmony_ci wqe->wr.opcode == IB_WR_SEND_WITH_IMM) 3998c2ecf20Sopenharmony_ci uwc->wc_flags = IB_WC_WITH_IMM; 4008c2ecf20Sopenharmony_ci uwc->byte_len = wqe->dma.length; 4018c2ecf20Sopenharmony_ci uwc->qp_num = qp->ibqp.qp_num; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* 4068c2ecf20Sopenharmony_ci * IBA Spec. Section 10.7.3.1 SIGNALED COMPLETIONS 4078c2ecf20Sopenharmony_ci * ---------8<---------8<------------- 4088c2ecf20Sopenharmony_ci * ...Note that if a completion error occurs, a Work Completion 4098c2ecf20Sopenharmony_ci * will always be generated, even if the signaling 4108c2ecf20Sopenharmony_ci * indicator requests an Unsignaled Completion. 4118c2ecf20Sopenharmony_ci * ---------8<---------8<------------- 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_cistatic void do_complete(struct rxe_qp *qp, struct rxe_send_wqe *wqe) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 4168c2ecf20Sopenharmony_ci struct rxe_cqe cqe; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if ((qp->sq_sig_type == IB_SIGNAL_ALL_WR) || 4198c2ecf20Sopenharmony_ci (wqe->wr.send_flags & IB_SEND_SIGNALED) || 4208c2ecf20Sopenharmony_ci wqe->status != IB_WC_SUCCESS) { 4218c2ecf20Sopenharmony_ci make_send_cqe(qp, wqe, &cqe); 4228c2ecf20Sopenharmony_ci advance_consumer(qp->sq.queue); 4238c2ecf20Sopenharmony_ci rxe_cq_post(qp->scq, &cqe, 0); 4248c2ecf20Sopenharmony_ci } else { 4258c2ecf20Sopenharmony_ci advance_consumer(qp->sq.queue); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (wqe->wr.opcode == IB_WR_SEND || 4298c2ecf20Sopenharmony_ci wqe->wr.opcode == IB_WR_SEND_WITH_IMM || 4308c2ecf20Sopenharmony_ci wqe->wr.opcode == IB_WR_SEND_WITH_INV) 4318c2ecf20Sopenharmony_ci rxe_counter_inc(rxe, RXE_CNT_RDMA_SEND); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* 4348c2ecf20Sopenharmony_ci * we completed something so let req run again 4358c2ecf20Sopenharmony_ci * if it is trying to fence 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ci if (qp->req.wait_fence) { 4388c2ecf20Sopenharmony_ci qp->req.wait_fence = 0; 4398c2ecf20Sopenharmony_ci rxe_run_task(&qp->req.task, 0); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic inline enum comp_state complete_ack(struct rxe_qp *qp, 4448c2ecf20Sopenharmony_ci struct rxe_pkt_info *pkt, 4458c2ecf20Sopenharmony_ci struct rxe_send_wqe *wqe) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci unsigned long flags; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (wqe->has_rd_atomic) { 4508c2ecf20Sopenharmony_ci wqe->has_rd_atomic = 0; 4518c2ecf20Sopenharmony_ci atomic_inc(&qp->req.rd_atomic); 4528c2ecf20Sopenharmony_ci if (qp->req.need_rd_atomic) { 4538c2ecf20Sopenharmony_ci qp->comp.timeout_retry = 0; 4548c2ecf20Sopenharmony_ci qp->req.need_rd_atomic = 0; 4558c2ecf20Sopenharmony_ci rxe_run_task(&qp->req.task, 0); 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (unlikely(qp->req.state == QP_STATE_DRAIN)) { 4608c2ecf20Sopenharmony_ci /* state_lock used by requester & completer */ 4618c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 4628c2ecf20Sopenharmony_ci if ((qp->req.state == QP_STATE_DRAIN) && 4638c2ecf20Sopenharmony_ci (qp->comp.psn == qp->req.psn)) { 4648c2ecf20Sopenharmony_ci qp->req.state = QP_STATE_DRAINED; 4658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (qp->ibqp.event_handler) { 4688c2ecf20Sopenharmony_ci struct ib_event ev; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ev.device = qp->ibqp.device; 4718c2ecf20Sopenharmony_ci ev.element.qp = &qp->ibqp; 4728c2ecf20Sopenharmony_ci ev.event = IB_EVENT_SQ_DRAINED; 4738c2ecf20Sopenharmony_ci qp->ibqp.event_handler(&ev, 4748c2ecf20Sopenharmony_ci qp->ibqp.qp_context); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci } else { 4778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci do_complete(qp, wqe); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (psn_compare(pkt->psn, qp->comp.psn) >= 0) 4848c2ecf20Sopenharmony_ci return COMPST_UPDATE_COMP; 4858c2ecf20Sopenharmony_ci else 4868c2ecf20Sopenharmony_ci return COMPST_DONE; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic inline enum comp_state complete_wqe(struct rxe_qp *qp, 4908c2ecf20Sopenharmony_ci struct rxe_pkt_info *pkt, 4918c2ecf20Sopenharmony_ci struct rxe_send_wqe *wqe) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci if (pkt && wqe->state == wqe_state_pending) { 4948c2ecf20Sopenharmony_ci if (psn_compare(wqe->last_psn, qp->comp.psn) >= 0) { 4958c2ecf20Sopenharmony_ci qp->comp.psn = (wqe->last_psn + 1) & BTH_PSN_MASK; 4968c2ecf20Sopenharmony_ci qp->comp.opcode = -1; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (qp->req.wait_psn) { 5008c2ecf20Sopenharmony_ci qp->req.wait_psn = 0; 5018c2ecf20Sopenharmony_ci rxe_run_task(&qp->req.task, 1); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci do_complete(qp, wqe); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return COMPST_GET_WQE; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic void rxe_drain_resp_pkts(struct rxe_qp *qp, bool notify) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct sk_buff *skb; 5138c2ecf20Sopenharmony_ci struct rxe_send_wqe *wqe; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci while ((skb = skb_dequeue(&qp->resp_pkts))) { 5168c2ecf20Sopenharmony_ci rxe_drop_ref(qp); 5178c2ecf20Sopenharmony_ci kfree_skb(skb); 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci while ((wqe = queue_head(qp->sq.queue))) { 5218c2ecf20Sopenharmony_ci if (notify) { 5228c2ecf20Sopenharmony_ci wqe->status = IB_WC_WR_FLUSH_ERR; 5238c2ecf20Sopenharmony_ci do_complete(qp, wqe); 5248c2ecf20Sopenharmony_ci } else { 5258c2ecf20Sopenharmony_ci advance_consumer(qp->sq.queue); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ciint rxe_completer(void *arg) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct rxe_qp *qp = (struct rxe_qp *)arg; 5338c2ecf20Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 5348c2ecf20Sopenharmony_ci struct rxe_send_wqe *wqe = NULL; 5358c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 5368c2ecf20Sopenharmony_ci struct rxe_pkt_info *pkt = NULL; 5378c2ecf20Sopenharmony_ci enum comp_state state; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci rxe_add_ref(qp); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (!qp->valid || qp->req.state == QP_STATE_ERROR || 5428c2ecf20Sopenharmony_ci qp->req.state == QP_STATE_RESET) { 5438c2ecf20Sopenharmony_ci rxe_drain_resp_pkts(qp, qp->valid && 5448c2ecf20Sopenharmony_ci qp->req.state == QP_STATE_ERROR); 5458c2ecf20Sopenharmony_ci goto exit; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (qp->comp.timeout) { 5498c2ecf20Sopenharmony_ci qp->comp.timeout_retry = 1; 5508c2ecf20Sopenharmony_ci qp->comp.timeout = 0; 5518c2ecf20Sopenharmony_ci } else { 5528c2ecf20Sopenharmony_ci qp->comp.timeout_retry = 0; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (qp->req.need_retry) 5568c2ecf20Sopenharmony_ci goto exit; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci state = COMPST_GET_ACK; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci while (1) { 5618c2ecf20Sopenharmony_ci pr_debug("qp#%d state = %s\n", qp_num(qp), 5628c2ecf20Sopenharmony_ci comp_state_name[state]); 5638c2ecf20Sopenharmony_ci switch (state) { 5648c2ecf20Sopenharmony_ci case COMPST_GET_ACK: 5658c2ecf20Sopenharmony_ci skb = skb_dequeue(&qp->resp_pkts); 5668c2ecf20Sopenharmony_ci if (skb) { 5678c2ecf20Sopenharmony_ci pkt = SKB_TO_PKT(skb); 5688c2ecf20Sopenharmony_ci qp->comp.timeout_retry = 0; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci state = COMPST_GET_WQE; 5718c2ecf20Sopenharmony_ci break; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci case COMPST_GET_WQE: 5748c2ecf20Sopenharmony_ci state = get_wqe(qp, pkt, &wqe); 5758c2ecf20Sopenharmony_ci break; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci case COMPST_CHECK_PSN: 5788c2ecf20Sopenharmony_ci state = check_psn(qp, pkt, wqe); 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci case COMPST_CHECK_ACK: 5828c2ecf20Sopenharmony_ci state = check_ack(qp, pkt, wqe); 5838c2ecf20Sopenharmony_ci break; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci case COMPST_READ: 5868c2ecf20Sopenharmony_ci state = do_read(qp, pkt, wqe); 5878c2ecf20Sopenharmony_ci break; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci case COMPST_ATOMIC: 5908c2ecf20Sopenharmony_ci state = do_atomic(qp, pkt, wqe); 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci case COMPST_WRITE_SEND: 5948c2ecf20Sopenharmony_ci if (wqe->state == wqe_state_pending && 5958c2ecf20Sopenharmony_ci wqe->last_psn == pkt->psn) 5968c2ecf20Sopenharmony_ci state = COMPST_COMP_ACK; 5978c2ecf20Sopenharmony_ci else 5988c2ecf20Sopenharmony_ci state = COMPST_UPDATE_COMP; 5998c2ecf20Sopenharmony_ci break; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci case COMPST_COMP_ACK: 6028c2ecf20Sopenharmony_ci state = complete_ack(qp, pkt, wqe); 6038c2ecf20Sopenharmony_ci break; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci case COMPST_COMP_WQE: 6068c2ecf20Sopenharmony_ci state = complete_wqe(qp, pkt, wqe); 6078c2ecf20Sopenharmony_ci break; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci case COMPST_UPDATE_COMP: 6108c2ecf20Sopenharmony_ci if (pkt->mask & RXE_END_MASK) 6118c2ecf20Sopenharmony_ci qp->comp.opcode = -1; 6128c2ecf20Sopenharmony_ci else 6138c2ecf20Sopenharmony_ci qp->comp.opcode = pkt->opcode; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (psn_compare(pkt->psn, qp->comp.psn) >= 0) 6168c2ecf20Sopenharmony_ci qp->comp.psn = (pkt->psn + 1) & BTH_PSN_MASK; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (qp->req.wait_psn) { 6198c2ecf20Sopenharmony_ci qp->req.wait_psn = 0; 6208c2ecf20Sopenharmony_ci rxe_run_task(&qp->req.task, 1); 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci state = COMPST_DONE; 6248c2ecf20Sopenharmony_ci break; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci case COMPST_DONE: 6278c2ecf20Sopenharmony_ci if (pkt) { 6288c2ecf20Sopenharmony_ci rxe_drop_ref(pkt->qp); 6298c2ecf20Sopenharmony_ci kfree_skb(skb); 6308c2ecf20Sopenharmony_ci skb = NULL; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci goto done; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci case COMPST_EXIT: 6358c2ecf20Sopenharmony_ci if (qp->comp.timeout_retry && wqe) { 6368c2ecf20Sopenharmony_ci state = COMPST_ERROR_RETRY; 6378c2ecf20Sopenharmony_ci break; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* re reset the timeout counter if 6418c2ecf20Sopenharmony_ci * (1) QP is type RC 6428c2ecf20Sopenharmony_ci * (2) the QP is alive 6438c2ecf20Sopenharmony_ci * (3) there is a packet sent by the requester that 6448c2ecf20Sopenharmony_ci * might be acked (we still might get spurious 6458c2ecf20Sopenharmony_ci * timeouts but try to keep them as few as possible) 6468c2ecf20Sopenharmony_ci * (4) the timeout parameter is set 6478c2ecf20Sopenharmony_ci */ 6488c2ecf20Sopenharmony_ci if ((qp_type(qp) == IB_QPT_RC) && 6498c2ecf20Sopenharmony_ci (qp->req.state == QP_STATE_READY) && 6508c2ecf20Sopenharmony_ci (psn_compare(qp->req.psn, qp->comp.psn) > 0) && 6518c2ecf20Sopenharmony_ci qp->qp_timeout_jiffies) 6528c2ecf20Sopenharmony_ci mod_timer(&qp->retrans_timer, 6538c2ecf20Sopenharmony_ci jiffies + qp->qp_timeout_jiffies); 6548c2ecf20Sopenharmony_ci goto exit; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci case COMPST_ERROR_RETRY: 6578c2ecf20Sopenharmony_ci /* we come here if the retry timer fired and we did 6588c2ecf20Sopenharmony_ci * not receive a response packet. try to retry the send 6598c2ecf20Sopenharmony_ci * queue if that makes sense and the limits have not 6608c2ecf20Sopenharmony_ci * been exceeded. remember that some timeouts are 6618c2ecf20Sopenharmony_ci * spurious since we do not reset the timer but kick 6628c2ecf20Sopenharmony_ci * it down the road or let it expire 6638c2ecf20Sopenharmony_ci */ 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* there is nothing to retry in this case */ 6668c2ecf20Sopenharmony_ci if (!wqe || (wqe->state == wqe_state_posted)) 6678c2ecf20Sopenharmony_ci goto exit; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* if we've started a retry, don't start another 6708c2ecf20Sopenharmony_ci * retry sequence, unless this is a timeout. 6718c2ecf20Sopenharmony_ci */ 6728c2ecf20Sopenharmony_ci if (qp->comp.started_retry && 6738c2ecf20Sopenharmony_ci !qp->comp.timeout_retry) { 6748c2ecf20Sopenharmony_ci if (pkt) { 6758c2ecf20Sopenharmony_ci rxe_drop_ref(pkt->qp); 6768c2ecf20Sopenharmony_ci kfree_skb(skb); 6778c2ecf20Sopenharmony_ci skb = NULL; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci goto done; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (qp->comp.retry_cnt > 0) { 6848c2ecf20Sopenharmony_ci if (qp->comp.retry_cnt != 7) 6858c2ecf20Sopenharmony_ci qp->comp.retry_cnt--; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* no point in retrying if we have already 6888c2ecf20Sopenharmony_ci * seen the last ack that the requester could 6898c2ecf20Sopenharmony_ci * have caused 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_ci if (psn_compare(qp->req.psn, 6928c2ecf20Sopenharmony_ci qp->comp.psn) > 0) { 6938c2ecf20Sopenharmony_ci /* tell the requester to retry the 6948c2ecf20Sopenharmony_ci * send queue next time around 6958c2ecf20Sopenharmony_ci */ 6968c2ecf20Sopenharmony_ci rxe_counter_inc(rxe, 6978c2ecf20Sopenharmony_ci RXE_CNT_COMP_RETRY); 6988c2ecf20Sopenharmony_ci qp->req.need_retry = 1; 6998c2ecf20Sopenharmony_ci qp->comp.started_retry = 1; 7008c2ecf20Sopenharmony_ci rxe_run_task(&qp->req.task, 0); 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (pkt) { 7048c2ecf20Sopenharmony_ci rxe_drop_ref(pkt->qp); 7058c2ecf20Sopenharmony_ci kfree_skb(skb); 7068c2ecf20Sopenharmony_ci skb = NULL; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci goto done; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci } else { 7128c2ecf20Sopenharmony_ci rxe_counter_inc(rxe, RXE_CNT_RETRY_EXCEEDED); 7138c2ecf20Sopenharmony_ci wqe->status = IB_WC_RETRY_EXC_ERR; 7148c2ecf20Sopenharmony_ci state = COMPST_ERROR; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci break; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci case COMPST_RNR_RETRY: 7198c2ecf20Sopenharmony_ci if (qp->comp.rnr_retry > 0) { 7208c2ecf20Sopenharmony_ci if (qp->comp.rnr_retry != 7) 7218c2ecf20Sopenharmony_ci qp->comp.rnr_retry--; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci qp->req.need_retry = 1; 7248c2ecf20Sopenharmony_ci pr_debug("qp#%d set rnr nak timer\n", 7258c2ecf20Sopenharmony_ci qp_num(qp)); 7268c2ecf20Sopenharmony_ci mod_timer(&qp->rnr_nak_timer, 7278c2ecf20Sopenharmony_ci jiffies + rnrnak_jiffies(aeth_syn(pkt) 7288c2ecf20Sopenharmony_ci & ~AETH_TYPE_MASK)); 7298c2ecf20Sopenharmony_ci rxe_drop_ref(pkt->qp); 7308c2ecf20Sopenharmony_ci kfree_skb(skb); 7318c2ecf20Sopenharmony_ci skb = NULL; 7328c2ecf20Sopenharmony_ci goto exit; 7338c2ecf20Sopenharmony_ci } else { 7348c2ecf20Sopenharmony_ci rxe_counter_inc(rxe, 7358c2ecf20Sopenharmony_ci RXE_CNT_RNR_RETRY_EXCEEDED); 7368c2ecf20Sopenharmony_ci wqe->status = IB_WC_RNR_RETRY_EXC_ERR; 7378c2ecf20Sopenharmony_ci state = COMPST_ERROR; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci break; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci case COMPST_ERROR: 7428c2ecf20Sopenharmony_ci WARN_ON_ONCE(wqe->status == IB_WC_SUCCESS); 7438c2ecf20Sopenharmony_ci do_complete(qp, wqe); 7448c2ecf20Sopenharmony_ci rxe_qp_error(qp); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (pkt) { 7478c2ecf20Sopenharmony_ci rxe_drop_ref(pkt->qp); 7488c2ecf20Sopenharmony_ci kfree_skb(skb); 7498c2ecf20Sopenharmony_ci skb = NULL; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci goto exit; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ciexit: 7578c2ecf20Sopenharmony_ci /* we come here if we are done with processing and want the task to 7588c2ecf20Sopenharmony_ci * exit from the loop calling us 7598c2ecf20Sopenharmony_ci */ 7608c2ecf20Sopenharmony_ci WARN_ON_ONCE(skb); 7618c2ecf20Sopenharmony_ci rxe_drop_ref(qp); 7628c2ecf20Sopenharmony_ci return -EAGAIN; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cidone: 7658c2ecf20Sopenharmony_ci /* we come here if we have processed a packet we want the task to call 7668c2ecf20Sopenharmony_ci * us again to see if there is anything else to do 7678c2ecf20Sopenharmony_ci */ 7688c2ecf20Sopenharmony_ci WARN_ON_ONCE(skb); 7698c2ecf20Sopenharmony_ci rxe_drop_ref(qp); 7708c2ecf20Sopenharmony_ci return 0; 7718c2ecf20Sopenharmony_ci} 772