net/bnxt: add initial TruFlow core resource management
[dpdk.git] / drivers / net / bnxt / tf_core / tf_core.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2020 Broadcom
3  * All rights reserved.
4  */
5
6 #include <stdio.h>
7
8 #include "tf_core.h"
9 #include "tf_session.h"
10 #include "tf_rm.h"
11 #include "tf_msg.h"
12 #include "tfp.h"
13 #include "bitalloc.h"
14 #include "bnxt.h"
15 #include "rand.h"
16
17 static inline uint32_t SWAP_WORDS32(uint32_t val32)
18 {
19         return (((val32 & 0x0000ffff) << 16) |
20                 ((val32 & 0xffff0000) >> 16));
21 }
22
23 static void tf_seeds_init(struct tf_session *session)
24 {
25         int i;
26         uint32_t r;
27
28         /* Initialize the lfsr */
29         rand_init();
30
31         /* RX and TX use the same seed values */
32         session->lkup_lkup3_init_cfg[TF_DIR_RX] =
33                 session->lkup_lkup3_init_cfg[TF_DIR_TX] =
34                                                 SWAP_WORDS32(rand32());
35
36         for (i = 0; i < TF_LKUP_SEED_MEM_SIZE / 2; i++) {
37                 r = SWAP_WORDS32(rand32());
38                 session->lkup_em_seed_mem[TF_DIR_RX][i * 2] = r;
39                 session->lkup_em_seed_mem[TF_DIR_TX][i * 2] = r;
40                 r = SWAP_WORDS32(rand32());
41                 session->lkup_em_seed_mem[TF_DIR_RX][i * 2 + 1] = (r & 0x1);
42                 session->lkup_em_seed_mem[TF_DIR_TX][i * 2 + 1] = (r & 0x1);
43         }
44 }
45
46 int
47 tf_open_session(struct tf                    *tfp,
48                 struct tf_open_session_parms *parms)
49 {
50         int rc;
51         struct tf_session *session;
52         struct tfp_calloc_parms alloc_parms;
53         unsigned int domain, bus, slot, device;
54         uint8_t fw_session_id;
55
56         if (tfp == NULL || parms == NULL)
57                 return -EINVAL;
58
59         /* Filter out any non-supported device types on the Core
60          * side. It is assumed that the Firmware will be supported if
61          * firmware open session succeeds.
62          */
63         if (parms->device_type != TF_DEVICE_TYPE_WH)
64                 return -ENOTSUP;
65
66         /* Build the beginning of session_id */
67         rc = sscanf(parms->ctrl_chan_name,
68                     "%x:%x:%x.%d",
69                     &domain,
70                     &bus,
71                     &slot,
72                     &device);
73         if (rc != 4) {
74                 PMD_DRV_LOG(ERR,
75                             "Failed to scan device ctrl_chan_name\n");
76                 return -EINVAL;
77         }
78
79         /* open FW session and get a new session_id */
80         rc = tf_msg_session_open(tfp,
81                                  parms->ctrl_chan_name,
82                                  &fw_session_id);
83         if (rc) {
84                 /* Log error */
85                 if (rc == -EEXIST)
86                         PMD_DRV_LOG(ERR,
87                                     "Session is already open, rc:%d\n",
88                                     rc);
89                 else
90                         PMD_DRV_LOG(ERR,
91                                     "Open message send failed, rc:%d\n",
92                                     rc);
93
94                 parms->session_id.id = TF_FW_SESSION_ID_INVALID;
95                 return rc;
96         }
97
98         /* Allocate session */
99         alloc_parms.nitems = 1;
100         alloc_parms.size = sizeof(struct tf_session_info);
101         alloc_parms.alignment = 0;
102         rc = tfp_calloc(&alloc_parms);
103         if (rc) {
104                 /* Log error */
105                 PMD_DRV_LOG(ERR,
106                             "Failed to allocate session info, rc:%d\n",
107                             rc);
108                 goto cleanup;
109         }
110
111         tfp->session = (struct tf_session_info *)alloc_parms.mem_va;
112
113         /* Allocate core data for the session */
114         alloc_parms.nitems = 1;
115         alloc_parms.size = sizeof(struct tf_session);
116         alloc_parms.alignment = 0;
117         rc = tfp_calloc(&alloc_parms);
118         if (rc) {
119                 /* Log error */
120                 PMD_DRV_LOG(ERR,
121                             "Failed to allocate session data, rc:%d\n",
122                             rc);
123                 goto cleanup;
124         }
125
126         tfp->session->core_data = alloc_parms.mem_va;
127
128         session = (struct tf_session *)tfp->session->core_data;
129         tfp_memcpy(session->ctrl_chan_name,
130                    parms->ctrl_chan_name,
131                    TF_SESSION_NAME_MAX);
132
133         /* Initialize Session */
134         session->device_type = parms->device_type;
135         tf_rm_init(tfp);
136
137         /* Construct the Session ID */
138         session->session_id.internal.domain = domain;
139         session->session_id.internal.bus = bus;
140         session->session_id.internal.device = device;
141         session->session_id.internal.fw_session_id = fw_session_id;
142
143         rc = tf_msg_session_qcfg(tfp);
144         if (rc) {
145                 /* Log error */
146                 PMD_DRV_LOG(ERR,
147                             "Query config message send failed, rc:%d\n",
148                             rc);
149                 goto cleanup_close;
150         }
151
152         /* Adjust the Session with what firmware allowed us to get */
153         rc = tf_rm_allocate_validate(tfp);
154         if (rc) {
155                 /* Log error */
156                 goto cleanup_close;
157         }
158
159         /* Setup hash seeds */
160         tf_seeds_init(session);
161
162         session->ref_count++;
163
164         /* Return session ID */
165         parms->session_id = session->session_id;
166
167         PMD_DRV_LOG(INFO,
168                     "Session created, session_id:%d\n",
169                     parms->session_id.id);
170
171         PMD_DRV_LOG(INFO,
172                     "domain:%d, bus:%d, device:%d, fw_session_id:%d\n",
173                     parms->session_id.internal.domain,
174                     parms->session_id.internal.bus,
175                     parms->session_id.internal.device,
176                     parms->session_id.internal.fw_session_id);
177
178         return 0;
179
180  cleanup:
181         tfp_free(tfp->session->core_data);
182         tfp_free(tfp->session);
183         tfp->session = NULL;
184         return rc;
185
186  cleanup_close:
187         tf_close_session(tfp);
188         return -EINVAL;
189 }
190
191 int
192 tf_attach_session(struct tf *tfp __rte_unused,
193                   struct tf_attach_session_parms *parms __rte_unused)
194 {
195 #if (TF_SHARED == 1)
196         int rc;
197
198         if (tfp == NULL)
199                 return -EINVAL;
200
201         /* - Open the shared memory for the attach_chan_name
202          * - Point to the shared session for this Device instance
203          * - Check that session is valid
204          * - Attach to the firmware so it can record there is more
205          *   than one client of the session.
206          */
207
208         if (tfp->session) {
209                 if (tfp->session->session_id.id != TF_SESSION_ID_INVALID) {
210                         rc = tf_msg_session_attach(tfp,
211                                                    parms->ctrl_chan_name,
212                                                    parms->session_id);
213                 }
214         }
215 #endif /* TF_SHARED */
216         return -1;
217 }
218
219 int
220 tf_close_session(struct tf *tfp)
221 {
222         int rc;
223         int rc_close = 0;
224         struct tf_session *tfs;
225         union tf_session_id session_id;
226
227         if (tfp == NULL || tfp->session == NULL)
228                 return -EINVAL;
229
230         tfs = (struct tf_session *)(tfp->session->core_data);
231
232         /* Cleanup if we're last user of the session */
233         if (tfs->ref_count == 1) {
234                 /* Cleanup any outstanding resources */
235                 rc_close = tf_rm_close(tfp);
236         }
237
238         if (tfs->session_id.id != TF_SESSION_ID_INVALID) {
239                 rc = tf_msg_session_close(tfp);
240                 if (rc) {
241                         /* Log error */
242                         PMD_DRV_LOG(ERR,
243                                     "Message send failed, rc:%d\n",
244                                     rc);
245                 }
246
247                 /* Update the ref_count */
248                 tfs->ref_count--;
249         }
250
251         session_id = tfs->session_id;
252
253         /* Final cleanup as we're last user of the session */
254         if (tfs->ref_count == 0) {
255                 tfp_free(tfp->session->core_data);
256                 tfp_free(tfp->session);
257                 tfp->session = NULL;
258         }
259
260         PMD_DRV_LOG(INFO,
261                     "Session closed, session_id:%d\n",
262                     session_id.id);
263
264         PMD_DRV_LOG(INFO,
265                     "domain:%d, bus:%d, device:%d, fw_session_id:%d\n",
266                     session_id.internal.domain,
267                     session_id.internal.bus,
268                     session_id.internal.device,
269                     session_id.internal.fw_session_id);
270
271         return rc_close;
272 }