xref: /dpdk/drivers/net/bnxt/tf_ulp/ulp_ha_mgr.c (revision 7d32c003ac175d7ac8669dc11684c75cc7eb56b8)
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 	pthread_mutex_init(&ha_info->ha_lock, NULL);
416 	rc = ulp_ha_mgr_timer_start(ulp_ctx->cfg_data);
417 	if (rc) {
418 		PMD_DRV_LOG_LINE(ERR, "Unable to start timer CB");
419 		goto cleanup;
420 	}
421 
422 	return 0;
423 cleanup:
424 	if (ha_info != NULL)
425 		ulp_ha_mgr_deinit(ulp_ctx);
426 	return -ENOMEM;
427 }
428 
429 void
430 ulp_ha_mgr_deinit(struct bnxt_ulp_context *ulp_ctx)
431 {
432 	struct bnxt_ulp_ha_mgr_info *ha_info;
433 
434 	ulp_ha_mgr_timer_cancel(ulp_ctx);
435 
436 	ha_info = bnxt_ulp_cntxt_ptr2_ha_info_get(ulp_ctx);
437 	if (ha_info == NULL) {
438 		BNXT_DRV_DBG(ERR, "Unable to get HA Info for deinit.\n");
439 		return;
440 	}
441 
442 	pthread_mutex_destroy(&ha_info->ha_lock);
443 	rte_free(ha_info);
444 
445 	bnxt_ulp_cntxt_ptr2_ha_info_set(ulp_ctx, NULL);
446 }
447 
448 int32_t
449 ulp_ha_mgr_app_type_get(struct bnxt_ulp_context *ulp_ctx,
450 			enum ulp_ha_mgr_app_type *app_type)
451 {
452 	struct bnxt_ulp_ha_mgr_info *ha_info;
453 
454 	if (ulp_ctx == NULL || app_type == NULL) {
455 		BNXT_DRV_DBG(ERR, "Invalid Parms.\n");
456 		return -EINVAL;
457 	}
458 
459 	ha_info = bnxt_ulp_cntxt_ptr2_ha_info_get(ulp_ctx);
460 	if (ha_info == NULL) {
461 		BNXT_DRV_DBG(ERR, "Unable to get the HA info.\n");
462 		return -EINVAL;
463 	}
464 	*app_type = ha_info->app_type;
465 
466 	return 0;
467 }
468 
469 static int32_t
470 ulp_ha_mgr_state_get_v1(struct bnxt_ulp_context *ulp_ctx,
471 			enum ulp_ha_mgr_state *state)
472 {
473 	struct tf_get_if_tbl_entry_parms get_parms = { 0 };
474 	struct tf *tfp;
475 	uint32_t val = 0;
476 	int32_t rc = 0;
477 
478 	if (ulp_ctx == NULL || state == NULL) {
479 		BNXT_DRV_DBG(ERR, "Invalid parms in state get.\n");
480 		return -EINVAL;
481 	}
482 	tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_DEFAULT);
483 	if (tfp == NULL) {
484 		BNXT_DRV_DBG(ERR, "Unable to get the TFP.\n");
485 		return -EINVAL;
486 	}
487 
488 	get_parms.dir = ULP_HA_IF_TBL_DIR;
489 	get_parms.type = ULP_HA_IF_TBL_TYPE;
490 	get_parms.idx = bnxt_ulp_cntxt_ha_reg_state_get(ulp_ctx);
491 	get_parms.data = (uint8_t *)&val;
492 	get_parms.data_sz_in_bytes = sizeof(val);
493 
494 	rc = tf_get_if_tbl_entry(tfp, &get_parms);
495 	if (rc)
496 		BNXT_DRV_DBG(ERR, "Failed to read the HA state\n");
497 
498 	*state = val;
499 	return rc;
500 }
501 
502 int32_t
503 ulp_ha_mgr_state_get(struct bnxt_ulp_context *ulp_ctx,
504 		     enum ulp_ha_mgr_state *state)
505 {
506 	if (bnxt_ulp_cntxt_multi_shared_session_enabled(ulp_ctx))
507 		return ulp_ha_mgr_tf_state_get(ulp_ctx, state, NULL);
508 	else
509 		return ulp_ha_mgr_state_get_v1(ulp_ctx, state);
510 }
511 
512 int32_t
513 ulp_ha_mgr_open(struct bnxt_ulp_context *ulp_ctx)
514 {
515 	enum ulp_ha_mgr_state curr_state;
516 	int32_t rc;
517 
518 	rc = ulp_ha_mgr_state_get(ulp_ctx, &curr_state);
519 	if (rc) {
520 		BNXT_DRV_DBG(ERR, "Failed to get HA state on Open (%d)\n", rc);
521 		return -EINVAL;
522 	}
523 
524 	/*
525 	 * An Open can only occur during the Init and Primary Run states. During
526 	 * Init, the system attempting to Open will become the only system
527 	 * running. During Primary Run, the system attempting to Open will
528 	 * become the secondary system temporarily, and should eventually be
529 	 * transitioned to the primary system.
530 	 */
531 	switch (curr_state) {
532 	case ULP_HA_STATE_INIT:
533 		/*
534 		 * No system is running, as we are the primary.  Since no other
535 		 * system is running, we start writing into the low region.  By
536 		 * writing into the low region, we save room for the secondary
537 		 * system to override our entries by using the high region.
538 		 */
539 		ulp_ha_mgr_app_type_set(ulp_ctx, ULP_HA_APP_TYPE_PRIM);
540 		ulp_ha_mgr_region_set(ulp_ctx, ULP_HA_REGION_LOW);
541 		rc = ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_PRIM_RUN);
542 		if (rc) {
543 			BNXT_DRV_DBG(ERR, "On Open: Failed to set PRIM_RUN.\n");
544 			return -EINVAL;
545 		}
546 
547 		BNXT_DRV_DBG(INFO, "On Open: [INIT] => PRIM[PRIM_RUN]\n");
548 		break;
549 	case ULP_HA_STATE_PRIM_RUN:
550 		/*
551 		 * The secondary system is starting in order to take over.
552 		 * The current primary is expected to eventually close and pass
553 		 * full control to this system;however, until the primary closes
554 		 * both are operational.
555 		 */
556 		ulp_ha_mgr_app_type_set(ulp_ctx, ULP_HA_APP_TYPE_SEC);
557 		ulp_ha_mgr_region_set(ulp_ctx, ULP_HA_REGION_HI);
558 
559 		rc = ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_PRIM_SEC_RUN);
560 		if (rc) {
561 			BNXT_DRV_DBG(ERR, "On Open: Failed to set PRIM_SEC_RUN\n");
562 			return -EINVAL;
563 		}
564 		BNXT_DRV_DBG(INFO, "On Open: [PRIM_RUN] => [PRIM_SEC_RUN]\n");
565 		break;
566 	default:
567 		BNXT_DRV_DBG(ERR, "On Open: Unknown state 0x%x\n", curr_state);
568 		return -EINVAL;
569 	}
570 
571 	return 0;
572 }
573 
574 int32_t
575 ulp_ha_mgr_close(struct bnxt_ulp_context *ulp_ctx)
576 {
577 	enum ulp_ha_mgr_state curr_state, next_state, poll_state;
578 	enum ulp_ha_mgr_app_type app_type;
579 	int32_t timeout;
580 	int32_t rc;
581 
582 	curr_state = ULP_HA_STATE_INIT;
583 	app_type = ULP_HA_APP_TYPE_NONE;
584 	rc = ulp_ha_mgr_state_get(ulp_ctx, &curr_state);
585 	if (rc) {
586 		BNXT_DRV_DBG(ERR, "On Close: Failed(%d) to get HA state\n", rc);
587 		return -EINVAL;
588 	}
589 
590 	rc = ulp_ha_mgr_app_type_get(ulp_ctx, &app_type);
591 	if (rc) {
592 		BNXT_DRV_DBG(ERR, "On Close: Failed to get the app type.\n");
593 		return -EINVAL;
594 	}
595 
596 	if (curr_state == ULP_HA_STATE_PRIM_RUN &&
597 	    app_type == ULP_HA_APP_TYPE_PRIM) {
598 		/*
599 		 * Only the primary is running, so a close effectively moves the
600 		 * system back to INIT.
601 		 */
602 		next_state = ULP_HA_STATE_INIT;
603 		ulp_ha_mgr_state_set(ulp_ctx, next_state);
604 		BNXT_DRV_DBG(INFO, "On Close: PRIM[PRIM_RUN] => [INIT]\n");
605 	} else if (curr_state == ULP_HA_STATE_PRIM_SEC_RUN &&
606 		  app_type == ULP_HA_APP_TYPE_PRIM) {
607 		/*
608 		 * While both are running, the primary received a close.
609 		 * Cleanup the flows, set the COPY state, and wait for the
610 		 * secondary to become the Primary.
611 		 */
612 		BNXT_DRV_DBG(INFO,
613 			     "On Close: PRIM[PRIM_SEC_RUN] flushing flows.\n");
614 
615 		ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR);
616 		ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_SEC_TIMER_COPY);
617 
618 		/*
619 		 * TODO: This needs to be bounded in case the other system does
620 		 * not move to PRIM_RUN.
621 		 */
622 		BNXT_DRV_DBG(INFO,
623 			     "On Close: PRIM[PRIM_SEC_RUN] => [Copy], enter wait.\n");
624 		timeout = ULP_HA_WAIT_TIMEOUT;
625 		do {
626 			rte_delay_ms(ULP_HA_WAIT_TIME);
627 			rc = ulp_ha_mgr_state_get(ulp_ctx, &poll_state);
628 			if (rc) {
629 				BNXT_DRV_DBG(ERR,
630 					     "Failed to get HA state on Close (%d)\n",
631 					     rc);
632 				goto cleanup;
633 			}
634 			timeout -= ULP_HA_WAIT_TIME;
635 			BNXT_DRV_DBG(INFO,
636 				     "On Close: Waiting %d ms for PRIM_RUN\n",
637 				     timeout);
638 		} while (poll_state != ULP_HA_STATE_PRIM_RUN && timeout > 0);
639 
640 		if (timeout <= 0) {
641 			BNXT_DRV_DBG(ERR, "On Close: SEC[COPY] Timed out\n");
642 			goto cleanup;
643 		}
644 
645 		BNXT_DRV_DBG(INFO, "On Close: PRIM[PRIM_SEC_RUN] => [COPY]\n");
646 	} else if (curr_state == ULP_HA_STATE_PRIM_SEC_RUN &&
647 		   app_type == ULP_HA_APP_TYPE_SEC) {
648 		/*
649 		 * While both are running, the secondary unexpectedly received a
650 		 * close.
651 		 */
652 		ulp_ha_mgr_state_set(ulp_ctx, ULP_HA_STATE_PRIM_RUN);
653 
654 		BNXT_DRV_DBG(INFO, "On Close: SEC[PRIM_SEC_RUN] => [PRIM_RUN]\n");
655 	} else if (curr_state == ULP_HA_STATE_SEC_TIMER_COPY &&
656 		   app_type == ULP_HA_APP_TYPE_SEC) {
657 		/*
658 		 * While both were running and the Secondary went into copy,
659 		 * secondary received a close.  Wait until the former Primary
660 		 * clears the copy stage, close, and set to INIT.
661 		 */
662 		BNXT_DRV_DBG(INFO, "On Close: SEC[COPY] wait for PRIM_RUN\n");
663 
664 		timeout = ULP_HA_WAIT_TIMEOUT;
665 		do {
666 			rte_delay_ms(ULP_HA_WAIT_TIME);
667 			rc = ulp_ha_mgr_state_get(ulp_ctx, &poll_state);
668 			if (rc) {
669 				BNXT_DRV_DBG(ERR,
670 					     "Failed to get HA state on Close (%d)\n",
671 					     rc);
672 				goto cleanup;
673 			}
674 
675 			timeout -= ULP_HA_WAIT_TIME;
676 			BNXT_DRV_DBG(INFO,
677 				     "On Close: Waiting %d ms for PRIM_RUN\n",
678 				     timeout);
679 		} while (poll_state != ULP_HA_STATE_PRIM_RUN &&
680 			 timeout >= 0);
681 
682 		if (timeout <= 0) {
683 			BNXT_DRV_DBG(ERR,
684 				     "On Close: SEC[COPY] Timed out\n");
685 			goto cleanup;
686 		}
687 
688 		next_state = ULP_HA_STATE_INIT;
689 		rc = ulp_ha_mgr_state_set(ulp_ctx, next_state);
690 		if (rc) {
691 			BNXT_DRV_DBG(ERR,
692 				     "On Close: Failed to set state to INIT(%x)\n",
693 				     rc);
694 			goto cleanup;
695 		}
696 
697 		BNXT_DRV_DBG(INFO,
698 			     "On Close: SEC[COPY] => [INIT] after %d ms\n",
699 			     ULP_HA_WAIT_TIMEOUT - timeout);
700 	} else {
701 		BNXT_DRV_DBG(ERR, "On Close: Invalid type/state %d/%d\n",
702 			     curr_state, app_type);
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_DRV_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_DRV_DBG(ERR, "Unable to get ha info\n");
724 		return -EINVAL;
725 	}
726 	*region = ha_info->region;
727 
728 	return 0;
729 }
730