xref: /linux/drivers/infiniband/hw/ionic/ionic_controlpath.c (revision f3bdbd42702c6b10ebe627828c76ef51c68e4355)
1*f3bdbd42SAbhijit Gangurde // SPDX-License-Identifier: GPL-2.0
2*f3bdbd42SAbhijit Gangurde /* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
3*f3bdbd42SAbhijit Gangurde 
4*f3bdbd42SAbhijit Gangurde #include "ionic_ibdev.h"
5*f3bdbd42SAbhijit Gangurde 
6*f3bdbd42SAbhijit Gangurde static int ionic_validate_qdesc(struct ionic_qdesc *q)
7*f3bdbd42SAbhijit Gangurde {
8*f3bdbd42SAbhijit Gangurde 	if (!q->addr || !q->size || !q->mask ||
9*f3bdbd42SAbhijit Gangurde 	    !q->depth_log2 || !q->stride_log2)
10*f3bdbd42SAbhijit Gangurde 		return -EINVAL;
11*f3bdbd42SAbhijit Gangurde 
12*f3bdbd42SAbhijit Gangurde 	if (q->addr & (PAGE_SIZE - 1))
13*f3bdbd42SAbhijit Gangurde 		return -EINVAL;
14*f3bdbd42SAbhijit Gangurde 
15*f3bdbd42SAbhijit Gangurde 	if (q->mask != BIT(q->depth_log2) - 1)
16*f3bdbd42SAbhijit Gangurde 		return -EINVAL;
17*f3bdbd42SAbhijit Gangurde 
18*f3bdbd42SAbhijit Gangurde 	if (q->size < BIT_ULL(q->depth_log2 + q->stride_log2))
19*f3bdbd42SAbhijit Gangurde 		return -EINVAL;
20*f3bdbd42SAbhijit Gangurde 
21*f3bdbd42SAbhijit Gangurde 	return 0;
22*f3bdbd42SAbhijit Gangurde }
23*f3bdbd42SAbhijit Gangurde 
24*f3bdbd42SAbhijit Gangurde static u32 ionic_get_eqid(struct ionic_ibdev *dev, u32 comp_vector, u8 udma_idx)
25*f3bdbd42SAbhijit Gangurde {
26*f3bdbd42SAbhijit Gangurde 	/* EQ per vector per udma, and the first eqs reserved for async events.
27*f3bdbd42SAbhijit Gangurde 	 * The rest of the vectors can be requested for completions.
28*f3bdbd42SAbhijit Gangurde 	 */
29*f3bdbd42SAbhijit Gangurde 	u32 comp_vec_count = dev->lif_cfg.eq_count / dev->lif_cfg.udma_count - 1;
30*f3bdbd42SAbhijit Gangurde 
31*f3bdbd42SAbhijit Gangurde 	return (comp_vector % comp_vec_count + 1) * dev->lif_cfg.udma_count + udma_idx;
32*f3bdbd42SAbhijit Gangurde }
33*f3bdbd42SAbhijit Gangurde 
34*f3bdbd42SAbhijit Gangurde static int ionic_get_cqid(struct ionic_ibdev *dev, u32 *cqid, u8 udma_idx)
35*f3bdbd42SAbhijit Gangurde {
36*f3bdbd42SAbhijit Gangurde 	unsigned int size, base, bound;
37*f3bdbd42SAbhijit Gangurde 	int rc;
38*f3bdbd42SAbhijit Gangurde 
39*f3bdbd42SAbhijit Gangurde 	size = dev->lif_cfg.cq_count / dev->lif_cfg.udma_count;
40*f3bdbd42SAbhijit Gangurde 	base = size * udma_idx;
41*f3bdbd42SAbhijit Gangurde 	bound = base + size;
42*f3bdbd42SAbhijit Gangurde 
43*f3bdbd42SAbhijit Gangurde 	rc = ionic_resid_get_shared(&dev->inuse_cqid, base, bound);
44*f3bdbd42SAbhijit Gangurde 	if (rc >= 0) {
45*f3bdbd42SAbhijit Gangurde 		/* cq_base is zero or a multiple of two queue groups */
46*f3bdbd42SAbhijit Gangurde 		*cqid = dev->lif_cfg.cq_base +
47*f3bdbd42SAbhijit Gangurde 			ionic_bitid_to_qid(rc, dev->lif_cfg.udma_qgrp_shift,
48*f3bdbd42SAbhijit Gangurde 					   dev->half_cqid_udma_shift);
49*f3bdbd42SAbhijit Gangurde 
50*f3bdbd42SAbhijit Gangurde 		rc = 0;
51*f3bdbd42SAbhijit Gangurde 	}
52*f3bdbd42SAbhijit Gangurde 
53*f3bdbd42SAbhijit Gangurde 	return rc;
54*f3bdbd42SAbhijit Gangurde }
55*f3bdbd42SAbhijit Gangurde 
56*f3bdbd42SAbhijit Gangurde static void ionic_put_cqid(struct ionic_ibdev *dev, u32 cqid)
57*f3bdbd42SAbhijit Gangurde {
58*f3bdbd42SAbhijit Gangurde 	u32 bitid = ionic_qid_to_bitid(cqid - dev->lif_cfg.cq_base,
59*f3bdbd42SAbhijit Gangurde 				       dev->lif_cfg.udma_qgrp_shift,
60*f3bdbd42SAbhijit Gangurde 				       dev->half_cqid_udma_shift);
61*f3bdbd42SAbhijit Gangurde 
62*f3bdbd42SAbhijit Gangurde 	ionic_resid_put(&dev->inuse_cqid, bitid);
63*f3bdbd42SAbhijit Gangurde }
64*f3bdbd42SAbhijit Gangurde 
65*f3bdbd42SAbhijit Gangurde int ionic_create_cq_common(struct ionic_vcq *vcq,
66*f3bdbd42SAbhijit Gangurde 			   struct ionic_tbl_buf *buf,
67*f3bdbd42SAbhijit Gangurde 			   const struct ib_cq_init_attr *attr,
68*f3bdbd42SAbhijit Gangurde 			   struct ionic_ctx *ctx,
69*f3bdbd42SAbhijit Gangurde 			   struct ib_udata *udata,
70*f3bdbd42SAbhijit Gangurde 			   struct ionic_qdesc *req_cq,
71*f3bdbd42SAbhijit Gangurde 			   __u32 *resp_cqid,
72*f3bdbd42SAbhijit Gangurde 			   int udma_idx)
73*f3bdbd42SAbhijit Gangurde {
74*f3bdbd42SAbhijit Gangurde 	struct ionic_ibdev *dev = to_ionic_ibdev(vcq->ibcq.device);
75*f3bdbd42SAbhijit Gangurde 	struct ionic_cq *cq = &vcq->cq[udma_idx];
76*f3bdbd42SAbhijit Gangurde 	void *entry;
77*f3bdbd42SAbhijit Gangurde 	int rc;
78*f3bdbd42SAbhijit Gangurde 
79*f3bdbd42SAbhijit Gangurde 	cq->vcq = vcq;
80*f3bdbd42SAbhijit Gangurde 
81*f3bdbd42SAbhijit Gangurde 	if (attr->cqe < 1 || attr->cqe + IONIC_CQ_GRACE > 0xffff) {
82*f3bdbd42SAbhijit Gangurde 		rc = -EINVAL;
83*f3bdbd42SAbhijit Gangurde 		goto err_args;
84*f3bdbd42SAbhijit Gangurde 	}
85*f3bdbd42SAbhijit Gangurde 
86*f3bdbd42SAbhijit Gangurde 	rc = ionic_get_cqid(dev, &cq->cqid, udma_idx);
87*f3bdbd42SAbhijit Gangurde 	if (rc)
88*f3bdbd42SAbhijit Gangurde 		goto err_args;
89*f3bdbd42SAbhijit Gangurde 
90*f3bdbd42SAbhijit Gangurde 	cq->eqid = ionic_get_eqid(dev, attr->comp_vector, udma_idx);
91*f3bdbd42SAbhijit Gangurde 
92*f3bdbd42SAbhijit Gangurde 	spin_lock_init(&cq->lock);
93*f3bdbd42SAbhijit Gangurde 	INIT_LIST_HEAD(&cq->poll_sq);
94*f3bdbd42SAbhijit Gangurde 	INIT_LIST_HEAD(&cq->flush_sq);
95*f3bdbd42SAbhijit Gangurde 	INIT_LIST_HEAD(&cq->flush_rq);
96*f3bdbd42SAbhijit Gangurde 
97*f3bdbd42SAbhijit Gangurde 	if (udata) {
98*f3bdbd42SAbhijit Gangurde 		rc = ionic_validate_qdesc(req_cq);
99*f3bdbd42SAbhijit Gangurde 		if (rc)
100*f3bdbd42SAbhijit Gangurde 			goto err_qdesc;
101*f3bdbd42SAbhijit Gangurde 
102*f3bdbd42SAbhijit Gangurde 		cq->umem = ib_umem_get(&dev->ibdev, req_cq->addr, req_cq->size,
103*f3bdbd42SAbhijit Gangurde 				       IB_ACCESS_LOCAL_WRITE);
104*f3bdbd42SAbhijit Gangurde 		if (IS_ERR(cq->umem)) {
105*f3bdbd42SAbhijit Gangurde 			rc = PTR_ERR(cq->umem);
106*f3bdbd42SAbhijit Gangurde 			goto err_qdesc;
107*f3bdbd42SAbhijit Gangurde 		}
108*f3bdbd42SAbhijit Gangurde 
109*f3bdbd42SAbhijit Gangurde 		cq->q.ptr = NULL;
110*f3bdbd42SAbhijit Gangurde 		cq->q.size = req_cq->size;
111*f3bdbd42SAbhijit Gangurde 		cq->q.mask = req_cq->mask;
112*f3bdbd42SAbhijit Gangurde 		cq->q.depth_log2 = req_cq->depth_log2;
113*f3bdbd42SAbhijit Gangurde 		cq->q.stride_log2 = req_cq->stride_log2;
114*f3bdbd42SAbhijit Gangurde 
115*f3bdbd42SAbhijit Gangurde 		*resp_cqid = cq->cqid;
116*f3bdbd42SAbhijit Gangurde 	} else {
117*f3bdbd42SAbhijit Gangurde 		rc = ionic_queue_init(&cq->q, dev->lif_cfg.hwdev,
118*f3bdbd42SAbhijit Gangurde 				      attr->cqe + IONIC_CQ_GRACE,
119*f3bdbd42SAbhijit Gangurde 				      sizeof(struct ionic_v1_cqe));
120*f3bdbd42SAbhijit Gangurde 		if (rc)
121*f3bdbd42SAbhijit Gangurde 			goto err_q_init;
122*f3bdbd42SAbhijit Gangurde 
123*f3bdbd42SAbhijit Gangurde 		ionic_queue_dbell_init(&cq->q, cq->cqid);
124*f3bdbd42SAbhijit Gangurde 		cq->color = true;
125*f3bdbd42SAbhijit Gangurde 		cq->credit = cq->q.mask;
126*f3bdbd42SAbhijit Gangurde 	}
127*f3bdbd42SAbhijit Gangurde 
128*f3bdbd42SAbhijit Gangurde 	rc = ionic_pgtbl_init(dev, buf, cq->umem, cq->q.dma, 1, PAGE_SIZE);
129*f3bdbd42SAbhijit Gangurde 	if (rc)
130*f3bdbd42SAbhijit Gangurde 		goto err_pgtbl_init;
131*f3bdbd42SAbhijit Gangurde 
132*f3bdbd42SAbhijit Gangurde 	init_completion(&cq->cq_rel_comp);
133*f3bdbd42SAbhijit Gangurde 	kref_init(&cq->cq_kref);
134*f3bdbd42SAbhijit Gangurde 
135*f3bdbd42SAbhijit Gangurde 	entry = xa_store_irq(&dev->cq_tbl, cq->cqid, cq, GFP_KERNEL);
136*f3bdbd42SAbhijit Gangurde 	if (entry) {
137*f3bdbd42SAbhijit Gangurde 		if (!xa_is_err(entry))
138*f3bdbd42SAbhijit Gangurde 			rc = -EINVAL;
139*f3bdbd42SAbhijit Gangurde 		else
140*f3bdbd42SAbhijit Gangurde 			rc = xa_err(entry);
141*f3bdbd42SAbhijit Gangurde 
142*f3bdbd42SAbhijit Gangurde 		goto err_xa;
143*f3bdbd42SAbhijit Gangurde 	}
144*f3bdbd42SAbhijit Gangurde 
145*f3bdbd42SAbhijit Gangurde 	return 0;
146*f3bdbd42SAbhijit Gangurde 
147*f3bdbd42SAbhijit Gangurde err_xa:
148*f3bdbd42SAbhijit Gangurde 	ionic_pgtbl_unbuf(dev, buf);
149*f3bdbd42SAbhijit Gangurde err_pgtbl_init:
150*f3bdbd42SAbhijit Gangurde 	if (!udata)
151*f3bdbd42SAbhijit Gangurde 		ionic_queue_destroy(&cq->q, dev->lif_cfg.hwdev);
152*f3bdbd42SAbhijit Gangurde err_q_init:
153*f3bdbd42SAbhijit Gangurde 	if (cq->umem)
154*f3bdbd42SAbhijit Gangurde 		ib_umem_release(cq->umem);
155*f3bdbd42SAbhijit Gangurde err_qdesc:
156*f3bdbd42SAbhijit Gangurde 	ionic_put_cqid(dev, cq->cqid);
157*f3bdbd42SAbhijit Gangurde err_args:
158*f3bdbd42SAbhijit Gangurde 	cq->vcq = NULL;
159*f3bdbd42SAbhijit Gangurde 
160*f3bdbd42SAbhijit Gangurde 	return rc;
161*f3bdbd42SAbhijit Gangurde }
162*f3bdbd42SAbhijit Gangurde 
163*f3bdbd42SAbhijit Gangurde void ionic_destroy_cq_common(struct ionic_ibdev *dev, struct ionic_cq *cq)
164*f3bdbd42SAbhijit Gangurde {
165*f3bdbd42SAbhijit Gangurde 	if (!cq->vcq)
166*f3bdbd42SAbhijit Gangurde 		return;
167*f3bdbd42SAbhijit Gangurde 
168*f3bdbd42SAbhijit Gangurde 	xa_erase_irq(&dev->cq_tbl, cq->cqid);
169*f3bdbd42SAbhijit Gangurde 
170*f3bdbd42SAbhijit Gangurde 	kref_put(&cq->cq_kref, ionic_cq_complete);
171*f3bdbd42SAbhijit Gangurde 	wait_for_completion(&cq->cq_rel_comp);
172*f3bdbd42SAbhijit Gangurde 
173*f3bdbd42SAbhijit Gangurde 	if (cq->umem)
174*f3bdbd42SAbhijit Gangurde 		ib_umem_release(cq->umem);
175*f3bdbd42SAbhijit Gangurde 	else
176*f3bdbd42SAbhijit Gangurde 		ionic_queue_destroy(&cq->q, dev->lif_cfg.hwdev);
177*f3bdbd42SAbhijit Gangurde 
178*f3bdbd42SAbhijit Gangurde 	ionic_put_cqid(dev, cq->cqid);
179*f3bdbd42SAbhijit Gangurde 
180*f3bdbd42SAbhijit Gangurde 	cq->vcq = NULL;
181*f3bdbd42SAbhijit Gangurde }
182