|
1 |
| -#!/usr/bin/env python |
2 |
| - |
3 | 1 | ########################################################################
|
4 | 2 | #
|
5 | 3 | # DELLEMC S6100
|
|
10 | 8 | ########################################################################
|
11 | 9 |
|
12 | 10 | try:
|
| 11 | + import array |
| 12 | + import ctypes |
| 13 | + import fcntl |
| 14 | + import glob |
13 | 15 | import os
|
14 | 16 | import struct
|
15 |
| - import ctypes |
16 | 17 | from sonic_platform_base.watchdog_base import WatchdogBase
|
17 | 18 | except ImportError as e:
|
18 | 19 | raise ImportError(str(e) + "- required module not found")
|
19 | 20 |
|
| 21 | +# ioctl constants |
| 22 | +IOC_WRITE = 0x40000000 |
| 23 | +IOC_READ = 0x80000000 |
| 24 | +IOC_SIZE_INT = 0x00040000 |
| 25 | + |
| 26 | +WATCHDOG_IOCTL_BASE = ord('W') |
| 27 | + |
| 28 | +WDIOC_SETOPTIONS = IOC_READ | IOC_SIZE_INT | (WATCHDOG_IOCTL_BASE << 8) | 4 |
| 29 | +WDIOC_KEEPALIVE = IOC_READ | IOC_SIZE_INT | (WATCHDOG_IOCTL_BASE << 8) | 5 |
| 30 | +WDIOC_SETTIMEOUT = IOC_READ | IOC_WRITE | IOC_SIZE_INT | (WATCHDOG_IOCTL_BASE << 8) | 6 |
| 31 | + |
| 32 | +WDIOS_DISABLECARD = 0x0001 |
| 33 | +WDIOS_ENABLECARD = 0x0002 |
| 34 | + |
20 | 35 |
|
21 | 36 | class _timespec(ctypes.Structure):
|
22 | 37 | _fields_ = [
|
23 | 38 | ('tv_sec', ctypes.c_long),
|
24 | 39 | ('tv_nsec', ctypes.c_long)
|
25 | 40 | ]
|
26 | 41 |
|
| 42 | + |
27 | 43 | class Watchdog(WatchdogBase):
|
28 | 44 | """
|
29 | 45 | Abstract base class for interfacing with a hardware watchdog module
|
@@ -226,3 +242,142 @@ def get_remaining_time(self):
|
226 | 242 |
|
227 | 243 | return 0
|
228 | 244 |
|
| 245 | + |
| 246 | +class WatchdogTCO(WatchdogBase): |
| 247 | + """ |
| 248 | + Watchdog class for interfacing with iTCO watchdog |
| 249 | + """ |
| 250 | + |
| 251 | + IDENTITY = "iTCO_wdt" |
| 252 | + |
| 253 | + def __init__(self): |
| 254 | + |
| 255 | + self.dev = None |
| 256 | + self.dev_name = None |
| 257 | + wd_sysfs_path = "/sys/class/watchdog" |
| 258 | + |
| 259 | + for dev_file in glob.glob("/dev/watchdog*"): |
| 260 | + dev = os.path.basename(dev_file) |
| 261 | + dev_identity = self._read_file("{}/{}/identity".format(wd_sysfs_path, dev)) |
| 262 | + if dev_identity == self.IDENTITY: |
| 263 | + self.dev_name = dev |
| 264 | + break |
| 265 | + |
| 266 | + if self.dev_name is None: |
| 267 | + raise RuntimeError("{} is not initialized".format(self.IDENTITY)) |
| 268 | + |
| 269 | + self.state_file = "{}/{}/state".format(wd_sysfs_path, self.dev_name) |
| 270 | + self.timeout_file = "{}/{}/timeout".format(wd_sysfs_path, self.dev_name) |
| 271 | + self.timeleft_file = "{}/{}/timeleft".format(wd_sysfs_path, self.dev_name) |
| 272 | + |
| 273 | + def __del__(self): |
| 274 | + if self.dev is not None: |
| 275 | + os.close(self.dev) |
| 276 | + |
| 277 | + def _ioctl(self, request, arg=0, mutate_flag=True): |
| 278 | + """ |
| 279 | + Perform ioctl on watchdog device |
| 280 | + """ |
| 281 | + self._open_wd_dev() |
| 282 | + fcntl.ioctl(self.dev, request, arg, mutate_flag) |
| 283 | + |
| 284 | + def _open_wd_dev(self): |
| 285 | + """ |
| 286 | + Open watchdog device file |
| 287 | + """ |
| 288 | + if self.dev is None: |
| 289 | + wd_dev = "/dev/{}".format(self.dev_name) |
| 290 | + self.dev = os.open(wd_dev, os.O_RDWR) |
| 291 | + |
| 292 | + @staticmethod |
| 293 | + def _read_file(file_path): |
| 294 | + """ |
| 295 | + Read a file |
| 296 | + """ |
| 297 | + try: |
| 298 | + with open(file_path, "r") as fd: |
| 299 | + read_str = fd.read() |
| 300 | + except OSError: |
| 301 | + return -1 |
| 302 | + |
| 303 | + return read_str.strip() |
| 304 | + |
| 305 | + def arm(self, seconds): |
| 306 | + """ |
| 307 | + Arm the hardware watchdog with a timeout of <seconds> seconds. |
| 308 | + If the watchdog is currently armed, calling this function will |
| 309 | + simply reset the timer to the provided value. If the underlying |
| 310 | + hardware does not support the value provided in <seconds>, this |
| 311 | + method should arm the watchdog with the *next greater* |
| 312 | + available value. |
| 313 | +
|
| 314 | + Returns: |
| 315 | + An integer specifying the *actual* number of seconds the |
| 316 | + watchdog was armed with. On failure returns -1. |
| 317 | + """ |
| 318 | + if seconds < 0 or seconds > 0x3ff: |
| 319 | + return -1 |
| 320 | + if seconds < 4: |
| 321 | + seconds = 4 |
| 322 | + |
| 323 | + try: |
| 324 | + timeout = int(self._read_file(self.timeout_file)) |
| 325 | + if timeout != seconds: |
| 326 | + buf = array.array('I', [seconds]) |
| 327 | + self._ioctl(WDIOC_SETTIMEOUT, buf) |
| 328 | + timeout = int(buf[0]) |
| 329 | + |
| 330 | + if self.is_armed(): |
| 331 | + self._ioctl(WDIOC_KEEPALIVE) |
| 332 | + else: |
| 333 | + buf = array.array('h', [WDIOS_ENABLECARD]) |
| 334 | + self._ioctl(WDIOC_SETOPTIONS, buf, False) |
| 335 | + except OSError: |
| 336 | + return -1 |
| 337 | + else: |
| 338 | + return timeout |
| 339 | + |
| 340 | + def disarm(self): |
| 341 | + """ |
| 342 | + Disarm the hardware watchdog |
| 343 | +
|
| 344 | + Returns: |
| 345 | + A boolean, True if watchdog is disarmed successfully, False |
| 346 | + if not |
| 347 | + """ |
| 348 | + disarmed = True |
| 349 | + if self.is_armed(): |
| 350 | + try: |
| 351 | + buf = array.array('h', [WDIOS_DISABLECARD]) |
| 352 | + self._ioctl(WDIOC_SETOPTIONS, buf, False) |
| 353 | + except OSError: |
| 354 | + disarmed = False |
| 355 | + |
| 356 | + return disarmed |
| 357 | + |
| 358 | + def is_armed(self): |
| 359 | + """ |
| 360 | + Retrieves the armed state of the hardware watchdog. |
| 361 | +
|
| 362 | + Returns: |
| 363 | + A boolean, True if watchdog is armed, False if not |
| 364 | + """ |
| 365 | + state = self._read_file(self.state_file) |
| 366 | + return state == "active" |
| 367 | + |
| 368 | + def get_remaining_time(self): |
| 369 | + """ |
| 370 | + If the watchdog is armed, retrieve the number of seconds |
| 371 | + remaining on the watchdog timer |
| 372 | +
|
| 373 | + Returns: |
| 374 | + An integer specifying the number of seconds remaining on |
| 375 | + their watchdog timer. If the watchdog is not armed, returns |
| 376 | + -1. |
| 377 | +
|
| 378 | + """ |
| 379 | + timeleft = -1 |
| 380 | + if self.is_armed(): |
| 381 | + timeleft = int(self._read_file(self.timeleft_file)) |
| 382 | + |
| 383 | + return timeleft |
0 commit comments