Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2019-2023 Broadcom
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include <rte_common.h>
7 : : #include <rte_cycles.h>
8 : : #include <rte_malloc.h>
9 : : #include <rte_log.h>
10 : : #include <rte_alarm.h>
11 : : #include "bnxt.h"
12 : : #include "bnxt_ulp.h"
13 : : #include "bnxt_tf_common.h"
14 : : #include "ulp_ha_mgr.h"
15 : : #include "ulp_flow_db.h"
16 : :
17 : : /* Local only MACROs and defines that aren't exported */
18 : : #define ULP_HA_TIMER_THREAD (1 << 0)
19 : : #define ULP_HA_TIMER_IS_RUNNING(info) (!!((info)->flags & ULP_HA_TIMER_THREAD))
20 : : #define ULP_HA_TIMER_SEC 1
21 : : #define ULP_HA_WAIT_TIME (MS_PER_S / 10)
22 : : #define ULP_HA_WAIT_TIMEOUT (MS_PER_S * 2)
23 : :
24 : : #define ULP_HA_IF_TBL_DIR TF_DIR_RX
25 : : #define ULP_HA_IF_TBL_TYPE TF_IF_TBL_TYPE_PROF_PARIF_ERR_ACT_REC_PTR
26 : :
27 : : static void ulp_ha_mgr_timer_cancel(struct bnxt_ulp_context *ulp_ctx);
28 : : static int32_t ulp_ha_mgr_timer_start(void *arg);
29 : : static void ulp_ha_mgr_timer_cb(void *arg);
30 : : static int32_t ulp_ha_mgr_app_type_set(struct bnxt_ulp_context *ulp_ctx,
31 : : enum ulp_ha_mgr_app_type app_type);
32 : : static int32_t
33 : : ulp_ha_mgr_region_set(struct bnxt_ulp_context *ulp_ctx,
34 : : enum ulp_ha_mgr_region region);
35 : : static int32_t
36 : : ulp_ha_mgr_state_set(struct bnxt_ulp_context *ulp_ctx,
37 : : enum ulp_ha_mgr_state state);
38 : :
39 : : static int32_t
40 : : ulp_ha_mgr_tf_client_num_get(struct bnxt_ulp_context *ulp_ctx, uint32_t *cnt);
41 : :
42 : : static int32_t
43 : 0 : ulp_ha_mgr_state_set_v1(struct bnxt_ulp_context *ulp_ctx,
44 : : enum ulp_ha_mgr_state state)
45 : : {
46 : 0 : struct tf_set_if_tbl_entry_parms set_parms = { 0 };
47 : : struct tf *tfp;
48 : 0 : uint32_t val = 0;
49 : : int32_t rc = 0;
50 : :
51 [ # # ]: 0 : if (ulp_ctx == NULL) {
52 : 0 : BNXT_TF_DBG(ERR, "Invalid parms in state get.\n");
53 : 0 : return -EINVAL;
54 : : }
55 : 0 : tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_DEFAULT);
56 [ # # ]: 0 : if (tfp == NULL) {
57 : 0 : BNXT_TF_DBG(ERR, "Unable to get the TFP.\n");
58 : 0 : return -EINVAL;
59 : : }
60 : :
61 : 0 : val = (uint32_t)state;
62 : :
63 : 0 : set_parms.dir = ULP_HA_IF_TBL_DIR;
64 : 0 : set_parms.type = ULP_HA_IF_TBL_TYPE;
65 : 0 : set_parms.data = (uint8_t *)&val;
66 : 0 : set_parms.data_sz_in_bytes = sizeof(val);
67 : 0 : set_parms.idx = bnxt_ulp_ha_reg_state_get(ulp_ctx);
68 : :
69 : 0 : rc = tf_set_if_tbl_entry(tfp, &set_parms);
70 [ # # ]: 0 : if (rc)
71 : 0 : BNXT_TF_DBG(ERR, "Failed to write the HA state\n");
72 : :
73 : : return rc;
74 : : }
75 : :
76 : : static int32_t
77 : 0 : ulp_ha_mgr_state_set_v2(struct bnxt_ulp_context *ulp_ctx,
78 : : enum ulp_ha_mgr_state state)
79 : : {
80 : 0 : struct tf_set_session_hotup_state_parms parms = { 0 };
81 : : struct tf *tfp;
82 : : int32_t rc = 0;
83 : :
84 [ # # ]: 0 : if (ulp_ctx == NULL) {
85 : 0 : BNXT_TF_DBG(ERR, "Invalid parms in state get.\n");
86 : 0 : return -EINVAL;
87 : : }
88 : :
89 : 0 : tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_SHARED_WC);
90 [ # # ]: 0 : if (tfp == NULL) {
91 : 0 : BNXT_TF_DBG(ERR, "Unable to get the TFP.\n");
92 : 0 : return -EINVAL;
93 : : }
94 : :
95 : 0 : parms.state = (uint16_t)state;
96 : 0 : rc = tf_set_session_hotup_state(tfp, &parms);
97 [ # # ]: 0 : if (rc) {
98 : 0 : BNXT_TF_DBG(ERR, "Failed to write the HA state\n");
99 : 0 : return rc;
100 : : }
101 : :
102 : : return rc;
103 : : }
104 : :
105 : : static int32_t
106 : 0 : ulp_ha_mgr_state_set(struct bnxt_ulp_context *ulp_ctx,
107 : : enum ulp_ha_mgr_state state)
108 : : {
109 [ # # ]: 0 : if (bnxt_ulp_cntxt_multi_shared_session_enabled(ulp_ctx))
110 : 0 : return ulp_ha_mgr_state_set_v2(ulp_ctx, state);
111 : : else
112 : 0 : return ulp_ha_mgr_state_set_v1(ulp_ctx, state);
113 : : }
114 : :
115 : : static int32_t
116 : 0 : ulp_ha_mgr_tf_state_get(struct bnxt_ulp_context *ulp_ctx,
117 : : uint32_t *state,
118 : : uint32_t *cnt)
119 : : {
120 : 0 : struct tf_get_session_hotup_state_parms parms = { 0 };
121 : : struct tf *tfp;
122 : : int32_t rc = 0;
123 : :
124 [ # # ]: 0 : if (ulp_ctx == NULL) {
125 : 0 : BNXT_TF_DBG(ERR, "Invalid parms in client num get.\n");
126 : 0 : return -EINVAL;
127 : : }
128 : :
129 : 0 : tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_SHARED_WC);
130 [ # # ]: 0 : if (tfp == NULL) {
131 : 0 : BNXT_TF_DBG(ERR, "Unable to get the TFP.\n");
132 : 0 : return -EINVAL;
133 : : }
134 : :
135 : 0 : rc = tf_get_session_hotup_state(tfp, &parms);
136 [ # # ]: 0 : if (rc) {
137 : 0 : BNXT_TF_DBG(ERR, "Failed to read the HA state\n");
138 : 0 : return rc;
139 : : }
140 : :
141 [ # # ]: 0 : if (state)
142 : 0 : *state = parms.state;
143 : :
144 [ # # ]: 0 : if (cnt)
145 : 0 : *cnt = parms.ref_cnt;
146 : :
147 : : return rc;
148 : : }
149 : :
150 : : static int32_t
151 : 0 : ulp_ha_mgr_tf_client_num_get_v1(struct bnxt_ulp_context *ulp_ctx,
152 : : uint32_t *cnt)
153 : : {
154 : 0 : struct tf_get_if_tbl_entry_parms get_parms = { 0 };
155 : : struct tf *tfp;
156 : 0 : uint32_t val = 0;
157 : : int32_t rc = 0;
158 : :
159 [ # # ]: 0 : if (ulp_ctx == NULL || cnt == NULL) {
160 : 0 : BNXT_TF_DBG(ERR, "Invalid parms in client num get.\n");
161 : 0 : return -EINVAL;
162 : : }
163 : 0 : tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_DEFAULT);
164 [ # # ]: 0 : if (tfp == NULL) {
165 : 0 : BNXT_TF_DBG(ERR, "Unable to get the TFP.\n");
166 : 0 : return -EINVAL;
167 : : }
168 : :
169 : 0 : get_parms.dir = ULP_HA_IF_TBL_DIR;
170 : 0 : get_parms.type = ULP_HA_IF_TBL_TYPE;
171 : 0 : get_parms.idx = bnxt_ulp_ha_reg_cnt_get(ulp_ctx);
172 : 0 : get_parms.data = (uint8_t *)&val;
173 : 0 : get_parms.data_sz_in_bytes = sizeof(val);
174 : :
175 : 0 : rc = tf_get_if_tbl_entry(tfp, &get_parms);
176 [ # # ]: 0 : if (rc)
177 : 0 : BNXT_TF_DBG(ERR, "Failed to read the number of HA clients\n");
178 : :
179 : 0 : *cnt = val;
180 : 0 : return rc;
181 : : }
182 : :
183 : : static int32_t
184 : 0 : ulp_ha_mgr_tf_client_num_get(struct bnxt_ulp_context *ulp_ctx,
185 : : uint32_t *cnt)
186 : : {
187 [ # # ]: 0 : if (bnxt_ulp_cntxt_multi_shared_session_enabled(ulp_ctx))
188 : 0 : return ulp_ha_mgr_tf_state_get(ulp_ctx, NULL, cnt);
189 : : else
190 : 0 : return ulp_ha_mgr_tf_client_num_get_v1(ulp_ctx, cnt);
191 : : }
192 : :
193 : : static int32_t
194 : 0 : ulp_ha_mgr_region_set(struct bnxt_ulp_context *ulp_ctx,
195 : : enum ulp_ha_mgr_region region)
196 : : {
197 : : struct bnxt_ulp_ha_mgr_info *ha_info;
198 : :
199 [ # # ]: 0 : if (ulp_ctx == NULL) {
200 : 0 : BNXT_TF_DBG(ERR, "Invalid params in ha region get.\n");
201 : 0 : return -EINVAL;
202 : : }
203 : :
204 : 0 : ha_info = bnxt_ulp_cntxt_ptr2_ha_info_get(ulp_ctx);
205 [ # # ]: 0 : if (ha_info == NULL) {
206 : 0 : BNXT_TF_DBG(ERR, "Unable to get ha info\n");
207 : 0 : return -EINVAL;
208 : : }
209 : 0 : ha_info->region = region;
210 : :
211 : 0 : return 0;
212 : : }
213 : :
214 : : static int32_t
215 : 0 : ulp_ha_mgr_app_type_set(struct bnxt_ulp_context *ulp_ctx,
216 : : enum ulp_ha_mgr_app_type app_type)
217 : : {
218 : : struct bnxt_ulp_ha_mgr_info *ha_info;
219 : :
220 [ # # ]: 0 : if (ulp_ctx == NULL) {
221 : 0 : BNXT_TF_DBG(ERR, "Invalid Parms.\n");
222 : 0 : return -EINVAL;
223 : : }
224 : :
225 : 0 : ha_info = bnxt_ulp_cntxt_ptr2_ha_info_get(ulp_ctx);
226 [ # # ]: 0 : if (ha_info == NULL) {
227 : 0 : BNXT_TF_DBG(ERR, "Unable to get the ha info.\n");
228 : 0 : return -EINVAL;
229 : : }
230 : 0 : ha_info->app_type = app_type;
231 : :
232 : 0 : return 0;
233 : : }
234 : :
235 : : static void
236 : 0 : ulp_ha_mgr_timer_cb(void *arg)
237 : : {
238 : 0 : struct tf_move_tcam_shared_entries_parms mparms = { 0 };
239 : 0 : struct tf_clear_tcam_shared_entries_parms cparms = { 0 };
240 : : struct bnxt_ulp_context *ulp_ctx;
241 : : enum ulp_ha_mgr_state curr_state;
242 : : enum ulp_ha_mgr_app_type app_type;
243 : : uint8_t myclient_cnt = 0;
244 : 0 : uint32_t client_cnt = 0;
245 : : struct tf *tfp;
246 : : int32_t rc;
247 : :
248 : 0 : ulp_ctx = bnxt_ulp_cntxt_entry_acquire(arg);
249 [ # # ]: 0 : if (ulp_ctx == NULL) {
250 : : ulp_ha_mgr_timer_start(arg);
251 : 0 : return;
252 : : }
253 : :
254 : 0 : myclient_cnt = bnxt_ulp_cntxt_num_shared_clients_get(ulp_ctx);
255 [ # # ]: 0 : if (myclient_cnt == 0) {
256 : 0 : bnxt_ulp_cntxt_entry_release();
257 : 0 : BNXT_TF_DBG(ERR,
258 : : "PANIC Client Count is zero kill timer\n.");
259 : 0 : return;
260 : : }
261 : :
262 : 0 : tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_SHARED_WC);
263 [ # # ]: 0 : if (tfp == NULL) {
264 : 0 : BNXT_TF_DBG(ERR, "Unable to get the TFP.\n");
265 : 0 : goto cb_restart;
266 : : }
267 : :
268 : 0 : rc = ulp_ha_mgr_state_get(ulp_ctx, &curr_state);
269 [ # # ]: 0 : if (rc) {
270 : : /*
271 : : * This shouldn't happen, if it does, reset the timer
272 : : * and try again next time.
273 : : */
274 : 0 : BNXT_TF_DBG(ERR, "Failed(%d) to get state.\n",
275 : : rc);
276 : 0 : goto cb_restart;
277 : : }
278 : :
279 : 0 : rc = ulp_ha_mgr_tf_client_num_get(ulp_ctx, &client_cnt);
280 [ # # ]: 0 : if (rc) {
281 : 0 : BNXT_TF_DBG(ERR, "Failed(%d) to get cnt.\n",
282 : : rc);
283 : 0 : goto cb_restart;
284 : : }
285 : :
286 : 0 : rc = ulp_ha_mgr_app_type_get(ulp_ctx, &app_type);
287 [ # # ]: 0 : if (rc) {
288 : 0 : BNXT_TF_DBG(ERR, "Failed(%d) to get type.\n",
289 : : rc);
290 : 0 : goto cb_restart;
291 : : }
292 : :
293 : : /* Handle the Cleanup if an app went away */
294 [ # # ]: 0 : if (client_cnt == myclient_cnt) {
295 [ # # ]: 0 : if (curr_state == ULP_HA_STATE_PRIM_SEC_RUN &&
296 [ # # ]: 0 : app_type == ULP_HA_APP_TYPE_PRIM) {
297 : : /*
298 : : * The SECONDARY went away:
299 : : * 1. Set the state to PRIM_RUN
300 : : * 2. Clear the High region so our TCAM will hit.
301 : : */
302 : 0 : rc = ulp_ha_mgr_state_set(ulp_ctx,
303 : : ULP_HA_STATE_PRIM_RUN);
304 [ # # ]: 0 : if (rc) {
305 : 0 : BNXT_TF_DBG(ERR,
306 : : "On HA CB:Failed(%d) to set state\n",
307 : : rc);
308 : 0 : goto cb_restart;
309 : : }
310 : :
311 : 0 : cparms.dir = TF_DIR_RX;
312 : 0 : cparms.tcam_tbl_type =
313 : : TF_TCAM_TBL_TYPE_WC_TCAM_HIGH;
314 : 0 : rc = tf_clear_tcam_shared_entries(tfp, &cparms);
315 [ # # ]: 0 : if (rc) {
316 : 0 : BNXT_TF_DBG(ERR,
317 : : "On HA CB:Failed(%d) clear tcam\n",
318 : : rc);
319 : 0 : goto cb_restart;
320 : : }
321 [ # # ]: 0 : } else if (curr_state == ULP_HA_STATE_PRIM_SEC_RUN &&
322 [ # # ]: 0 : app_type == ULP_HA_APP_TYPE_SEC) {
323 : : /*
324 : : * The PRIMARY went away:
325 : : * 1. Set the state to SEC_COPY
326 : : * 2. Clear the Low Region for the next copy
327 : : */
328 : 0 : rc = ulp_ha_mgr_state_set(ulp_ctx,
329 : : ULP_HA_STATE_SEC_TIMER_COPY);
330 [ # # ]: 0 : if (rc) {
331 : 0 : BNXT_TF_DBG(ERR,
332 : : "On HA CB:Failed(%d) to set state\n",
333 : : rc);
334 : 0 : goto cb_restart;
335 : : }
336 : 0 : curr_state = ULP_HA_STATE_SEC_TIMER_COPY;
337 : : }
338 : : }
339 : :
340 : : /* Only the Secondary has work to on SEC_TIMER_COPY */
341 [ # # ]: 0 : if (curr_state != ULP_HA_STATE_SEC_TIMER_COPY ||
342 [ # # ]: 0 : app_type != ULP_HA_APP_TYPE_SEC)
343 : 0 : goto cb_restart;
344 : :
345 : : /* Protect the flow database during the copy */
346 [ # # ]: 0 : if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) {
347 : : /* Should not fail, if we do, restart timer and try again */
348 : 0 : BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n");
349 : 0 : goto cb_restart;
350 : : }
351 : : /* All paths after this point must release the fdb lock */
352 : :
353 : : /* The Primary has issued a close and we are in the timer copy
354 : : * phase. Become the new Primary, Set state to Primary Run and
355 : : * move WC entries to Low Region.
356 : : */
357 : 0 : BNXT_TF_DBG(INFO, "On HA CB: Moving entries HI to LOW\n");
358 : :
359 : 0 : cparms.dir = TF_DIR_RX;
360 : 0 : cparms.tcam_tbl_type = TF_TCAM_TBL_TYPE_WC_TCAM_LOW;
361 : 0 : rc = tf_clear_tcam_shared_entries(tfp, &cparms);
362 [ # # ]: 0 : if (rc) {
363 : 0 : BNXT_TF_DBG(ERR,
364 : : "On HA CB:Failed(%d) clear tcam low\n",
365 : : rc);
366 : 0 : goto unlock;
367 : : }
368 : :
369 : 0 : mparms.dir = TF_DIR_RX;
370 : 0 : mparms.tcam_tbl_type = TF_TCAM_TBL_TYPE_WC_TCAM_HIGH;
371 : 0 : rc = tf_move_tcam_shared_entries(tfp, &mparms);
372 [ # # ]: 0 : if (rc) {
373 : 0 : BNXT_TF_DBG(ERR, "On HA_CB: Failed to move entries\n");
374 : 0 : goto unlock;
375 : : }
376 : :
377 : 0 : ulp_ha_mgr_region_set(ulp_ctx, ULP_HA_REGION_LOW);
378 : 0 : ulp_ha_mgr_app_type_set(ulp_ctx, ULP_HA_APP_TYPE_PRIM);
379 : 0 : ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_PRIM_RUN);
380 : 0 : BNXT_TF_DBG(INFO, "On HA CB: SEC[SEC_TIMER_COPY] => PRIM[PRIM_RUN]\n");
381 : 0 : unlock:
382 : 0 : bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx);
383 : 0 : cb_restart:
384 : 0 : bnxt_ulp_cntxt_entry_release();
385 : : ulp_ha_mgr_timer_start(arg);
386 : : }
387 : :
388 : : static int32_t
389 : : ulp_ha_mgr_timer_start(void *arg)
390 : : {
391 : 0 : rte_eal_alarm_set(US_PER_S * ULP_HA_TIMER_SEC,
392 : : ulp_ha_mgr_timer_cb, arg);
393 : : return 0;
394 : : }
395 : :
396 : : static void
397 : : ulp_ha_mgr_timer_cancel(struct bnxt_ulp_context *ulp_ctx)
398 : : {
399 : 0 : rte_eal_alarm_cancel(ulp_ha_mgr_timer_cb, ulp_ctx->cfg_data);
400 : : }
401 : :
402 : : int32_t
403 : 0 : ulp_ha_mgr_init(struct bnxt_ulp_context *ulp_ctx)
404 : : {
405 : : struct bnxt_ulp_ha_mgr_info *ha_info;
406 : : int32_t rc;
407 : 0 : ha_info = rte_zmalloc("ulp_ha_mgr_info", sizeof(*ha_info), 0);
408 [ # # ]: 0 : if (!ha_info)
409 : : return -ENOMEM;
410 : :
411 : : /* Add the HA info tbl to the ulp context. */
412 : 0 : bnxt_ulp_cntxt_ptr2_ha_info_set(ulp_ctx, ha_info);
413 : :
414 : 0 : rc = pthread_mutex_init(&ha_info->ha_lock, NULL);
415 [ # # ]: 0 : if (rc) {
416 : 0 : PMD_DRV_LOG(ERR, "Failed to initialize ha mutex\n");
417 : 0 : goto cleanup;
418 : : }
419 : 0 : rc = ulp_ha_mgr_timer_start(ulp_ctx->cfg_data);
420 : : if (rc) {
421 : : BNXT_TF_DBG(ERR, "Unable to start timer CB.\n");
422 : : goto cleanup;
423 : : }
424 : :
425 : 0 : return 0;
426 : : cleanup:
427 : : if (ha_info != NULL)
428 : 0 : ulp_ha_mgr_deinit(ulp_ctx);
429 : 0 : return -ENOMEM;
430 : : }
431 : :
432 : : void
433 : 0 : ulp_ha_mgr_deinit(struct bnxt_ulp_context *ulp_ctx)
434 : : {
435 : : struct bnxt_ulp_ha_mgr_info *ha_info;
436 : :
437 : : ulp_ha_mgr_timer_cancel(ulp_ctx);
438 : :
439 : 0 : ha_info = bnxt_ulp_cntxt_ptr2_ha_info_get(ulp_ctx);
440 [ # # ]: 0 : if (ha_info == NULL) {
441 : 0 : BNXT_TF_DBG(ERR, "Unable to get HA Info for deinit.\n");
442 : 0 : return;
443 : : }
444 : :
445 : 0 : pthread_mutex_destroy(&ha_info->ha_lock);
446 : 0 : rte_free(ha_info);
447 : :
448 : 0 : bnxt_ulp_cntxt_ptr2_ha_info_set(ulp_ctx, NULL);
449 : : }
450 : :
451 : : int32_t
452 : 0 : ulp_ha_mgr_app_type_get(struct bnxt_ulp_context *ulp_ctx,
453 : : enum ulp_ha_mgr_app_type *app_type)
454 : : {
455 : : struct bnxt_ulp_ha_mgr_info *ha_info;
456 : :
457 [ # # ]: 0 : if (ulp_ctx == NULL || app_type == NULL) {
458 : 0 : BNXT_TF_DBG(ERR, "Invalid Parms.\n");
459 : 0 : return -EINVAL;
460 : : }
461 : :
462 : 0 : ha_info = bnxt_ulp_cntxt_ptr2_ha_info_get(ulp_ctx);
463 [ # # ]: 0 : if (ha_info == NULL) {
464 : 0 : BNXT_TF_DBG(ERR, "Unable to get the HA info.\n");
465 : 0 : return -EINVAL;
466 : : }
467 : 0 : *app_type = ha_info->app_type;
468 : :
469 : 0 : return 0;
470 : : }
471 : :
472 : : static int32_t
473 : 0 : ulp_ha_mgr_state_get_v1(struct bnxt_ulp_context *ulp_ctx,
474 : : enum ulp_ha_mgr_state *state)
475 : : {
476 : 0 : struct tf_get_if_tbl_entry_parms get_parms = { 0 };
477 : : struct tf *tfp;
478 : 0 : uint32_t val = 0;
479 : : int32_t rc = 0;
480 : :
481 [ # # ]: 0 : if (ulp_ctx == NULL || state == NULL) {
482 : 0 : BNXT_TF_DBG(ERR, "Invalid parms in state get.\n");
483 : 0 : return -EINVAL;
484 : : }
485 : 0 : tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_DEFAULT);
486 [ # # ]: 0 : if (tfp == NULL) {
487 : 0 : BNXT_TF_DBG(ERR, "Unable to get the TFP.\n");
488 : 0 : return -EINVAL;
489 : : }
490 : :
491 : 0 : get_parms.dir = ULP_HA_IF_TBL_DIR;
492 : 0 : get_parms.type = ULP_HA_IF_TBL_TYPE;
493 : 0 : get_parms.idx = bnxt_ulp_ha_reg_state_get(ulp_ctx);
494 : 0 : get_parms.data = (uint8_t *)&val;
495 : 0 : get_parms.data_sz_in_bytes = sizeof(val);
496 : :
497 : 0 : rc = tf_get_if_tbl_entry(tfp, &get_parms);
498 [ # # ]: 0 : if (rc)
499 : 0 : BNXT_TF_DBG(ERR, "Failed to read the HA state\n");
500 : :
501 : 0 : *state = val;
502 : 0 : return rc;
503 : : }
504 : :
505 : : int32_t
506 : 0 : ulp_ha_mgr_state_get(struct bnxt_ulp_context *ulp_ctx,
507 : : enum ulp_ha_mgr_state *state)
508 : : {
509 [ # # ]: 0 : if (bnxt_ulp_cntxt_multi_shared_session_enabled(ulp_ctx))
510 : 0 : return ulp_ha_mgr_tf_state_get(ulp_ctx, state, NULL);
511 : : else
512 : 0 : return ulp_ha_mgr_state_get_v1(ulp_ctx, state);
513 : : }
514 : :
515 : : int32_t
516 : 0 : ulp_ha_mgr_open(struct bnxt_ulp_context *ulp_ctx)
517 : : {
518 : : enum ulp_ha_mgr_state curr_state;
519 : : int32_t rc;
520 : :
521 : 0 : rc = ulp_ha_mgr_state_get(ulp_ctx, &curr_state);
522 [ # # ]: 0 : if (rc) {
523 : 0 : BNXT_TF_DBG(ERR, "Failed to get HA state on Open (%d)\n", rc);
524 : 0 : return -EINVAL;
525 : : }
526 : :
527 : : /*
528 : : * An Open can only occur during the Init and Primary Run states. During
529 : : * Init, the system attempting to Open will become the only system
530 : : * running. During Primary Run, the system attempting to Open will
531 : : * become the secondary system temporarily, and should eventually be
532 : : * transitioned to the primary system.
533 : : */
534 [ # # # ]: 0 : switch (curr_state) {
535 : 0 : case ULP_HA_STATE_INIT:
536 : : /*
537 : : * No system is running, as we are the primary. Since no other
538 : : * system is running, we start writing into the low region. By
539 : : * writing into the low region, we save room for the secondary
540 : : * system to override our entries by using the high region.
541 : : */
542 : 0 : ulp_ha_mgr_app_type_set(ulp_ctx, ULP_HA_APP_TYPE_PRIM);
543 : 0 : ulp_ha_mgr_region_set(ulp_ctx, ULP_HA_REGION_LOW);
544 : 0 : rc = ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_PRIM_RUN);
545 [ # # ]: 0 : if (rc) {
546 : 0 : BNXT_TF_DBG(ERR, "On Open: Failed to set PRIM_RUN.\n");
547 : 0 : return -EINVAL;
548 : : }
549 : :
550 : 0 : BNXT_TF_DBG(INFO, "On Open: [INIT] => PRIM[PRIM_RUN]\n");
551 : 0 : break;
552 : 0 : case ULP_HA_STATE_PRIM_RUN:
553 : : /*
554 : : * The secondary system is starting in order to take over.
555 : : * The current primary is expected to eventually close and pass
556 : : * full control to this system;however, until the primary closes
557 : : * both are operational.
558 : : */
559 : 0 : ulp_ha_mgr_app_type_set(ulp_ctx, ULP_HA_APP_TYPE_SEC);
560 : 0 : ulp_ha_mgr_region_set(ulp_ctx, ULP_HA_REGION_HI);
561 : :
562 : 0 : rc = ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_PRIM_SEC_RUN);
563 [ # # ]: 0 : if (rc) {
564 : 0 : BNXT_TF_DBG(ERR, "On Open: Failed to set PRIM_SEC_RUN\n");
565 : 0 : return -EINVAL;
566 : : }
567 : 0 : BNXT_TF_DBG(INFO, "On Open: [PRIM_RUN] => [PRIM_SEC_RUN]\n");
568 : 0 : break;
569 : 0 : default:
570 : 0 : BNXT_TF_DBG(ERR, "On Open: Unknown state 0x%x\n", curr_state);
571 : 0 : return -EINVAL;
572 : : }
573 : :
574 : : return 0;
575 : : }
576 : :
577 : : int32_t
578 : 0 : ulp_ha_mgr_close(struct bnxt_ulp_context *ulp_ctx)
579 : : {
580 : : enum ulp_ha_mgr_state curr_state, next_state, poll_state;
581 : : enum ulp_ha_mgr_app_type app_type;
582 : : int32_t timeout;
583 : : int32_t rc;
584 : :
585 : 0 : curr_state = ULP_HA_STATE_INIT;
586 : 0 : app_type = ULP_HA_APP_TYPE_NONE;
587 : 0 : rc = ulp_ha_mgr_state_get(ulp_ctx, &curr_state);
588 [ # # ]: 0 : if (rc) {
589 : 0 : BNXT_TF_DBG(ERR, "On Close: Failed(%d) to get HA state\n", rc);
590 : 0 : return -EINVAL;
591 : : }
592 : :
593 : 0 : rc = ulp_ha_mgr_app_type_get(ulp_ctx, &app_type);
594 [ # # ]: 0 : if (rc) {
595 : 0 : BNXT_TF_DBG(ERR, "On Close: Failed to get the app type.\n");
596 : 0 : return -EINVAL;
597 : : }
598 : :
599 [ # # ]: 0 : if (curr_state == ULP_HA_STATE_PRIM_RUN &&
600 [ # # ]: 0 : app_type == ULP_HA_APP_TYPE_PRIM) {
601 : : /*
602 : : * Only the primary is running, so a close effectively moves the
603 : : * system back to INIT.
604 : : */
605 : : next_state = ULP_HA_STATE_INIT;
606 : 0 : ulp_ha_mgr_state_set(ulp_ctx, next_state);
607 : 0 : BNXT_TF_DBG(INFO, "On Close: PRIM[PRIM_RUN] => [INIT]\n");
608 [ # # ]: 0 : } else if (curr_state == ULP_HA_STATE_PRIM_SEC_RUN &&
609 [ # # ]: 0 : app_type == ULP_HA_APP_TYPE_PRIM) {
610 : : /*
611 : : * While both are running, the primary received a close.
612 : : * Cleanup the flows, set the COPY state, and wait for the
613 : : * secondary to become the Primary.
614 : : */
615 : 0 : BNXT_TF_DBG(INFO,
616 : : "On Close: PRIM[PRIM_SEC_RUN] flushing flows.\n");
617 : :
618 : 0 : ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR);
619 : 0 : ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_SEC_TIMER_COPY);
620 : :
621 : : /*
622 : : * TODO: This needs to be bounded in case the other system does
623 : : * not move to PRIM_RUN.
624 : : */
625 : 0 : BNXT_TF_DBG(INFO,
626 : : "On Close: PRIM[PRIM_SEC_RUN] => [Copy], enter wait.\n");
627 : : timeout = ULP_HA_WAIT_TIMEOUT;
628 : : do {
629 : : rte_delay_ms(ULP_HA_WAIT_TIME);
630 : 0 : rc = ulp_ha_mgr_state_get(ulp_ctx, &poll_state);
631 [ # # ]: 0 : if (rc) {
632 : 0 : BNXT_TF_DBG(ERR,
633 : : "Failed to get HA state on Close (%d)\n",
634 : : rc);
635 : 0 : goto cleanup;
636 : : }
637 : 0 : timeout -= ULP_HA_WAIT_TIME;
638 : 0 : BNXT_TF_DBG(INFO,
639 : : "On Close: Waiting %d ms for PRIM_RUN\n",
640 : : timeout);
641 [ # # # # ]: 0 : } while (poll_state != ULP_HA_STATE_PRIM_RUN && timeout > 0);
642 : :
643 [ # # ]: 0 : if (timeout <= 0) {
644 : 0 : BNXT_TF_DBG(ERR, "On Close: SEC[COPY] Timed out\n");
645 : 0 : goto cleanup;
646 : : }
647 : :
648 : 0 : BNXT_TF_DBG(INFO, "On Close: PRIM[PRIM_SEC_RUN] => [COPY]\n");
649 [ # # ]: 0 : } else if (curr_state == ULP_HA_STATE_PRIM_SEC_RUN &&
650 [ # # ]: 0 : app_type == ULP_HA_APP_TYPE_SEC) {
651 : : /*
652 : : * While both are running, the secondary unexpectedly received a
653 : : * close.
654 : : */
655 : 0 : ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_PRIM_RUN);
656 : :
657 : 0 : BNXT_TF_DBG(INFO, "On Close: SEC[PRIM_SEC_RUN] => [PRIM_RUN]\n");
658 [ # # ]: 0 : } else if (curr_state == ULP_HA_STATE_SEC_TIMER_COPY &&
659 [ # # ]: 0 : app_type == ULP_HA_APP_TYPE_SEC) {
660 : : /*
661 : : * While both were running and the Secondary went into copy,
662 : : * secondary received a close. Wait until the former Primary
663 : : * clears the copy stage, close, and set to INIT.
664 : : */
665 : 0 : BNXT_TF_DBG(INFO, "On Close: SEC[COPY] wait for PRIM_RUN\n");
666 : :
667 : : timeout = ULP_HA_WAIT_TIMEOUT;
668 : : do {
669 : : rte_delay_ms(ULP_HA_WAIT_TIME);
670 : 0 : rc = ulp_ha_mgr_state_get(ulp_ctx, &poll_state);
671 [ # # ]: 0 : if (rc) {
672 : 0 : BNXT_TF_DBG(ERR,
673 : : "Failed to get HA state on Close (%d)\n",
674 : : rc);
675 : 0 : goto cleanup;
676 : : }
677 : :
678 : 0 : timeout -= ULP_HA_WAIT_TIME;
679 : 0 : BNXT_TF_DBG(INFO,
680 : : "On Close: Waiting %d ms for PRIM_RUN\n",
681 : : timeout);
682 [ # # # # ]: 0 : } while (poll_state != ULP_HA_STATE_PRIM_RUN &&
683 : : timeout >= 0);
684 : :
685 [ # # ]: 0 : if (timeout <= 0) {
686 : 0 : BNXT_TF_DBG(ERR,
687 : : "On Close: SEC[COPY] Timed out\n");
688 : 0 : goto cleanup;
689 : : }
690 : :
691 : : next_state = ULP_HA_STATE_INIT;
692 : 0 : rc = ulp_ha_mgr_state_set(ulp_ctx, next_state);
693 [ # # ]: 0 : if (rc) {
694 : 0 : BNXT_TF_DBG(ERR,
695 : : "On Close: Failed to set state to INIT(%x)\n",
696 : : rc);
697 : 0 : goto cleanup;
698 : : }
699 : :
700 : 0 : BNXT_TF_DBG(INFO,
701 : : "On Close: SEC[COPY] => [INIT] after %d ms\n",
702 : : ULP_HA_WAIT_TIMEOUT - timeout);
703 : : }
704 : : /* else do nothing just return*/
705 : :
706 : 0 : cleanup:
707 : : return rc;
708 : : }
709 : :
710 : : int32_t
711 : 0 : ulp_ha_mgr_region_get(struct bnxt_ulp_context *ulp_ctx,
712 : : enum ulp_ha_mgr_region *region)
713 : : {
714 : : struct bnxt_ulp_ha_mgr_info *ha_info;
715 : :
716 [ # # ]: 0 : if (ulp_ctx == NULL || region == NULL) {
717 : 0 : BNXT_TF_DBG(ERR, "Invalid params in ha region get.\n");
718 : 0 : return -EINVAL;
719 : : }
720 : :
721 : 0 : ha_info = bnxt_ulp_cntxt_ptr2_ha_info_get(ulp_ctx);
722 [ # # ]: 0 : if (ha_info == NULL) {
723 : 0 : BNXT_TF_DBG(ERR, "Unable to get ha info\n");
724 : 0 : return -EINVAL;
725 : : }
726 : 0 : *region = ha_info->region;
727 : :
728 : 0 : return 0;
729 : : }
|