18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright(c) 2016 Intel Corporation. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 58c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 118c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 148c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 158c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 168c2ecf20Sopenharmony_ci * General Public License for more details. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * BSD LICENSE 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 218c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 228c2ecf20Sopenharmony_ci * are met: 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above copyright 258c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 268c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above copyright 278c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 288c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 298c2ecf20Sopenharmony_ci * distribution. 308c2ecf20Sopenharmony_ci * - Neither the name of Intel Corporation nor the names of its 318c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 328c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 358c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 368c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 378c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 388c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 398c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 408c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 418c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 428c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 438c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 448c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#include <rdma/rdmavt_qp.h> 498c2ecf20Sopenharmony_ci#include <rdma/ib_hdrs.h> 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* 528c2ecf20Sopenharmony_ci * Convert the AETH credit code into the number of credits. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_cistatic const u16 credit_table[31] = { 558c2ecf20Sopenharmony_ci 0, /* 0 */ 568c2ecf20Sopenharmony_ci 1, /* 1 */ 578c2ecf20Sopenharmony_ci 2, /* 2 */ 588c2ecf20Sopenharmony_ci 3, /* 3 */ 598c2ecf20Sopenharmony_ci 4, /* 4 */ 608c2ecf20Sopenharmony_ci 6, /* 5 */ 618c2ecf20Sopenharmony_ci 8, /* 6 */ 628c2ecf20Sopenharmony_ci 12, /* 7 */ 638c2ecf20Sopenharmony_ci 16, /* 8 */ 648c2ecf20Sopenharmony_ci 24, /* 9 */ 658c2ecf20Sopenharmony_ci 32, /* A */ 668c2ecf20Sopenharmony_ci 48, /* B */ 678c2ecf20Sopenharmony_ci 64, /* C */ 688c2ecf20Sopenharmony_ci 96, /* D */ 698c2ecf20Sopenharmony_ci 128, /* E */ 708c2ecf20Sopenharmony_ci 192, /* F */ 718c2ecf20Sopenharmony_ci 256, /* 10 */ 728c2ecf20Sopenharmony_ci 384, /* 11 */ 738c2ecf20Sopenharmony_ci 512, /* 12 */ 748c2ecf20Sopenharmony_ci 768, /* 13 */ 758c2ecf20Sopenharmony_ci 1024, /* 14 */ 768c2ecf20Sopenharmony_ci 1536, /* 15 */ 778c2ecf20Sopenharmony_ci 2048, /* 16 */ 788c2ecf20Sopenharmony_ci 3072, /* 17 */ 798c2ecf20Sopenharmony_ci 4096, /* 18 */ 808c2ecf20Sopenharmony_ci 6144, /* 19 */ 818c2ecf20Sopenharmony_ci 8192, /* 1A */ 828c2ecf20Sopenharmony_ci 12288, /* 1B */ 838c2ecf20Sopenharmony_ci 16384, /* 1C */ 848c2ecf20Sopenharmony_ci 24576, /* 1D */ 858c2ecf20Sopenharmony_ci 32768 /* 1E */ 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/** 898c2ecf20Sopenharmony_ci * rvt_compute_aeth - compute the AETH (syndrome + MSN) 908c2ecf20Sopenharmony_ci * @qp: the queue pair to compute the AETH for 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * Returns the AETH. 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci__be32 rvt_compute_aeth(struct rvt_qp *qp) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci u32 aeth = qp->r_msn & IB_MSN_MASK; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (qp->ibqp.srq) { 998c2ecf20Sopenharmony_ci /* 1008c2ecf20Sopenharmony_ci * Shared receive queues don't generate credits. 1018c2ecf20Sopenharmony_ci * Set the credit field to the invalid value. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci aeth |= IB_AETH_CREDIT_INVAL << IB_AETH_CREDIT_SHIFT; 1048c2ecf20Sopenharmony_ci } else { 1058c2ecf20Sopenharmony_ci u32 min, max, x; 1068c2ecf20Sopenharmony_ci u32 credits; 1078c2ecf20Sopenharmony_ci u32 head; 1088c2ecf20Sopenharmony_ci u32 tail; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci credits = READ_ONCE(qp->r_rq.kwq->count); 1118c2ecf20Sopenharmony_ci if (credits == 0) { 1128c2ecf20Sopenharmony_ci /* sanity check pointers before trusting them */ 1138c2ecf20Sopenharmony_ci if (qp->ip) { 1148c2ecf20Sopenharmony_ci head = RDMA_READ_UAPI_ATOMIC(qp->r_rq.wq->head); 1158c2ecf20Sopenharmony_ci tail = RDMA_READ_UAPI_ATOMIC(qp->r_rq.wq->tail); 1168c2ecf20Sopenharmony_ci } else { 1178c2ecf20Sopenharmony_ci head = READ_ONCE(qp->r_rq.kwq->head); 1188c2ecf20Sopenharmony_ci tail = READ_ONCE(qp->r_rq.kwq->tail); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci if (head >= qp->r_rq.size) 1218c2ecf20Sopenharmony_ci head = 0; 1228c2ecf20Sopenharmony_ci if (tail >= qp->r_rq.size) 1238c2ecf20Sopenharmony_ci tail = 0; 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * Compute the number of credits available (RWQEs). 1268c2ecf20Sopenharmony_ci * There is a small chance that the pair of reads are 1278c2ecf20Sopenharmony_ci * not atomic, which is OK, since the fuzziness is 1288c2ecf20Sopenharmony_ci * resolved as further ACKs go out. 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci credits = rvt_get_rq_count(&qp->r_rq, head, tail); 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci /* 1338c2ecf20Sopenharmony_ci * Binary search the credit table to find the code to 1348c2ecf20Sopenharmony_ci * use. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci min = 0; 1378c2ecf20Sopenharmony_ci max = 31; 1388c2ecf20Sopenharmony_ci for (;;) { 1398c2ecf20Sopenharmony_ci x = (min + max) / 2; 1408c2ecf20Sopenharmony_ci if (credit_table[x] == credits) 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci if (credit_table[x] > credits) { 1438c2ecf20Sopenharmony_ci max = x; 1448c2ecf20Sopenharmony_ci } else { 1458c2ecf20Sopenharmony_ci if (min == x) 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci min = x; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci aeth |= x << IB_AETH_CREDIT_SHIFT; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci return cpu_to_be32(aeth); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_compute_aeth); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/** 1578c2ecf20Sopenharmony_ci * rvt_get_credit - flush the send work queue of a QP 1588c2ecf20Sopenharmony_ci * @qp: the qp who's send work queue to flush 1598c2ecf20Sopenharmony_ci * @aeth: the Acknowledge Extended Transport Header 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * The QP s_lock should be held. 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_civoid rvt_get_credit(struct rvt_qp *qp, u32 aeth) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 1668c2ecf20Sopenharmony_ci u32 credit = (aeth >> IB_AETH_CREDIT_SHIFT) & IB_AETH_CREDIT_MASK; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 1698c2ecf20Sopenharmony_ci /* 1708c2ecf20Sopenharmony_ci * If the credit is invalid, we can send 1718c2ecf20Sopenharmony_ci * as many packets as we like. Otherwise, we have to 1728c2ecf20Sopenharmony_ci * honor the credit field. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci if (credit == IB_AETH_CREDIT_INVAL) { 1758c2ecf20Sopenharmony_ci if (!(qp->s_flags & RVT_S_UNLIMITED_CREDIT)) { 1768c2ecf20Sopenharmony_ci qp->s_flags |= RVT_S_UNLIMITED_CREDIT; 1778c2ecf20Sopenharmony_ci if (qp->s_flags & RVT_S_WAIT_SSN_CREDIT) { 1788c2ecf20Sopenharmony_ci qp->s_flags &= ~RVT_S_WAIT_SSN_CREDIT; 1798c2ecf20Sopenharmony_ci rdi->driver_f.schedule_send(qp); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci } else if (!(qp->s_flags & RVT_S_UNLIMITED_CREDIT)) { 1838c2ecf20Sopenharmony_ci /* Compute new LSN (i.e., MSN + credit) */ 1848c2ecf20Sopenharmony_ci credit = (aeth + credit_table[credit]) & IB_MSN_MASK; 1858c2ecf20Sopenharmony_ci if (rvt_cmp_msn(credit, qp->s_lsn) > 0) { 1868c2ecf20Sopenharmony_ci qp->s_lsn = credit; 1878c2ecf20Sopenharmony_ci if (qp->s_flags & RVT_S_WAIT_SSN_CREDIT) { 1888c2ecf20Sopenharmony_ci qp->s_flags &= ~RVT_S_WAIT_SSN_CREDIT; 1898c2ecf20Sopenharmony_ci rdi->driver_f.schedule_send(qp); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_get_credit); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/** 1978c2ecf20Sopenharmony_ci * rvt_restart_sge - rewind the sge state for a wqe 1988c2ecf20Sopenharmony_ci * @ss: the sge state pointer 1998c2ecf20Sopenharmony_ci * @wqe: the wqe to rewind 2008c2ecf20Sopenharmony_ci * @len: the data length from the start of the wqe in bytes 2018c2ecf20Sopenharmony_ci * 2028c2ecf20Sopenharmony_ci * Returns the remaining data length. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ciu32 rvt_restart_sge(struct rvt_sge_state *ss, struct rvt_swqe *wqe, u32 len) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci ss->sge = wqe->sg_list[0]; 2078c2ecf20Sopenharmony_ci ss->sg_list = wqe->sg_list + 1; 2088c2ecf20Sopenharmony_ci ss->num_sge = wqe->wr.num_sge; 2098c2ecf20Sopenharmony_ci ss->total_len = wqe->length; 2108c2ecf20Sopenharmony_ci rvt_skip_sge(ss, len, false); 2118c2ecf20Sopenharmony_ci return wqe->length - len; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_restart_sge); 2148c2ecf20Sopenharmony_ci 215