Commit 6e2ac20e9c47cf26a1dd5a0f05b93ef0afd3c1c5

Authored by Markus Mayer
Committed by Wim Van Sebroeck
1 parent 6adb730dc2

watchdog: bcm281xx: Debugfs support

This change introduces debugfs support for the BCM281xx watchdog driver.

Signed-off-by: Markus Mayer <markus.mayer@linaro.org>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>

Showing 3 changed files with 115 additions and 4 deletions Side-by-side Diff

arch/arm/configs/bcm_defconfig
... ... @@ -128,4 +128,5 @@
128 128 CONFIG_PINCTRL_CAPRI=y
129 129 CONFIG_WATCHDOG=y
130 130 CONFIG_BCM_KONA_WDT=y
  131 +CONFIG_BCM_KONA_WDT_DEBUG=y
drivers/watchdog/Kconfig
... ... @@ -1151,6 +1151,16 @@
1151 1151 Say 'Y' or 'M' here to enable the driver. The module will be called
1152 1152 bcm_kona_wdt.
1153 1153  
  1154 +config BCM_KONA_WDT_DEBUG
  1155 + bool "DEBUGFS support for BCM Kona Watchdog"
  1156 + depends on BCM_KONA_WDT
  1157 + help
  1158 + If enabled, adds /sys/kernel/debug/bcm_kona_wdt/info which provides
  1159 + access to the driver's internal data structures as well as watchdog
  1160 + timer hardware registres.
  1161 +
  1162 + If in doubt, say 'N'.
  1163 +
1154 1164 config LANTIQ_WDT
1155 1165 tristate "Lantiq SoC watchdog"
1156 1166 depends on LANTIQ
drivers/watchdog/bcm_kona_wdt.c
... ... @@ -11,6 +11,7 @@
11 11 * GNU General Public License for more details.
12 12 */
13 13  
  14 +#include <linux/debugfs.h>
14 15 #include <linux/delay.h>
15 16 #include <linux/err.h>
16 17 #include <linux/io.h>
17 18  
... ... @@ -55,9 +56,13 @@
55 56 */
56 57 int resolution;
57 58 spinlock_t lock;
  59 +#ifdef CONFIG_BCM_KONA_WDT_DEBUG
  60 + unsigned long busy_count;
  61 + struct dentry *debugfs;
  62 +#endif
58 63 };
59 64  
60   -static int secure_register_read(void __iomem *addr)
  65 +static int secure_register_read(struct bcm_kona_wdt *wdt, uint32_t offset)
