crypto/bcmfs: add queue pair management
[dpdk.git] / drivers / crypto / bcmfs / bcmfs_qp.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2020 Broadcom.
3  * All rights reserved.
4  */
5
6 #include <inttypes.h>
7
8 #include <rte_atomic.h>
9 #include <rte_bitmap.h>
10 #include <rte_common.h>
11 #include <rte_dev.h>
12 #include <rte_malloc.h>
13 #include <rte_memzone.h>
14 #include <rte_prefetch.h>
15 #include <rte_string_fns.h>
16
17 #include "bcmfs_logs.h"
18 #include "bcmfs_qp.h"
19 #include "bcmfs_hw_defs.h"
20
21 /* TX or submission queue name */
22 static const char *txq_name = "tx";
23 /* Completion or receive queue name */
24 static const char *cmplq_name = "cmpl";
25
26 /* Helper function */
27 static int
28 bcmfs_qp_check_queue_alignment(uint64_t phys_addr,
29                                uint32_t align)
30 {
31         if (((align - 1) & phys_addr) != 0)
32                 return -EINVAL;
33         return 0;
34 }
35
36 static void
37 bcmfs_queue_delete(struct bcmfs_queue *queue,
38                    uint16_t queue_pair_id)
39 {
40         const struct rte_memzone *mz;
41         int status = 0;
42
43         if (queue == NULL) {
44                 BCMFS_LOG(DEBUG, "Invalid queue");
45                 return;
46         }
47         BCMFS_LOG(DEBUG, "Free ring %d type %d, memzone: %s",
48                   queue_pair_id, queue->q_type, queue->memz_name);
49
50         mz = rte_memzone_lookup(queue->memz_name);
51         if (mz != NULL) {
52                 /* Write an unused pattern to the queue memory. */
53                 memset(queue->base_addr, 0x9B, queue->queue_size);
54                 status = rte_memzone_free(mz);
55                 if (status != 0)
56                         BCMFS_LOG(ERR, "Error %d on freeing queue %s",
57                                         status, queue->memz_name);
58         } else {
59                 BCMFS_LOG(DEBUG, "queue %s doesn't exist",
60                                 queue->memz_name);
61         }
62 }
63
64 static const struct rte_memzone *
65 queue_dma_zone_reserve(const char *queue_name, uint32_t queue_size,
66                        int socket_id, unsigned int align)
67 {
68         const struct rte_memzone *mz;
69
70         mz = rte_memzone_lookup(queue_name);
71         if (mz != NULL) {
72                 if (((size_t)queue_size <= mz->len) &&
73                     (socket_id == SOCKET_ID_ANY ||
74                      socket_id == mz->socket_id)) {
75                         BCMFS_LOG(DEBUG, "re-use memzone already "
76                                         "allocated for %s", queue_name);
77                         return mz;
78                 }
79
80                 BCMFS_LOG(ERR, "Incompatible memzone already "
81                                 "allocated %s, size %u, socket %d. "
82                                 "Requested size %u, socket %u",
83                                 queue_name, (uint32_t)mz->len,
84                                 mz->socket_id, queue_size, socket_id);
85                 return NULL;
86         }
87
88         BCMFS_LOG(DEBUG, "Allocate memzone for %s, size %u on socket %u",
89                   queue_name, queue_size, socket_id);
90         return rte_memzone_reserve_aligned(queue_name, queue_size,
91                 socket_id, RTE_MEMZONE_IOVA_CONTIG, align);
92 }
93
94 static int
95 bcmfs_queue_create(struct bcmfs_queue *queue,
96                    struct bcmfs_qp_config *qp_conf,
97                    uint16_t queue_pair_id,
98                    enum bcmfs_queue_type qtype)
99 {
100         const struct rte_memzone *qp_mz;
101         char q_name[16];
102         unsigned int align;
103         uint32_t queue_size_bytes;
104         int ret;
105
106         if (qtype == BCMFS_RM_TXQ) {
107                 strlcpy(q_name, txq_name, sizeof(q_name));
108                 align = 1U << FS_RING_BD_ALIGN_ORDER;
109                 queue_size_bytes = qp_conf->nb_descriptors *
110                                    qp_conf->max_descs_req * FS_RING_DESC_SIZE;
111                 queue_size_bytes = RTE_ALIGN_MUL_CEIL(queue_size_bytes,
112                                                       FS_RING_PAGE_SIZE);
113                 /* make queue size to multiple for 4K pages */
114         } else if (qtype == BCMFS_RM_CPLQ) {
115                 strlcpy(q_name, cmplq_name, sizeof(q_name));
116                 align = 1U << FS_RING_CMPL_ALIGN_ORDER;
117
118                 /*
119                  * Memory size for cmpl + MSI
120                  * For MSI allocate here itself and so we allocate twice
121                  */
122                 queue_size_bytes = 2 * FS_RING_CMPL_SIZE;
123         } else {
124                 BCMFS_LOG(ERR, "Invalid queue selection");
125                 return -EINVAL;
126         }
127
128         queue->q_type = qtype;
129
130         /*
131          * Allocate a memzone for the queue - create a unique name.
132          */
133         snprintf(queue->memz_name, sizeof(queue->memz_name),
134                  "%s_%d_%s_%d_%s", "bcmfs", qtype, "qp_mem",
135                  queue_pair_id, q_name);
136         qp_mz = queue_dma_zone_reserve(queue->memz_name, queue_size_bytes,
137                                        0, align);
138         if (qp_mz == NULL) {
139                 BCMFS_LOG(ERR, "Failed to allocate ring memzone");
140                 return -ENOMEM;
141         }
142
143         if (bcmfs_qp_check_queue_alignment(qp_mz->iova, align)) {
144                 BCMFS_LOG(ERR, "Invalid alignment on queue create "
145                                         " 0x%" PRIx64 "\n",
146                                         queue->base_phys_addr);
147                 ret = -EFAULT;
148                 goto queue_create_err;
149         }
150
151         queue->base_addr = (char *)qp_mz->addr;
152         queue->base_phys_addr = qp_mz->iova;
153         queue->queue_size = queue_size_bytes;
154
155         return 0;
156
157 queue_create_err:
158         rte_memzone_free(qp_mz);
159
160         return ret;
161 }
162
163 int
164 bcmfs_qp_release(struct bcmfs_qp **qp_addr)
165 {
166         struct bcmfs_qp *qp = *qp_addr;
167
168         if (qp == NULL) {
169                 BCMFS_LOG(DEBUG, "qp already freed");
170                 return 0;
171         }
172
173         /* Don't free memory if there are still responses to be processed */
174         if ((qp->stats.enqueued_count - qp->stats.dequeued_count) == 0) {
175                 /* Stop the h/w ring */
176                 qp->ops->stopq(qp);
177                 /* Delete the queue pairs */
178                 bcmfs_queue_delete(&qp->tx_q, qp->qpair_id);
179                 bcmfs_queue_delete(&qp->cmpl_q, qp->qpair_id);
180         } else {
181                 return -EAGAIN;
182         }
183
184         rte_bitmap_reset(qp->ctx_bmp);
185         rte_free(qp->ctx_bmp_mem);
186         rte_free(qp->ctx_pool);
187
188         rte_free(qp);
189         *qp_addr = NULL;
190
191         return 0;
192 }
193
194 int
195 bcmfs_qp_setup(struct bcmfs_qp **qp_addr,
196                uint16_t queue_pair_id,
197                struct bcmfs_qp_config *qp_conf)
198 {
199         struct bcmfs_qp *qp;
200         uint32_t bmp_size;
201         uint32_t nb_descriptors = qp_conf->nb_descriptors;
202         uint16_t i;
203         int rc;
204
205         if (nb_descriptors < FS_RM_MIN_REQS) {
206                 BCMFS_LOG(ERR, "Can't create qp for %u descriptors",
207                           nb_descriptors);
208                 return -EINVAL;
209         }
210
211         if (nb_descriptors > FS_RM_MAX_REQS)
212                 nb_descriptors = FS_RM_MAX_REQS;
213
214         if (qp_conf->iobase == NULL) {
215                 BCMFS_LOG(ERR, "IO onfig space null");
216                 return -EINVAL;
217         }
218
219         qp = rte_zmalloc_socket("BCM FS PMD qp metadata",
220                                 sizeof(*qp), RTE_CACHE_LINE_SIZE,
221                                 qp_conf->socket_id);
222         if (qp == NULL) {
223                 BCMFS_LOG(ERR, "Failed to alloc mem for qp struct");
224                 return -ENOMEM;
225         }
226
227         qp->qpair_id = queue_pair_id;
228         qp->ioreg = qp_conf->iobase;
229         qp->nb_descriptors = nb_descriptors;
230
231         qp->stats.enqueued_count = 0;
232         qp->stats.dequeued_count = 0;
233
234         rc = bcmfs_queue_create(&qp->tx_q, qp_conf, qp->qpair_id,
235                                 BCMFS_RM_TXQ);
236         if (rc) {
237                 BCMFS_LOG(ERR, "Tx queue create failed queue_pair_id %u",
238                           queue_pair_id);
239                 goto create_err;
240         }
241
242         rc = bcmfs_queue_create(&qp->cmpl_q, qp_conf, qp->qpair_id,
243                                 BCMFS_RM_CPLQ);
244         if (rc) {
245                 BCMFS_LOG(ERR, "Cmpl queue create failed queue_pair_id= %u",
246                           queue_pair_id);
247                 goto q_create_err;
248         }
249
250         /* ctx saving bitmap */
251         bmp_size = rte_bitmap_get_memory_footprint(nb_descriptors);
252
253         /* Allocate memory for bitmap */
254         qp->ctx_bmp_mem = rte_zmalloc("ctx_bmp_mem", bmp_size,
255                                       RTE_CACHE_LINE_SIZE);
256         if (qp->ctx_bmp_mem == NULL) {
257                 rc = -ENOMEM;
258                 goto qp_create_err;
259         }
260
261         /* Initialize pool resource bitmap array */
262         qp->ctx_bmp = rte_bitmap_init(nb_descriptors, qp->ctx_bmp_mem,
263                                       bmp_size);
264         if (qp->ctx_bmp == NULL) {
265                 rc = -EINVAL;
266                 goto bmap_mem_free;
267         }
268
269         /* Mark all pools available */
270         for (i = 0; i < nb_descriptors; i++)
271                 rte_bitmap_set(qp->ctx_bmp, i);
272
273         /* Allocate memory for context */
274         qp->ctx_pool = rte_zmalloc("qp_ctx_pool",
275                                    sizeof(unsigned long) *
276                                    nb_descriptors, 0);
277         if (qp->ctx_pool == NULL) {
278                 BCMFS_LOG(ERR, "ctx allocation pool fails");
279                 rc = -ENOMEM;
280                 goto bmap_free;
281         }
282
283         /* Start h/w ring */
284         qp->ops->startq(qp);
285
286         *qp_addr = qp;
287
288         return 0;
289
290 bmap_free:
291         rte_bitmap_reset(qp->ctx_bmp);
292 bmap_mem_free:
293         rte_free(qp->ctx_bmp_mem);
294 qp_create_err:
295         bcmfs_queue_delete(&qp->cmpl_q, queue_pair_id);
296 q_create_err:
297         bcmfs_queue_delete(&qp->tx_q, queue_pair_id);
298 create_err:
299         rte_free(qp);
300
301         return rc;
302 }
303
304 uint16_t
305 bcmfs_enqueue_op_burst(void *qp, void **ops, uint16_t nb_ops)
306 {
307         struct bcmfs_qp *tmp_qp = (struct bcmfs_qp *)qp;
308         register uint32_t nb_ops_sent = 0;
309         uint16_t nb_ops_possible = nb_ops;
310         int ret;
311
312         if (unlikely(nb_ops == 0))
313                 return 0;
314
315         while (nb_ops_sent != nb_ops_possible) {
316                 ret = tmp_qp->ops->enq_one_req(qp, *ops);
317                 if (ret != 0) {
318                         tmp_qp->stats.enqueue_err_count++;
319                         /* This message cannot be enqueued */
320                         if (nb_ops_sent == 0)
321                                 return 0;
322                         goto ring_db;
323                 }
324
325                 ops++;
326                 nb_ops_sent++;
327         }
328
329 ring_db:
330         tmp_qp->stats.enqueued_count += nb_ops_sent;
331         tmp_qp->ops->ring_db(tmp_qp);
332
333         return nb_ops_sent;
334 }
335
336 uint16_t
337 bcmfs_dequeue_op_burst(void *qp, void **ops, uint16_t nb_ops)
338 {
339         struct bcmfs_qp *tmp_qp = (struct bcmfs_qp *)qp;
340         uint32_t deq = tmp_qp->ops->dequeue(tmp_qp, ops, nb_ops);
341
342         tmp_qp->stats.dequeued_count += deq;
343
344         return deq;
345 }