44# SPDX-License-Identifier: Apache-2.0
55
66from sonic_platform_base .watchdog_base import WatchdogBase
7+ from nexthop import fpga_lib
8+ from sonic_py_common import syslogger
9+
10+ _SYSLOG_IDENTIFIER = "sonic_platform.watchdog"
11+ _logger = syslogger .SysLogger (_SYSLOG_IDENTIFIER )
12+
713
814class Watchdog (WatchdogBase ):
915 """
1016 Nexthop platform-specific placeholder Watchdog class
11- This class isn't implemented yet.
1217 """
1318
14- def __init__ (self ):
19+ # Counter is 24 bits and should be interpreted as milliseconds
20+ _MAX_WATCHDOG_COUNTER_MILLISECONDS = 0xFFFFFF
21+
22+ def __init__ (
23+ self ,
24+ fpga_pci_addr : str ,
25+ event_driven_power_cycle_control_reg_offset : int ,
26+ watchdog_counter_reg_offset : int ,
27+ ):
1528 """
1629 Initialize the Watchdog class
1730 """
18- self .armed = False
19- self .timeout = 0
20- # Add any platform-specific initialization here
31+ super ().__init__ ()
32+ self .fpga_pci_addr : str = fpga_pci_addr
33+ self .event_driven_power_cycle_control_reg_offset : int = (
34+ event_driven_power_cycle_control_reg_offset
35+ )
36+ self .watchdog_counter_reg_offset : int = watchdog_counter_reg_offset
37+
38+ def _read_watchdog_counter_register (self ) -> int :
39+ """Returns the value of the watchdog counter register."""
40+ return fpga_lib .read_32 (
41+ pci_address = self .fpga_pci_addr , offset = self .watchdog_counter_reg_offset
42+ )
43+
44+ def _read_watchdog_countdown_value_milliseconds (self ) -> int :
45+ """Returns the value in the watchdog countdown, in milliseconds."""
46+ reg_val = self ._read_watchdog_counter_register ()
47+ return fpga_lib .get_field (reg_val = reg_val , bit_range = (0 , 23 ))
48+
49+ def _update_watchdog_countdown_value (self , milliseconds : int ) -> None :
50+ """Updates the watchdog counter value."""
51+ reg_val = self ._read_watchdog_counter_register ()
52+ new_reg_val = fpga_lib .overwrite_field (
53+ reg_val = reg_val , bit_range = (0 , 23 ), field_val = milliseconds
54+ )
55+ fpga_lib .write_32 (
56+ pci_address = self .fpga_pci_addr ,
57+ offset = self .watchdog_counter_reg_offset ,
58+ val = new_reg_val ,
59+ )
60+
61+ def _read_watchdog_counter_enable (self ) -> int :
62+ """Reads the bit of whether the counter is enabled."""
63+ reg_val = self ._read_watchdog_counter_register ()
64+ return fpga_lib .get_field (reg_val = reg_val , bit_range = (31 , 31 ))
2165
22- def arm (self , seconds ):
66+ def _toggle_watchdog_counter_enable (self , enable : bool ) -> None :
67+ """Enables or disables the watchdog counter."""
68+ reg_val = self ._read_watchdog_counter_register ()
69+ new_reg_val = fpga_lib .overwrite_field (
70+ reg_val = reg_val , bit_range = (31 , 31 ), field_val = int (enable )
71+ )
72+ fpga_lib .write_32 (
73+ pci_address = self .fpga_pci_addr ,
74+ offset = self .watchdog_counter_reg_offset ,
75+ val = new_reg_val ,
76+ )
77+
78+ def _toggle_watchdog_reboot (self , enable : bool ) -> None :
79+ """Enables or disables the capability of reboot induced by watchdog."""
80+ reg_val = fpga_lib .read_32 (
81+ pci_address = self .fpga_pci_addr ,
82+ offset = self .event_driven_power_cycle_control_reg_offset ,
83+ )
84+ new_reg_val = fpga_lib .overwrite_field (
85+ reg_val = reg_val , bit_range = (4 , 4 ), field_val = int (enable )
86+ )
87+ fpga_lib .write_32 (
88+ pci_address = self .fpga_pci_addr ,
89+ offset = self .event_driven_power_cycle_control_reg_offset ,
90+ val = new_reg_val ,
91+ )
92+
93+ def arm (self , seconds : int ) -> int :
2394 """
2495 Arm the hardware watchdog with a timeout of <seconds> seconds.
2596 If the watchdog is currently armed, calling this function will
@@ -32,38 +103,50 @@ def arm(self, seconds):
32103 An integer specifying the *actual* number of seconds the watchdog
33104 was armed with. On failure returns -1.
34105 """
35- # Implement platform-specific arming logic here
36- # For now, just simulate successful arming
37- if seconds < 0 :
106+ milliseconds = seconds * 1_000
107+
108+ if milliseconds < 0 or milliseconds > self ._MAX_WATCHDOG_COUNTER_MILLISECONDS :
109+ _logger .log_error (
110+ f"cannot arm watchdog with { milliseconds } ms. should be within 0 and { self ._MAX_WATCHDOG_COUNTER_MILLISECONDS } ms"
111+ )
38112 return - 1
39-
40- self .timeout = seconds
41- self .armed = True
42- return self .timeout
43113
44- def disarm (self ):
114+ try :
115+ self ._toggle_watchdog_counter_enable (True )
116+ self ._toggle_watchdog_reboot (True )
117+ self ._update_watchdog_countdown_value (milliseconds = milliseconds )
118+ except Exception as e :
119+ _logger .log_error (f"cannot arm watchdog: { e } " )
120+ return - 1
121+ else :
122+ return seconds
123+
124+ def disarm (self ) -> bool :
45125 """
46126 Disarm the hardware watchdog
47127
48128 Returns:
49129 A boolean, True if watchdog is disarmed successfully, False if not
50130 """
51- # Implement platform-specific disarming logic here
52- # For now, just simulate successful disarming
53- self .armed = False
54- self .timeout = 0
55- return True
131+ try :
132+ self ._toggle_watchdog_counter_enable (False )
133+ self ._toggle_watchdog_reboot (False )
134+ except Exception as e :
135+ _logger .log_error (f"cannot disarm watchdog: { e } " )
136+ return False
137+ else :
138+ return True
56139
57- def is_armed (self ):
140+ def is_armed (self ) -> bool :
58141 """
59142 Retrieves the armed state of the hardware watchdog.
60143
61144 Returns:
62145 A boolean, True if watchdog is armed, False if not
63146 """
64- return self .armed
147+ return bool ( self ._read_watchdog_counter_enable ())
65148
66- def get_remaining_time (self ):
149+ def get_remaining_time (self ) -> int :
67150 """
68151 If the watchdog is armed, retrieve the number of seconds remaining on
69152 the watchdog timer
@@ -72,10 +155,8 @@ def get_remaining_time(self):
72155 An integer specifying the number of seconds remaining on the
73156 watchdog timer. If the watchdog is not armed, returns -1.
74157 """
75- # Implement platform-specific logic to get remaining time
76- # For now, just return the timeout if armed
77- if not self .armed :
158+ if not self .is_armed ():
78159 return - 1
79-
80- # In a real implementation, you would calculate the actual remaining time
81- return self . timeout
160+
161+ countdown_milliseconds = self . _read_watchdog_countdown_value_milliseconds ()
162+ return int ( countdown_milliseconds / 1_000 )
0 commit comments