61 66 {
62 67 uint32_t val;
63 68 unsigned count = 0;
64 69  
... ... @@ -70,10 +75,16 @@
70 75 do {
71 76 if (unlikely(count > 1))
72 77 udelay(5);
73   - val = readl_relaxed(addr);
  78 + val = readl_relaxed(wdt->base + offset);
74 79 count++;
75 80 } while ((val & SECWDOG_WD_LOAD_FLAG) && count < SECWDOG_MAX_TRY);
76 81  
  82 +#ifdef CONFIG_BCM_KONA_WDT_DEBUG
  83 + /* Remember the maximum number iterations due to WD_LOAD_FLAG */
  84 + if (count > wdt->busy_count)
  85 + wdt->busy_count = count;
  86 +#endif
  87 +
77 88 /* This is the only place we return a negative value. */
78 89 if (val & SECWDOG_WD_LOAD_FLAG)
79 90 return -ETIMEDOUT;
... ... @@ -84,6 +95,93 @@
84 95 return val;
85 96 }
86 97  
  98 +#ifdef CONFIG_BCM_KONA_WDT_DEBUG
  99 +
  100 +static int bcm_kona_wdt_dbg_show(struct seq_file *s, void *data)
  101 +{
  102 + int ctl_val, cur_val, ret;
  103 + unsigned long flags;
  104 + struct bcm_kona_wdt *wdt = s->private;
  105 +
  106 + if (!wdt)
  107 + return seq_puts(s, "No device pointer\n");
  108 +
  109 + spin_lock_irqsave(&wdt->lock, flags);
  110 + ctl_val = secure_register_read(wdt, SECWDOG_CTRL_REG);
  111 + cur_val = secure_register_read(wdt, SECWDOG_COUNT_REG);
  112 + spin_unlock_irqrestore(&wdt->lock, flags);
  113 +
  114 + if (ctl_val < 0 || cur_val < 0) {
  115 + ret = seq_puts(s, "Error accessing hardware\n");
  116 + } else {
  117 + int ctl, cur, ctl_sec, cur_sec, res;
  118 +
  119 + ctl = ctl_val & SECWDOG_COUNT_MASK;
  120 + res = (ctl_val & SECWDOG_RES_MASK) >> SECWDOG_CLKS_SHIFT;
  121 + cur = cur_val & SECWDOG_COUNT_MASK;
  122 + ctl_sec = TICKS_TO_SECS(ctl, wdt);
  123 + cur_sec = TICKS_TO_SECS(cur, wdt);
  124 + ret = seq_printf(s, "Resolution: %d / %d\n"
  125 + "Control: %d s / %d (%#x) ticks\n"
  126 + "Current: %d s / %d (%#x) ticks\n"
  127 + "Busy count: %lu\n", res,
  128 + wdt->resolution, ctl_sec, ctl, ctl, cur_sec,
  129 + cur, cur, wdt->busy_count);
  130 + }
  131 +
  132 + return ret;
  133 +}
  134 +
  135 +static int bcm_kona_dbg_open(struct inode *inode, struct file *file)
  136 +{
  137 + return single_open(file, bcm_kona_wdt_dbg_show, inode->i_private);
  138 +}
  139 +
  140 +static const struct file_operations bcm_kona_dbg_operations = {
  141 + .open = bcm_kona_dbg_open,
  142 + .read = seq_read,
  143 + .llseek = seq_lseek,
  144 + .release = single_release,
  145 +};
  146 +
  147 +static void bcm_kona_wdt_debug_init(struct platform_device *pdev)
  148 +{
  149 + struct dentry *dir;
  150 + struct bcm_kona_wdt *wdt = platform_get_drvdata(pdev);
  151 +
  152 + if (!wdt)
  153 + return;
  154 +
  155 + wdt->debugfs = NULL;
  156 +
  157 + dir = debugfs_create_dir(BCM_KONA_WDT_NAME, NULL);
  158 + if (IS_ERR_OR_NULL(dir))
  159 + return;
  160 +
  161 + if (debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt,
  162 + &bcm_kona_dbg_operations))
  163 + wdt->debugfs = dir;
  164 + else
  165 + debugfs_remove_recursive(dir);
  166 +}
  167 +
  168 +static void bcm_kona_wdt_debug_exit(struct platform_device *pdev)
  169 +{
  170 + struct bcm_kona_wdt *wdt = platform_get_drvdata(pdev);
  171 +
  172 + if (wdt && wdt->debugfs) {
  173 + debugfs_remove_recursive(wdt->debugfs);
  174 + wdt->debugfs = NULL;
  175 + }
  176 +}
  177 +
  178 +#else
  179 +
  180 +static void bcm_kona_wdt_debug_init(struct platform_device *pdev) {}
  181 +static void bcm_kona_wdt_debug_exit(struct platform_device *pdev) {}
  182 +
  183 +#endif /* CONFIG_BCM_KONA_WDT_DEBUG */
  184 +
87 185 static int bcm_kona_wdt_ctrl_reg_modify(struct bcm_kona_wdt *wdt,
88 186 unsigned mask, unsigned newval)
89 187 {
... ... @@ -93,7 +191,7 @@
93 191  
94 192 spin_lock_irqsave(&wdt->lock, flags);
95 193  
96   - val = secure_register_read(wdt->base + SECWDOG_CTRL_REG);
  194 + val = secure_register_read(wdt, SECWDOG_CTRL_REG);
97 195 if (val < 0) {
98 196 ret = val;
99 197 } else {
... ... @@ -140,7 +238,7 @@
140 238 unsigned long flags;
141 239  
142 240 spin_lock_irqsave(&wdt->lock, flags);
143   - val = secure_register_read(wdt->base + SECWDOG_COUNT_REG);
  241 + val = secure_register_read(wdt, SECWDOG_COUNT_REG);
144 242 spin_unlock_irqrestore(&wdt->lock, flags);
145 243  
146 244 if (val < 0)
... ... @@ -229,6 +327,7 @@
229 327 return ret;
230 328 }
231 329  
  330 + bcm_kona_wdt_debug_init(pdev);
232 331 dev_dbg(dev, "Broadcom Kona Watchdog Timer");
233 332  
234 333 return 0;
... ... @@ -236,6 +335,7 @@
236 335  
237 336 static int bcm_kona_wdt_remove(struct platform_device *pdev)
238 337 {
  338 + bcm_kona_wdt_debug_exit(pdev);
239 339 bcm_kona_wdt_shutdown(pdev);
240 340 watchdog_unregister_device(&bcm_kona_wdt_wdd);
241 341 dev_dbg(&pdev->dev, "Watchdog driver disabled");