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