2019-07-08 13:26:27 -05:00
|
|
|
#############################################################################
|
|
|
|
# Celestica
|
|
|
|
#
|
|
|
|
# Watchdog contains an implementation of SONiC Platform Base API
|
|
|
|
#
|
|
|
|
#############################################################################
|
|
|
|
|
|
|
|
try:
|
2021-07-23 08:18:39 -05:00
|
|
|
import os
|
|
|
|
import time
|
2019-07-08 13:26:27 -05:00
|
|
|
from sonic_platform_base.watchdog_base import WatchdogBase
|
2021-07-23 08:18:39 -05:00
|
|
|
from .common import Common
|
2019-07-08 13:26:27 -05:00
|
|
|
except ImportError as e:
|
|
|
|
raise ImportError(str(e) + "- required module not found")
|
|
|
|
|
|
|
|
|
2021-07-23 08:18:39 -05:00
|
|
|
PLATFORM_CPLD_PATH = '/sys/devices/platform/e1031.smc/'
|
|
|
|
SETREG_FILE = 'setreg'
|
|
|
|
GETREG_FILE = 'getreg'
|
2019-07-08 13:26:27 -05:00
|
|
|
WDT_COMMON_ERROR = -1
|
2021-07-23 08:18:39 -05:00
|
|
|
MMC_VERSION_REG = "0x100"
|
|
|
|
|
|
|
|
# watchdog infomation for cpld v06
|
|
|
|
V06_MMC_VERSION = 0x05
|
|
|
|
V06_WDT_WIDTH = '0x110'
|
|
|
|
V06_WDT_WIDTH_SELECTOR = {
|
|
|
|
30: '0x1',
|
|
|
|
60: '0x2',
|
|
|
|
180: '0x3'
|
|
|
|
}
|
|
|
|
|
|
|
|
V06_CPLD_WDT_INFO = {
|
|
|
|
'wdt_en_reg': '0x111',
|
|
|
|
'wdt_en_cmd': '0x0',
|
|
|
|
'wdt_dis_cmd': '0x1'
|
|
|
|
}
|
|
|
|
|
|
|
|
# watchdog infomation
|
|
|
|
WDT_TIMER_L_BIT_REG = '0x117'
|
|
|
|
WDT_TIMER_M_BIT_REG = '0x118'
|
|
|
|
WDT_TIMER_H_BIT_REG = '0x119'
|
|
|
|
WDT_KEEP_ALVIVE_REG = '0x11a'
|
|
|
|
|
|
|
|
CPLD_WDT_INFO = {
|
|
|
|
'wdt_en_reg': '0x116',
|
|
|
|
'wdt_en_cmd': '0x1',
|
|
|
|
'wdt_dis_cmd': '0x0'
|
|
|
|
}
|
2019-07-08 13:26:27 -05:00
|
|
|
|
|
|
|
|
|
|
|
class Watchdog(WatchdogBase):
|
|
|
|
|
|
|
|
def __init__(self):
|
2021-07-23 08:18:39 -05:00
|
|
|
# Init api_common
|
|
|
|
self._api_common = Common()
|
|
|
|
|
|
|
|
# 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)
|
|
|
|
|
|
|
|
self.mmc_v = self._get_mmc_version()
|
|
|
|
self.cpld_info = V06_CPLD_WDT_INFO if self.mmc_v <= V06_MMC_VERSION else CPLD_WDT_INFO
|
2019-07-08 13:26:27 -05:00
|
|
|
|
|
|
|
# Set default value
|
|
|
|
self._disable()
|
|
|
|
self.armed = False
|
2021-07-23 08:18:39 -05:00
|
|
|
self.timeout = 0
|
2019-07-08 13:26:27 -05:00
|
|
|
|
2021-07-23 08:18:39 -05:00
|
|
|
def _get_mmc_version(self):
|
|
|
|
hex_str_v = self._api_common.get_reg(self.getreg_path, MMC_VERSION_REG)
|
|
|
|
return int(hex_str_v, 16)
|
2019-07-08 13:26:27 -05:00
|
|
|
|
2021-07-23 08:18:39 -05:00
|
|
|
def _get_level_hex(self, sub_hex):
|
|
|
|
sub_hex_str = sub_hex.replace("x", "0")
|
|
|
|
return hex(int(sub_hex_str, 16))
|
2019-07-08 13:26:27 -05:00
|
|
|
|
2021-07-23 08:18:39 -05:00
|
|
|
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)
|
2019-07-08 13:26:27 -05:00
|
|
|
|
|
|
|
def _enable(self):
|
|
|
|
"""
|
|
|
|
Turn on the watchdog timer
|
|
|
|
"""
|
2021-07-23 08:18:39 -05:00
|
|
|
return self._api_common.set_reg(self.setreg_path, self.cpld_info['wdt_en_reg'], self.cpld_info['wdt_en_cmd'])
|
2019-07-08 13:26:27 -05:00
|
|
|
|
|
|
|
def _disable(self):
|
|
|
|
"""
|
|
|
|
Turn off the watchdog timer
|
|
|
|
"""
|
2021-07-23 08:18:39 -05:00
|
|
|
return self._api_common.set_reg(self.setreg_path, self.cpld_info['wdt_en_reg'], self.cpld_info['wdt_dis_cmd'])
|
2019-07-08 13:26:27 -05:00
|
|
|
|
|
|
|
def _keepalive(self):
|
|
|
|
"""
|
|
|
|
Keep alive watchdog timer
|
|
|
|
"""
|
2021-07-23 08:18:39 -05:00
|
|
|
if self.mmc_v <= V06_MMC_VERSION:
|
|
|
|
self._disable()
|
|
|
|
self._enable()
|
|
|
|
|
|
|
|
else:
|
|
|
|
self._api_common.set_reg(
|
|
|
|
self.setreg_path, WDT_KEEP_ALVIVE_REG, self.cpld_info['wdt_en_cmd'])
|
2019-07-08 13:26:27 -05:00
|
|
|
|
|
|
|
def _settimeout(self, seconds):
|
|
|
|
"""
|
|
|
|
Set watchdog timer timeout
|
|
|
|
@param seconds - timeout in seconds
|
|
|
|
@return is the actual set timeout
|
|
|
|
"""
|
|
|
|
|
2021-07-23 08:18:39 -05:00
|
|
|
if self.mmc_v <= V06_MMC_VERSION:
|
|
|
|
timeout_hex = V06_WDT_WIDTH_SELECTOR.get(seconds, '0x2')
|
|
|
|
seconds = 60 if timeout_hex == '0x2' else seconds
|
|
|
|
self._api_common.set_reg(
|
|
|
|
self.setreg_path, V06_WDT_WIDTH, timeout_hex)
|
2019-07-08 13:26:27 -05:00
|
|
|
|
2021-07-23 08:18:39 -05:00
|
|
|
else:
|
|
|
|
(l, m, h) = self._seconds_to_lmh_hex(seconds)
|
|
|
|
self._api_common.set_reg(
|
|
|
|
self.setreg_path, WDT_TIMER_H_BIT_REG, h) # set high bit
|
|
|
|
self._api_common.set_reg(
|
|
|
|
self.setreg_path, WDT_TIMER_M_BIT_REG, m) # set med bit
|
|
|
|
self._api_common.set_reg(
|
|
|
|
self.setreg_path, WDT_TIMER_L_BIT_REG, l) # set low bit
|
2019-07-08 13:26:27 -05:00
|
|
|
|
2021-07-23 08:18:39 -05:00
|
|
|
return seconds
|
2019-07-08 13:26:27 -05:00
|
|
|
|
|
|
|
#################################################################
|
|
|
|
|
|
|
|
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
|
2021-07-23 08:18:39 -05:00
|
|
|
|
|
|
|
if seconds < 0 or seconds > 180:
|
2019-07-08 13:26:27 -05:00
|
|
|
return ret
|
|
|
|
|
|
|
|
try:
|
|
|
|
if self.timeout != seconds:
|
|
|
|
self.timeout = self._settimeout(seconds)
|
2021-07-23 08:18:39 -05:00
|
|
|
|
2019-07-08 13:26:27 -05:00
|
|
|
if self.armed:
|
|
|
|
self._keepalive()
|
|
|
|
else:
|
|
|
|
self._enable()
|
|
|
|
self.armed = True
|
2021-07-23 08:18:39 -05:00
|
|
|
|
2019-07-08 13:26:27 -05:00
|
|
|
ret = self.timeout
|
2021-07-23 08:18:39 -05:00
|
|
|
self.arm_timestamp = time.time()
|
2019-07-08 13:26:27 -05:00
|
|
|
except IOError as e:
|
2021-07-23 08:18:39 -05:00
|
|
|
print("Error: unable to enable wdt due to : {}".format(e))
|
2019-07-08 13:26:27 -05:00
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def disarm(self):
|
|
|
|
"""
|
|
|
|
Disarm the hardware watchdog
|
|
|
|
Returns:
|
|
|
|
A boolean, True if watchdog is disarmed successfully, False if not
|
|
|
|
"""
|
|
|
|
disarmed = False
|
2021-07-23 08:18:39 -05:00
|
|
|
try:
|
|
|
|
self._disable()
|
|
|
|
self.armed = False
|
|
|
|
disarmed = True
|
|
|
|
except IOError as e:
|
|
|
|
print("Error: unable to disable wdt due to : {}".format(e))
|
2019-07-08 13:26:27 -05:00
|
|
|
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.
|
|
|
|
"""
|
|
|
|
|
|
|
|
timeleft = WDT_COMMON_ERROR
|
|
|
|
|
|
|
|
if self.armed:
|
2021-07-23 08:18:39 -05:00
|
|
|
timeleft = int(self.timeout - (time.time() - self.arm_timestamp))
|
2019-07-08 13:26:27 -05:00
|
|
|
|
|
|
|
return timeleft
|