162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright(c) 2016 Intel Corporation. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <rdma/rdmavt_qp.h> 762306a36Sopenharmony_ci#include <rdma/ib_hdrs.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * Convert the AETH credit code into the number of credits. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_cistatic const u16 credit_table[31] = { 1362306a36Sopenharmony_ci 0, /* 0 */ 1462306a36Sopenharmony_ci 1, /* 1 */ 1562306a36Sopenharmony_ci 2, /* 2 */ 1662306a36Sopenharmony_ci 3, /* 3 */ 1762306a36Sopenharmony_ci 4, /* 4 */ 1862306a36Sopenharmony_ci 6, /* 5 */ 1962306a36Sopenharmony_ci 8, /* 6 */ 2062306a36Sopenharmony_ci 12, /* 7 */ 2162306a36Sopenharmony_ci 16, /* 8 */ 2262306a36Sopenharmony_ci 24, /* 9 */ 2362306a36Sopenharmony_ci 32, /* A */ 2462306a36Sopenharmony_ci 48, /* B */ 2562306a36Sopenharmony_ci 64, /* C */ 2662306a36Sopenharmony_ci 96, /* D */ 2762306a36Sopenharmony_ci 128, /* E */ 2862306a36Sopenharmony_ci 192, /* F */ 2962306a36Sopenharmony_ci 256, /* 10 */ 3062306a36Sopenharmony_ci 384, /* 11 */ 3162306a36Sopenharmony_ci 512, /* 12 */ 3262306a36Sopenharmony_ci 768, /* 13 */ 3362306a36Sopenharmony_ci 1024, /* 14 */ 3462306a36Sopenharmony_ci 1536, /* 15 */ 3562306a36Sopenharmony_ci 2048, /* 16 */ 3662306a36Sopenharmony_ci 3072, /* 17 */ 3762306a36Sopenharmony_ci 4096, /* 18 */ 3862306a36Sopenharmony_ci 6144, /* 19 */ 3962306a36Sopenharmony_ci 8192, /* 1A */ 4062306a36Sopenharmony_ci 12288, /* 1B */ 4162306a36Sopenharmony_ci 16384, /* 1C */ 4262306a36Sopenharmony_ci 24576, /* 1D */ 4362306a36Sopenharmony_ci 32768 /* 1E */ 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/** 4762306a36Sopenharmony_ci * rvt_compute_aeth - compute the AETH (syndrome + MSN) 4862306a36Sopenharmony_ci * @qp: the queue pair to compute the AETH for 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * Returns the AETH. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci__be32 rvt_compute_aeth(struct rvt_qp *qp) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci u32 aeth = qp->r_msn & IB_MSN_MASK; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (qp->ibqp.srq) { 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * Shared receive queues don't generate credits. 5962306a36Sopenharmony_ci * Set the credit field to the invalid value. 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ci aeth |= IB_AETH_CREDIT_INVAL << IB_AETH_CREDIT_SHIFT; 6262306a36Sopenharmony_ci } else { 6362306a36Sopenharmony_ci u32 min, max, x; 6462306a36Sopenharmony_ci u32 credits; 6562306a36Sopenharmony_ci u32 head; 6662306a36Sopenharmony_ci u32 tail; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci credits = READ_ONCE(qp->r_rq.kwq->count); 6962306a36Sopenharmony_ci if (credits == 0) { 7062306a36Sopenharmony_ci /* sanity check pointers before trusting them */ 7162306a36Sopenharmony_ci if (qp->ip) { 7262306a36Sopenharmony_ci head = RDMA_READ_UAPI_ATOMIC(qp->r_rq.wq->head); 7362306a36Sopenharmony_ci tail = RDMA_READ_UAPI_ATOMIC(qp->r_rq.wq->tail); 7462306a36Sopenharmony_ci } else { 7562306a36Sopenharmony_ci head = READ_ONCE(qp->r_rq.kwq->head); 7662306a36Sopenharmony_ci tail = READ_ONCE(qp->r_rq.kwq->tail); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci if (head >= qp->r_rq.size) 7962306a36Sopenharmony_ci head = 0; 8062306a36Sopenharmony_ci if (tail >= qp->r_rq.size) 8162306a36Sopenharmony_ci tail = 0; 8262306a36Sopenharmony_ci /* 8362306a36Sopenharmony_ci * Compute the number of credits available (RWQEs). 8462306a36Sopenharmony_ci * There is a small chance that the pair of reads are 8562306a36Sopenharmony_ci * not atomic, which is OK, since the fuzziness is 8662306a36Sopenharmony_ci * resolved as further ACKs go out. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci credits = rvt_get_rq_count(&qp->r_rq, head, tail); 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci /* 9162306a36Sopenharmony_ci * Binary search the credit table to find the code to 9262306a36Sopenharmony_ci * use. 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci min = 0; 9562306a36Sopenharmony_ci max = 31; 9662306a36Sopenharmony_ci for (;;) { 9762306a36Sopenharmony_ci x = (min + max) / 2; 9862306a36Sopenharmony_ci if (credit_table[x] == credits) 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci if (credit_table[x] > credits) { 10162306a36Sopenharmony_ci max = x; 10262306a36Sopenharmony_ci } else { 10362306a36Sopenharmony_ci if (min == x) 10462306a36Sopenharmony_ci break; 10562306a36Sopenharmony_ci min = x; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci aeth |= x << IB_AETH_CREDIT_SHIFT; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci return cpu_to_be32(aeth); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_compute_aeth); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/** 11562306a36Sopenharmony_ci * rvt_get_credit - flush the send work queue of a QP 11662306a36Sopenharmony_ci * @qp: the qp who's send work queue to flush 11762306a36Sopenharmony_ci * @aeth: the Acknowledge Extended Transport Header 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * The QP s_lock should be held. 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_civoid rvt_get_credit(struct rvt_qp *qp, u32 aeth) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 12462306a36Sopenharmony_ci u32 credit = (aeth >> IB_AETH_CREDIT_SHIFT) & IB_AETH_CREDIT_MASK; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 12762306a36Sopenharmony_ci /* 12862306a36Sopenharmony_ci * If the credit is invalid, we can send 12962306a36Sopenharmony_ci * as many packets as we like. Otherwise, we have to 13062306a36Sopenharmony_ci * honor the credit field. 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci if (credit == IB_AETH_CREDIT_INVAL) { 13362306a36Sopenharmony_ci if (!(qp->s_flags & RVT_S_UNLIMITED_CREDIT)) { 13462306a36Sopenharmony_ci qp->s_flags |= RVT_S_UNLIMITED_CREDIT; 13562306a36Sopenharmony_ci if (qp->s_flags & RVT_S_WAIT_SSN_CREDIT) { 13662306a36Sopenharmony_ci qp->s_flags &= ~RVT_S_WAIT_SSN_CREDIT; 13762306a36Sopenharmony_ci rdi->driver_f.schedule_send(qp); 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci } else if (!(qp->s_flags & RVT_S_UNLIMITED_CREDIT)) { 14162306a36Sopenharmony_ci /* Compute new LSN (i.e., MSN + credit) */ 14262306a36Sopenharmony_ci credit = (aeth + credit_table[credit]) & IB_MSN_MASK; 14362306a36Sopenharmony_ci if (rvt_cmp_msn(credit, qp->s_lsn) > 0) { 14462306a36Sopenharmony_ci qp->s_lsn = credit; 14562306a36Sopenharmony_ci if (qp->s_flags & RVT_S_WAIT_SSN_CREDIT) { 14662306a36Sopenharmony_ci qp->s_flags &= ~RVT_S_WAIT_SSN_CREDIT; 14762306a36Sopenharmony_ci rdi->driver_f.schedule_send(qp); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_get_credit); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/** 15562306a36Sopenharmony_ci * rvt_restart_sge - rewind the sge state for a wqe 15662306a36Sopenharmony_ci * @ss: the sge state pointer 15762306a36Sopenharmony_ci * @wqe: the wqe to rewind 15862306a36Sopenharmony_ci * @len: the data length from the start of the wqe in bytes 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * Returns the remaining data length. 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ciu32 rvt_restart_sge(struct rvt_sge_state *ss, struct rvt_swqe *wqe, u32 len) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci ss->sge = wqe->sg_list[0]; 16562306a36Sopenharmony_ci ss->sg_list = wqe->sg_list + 1; 16662306a36Sopenharmony_ci ss->num_sge = wqe->wr.num_sge; 16762306a36Sopenharmony_ci ss->total_len = wqe->length; 16862306a36Sopenharmony_ci rvt_skip_sge(ss, len, false); 16962306a36Sopenharmony_ci return wqe->length - len; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_restart_sge); 17262306a36Sopenharmony_ci 173