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