-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[device/celestica] Implement Watchdog APIs based on the new platform …
…API (#3123)
- Loading branch information
Showing
6 changed files
with
574 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
233 changes: 233 additions & 0 deletions
233
device/celestica/x86_64-cel_e1031-r0/sonic_platform/watchdog.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
#!/usr/bin/env python | ||
|
||
############################################################################# | ||
# Celestica | ||
# | ||
# Watchdog contains an implementation of SONiC Platform Base API | ||
# | ||
############################################################################# | ||
import ctypes | ||
import fcntl | ||
import os | ||
import subprocess | ||
import time | ||
import array | ||
|
||
try: | ||
from sonic_platform_base.watchdog_base import WatchdogBase | ||
except ImportError as e: | ||
raise ImportError(str(e) + "- required module not found") | ||
|
||
""" ioctl constants """ | ||
IO_WRITE = 0x40000000 | ||
IO_READ = 0x80000000 | ||
IO_READ_WRITE = 0xC0000000 | ||
IO_SIZE_INT = 0x00040000 | ||
IO_SIZE_40 = 0x00280000 | ||
IO_TYPE_WATCHDOG = ord('W') << 8 | ||
|
||
WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG | ||
WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG | ||
WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG | ||
|
||
""" Watchdog ioctl commands """ | ||
WDIOC_GETSUPPORT = 0 | WDR_40 | ||
WDIOC_GETSTATUS = 1 | WDR_INT | ||
WDIOC_GETBOOTSTATUS = 2 | WDR_INT | ||
WDIOC_GETTEMP = 3 | WDR_INT | ||
WDIOC_SETOPTIONS = 4 | WDR_INT | ||
WDIOC_KEEPALIVE = 5 | WDR_INT | ||
WDIOC_SETTIMEOUT = 6 | WDWR_INT | ||
WDIOC_GETTIMEOUT = 7 | WDR_INT | ||
WDIOC_SETPRETIMEOUT = 8 | WDWR_INT | ||
WDIOC_GETPRETIMEOUT = 9 | WDR_INT | ||
WDIOC_GETTIMELEFT = 10 | WDR_INT | ||
|
||
""" Watchdog status constants """ | ||
WDIOS_DISABLECARD = 0x0001 | ||
WDIOS_ENABLECARD = 0x0002 | ||
|
||
WDT_COMMON_ERROR = -1 | ||
WD_MAIN_IDENTITY = "iTCO_wdt" | ||
WDT_SYSFS_PATH = "/sys/class/watchdog/" | ||
|
||
|
||
class Watchdog(WatchdogBase): | ||
|
||
def __init__(self): | ||
|
||
self.watchdog, self.wdt_main_dev_name = self._get_wdt() | ||
self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name | ||
self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name | ||
self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name | ||
# Set default value | ||
self._disable() | ||
self.armed = False | ||
self.timeout = self._gettimeout(self.timeout_path) | ||
|
||
def _is_wd_main(self, dev): | ||
""" | ||
Checks watchdog identity | ||
""" | ||
identity = self._read_file( | ||
"{}/{}/identity".format(WDT_SYSFS_PATH, dev)) | ||
return identity == WD_MAIN_IDENTITY | ||
|
||
def _get_wdt(self): | ||
""" | ||
Retrieves watchdog device | ||
""" | ||
wdt_main_dev_list = [dev for dev in os.listdir( | ||
"/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)] | ||
if not wdt_main_dev_list: | ||
return None | ||
wdt_main_dev_name = wdt_main_dev_list[0] | ||
watchdog_device_path = "/dev/{}".format(wdt_main_dev_name) | ||
watchdog = os.open(watchdog_device_path, os.O_RDWR) | ||
return watchdog, wdt_main_dev_name | ||
|
||
def _read_file(self, file_path): | ||
""" | ||
Read text file | ||
""" | ||
try: | ||
with open(file_path, "r") as fd: | ||
txt = fd.read() | ||
except IOError: | ||
return WDT_COMMON_ERROR | ||
return txt.strip() | ||
|
||
def _enable(self): | ||
""" | ||
Turn on the watchdog timer | ||
""" | ||
req = array.array('h', [WDIOS_ENABLECARD]) | ||
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) | ||
|
||
def _disable(self): | ||
""" | ||
Turn off the watchdog timer | ||
""" | ||
req = array.array('h', [WDIOS_DISABLECARD]) | ||
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) | ||
|
||
def _keepalive(self): | ||
""" | ||
Keep alive watchdog timer | ||
""" | ||
fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE) | ||
|
||
def _settimeout(self, seconds): | ||
""" | ||
Set watchdog timer timeout | ||
@param seconds - timeout in seconds | ||
@return is the actual set timeout | ||
""" | ||
req = array.array('I', [seconds]) | ||
fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True) | ||
return int(req[0]) | ||
|
||
def _gettimeout(self, timeout_path): | ||
""" | ||
Get watchdog timeout | ||
@return watchdog timeout | ||
""" | ||
req = array.array('I', [0]) | ||
fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True) | ||
|
||
return int(req[0]) | ||
|
||
def _gettimeleft(self): | ||
""" | ||
Get time left before watchdog timer expires | ||
@return time left in seconds | ||
""" | ||
req = array.array('I', [0]) | ||
fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True) | ||
|
||
return int(req[0]) | ||
|
||
################################################################# | ||
|
||
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 | ||
|
||
try: | ||
if self.timeout != seconds: | ||
self.timeout = self._settimeout(seconds) | ||
if self.armed: | ||
self._keepalive() | ||
else: | ||
self._enable() | ||
self.armed = True | ||
ret = self.timeout | ||
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. | ||
""" | ||
|
||
timeleft = WDT_COMMON_ERROR | ||
|
||
if self.armed: | ||
try: | ||
timeleft = self._gettimeleft() | ||
except IOError: | ||
pass | ||
|
||
return timeleft | ||
|
||
def __del__(self): | ||
""" | ||
Close watchdog | ||
""" | ||
|
||
os.close(self.watchdog) |
Oops, something went wrong.