net/bnxt: delay EEM sysmem mapping
[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 int offload_system_mmap(struct tf_tbl_scope_cb *tbl_scope_cb)
276 {
277         int rc;
278         int dmabuf_fd;
279         enum tf_dir dir;
280         enum hcapi_cfa_em_table_type tbl_type;
281
282         rc = tf_prepare_dmabuf_bnxt_lfc_device(tbl_scope_cb);
283         if (rc) {
284                 TFP_DRV_LOG(ERR, "EEM: Prepare bnxt_lfc channel failed\n");
285                 return rc;
286         }
287
288         rc = tf_export_tbl_scope(tbl_scope_cb->lfc_fd,
289                                  (int *)tbl_scope_cb->fd,
290                                  tbl_scope_cb->bus,
291                                  tbl_scope_cb->devfn);
292         if (rc) {
293                 TFP_DRV_LOG(ERR,
294                             "export dmabuf fd failed\n");
295                 return rc;
296         }
297
298         tbl_scope_cb->valid = true;
299
300         for (dir = 0; dir < TF_DIR_MAX; dir++) {
301                 for (tbl_type = TF_KEY0_TABLE; tbl_type <
302                              TF_MAX_TABLE; tbl_type++) {
303                         if (tbl_type == TF_EFC_TABLE)
304                                 continue;
305
306                         dmabuf_fd = tbl_scope_cb->fd[(dir ? 0 : 1)][tbl_type];
307                         rc = tf_mmap_tbl_scope(tbl_scope_cb,
308                                                dir,
309                                                tbl_type,
310                                                dmabuf_fd);
311                         if (rc) {
312                                 TFP_DRV_LOG(ERR,
313                                             "dir:%d tbl:%d mmap failed rc %d\n",
314                                             dir,
315                                             tbl_type,
316                                             rc);
317                                 break;
318                         }
319                 }
320         }
321         return 0;
322 }
323
324 static int
325 tf_destroy_dmabuf_bnxt_lfc_device(struct tf_tbl_scope_cb *tbl_scope_cb)
326 {
327         close(tbl_scope_cb->lfc_fd);
328
329         return 0;
330 }
331
332 static int
333 tf_dmabuf_alloc(struct tf *tfp, struct tf_tbl_scope_cb *tbl_scope_cb)
334 {
335         int rc;
336
337         rc = tfp_msg_hwrm_oem_cmd(tfp,
338                 tbl_scope_cb->em_ctx_info[TF_DIR_RX].em_tables[TF_KEY0_TABLE].num_entries);
339         if (rc)
340                 PMD_DRV_LOG(ERR, "EEM: Failed to prepare system memory rc:%d\n",
341                             rc);
342
343         return 0;
344 }
345
346 static int
347 tf_dmabuf_free(struct tf *tfp, struct tf_tbl_scope_cb *tbl_scope_cb)
348 {
349         int rc;
350
351         rc = tfp_msg_hwrm_oem_cmd(tfp, 0);
352         if (rc)
353                 TFP_DRV_LOG(ERR, "EEM: Failed to cleanup system memory\n");
354
355         tf_destroy_dmabuf_bnxt_lfc_device(tbl_scope_cb);
356
357         return 0;
358 }
359
360 int
361 tf_em_ext_alloc(struct tf *tfp,
362                 struct tf_alloc_tbl_scope_parms *parms)
363 {
364         int rc;
365         struct tf_session *tfs;
366         struct tf_tbl_scope_cb *tbl_scope_cb;
367         struct tf_rm_allocate_parms aparms = { 0 };
368         struct tf_free_tbl_scope_parms free_parms;
369         struct tf_rm_free_parms fparms = { 0 };
370         int dir;
371         int i;
372         struct hcapi_cfa_em_table *em_tables;
373
374         TF_CHECK_PARMS2(tfp, parms);
375
376         /* Retrieve the session information */
377         rc = tf_session_get_session(tfp, &tfs);
378         if (rc) {
379                 TFP_DRV_LOG(ERR,
380                             "Failed to lookup session, rc:%s\n",
381                             strerror(-rc));
382                 return rc;
383         }
384
385         aparms.rm_db = eem_db[TF_DIR_RX];
386         aparms.db_index = TF_EM_TBL_TYPE_TBL_SCOPE;
387         aparms.index = (uint32_t *)&parms->tbl_scope_id;
388         rc = tf_rm_allocate(&aparms);
389         if (rc) {
390                 TFP_DRV_LOG(ERR,
391                             "Failed to allocate table scope\n");
392                 return rc;
393         }
394
395         tbl_scope_cb = &tbl_scopes[parms->tbl_scope_id];
396         tbl_scope_cb->index = parms->tbl_scope_id;
397         tbl_scope_cb->tbl_scope_id = parms->tbl_scope_id;
398         tbl_scope_cb->bus = tfs->session_id.internal.bus;
399         tbl_scope_cb->devfn = tfs->session_id.internal.device;
400
401         for (dir = 0; dir < TF_DIR_MAX; dir++) {
402                 rc = tf_msg_em_qcaps(tfp,
403                                      dir,
404                                      &tbl_scope_cb->em_caps[dir]);
405                 if (rc) {
406                         TFP_DRV_LOG(ERR,
407                                     "EEM: Unable to query for EEM capability,"
408                                     " rc:%s\n",
409                                     strerror(-rc));
410                         goto cleanup;
411                 }
412         }
413
414         /*
415          * Validate and setup table sizes
416          */
417         if (tf_em_validate_num_entries(tbl_scope_cb, parms))
418                 goto cleanup;
419
420         rc = tf_dmabuf_alloc(tfp, tbl_scope_cb);
421         if (rc) {
422                 TFP_DRV_LOG(ERR,
423                             "System DMA buff alloc failed\n");
424                 return -EIO;
425         }
426
427         for (dir = 0; dir < TF_DIR_MAX; dir++) {
428                 for (i = TF_KEY0_TABLE; i < TF_MAX_TABLE; i++) {
429                         if (i == TF_EFC_TABLE)
430                                 continue;
431
432                         em_tables =
433                                 &tbl_scope_cb->em_ctx_info[dir].em_tables[i];
434
435                         rc = tf_em_size_table(em_tables, TF_EM_PAGE_SIZE);
436                         if (rc) {
437                                 TFP_DRV_LOG(ERR, "Size table failed\n");
438                                 goto cleanup;
439                         }
440                 }
441
442                 em_tables = tbl_scope_cb->em_ctx_info[dir].em_tables;
443                 rc = tf_create_tbl_pool_external(dir,
444                                         tbl_scope_cb,
445                                         em_tables[TF_RECORD_TABLE].num_entries,
446                                         em_tables[TF_RECORD_TABLE].entry_size);
447
448                 if (rc) {
449                         TFP_DRV_LOG(ERR,
450                                     "%s TBL: Unable to allocate idx pools %s\n",
451                                     tf_dir_2_str(dir),
452                                     strerror(-rc));
453                         goto cleanup_full;
454                 }
455         }
456
457 #if (TF_EM_SYSMEM_DELAY_EXPORT == 0)
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 #endif
466
467         return rc;
468
469 cleanup_full:
470         free_parms.tbl_scope_id = parms->tbl_scope_id;
471         tf_em_ext_free(tfp, &free_parms);
472         return -EINVAL;
473
474 cleanup:
475         /* Free Table control block */
476         fparms.rm_db = eem_db[TF_DIR_RX];
477         fparms.db_index = TF_EM_TBL_TYPE_TBL_SCOPE;
478         fparms.index = parms->tbl_scope_id;
479         tf_rm_free(&fparms);
480         return -EINVAL;
481 }
482
483 int
484 tf_em_ext_free(struct tf *tfp,
485                struct tf_free_tbl_scope_parms *parms)
486 {
487         int rc;
488         struct tf_session *tfs;
489         struct tf_tbl_scope_cb *tbl_scope_cb;
490         int dir;
491         struct tf_rm_free_parms aparms = { 0 };
492
493         TF_CHECK_PARMS2(tfp, parms);
494
495         /* Retrieve the session information */
496         rc = tf_session_get_session(tfp, &tfs);
497         if (rc) {
498                 TFP_DRV_LOG(ERR,
499                             "Failed to lookup session, rc:%s\n",
500                             strerror(-rc));
501                 return rc;
502         }
503
504         tbl_scope_cb = &tbl_scopes[parms->tbl_scope_id];
505
506                 /* Free Table control block */
507         aparms.rm_db = eem_db[TF_DIR_RX];
508         aparms.db_index = TF_EM_TBL_TYPE_TBL_SCOPE;
509         aparms.index = parms->tbl_scope_id;
510         rc = tf_rm_free(&aparms);
511         if (rc) {
512                 TFP_DRV_LOG(ERR,
513                             "Failed to free table scope\n");
514         }
515
516         for (dir = 0; dir < TF_DIR_MAX; dir++) {
517                 /* Free associated external pools
518                  */
519                 tf_destroy_tbl_pool_external(dir,
520                                              tbl_scope_cb);
521
522                 /* Unmap memory */
523                 tf_em_ctx_unreg(tbl_scope_cb, dir);
524
525                 tf_msg_em_op(tfp,
526                              dir,
527                              HWRM_TF_EXT_EM_OP_INPUT_OP_EXT_EM_DISABLE);
528         }
529
530         tf_dmabuf_free(tfp, tbl_scope_cb);
531         tbl_scope_cb->valid = false;
532
533         return rc;
534 }