From 94ec85464b00162c5ac45d6c335a12e543c6ea08 Mon Sep 17 00:00:00 2001 From: arunlk-dell <83708154+arunlk-dell@users.noreply.github.com> Date: Fri, 1 Apr 2022 20:03:08 +0530 Subject: [PATCH] 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 --- .../n3248pxe/modules/dell_n3248pxe_platform.c | 37 +++++++++ .../n3248pxe/sonic_platform/watchdog.py | 79 +++++++++--------- .../n3248te/modules/dell_n3248te_platform.c | 40 ++++++++- .../n3248te/sonic_platform/watchdog.py | 83 +++++++++---------- 4 files changed, 154 insertions(+), 85 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/dell_n3248pxe_platform.c b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/dell_n3248pxe_platform.c index 1c5d07bffa..5fb106f186 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/dell_n3248pxe_platform.c +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/modules/dell_n3248pxe_platform.c @@ -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, diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/watchdog.py index 876aa4beda..00277c2872 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/watchdog.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248pxe/sonic_platform/watchdog.py @@ -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 - diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248te/modules/dell_n3248te_platform.c b/platform/broadcom/sonic-platform-modules-dell/n3248te/modules/dell_n3248te_platform.c index f7a13c2a73..92ee30af31 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248te/modules/dell_n3248te_platform.c +++ b/platform/broadcom/sonic-platform-modules-dell/n3248te/modules/dell_n3248te_platform.c @@ -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, diff --git a/platform/broadcom/sonic-platform-modules-dell/n3248te/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-dell/n3248te/sonic_platform/watchdog.py index ebd4706b42..1e077e45d1 100644 --- a/platform/broadcom/sonic-platform-modules-dell/n3248te/sonic_platform/watchdog.py +++ b/platform/broadcom/sonic-platform-modules-dell/n3248te/sonic_platform/watchdog.py @@ -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 -