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