[DellEMC] S6100 Watchdog Support (#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.
This commit is contained in:
Santhosh Kumar T 2019-11-08 02:57:02 +05:30 committed by lguohan
parent 6a76cd2bb6
commit a5e2799b33

View File

@ -0,0 +1,227 @@
#!/usr/bin/env python
########################################################################
#
# DELLEMC S6100
#
# Abstract base class for implementing a platform-specific class with
# which to interact with a hardware watchdog module in SONiC
#
########################################################################
try:
import os
import struct
import ctypes
from sonic_platform_base.watchdog_base import WatchdogBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class _timespec(ctypes.Structure):
_fields_ = [
('tv_sec', ctypes.c_long),
('tv_nsec', ctypes.c_long)
]
class Watchdog(WatchdogBase):
"""
Abstract base class for interfacing with a hardware watchdog module
"""
io_resource = '/dev/port'
WD_STATUS_OFFSET = 0x207
WD_TIMER_OFFSET = 0x206
WD_ENABLE = 0
WD_DISABLE = 1
armed_time = 0
timeout = 0
CLOCK_MONOTONIC = 1
def __init__(self):
self._librt = ctypes.CDLL('librt.so.1', use_errno=True)
self._clock_gettime = self._librt.clock_gettime
self._clock_gettime.argtypes=[ctypes.c_int, ctypes.POINTER(_timespec)]
def _io_reg_read(self, offset):
"""
Read the resource file
"""
fd = os.open(self.io_resource, os.O_RDONLY)
if fd < 0:
return -1
if os.lseek(fd, offset, os.SEEK_SET) != offset:
os.close(fd)
return -1
buf = os.read(fd, 1)
reg_value = ord(buf)
os.close(fd)
return reg_value
def _io_reg_write(self, offset, val):
"""
Write in the resource file
"""
fd = os.open(self.io_resource, os.O_RDWR)
if fd < 0:
return -1
if os.lseek(fd, offset, os.SEEK_SET) != offset:
os.close(fd)
return -1
ret = os.write(fd, struct.pack('B', val))
if ret != 1:
os.close(fd)
return -1
os.close(fd)
return ret
def _read_gpio_file(self, file_path):
"""
Read the GPIO values
"""
fd = os.open(file_path, os.O_RDONLY)
read_str = os.read(fd, os.path.getsize(file_path))
gpio_val = int(read_str, 16)
os.close(fd)
return gpio_val
def _write_gpio_file(self, file_path, val):
"""
Write the GPIO values
"""
fd = os.open(file_path, os.O_RDWR)
ret = os.write(fd, val)
if ret < 0:
os.close(fd)
return -1
os.close(fd)
return 1
def _get_time(self):
"""
To get clock monotonic time
"""
ts = _timespec()
if self._clock_gettime(self.CLOCK_MONOTONIC, ctypes.pointer(ts)) != 0:
errno_ = ctypes.get_errno()
return 0
return ts.tv_sec + ts.tv_nsec * 1e-9
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.
"""
gpio = "/sys/devices/platform/dell_ich.0/sc_gp_lvl"
timer_offset = -1
if seconds <= 30:
timer_offset = 1
seconds = 30
elif seconds > 30 and seconds <= 60:
timer_offset = 2
seconds = 60
elif seconds > 60 and seconds <= 180:
timer_offset = 3
seconds = 180
if timer_offset == -1:
return -1
if self._io_reg_read(self.WD_TIMER_OFFSET) != timer_offset:
if self._io_reg_write(self.WD_TIMER_OFFSET, timer_offset) == -1:
return -1
self.disarm()
if self.is_armed():
gpio_val = self._read_gpio_file(gpio)
high_val = gpio_val | (1 << 15)
if self._write_gpio_file(gpio, hex(high_val)) != -1:
low_val = high_val & 0xFFFF7FFF
if self._write_gpio_file(gpio, hex(low_val)) != -1:
self.armed_time = self._get_time()
self.timeout = seconds
return seconds
elif self._io_reg_write(self.WD_STATUS_OFFSET, self.WD_ENABLE) != -1:
self.armed_time = self._get_time()
self.timeout = seconds
return seconds
return -1
def disarm(self):
"""
Disarm the hardware watchdog
Returns:
A boolean, True if watchdog is disarmed successfully, False
if not
"""
if self._io_reg_write(self.WD_STATUS_OFFSET, self.WD_DISABLE) != -1:
self.armed_time = 0
self.timeout = 0
return True
return False
def is_armed(self):
"""
Retrieves the armed state of the hardware watchdog.
Returns:
A boolean, True if watchdog is armed, False if not
"""
wd_status = self.WD_DISABLE
wd_status = self._io_reg_read(self.WD_STATUS_OFFSET)
if wd_status == self.WD_ENABLE:
return True
return False
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
their watchdog timer. If the watchdog is not armed, returns
-1.
S6100 doesnot have hardware support to show remaining time.
Due to this limitation, this API is implemented in software.
This API would return correct software time difference if it
is called from the process which armed the watchdog timer.
If this API called from any other process, it would return
0. If the watchdog is not armed, this API would return -1.
"""
if not self.is_armed():
return -1
if self.armed_time > 0 and self.timeout != 0:
cur_time = self._get_time()
if cur_time <= 0:
return 0
diff_time = int(cur_time - self.armed_time)
if diff_time > self.timeout:
return self.timeout
else:
return self.timeout - diff_time
return 0