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