Skip to content

Commit 9ba350b

Browse files
santhosh-ktzhenggen-xu
authored andcommitted
[DellEMC] S6100 Watchdog Support (sonic-net#3698)
Implement Watchdog platform2.0 API for DellEMC S6100 platform. - Added new file watchdog.py in sonic_platform directory. - Enabled API support to Enable/disable watchdog.
1 parent 84eb0fe commit 9ba350b

File tree

1 file changed

+227
-0
lines changed
  • platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform

1 file changed

+227
-0
lines changed
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
#!/usr/bin/env python
2+
3+
########################################################################
4+
#
5+
# DELLEMC S6100
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 os
14+
import struct
15+
import ctypes
16+
from sonic_platform_base.watchdog_base import WatchdogBase
17+
except ImportError as e:
18+
raise ImportError(str(e) + "- required module not found")
19+
20+
21+
class _timespec(ctypes.Structure):
22+
_fields_ = [
23+
('tv_sec', ctypes.c_long),
24+
('tv_nsec', ctypes.c_long)
25+
]
26+
27+
class Watchdog(WatchdogBase):
28+
"""
29+
Abstract base class for interfacing with a hardware watchdog module
30+
"""
31+
32+
io_resource = '/dev/port'
33+
34+
WD_STATUS_OFFSET = 0x207
35+
WD_TIMER_OFFSET = 0x206
36+
WD_ENABLE = 0
37+
WD_DISABLE = 1
38+
39+
armed_time = 0
40+
timeout = 0
41+
CLOCK_MONOTONIC = 1
42+
43+
def __init__(self):
44+
self._librt = ctypes.CDLL('librt.so.1', use_errno=True)
45+
self._clock_gettime = self._librt.clock_gettime
46+
self._clock_gettime.argtypes=[ctypes.c_int, ctypes.POINTER(_timespec)]
47+
48+
def _io_reg_read(self, offset):
49+
"""
50+
Read the resource file
51+
"""
52+
fd = os.open(self.io_resource, os.O_RDONLY)
53+
if fd < 0:
54+
return -1
55+
56+
if os.lseek(fd, offset, os.SEEK_SET) != offset:
57+
os.close(fd)
58+
return -1
59+
60+
buf = os.read(fd, 1)
61+
reg_value = ord(buf)
62+
63+
os.close(fd)
64+
return reg_value
65+
66+
def _io_reg_write(self, offset, val):
67+
"""
68+
Write in the resource file
69+
"""
70+
fd = os.open(self.io_resource, os.O_RDWR)
71+
if fd < 0:
72+
return -1
73+
74+
if os.lseek(fd, offset, os.SEEK_SET) != offset:
75+
os.close(fd)
76+
return -1
77+
78+
ret = os.write(fd, struct.pack('B', val))
79+
if ret != 1:
80+
os.close(fd)
81+
return -1
82+
83+
os.close(fd)
84+
return ret
85+
86+
def _read_gpio_file(self, file_path):
87+
"""
88+
Read the GPIO values
89+
"""
90+
fd = os.open(file_path, os.O_RDONLY)
91+
read_str = os.read(fd, os.path.getsize(file_path))
92+
gpio_val = int(read_str, 16)
93+
os.close(fd)
94+
return gpio_val
95+
96+
def _write_gpio_file(self, file_path, val):
97+
"""
98+
Write the GPIO values
99+
"""
100+
fd = os.open(file_path, os.O_RDWR)
101+
ret = os.write(fd, val)
102+
if ret < 0:
103+
os.close(fd)
104+
return -1
105+
106+
os.close(fd)
107+
return 1
108+
109+
def _get_time(self):
110+
"""
111+
To get clock monotonic time
112+
"""
113+
ts = _timespec()
114+
if self._clock_gettime(self.CLOCK_MONOTONIC, ctypes.pointer(ts)) != 0:
115+
errno_ = ctypes.get_errno()
116+
return 0
117+
return ts.tv_sec + ts.tv_nsec * 1e-9
118+
119+
def arm(self, seconds):
120+
"""
121+
Arm the hardware watchdog with a timeout of <seconds> seconds.
122+
If the watchdog is currently armed, calling this function will
123+
simply reset the timer to the provided value. If the underlying
124+
hardware does not support the value provided in <seconds>, this
125+
method should arm the watchdog with the *next greater*
126+
available value.
127+
128+
Returns:
129+
An integer specifying the *actual* number of seconds the
130+
watchdog was armed with. On failure returns -1.
131+
"""
132+
gpio = "/sys/devices/platform/dell_ich.0/sc_gp_lvl"
133+
timer_offset = -1
134+
if seconds <= 30:
135+
timer_offset = 1
136+
seconds = 30
137+
elif seconds > 30 and seconds <= 60:
138+
timer_offset = 2
139+
seconds = 60
140+
elif seconds > 60 and seconds <= 180:
141+
timer_offset = 3
142+
seconds = 180
143+
144+
if timer_offset == -1:
145+
return -1
146+
if self._io_reg_read(self.WD_TIMER_OFFSET) != timer_offset:
147+
if self._io_reg_write(self.WD_TIMER_OFFSET, timer_offset) == -1:
148+
return -1
149+
self.disarm()
150+
151+
if self.is_armed():
152+
gpio_val = self._read_gpio_file(gpio)
153+
high_val = gpio_val | (1 << 15)
154+
if self._write_gpio_file(gpio, hex(high_val)) != -1:
155+
low_val = high_val & 0xFFFF7FFF
156+
if self._write_gpio_file(gpio, hex(low_val)) != -1:
157+
self.armed_time = self._get_time()
158+
self.timeout = seconds
159+
return seconds
160+
elif self._io_reg_write(self.WD_STATUS_OFFSET, self.WD_ENABLE) != -1:
161+
self.armed_time = self._get_time()
162+
self.timeout = seconds
163+
return seconds
164+
165+
return -1
166+
167+
def disarm(self):
168+
"""
169+
Disarm the hardware watchdog
170+
171+
Returns:
172+
A boolean, True if watchdog is disarmed successfully, False
173+
if not
174+
"""
175+
if self._io_reg_write(self.WD_STATUS_OFFSET, self.WD_DISABLE) != -1:
176+
self.armed_time = 0
177+
self.timeout = 0
178+
return True
179+
180+
return False
181+
182+
def is_armed(self):
183+
"""
184+
Retrieves the armed state of the hardware watchdog.
185+
186+
Returns:
187+
A boolean, True if watchdog is armed, False if not
188+
"""
189+
wd_status = self.WD_DISABLE
190+
wd_status = self._io_reg_read(self.WD_STATUS_OFFSET)
191+
if wd_status == self.WD_ENABLE:
192+
return True
193+
194+
return False
195+
196+
def get_remaining_time(self):
197+
"""
198+
If the watchdog is armed, retrieve the number of seconds
199+
remaining on the watchdog timer
200+
201+
Returns:
202+
An integer specifying the number of seconds remaining on
203+
their watchdog timer. If the watchdog is not armed, returns
204+
-1.
205+
206+
S6100 doesnot have hardware support to show remaining time.
207+
Due to this limitation, this API is implemented in software.
208+
This API would return correct software time difference if it
209+
is called from the process which armed the watchdog timer.
210+
If this API called from any other process, it would return
211+
0. If the watchdog is not armed, this API would return -1.
212+
"""
213+
if not self.is_armed():
214+
return -1
215+
216+
if self.armed_time > 0 and self.timeout != 0:
217+
cur_time = self._get_time()
218+
if cur_time <= 0:
219+
return 0
220+
diff_time = int(cur_time - self.armed_time)
221+
if diff_time > self.timeout:
222+
return self.timeout
223+
else:
224+
return self.timeout - diff_time
225+
226+
return 0
227+

0 commit comments

Comments
 (0)