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