Skip to content

Commit 7bc8f12

Browse files
[DellEMC] Z9264f Watchdog support (#4192)
Co-authored-by: Sujin Kang <[email protected]>
1 parent 296470d commit 7bc8f12

File tree

2 files changed

+217
-0
lines changed

2 files changed

+217
-0
lines changed

platform/broadcom/sonic-platform-modules-dell/z9264f/sonic_platform/chassis.py

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from sonic_platform.eeprom import Eeprom
1717
from sonic_platform.component import Component
1818
from sonic_platform.psu import Psu
19+
from sonic_platform.watchdog import Watchdog
1920
from sonic_platform.fan import Fan
2021
from sonic_platform.thermal import Thermal
2122
except ImportError as e:
@@ -61,6 +62,8 @@ def __init__(self):
6162
self._sfp_list.append(sfp_node)
6263

6364
self._eeprom = Eeprom()
65+
66+
self._watchdog = Watchdog()
6467

6568
for i in range(MAX_Z9264F_COMPONENT):
6669
component = Component(i)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
#!/usr/bin/env python
2+
3+
########################################################################
4+
#
5+
# DELLEMC Z9264f
6+
#
7+
# Abstract base class for implementing a platform-specific class with
8+
# which to interact with a hardware watchdog module in SONiC
9+
#
10+
########################################################################
11+
12+
try:
13+
import sys
14+
import struct
15+
import ctypes
16+
import subprocess
17+
from sonic_platform_base.watchdog_base import WatchdogBase
18+
except ImportError as e:
19+
raise ImportError(str(e) + "- required module not found")
20+
21+
22+
class _timespec(ctypes.Structure):
23+
_fields_ = [
24+
('tv_sec', ctypes.c_long),
25+
('tv_nsec', ctypes.c_long)
26+
]
27+
28+
29+
class Watchdog(WatchdogBase):
30+
"""
31+
Abstract base class for interfacing with a hardware watchdog module
32+
"""
33+
34+
TIMERS = [15,20,30,40,50,60,65,70]
35+
36+
armed_time = 0
37+
timeout = 0
38+
CLOCK_MONOTONIC = 1
39+
40+
def __init__(self):
41+
self._librt = ctypes.CDLL('librt.so.1', use_errno=True)
42+
self._clock_gettime = self._librt.clock_gettime
43+
self._clock_gettime.argtypes=[ctypes.c_int, ctypes.POINTER(_timespec)]
44+
45+
def _get_command_result(self, cmdline):
46+
try:
47+
proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE,
48+
stderr=subprocess.STDOUT)
49+
stdout = proc.communicate()[0]
50+
proc.wait()
51+
result = stdout.rstrip('\n')
52+
except OSError:
53+
result = None
54+
55+
return result
56+
57+
def _get_reg_val(self):
58+
# 0x31 = CPLD I2C Base Address
59+
# 0x07 = Watchdog Function Register
60+
value = self._get_command_result("/usr/sbin/i2cget -y 601 0x31 0x07")
61+
if not value:
62+
return None
63+
else:
64+
return int(value, 16)
65+
66+
def _set_reg_val(self,val):
67+
# 0x31 = CPLD I2C Base Address
68+
# 0x07 = Watchdog Function Register
69+
value = self._get_command_result("/usr/sbin/i2cset -y 601 0x31 0x07 %s"
70+
% (val))
71+
return value
72+
73+
def _get_time(self):
74+
"""
75+
To get clock monotonic time
76+
"""
77+
ts = _timespec()
78+
if self._clock_gettime(self.CLOCK_MONOTONIC, ctypes.pointer(ts)) != 0:
79+
self._errno = ctypes.get_errno()
80+
return 0
81+
return ts.tv_sec + ts.tv_nsec * 1e-9
82+
83+
def arm(self, seconds):
84+
"""
85+
Arm the hardware watchdog with a timeout of <seconds> seconds.
86+
If the watchdog is currently armed, calling this function will
87+
simply reset the timer to the provided value. If the underlying
88+
hardware does not support the value provided in <seconds>, this
89+
method should arm the watchdog with the *next greater*
90+
available value.
91+
92+
Returns:
93+
An integer specifying the *actual* number of seconds the
94+
watchdog was armed with. On failure returns -1.
95+
"""
96+
timer_offset = -1
97+
for key,timer_seconds in enumerate(self.TIMERS):
98+
if seconds <= timer_seconds:
99+
timer_offset = key
100+
seconds = timer_seconds
101+
break
102+
103+
if timer_offset == -1:
104+
return -1
105+
106+
# Extracting 5th to 7th bits for WD timer values
107+
# 000 - 15 sec
108+
# 001 - 20 sec
109+
# 010 - 30 sec
110+
# 011 - 40 sec
111+
# 100 - 50 sec
112+
# 101 - 60 sec
113+
# 110 - 65 sec
114+
# 111 - 70 sec
115+
reg_val = self._get_reg_val()
116+
wd_timer_offset = (reg_val >> 4) & 0x7
117+
118+
if wd_timer_offset != timer_offset:
119+
# Setting 5th to 7th bits
120+
# value from timer_offset
121+
self.disarm()
122+
self._set_reg_val((reg_val & 0x87) | (timer_offset << 4))
123+
124+
if self.is_armed():
125+
# Setting last bit to WD Timer punch
126+
# Last bit = WD Timer punch
127+
self._set_reg_val(reg_val & 0xFE)
128+
129+
self.armed_time = self._get_time()
130+
self.timeout = seconds
131+
return seconds
132+
else:
133+
# Setting 4th bit to enable WD
134+
# 4th bit = Enable WD
135+
reg_val = self._get_reg_val()
136+
self._set_reg_val(reg_val | 0x8)
137+
138+
self.armed_time = self._get_time()
139+
self.timeout = seconds
140+
return seconds
141+
142+
return -1
143+
144+
def disarm(self):
145+
"""
146+
Disarm the hardware watchdog
147+
148+
Returns:
149+
A boolean, True if watchdog is disarmed successfully, False
150+
if not
151+
"""
152+
if self.is_armed():
153+
# Setting 4th bit to disable WD
154+
# 4th bit = Disable WD
155+
reg_val = self._get_reg_val()
156+
self._set_reg_val(reg_val & 0xF7)
157+
158+
self.armed_time = 0
159+
self.timeout = 0
160+
return True
161+
162+
return False
163+
164+
def is_armed(self):
165+
"""
166+
Retrieves the armed state of the hardware watchdog.
167+
168+
Returns:
169+
A boolean, True if watchdog is armed, False if not
170+
"""
171+
172+
# Extracting 4th bit to get WD Enable/Disable status
173+
# 0 - Disabled WD
174+
# 1 - Enabled WD
175+
reg_val = self._get_reg_val()
176+
wd_offset = (reg_val >> 3) & 1
177+
178+
return bool(wd_offset)
179+
180+
def get_remaining_time(self):
181+
"""
182+
If the watchdog is armed, retrieve the number of seconds
183+
remaining on the watchdog timer
184+
185+
Returns:
186+
An integer specifying the number of seconds remaining on
187+
their watchdog timer. If the watchdog is not armed, returns
188+
-1.
189+
190+
Z9264 doesnot have hardware support to show remaining time.
191+
Due to this limitation, this API is implemented in software.
192+
This API would return correct software time difference if it
193+
is called from the process which armed the watchdog timer.
194+
If this API called from any other process, it would return
195+
0. If the watchdog is not armed, this API would return -1.
196+
"""
197+
if not self.is_armed():
198+
return -1
199+
200+
if self.armed_time > 0 and self.timeout != 0:
201+
cur_time = self._get_time()
202+
203+
if cur_time <= 0:
204+
return 0
205+
206+
diff_time = int(cur_time - self.armed_time)
207+
208+
if diff_time > self.timeout:
209+
return self.timeout
210+
else:
211+
return self.timeout - diff_time
212+
213+
return 0
214+

0 commit comments

Comments
 (0)