net/bnxt: support two table scopes
[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_free_tbl_scope_parms free_parms;
368         int dir;
369         int i;
370         struct hcapi_cfa_em_table *em_tables;
371
372         TF_CHECK_PARMS2(tfp, parms);
373
374         /* Retrieve the session information */
375         rc = tf_session_get_session(tfp, &tfs);
376         if (rc) {
377                 TFP_DRV_LOG(ERR,
378                             "Failed to lookup session, rc:%s\n",
379                             strerror(-rc));
380                 return rc;
381         }
382
383         rc = tf_tbl_scope_alloc(&parms->tbl_scope_id);
384         if (rc) {
385                 TFP_DRV_LOG(ERR,
386                             "Failed to allocate table scope\n");
387                 return rc;
388         }
389
390         tbl_scope_cb = &tbl_scopes[parms->tbl_scope_id];
391         tbl_scope_cb->index = parms->tbl_scope_id;
392         tbl_scope_cb->tbl_scope_id = parms->tbl_scope_id;
393         tbl_scope_cb->bus = tfs->session_id.internal.bus;
394         tbl_scope_cb->devfn = tfs->session_id.internal.device;
395
396         for (dir = 0; dir < TF_DIR_MAX; dir++) {
397                 rc = tf_msg_em_qcaps(tfp,
398                                      dir,
399                                      &tbl_scope_cb->em_caps[dir]);
400                 if (rc) {
401                         TFP_DRV_LOG(ERR,
402                                     "EEM: Unable to query for EEM capability,"
403                                     " rc:%s\n",
404                                     strerror(-rc));
405                         goto cleanup;
406                 }
407         }
408
409         /*
410          * Validate and setup table sizes
411          */
412         if (tf_em_validate_num_entries(tbl_scope_cb, parms))
413                 goto cleanup;
414
415         rc = tf_dmabuf_alloc(tfp, tbl_scope_cb);
416         if (rc) {
417                 TFP_DRV_LOG(ERR,
418                             "System DMA buff alloc failed\n");
419                 return -EIO;
420         }
421
422         for (dir = 0; dir < TF_DIR_MAX; dir++) {
423                 for (i = TF_KEY0_TABLE; i < TF_MAX_TABLE; i++) {
424                         if (i == TF_EFC_TABLE)
425                                 continue;
426
427                         em_tables =
428                                 &tbl_scope_cb->em_ctx_info[dir].em_tables[i];
429
430                         rc = tf_em_size_table(em_tables, TF_EM_PAGE_SIZE);
431                         if (rc) {
432                                 TFP_DRV_LOG(ERR, "Size table failed\n");
433                                 goto cleanup;
434                         }
435                 }
436
437                 em_tables = tbl_scope_cb->em_ctx_info[dir].em_tables;
438                 rc = tf_create_tbl_pool_external(dir,
439                                         tbl_scope_cb,
440                                         em_tables[TF_RECORD_TABLE].num_entries,
441                                         em_tables[TF_RECORD_TABLE].entry_size);
442
443                 if (rc) {
444                         TFP_DRV_LOG(ERR,
445                                     "%s TBL: Unable to allocate idx pools %s\n",
446                                     tf_dir_2_str(dir),
447                                     strerror(-rc));
448                         goto cleanup_full;
449                 }
450         }
451
452 #if (TF_EM_SYSMEM_DELAY_EXPORT == 0)
453         rc = offload_system_mmap(tbl_scope_cb);
454
455         if (rc) {
456                 TFP_DRV_LOG(ERR,
457                             "System alloc mmap failed\n");
458                 goto cleanup_full;
459         }
460 #endif
461
462         return rc;
463
464 cleanup_full:
465         free_parms.tbl_scope_id = parms->tbl_scope_id;
466         tf_em_ext_free(tfp, &free_parms);
467         return -EINVAL;
468
469 cleanup:
470         /* Free Table control block */
471         tf_tbl_scope_free(parms->tbl_scope_id);
472         return -EINVAL;
473 }
474
475 int
476 tf_em_ext_free(struct tf *tfp,
477                struct tf_free_tbl_scope_parms *parms)
478 {
479         int rc;
480         struct tf_session *tfs;
481         struct tf_tbl_scope_cb *tbl_scope_cb;
482         int dir;
483
484         TF_CHECK_PARMS2(tfp, parms);
485
486         /* Retrieve the session information */
487         rc = tf_session_get_session(tfp, &tfs);
488         if (rc) {
489                 TFP_DRV_LOG(ERR,
490                             "Failed to lookup session, rc:%s\n",
491                             strerror(-rc));
492                 return rc;
493         }
494
495         tbl_scope_cb = &tbl_scopes[parms->tbl_scope_id];
496
497         rc = tf_tbl_scope_free(parms->tbl_scope_id);
498         if (rc) {
499                 TFP_DRV_LOG(ERR,
500                             "Failed to free table scope\n");
501         }
502
503         for (dir = 0; dir < TF_DIR_MAX; dir++) {
504                 /* Free associated external pools
505                  */
506                 tf_destroy_tbl_pool_external(dir,
507                                              tbl_scope_cb);
508
509                 /* Unmap memory */
510                 tf_em_ctx_unreg(tbl_scope_cb, dir);
511
512                 tf_msg_em_op(tfp,
513                              dir,
514                              HWRM_TF_EXT_EM_OP_INPUT_OP_EXT_EM_DISABLE);
515         }
516
517         tf_dmabuf_free(tfp, tbl_scope_cb);
518         tbl_scope_cb->valid = false;
519
520         return rc;
521 }