18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */ 48c2ecf20Sopenharmony_ci/* Copyright (c) 2008-2019, IBM Corporation */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/errno.h> 78c2ecf20Sopenharmony_ci#include <linux/types.h> 88c2ecf20Sopenharmony_ci#include <linux/net.h> 98c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 108c2ecf20Sopenharmony_ci#include <linux/llist.h> 118c2ecf20Sopenharmony_ci#include <asm/barrier.h> 128c2ecf20Sopenharmony_ci#include <net/tcp.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "siw.h" 158c2ecf20Sopenharmony_ci#include "siw_verbs.h" 168c2ecf20Sopenharmony_ci#include "siw_mem.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic char siw_qp_state_to_string[SIW_QP_STATE_COUNT][sizeof "TERMINATE"] = { 198c2ecf20Sopenharmony_ci [SIW_QP_STATE_IDLE] = "IDLE", 208c2ecf20Sopenharmony_ci [SIW_QP_STATE_RTR] = "RTR", 218c2ecf20Sopenharmony_ci [SIW_QP_STATE_RTS] = "RTS", 228c2ecf20Sopenharmony_ci [SIW_QP_STATE_CLOSING] = "CLOSING", 238c2ecf20Sopenharmony_ci [SIW_QP_STATE_TERMINATE] = "TERMINATE", 248c2ecf20Sopenharmony_ci [SIW_QP_STATE_ERROR] = "ERROR" 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * iWARP (RDMAP, DDP and MPA) parameters as well as Softiwarp settings on a 298c2ecf20Sopenharmony_ci * per-RDMAP message basis. Please keep order of initializer. All MPA len 308c2ecf20Sopenharmony_ci * is initialized to minimum packet size. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_cistruct iwarp_msg_info iwarp_pktinfo[RDMAP_TERMINATE + 1] = { 338c2ecf20Sopenharmony_ci { /* RDMAP_RDMA_WRITE */ 348c2ecf20Sopenharmony_ci .hdr_len = sizeof(struct iwarp_rdma_write), 358c2ecf20Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_rdma_write) - 2), 368c2ecf20Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_TAGGED | DDP_FLAG_LAST | 378c2ecf20Sopenharmony_ci cpu_to_be16(DDP_VERSION << 8) | 388c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 398c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_RDMA_WRITE), 408c2ecf20Sopenharmony_ci .rx_data = siw_proc_write }, 418c2ecf20Sopenharmony_ci { /* RDMAP_RDMA_READ_REQ */ 428c2ecf20Sopenharmony_ci .hdr_len = sizeof(struct iwarp_rdma_rreq), 438c2ecf20Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_rdma_rreq) - 2), 448c2ecf20Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) | 458c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 468c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_RDMA_READ_REQ), 478c2ecf20Sopenharmony_ci .rx_data = siw_proc_rreq }, 488c2ecf20Sopenharmony_ci { /* RDMAP_RDMA_READ_RESP */ 498c2ecf20Sopenharmony_ci .hdr_len = sizeof(struct iwarp_rdma_rresp), 508c2ecf20Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_rdma_rresp) - 2), 518c2ecf20Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_TAGGED | DDP_FLAG_LAST | 528c2ecf20Sopenharmony_ci cpu_to_be16(DDP_VERSION << 8) | 538c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 548c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_RDMA_READ_RESP), 558c2ecf20Sopenharmony_ci .rx_data = siw_proc_rresp }, 568c2ecf20Sopenharmony_ci { /* RDMAP_SEND */ 578c2ecf20Sopenharmony_ci .hdr_len = sizeof(struct iwarp_send), 588c2ecf20Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_send) - 2), 598c2ecf20Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) | 608c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 618c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_SEND), 628c2ecf20Sopenharmony_ci .rx_data = siw_proc_send }, 638c2ecf20Sopenharmony_ci { /* RDMAP_SEND_INVAL */ 648c2ecf20Sopenharmony_ci .hdr_len = sizeof(struct iwarp_send_inv), 658c2ecf20Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_send_inv) - 2), 668c2ecf20Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) | 678c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 688c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_SEND_INVAL), 698c2ecf20Sopenharmony_ci .rx_data = siw_proc_send }, 708c2ecf20Sopenharmony_ci { /* RDMAP_SEND_SE */ 718c2ecf20Sopenharmony_ci .hdr_len = sizeof(struct iwarp_send), 728c2ecf20Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_send) - 2), 738c2ecf20Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) | 748c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 758c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_SEND_SE), 768c2ecf20Sopenharmony_ci .rx_data = siw_proc_send }, 778c2ecf20Sopenharmony_ci { /* RDMAP_SEND_SE_INVAL */ 788c2ecf20Sopenharmony_ci .hdr_len = sizeof(struct iwarp_send_inv), 798c2ecf20Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_send_inv) - 2), 808c2ecf20Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) | 818c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 828c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_SEND_SE_INVAL), 838c2ecf20Sopenharmony_ci .rx_data = siw_proc_send }, 848c2ecf20Sopenharmony_ci { /* RDMAP_TERMINATE */ 858c2ecf20Sopenharmony_ci .hdr_len = sizeof(struct iwarp_terminate), 868c2ecf20Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_terminate) - 2), 878c2ecf20Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) | 888c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 898c2ecf20Sopenharmony_ci cpu_to_be16(RDMAP_TERMINATE), 908c2ecf20Sopenharmony_ci .rx_data = siw_proc_terminate } 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_civoid siw_qp_llp_data_ready(struct sock *sk) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct siw_qp *qp; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci read_lock(&sk->sk_callback_lock); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (unlikely(!sk->sk_user_data || !sk_to_qp(sk))) 1008c2ecf20Sopenharmony_ci goto done; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci qp = sk_to_qp(sk); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (likely(!qp->rx_stream.rx_suspend && 1058c2ecf20Sopenharmony_ci down_read_trylock(&qp->state_lock))) { 1068c2ecf20Sopenharmony_ci read_descriptor_t rd_desc = { .arg.data = qp, .count = 1 }; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (likely(qp->attrs.state == SIW_QP_STATE_RTS)) 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Implements data receive operation during 1118c2ecf20Sopenharmony_ci * socket callback. TCP gracefully catches 1128c2ecf20Sopenharmony_ci * the case where there is nothing to receive 1138c2ecf20Sopenharmony_ci * (not calling siw_tcp_rx_data() then). 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci tcp_read_sock(sk, &rd_desc, siw_tcp_rx_data); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci up_read(&qp->state_lock); 1188c2ecf20Sopenharmony_ci } else { 1198c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "unable to process RX, suspend: %d\n", 1208c2ecf20Sopenharmony_ci qp->rx_stream.rx_suspend); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_cidone: 1238c2ecf20Sopenharmony_ci read_unlock(&sk->sk_callback_lock); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_civoid siw_qp_llp_close(struct siw_qp *qp) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "enter llp close, state = %s\n", 1298c2ecf20Sopenharmony_ci siw_qp_state_to_string[qp->attrs.state]); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci down_write(&qp->state_lock); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci qp->rx_stream.rx_suspend = 1; 1348c2ecf20Sopenharmony_ci qp->tx_ctx.tx_suspend = 1; 1358c2ecf20Sopenharmony_ci qp->attrs.sk = NULL; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci switch (qp->attrs.state) { 1388c2ecf20Sopenharmony_ci case SIW_QP_STATE_RTS: 1398c2ecf20Sopenharmony_ci case SIW_QP_STATE_RTR: 1408c2ecf20Sopenharmony_ci case SIW_QP_STATE_IDLE: 1418c2ecf20Sopenharmony_ci case SIW_QP_STATE_TERMINATE: 1428c2ecf20Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 1438c2ecf20Sopenharmony_ci break; 1448c2ecf20Sopenharmony_ci /* 1458c2ecf20Sopenharmony_ci * SIW_QP_STATE_CLOSING: 1468c2ecf20Sopenharmony_ci * 1478c2ecf20Sopenharmony_ci * This is a forced close. shall the QP be moved to 1488c2ecf20Sopenharmony_ci * ERROR or IDLE ? 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_ci case SIW_QP_STATE_CLOSING: 1518c2ecf20Sopenharmony_ci if (tx_wqe(qp)->wr_status == SIW_WR_IDLE) 1528c2ecf20Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 1538c2ecf20Sopenharmony_ci else 1548c2ecf20Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_IDLE; 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci default: 1588c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "llp close: no state transition needed: %s\n", 1598c2ecf20Sopenharmony_ci siw_qp_state_to_string[qp->attrs.state]); 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci siw_sq_flush(qp); 1638c2ecf20Sopenharmony_ci siw_rq_flush(qp); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* 1668c2ecf20Sopenharmony_ci * Dereference closing CEP 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_ci if (qp->cep) { 1698c2ecf20Sopenharmony_ci siw_cep_put(qp->cep); 1708c2ecf20Sopenharmony_ci qp->cep = NULL; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci up_write(&qp->state_lock); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "llp close exit: state %s\n", 1768c2ecf20Sopenharmony_ci siw_qp_state_to_string[qp->attrs.state]); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* 1808c2ecf20Sopenharmony_ci * socket callback routine informing about newly available send space. 1818c2ecf20Sopenharmony_ci * Function schedules SQ work for processing SQ items. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_civoid siw_qp_llp_write_space(struct sock *sk) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct siw_cep *cep; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci read_lock(&sk->sk_callback_lock); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci cep = sk_to_cep(sk); 1908c2ecf20Sopenharmony_ci if (cep) { 1918c2ecf20Sopenharmony_ci cep->sk_write_space(sk); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (!test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) 1948c2ecf20Sopenharmony_ci (void)siw_sq_start(cep->qp); 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci read_unlock(&sk->sk_callback_lock); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int siw_qp_readq_init(struct siw_qp *qp, int irq_size, int orq_size) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci if (irq_size) { 2038c2ecf20Sopenharmony_ci irq_size = roundup_pow_of_two(irq_size); 2048c2ecf20Sopenharmony_ci qp->irq = vzalloc(irq_size * sizeof(struct siw_sqe)); 2058c2ecf20Sopenharmony_ci if (!qp->irq) { 2068c2ecf20Sopenharmony_ci qp->attrs.irq_size = 0; 2078c2ecf20Sopenharmony_ci return -ENOMEM; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci if (orq_size) { 2118c2ecf20Sopenharmony_ci orq_size = roundup_pow_of_two(orq_size); 2128c2ecf20Sopenharmony_ci qp->orq = vzalloc(orq_size * sizeof(struct siw_sqe)); 2138c2ecf20Sopenharmony_ci if (!qp->orq) { 2148c2ecf20Sopenharmony_ci qp->attrs.orq_size = 0; 2158c2ecf20Sopenharmony_ci qp->attrs.irq_size = 0; 2168c2ecf20Sopenharmony_ci vfree(qp->irq); 2178c2ecf20Sopenharmony_ci return -ENOMEM; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci qp->attrs.irq_size = irq_size; 2218c2ecf20Sopenharmony_ci qp->attrs.orq_size = orq_size; 2228c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "ORD %d, IRD %d\n", orq_size, irq_size); 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int siw_qp_enable_crc(struct siw_qp *qp) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct siw_rx_stream *c_rx = &qp->rx_stream; 2298c2ecf20Sopenharmony_ci struct siw_iwarp_tx *c_tx = &qp->tx_ctx; 2308c2ecf20Sopenharmony_ci int size; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (siw_crypto_shash == NULL) 2338c2ecf20Sopenharmony_ci return -ENOENT; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci size = crypto_shash_descsize(siw_crypto_shash) + 2368c2ecf20Sopenharmony_ci sizeof(struct shash_desc); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci c_tx->mpa_crc_hd = kzalloc(size, GFP_KERNEL); 2398c2ecf20Sopenharmony_ci c_rx->mpa_crc_hd = kzalloc(size, GFP_KERNEL); 2408c2ecf20Sopenharmony_ci if (!c_tx->mpa_crc_hd || !c_rx->mpa_crc_hd) { 2418c2ecf20Sopenharmony_ci kfree(c_tx->mpa_crc_hd); 2428c2ecf20Sopenharmony_ci kfree(c_rx->mpa_crc_hd); 2438c2ecf20Sopenharmony_ci c_tx->mpa_crc_hd = NULL; 2448c2ecf20Sopenharmony_ci c_rx->mpa_crc_hd = NULL; 2458c2ecf20Sopenharmony_ci return -ENOMEM; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci c_tx->mpa_crc_hd->tfm = siw_crypto_shash; 2488c2ecf20Sopenharmony_ci c_rx->mpa_crc_hd->tfm = siw_crypto_shash; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return 0; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* 2548c2ecf20Sopenharmony_ci * Send a non signalled READ or WRITE to peer side as negotiated 2558c2ecf20Sopenharmony_ci * with MPAv2 P2P setup protocol. The work request is only created 2568c2ecf20Sopenharmony_ci * as a current active WR and does not consume Send Queue space. 2578c2ecf20Sopenharmony_ci * 2588c2ecf20Sopenharmony_ci * Caller must hold QP state lock. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ciint siw_qp_mpa_rts(struct siw_qp *qp, enum mpa_v2_ctrl ctrl) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct siw_wqe *wqe = tx_wqe(qp); 2638c2ecf20Sopenharmony_ci unsigned long flags; 2648c2ecf20Sopenharmony_ci int rv = 0; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->sq_lock, flags); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (unlikely(wqe->wr_status != SIW_WR_IDLE)) { 2698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->sq_lock, flags); 2708c2ecf20Sopenharmony_ci return -EIO; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci wqe->wr_status = SIW_WR_QUEUED; 2758c2ecf20Sopenharmony_ci wqe->sqe.flags = 0; 2768c2ecf20Sopenharmony_ci wqe->sqe.num_sge = 1; 2778c2ecf20Sopenharmony_ci wqe->sqe.sge[0].length = 0; 2788c2ecf20Sopenharmony_ci wqe->sqe.sge[0].laddr = 0; 2798c2ecf20Sopenharmony_ci wqe->sqe.sge[0].lkey = 0; 2808c2ecf20Sopenharmony_ci /* 2818c2ecf20Sopenharmony_ci * While it must not be checked for inbound zero length 2828c2ecf20Sopenharmony_ci * READ/WRITE, some HW may treat STag 0 special. 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_ci wqe->sqe.rkey = 1; 2858c2ecf20Sopenharmony_ci wqe->sqe.raddr = 0; 2868c2ecf20Sopenharmony_ci wqe->processed = 0; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (ctrl & MPA_V2_RDMA_WRITE_RTR) 2898c2ecf20Sopenharmony_ci wqe->sqe.opcode = SIW_OP_WRITE; 2908c2ecf20Sopenharmony_ci else if (ctrl & MPA_V2_RDMA_READ_RTR) { 2918c2ecf20Sopenharmony_ci struct siw_sqe *rreq = NULL; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci wqe->sqe.opcode = SIW_OP_READ; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci spin_lock(&qp->orq_lock); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (qp->attrs.orq_size) 2988c2ecf20Sopenharmony_ci rreq = orq_get_free(qp); 2998c2ecf20Sopenharmony_ci if (rreq) { 3008c2ecf20Sopenharmony_ci siw_read_to_orq(rreq, &wqe->sqe); 3018c2ecf20Sopenharmony_ci qp->orq_put++; 3028c2ecf20Sopenharmony_ci } else 3038c2ecf20Sopenharmony_ci rv = -EIO; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci spin_unlock(&qp->orq_lock); 3068c2ecf20Sopenharmony_ci } else 3078c2ecf20Sopenharmony_ci rv = -EINVAL; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (rv) 3108c2ecf20Sopenharmony_ci wqe->wr_status = SIW_WR_IDLE; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->sq_lock, flags); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (!rv) 3158c2ecf20Sopenharmony_ci rv = siw_sq_start(qp); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return rv; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/* 3218c2ecf20Sopenharmony_ci * Map memory access error to DDP tagged error 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_cienum ddp_ecode siw_tagged_error(enum siw_access_state state) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci switch (state) { 3268c2ecf20Sopenharmony_ci case E_STAG_INVALID: 3278c2ecf20Sopenharmony_ci return DDP_ECODE_T_INVALID_STAG; 3288c2ecf20Sopenharmony_ci case E_BASE_BOUNDS: 3298c2ecf20Sopenharmony_ci return DDP_ECODE_T_BASE_BOUNDS; 3308c2ecf20Sopenharmony_ci case E_PD_MISMATCH: 3318c2ecf20Sopenharmony_ci return DDP_ECODE_T_STAG_NOT_ASSOC; 3328c2ecf20Sopenharmony_ci case E_ACCESS_PERM: 3338c2ecf20Sopenharmony_ci /* 3348c2ecf20Sopenharmony_ci * RFC 5041 (DDP) lacks an ecode for insufficient access 3358c2ecf20Sopenharmony_ci * permissions. 'Invalid STag' seem to be the closest 3368c2ecf20Sopenharmony_ci * match though. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci return DDP_ECODE_T_INVALID_STAG; 3398c2ecf20Sopenharmony_ci default: 3408c2ecf20Sopenharmony_ci WARN_ON(1); 3418c2ecf20Sopenharmony_ci return DDP_ECODE_T_INVALID_STAG; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci/* 3468c2ecf20Sopenharmony_ci * Map memory access error to RDMAP protection error 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_cienum rdmap_ecode siw_rdmap_error(enum siw_access_state state) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci switch (state) { 3518c2ecf20Sopenharmony_ci case E_STAG_INVALID: 3528c2ecf20Sopenharmony_ci return RDMAP_ECODE_INVALID_STAG; 3538c2ecf20Sopenharmony_ci case E_BASE_BOUNDS: 3548c2ecf20Sopenharmony_ci return RDMAP_ECODE_BASE_BOUNDS; 3558c2ecf20Sopenharmony_ci case E_PD_MISMATCH: 3568c2ecf20Sopenharmony_ci return RDMAP_ECODE_STAG_NOT_ASSOC; 3578c2ecf20Sopenharmony_ci case E_ACCESS_PERM: 3588c2ecf20Sopenharmony_ci return RDMAP_ECODE_ACCESS_RIGHTS; 3598c2ecf20Sopenharmony_ci default: 3608c2ecf20Sopenharmony_ci return RDMAP_ECODE_UNSPECIFIED; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_civoid siw_init_terminate(struct siw_qp *qp, enum term_elayer layer, u8 etype, 3658c2ecf20Sopenharmony_ci u8 ecode, int in_tx) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci if (!qp->term_info.valid) { 3688c2ecf20Sopenharmony_ci memset(&qp->term_info, 0, sizeof(qp->term_info)); 3698c2ecf20Sopenharmony_ci qp->term_info.layer = layer; 3708c2ecf20Sopenharmony_ci qp->term_info.etype = etype; 3718c2ecf20Sopenharmony_ci qp->term_info.ecode = ecode; 3728c2ecf20Sopenharmony_ci qp->term_info.in_tx = in_tx; 3738c2ecf20Sopenharmony_ci qp->term_info.valid = 1; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "init TERM: layer %d, type %d, code %d, in tx %s\n", 3768c2ecf20Sopenharmony_ci layer, etype, ecode, in_tx ? "yes" : "no"); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci/* 3808c2ecf20Sopenharmony_ci * Send a TERMINATE message, as defined in RFC's 5040/5041/5044/6581. 3818c2ecf20Sopenharmony_ci * Sending TERMINATE messages is best effort - such messages 3828c2ecf20Sopenharmony_ci * can only be send if the QP is still connected and it does 3838c2ecf20Sopenharmony_ci * not have another outbound message in-progress, i.e. the 3848c2ecf20Sopenharmony_ci * TERMINATE message must not interfer with an incomplete current 3858c2ecf20Sopenharmony_ci * transmit operation. 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_civoid siw_send_terminate(struct siw_qp *qp) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct kvec iov[3]; 3908c2ecf20Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_EOR }; 3918c2ecf20Sopenharmony_ci struct iwarp_terminate *term = NULL; 3928c2ecf20Sopenharmony_ci union iwarp_hdr *err_hdr = NULL; 3938c2ecf20Sopenharmony_ci struct socket *s = qp->attrs.sk; 3948c2ecf20Sopenharmony_ci struct siw_rx_stream *srx = &qp->rx_stream; 3958c2ecf20Sopenharmony_ci union iwarp_hdr *rx_hdr = &srx->hdr; 3968c2ecf20Sopenharmony_ci u32 crc = 0; 3978c2ecf20Sopenharmony_ci int num_frags, len_terminate, rv; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (!qp->term_info.valid) 4008c2ecf20Sopenharmony_ci return; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci qp->term_info.valid = 0; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (tx_wqe(qp)->wr_status == SIW_WR_INPROGRESS) { 4058c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "cannot send TERMINATE: op %d in progress\n", 4068c2ecf20Sopenharmony_ci tx_type(tx_wqe(qp))); 4078c2ecf20Sopenharmony_ci return; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci if (!s && qp->cep) 4108c2ecf20Sopenharmony_ci /* QP not yet in RTS. Take socket from connection end point */ 4118c2ecf20Sopenharmony_ci s = qp->cep->sock; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (!s) { 4148c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "cannot send TERMINATE: not connected\n"); 4158c2ecf20Sopenharmony_ci return; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci term = kzalloc(sizeof(*term), GFP_KERNEL); 4198c2ecf20Sopenharmony_ci if (!term) 4208c2ecf20Sopenharmony_ci return; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci term->ddp_qn = cpu_to_be32(RDMAP_UNTAGGED_QN_TERMINATE); 4238c2ecf20Sopenharmony_ci term->ddp_mo = 0; 4248c2ecf20Sopenharmony_ci term->ddp_msn = cpu_to_be32(1); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci iov[0].iov_base = term; 4278c2ecf20Sopenharmony_ci iov[0].iov_len = sizeof(*term); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if ((qp->term_info.layer == TERM_ERROR_LAYER_DDP) || 4308c2ecf20Sopenharmony_ci ((qp->term_info.layer == TERM_ERROR_LAYER_RDMAP) && 4318c2ecf20Sopenharmony_ci (qp->term_info.etype != RDMAP_ETYPE_CATASTROPHIC))) { 4328c2ecf20Sopenharmony_ci err_hdr = kzalloc(sizeof(*err_hdr), GFP_KERNEL); 4338c2ecf20Sopenharmony_ci if (!err_hdr) { 4348c2ecf20Sopenharmony_ci kfree(term); 4358c2ecf20Sopenharmony_ci return; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci memcpy(&term->ctrl, &iwarp_pktinfo[RDMAP_TERMINATE].ctrl, 4398c2ecf20Sopenharmony_ci sizeof(struct iwarp_ctrl)); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci __rdmap_term_set_layer(term, qp->term_info.layer); 4428c2ecf20Sopenharmony_ci __rdmap_term_set_etype(term, qp->term_info.etype); 4438c2ecf20Sopenharmony_ci __rdmap_term_set_ecode(term, qp->term_info.ecode); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci switch (qp->term_info.layer) { 4468c2ecf20Sopenharmony_ci case TERM_ERROR_LAYER_RDMAP: 4478c2ecf20Sopenharmony_ci if (qp->term_info.etype == RDMAP_ETYPE_CATASTROPHIC) 4488c2ecf20Sopenharmony_ci /* No additional DDP/RDMAP header to be included */ 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (qp->term_info.etype == RDMAP_ETYPE_REMOTE_PROTECTION) { 4528c2ecf20Sopenharmony_ci /* 4538c2ecf20Sopenharmony_ci * Complete RDMAP frame will get attached, and 4548c2ecf20Sopenharmony_ci * DDP segment length is valid 4558c2ecf20Sopenharmony_ci */ 4568c2ecf20Sopenharmony_ci term->flag_m = 1; 4578c2ecf20Sopenharmony_ci term->flag_d = 1; 4588c2ecf20Sopenharmony_ci term->flag_r = 1; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (qp->term_info.in_tx) { 4618c2ecf20Sopenharmony_ci struct iwarp_rdma_rreq *rreq; 4628c2ecf20Sopenharmony_ci struct siw_wqe *wqe = tx_wqe(qp); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* Inbound RREQ error, detected during 4658c2ecf20Sopenharmony_ci * RRESP creation. Take state from 4668c2ecf20Sopenharmony_ci * current TX work queue element to 4678c2ecf20Sopenharmony_ci * reconstruct peers RREQ. 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_ci rreq = (struct iwarp_rdma_rreq *)err_hdr; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci memcpy(&rreq->ctrl, 4728c2ecf20Sopenharmony_ci &iwarp_pktinfo[RDMAP_RDMA_READ_REQ].ctrl, 4738c2ecf20Sopenharmony_ci sizeof(struct iwarp_ctrl)); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci rreq->rsvd = 0; 4768c2ecf20Sopenharmony_ci rreq->ddp_qn = 4778c2ecf20Sopenharmony_ci htonl(RDMAP_UNTAGGED_QN_RDMA_READ); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* Provide RREQ's MSN as kept aside */ 4808c2ecf20Sopenharmony_ci rreq->ddp_msn = htonl(wqe->sqe.sge[0].length); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci rreq->ddp_mo = htonl(wqe->processed); 4838c2ecf20Sopenharmony_ci rreq->sink_stag = htonl(wqe->sqe.rkey); 4848c2ecf20Sopenharmony_ci rreq->sink_to = cpu_to_be64(wqe->sqe.raddr); 4858c2ecf20Sopenharmony_ci rreq->read_size = htonl(wqe->sqe.sge[0].length); 4868c2ecf20Sopenharmony_ci rreq->source_stag = htonl(wqe->sqe.sge[0].lkey); 4878c2ecf20Sopenharmony_ci rreq->source_to = 4888c2ecf20Sopenharmony_ci cpu_to_be64(wqe->sqe.sge[0].laddr); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci iov[1].iov_base = rreq; 4918c2ecf20Sopenharmony_ci iov[1].iov_len = sizeof(*rreq); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci rx_hdr = (union iwarp_hdr *)rreq; 4948c2ecf20Sopenharmony_ci } else { 4958c2ecf20Sopenharmony_ci /* Take RDMAP/DDP information from 4968c2ecf20Sopenharmony_ci * current (failed) inbound frame. 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_ci iov[1].iov_base = rx_hdr; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (__rdmap_get_opcode(&rx_hdr->ctrl) == 5018c2ecf20Sopenharmony_ci RDMAP_RDMA_READ_REQ) 5028c2ecf20Sopenharmony_ci iov[1].iov_len = 5038c2ecf20Sopenharmony_ci sizeof(struct iwarp_rdma_rreq); 5048c2ecf20Sopenharmony_ci else /* SEND type */ 5058c2ecf20Sopenharmony_ci iov[1].iov_len = 5068c2ecf20Sopenharmony_ci sizeof(struct iwarp_send); 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci } else { 5098c2ecf20Sopenharmony_ci /* Do not report DDP hdr information if packet 5108c2ecf20Sopenharmony_ci * layout is unknown 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_ci if ((qp->term_info.ecode == RDMAP_ECODE_VERSION) || 5138c2ecf20Sopenharmony_ci (qp->term_info.ecode == RDMAP_ECODE_OPCODE)) 5148c2ecf20Sopenharmony_ci break; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci iov[1].iov_base = rx_hdr; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* Only DDP frame will get attached */ 5198c2ecf20Sopenharmony_ci if (rx_hdr->ctrl.ddp_rdmap_ctrl & DDP_FLAG_TAGGED) 5208c2ecf20Sopenharmony_ci iov[1].iov_len = 5218c2ecf20Sopenharmony_ci sizeof(struct iwarp_rdma_write); 5228c2ecf20Sopenharmony_ci else 5238c2ecf20Sopenharmony_ci iov[1].iov_len = sizeof(struct iwarp_send); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci term->flag_m = 1; 5268c2ecf20Sopenharmony_ci term->flag_d = 1; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci term->ctrl.mpa_len = cpu_to_be16(iov[1].iov_len); 5298c2ecf20Sopenharmony_ci break; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci case TERM_ERROR_LAYER_DDP: 5328c2ecf20Sopenharmony_ci /* Report error encountered while DDP processing. 5338c2ecf20Sopenharmony_ci * This can only happen as a result of inbound 5348c2ecf20Sopenharmony_ci * DDP processing 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* Do not report DDP hdr information if packet 5388c2ecf20Sopenharmony_ci * layout is unknown 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_ci if (((qp->term_info.etype == DDP_ETYPE_TAGGED_BUF) && 5418c2ecf20Sopenharmony_ci (qp->term_info.ecode == DDP_ECODE_T_VERSION)) || 5428c2ecf20Sopenharmony_ci ((qp->term_info.etype == DDP_ETYPE_UNTAGGED_BUF) && 5438c2ecf20Sopenharmony_ci (qp->term_info.ecode == DDP_ECODE_UT_VERSION))) 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci iov[1].iov_base = rx_hdr; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (rx_hdr->ctrl.ddp_rdmap_ctrl & DDP_FLAG_TAGGED) 5498c2ecf20Sopenharmony_ci iov[1].iov_len = sizeof(struct iwarp_ctrl_tagged); 5508c2ecf20Sopenharmony_ci else 5518c2ecf20Sopenharmony_ci iov[1].iov_len = sizeof(struct iwarp_ctrl_untagged); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci term->flag_m = 1; 5548c2ecf20Sopenharmony_ci term->flag_d = 1; 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci default: 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci if (term->flag_m || term->flag_d || term->flag_r) { 5618c2ecf20Sopenharmony_ci iov[2].iov_base = &crc; 5628c2ecf20Sopenharmony_ci iov[2].iov_len = sizeof(crc); 5638c2ecf20Sopenharmony_ci len_terminate = sizeof(*term) + iov[1].iov_len + MPA_CRC_SIZE; 5648c2ecf20Sopenharmony_ci num_frags = 3; 5658c2ecf20Sopenharmony_ci } else { 5668c2ecf20Sopenharmony_ci iov[1].iov_base = &crc; 5678c2ecf20Sopenharmony_ci iov[1].iov_len = sizeof(crc); 5688c2ecf20Sopenharmony_ci len_terminate = sizeof(*term) + MPA_CRC_SIZE; 5698c2ecf20Sopenharmony_ci num_frags = 2; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* Adjust DDP Segment Length parameter, if valid */ 5738c2ecf20Sopenharmony_ci if (term->flag_m) { 5748c2ecf20Sopenharmony_ci u32 real_ddp_len = be16_to_cpu(rx_hdr->ctrl.mpa_len); 5758c2ecf20Sopenharmony_ci enum rdma_opcode op = __rdmap_get_opcode(&rx_hdr->ctrl); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci real_ddp_len -= iwarp_pktinfo[op].hdr_len - MPA_HDR_SIZE; 5788c2ecf20Sopenharmony_ci rx_hdr->ctrl.mpa_len = cpu_to_be16(real_ddp_len); 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci term->ctrl.mpa_len = 5828c2ecf20Sopenharmony_ci cpu_to_be16(len_terminate - (MPA_HDR_SIZE + MPA_CRC_SIZE)); 5838c2ecf20Sopenharmony_ci if (qp->tx_ctx.mpa_crc_hd) { 5848c2ecf20Sopenharmony_ci crypto_shash_init(qp->tx_ctx.mpa_crc_hd); 5858c2ecf20Sopenharmony_ci if (crypto_shash_update(qp->tx_ctx.mpa_crc_hd, 5868c2ecf20Sopenharmony_ci (u8 *)iov[0].iov_base, 5878c2ecf20Sopenharmony_ci iov[0].iov_len)) 5888c2ecf20Sopenharmony_ci goto out; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (num_frags == 3) { 5918c2ecf20Sopenharmony_ci if (crypto_shash_update(qp->tx_ctx.mpa_crc_hd, 5928c2ecf20Sopenharmony_ci (u8 *)iov[1].iov_base, 5938c2ecf20Sopenharmony_ci iov[1].iov_len)) 5948c2ecf20Sopenharmony_ci goto out; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci crypto_shash_final(qp->tx_ctx.mpa_crc_hd, (u8 *)&crc); 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci rv = kernel_sendmsg(s, &msg, iov, num_frags, len_terminate); 6008c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "sent TERM: %s, layer %d, type %d, code %d (%d bytes)\n", 6018c2ecf20Sopenharmony_ci rv == len_terminate ? "success" : "failure", 6028c2ecf20Sopenharmony_ci __rdmap_term_layer(term), __rdmap_term_etype(term), 6038c2ecf20Sopenharmony_ci __rdmap_term_ecode(term), rv); 6048c2ecf20Sopenharmony_ciout: 6058c2ecf20Sopenharmony_ci kfree(term); 6068c2ecf20Sopenharmony_ci kfree(err_hdr); 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci/* 6108c2ecf20Sopenharmony_ci * Handle all attrs other than state 6118c2ecf20Sopenharmony_ci */ 6128c2ecf20Sopenharmony_cistatic void siw_qp_modify_nonstate(struct siw_qp *qp, 6138c2ecf20Sopenharmony_ci struct siw_qp_attrs *attrs, 6148c2ecf20Sopenharmony_ci enum siw_qp_attr_mask mask) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci if (mask & SIW_QP_ATTR_ACCESS_FLAGS) { 6178c2ecf20Sopenharmony_ci if (attrs->flags & SIW_RDMA_BIND_ENABLED) 6188c2ecf20Sopenharmony_ci qp->attrs.flags |= SIW_RDMA_BIND_ENABLED; 6198c2ecf20Sopenharmony_ci else 6208c2ecf20Sopenharmony_ci qp->attrs.flags &= ~SIW_RDMA_BIND_ENABLED; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (attrs->flags & SIW_RDMA_WRITE_ENABLED) 6238c2ecf20Sopenharmony_ci qp->attrs.flags |= SIW_RDMA_WRITE_ENABLED; 6248c2ecf20Sopenharmony_ci else 6258c2ecf20Sopenharmony_ci qp->attrs.flags &= ~SIW_RDMA_WRITE_ENABLED; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (attrs->flags & SIW_RDMA_READ_ENABLED) 6288c2ecf20Sopenharmony_ci qp->attrs.flags |= SIW_RDMA_READ_ENABLED; 6298c2ecf20Sopenharmony_ci else 6308c2ecf20Sopenharmony_ci qp->attrs.flags &= ~SIW_RDMA_READ_ENABLED; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic int siw_qp_nextstate_from_idle(struct siw_qp *qp, 6358c2ecf20Sopenharmony_ci struct siw_qp_attrs *attrs, 6368c2ecf20Sopenharmony_ci enum siw_qp_attr_mask mask) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci int rv = 0; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci switch (attrs->state) { 6418c2ecf20Sopenharmony_ci case SIW_QP_STATE_RTS: 6428c2ecf20Sopenharmony_ci if (attrs->flags & SIW_MPA_CRC) { 6438c2ecf20Sopenharmony_ci rv = siw_qp_enable_crc(qp); 6448c2ecf20Sopenharmony_ci if (rv) 6458c2ecf20Sopenharmony_ci break; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci if (!(mask & SIW_QP_ATTR_LLP_HANDLE)) { 6488c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "no socket\n"); 6498c2ecf20Sopenharmony_ci rv = -EINVAL; 6508c2ecf20Sopenharmony_ci break; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci if (!(mask & SIW_QP_ATTR_MPA)) { 6538c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "no MPA\n"); 6548c2ecf20Sopenharmony_ci rv = -EINVAL; 6558c2ecf20Sopenharmony_ci break; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci /* 6588c2ecf20Sopenharmony_ci * Initialize iWARP TX state 6598c2ecf20Sopenharmony_ci */ 6608c2ecf20Sopenharmony_ci qp->tx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_SEND] = 0; 6618c2ecf20Sopenharmony_ci qp->tx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ] = 0; 6628c2ecf20Sopenharmony_ci qp->tx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_TERMINATE] = 0; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* 6658c2ecf20Sopenharmony_ci * Initialize iWARP RX state 6668c2ecf20Sopenharmony_ci */ 6678c2ecf20Sopenharmony_ci qp->rx_stream.ddp_msn[RDMAP_UNTAGGED_QN_SEND] = 1; 6688c2ecf20Sopenharmony_ci qp->rx_stream.ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ] = 1; 6698c2ecf20Sopenharmony_ci qp->rx_stream.ddp_msn[RDMAP_UNTAGGED_QN_TERMINATE] = 1; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* 6728c2ecf20Sopenharmony_ci * init IRD free queue, caller has already checked 6738c2ecf20Sopenharmony_ci * limits. 6748c2ecf20Sopenharmony_ci */ 6758c2ecf20Sopenharmony_ci rv = siw_qp_readq_init(qp, attrs->irq_size, 6768c2ecf20Sopenharmony_ci attrs->orq_size); 6778c2ecf20Sopenharmony_ci if (rv) 6788c2ecf20Sopenharmony_ci break; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci qp->attrs.sk = attrs->sk; 6818c2ecf20Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_RTS; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "enter RTS: crc=%s, ord=%u, ird=%u\n", 6848c2ecf20Sopenharmony_ci attrs->flags & SIW_MPA_CRC ? "y" : "n", 6858c2ecf20Sopenharmony_ci qp->attrs.orq_size, qp->attrs.irq_size); 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci case SIW_QP_STATE_ERROR: 6898c2ecf20Sopenharmony_ci siw_rq_flush(qp); 6908c2ecf20Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 6918c2ecf20Sopenharmony_ci if (qp->cep) { 6928c2ecf20Sopenharmony_ci siw_cep_put(qp->cep); 6938c2ecf20Sopenharmony_ci qp->cep = NULL; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci break; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci default: 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci return rv; 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic int siw_qp_nextstate_from_rts(struct siw_qp *qp, 7048c2ecf20Sopenharmony_ci struct siw_qp_attrs *attrs) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci int drop_conn = 0; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci switch (attrs->state) { 7098c2ecf20Sopenharmony_ci case SIW_QP_STATE_CLOSING: 7108c2ecf20Sopenharmony_ci /* 7118c2ecf20Sopenharmony_ci * Verbs: move to IDLE if SQ and ORQ are empty. 7128c2ecf20Sopenharmony_ci * Move to ERROR otherwise. But first of all we must 7138c2ecf20Sopenharmony_ci * close the connection. So we keep CLOSING or ERROR 7148c2ecf20Sopenharmony_ci * as a transient state, schedule connection drop work 7158c2ecf20Sopenharmony_ci * and wait for the socket state change upcall to 7168c2ecf20Sopenharmony_ci * come back closed. 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_ci if (tx_wqe(qp)->wr_status == SIW_WR_IDLE) { 7198c2ecf20Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_CLOSING; 7208c2ecf20Sopenharmony_ci } else { 7218c2ecf20Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 7228c2ecf20Sopenharmony_ci siw_sq_flush(qp); 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci siw_rq_flush(qp); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci drop_conn = 1; 7278c2ecf20Sopenharmony_ci break; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci case SIW_QP_STATE_TERMINATE: 7308c2ecf20Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_TERMINATE; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP, 7338c2ecf20Sopenharmony_ci RDMAP_ETYPE_CATASTROPHIC, 7348c2ecf20Sopenharmony_ci RDMAP_ECODE_UNSPECIFIED, 1); 7358c2ecf20Sopenharmony_ci drop_conn = 1; 7368c2ecf20Sopenharmony_ci break; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci case SIW_QP_STATE_ERROR: 7398c2ecf20Sopenharmony_ci /* 7408c2ecf20Sopenharmony_ci * This is an emergency close. 7418c2ecf20Sopenharmony_ci * 7428c2ecf20Sopenharmony_ci * Any in progress transmit operation will get 7438c2ecf20Sopenharmony_ci * cancelled. 7448c2ecf20Sopenharmony_ci * This will likely result in a protocol failure, 7458c2ecf20Sopenharmony_ci * if a TX operation is in transit. The caller 7468c2ecf20Sopenharmony_ci * could unconditional wait to give the current 7478c2ecf20Sopenharmony_ci * operation a chance to complete. 7488c2ecf20Sopenharmony_ci * Esp., how to handle the non-empty IRQ case? 7498c2ecf20Sopenharmony_ci * The peer was asking for data transfer at a valid 7508c2ecf20Sopenharmony_ci * point in time. 7518c2ecf20Sopenharmony_ci */ 7528c2ecf20Sopenharmony_ci siw_sq_flush(qp); 7538c2ecf20Sopenharmony_ci siw_rq_flush(qp); 7548c2ecf20Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 7558c2ecf20Sopenharmony_ci drop_conn = 1; 7568c2ecf20Sopenharmony_ci break; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci default: 7598c2ecf20Sopenharmony_ci break; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci return drop_conn; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic void siw_qp_nextstate_from_term(struct siw_qp *qp, 7658c2ecf20Sopenharmony_ci struct siw_qp_attrs *attrs) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci switch (attrs->state) { 7688c2ecf20Sopenharmony_ci case SIW_QP_STATE_ERROR: 7698c2ecf20Sopenharmony_ci siw_rq_flush(qp); 7708c2ecf20Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (tx_wqe(qp)->wr_status != SIW_WR_IDLE) 7738c2ecf20Sopenharmony_ci siw_sq_flush(qp); 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci default: 7778c2ecf20Sopenharmony_ci break; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic int siw_qp_nextstate_from_close(struct siw_qp *qp, 7828c2ecf20Sopenharmony_ci struct siw_qp_attrs *attrs) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci int rv = 0; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci switch (attrs->state) { 7878c2ecf20Sopenharmony_ci case SIW_QP_STATE_IDLE: 7888c2ecf20Sopenharmony_ci WARN_ON(tx_wqe(qp)->wr_status != SIW_WR_IDLE); 7898c2ecf20Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_IDLE; 7908c2ecf20Sopenharmony_ci break; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci case SIW_QP_STATE_CLOSING: 7938c2ecf20Sopenharmony_ci /* 7948c2ecf20Sopenharmony_ci * The LLP may already moved the QP to closing 7958c2ecf20Sopenharmony_ci * due to graceful peer close init 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci case SIW_QP_STATE_ERROR: 8008c2ecf20Sopenharmony_ci /* 8018c2ecf20Sopenharmony_ci * QP was moved to CLOSING by LLP event 8028c2ecf20Sopenharmony_ci * not yet seen by user. 8038c2ecf20Sopenharmony_ci */ 8048c2ecf20Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (tx_wqe(qp)->wr_status != SIW_WR_IDLE) 8078c2ecf20Sopenharmony_ci siw_sq_flush(qp); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci siw_rq_flush(qp); 8108c2ecf20Sopenharmony_ci break; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci default: 8138c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "state transition undefined: %s => %s\n", 8148c2ecf20Sopenharmony_ci siw_qp_state_to_string[qp->attrs.state], 8158c2ecf20Sopenharmony_ci siw_qp_state_to_string[attrs->state]); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci rv = -ECONNABORTED; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci return rv; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci/* 8238c2ecf20Sopenharmony_ci * Caller must hold qp->state_lock 8248c2ecf20Sopenharmony_ci */ 8258c2ecf20Sopenharmony_ciint siw_qp_modify(struct siw_qp *qp, struct siw_qp_attrs *attrs, 8268c2ecf20Sopenharmony_ci enum siw_qp_attr_mask mask) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci int drop_conn = 0, rv = 0; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (!mask) 8318c2ecf20Sopenharmony_ci return 0; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "state: %s => %s\n", 8348c2ecf20Sopenharmony_ci siw_qp_state_to_string[qp->attrs.state], 8358c2ecf20Sopenharmony_ci siw_qp_state_to_string[attrs->state]); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (mask != SIW_QP_ATTR_STATE) 8388c2ecf20Sopenharmony_ci siw_qp_modify_nonstate(qp, attrs, mask); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci if (!(mask & SIW_QP_ATTR_STATE)) 8418c2ecf20Sopenharmony_ci return 0; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci switch (qp->attrs.state) { 8448c2ecf20Sopenharmony_ci case SIW_QP_STATE_IDLE: 8458c2ecf20Sopenharmony_ci case SIW_QP_STATE_RTR: 8468c2ecf20Sopenharmony_ci rv = siw_qp_nextstate_from_idle(qp, attrs, mask); 8478c2ecf20Sopenharmony_ci break; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci case SIW_QP_STATE_RTS: 8508c2ecf20Sopenharmony_ci drop_conn = siw_qp_nextstate_from_rts(qp, attrs); 8518c2ecf20Sopenharmony_ci break; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci case SIW_QP_STATE_TERMINATE: 8548c2ecf20Sopenharmony_ci siw_qp_nextstate_from_term(qp, attrs); 8558c2ecf20Sopenharmony_ci break; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci case SIW_QP_STATE_CLOSING: 8588c2ecf20Sopenharmony_ci siw_qp_nextstate_from_close(qp, attrs); 8598c2ecf20Sopenharmony_ci break; 8608c2ecf20Sopenharmony_ci default: 8618c2ecf20Sopenharmony_ci break; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci if (drop_conn) 8648c2ecf20Sopenharmony_ci siw_qp_cm_drop(qp, 0); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci return rv; 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_civoid siw_read_to_orq(struct siw_sqe *rreq, struct siw_sqe *sqe) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci rreq->id = sqe->id; 8728c2ecf20Sopenharmony_ci rreq->opcode = sqe->opcode; 8738c2ecf20Sopenharmony_ci rreq->sge[0].laddr = sqe->sge[0].laddr; 8748c2ecf20Sopenharmony_ci rreq->sge[0].length = sqe->sge[0].length; 8758c2ecf20Sopenharmony_ci rreq->sge[0].lkey = sqe->sge[0].lkey; 8768c2ecf20Sopenharmony_ci rreq->sge[1].lkey = sqe->sge[1].lkey; 8778c2ecf20Sopenharmony_ci rreq->flags = sqe->flags | SIW_WQE_VALID; 8788c2ecf20Sopenharmony_ci rreq->num_sge = 1; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic int siw_activate_tx_from_sq(struct siw_qp *qp) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci struct siw_sqe *sqe; 8848c2ecf20Sopenharmony_ci struct siw_wqe *wqe = tx_wqe(qp); 8858c2ecf20Sopenharmony_ci int rv = 1; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci sqe = sq_get_next(qp); 8888c2ecf20Sopenharmony_ci if (!sqe) 8898c2ecf20Sopenharmony_ci return 0; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE); 8928c2ecf20Sopenharmony_ci wqe->wr_status = SIW_WR_QUEUED; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* First copy SQE to kernel private memory */ 8958c2ecf20Sopenharmony_ci memcpy(&wqe->sqe, sqe, sizeof(*sqe)); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci if (wqe->sqe.opcode >= SIW_NUM_OPCODES) { 8988c2ecf20Sopenharmony_ci rv = -EINVAL; 8998c2ecf20Sopenharmony_ci goto out; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci if (wqe->sqe.flags & SIW_WQE_INLINE) { 9028c2ecf20Sopenharmony_ci if (wqe->sqe.opcode != SIW_OP_SEND && 9038c2ecf20Sopenharmony_ci wqe->sqe.opcode != SIW_OP_WRITE) { 9048c2ecf20Sopenharmony_ci rv = -EINVAL; 9058c2ecf20Sopenharmony_ci goto out; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci if (wqe->sqe.sge[0].length > SIW_MAX_INLINE) { 9088c2ecf20Sopenharmony_ci rv = -EINVAL; 9098c2ecf20Sopenharmony_ci goto out; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci wqe->sqe.sge[0].laddr = (uintptr_t)&wqe->sqe.sge[1]; 9128c2ecf20Sopenharmony_ci wqe->sqe.sge[0].lkey = 0; 9138c2ecf20Sopenharmony_ci wqe->sqe.num_sge = 1; 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci if (wqe->sqe.flags & SIW_WQE_READ_FENCE) { 9168c2ecf20Sopenharmony_ci /* A READ cannot be fenced */ 9178c2ecf20Sopenharmony_ci if (unlikely(wqe->sqe.opcode == SIW_OP_READ || 9188c2ecf20Sopenharmony_ci wqe->sqe.opcode == 9198c2ecf20Sopenharmony_ci SIW_OP_READ_LOCAL_INV)) { 9208c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "cannot fence read\n"); 9218c2ecf20Sopenharmony_ci rv = -EINVAL; 9228c2ecf20Sopenharmony_ci goto out; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci spin_lock(&qp->orq_lock); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (qp->attrs.orq_size && !siw_orq_empty(qp)) { 9278c2ecf20Sopenharmony_ci qp->tx_ctx.orq_fence = 1; 9288c2ecf20Sopenharmony_ci rv = 0; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci spin_unlock(&qp->orq_lock); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci } else if (wqe->sqe.opcode == SIW_OP_READ || 9338c2ecf20Sopenharmony_ci wqe->sqe.opcode == SIW_OP_READ_LOCAL_INV) { 9348c2ecf20Sopenharmony_ci struct siw_sqe *rreq; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (unlikely(!qp->attrs.orq_size)) { 9378c2ecf20Sopenharmony_ci /* We negotiated not to send READ req's */ 9388c2ecf20Sopenharmony_ci rv = -EINVAL; 9398c2ecf20Sopenharmony_ci goto out; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci wqe->sqe.num_sge = 1; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci spin_lock(&qp->orq_lock); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci rreq = orq_get_free(qp); 9468c2ecf20Sopenharmony_ci if (rreq) { 9478c2ecf20Sopenharmony_ci /* 9488c2ecf20Sopenharmony_ci * Make an immediate copy in ORQ to be ready 9498c2ecf20Sopenharmony_ci * to process loopback READ reply 9508c2ecf20Sopenharmony_ci */ 9518c2ecf20Sopenharmony_ci siw_read_to_orq(rreq, &wqe->sqe); 9528c2ecf20Sopenharmony_ci qp->orq_put++; 9538c2ecf20Sopenharmony_ci } else { 9548c2ecf20Sopenharmony_ci qp->tx_ctx.orq_fence = 1; 9558c2ecf20Sopenharmony_ci rv = 0; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci spin_unlock(&qp->orq_lock); 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* Clear SQE, can be re-used by application */ 9618c2ecf20Sopenharmony_ci smp_store_mb(sqe->flags, 0); 9628c2ecf20Sopenharmony_ci qp->sq_get++; 9638c2ecf20Sopenharmony_ciout: 9648c2ecf20Sopenharmony_ci if (unlikely(rv < 0)) { 9658c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "error %d\n", rv); 9668c2ecf20Sopenharmony_ci wqe->wr_status = SIW_WR_IDLE; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci return rv; 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci/* 9728c2ecf20Sopenharmony_ci * Must be called with SQ locked. 9738c2ecf20Sopenharmony_ci * To avoid complete SQ starvation by constant inbound READ requests, 9748c2ecf20Sopenharmony_ci * the active IRQ will not be served after qp->irq_burst, if the 9758c2ecf20Sopenharmony_ci * SQ has pending work. 9768c2ecf20Sopenharmony_ci */ 9778c2ecf20Sopenharmony_ciint siw_activate_tx(struct siw_qp *qp) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci struct siw_sqe *irqe; 9808c2ecf20Sopenharmony_ci struct siw_wqe *wqe = tx_wqe(qp); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (!qp->attrs.irq_size) 9838c2ecf20Sopenharmony_ci return siw_activate_tx_from_sq(qp); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci irqe = &qp->irq[qp->irq_get % qp->attrs.irq_size]; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci if (!(irqe->flags & SIW_WQE_VALID)) 9888c2ecf20Sopenharmony_ci return siw_activate_tx_from_sq(qp); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* 9918c2ecf20Sopenharmony_ci * Avoid local WQE processing starvation in case 9928c2ecf20Sopenharmony_ci * of constant inbound READ request stream 9938c2ecf20Sopenharmony_ci */ 9948c2ecf20Sopenharmony_ci if (sq_get_next(qp) && ++qp->irq_burst >= SIW_IRQ_MAXBURST_SQ_ACTIVE) { 9958c2ecf20Sopenharmony_ci qp->irq_burst = 0; 9968c2ecf20Sopenharmony_ci return siw_activate_tx_from_sq(qp); 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE); 9998c2ecf20Sopenharmony_ci wqe->wr_status = SIW_WR_QUEUED; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* start READ RESPONSE */ 10028c2ecf20Sopenharmony_ci wqe->sqe.opcode = SIW_OP_READ_RESPONSE; 10038c2ecf20Sopenharmony_ci wqe->sqe.flags = 0; 10048c2ecf20Sopenharmony_ci if (irqe->num_sge) { 10058c2ecf20Sopenharmony_ci wqe->sqe.num_sge = 1; 10068c2ecf20Sopenharmony_ci wqe->sqe.sge[0].length = irqe->sge[0].length; 10078c2ecf20Sopenharmony_ci wqe->sqe.sge[0].laddr = irqe->sge[0].laddr; 10088c2ecf20Sopenharmony_ci wqe->sqe.sge[0].lkey = irqe->sge[0].lkey; 10098c2ecf20Sopenharmony_ci } else { 10108c2ecf20Sopenharmony_ci wqe->sqe.num_sge = 0; 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci /* Retain original RREQ's message sequence number for 10148c2ecf20Sopenharmony_ci * potential error reporting cases. 10158c2ecf20Sopenharmony_ci */ 10168c2ecf20Sopenharmony_ci wqe->sqe.sge[1].length = irqe->sge[1].length; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci wqe->sqe.rkey = irqe->rkey; 10198c2ecf20Sopenharmony_ci wqe->sqe.raddr = irqe->raddr; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci wqe->processed = 0; 10228c2ecf20Sopenharmony_ci qp->irq_get++; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci /* mark current IRQ entry free */ 10258c2ecf20Sopenharmony_ci smp_store_mb(irqe->flags, 0); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci return 1; 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci/* 10318c2ecf20Sopenharmony_ci * Check if current CQ state qualifies for calling CQ completion 10328c2ecf20Sopenharmony_ci * handler. Must be called with CQ lock held. 10338c2ecf20Sopenharmony_ci */ 10348c2ecf20Sopenharmony_cistatic bool siw_cq_notify_now(struct siw_cq *cq, u32 flags) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci u32 cq_notify; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci if (!cq->base_cq.comp_handler) 10398c2ecf20Sopenharmony_ci return false; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* Read application shared notification state */ 10428c2ecf20Sopenharmony_ci cq_notify = READ_ONCE(cq->notify->flags); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if ((cq_notify & SIW_NOTIFY_NEXT_COMPLETION) || 10458c2ecf20Sopenharmony_ci ((cq_notify & SIW_NOTIFY_SOLICITED) && 10468c2ecf20Sopenharmony_ci (flags & SIW_WQE_SOLICITED))) { 10478c2ecf20Sopenharmony_ci /* 10488c2ecf20Sopenharmony_ci * CQ notification is one-shot: Since the 10498c2ecf20Sopenharmony_ci * current CQE causes user notification, 10508c2ecf20Sopenharmony_ci * the CQ gets dis-aremd and must be re-aremd 10518c2ecf20Sopenharmony_ci * by the user for a new notification. 10528c2ecf20Sopenharmony_ci */ 10538c2ecf20Sopenharmony_ci WRITE_ONCE(cq->notify->flags, SIW_NOTIFY_NOT); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci return true; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci return false; 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ciint siw_sqe_complete(struct siw_qp *qp, struct siw_sqe *sqe, u32 bytes, 10618c2ecf20Sopenharmony_ci enum siw_wc_status status) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci struct siw_cq *cq = qp->scq; 10648c2ecf20Sopenharmony_ci int rv = 0; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci if (cq) { 10678c2ecf20Sopenharmony_ci u32 sqe_flags = sqe->flags; 10688c2ecf20Sopenharmony_ci struct siw_cqe *cqe; 10698c2ecf20Sopenharmony_ci u32 idx; 10708c2ecf20Sopenharmony_ci unsigned long flags; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci spin_lock_irqsave(&cq->lock, flags); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci idx = cq->cq_put % cq->num_cqe; 10758c2ecf20Sopenharmony_ci cqe = &cq->queue[idx]; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci if (!READ_ONCE(cqe->flags)) { 10788c2ecf20Sopenharmony_ci bool notify; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci cqe->id = sqe->id; 10818c2ecf20Sopenharmony_ci cqe->opcode = sqe->opcode; 10828c2ecf20Sopenharmony_ci cqe->status = status; 10838c2ecf20Sopenharmony_ci cqe->imm_data = 0; 10848c2ecf20Sopenharmony_ci cqe->bytes = bytes; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci if (rdma_is_kernel_res(&cq->base_cq.res)) 10878c2ecf20Sopenharmony_ci cqe->base_qp = &qp->base_qp; 10888c2ecf20Sopenharmony_ci else 10898c2ecf20Sopenharmony_ci cqe->qp_id = qp_id(qp); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci /* mark CQE valid for application */ 10928c2ecf20Sopenharmony_ci WRITE_ONCE(cqe->flags, SIW_WQE_VALID); 10938c2ecf20Sopenharmony_ci /* recycle SQE */ 10948c2ecf20Sopenharmony_ci smp_store_mb(sqe->flags, 0); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci cq->cq_put++; 10978c2ecf20Sopenharmony_ci notify = siw_cq_notify_now(cq, sqe_flags); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cq->lock, flags); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci if (notify) { 11028c2ecf20Sopenharmony_ci siw_dbg_cq(cq, "Call completion handler\n"); 11038c2ecf20Sopenharmony_ci cq->base_cq.comp_handler(&cq->base_cq, 11048c2ecf20Sopenharmony_ci cq->base_cq.cq_context); 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci } else { 11078c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cq->lock, flags); 11088c2ecf20Sopenharmony_ci rv = -ENOMEM; 11098c2ecf20Sopenharmony_ci siw_cq_event(cq, IB_EVENT_CQ_ERR); 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci } else { 11128c2ecf20Sopenharmony_ci /* recycle SQE */ 11138c2ecf20Sopenharmony_ci smp_store_mb(sqe->flags, 0); 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci return rv; 11168c2ecf20Sopenharmony_ci} 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ciint siw_rqe_complete(struct siw_qp *qp, struct siw_rqe *rqe, u32 bytes, 11198c2ecf20Sopenharmony_ci u32 inval_stag, enum siw_wc_status status) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci struct siw_cq *cq = qp->rcq; 11228c2ecf20Sopenharmony_ci int rv = 0; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci if (cq) { 11258c2ecf20Sopenharmony_ci struct siw_cqe *cqe; 11268c2ecf20Sopenharmony_ci u32 idx; 11278c2ecf20Sopenharmony_ci unsigned long flags; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci spin_lock_irqsave(&cq->lock, flags); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci idx = cq->cq_put % cq->num_cqe; 11328c2ecf20Sopenharmony_ci cqe = &cq->queue[idx]; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci if (!READ_ONCE(cqe->flags)) { 11358c2ecf20Sopenharmony_ci bool notify; 11368c2ecf20Sopenharmony_ci u8 cqe_flags = SIW_WQE_VALID; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci cqe->id = rqe->id; 11398c2ecf20Sopenharmony_ci cqe->opcode = SIW_OP_RECEIVE; 11408c2ecf20Sopenharmony_ci cqe->status = status; 11418c2ecf20Sopenharmony_ci cqe->imm_data = 0; 11428c2ecf20Sopenharmony_ci cqe->bytes = bytes; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci if (rdma_is_kernel_res(&cq->base_cq.res)) { 11458c2ecf20Sopenharmony_ci cqe->base_qp = &qp->base_qp; 11468c2ecf20Sopenharmony_ci if (inval_stag) { 11478c2ecf20Sopenharmony_ci cqe_flags |= SIW_WQE_REM_INVAL; 11488c2ecf20Sopenharmony_ci cqe->inval_stag = inval_stag; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci } else { 11518c2ecf20Sopenharmony_ci cqe->qp_id = qp_id(qp); 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci /* mark CQE valid for application */ 11548c2ecf20Sopenharmony_ci WRITE_ONCE(cqe->flags, cqe_flags); 11558c2ecf20Sopenharmony_ci /* recycle RQE */ 11568c2ecf20Sopenharmony_ci smp_store_mb(rqe->flags, 0); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci cq->cq_put++; 11598c2ecf20Sopenharmony_ci notify = siw_cq_notify_now(cq, SIW_WQE_SIGNALLED); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cq->lock, flags); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci if (notify) { 11648c2ecf20Sopenharmony_ci siw_dbg_cq(cq, "Call completion handler\n"); 11658c2ecf20Sopenharmony_ci cq->base_cq.comp_handler(&cq->base_cq, 11668c2ecf20Sopenharmony_ci cq->base_cq.cq_context); 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci } else { 11698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cq->lock, flags); 11708c2ecf20Sopenharmony_ci rv = -ENOMEM; 11718c2ecf20Sopenharmony_ci siw_cq_event(cq, IB_EVENT_CQ_ERR); 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci } else { 11748c2ecf20Sopenharmony_ci /* recycle RQE */ 11758c2ecf20Sopenharmony_ci smp_store_mb(rqe->flags, 0); 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci return rv; 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci/* 11818c2ecf20Sopenharmony_ci * siw_sq_flush() 11828c2ecf20Sopenharmony_ci * 11838c2ecf20Sopenharmony_ci * Flush SQ and ORRQ entries to CQ. 11848c2ecf20Sopenharmony_ci * 11858c2ecf20Sopenharmony_ci * Must be called with QP state write lock held. 11868c2ecf20Sopenharmony_ci * Therefore, SQ and ORQ lock must not be taken. 11878c2ecf20Sopenharmony_ci */ 11888c2ecf20Sopenharmony_civoid siw_sq_flush(struct siw_qp *qp) 11898c2ecf20Sopenharmony_ci{ 11908c2ecf20Sopenharmony_ci struct siw_sqe *sqe; 11918c2ecf20Sopenharmony_ci struct siw_wqe *wqe = tx_wqe(qp); 11928c2ecf20Sopenharmony_ci int async_event = 0; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci /* 11958c2ecf20Sopenharmony_ci * Start with completing any work currently on the ORQ 11968c2ecf20Sopenharmony_ci */ 11978c2ecf20Sopenharmony_ci while (qp->attrs.orq_size) { 11988c2ecf20Sopenharmony_ci sqe = &qp->orq[qp->orq_get % qp->attrs.orq_size]; 11998c2ecf20Sopenharmony_ci if (!READ_ONCE(sqe->flags)) 12008c2ecf20Sopenharmony_ci break; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (siw_sqe_complete(qp, sqe, 0, SIW_WC_WR_FLUSH_ERR) != 0) 12038c2ecf20Sopenharmony_ci break; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci WRITE_ONCE(sqe->flags, 0); 12068c2ecf20Sopenharmony_ci qp->orq_get++; 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci /* 12098c2ecf20Sopenharmony_ci * Flush an in-progress WQE if present 12108c2ecf20Sopenharmony_ci */ 12118c2ecf20Sopenharmony_ci if (wqe->wr_status != SIW_WR_IDLE) { 12128c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "flush current SQE, type %d, status %d\n", 12138c2ecf20Sopenharmony_ci tx_type(wqe), wqe->wr_status); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci siw_wqe_put_mem(wqe, tx_type(wqe)); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (tx_type(wqe) != SIW_OP_READ_RESPONSE && 12188c2ecf20Sopenharmony_ci ((tx_type(wqe) != SIW_OP_READ && 12198c2ecf20Sopenharmony_ci tx_type(wqe) != SIW_OP_READ_LOCAL_INV) || 12208c2ecf20Sopenharmony_ci wqe->wr_status == SIW_WR_QUEUED)) 12218c2ecf20Sopenharmony_ci /* 12228c2ecf20Sopenharmony_ci * An in-progress Read Request is already in 12238c2ecf20Sopenharmony_ci * the ORQ 12248c2ecf20Sopenharmony_ci */ 12258c2ecf20Sopenharmony_ci siw_sqe_complete(qp, &wqe->sqe, wqe->bytes, 12268c2ecf20Sopenharmony_ci SIW_WC_WR_FLUSH_ERR); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci wqe->wr_status = SIW_WR_IDLE; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci /* 12318c2ecf20Sopenharmony_ci * Flush the Send Queue 12328c2ecf20Sopenharmony_ci */ 12338c2ecf20Sopenharmony_ci while (qp->attrs.sq_size) { 12348c2ecf20Sopenharmony_ci sqe = &qp->sendq[qp->sq_get % qp->attrs.sq_size]; 12358c2ecf20Sopenharmony_ci if (!READ_ONCE(sqe->flags)) 12368c2ecf20Sopenharmony_ci break; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci async_event = 1; 12398c2ecf20Sopenharmony_ci if (siw_sqe_complete(qp, sqe, 0, SIW_WC_WR_FLUSH_ERR) != 0) 12408c2ecf20Sopenharmony_ci /* 12418c2ecf20Sopenharmony_ci * Shall IB_EVENT_SQ_DRAINED be supressed if work 12428c2ecf20Sopenharmony_ci * completion fails? 12438c2ecf20Sopenharmony_ci */ 12448c2ecf20Sopenharmony_ci break; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci WRITE_ONCE(sqe->flags, 0); 12478c2ecf20Sopenharmony_ci qp->sq_get++; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci if (async_event) 12508c2ecf20Sopenharmony_ci siw_qp_event(qp, IB_EVENT_SQ_DRAINED); 12518c2ecf20Sopenharmony_ci} 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci/* 12548c2ecf20Sopenharmony_ci * siw_rq_flush() 12558c2ecf20Sopenharmony_ci * 12568c2ecf20Sopenharmony_ci * Flush recv queue entries to CQ. Also 12578c2ecf20Sopenharmony_ci * takes care of pending active tagged and untagged 12588c2ecf20Sopenharmony_ci * inbound transfers, which have target memory 12598c2ecf20Sopenharmony_ci * referenced. 12608c2ecf20Sopenharmony_ci * 12618c2ecf20Sopenharmony_ci * Must be called with QP state write lock held. 12628c2ecf20Sopenharmony_ci * Therefore, RQ lock must not be taken. 12638c2ecf20Sopenharmony_ci */ 12648c2ecf20Sopenharmony_civoid siw_rq_flush(struct siw_qp *qp) 12658c2ecf20Sopenharmony_ci{ 12668c2ecf20Sopenharmony_ci struct siw_wqe *wqe = &qp->rx_untagged.wqe_active; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci /* 12698c2ecf20Sopenharmony_ci * Flush an in-progress untagged operation if present 12708c2ecf20Sopenharmony_ci */ 12718c2ecf20Sopenharmony_ci if (wqe->wr_status != SIW_WR_IDLE) { 12728c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "flush current rqe, type %d, status %d\n", 12738c2ecf20Sopenharmony_ci rx_type(wqe), wqe->wr_status); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci siw_wqe_put_mem(wqe, rx_type(wqe)); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci if (rx_type(wqe) == SIW_OP_RECEIVE) { 12788c2ecf20Sopenharmony_ci siw_rqe_complete(qp, &wqe->rqe, wqe->bytes, 12798c2ecf20Sopenharmony_ci 0, SIW_WC_WR_FLUSH_ERR); 12808c2ecf20Sopenharmony_ci } else if (rx_type(wqe) != SIW_OP_READ && 12818c2ecf20Sopenharmony_ci rx_type(wqe) != SIW_OP_READ_RESPONSE && 12828c2ecf20Sopenharmony_ci rx_type(wqe) != SIW_OP_WRITE) { 12838c2ecf20Sopenharmony_ci siw_sqe_complete(qp, &wqe->sqe, 0, SIW_WC_WR_FLUSH_ERR); 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci wqe->wr_status = SIW_WR_IDLE; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci wqe = &qp->rx_tagged.wqe_active; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci if (wqe->wr_status != SIW_WR_IDLE) { 12908c2ecf20Sopenharmony_ci siw_wqe_put_mem(wqe, rx_type(wqe)); 12918c2ecf20Sopenharmony_ci wqe->wr_status = SIW_WR_IDLE; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci /* 12948c2ecf20Sopenharmony_ci * Flush the Receive Queue 12958c2ecf20Sopenharmony_ci */ 12968c2ecf20Sopenharmony_ci while (qp->attrs.rq_size) { 12978c2ecf20Sopenharmony_ci struct siw_rqe *rqe = 12988c2ecf20Sopenharmony_ci &qp->recvq[qp->rq_get % qp->attrs.rq_size]; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci if (!READ_ONCE(rqe->flags)) 13018c2ecf20Sopenharmony_ci break; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (siw_rqe_complete(qp, rqe, 0, 0, SIW_WC_WR_FLUSH_ERR) != 0) 13048c2ecf20Sopenharmony_ci break; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci WRITE_ONCE(rqe->flags, 0); 13078c2ecf20Sopenharmony_ci qp->rq_get++; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci} 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ciint siw_qp_add(struct siw_device *sdev, struct siw_qp *qp) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci int rv = xa_alloc(&sdev->qp_xa, &qp->base_qp.qp_num, qp, xa_limit_32b, 13148c2ecf20Sopenharmony_ci GFP_KERNEL); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (!rv) { 13178c2ecf20Sopenharmony_ci kref_init(&qp->ref); 13188c2ecf20Sopenharmony_ci qp->sdev = sdev; 13198c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "new QP\n"); 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci return rv; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_civoid siw_free_qp(struct kref *ref) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci struct siw_qp *found, *qp = container_of(ref, struct siw_qp, ref); 13278c2ecf20Sopenharmony_ci struct siw_device *sdev = qp->sdev; 13288c2ecf20Sopenharmony_ci unsigned long flags; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci if (qp->cep) 13318c2ecf20Sopenharmony_ci siw_cep_put(qp->cep); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci found = xa_erase(&sdev->qp_xa, qp_id(qp)); 13348c2ecf20Sopenharmony_ci WARN_ON(found != qp); 13358c2ecf20Sopenharmony_ci spin_lock_irqsave(&sdev->lock, flags); 13368c2ecf20Sopenharmony_ci list_del(&qp->devq); 13378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sdev->lock, flags); 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci vfree(qp->sendq); 13408c2ecf20Sopenharmony_ci vfree(qp->recvq); 13418c2ecf20Sopenharmony_ci vfree(qp->irq); 13428c2ecf20Sopenharmony_ci vfree(qp->orq); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci siw_put_tx_cpu(qp->tx_cpu); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci atomic_dec(&sdev->num_qp); 13478c2ecf20Sopenharmony_ci siw_dbg_qp(qp, "free QP\n"); 13488c2ecf20Sopenharmony_ci kfree_rcu(qp, rcu); 13498c2ecf20Sopenharmony_ci} 1350