blob: 3fc8d31b051124bfdf417e877e27d12369ba1498 [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/*
2<:copyright-BRCM:2016:DUAL/GPL:standard
3
4 Broadcom Proprietary and Confidential.(c) 2016 Broadcom
5 All Rights Reserved
6
7Unless you and Broadcom execute a separate written software license
8agreement governing use of this software, this software is licensed
9to you under the terms of the GNU General Public License version 2
10(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11with 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
22Not withstanding the above, under no circumstances may you combine
23this software in any way with any other Broadcom software provided
24under a license other than the GPL, without Broadcom's express prior
25written 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
45typedef struct
46{
47 bcmolt_ps_pair pair;
48 bcmos_bool is_valid;
49} ps_pair_state;
50
51typedef 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
59typedef struct
60{
61 bcmos_msg os_msg;
62 bcmolt_ps_pon pon;
63 bcmolt_auto *ind;
64} ps_task_msg;
65
66typedef 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
74static ps_global_state ps_state = {};
75static bcmos_mutex ps_mutex;
76static bcmos_task ps_task;
77
78#ifdef ENABLE_LOG
79static dev_log_id ps_log_id;
80dev_log_id ps_get_log_id(void)
81{
82 return ps_log_id;
83}
84#endif
85
86static 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
91static 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
96static 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
123static 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
136static 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
146static 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
181static 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
225void 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
243bcmos_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
272bcmos_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
293bcmos_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
302bcmos_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
322bcmos_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
347bcmos_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
383bcmos_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
441bcmos_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
477bcmos_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
511bcmos_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
557static 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
584static 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
611static 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
624static 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
643bcmos_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
727exit:
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
749uint32_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}