diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2016-01-07 17:49:23 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-02-07 01:11:06 -0500 |
commit | c9cf20ee45602a7a5512b7fbbef5672382790555 (patch) | |
tree | 4b3555c09e163186c194a3a5cf5c7daffe94b905 | |
parent | 222818c3d84c1f3190767f5f09f2b9b9a0e0ca7f (diff) |
watchdog: mei_wdt: add status debugfs entry
Add entry for displaying current watchdog internal state
cat <debugfs>/mei_wdt/state
IDLE|START|RUNNING|STOPPING
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/watchdog/mei_wdt.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/watchdog/mei_wdt.c b/drivers/watchdog/mei_wdt.c index 32e3e1d55ef3..e7e3f144f2b0 100644 --- a/drivers/watchdog/mei_wdt.c +++ b/drivers/watchdog/mei_wdt.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/debugfs.h> | ||
18 | #include <linux/watchdog.h> | 19 | #include <linux/watchdog.h> |
19 | 20 | ||
20 | #include <linux/uuid.h> | 21 | #include <linux/uuid.h> |
@@ -54,6 +55,24 @@ enum mei_wdt_state { | |||
54 | MEI_WDT_STOPPING, | 55 | MEI_WDT_STOPPING, |
55 | }; | 56 | }; |
56 | 57 | ||
58 | #if IS_ENABLED(CONFIG_DEBUG_FS) | ||
59 | static const char *mei_wdt_state_str(enum mei_wdt_state state) | ||
60 | { | ||
61 | switch (state) { | ||
62 | case MEI_WDT_IDLE: | ||
63 | return "IDLE"; | ||
64 | case MEI_WDT_START: | ||
65 | return "START"; | ||
66 | case MEI_WDT_RUNNING: | ||
67 | return "RUNNING"; | ||
68 | case MEI_WDT_STOPPING: | ||
69 | return "STOPPING"; | ||
70 | default: | ||
71 | return "unknown"; | ||
72 | } | ||
73 | } | ||
74 | #endif /* CONFIG_DEBUG_FS */ | ||
75 | |||
57 | /** | 76 | /** |
58 | * struct mei_wdt - mei watchdog driver | 77 | * struct mei_wdt - mei watchdog driver |
59 | * @wdd: watchdog device | 78 | * @wdd: watchdog device |
@@ -61,6 +80,8 @@ enum mei_wdt_state { | |||
61 | * @cldev: mei watchdog client device | 80 | * @cldev: mei watchdog client device |
62 | * @state: watchdog internal state | 81 | * @state: watchdog internal state |
63 | * @timeout: watchdog current timeout | 82 | * @timeout: watchdog current timeout |
83 | * | ||
84 | * @dbgfs_dir: debugfs dir entry | ||
64 | */ | 85 | */ |
65 | struct mei_wdt { | 86 | struct mei_wdt { |
66 | struct watchdog_device wdd; | 87 | struct watchdog_device wdd; |
@@ -68,6 +89,10 @@ struct mei_wdt { | |||
68 | struct mei_cl_device *cldev; | 89 | struct mei_cl_device *cldev; |
69 | enum mei_wdt_state state; | 90 | enum mei_wdt_state state; |
70 | u16 timeout; | 91 | u16 timeout; |
92 | |||
93 | #if IS_ENABLED(CONFIG_DEBUG_FS) | ||
94 | struct dentry *dbgfs_dir; | ||
95 | #endif /* CONFIG_DEBUG_FS */ | ||
71 | }; | 96 | }; |
72 | 97 | ||
73 | /* | 98 | /* |
@@ -310,6 +335,63 @@ static int mei_wdt_register(struct mei_wdt *wdt) | |||
310 | return ret; | 335 | return ret; |
311 | } | 336 | } |
312 | 337 | ||
338 | #if IS_ENABLED(CONFIG_DEBUG_FS) | ||
339 | |||
340 | static ssize_t mei_dbgfs_read_state(struct file *file, char __user *ubuf, | ||
341 | size_t cnt, loff_t *ppos) | ||
342 | { | ||
343 | struct mei_wdt *wdt = file->private_data; | ||
344 | const size_t bufsz = 32; | ||
345 | char buf[bufsz]; | ||
346 | ssize_t pos; | ||
347 | |||
348 | pos = scnprintf(buf, bufsz, "state: %s\n", | ||
349 | mei_wdt_state_str(wdt->state)); | ||
350 | |||
351 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); | ||
352 | } | ||
353 | |||
354 | static const struct file_operations dbgfs_fops_state = { | ||
355 | .open = simple_open, | ||
356 | .read = mei_dbgfs_read_state, | ||
357 | .llseek = generic_file_llseek, | ||
358 | }; | ||
359 | |||
360 | static void dbgfs_unregister(struct mei_wdt *wdt) | ||
361 | { | ||
362 | debugfs_remove_recursive(wdt->dbgfs_dir); | ||
363 | wdt->dbgfs_dir = NULL; | ||
364 | } | ||
365 | |||
366 | static int dbgfs_register(struct mei_wdt *wdt) | ||
367 | { | ||
368 | struct dentry *dir, *f; | ||
369 | |||
370 | dir = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
371 | if (!dir) | ||
372 | return -ENOMEM; | ||
373 | |||
374 | wdt->dbgfs_dir = dir; | ||
375 | f = debugfs_create_file("state", S_IRUSR, dir, wdt, &dbgfs_fops_state); | ||
376 | if (!f) | ||
377 | goto err; | ||
378 | |||
379 | return 0; | ||
380 | err: | ||
381 | dbgfs_unregister(wdt); | ||
382 | return -ENODEV; | ||
383 | } | ||
384 | |||
385 | #else | ||
386 | |||
387 | static inline void dbgfs_unregister(struct mei_wdt *wdt) {} | ||
388 | |||
389 | static inline int dbgfs_register(struct mei_wdt *wdt) | ||
390 | { | ||
391 | return 0; | ||
392 | } | ||
393 | #endif /* CONFIG_DEBUG_FS */ | ||
394 | |||
313 | static int mei_wdt_probe(struct mei_cl_device *cldev, | 395 | static int mei_wdt_probe(struct mei_cl_device *cldev, |
314 | const struct mei_cl_device_id *id) | 396 | const struct mei_cl_device_id *id) |
315 | { | 397 | { |
@@ -337,6 +419,9 @@ static int mei_wdt_probe(struct mei_cl_device *cldev, | |||
337 | if (ret) | 419 | if (ret) |
338 | goto err_disable; | 420 | goto err_disable; |
339 | 421 | ||
422 | if (dbgfs_register(wdt)) | ||
423 | dev_warn(&cldev->dev, "cannot register debugfs\n"); | ||
424 | |||
340 | return 0; | 425 | return 0; |
341 | 426 | ||
342 | err_disable: | 427 | err_disable: |
@@ -356,6 +441,8 @@ static int mei_wdt_remove(struct mei_cl_device *cldev) | |||
356 | 441 | ||
357 | mei_cldev_disable(cldev); | 442 | mei_cldev_disable(cldev); |
358 | 443 | ||
444 | dbgfs_unregister(wdt); | ||
445 | |||
359 | kfree(wdt); | 446 | kfree(wdt); |
360 | 447 | ||
361 | return 0; | 448 | return 0; |