xref: /dpdk/drivers/net/bnxt/tf_ulp/ulp_ha_mgr.c (revision e9fd1ebf981f361844aea9ec94e17f4bda5e1479)
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 ulp_ha_mgr_state_set_v1(struct bnxt_ulp_context *ulp_ctx,
44 			enum ulp_ha_mgr_state state)
45 {
46 	struct tf_set_if_tbl_entry_parms set_parms = { 0 };
47 	struct tf *tfp;
48 	uint32_t val = 0;
49 	int32_t rc = 0;
50 
51 	if (ulp_ctx == NULL) {
52 		BNXT_TF_DBG(ERR, "Invalid parms in state get.\n");
53 		return -EINVAL;
54 	}
55 	tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_DEFAULT);
56 	if (tfp == NULL) {
57 		BNXT_TF_DBG(ERR, "Unable to get the TFP.\n");
58 		return -EINVAL;
59 	}
60 
61 	val = (uint32_t)state;
62 
63 	set_parms.dir = ULP_HA_IF_TBL_DIR;
64 	set_parms.type = ULP_HA_IF_TBL_TYPE;
65 	set_parms.data = (uint8_t *)&val;
66 	set_parms.data_sz_in_bytes = sizeof(val);
67 	set_parms.idx = bnxt_ulp_ha_reg_state_get(ulp_ctx);
68 
69 	rc = tf_set_if_tbl_entry(tfp, &set_parms);
70 	if (rc)
71 		BNXT_TF_DBG(ERR, "Failed to write the HA state\n");
72 
73 	return rc;
74 }
75 
76 static int32_t
77 ulp_ha_mgr_state_set_v2(struct bnxt_ulp_context *ulp_ctx,
78 			enum ulp_ha_mgr_state state)
79 {
80 	struct tf_set_session_hotup_state_parms parms = { 0 };
81 	struct tf *tfp;
82 	int32_t rc = 0;
83 
84 	if (ulp_ctx == NULL) {
85 		BNXT_TF_DBG(ERR, "Invalid parms in state get.\n");
86 		return -EINVAL;
87 	}
88 
89 	tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_SHARED_WC);
90 	if (tfp == NULL) {
91 		BNXT_TF_DBG(ERR, "Unable to get the TFP.\n");
92 		return -EINVAL;
93 	}
94 
95 	parms.state = (uint16_t)state;
96 	rc = tf_set_session_hotup_state(tfp, &parms);
97 	if (rc) {
98 		BNXT_TF_DBG(ERR, "Failed to write the HA state\n");
99 		return rc;
100 	}
101 
102 	return rc;
103 }
104 
105 static int32_t
106 ulp_ha_mgr_state_set(struct bnxt_ulp_context *ulp_ctx,
107 		     enum ulp_ha_mgr_state state)
108 {
109 	if (bnxt_ulp_cntxt_multi_shared_session_enabled(ulp_ctx))
110 		return ulp_ha_mgr_state_set_v2(ulp_ctx, state);
111 	else
112 		return ulp_ha_mgr_state_set_v1(ulp_ctx, state);
113 }
114 
115 static int32_t
116 ulp_ha_mgr_tf_state_get(struct bnxt_ulp_context *ulp_ctx,
117 			uint32_t *state,
118 			uint32_t *cnt)
119 {
120 	struct tf_get_session_hotup_state_parms parms = { 0 };
121 	struct tf *tfp;
122 	int32_t rc = 0;
123 
124 	if (ulp_ctx == NULL) {
125 		BNXT_TF_DBG(ERR, "Invalid parms in client num get.\n");
126 		return -EINVAL;
127 	}
128 
129 	tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_SHARED_WC);
130 	if (tfp == NULL) {
131 		BNXT_TF_DBG(ERR, "Unable to get the TFP.\n");
132 		return -EINVAL;
133 	}
134 
135 	rc = tf_get_session_hotup_state(tfp, &parms);
136 	if (rc) {
137 		BNXT_TF_DBG(ERR, "Failed to read the HA state\n");
138 		return rc;
139 	}
140 
141 	if (state)
142 		*state = parms.state;
143 
144 	if (cnt)
145 		*cnt = parms.ref_cnt;
146 
147 	return rc;
148 }
149 
150 static int32_t
151 ulp_ha_mgr_tf_client_num_get_v1(struct bnxt_ulp_context *ulp_ctx,
152 				uint32_t *cnt)
153 {
154 	struct tf_get_if_tbl_entry_parms get_parms = { 0 };
155 	struct tf *tfp;
156 	uint32_t val = 0;
157 	int32_t rc = 0;
158 
159 	if (ulp_ctx == NULL || cnt == NULL) {
160 		BNXT_TF_DBG(ERR, "Invalid parms in client num get.\n");
161 		return -EINVAL;
162 	}
163 	tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_DEFAULT);
164 	if (tfp == NULL) {
165 		BNXT_TF_DBG(ERR, "Unable to get the TFP.\n");
166 		return -EINVAL;
167 	}
168 
169 	get_parms.dir = ULP_HA_IF_TBL_DIR;
170 	get_parms.type = ULP_HA_IF_TBL_TYPE;
171 	get_parms.idx = bnxt_ulp_ha_reg_cnt_get(ulp_ctx);
172 	get_parms.data = (uint8_t *)&val;
173 	get_parms.data_sz_in_bytes = sizeof(val);
174 
175 	rc = tf_get_if_tbl_entry(tfp, &get_parms);
176 	if (rc)
177 		BNXT_TF_DBG(ERR, "Failed to read the number of HA clients\n");
178 
179 	*cnt = val;
180 	return rc;
181 }
182 
183 static int32_t
184 ulp_ha_mgr_tf_client_num_get(struct bnxt_ulp_context *ulp_ctx,
185 			     uint32_t *cnt)
186 {
187 	if (bnxt_ulp_cntxt_multi_shared_session_enabled(ulp_ctx))
188 		return ulp_ha_mgr_tf_state_get(ulp_ctx, NULL, cnt);
189 	else
190 		return ulp_ha_mgr_tf_client_num_get_v1(ulp_ctx, cnt);
191 }
192 
193 static int32_t
194 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 	if (ulp_ctx == NULL) {
200 		BNXT_TF_DBG(ERR, "Invalid params in ha region get.\n");
201 		return -EINVAL;
202 	}
203 
204 	ha_info = bnxt_ulp_cntxt_ptr2_ha_info_get(ulp_ctx);
205 	if (ha_info == NULL) {
206 		BNXT_TF_DBG(ERR, "Unable to get ha info\n");
207 		return -EINVAL;
208 	}
209 	ha_info->region = region;
210 
211 	return 0;
212 }
213 
214 static int32_t
215 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 	if (ulp_ctx == NULL) {
221 		BNXT_TF_DBG(ERR, "Invalid Parms.\n");
222 		return -EINVAL;
223 	}
224 
225 	ha_info = bnxt_ulp_cntxt_ptr2_ha_info_get(ulp_ctx);
226 	if (ha_info == NULL) {
227 		BNXT_TF_DBG(ERR, "Unable to get the ha info.\n");
228 		return -EINVAL;
229 	}
230 	ha_info->app_type = app_type;
231 
232 	return 0;
233 }
234 
235 static void
236 ulp_ha_mgr_timer_cb(void *arg)
237 {
238 	struct tf_move_tcam_shared_entries_parms mparms = { 0 };
239 	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 	uint32_t client_cnt = 0;
245 	struct tf *tfp;
246 	int32_t rc;
247 
248 	ulp_ctx = bnxt_ulp_cntxt_entry_acquire(arg);
249 	if (ulp_ctx == NULL) {
250 		ulp_ha_mgr_timer_start(arg);
251 		return;
252 	}
253 
254 	myclient_cnt = bnxt_ulp_cntxt_num_shared_clients_get(ulp_ctx);
255 	if (myclient_cnt == 0) {
256 		bnxt_ulp_cntxt_entry_release();
257 		BNXT_TF_DBG(ERR,
258 			    "PANIC Client Count is zero kill timer\n.");
259 		return;
260 	}
261 
262 	tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_SHARED_WC);
263 	if (tfp == NULL) {
264 		BNXT_TF_DBG(ERR, "Unable to get the TFP.\n");
265 		goto cb_restart;
266 	}
267 
268 	rc = ulp_ha_mgr_state_get(ulp_ctx, &curr_state);
269 	if (rc) {
270 		/*
271 		 * This shouldn't happen, if it does, reset the timer
272 		 * and try again next time.
273 		 */
274 		BNXT_TF_DBG(ERR, "Failed(%d) to get state.\n",
275 			    rc);
276 		goto cb_restart;
277 	}
278 
279 	rc = ulp_ha_mgr_tf_client_num_get(ulp_ctx, &client_cnt);
280 	if (rc) {
281 		BNXT_TF_DBG(ERR, "Failed(%d) to get cnt.\n",
282 			    rc);
283 		goto cb_restart;
284 	}
285 
286 	rc =  ulp_ha_mgr_app_type_get(ulp_ctx, &app_type);
287 	if (rc) {
288 		BNXT_TF_DBG(ERR, "Failed(%d) to get type.\n",
289 			    rc);
290 		goto cb_restart;
291 	}
292 
293 	/* Handle the Cleanup if an app went away */
294 	if (client_cnt == myclient_cnt) {
295 		if (curr_state == ULP_HA_STATE_PRIM_SEC_RUN &&
296 		    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 			rc = ulp_ha_mgr_state_set(ulp_ctx,
303 						  ULP_HA_STATE_PRIM_RUN);
304 			if (rc) {
305 				BNXT_TF_DBG(ERR,
306 					    "On HA CB:Failed(%d) to set state\n",
307 					    rc);
308 				goto cb_restart;
309 			}
310 
311 			cparms.dir = TF_DIR_RX;
312 			cparms.tcam_tbl_type =
313 				TF_TCAM_TBL_TYPE_WC_TCAM_HIGH;
314 			rc = tf_clear_tcam_shared_entries(tfp, &cparms);
315 			if (rc) {
316 				BNXT_TF_DBG(ERR,
317 					    "On HA CB:Failed(%d) clear tcam\n",
318 					    rc);
319 				goto cb_restart;
320 			}
321 		} else if (curr_state == ULP_HA_STATE_PRIM_SEC_RUN &&
322 			    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 			rc = ulp_ha_mgr_state_set(ulp_ctx,
329 						  ULP_HA_STATE_SEC_TIMER_COPY);
330 			if (rc) {
331 				BNXT_TF_DBG(ERR,
332 					    "On HA CB:Failed(%d) to set state\n",
333 					    rc);
334 				goto cb_restart;
335 			}
336 			curr_state = ULP_HA_STATE_SEC_TIMER_COPY;
337 		}
338 	}
339 
340 	/* Only the Secondary has work to on SEC_TIMER_COPY */
341 	if (curr_state != ULP_HA_STATE_SEC_TIMER_COPY ||
342 	    app_type != ULP_HA_APP_TYPE_SEC)
343 		goto cb_restart;
344 
345 	/* Protect the flow database during the copy */
346 	if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) {
347 		/* Should not fail, if we do, restart timer and try again */
348 		BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n");
349 		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 	BNXT_TF_DBG(INFO, "On HA CB: Moving entries HI to LOW\n");
358 
359 	cparms.dir = TF_DIR_RX;
360 	cparms.tcam_tbl_type = TF_TCAM_TBL_TYPE_WC_TCAM_LOW;
361 	rc = tf_clear_tcam_shared_entries(tfp, &cparms);
362 	if (rc) {
363 		BNXT_TF_DBG(ERR,
364 			    "On HA CB:Failed(%d) clear tcam low\n",
365 			    rc);
366 		goto unlock;
367 	}
368 
369 	mparms.dir = TF_DIR_RX;
370 	mparms.tcam_tbl_type = TF_TCAM_TBL_TYPE_WC_TCAM_HIGH;
371 	rc = tf_move_tcam_shared_entries(tfp, &mparms);
372 	if (rc) {
373 		BNXT_TF_DBG(ERR, "On HA_CB: Failed to move entries\n");
374 		goto unlock;
375 	}
376 
377 	ulp_ha_mgr_region_set(ulp_ctx, ULP_HA_REGION_LOW);
378 	ulp_ha_mgr_app_type_set(ulp_ctx, ULP_HA_APP_TYPE_PRIM);
379 	ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_PRIM_RUN);
380 	BNXT_TF_DBG(INFO, "On HA CB: SEC[SEC_TIMER_COPY] => PRIM[PRIM_RUN]\n");
381 unlock:
382 	bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx);
383 cb_restart:
384 	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 	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 	rte_eal_alarm_cancel(ulp_ha_mgr_timer_cb, ulp_ctx->cfg_data);
400 }
401 
402 int32_t
403 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 	ha_info = rte_zmalloc("ulp_ha_mgr_info", sizeof(*ha_info), 0);
408 	if (!ha_info)
409 		return -ENOMEM;
410 
411 	/* Add the HA info tbl to the ulp context. */
412 	bnxt_ulp_cntxt_ptr2_ha_info_set(ulp_ctx, ha_info);
413 
414 	rc = pthread_mutex_init(&ha_info->ha_lock, NULL);
415 	if (rc) {
416 		PMD_DRV_LOG(ERR, "Failed to initialize ha mutex\n");
417 		goto cleanup;
418 	}
419 	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 	return 0;
426 cleanup:
427 	if (ha_info != NULL)
428 		ulp_ha_mgr_deinit(ulp_ctx);
429 	return -ENOMEM;
430 }
431 
432 void
433 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 	ha_info = bnxt_ulp_cntxt_ptr2_ha_info_get(ulp_ctx);
440 	if (ha_info == NULL) {
441 		BNXT_TF_DBG(ERR, "Unable to get HA Info for deinit.\n");
442 		return;
443 	}
444 
445 	pthread_mutex_destroy(&ha_info->ha_lock);
446 	rte_free(ha_info);
447 
448 	bnxt_ulp_cntxt_ptr2_ha_info_set(ulp_ctx, NULL);
449 }
450 
451 int32_t
452 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 	if (ulp_ctx == NULL || app_type == NULL) {
458 		BNXT_TF_DBG(ERR, "Invalid Parms.\n");
459 		return -EINVAL;
460 	}
461 
462 	ha_info = bnxt_ulp_cntxt_ptr2_ha_info_get(ulp_ctx);
463 	if (ha_info == NULL) {
464 		BNXT_TF_DBG(ERR, "Unable to get the HA info.\n");
465 		return -EINVAL;
466 	}
467 	*app_type = ha_info->app_type;
468 
469 	return 0;
470 }
471 
472 static int32_t
473 ulp_ha_mgr_state_get_v1(struct bnxt_ulp_context *ulp_ctx,
474 			enum ulp_ha_mgr_state *state)
475 {
476 	struct tf_get_if_tbl_entry_parms get_parms = { 0 };
477 	struct tf *tfp;
478 	uint32_t val = 0;
479 	int32_t rc = 0;
480 
481 	if (ulp_ctx == NULL || state == NULL) {
482 		BNXT_TF_DBG(ERR, "Invalid parms in state get.\n");
483 		return -EINVAL;
484 	}
485 	tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_DEFAULT);
486 	if (tfp == NULL) {
487 		BNXT_TF_DBG(ERR, "Unable to get the TFP.\n");
488 		return -EINVAL;
489 	}
490 
491 	get_parms.dir = ULP_HA_IF_TBL_DIR;
492 	get_parms.type = ULP_HA_IF_TBL_TYPE;
493 	get_parms.idx = bnxt_ulp_ha_reg_state_get(ulp_ctx);
494 	get_parms.data = (uint8_t *)&val;
495 	get_parms.data_sz_in_bytes = sizeof(val);
496 
497 	rc = tf_get_if_tbl_entry(tfp, &get_parms);
498 	if (rc)
499 		BNXT_TF_DBG(ERR, "Failed to read the HA state\n");
500 
501 	*state = val;
502 	return rc;
503 }
504 
505 int32_t
506 ulp_ha_mgr_state_get(struct bnxt_ulp_context *ulp_ctx,
507 		     enum ulp_ha_mgr_state *state)
508 {
509 	if (bnxt_ulp_cntxt_multi_shared_session_enabled(ulp_ctx))
510 		return ulp_ha_mgr_tf_state_get(ulp_ctx, state, NULL);
511 	else
512 		return ulp_ha_mgr_state_get_v1(ulp_ctx, state);
513 }
514 
515 int32_t
516 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 	rc = ulp_ha_mgr_state_get(ulp_ctx, &curr_state);
522 	if (rc) {
523 		BNXT_TF_DBG(ERR, "Failed to get HA state on Open (%d)\n", rc);
524 		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 	switch (curr_state) {
535 	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 		ulp_ha_mgr_app_type_set(ulp_ctx, ULP_HA_APP_TYPE_PRIM);
543 		ulp_ha_mgr_region_set(ulp_ctx, ULP_HA_REGION_LOW);
544 		rc = ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_PRIM_RUN);
545 		if (rc) {
546 			BNXT_TF_DBG(ERR, "On Open: Failed to set PRIM_RUN.\n");
547 			return -EINVAL;
548 		}
549 
550 		BNXT_TF_DBG(INFO, "On Open: [INIT] => PRIM[PRIM_RUN]\n");
551 		break;
552 	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 		ulp_ha_mgr_app_type_set(ulp_ctx, ULP_HA_APP_TYPE_SEC);
560 		ulp_ha_mgr_region_set(ulp_ctx, ULP_HA_REGION_HI);
561 
562 		rc = ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_PRIM_SEC_RUN);
563 		if (rc) {
564 			BNXT_TF_DBG(ERR, "On Open: Failed to set PRIM_SEC_RUN\n");
565 			return -EINVAL;
566 		}
567 		BNXT_TF_DBG(INFO, "On Open: [PRIM_RUN] => [PRIM_SEC_RUN]\n");
568 		break;
569 	default:
570 		BNXT_TF_DBG(ERR, "On Open: Unknown state 0x%x\n", curr_state);
571 		return -EINVAL;
572 	}
573 
574 	return 0;
575 }
576 
577 int32_t
578 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 	curr_state = ULP_HA_STATE_INIT;
586 	app_type = ULP_HA_APP_TYPE_NONE;
587 	rc = ulp_ha_mgr_state_get(ulp_ctx, &curr_state);
588 	if (rc) {
589 		BNXT_TF_DBG(ERR, "On Close: Failed(%d) to get HA state\n", rc);
590 		return -EINVAL;
591 	}
592 
593 	rc = ulp_ha_mgr_app_type_get(ulp_ctx, &app_type);
594 	if (rc) {
595 		BNXT_TF_DBG(ERR, "On Close: Failed to get the app type.\n");
596 		return -EINVAL;
597 	}
598 
599 	if (curr_state == ULP_HA_STATE_PRIM_RUN &&
600 	    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 		ulp_ha_mgr_state_set(ulp_ctx, next_state);
607 		BNXT_TF_DBG(INFO, "On Close: PRIM[PRIM_RUN] => [INIT]\n");
608 	} else if (curr_state == ULP_HA_STATE_PRIM_SEC_RUN &&
609 		  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 		BNXT_TF_DBG(INFO,
616 			    "On Close: PRIM[PRIM_SEC_RUN] flushing flows.\n");
617 
618 		ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR);
619 		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 		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 			rc = ulp_ha_mgr_state_get(ulp_ctx, &poll_state);
631 			if (rc) {
632 				BNXT_TF_DBG(ERR,
633 					    "Failed to get HA state on Close (%d)\n",
634 					    rc);
635 				goto cleanup;
636 			}
637 			timeout -= ULP_HA_WAIT_TIME;
638 			BNXT_TF_DBG(INFO,
639 				    "On Close: Waiting %d ms for PRIM_RUN\n",
640 				    timeout);
641 		} while (poll_state != ULP_HA_STATE_PRIM_RUN && timeout > 0);
642 
643 		if (timeout <= 0) {
644 			BNXT_TF_DBG(ERR, "On Close: SEC[COPY] Timed out\n");
645 			goto cleanup;
646 		}
647 
648 		BNXT_TF_DBG(INFO, "On Close: PRIM[PRIM_SEC_RUN] => [COPY]\n");
649 	} else if (curr_state == ULP_HA_STATE_PRIM_SEC_RUN &&
650 		   app_type == ULP_HA_APP_TYPE_SEC) {
651 		/*
652 		 * While both are running, the secondary unexpectedly received a
653 		 * close.
654 		 */
655 		ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_PRIM_RUN);
656 
657 		BNXT_TF_DBG(INFO, "On Close: SEC[PRIM_SEC_RUN] => [PRIM_RUN]\n");
658 	} else if (curr_state == ULP_HA_STATE_SEC_TIMER_COPY &&
659 		   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 		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 			rc = ulp_ha_mgr_state_get(ulp_ctx, &poll_state);
671 			if (rc) {
672 				BNXT_TF_DBG(ERR,
673 					    "Failed to get HA state on Close (%d)\n",
674 					    rc);
675 				goto cleanup;
676 			}
677 
678 			timeout -= ULP_HA_WAIT_TIME;
679 			BNXT_TF_DBG(INFO,
680 				    "On Close: Waiting %d ms for PRIM_RUN\n",
681 				    timeout);
682 		} while (poll_state != ULP_HA_STATE_PRIM_RUN &&
683 			 timeout >= 0);
684 
685 		if (timeout <= 0) {
686 			BNXT_TF_DBG(ERR,
687 				    "On Close: SEC[COPY] Timed out\n");
688 			goto cleanup;
689 		}
690 
691 		next_state = ULP_HA_STATE_INIT;
692 		rc = ulp_ha_mgr_state_set(ulp_ctx, next_state);
693 		if (rc) {
694 			BNXT_TF_DBG(ERR,
695 				    "On Close: Failed to set state to INIT(%x)\n",
696 				    rc);
697 			goto cleanup;
698 		}
699 
700 		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 cleanup:
707 	return rc;
708 }
709 
710 int32_t
711 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 	if (ulp_ctx == NULL || region == NULL) {
717 		BNXT_TF_DBG(ERR, "Invalid params in ha region get.\n");
718 		return -EINVAL;
719 	}
720 
721 	ha_info = bnxt_ulp_cntxt_ptr2_ha_info_get(ulp_ctx);
722 	if (ha_info == NULL) {
723 		BNXT_TF_DBG(ERR, "Unable to get ha info\n");
724 		return -EINVAL;
725 	}
726 	*region = ha_info->region;
727 
728 	return 0;
729 }
730