net/bnxt: support EEM system memory
[dpdk.git] / drivers / net / bnxt / tf_core / tf_em_system.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2020 Broadcom
3  * All rights reserved.
4  */
5
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <stdbool.h>
11 #include <math.h>
12 #include <sys/param.h>
13 #include <sys/mman.h>
14 #include <sys/ioctl.h>
15 #include <unistd.h>
16
17 #include <rte_common.h>
18 #include <rte_errno.h>
19 #include <rte_log.h>
20
21 #include "tf_core.h"
22 #include "tf_util.h"
23 #include "tf_common.h"
24 #include "tf_em.h"
25 #include "tf_em_common.h"
26 #include "tf_msg.h"
27 #include "tfp.h"
28 #include "lookup3.h"
29 #include "tf_ext_flow_handle.h"
30
31 #include "bnxt.h"
32
33 enum tf_em_req_type {
34         TF_EM_BNXT_LFC_CFA_EEM_DMABUF_EXPORT_REQ = 5,
35 };
36
37 struct tf_em_bnxt_lfc_req_hdr {
38         uint32_t ver;
39         uint32_t bus;
40         uint32_t devfn;
41         enum tf_em_req_type req_type;
42 };
43
44 struct tf_em_bnxt_lfc_cfa_eem_std_hdr {
45         uint16_t version;
46         uint16_t size;
47         uint32_t flags;
48         #define TF_EM_BNXT_LFC_EEM_CFG_PRIMARY_FUNC     (1 << 0)
49 };
50
51 struct tf_em_bnxt_lfc_dmabuf_fd {
52         int fd[TF_DIR_MAX][TF_MAX_TABLE];
53 };
54
55 #ifndef __user
56 #define __user
57 #endif
58
59 struct tf_em_bnxt_lfc_cfa_eem_dmabuf_export_req {
60         struct tf_em_bnxt_lfc_cfa_eem_std_hdr std;
61         uint8_t dir;
62         uint32_t flags;
63         void __user *dma_fd;
64 };
65
66 struct tf_em_bnxt_lfc_req {
67         struct tf_em_bnxt_lfc_req_hdr hdr;
68         union {
69                 struct tf_em_bnxt_lfc_cfa_eem_dmabuf_export_req
70                        eem_dmabuf_export_req;
71                 uint64_t hreq;
72         } req;
73 };
74
75 #define TF_EEM_BNXT_LFC_IOCTL_MAGIC     0x98
76 #define BNXT_LFC_REQ    \
77         _IOW(TF_EEM_BNXT_LFC_IOCTL_MAGIC, 1, struct tf_em_bnxt_lfc_req)
78
79 /**
80  * EM DBs.
81  */
82 extern void *eem_db[TF_DIR_MAX];
83
84 extern struct tf_tbl_scope_cb tbl_scopes[TF_NUM_TBL_SCOPE];
85
86 static void
87 tf_em_dmabuf_mem_unmap(struct hcapi_cfa_em_table *tbl)
88 {
89         struct hcapi_cfa_em_page_tbl *tp;
90         int level;
91         uint32_t page_no, pg_count;
92
93         for (level = (tbl->num_lvl - 1); level < tbl->num_lvl; level++) {
94                 tp = &tbl->pg_tbl[level];
95
96                 pg_count = tbl->page_cnt[level];
97                 for (page_no = 0; page_no < pg_count; page_no++) {
98                         if (tp->pg_va_tbl != NULL &&
99                             tp->pg_va_tbl[page_no] != NULL &&
100                             tp->pg_size != 0) {
101                                 (void)munmap(tp->pg_va_tbl[page_no],
102                                              tp->pg_size);
103                         }
104                 }
105
106                 tfp_free((void *)tp->pg_va_tbl);
107                 tfp_free((void *)tp->pg_pa_tbl);
108         }
109 }
110
111 /**
112  * Unregisters EM Ctx in Firmware
113  *
114  * [in] tfp
115  *   Pointer to a TruFlow handle
116  *
117  * [in] tbl_scope_cb
118  *   Pointer to a table scope control block
119  *
120  * [in] dir
121  *   Receive or transmit direction
122  */
123 static void
124 tf_em_ctx_unreg(struct tf_tbl_scope_cb *tbl_scope_cb,
125                 int dir)
126 {
127         struct hcapi_cfa_em_ctx_mem_info *ctxp =
128                 &tbl_scope_cb->em_ctx_info[dir];
129         struct hcapi_cfa_em_table *tbl;
130         int i;
131
132         for (i = TF_KEY0_TABLE; i < TF_MAX_TABLE; i++) {
133                 tbl = &ctxp->em_tables[i];
134                         tf_em_dmabuf_mem_unmap(tbl);
135         }
136 }
137
138 static int tf_export_tbl_scope(int lfc_fd,
139                                int *fd,
140                                int bus,
141                                int devfn)
142 {
143         struct tf_em_bnxt_lfc_req tf_lfc_req;
144         struct tf_em_bnxt_lfc_dmabuf_fd *dma_fd;
145         struct tfp_calloc_parms  mparms;
146         int rc;
147
148         memset(&tf_lfc_req, 0, sizeof(struct tf_em_bnxt_lfc_req));
149         tf_lfc_req.hdr.ver = 1;
150         tf_lfc_req.hdr.bus = bus;
151         tf_lfc_req.hdr.devfn = devfn;
152         tf_lfc_req.hdr.req_type = TF_EM_BNXT_LFC_CFA_EEM_DMABUF_EXPORT_REQ;
153         tf_lfc_req.req.eem_dmabuf_export_req.flags = O_ACCMODE;
154         tf_lfc_req.req.eem_dmabuf_export_req.std.version = 1;
155
156         mparms.nitems = 1;
157         mparms.size = sizeof(struct tf_em_bnxt_lfc_dmabuf_fd);
158         mparms.alignment = 0;
159         tfp_calloc(&mparms);
160         dma_fd = (struct tf_em_bnxt_lfc_dmabuf_fd *)mparms.mem_va;
161         tf_lfc_req.req.eem_dmabuf_export_req.dma_fd = dma_fd;
162
163         rc = ioctl(lfc_fd, BNXT_LFC_REQ, &tf_lfc_req);
164         if (rc) {
165                 TFP_DRV_LOG(ERR,
166                             "EXT EEM export chanel_fd %d, rc=%d\n",
167                             lfc_fd,
168                             rc);
169                 tfp_free(dma_fd);
170                 return rc;
171         }
172
173         memcpy(fd, dma_fd->fd, sizeof(dma_fd->fd));
174         tfp_free(dma_fd);
175
176         return rc;
177 }
178
179 static int
180 tf_em_dmabuf_mem_map(struct hcapi_cfa_em_table *tbl,
181                      int dmabuf_fd)
182 {
183         struct hcapi_cfa_em_page_tbl *tp;
184         int level;
185         uint32_t page_no;
186         uint32_t pg_count;
187         uint32_t offset;
188         struct tfp_calloc_parms parms;
189
190         for (level = (tbl->num_lvl - 1); level < tbl->num_lvl; level++) {
191                 tp = &tbl->pg_tbl[level];
192
193                 pg_count = tbl->page_cnt[level];
194                 offset = 0;
195
196                 parms.nitems = pg_count;
197                 parms.size = sizeof(void *);
198                 parms.alignment = 0;
199
200                 if ((tfp_calloc(&parms)) != 0)
201                         return -ENOMEM;
202
203                 tp->pg_va_tbl = parms.mem_va;
204                 parms.nitems = pg_count;
205                 parms.size = sizeof(void *);
206                 parms.alignment = 0;
207
208                 if ((tfp_calloc(&parms)) != 0) {
209                         tfp_free((void *)tp->pg_va_tbl);
210                         return -ENOMEM;
211                 }
212
213                 tp->pg_pa_tbl = parms.mem_va;
214                 tp->pg_count = 0;
215                 tp->pg_size =  TF_EM_PAGE_SIZE;
216
217                 for (page_no = 0; page_no < pg_count; page_no++) {
218                         tp->pg_va_tbl[page_no] = mmap(NULL,
219                                                       TF_EM_PAGE_SIZE,
220                                                       PROT_READ | PROT_WRITE,
221                                                       MAP_SHARED,
222                                                       dmabuf_fd,
223                                                       offset);
224                         if (tp->pg_va_tbl[page_no] == (void *)-1) {
225                                 TFP_DRV_LOG(ERR,
226                 "MMap memory error. level:%d page:%d pg_count:%d - %s\n",
227                                             level,
228                                      page_no,
229                                             pg_count,
230                                             strerror(errno));
231                                 return -ENOMEM;
232                         }
233                         offset += tp->pg_size;
234                         tp->pg_count++;
235                 }
236         }
237
238         return 0;
239 }
240
241 static int tf_mmap_tbl_scope(struct tf_tbl_scope_cb *tbl_scope_cb,
242                              enum tf_dir dir,
243                              int tbl_type,
244                              int dmabuf_fd)
245 {
246         struct hcapi_cfa_em_table *tbl;
247
248         if (tbl_type == TF_EFC_TABLE)
249                 return 0;
250
251         tbl = &tbl_scope_cb->em_ctx_info[dir].em_tables[tbl_type];
252         return tf_em_dmabuf_mem_map(tbl, dmabuf_fd);
253 }
254
255 #define TF_LFC_DEVICE "/dev/bnxt_lfc"
256
257 static int
258 tf_prepare_dmabuf_bnxt_lfc_device(struct tf_tbl_scope_cb *tbl_scope_cb)
259 {
260         int lfc_fd;
261
262         lfc_fd = open(TF_LFC_DEVICE, O_RDWR);
263         if (!lfc_fd) {
264                 TFP_DRV_LOG(ERR,
265                             "EEM: open %s device error\n",
266                             TF_LFC_DEVICE);
267                 return -ENOENT;
268         }
269
270         tbl_scope_cb->lfc_fd = lfc_fd;
271
272         return 0;
273 }
274
275 static int
276 offload_system_mmap(struct tf_tbl_scope_cb *tbl_scope_cb)
277 {
278         int rc;
279         int dmabuf_fd;
280         enum tf_dir dir;
281         enum hcapi_cfa_em_table_type tbl_type;
282
283         rc = tf_prepare_dmabuf_bnxt_lfc_device(tbl_scope_cb);
284         if (rc) {
285                 TFP_DRV_LOG(ERR, "EEM: Prepare bnxt_lfc channel failed\n");
286                 return rc;
287         }
288
289         rc = tf_export_tbl_scope(tbl_scope_cb->lfc_fd,
290                                  (int *)tbl_scope_cb->fd,
291                                  tbl_scope_cb->bus,
292                                  tbl_scope_cb->devfn);
293         if (rc) {
294                 TFP_DRV_LOG(ERR,
295                             "export dmabuf fd failed\n");
296                 return rc;
297         }
298
299         tbl_scope_cb->valid = true;
300
301         for (dir = 0; dir < TF_DIR_MAX; dir++) {
302                 for (tbl_type = TF_KEY0_TABLE; tbl_type <
303                              TF_MAX_TABLE; tbl_type++) {
304                         if (tbl_type == TF_EFC_TABLE)
305                                 continue;
306
307                         dmabuf_fd = tbl_scope_cb->fd[(dir ? 0 : 1)][tbl_type];
308                         rc = tf_mmap_tbl_scope(tbl_scope_cb,
309                                                dir,
310                                                tbl_type,
311                                                dmabuf_fd);
312                         if (rc) {
313                                 TFP_DRV_LOG(ERR,
314                                             "dir:%d tbl:%d mmap failed rc %d\n",
315                                             dir,
316                                             tbl_type,
317                                             rc);
318                                 break;
319                         }
320                 }
321         }
322         return 0;
323 }
324
325 static int
326 tf_destroy_dmabuf_bnxt_lfc_device(struct tf_tbl_scope_cb *tbl_scope_cb)
327 {
328         close(tbl_scope_cb->lfc_fd);
329
330         return 0;
331 }
332
333 static int
334 tf_dmabuf_alloc(struct tf *tfp, struct tf_tbl_scope_cb *tbl_scope_cb)
335 {
336         int rc;
337
338         rc = tfp_msg_hwrm_oem_cmd(tfp,
339                 tbl_scope_cb->em_ctx_info[TF_DIR_RX].em_tables[TF_KEY0_TABLE].num_entries);
340         if (rc)
341                 PMD_DRV_LOG(ERR, "EEM: Failed to prepare system memory rc:%d\n",
342                             rc);
343
344         return 0;
345 }
346
347 static int
348 tf_dmabuf_free(struct tf *tfp, struct tf_tbl_scope_cb *tbl_scope_cb)
349 {
350         int rc;
351
352         rc = tfp_msg_hwrm_oem_cmd(tfp, 0);
353         if (rc)
354                 TFP_DRV_LOG(ERR, "EEM: Failed to cleanup system memory\n");
355
356         tf_destroy_dmabuf_bnxt_lfc_device(tbl_scope_cb);
357
358         return 0;
359 }
360
361 int
362 tf_em_ext_alloc(struct tf *tfp,
363                 struct tf_alloc_tbl_scope_parms *parms)
364 {
365         int rc;
366         struct tf_session *tfs;
367         struct tf_tbl_scope_cb *tbl_scope_cb;
368         struct tf_rm_allocate_parms aparms = { 0 };
369         struct tf_free_tbl_scope_parms free_parms;
370         struct tf_rm_free_parms fparms = { 0 };
371         int dir;
372         int i;
373         struct hcapi_cfa_em_table *em_tables;
374
375         TF_CHECK_PARMS2(tfp, parms);
376
377         /* Retrieve the session information */
378         rc = tf_session_get_session(tfp, &tfs);
379         if (rc) {
380                 TFP_DRV_LOG(ERR,
381                             "Failed to lookup session, rc:%s\n",
382                             strerror(-rc));
383                 return rc;
384         }
385
386         aparms.rm_db = eem_db[TF_DIR_RX];
387         aparms.db_index = TF_EM_TBL_TYPE_TBL_SCOPE;
388         aparms.index = (uint32_t *)&parms->tbl_scope_id;
389         rc = tf_rm_allocate(&aparms);
390         if (rc) {
391                 TFP_DRV_LOG(ERR,
392                             "Failed to allocate table scope\n");
393                 return rc;
394         }
395
396         tbl_scope_cb = &tbl_scopes[parms->tbl_scope_id];
397         tbl_scope_cb->index = parms->tbl_scope_id;
398         tbl_scope_cb->tbl_scope_id = parms->tbl_scope_id;
399         tbl_scope_cb->bus = tfs->session_id.internal.bus;
400         tbl_scope_cb->devfn = tfs->session_id.internal.device;
401
402         for (dir = 0; dir < TF_DIR_MAX; dir++) {
403                 rc = tf_msg_em_qcaps(tfp,
404                                      dir,
405                                      &tbl_scope_cb->em_caps[dir]);
406                 if (rc) {
407                         TFP_DRV_LOG(ERR,
408                                     "EEM: Unable to query for EEM capability,"
409                                     " rc:%s\n",
410                                     strerror(-rc));
411                         goto cleanup;
412                 }
413         }
414
415         /*
416          * Validate and setup table sizes
417          */
418         if (tf_em_validate_num_entries(tbl_scope_cb, parms))
419                 goto cleanup;
420
421         rc = tf_dmabuf_alloc(tfp, tbl_scope_cb);
422         if (rc) {
423                 TFP_DRV_LOG(ERR,
424                             "System DMA buff alloc failed\n");
425                 return -EIO;
426         }
427
428         for (dir = 0; dir < TF_DIR_MAX; dir++) {
429                 for (i = TF_KEY0_TABLE; i < TF_MAX_TABLE; i++) {
430                         if (i == TF_EFC_TABLE)
431                                 continue;
432
433                         em_tables =
434                                 &tbl_scope_cb->em_ctx_info[dir].em_tables[i];
435
436                         rc = tf_em_size_table(em_tables, TF_EM_PAGE_SIZE);
437                         if (rc) {
438                                 TFP_DRV_LOG(ERR, "Size table failed\n");
439                                 goto cleanup;
440                         }
441                 }
442
443                 em_tables = tbl_scope_cb->em_ctx_info[dir].em_tables;
444                 rc = tf_create_tbl_pool_external(dir,
445                                         tbl_scope_cb,
446                                         em_tables[TF_RECORD_TABLE].num_entries,
447                                         em_tables[TF_RECORD_TABLE].entry_size);
448
449                 if (rc) {
450                         TFP_DRV_LOG(ERR,
451                                     "%s TBL: Unable to allocate idx pools %s\n",
452                                     tf_dir_2_str(dir),
453                                     strerror(-rc));
454                         goto cleanup_full;
455                 }
456         }
457
458         rc = offload_system_mmap(tbl_scope_cb);
459
460         if (rc) {
461                 TFP_DRV_LOG(ERR,
462                             "System alloc mmap failed\n");
463                 goto cleanup_full;
464         }
465
466         return rc;
467
468 cleanup_full:
469         free_parms.tbl_scope_id = parms->tbl_scope_id;
470         tf_em_ext_free(tfp, &free_parms);
471         return -EINVAL;
472
473 cleanup:
474         /* Free Table control block */
475         fparms.rm_db = eem_db[TF_DIR_RX];
476         fparms.db_index = TF_EM_TBL_TYPE_TBL_SCOPE;
477         fparms.index = parms->tbl_scope_id;
478         tf_rm_free(&fparms);
479         return -EINVAL;
480 }
481
482 int
483 tf_em_ext_free(struct tf *tfp,
484                struct tf_free_tbl_scope_parms *parms)
485 {
486         int rc;
487         struct tf_session *tfs;
488         struct tf_tbl_scope_cb *tbl_scope_cb;
489         int dir;
490         struct tf_rm_free_parms aparms = { 0 };
491
492         TF_CHECK_PARMS2(tfp, parms);
493
494         /* Retrieve the session information */
495         rc = tf_session_get_session(tfp, &tfs);
496         if (rc) {
497                 TFP_DRV_LOG(ERR,
498                             "Failed to lookup session, rc:%s\n",
499                             strerror(-rc));
500                 return rc;
501         }
502
503         tbl_scope_cb = &tbl_scopes[parms->tbl_scope_id];
504
505                 /* Free Table control block */
506         aparms.rm_db = eem_db[TF_DIR_RX];
507         aparms.db_index = TF_EM_TBL_TYPE_TBL_SCOPE;
508         aparms.index = parms->tbl_scope_id;
509         rc = tf_rm_free(&aparms);
510         if (rc) {
511                 TFP_DRV_LOG(ERR,
512                             "Failed to free table scope\n");
513         }
514
515         for (dir = 0; dir < TF_DIR_MAX; dir++) {
516                 /* Free associated external pools
517                  */
518                 tf_destroy_tbl_pool_external(dir,
519                                              tbl_scope_cb);
520
521                 /* Unmap memory */
522                 tf_em_ctx_unreg(tbl_scope_cb, dir);
523
524                 tf_msg_em_op(tfp,
525                              dir,
526                              HWRM_TF_EXT_EM_OP_INPUT_OP_EXT_EM_DISABLE);
527         }
528
529         tf_dmabuf_free(tfp, tbl_scope_cb);
530
531         return rc;
532 }