Shad Ansari | 2f7f9be | 2017-06-07 13:34:53 -0700 | [diff] [blame^] | 1 | /* |
| 2 | <:copyright-BRCM:2016:DUAL/GPL:standard |
| 3 | |
| 4 | Broadcom Proprietary and Confidential.(c) 2016 Broadcom |
| 5 | All Rights Reserved |
| 6 | |
| 7 | Unless you and Broadcom execute a separate written software license |
| 8 | agreement governing use of this software, this software is licensed |
| 9 | to you under the terms of the GNU General Public License version 2 |
| 10 | (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, |
| 11 | with the following added to such license: |
| 12 | |
| 13 | As a special exception, the copyright holders of this software give |
| 14 | you permission to link this software with independent modules, and |
| 15 | to copy and distribute the resulting executable under terms of your |
| 16 | choice, provided that you also meet, for each linked independent |
| 17 | module, the terms and conditions of the license of that module. |
| 18 | An independent module is a module which is not derived from this |
| 19 | software. The special exception does not apply to any modifications |
| 20 | of the software. |
| 21 | |
| 22 | Not withstanding the above, under no circumstances may you combine |
| 23 | this software in any way with any other Broadcom software provided |
| 24 | under a license other than the GPL, without Broadcom's express prior |
| 25 | written consent. |
| 26 | |
| 27 | :> |
| 28 | */ |
| 29 | |
| 30 | #include <bcmos_system.h> |
| 31 | #include <bcmolt_api.h> |
| 32 | #include <bcmolt_msg_pack.h> |
| 33 | #include <bcmolt_model_types.h> |
| 34 | #include <bcm_dev_log.h> |
| 35 | #include "bcmolt_user_appl_ps.h" |
| 36 | #include "bcmolt_user_appl_ps_internal.h" |
| 37 | |
| 38 | #ifndef SIMULATION_BUILD |
| 39 | #include <bcmolt_board.h> |
| 40 | #endif |
| 41 | |
| 42 | #define PS_DEFAULT_MAX_PAIRS 16 |
| 43 | #define PS_TASK_MSG_Q_SIZE 64 |
| 44 | |
| 45 | typedef struct |
| 46 | { |
| 47 | bcmolt_ps_pair pair; |
| 48 | bcmos_bool is_valid; |
| 49 | } ps_pair_state; |
| 50 | |
| 51 | typedef struct |
| 52 | { |
| 53 | bcmos_bool is_running; |
| 54 | bcmolt_ps_global_cfg cfg; |
| 55 | ps_pair_state *pairs; |
| 56 | uint32_t switch_start_time_us; |
| 57 | } ps_global_state; |
| 58 | |
| 59 | typedef struct |
| 60 | { |
| 61 | bcmos_msg os_msg; |
| 62 | bcmolt_ps_pon pon; |
| 63 | bcmolt_auto *ind; |
| 64 | } ps_task_msg; |
| 65 | |
| 66 | typedef enum |
| 67 | { |
| 68 | PS_PON_MODE_INVALID, |
| 69 | PS_PON_MODE_GPON, |
| 70 | PS_PON_MODE_EPON, |
| 71 | PS_PON_MODE_XGPON, |
| 72 | } ps_pon_mode; |
| 73 | |
| 74 | static ps_global_state ps_state = {}; |
| 75 | static bcmos_mutex ps_mutex; |
| 76 | static bcmos_task ps_task; |
| 77 | |
| 78 | #ifdef ENABLE_LOG |
| 79 | static dev_log_id ps_log_id; |
| 80 | dev_log_id ps_get_log_id(void) |
| 81 | { |
| 82 | return ps_log_id; |
| 83 | } |
| 84 | #endif |
| 85 | |
| 86 | static inline bcmos_bool ps_pon_equal(const bcmolt_ps_pon *a, const bcmolt_ps_pon *b) |
| 87 | { |
| 88 | return a->device_id == b->device_id && a->pon_id == b->pon_id; |
| 89 | } |
| 90 | |
| 91 | static inline bcmos_bool ps_pair_equal(const bcmolt_ps_pair *a, const bcmolt_ps_pair *b) |
| 92 | { |
| 93 | return ps_pon_equal(&a->standby, &b->standby) && ps_pon_equal(&a->working, &b->working); |
| 94 | } |
| 95 | |
| 96 | static bcmos_errno bcmolt_ps_pon_pair_get(const bcmolt_ps_pon *pon, bcmolt_ps_pair **pair) |
| 97 | { |
| 98 | uint16_t i; |
| 99 | |
| 100 | if (!ps_state.is_running) |
| 101 | { |
| 102 | *pair = NULL; |
| 103 | PS_ERR("PS application not running\n"); |
| 104 | return BCM_ERR_STATE; |
| 105 | } |
| 106 | |
| 107 | for (i = 0; i < ps_state.cfg.max_num_pairs; i++) |
| 108 | { |
| 109 | if (ps_state.pairs[i].is_valid) |
| 110 | { |
| 111 | if (ps_pon_equal(pon, &ps_state.pairs[i].pair.standby) || |
| 112 | ps_pon_equal(pon, &ps_state.pairs[i].pair.working)) |
| 113 | { |
| 114 | *pair = &ps_state.pairs[i].pair; |
| 115 | return BCM_ERR_OK; |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | return BCM_ERR_NOENT; |
| 121 | } |
| 122 | |
| 123 | static bcmos_errno ps_init_task(void) |
| 124 | { |
| 125 | bcmos_task_parm task_params = |
| 126 | { |
| 127 | .name = "user_appl_ps", |
| 128 | .priority = TASK_PRIORITY_USER_APPL_PS, |
| 129 | .core = BCMOS_CPU_CORE_ANY, /* No CPU affinity */ |
| 130 | .init_handler = NULL |
| 131 | }; |
| 132 | |
| 133 | return bcmos_task_create(&ps_task, &task_params); |
| 134 | } |
| 135 | |
| 136 | static bcmos_errno ps_init_module(void) |
| 137 | { |
| 138 | bcmos_module_parm module_params = |
| 139 | { |
| 140 | .qparm = { .name = "user_appl_ps", .size = PS_TASK_MSG_Q_SIZE } |
| 141 | }; |
| 142 | |
| 143 | return bcmos_module_create(BCMOS_MODULE_ID_USER_APPL_PS, &ps_task, &module_params); |
| 144 | } |
| 145 | |
| 146 | static ps_pon_mode ps_pon_mode_get(bcmolt_devid dev) |
| 147 | { |
| 148 | bcmos_errno err; |
| 149 | bcmolt_system_mode system_mode; |
| 150 | |
| 151 | err = bcmolt_system_mode_get(dev, &system_mode); |
| 152 | if (err != BCM_ERR_OK) |
| 153 | { |
| 154 | return PS_PON_MODE_INVALID; |
| 155 | } |
| 156 | switch (system_mode) |
| 157 | { |
| 158 | case BCMOLT_SYSTEM_MODE_GPON__4_X: |
| 159 | case BCMOLT_SYSTEM_MODE_GPON__8_X: |
| 160 | case BCMOLT_SYSTEM_MODE_GPON__16_X: |
| 161 | return PS_PON_MODE_GPON; |
| 162 | case BCMOLT_SYSTEM_MODE_EPON__16_X: |
| 163 | case BCMOLT_SYSTEM_MODE_EPON__8_X: |
| 164 | case BCMOLT_SYSTEM_MODE_EPON__4_X: |
| 165 | case BCMOLT_SYSTEM_MODE_EPON__8_X_COEXISTENCE_TDMA: |
| 166 | case BCMOLT_SYSTEM_MODE_EPON__4_X_COEXISTENCE_TDMA: |
| 167 | case BCMOLT_SYSTEM_MODE_EPON__8_X_10_G: |
| 168 | case BCMOLT_SYSTEM_MODE_EPON__4_X_10_G: |
| 169 | case BCMOLT_SYSTEM_MODE_EPON__2_X_10_G: |
| 170 | return PS_PON_MODE_EPON; |
| 171 | case BCMOLT_SYSTEM_MODE_XGPON_1__4_X: |
| 172 | case BCMOLT_SYSTEM_MODE_XGPON_1__8_X: |
| 173 | case BCMOLT_SYSTEM_MODE_XGS__2_X_10_G: |
| 174 | case BCMOLT_SYSTEM_MODE_NGPON2__2_X_10_G: |
| 175 | return PS_PON_MODE_XGPON; |
| 176 | default: |
| 177 | return PS_PON_MODE_INVALID; |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | static void ps_handle_msg(bcmos_module_id module_id, bcmos_msg *os_msg) |
| 182 | { |
| 183 | ps_task_msg *msg = (ps_task_msg *)os_msg; |
| 184 | bcmos_errno err; |
| 185 | |
| 186 | /* process the indication */ |
| 187 | if (msg->ind->hdr.obj_type == BCMOLT_OBJ_ID_DEVICE || msg->ind->hdr.obj_type == BCMOLT_OBJ_ID_DEBUG) |
| 188 | { |
| 189 | /* there's no need to mirror device-level indications */ |
| 190 | err = BCM_ERR_OK; |
| 191 | } |
| 192 | else |
| 193 | { |
| 194 | switch (ps_pon_mode_get(msg->pon.device_id)) |
| 195 | { |
| 196 | case PS_PON_MODE_GPON: |
| 197 | err = ps_process_ind_gpon(&msg->pon, msg->ind); |
| 198 | break; |
| 199 | case PS_PON_MODE_EPON: |
| 200 | err = ps_process_ind_epon(&msg->pon, msg->ind); |
| 201 | break; |
| 202 | case PS_PON_MODE_XGPON: |
| 203 | err = ps_process_ind_xgpon(&msg->pon, msg->ind); |
| 204 | break; |
| 205 | default: |
| 206 | err = BCM_ERR_STATE; /* not a supported system mode */ |
| 207 | break; |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | if (err != BCM_ERR_OK) |
| 212 | { |
| 213 | bcmolt_auto *ind = msg->ind; |
| 214 | |
| 215 | PS_ERR("Error processing indication (obj_type=%u, subgroup=%u): %s\n", ind->hdr.obj_type, ind->hdr.subgroup, bcmos_strerror(err)); |
| 216 | } |
| 217 | |
| 218 | /* free the cloned indication since we're done processing it */ |
| 219 | bcmolt_msg_free(&msg->ind->hdr); |
| 220 | |
| 221 | /* free the internal OS message handle */ |
| 222 | bcmos_free(os_msg); |
| 223 | } |
| 224 | |
| 225 | void bcmolt_ps_appl_init(void) |
| 226 | { |
| 227 | bcmos_errno err; |
| 228 | |
| 229 | #ifdef ENABLE_LOG |
| 230 | ps_log_id = bcm_dev_log_id_register("user_appl_ps", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH); |
| 231 | #endif |
| 232 | |
| 233 | err = bcmos_mutex_create(&ps_mutex, 0, NULL); |
| 234 | BUG_ON(err != BCM_ERR_OK); |
| 235 | |
| 236 | err = ps_init_task(); |
| 237 | BUG_ON(err != BCM_ERR_OK); |
| 238 | |
| 239 | err = ps_init_module(); |
| 240 | BUG_ON(err != BCM_ERR_OK); |
| 241 | } |
| 242 | |
| 243 | bcmos_errno bcmolt_ps_appl_start(const bcmolt_ps_global_cfg *cfg) |
| 244 | { |
| 245 | bcmos_mutex_lock(&ps_mutex); |
| 246 | |
| 247 | if (ps_state.is_running) |
| 248 | { |
| 249 | bcmos_mutex_unlock(&ps_mutex); |
| 250 | PS_ERR("PS application already running\n"); |
| 251 | return BCM_ERR_STATE; |
| 252 | } |
| 253 | |
| 254 | ps_state.cfg = *cfg; |
| 255 | ps_state.cfg.max_num_pairs = (ps_state.cfg.max_num_pairs == 0) ? PS_DEFAULT_MAX_PAIRS : ps_state.cfg.max_num_pairs; |
| 256 | ps_state.pairs = bcmos_calloc(sizeof(*ps_state.pairs) * ps_state.cfg.max_num_pairs); |
| 257 | if (ps_state.pairs == NULL) |
| 258 | { |
| 259 | BCM_MEMZERO_STRUCT(&ps_state); |
| 260 | bcmos_mutex_unlock(&ps_mutex); |
| 261 | PS_ERR("memory allocation failed\n"); |
| 262 | return BCM_ERR_NOMEM; |
| 263 | } |
| 264 | |
| 265 | ps_state.is_running = BCMOS_TRUE; |
| 266 | |
| 267 | bcmos_mutex_unlock(&ps_mutex); |
| 268 | PS_INFO("PS application started\n"); |
| 269 | return BCM_ERR_OK; |
| 270 | } |
| 271 | |
| 272 | bcmos_errno bcmolt_ps_appl_stop(void) |
| 273 | { |
| 274 | bcmos_mutex_lock(&ps_mutex); |
| 275 | |
| 276 | if (!ps_state.is_running) |
| 277 | { |
| 278 | bcmos_mutex_unlock(&ps_mutex); |
| 279 | PS_ERR("PS application not running\n"); |
| 280 | return BCM_ERR_STATE; |
| 281 | } |
| 282 | |
| 283 | ps_state.is_running = BCMOS_FALSE; |
| 284 | |
| 285 | bcmos_free(ps_state.pairs); |
| 286 | BCM_MEMZERO_STRUCT(&ps_state); |
| 287 | |
| 288 | bcmos_mutex_unlock(&ps_mutex); |
| 289 | PS_INFO("PS application stopped\n"); |
| 290 | return BCM_ERR_OK; |
| 291 | } |
| 292 | |
| 293 | bcmos_bool bcmolt_ps_appl_is_running(void) |
| 294 | { |
| 295 | bcmos_bool ret; |
| 296 | bcmos_mutex_lock(&ps_mutex); |
| 297 | ret = ps_state.is_running; |
| 298 | bcmos_mutex_unlock(&ps_mutex); |
| 299 | return ret; |
| 300 | } |
| 301 | |
| 302 | bcmos_errno bcmolt_ps_global_cfg_get(bcmolt_ps_global_cfg *cfg) |
| 303 | { |
| 304 | bcmos_errno err; |
| 305 | bcmos_mutex_lock(&ps_mutex); |
| 306 | |
| 307 | if (!ps_state.is_running) |
| 308 | { |
| 309 | PS_ERR("PS application not running\n"); |
| 310 | err = BCM_ERR_STATE; |
| 311 | } |
| 312 | else |
| 313 | { |
| 314 | *cfg = ps_state.cfg; |
| 315 | err = BCM_ERR_OK; |
| 316 | } |
| 317 | |
| 318 | bcmos_mutex_unlock(&ps_mutex); |
| 319 | return err; |
| 320 | } |
| 321 | |
| 322 | bcmos_errno bcmolt_ps_global_cfg_update(const bcmolt_ps_global_cfg *cfg) |
| 323 | { |
| 324 | bcmos_errno err; |
| 325 | bcmos_mutex_lock(&ps_mutex); |
| 326 | |
| 327 | if (!ps_state.is_running) |
| 328 | { |
| 329 | PS_ERR("PS application not running\n"); |
| 330 | err = BCM_ERR_STATE; |
| 331 | } |
| 332 | else if (cfg->max_num_pairs != ps_state.cfg.max_num_pairs) |
| 333 | { |
| 334 | PS_ERR("cannot change max number of protected pairs while running\n"); |
| 335 | err = BCM_ERR_PARM; |
| 336 | } |
| 337 | else |
| 338 | { |
| 339 | ps_state.cfg = *cfg; |
| 340 | err = BCM_ERR_OK; |
| 341 | } |
| 342 | |
| 343 | bcmos_mutex_unlock(&ps_mutex); |
| 344 | return err; |
| 345 | } |
| 346 | |
| 347 | bcmos_errno bcmolt_ps_pairs_get(uint16_t array_len, bcmolt_ps_pair *pairs, uint16_t *num_written) |
| 348 | { |
| 349 | bcmos_errno err; |
| 350 | uint16_t i; |
| 351 | |
| 352 | bcmos_mutex_lock(&ps_mutex); |
| 353 | |
| 354 | if (!ps_state.is_running) |
| 355 | { |
| 356 | PS_ERR("PS application not running\n"); |
| 357 | err = BCM_ERR_STATE; |
| 358 | } |
| 359 | else |
| 360 | { |
| 361 | *num_written = 0; |
| 362 | err = BCM_ERR_OK; |
| 363 | for (i = 0; i < ps_state.cfg.max_num_pairs; i++) |
| 364 | { |
| 365 | if (ps_state.pairs[i].is_valid) |
| 366 | { |
| 367 | if (*num_written == array_len) |
| 368 | { |
| 369 | PS_ERR("array size too small to collect all pairs\n"); |
| 370 | err = BCM_ERR_PARM; |
| 371 | break; |
| 372 | } |
| 373 | pairs[*num_written] = ps_state.pairs[i].pair; |
| 374 | (*num_written)++; |
| 375 | } |
| 376 | } |
| 377 | } |
| 378 | |
| 379 | bcmos_mutex_unlock(&ps_mutex); |
| 380 | return err; |
| 381 | } |
| 382 | |
| 383 | bcmos_errno bcmolt_ps_pair_add(const bcmolt_ps_pair *pair) |
| 384 | { |
| 385 | uint16_t i; |
| 386 | bcmos_errno err; |
| 387 | |
| 388 | bcmos_mutex_lock(&ps_mutex); |
| 389 | |
| 390 | if (!ps_state.is_running) |
| 391 | { |
| 392 | PS_ERR("PS application not running\n"); |
| 393 | err = BCM_ERR_STATE; |
| 394 | } |
| 395 | else if (ps_pon_equal(&pair->working, &pair->standby)) |
| 396 | { |
| 397 | PS_ERR("A PON cannot protect itself\n"); |
| 398 | err = BCM_ERR_PARM; |
| 399 | } |
| 400 | else |
| 401 | { |
| 402 | err = BCM_ERR_OK; |
| 403 | for (i = 0; i < ps_state.cfg.max_num_pairs; i++) |
| 404 | { |
| 405 | if (ps_state.pairs[i].is_valid && |
| 406 | (ps_pon_equal(&pair->working, &ps_state.pairs[i].pair.working) || |
| 407 | ps_pon_equal(&pair->working, &ps_state.pairs[i].pair.standby) || |
| 408 | ps_pon_equal(&pair->standby, &ps_state.pairs[i].pair.working) || |
| 409 | ps_pon_equal(&pair->standby, &ps_state.pairs[i].pair.standby))) |
| 410 | { |
| 411 | PS_ERR("One of the PONs was already present in an existing pair\n"); |
| 412 | err = BCM_ERR_ALREADY; |
| 413 | break; |
| 414 | } |
| 415 | } |
| 416 | |
| 417 | if (err == BCM_ERR_OK) |
| 418 | { |
| 419 | err = BCM_ERR_NORES; |
| 420 | for (i = 0; i < ps_state.cfg.max_num_pairs; i++) |
| 421 | { |
| 422 | if (!ps_state.pairs[i].is_valid) |
| 423 | { |
| 424 | ps_state.pairs[i].pair = *pair; |
| 425 | ps_state.pairs[i].is_valid = BCMOS_TRUE; |
| 426 | err = BCM_ERR_OK; |
| 427 | break; |
| 428 | } |
| 429 | } |
| 430 | if (err == BCM_ERR_NORES) |
| 431 | { |
| 432 | PS_ERR("Not enough memory available to add pair\n"); |
| 433 | } |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | bcmos_mutex_unlock(&ps_mutex); |
| 438 | return err; |
| 439 | } |
| 440 | |
| 441 | bcmos_errno bcmolt_ps_pon_remove(const bcmolt_ps_pon *pon) |
| 442 | { |
| 443 | uint16_t i; |
| 444 | bcmos_errno err; |
| 445 | |
| 446 | bcmos_mutex_lock(&ps_mutex); |
| 447 | |
| 448 | if (!ps_state.is_running) |
| 449 | { |
| 450 | PS_ERR("PS application not running\n"); |
| 451 | err = BCM_ERR_STATE; |
| 452 | } |
| 453 | else |
| 454 | { |
| 455 | err = BCM_ERR_NOENT; |
| 456 | for (i = 0; i < ps_state.cfg.max_num_pairs; i++) |
| 457 | { |
| 458 | if (ps_state.pairs[i].is_valid && |
| 459 | (ps_pon_equal(pon, &ps_state.pairs[i].pair.working) || |
| 460 | ps_pon_equal(pon, &ps_state.pairs[i].pair.standby))) |
| 461 | { |
| 462 | ps_state.pairs[i].is_valid = BCMOS_FALSE; |
| 463 | err = BCM_ERR_OK; |
| 464 | break; |
| 465 | } |
| 466 | } |
| 467 | if (err == BCM_ERR_NOENT) |
| 468 | { |
| 469 | PS_ERR("Specified PON not found\n"); |
| 470 | } |
| 471 | } |
| 472 | |
| 473 | bcmos_mutex_unlock(&ps_mutex); |
| 474 | return err; |
| 475 | } |
| 476 | |
| 477 | bcmos_errno bcmolt_ps_pon_state_get(const bcmolt_ps_pon *pon, bcmolt_ps_pon_state *state, bcmolt_ps_pon *partner) |
| 478 | { |
| 479 | bcmos_errno err; |
| 480 | bcmolt_ps_pair *pair; |
| 481 | |
| 482 | bcmos_mutex_lock(&ps_mutex); |
| 483 | err = bcmolt_ps_pon_pair_get(pon, &pair); |
| 484 | bcmos_mutex_unlock(&ps_mutex); |
| 485 | |
| 486 | if (err == BCM_ERR_OK) |
| 487 | { |
| 488 | if (ps_pon_equal(pon, &pair->standby)) |
| 489 | { |
| 490 | *state = BCMOLT_PS_PON_STATE_STANDBY; |
| 491 | *partner = pair->working; |
| 492 | } |
| 493 | else |
| 494 | { |
| 495 | *state = BCMOLT_PS_PON_STATE_WORKING; |
| 496 | *partner = pair->standby; |
| 497 | } |
| 498 | return BCM_ERR_OK; |
| 499 | } |
| 500 | else if (err == BCM_ERR_NOENT) |
| 501 | { |
| 502 | *state = BCMOLT_PS_PON_STATE_UNASSOCIATED; |
| 503 | return BCM_ERR_OK; |
| 504 | } |
| 505 | else |
| 506 | { |
| 507 | return err; |
| 508 | } |
| 509 | } |
| 510 | |
| 511 | bcmos_errno bcmolt_ps_process_ind(const bcmolt_ps_pon *pon, bcmolt_auto *ind) |
| 512 | { |
| 513 | bcmos_errno err; |
| 514 | bcmolt_msg *ind_clone = NULL; |
| 515 | |
| 516 | if (!bcmolt_ps_appl_is_running()) |
| 517 | { |
| 518 | return BCM_ERR_OK; |
| 519 | } |
| 520 | |
| 521 | /* Make a copy of all indications received so they can be handled later asynchronously. We don't validate PON state |
| 522 | * here since it might change before we get around to handling it. |
| 523 | * |
| 524 | * Note that this could be optimized to filter out indications that aren't relevant for protection switching before |
| 525 | * copying them, but this is left out for simplicity. */ |
| 526 | err = bcmolt_msg_clone(&ind_clone, &ind->hdr); |
| 527 | if (err != BCM_ERR_OK) |
| 528 | { |
| 529 | PS_ERR("Indication clone failed: %s\n", bcmos_strerror(err)); |
| 530 | return err; |
| 531 | } |
| 532 | |
| 533 | /* send this indication to the internal task's message queue to be processed */ |
| 534 | ps_task_msg *msg = bcmos_calloc(sizeof(*msg)); |
| 535 | if (msg == NULL) |
| 536 | { |
| 537 | PS_ERR("Message calloc failed\n"); |
| 538 | bcmolt_msg_free(ind_clone); |
| 539 | return BCM_ERR_NOMEM; |
| 540 | } |
| 541 | |
| 542 | msg->os_msg.handler = ps_handle_msg; |
| 543 | msg->os_msg.release = bcmolt_os_msg_release_cb; |
| 544 | msg->pon = *pon; |
| 545 | msg->ind = (bcmolt_auto *)ind_clone; |
| 546 | |
| 547 | err = bcmos_msg_send_to_module(BCMOS_MODULE_ID_USER_APPL_PS, &msg->os_msg, 0); |
| 548 | if (err != BCM_ERR_OK) |
| 549 | { |
| 550 | PS_ERR("Message send failed: %s\n", bcmos_strerror(err)); |
| 551 | return err; |
| 552 | } |
| 553 | |
| 554 | return BCM_ERR_OK; |
| 555 | } |
| 556 | |
| 557 | static bcmos_errno bcmolt_ps_change_pon_to_standby(const bcmolt_ps_pon *pon) |
| 558 | { |
| 559 | bcmos_errno err; |
| 560 | |
| 561 | PS_INFO("Switching PON <%d:%d> working->standby\n", pon->device_id, pon->pon_id); |
| 562 | switch (ps_pon_mode_get(pon->device_id)) |
| 563 | { |
| 564 | case PS_PON_MODE_GPON: |
| 565 | err = ps_move_to_standby_gpon(pon); |
| 566 | break; |
| 567 | case PS_PON_MODE_EPON: |
| 568 | err = ps_move_to_standby_epon(pon); |
| 569 | break; |
| 570 | case PS_PON_MODE_XGPON: |
| 571 | err = ps_move_to_standby_xgpon(pon); |
| 572 | break; |
| 573 | default: |
| 574 | err = BCM_ERR_STATE; /* not a supported system mode */ |
| 575 | break; |
| 576 | } |
| 577 | if (err != BCM_ERR_OK) |
| 578 | { |
| 579 | PS_ERR("<%d:%d> working->standby API failed: %s\n", pon->device_id, pon->pon_id, bcmos_strerror(err)); |
| 580 | } |
| 581 | return err; |
| 582 | } |
| 583 | |
| 584 | static bcmos_errno bcmolt_ps_change_pon_to_working(const bcmolt_ps_pon *pon) |
| 585 | { |
| 586 | bcmos_errno err; |
| 587 | |
| 588 | PS_INFO("Switching PON <%d:%d> standby->working\n", pon->device_id, pon->pon_id); |
| 589 | switch (ps_pon_mode_get(pon->device_id)) |
| 590 | { |
| 591 | case PS_PON_MODE_GPON: |
| 592 | err = ps_move_to_working_gpon(pon); |
| 593 | break; |
| 594 | case PS_PON_MODE_EPON: |
| 595 | err = ps_move_to_working_epon(pon); |
| 596 | break; |
| 597 | case PS_PON_MODE_XGPON: |
| 598 | err = ps_move_to_working_xgpon(pon); |
| 599 | break; |
| 600 | default: |
| 601 | err = BCM_ERR_STATE; /* not a supported system mode */ |
| 602 | break; |
| 603 | } |
| 604 | if (err != BCM_ERR_OK) |
| 605 | { |
| 606 | PS_ERR("<%d:%d> standby->working API failed: %s\n", pon->device_id, pon->pon_id, bcmos_strerror(err)); |
| 607 | } |
| 608 | return err; |
| 609 | } |
| 610 | |
| 611 | static bcmos_errno bcmolt_ps_disable_tx_optics(const bcmolt_ps_pon *pon) |
| 612 | { |
| 613 | PS_INFO("Disabling TRX for PON <%d:%d:%d>\n", pon->device_id, pon->pon_id, pon->transceiver_id); |
| 614 | |
| 615 | /* This disables the TX optical channel on a given PON port on the BCM68620 SVK board. |
| 616 | For other boards, this must be changed to match the board design. */ |
| 617 | #ifndef SIMULATION_BUILD |
| 618 | return bcm_board_trx_enable(pon->transceiver_id, BCMOS_FALSE); |
| 619 | #else |
| 620 | return BCM_ERR_OK; |
| 621 | #endif |
| 622 | } |
| 623 | |
| 624 | static bcmos_errno bcmolt_ps_enable_tx_optics(const bcmolt_ps_pon *pon) |
| 625 | { |
| 626 | #ifndef SIMULATION_BUILD |
| 627 | bcmos_errno ret; |
| 628 | #endif |
| 629 | |
| 630 | PS_INFO("Enabling TRX for PON <%d:%d:%d>\n", pon->device_id, pon->pon_id, pon->transceiver_id); |
| 631 | |
| 632 | /* This enables the TX optical channel on a given PON port on the BCM68620 SVK board. |
| 633 | For other boards, this must be changed to match the board design. */ |
| 634 | #ifndef SIMULATION_BUILD |
| 635 | ret = bcm_board_trx_enable(pon->transceiver_id, BCMOS_TRUE); |
| 636 | bcmos_usleep(ps_state.cfg.trx_warming_delay); |
| 637 | return ret; |
| 638 | #else |
| 639 | return BCM_ERR_OK; |
| 640 | #endif |
| 641 | } |
| 642 | |
| 643 | bcmos_errno bcmolt_ps_switch_perform(const bcmolt_ps_pon *pon) |
| 644 | { |
| 645 | bcmos_errno err; |
| 646 | bcmolt_ps_pair *pair; |
| 647 | bcmolt_ps_pon temp_pon; |
| 648 | |
| 649 | bcmos_mutex_lock(&ps_mutex); |
| 650 | ps_state.switch_start_time_us = bcmos_timestamp(); |
| 651 | err = bcmolt_ps_pon_pair_get(pon, &pair); |
| 652 | bcmos_mutex_unlock(&ps_mutex); |
| 653 | |
| 654 | if (err != BCM_ERR_OK) |
| 655 | { |
| 656 | goto exit; |
| 657 | } |
| 658 | |
| 659 | if (ps_state.cfg.switch_sequence == BCMOLT_PS_SWITCH_SEQUENCE_TRX_FIRST) |
| 660 | { |
| 661 | /* step 1: disable optical TX channel of the working PON */ |
| 662 | err = bcmolt_ps_disable_tx_optics(&pair->working); |
| 663 | if (err != BCM_ERR_OK) |
| 664 | { |
| 665 | goto exit; |
| 666 | } |
| 667 | |
| 668 | /* step 2: enable optical TX channel of the standby PON */ |
| 669 | err = bcmolt_ps_enable_tx_optics(&pair->standby); |
| 670 | if (err != BCM_ERR_OK) |
| 671 | { |
| 672 | goto exit; |
| 673 | } |
| 674 | |
| 675 | /* step 3: change the standby PON state to working */ |
| 676 | err = bcmolt_ps_change_pon_to_working(&pair->standby); |
| 677 | if (err != BCM_ERR_OK) |
| 678 | { |
| 679 | goto exit; |
| 680 | } |
| 681 | |
| 682 | /* step 4: change the working PON state to standby */ |
| 683 | err = bcmolt_ps_change_pon_to_standby(&pair->working); |
| 684 | if (err != BCM_ERR_OK) |
| 685 | { |
| 686 | goto exit; |
| 687 | } |
| 688 | } |
| 689 | else /* ps_state.cfg.switch_sequence == BCMOLT_PS_SWITCH_SEQUENCE_STANDARD */ |
| 690 | { |
| 691 | /* step 1: change the working PON state to standby */ |
| 692 | err = bcmolt_ps_change_pon_to_standby(&pair->working); |
| 693 | if (err != BCM_ERR_OK) |
| 694 | { |
| 695 | goto exit; |
| 696 | } |
| 697 | |
| 698 | /* step 2: disable optical TX channel of the working PON */ |
| 699 | err = bcmolt_ps_disable_tx_optics(&pair->working); |
| 700 | if (err != BCM_ERR_OK) |
| 701 | { |
| 702 | goto exit; |
| 703 | } |
| 704 | |
| 705 | /* step 3: enable optical TX channel of the standby PON */ |
| 706 | err = bcmolt_ps_enable_tx_optics(&pair->standby); |
| 707 | if (err != BCM_ERR_OK) |
| 708 | { |
| 709 | goto exit; |
| 710 | } |
| 711 | |
| 712 | /* step 4: change the standby PON state to working */ |
| 713 | err = bcmolt_ps_change_pon_to_working(&pair->standby); |
| 714 | if (err != BCM_ERR_OK) |
| 715 | { |
| 716 | goto exit; |
| 717 | } |
| 718 | } |
| 719 | |
| 720 | /* step 5: update internal database for new PON states */ |
| 721 | bcmos_mutex_lock(&ps_mutex); |
| 722 | temp_pon = pair->working; |
| 723 | pair->working = pair->standby; |
| 724 | pair->standby = temp_pon; |
| 725 | bcmos_mutex_unlock(&ps_mutex); |
| 726 | |
| 727 | exit: |
| 728 | if (err == BCM_ERR_OK) |
| 729 | { |
| 730 | PS_INFO( |
| 731 | "<%d:%d> switchover started successfully (<%d:%d> is now standby)\n", |
| 732 | pair->working.device_id, |
| 733 | pair->working.pon_id, |
| 734 | pair->standby.device_id, |
| 735 | pair->standby.pon_id); |
| 736 | } |
| 737 | else if (pair) |
| 738 | { |
| 739 | PS_INFO( |
| 740 | "<%d:%d> switchover encountered an error: %s\n", |
| 741 | pair->working.device_id, |
| 742 | pair->working.pon_id, |
| 743 | bcmos_strerror(err)); |
| 744 | } |
| 745 | |
| 746 | return err; |
| 747 | } |
| 748 | |
| 749 | uint32_t ps_get_last_switch_start_time_us(void) |
| 750 | { |
| 751 | uint32_t ret; |
| 752 | bcmos_mutex_lock(&ps_mutex); |
| 753 | ret = ps_state.switch_start_time_us; |
| 754 | bcmos_mutex_unlock(&ps_mutex); |
| 755 | return ret; |
| 756 | } |