DellEMC: N3248TE/N3248PXE Watchdog Support (#9398)

Why I did it
DellEMC : Added support for N3248TE/N3248PXE platforms

How I did it
Implemented the changes to enable/disable the watchdog support

How to verify it
watchdog_unit_test.txt

Co-authored-by: Arun LK <Arun_L_K@dell.com>
This commit is contained in:
arunlk-dell 2022-04-01 20:03:08 +05:30 committed by GitHub
parent 0f488a8cb6
commit 94ec85464b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 154 additions and 85 deletions

View File

@ -853,6 +853,41 @@ static ssize_t fan_led_store(struct device *dev, struct device_attribute *devatt
return count;
}
static ssize_t watchdog_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
s32 ret;
u8 data = 0;
struct cpld_platform_data *pdata = dev->platform_data;
ret = i2c_smbus_read_byte_data(pdata[cpu_cpld].client, 0x7);
if (ret < 0)
return sprintf(buf, "read error");
data = ret;
return sprintf(buf, "%x\n", data);
}
static ssize_t watchdog_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count)
{
s32 ret, err;
unsigned long val;
u8 data = 0;
struct cpld_platform_data *pdata = dev->platform_data;
err = kstrtoul(buf, 10, &val);
if (err)
return err;
if (data)
{
ret = i2c_smbus_write_byte_data(pdata[cpu_cpld].client, 0x7, data);
if (ret < 0)
return ret;
}
return count;
}
static ssize_t power_good_show(struct device *dev,
struct device_attribute *devattr, char *buf)
@ -947,6 +982,7 @@ static DEVICE_ATTR_RO(psu1_prs);
static DEVICE_ATTR_RO(psu0_status);
static DEVICE_ATTR_RO(psu1_status);
static DEVICE_ATTR_RW(system_led);
static DEVICE_ATTR_RW(watchdog);
static DEVICE_ATTR_RW(locator_led);
static DEVICE_ATTR_RW(power_led);
static DEVICE_ATTR_RW(master_led);
@ -988,6 +1024,7 @@ static struct attribute *n3248pxe_cpld_attrs[] = {
&dev_attr_psu0_status.attr,
&dev_attr_psu1_status.attr,
&dev_attr_system_led.attr,
&dev_attr_watchdog.attr,
&dev_attr_locator_led.attr,
&dev_attr_power_led.attr,
&dev_attr_master_led.attr,

View File

@ -11,7 +11,6 @@
try:
import ctypes
import subprocess
from sonic_platform_base.watchdog_base import WatchdogBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
@ -29,43 +28,53 @@ class Watchdog(WatchdogBase):
Abstract base class for interfacing with a hardware watchdog module
"""
TIMERS = [15,20,30,40,50,60,65,70]
TIMERS = [15,20,30,40,50,60,65,70,80,100,120,140,160,180,210,240]
armed_time = 0
timeout = 0
CLOCK_MONOTONIC = 1
def __init__(self):
WatchdogBase.__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)]
self.watchdog_reg = "watchdog"
def _get_command_result(self, cmdline):
def _get_cpld_register(self, reg_name):
# On successful read, returns the value read from given
# reg name and on failure rethrns 'ERR'
cpld_dir = "/sys/devices/platform/dell-n3248pxe-cpld.0/"
cpld_reg_file = cpld_dir + '/' + reg_name
try:
proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
result = stdout.rstrip('\n')
except OSError:
result = None
with open(cpld_reg_file, 'r') as fd:
rv = fd.read()
except IOError : return 'ERR'
return rv.strip('\r\n').lstrip(' ')
return result
def _set_cpld_register(self, reg_name, value):
# On successful write, returns the value will be written on
# reg_name and on failure returns 'ERR'
cpld_dir = "/sys/devices/platform/dell-n3248pxe-cpld.0/"
cpld_reg_file = cpld_dir + '/' + reg_name
try:
with open(cpld_reg_file, 'w') as fd:
rv = fd.write(str(value))
except Exception:
rv = 'ERR'
return rv
def _get_reg_val(self):
# 0x31 = CPLD I2C Base Address
# 0x07 = Watchdog Function Register
value = self._get_command_result("/usr/sbin/i2cget -y 601 0x31 0x07")
if not value:
return None
else:
return int(value, 16)
value = self._get_cpld_register(self.watchdog_reg).strip()
if value == 'ERR': return False
return int(value,16)
def _set_reg_val(self,val):
# 0x31 = CPLD I2C Base Address
# 0x07 = Watchdog Function Register
value = self._get_command_result("/usr/sbin/i2cset -y 601 0x31 0x07 %s"
% (val))
value = self._set_cpld_register(self.watchdog_reg, val)
return value
def _get_time(self):
@ -93,7 +102,7 @@ class Watchdog(WatchdogBase):
"""
timer_offset = -1
for key,timer_seconds in enumerate(self.TIMERS):
if seconds <= timer_seconds:
if seconds > 0 and seconds <= timer_seconds:
timer_offset = key
seconds = timer_seconds
break
@ -101,40 +110,29 @@ class Watchdog(WatchdogBase):
if timer_offset == -1:
return -1
# Extracting 5th to 7th bits for WD timer values
# 000 - 15 sec
# 001 - 20 sec
# 010 - 30 sec
# 011 - 40 sec
# 100 - 50 sec
# 101 - 60 sec
# 110 - 65 sec
# 111 - 70 sec
# Extracting 5th to 8th bits for WD timer values
reg_val = self._get_reg_val()
wd_timer_offset = (reg_val >> 4) & 0x7
wd_timer_offset = (reg_val >> 4) & 0xF
if wd_timer_offset != timer_offset:
# Setting 5th to 7th bits
# Setting 5th to 8th bits
# value from timer_offset
self.disarm()
self._set_reg_val(reg_val | (timer_offset << 4))
self._set_reg_val((reg_val & 0x0F) | (timer_offset << 4))
if self.is_armed():
# Setting last bit to WD Timer punch
# Last bit = WD Timer punch
self._set_reg_val(reg_val & 0xFE)
self.armed_time = self._get_time()
self.timeout = seconds
else:
# Setting 4th bit to enable WD
# 4th bit = Enable WD
reg_val = self._get_reg_val()
self._set_reg_val(reg_val | 0x8)
self.armed_time = self._get_time()
self.timeout = seconds
self.armed_time = self._get_time()
self.timeout = seconds
return seconds
def disarm(self):
@ -207,4 +205,3 @@ class Watchdog(WatchdogBase):
return self.timeout - diff_time
return 0

View File

@ -572,7 +572,7 @@ static ssize_t system_led_show(struct device *dev, struct device_attribute *deva
if (ret < 0)
return sprintf(buf, "read error");
data = (u8)(ret & 0x30) >> 5;
data = (u8)(ret & 0x30) >> 4;
switch (data)
{
@ -878,6 +878,42 @@ static ssize_t fan_led_store(struct device *dev, struct device_attribute *devatt
return count;
}
static ssize_t watchdog_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
s32 ret;
u8 data = 0;
struct cpld_platform_data *pdata = dev->platform_data;
ret = i2c_smbus_read_byte_data(pdata[cpu_cpld].client, 0x7);
if (ret < 0)
return sprintf(buf, "read error");
data = ret;
return sprintf(buf, "%x\n", data);
}
static ssize_t watchdog_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count)
{
s32 ret, err;
unsigned long val;
u8 data = 0;
struct cpld_platform_data *pdata = dev->platform_data;
err = kstrtoul(buf, 10, &val);
if (err)
return err;
data = (u8) val;
if (data)
{
ret = i2c_smbus_write_byte_data(pdata[cpu_cpld].client, 0x7, data);
if (ret < 0)
return ret;
}
return count;
}
static ssize_t power_good_show(struct device *dev,
struct device_attribute *devattr, char *buf)
@ -974,6 +1010,7 @@ static DEVICE_ATTR_RO(psu1_prs);
static DEVICE_ATTR_RO(psu0_status);
static DEVICE_ATTR_RO(psu1_status);
static DEVICE_ATTR_RW(system_led);
static DEVICE_ATTR_RW(watchdog);
static DEVICE_ATTR_RW(locator_led);
static DEVICE_ATTR_RW(power_led);
static DEVICE_ATTR_RW(master_led);
@ -1017,6 +1054,7 @@ static struct attribute *n3248te_cpld_attrs[] = {
&dev_attr_psu0_status.attr,
&dev_attr_psu1_status.attr,
&dev_attr_system_led.attr,
&dev_attr_watchdog.attr,
&dev_attr_locator_led.attr,
&dev_attr_power_led.attr,
&dev_attr_master_led.attr,

View File

@ -11,7 +11,6 @@
try:
import ctypes
import subprocess
from sonic_platform_base.watchdog_base import WatchdogBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
@ -29,43 +28,53 @@ class Watchdog(WatchdogBase):
Abstract base class for interfacing with a hardware watchdog module
"""
TIMERS = [15,20,30,40,50,60,65,70]
TIMERS = [15,20,30,40,50,60,65,70,80,100,120,140,160,180,210,240]
armed_time = 0
timeout = 0
CLOCK_MONOTONIC = 1
def __init__(self):
WatchdogBase.__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)]
self.watchdog_reg = "watchdog"
def _get_command_result(self, cmdline):
def _get_cpld_register(self, reg_name):
# On successful read, returns the value read from given
# reg name and on failure rethrns 'ERR'
cpld_dir = "/sys/devices/platform/dell-n3248te-cpld.0/"
cpld_reg_file = cpld_dir + '/' + reg_name
try:
proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
result = stdout.rstrip('\n')
except OSError:
result = None
with open(cpld_reg_file, 'r') as fd:
rv = fd.read()
except IOError : return 'ERR'
return rv.strip('\r\n').lstrip(' ')
return result
def _set_cpld_register(self, reg_name, value):
# On successful write, returns the value will be written on
# reg_name and on failure returns 'ERR'
cpld_dir = "/sys/devices/platform/dell-n3248te-cpld.0/"
cpld_reg_file = cpld_dir + '/' + reg_name
try:
with open(cpld_reg_file, 'w') as fd:
rv = fd.write(str(value))
except Exception:
rv = 'ERR'
return rv
def _get_reg_val(self):
# 0x31 = CPLD I2C Base Address
# 0x07 = Watchdog Function Register
value = self._get_command_result("/usr/sbin/i2cget -y 601 0x31 0x07")
if not value:
return None
else:
return int(value, 16)
value = self._get_cpld_register(self.watchdog_reg).strip()
if value == 'ERR': return False
return int(value,16)
def _set_reg_val(self,val):
# 0x31 = CPLD I2C Base Address
# 0x07 = Watchdog Function Register
value = self._get_command_result("/usr/sbin/i2cset -y 601 0x31 0x07 %s"
% (val))
value = self._set_cpld_register(self.watchdog_reg, val)
return value
def _get_time(self):
@ -93,7 +102,7 @@ class Watchdog(WatchdogBase):
"""
timer_offset = -1
for key,timer_seconds in enumerate(self.TIMERS):
if seconds <= timer_seconds:
if seconds > 0 and seconds <= timer_seconds:
timer_offset = key
seconds = timer_seconds
break
@ -101,41 +110,30 @@ class Watchdog(WatchdogBase):
if timer_offset == -1:
return -1
# Extracting 5th to 7th bits for WD timer values
# 000 - 15 sec
# 001 - 20 sec
# 010 - 30 sec
# 011 - 40 sec
# 100 - 50 sec
# 101 - 60 sec
# 110 - 65 sec
# 111 - 70 sec
# Extracting 5th to 8th bits for WD timer values
reg_val = self._get_reg_val()
wd_timer_offset = (reg_val >> 4) & 0x7
wd_timer_offset = (reg_val >> 4) & 0xF
if wd_timer_offset != timer_offset:
# Setting 5th to 7th bits
# Setting 5th to 8th bits
# value from timer_offset
self.disarm()
self._set_reg_val(reg_val | (timer_offset << 4))
self._set_reg_val((reg_val & 0x0F) | (timer_offset << 4))
if self.is_armed():
# Setting last bit to WD Timer punch
# Last bit = WD Timer punch
self._set_reg_val(reg_val & 0xFE)
self.armed_time = self._get_time()
self.timeout = seconds
return seconds
else:
# Setting 4th bit to enable WD
# 4th bit = Enable WD
reg_val = self._get_reg_val()
self._set_reg_val(reg_val | 0x8)
self.armed_time = self._get_time()
self.timeout = seconds
return seconds
self.armed_time = self._get_time()
self.timeout = seconds
return seconds
def disarm(self):
"""
@ -183,7 +181,7 @@ class Watchdog(WatchdogBase):
their watchdog timer. If the watchdog is not armed, returns
-1.
S5232 doesnot have hardware support to show remaining time.
N3248PXE 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.
@ -207,4 +205,3 @@ class Watchdog(WatchdogBase):
return self.timeout - diff_time
return 0