-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
watchdog.py
194 lines (160 loc) · 5.91 KB
/
watchdog.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#############################################################################
# Celestica
#
# Watchdog contains an implementation of SONiC Platform Base API
#
#############################################################################
import ctypes
import os
import subprocess
import time
try:
from sonic_platform_base.watchdog_base import WatchdogBase
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
PLATFORM_CPLD_PATH = '/sys/devices/platform/dx010_cpld'
GETREG_FILE = 'getreg'
SETREG_FILE = 'setreg'
WDT_ENABLE_REG = '0x141'
WDT_TIMER_L_BIT_REG = '0x142'
WDT_TIMER_M_BIT_REG = '0x143'
WDT_TIMER_H_BIT_REG = '0x144'
WDT_KEEP_ALVIVE_REG = '0x145'
ENABLE_CMD = '0x1'
DISABLE_CMD = '0x0'
WDT_COMMON_ERROR = -1
class Watchdog(WatchdogBase):
def __init__(self):
WatchdogBase.__init__(self)
# Init helper
self._api_helper = APIHelper()
# Init cpld reg path
self.setreg_path = os.path.join(PLATFORM_CPLD_PATH, SETREG_FILE)
self.getreg_path = os.path.join(PLATFORM_CPLD_PATH, GETREG_FILE)
# Set default value
self._disable()
self.armed = False
self.timeout = self._gettimeout()
def _enable(self):
"""
Turn on the watchdog timer
"""
# echo 0x141 0x1 > /sys/devices/platform/dx010_cpld/setreg
enable_val = '{} {}'.format(WDT_ENABLE_REG, ENABLE_CMD)
return self._api_helper.write_txt_file(self.setreg_path, enable_val)
def _disable(self):
"""
Turn off the watchdog timer
"""
# echo 0x141 0x0 > /sys/devices/platform/dx010_cpld/setreg
disable_val = '{} {}'.format(WDT_ENABLE_REG, DISABLE_CMD)
return self._api_helper.write_txt_file(self.setreg_path, disable_val)
def _keepalive(self):
"""
Keep alive watchdog timer
"""
# echo 0x145 0x1 > /sys/devices/platform/dx010_cpld/setreg
enable_val = '{} {}'.format(WDT_KEEP_ALVIVE_REG, ENABLE_CMD)
return self._api_helper.write_txt_file(self.setreg_path, enable_val)
def _get_level_hex(self, sub_hex):
sub_hex_str = sub_hex.replace("x", "0")
return hex(int(sub_hex_str, 16))
def _seconds_to_lmh_hex(self, seconds):
ms = seconds*1000 # calculate timeout in ms format
hex_str = hex(ms)
l = self._get_level_hex(hex_str[-2:])
m = self._get_level_hex(hex_str[-4:-2])
h = self._get_level_hex(hex_str[-6:-4])
return (l, m, h)
def _settimeout(self, seconds):
"""
Set watchdog timer timeout
@param seconds - timeout in seconds
@return is the actual set timeout
"""
# max = 0xffffff = 16777.215 seconds
(l, m, h) = self._seconds_to_lmh_hex(seconds)
set_h_val = '{} {}'.format(WDT_TIMER_H_BIT_REG, h)
set_m_val = '{} {}'.format(WDT_TIMER_M_BIT_REG, m)
set_l_val = '{} {}'.format(WDT_TIMER_L_BIT_REG, l)
self._api_helper.write_txt_file(self.setreg_path, set_h_val)
self._api_helper.write_txt_file(self.setreg_path, set_m_val)
self._api_helper.write_txt_file(self.setreg_path, set_l_val)
return seconds
def _gettimeout(self):
"""
Get watchdog timeout
@return watchdog timeout
"""
h_bit = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_TIMER_H_BIT_REG)
m_bit = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_TIMER_M_BIT_REG)
l_bit = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_TIMER_L_BIT_REG)
hex_time = '0x{}{}{}'.format(h_bit[2:], m_bit[2:], l_bit[2:])
ms = int(hex_time, 16)
return int(float(ms)/1000)
#################################################################
def arm(self, seconds):
"""
Arm the hardware watchdog with a timeout of <seconds> seconds.
If the watchdog is currently armed, calling this function will
simply reset the timer to the provided value. If the underlying
hardware does not support the value provided in <seconds>, this
method should arm the watchdog with the *next greater* available
value.
Returns:
An integer specifying the *actual* number of seconds the watchdog
was armed with. On failure returns -1.
"""
ret = WDT_COMMON_ERROR
if seconds < 0:
return ret
if seconds > 16777:
return ret
try:
if self.timeout != seconds:
self.timeout = self._settimeout(seconds)
if self.armed:
self._keepalive()
else:
self._enable()
self.armed = True
ret = self.timeout
self.arm_timestamp = time.time()
except IOError as e:
pass
return ret
def disarm(self):
"""
Disarm the hardware watchdog
Returns:
A boolean, True if watchdog is disarmed successfully, False if not
"""
disarmed = False
if self.is_armed():
try:
self._disable()
self.armed = False
disarmed = True
except IOError:
pass
return disarmed
def is_armed(self):
"""
Retrieves the armed state of the hardware watchdog.
Returns:
A boolean, True if watchdog is armed, False if not
"""
return self.armed
def get_remaining_time(self):
"""
If the watchdog is armed, retrieve the number of seconds remaining on
the watchdog timer
Returns:
An integer specifying the number of seconds remaining on thei
watchdog timer. If the watchdog is not armed, returns -1.
"""
return int(self.timeout - (time.time() - self.arm_timestamp)) if self.armed else WDT_COMMON_ERROR