* [PATCH 0/2] clocksource: fix Tegra234 SoC Watchdog Timer.
@ 2024-01-16 11:58 Pohsun Su
2024-01-16 11:58 ` [PATCH 1/2] clocksource/drivers/timer-tegra186: add WDIOC_GETTIMELEFT support Pohsun Su
2024-01-16 11:58 ` [PATCH 2/2] clocksource/drivers/timer-tegra186: fix watchdog self-pinging Pohsun Su
0 siblings, 2 replies; 5+ messages in thread
From: Pohsun Su @ 2024-01-16 11:58 UTC (permalink / raw)
To: daniel.lezcano, tglx, thierry.reding, jonathanh
Cc: sumitg, linux-kernel, linux-tegra, Pohsun Su
This set of patches includes a fix for watchdog for it may not bark
due to self-pinging and adds WDIOC_GETTIMELEFT support.
Pohsun Su (2):
clocksource/drivers/timer-tegra186: add WDIOC_GETTIMELEFT support
clocksource/drivers/timer-tegra186: fix watchdog self-pinging.
drivers/clocksource/timer-tegra186.c | 65 ++++++++++++++++++----------
1 file changed, 43 insertions(+), 22 deletions(-)
--
2.17.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] clocksource/drivers/timer-tegra186: add WDIOC_GETTIMELEFT support
2024-01-16 11:58 [PATCH 0/2] clocksource: fix Tegra234 SoC Watchdog Timer Pohsun Su
@ 2024-01-16 11:58 ` Pohsun Su
2024-01-17 12:26 ` kernel test robot
2024-01-16 11:58 ` [PATCH 2/2] clocksource/drivers/timer-tegra186: fix watchdog self-pinging Pohsun Su
1 sibling, 1 reply; 5+ messages in thread
From: Pohsun Su @ 2024-01-16 11:58 UTC (permalink / raw)
To: daniel.lezcano, tglx, thierry.reding, jonathanh
Cc: sumitg, linux-kernel, linux-tegra, Pohsun Su
This change adds support for WDIOC_GETTIMELEFT so userspace
programs can get the number of seconds before system reset by
the watchdog timer via ioctl.
Signed-off-by: Pohsun Su <pohsuns@nvidia.com>
---
drivers/clocksource/timer-tegra186.c | 41 ++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/drivers/clocksource/timer-tegra186.c b/drivers/clocksource/timer-tegra186.c
index 304537dadf2c..685c6689a2da 100644
--- a/drivers/clocksource/timer-tegra186.c
+++ b/drivers/clocksource/timer-tegra186.c
@@ -29,6 +29,7 @@
#define TMRSR 0x004
#define TMRSR_INTR_CLR BIT(30)
+#define TMRSR_PCV GENMASK(28, 0)
#define TMRCSSR 0x008
#define TMRCSSR_SRC_USEC (0 << 0)
@@ -45,6 +46,9 @@
#define WDTCR_TIMER_SOURCE_MASK 0xf
#define WDTCR_TIMER_SOURCE(x) ((x) & 0xf)
+#define WDTSR 0x004
+#define WDTSR_CURRENT_EXPIRATION_COUNT GENMASK(14, 12)
+
#define WDTCMDR 0x008
#define WDTCMDR_DISABLE_COUNTER BIT(1)
#define WDTCMDR_START_COUNTER BIT(0)
@@ -234,12 +238,49 @@ static int tegra186_wdt_set_timeout(struct watchdog_device *wdd,
return 0;
}
+static unsigned int tegra186_wdt_get_timeleft(struct watchdog_device *wdd)
+{
+ struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
+ u32 timeleft;
+ u32 expiration;
+
+ if (!watchdog_active(&wdt->base)) {
+ /* return zero if the watchdog timer is not activated. */
+ return 0;
+ }
+
+ /*
+ * System power-on reset occurs on the fifth expiration of the watchdog timer and so
+ * when the watchdog timer is configured, the actual value programmed into the counter
+ * is 1/5 of the timeout value. Once the counter reaches 0, expiration count will be
+ * increased by 1 and the down counter restarts.
+ * Hence to get the time left before system reset we must combine 2 parts:
+ * 1. value of the current down counter
+ * 2. (number of counter expirations remaining) * (timeout/5)
+ */
+
+ /* Get the current number of counter expirations. Should be a value between 0 and 4. */
+ expiration = FIELD_GET(WDTSR_CURRENT_EXPIRATION_COUNT, readl_relaxed(wdt->regs + WDTSR));
+
+ /* Convert the current counter value to seconds, rounding up to the nearest second. */
+ timeleft = FIELD_GET(TMRSR_PCV, readl_relaxed(wdt->tmr->regs + TMRSR));
+ timeleft = (timeleft + USEC_PER_SEC / 2) / USEC_PER_SEC;
+
+ /*
+ * Calculate the time remaining by adding the time for the counter value
+ * to the time of the counter expirations that remain.
+ */
+ timeleft += wdt->base.timeout * (4 - expiration) / 5;
+ return timeleft;
+}
+
static const struct watchdog_ops tegra186_wdt_ops = {
.owner = THIS_MODULE,
.start = tegra186_wdt_start,
.stop = tegra186_wdt_stop,
.ping = tegra186_wdt_ping,
.set_timeout = tegra186_wdt_set_timeout,
+ .get_timeleft = tegra186_wdt_get_timeleft,
};
static struct tegra186_wdt *tegra186_wdt_create(struct tegra186_timer *tegra,
--
2.17.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] clocksource/drivers/timer-tegra186: fix watchdog self-pinging.
2024-01-16 11:58 [PATCH 0/2] clocksource: fix Tegra234 SoC Watchdog Timer Pohsun Su
2024-01-16 11:58 ` [PATCH 1/2] clocksource/drivers/timer-tegra186: add WDIOC_GETTIMELEFT support Pohsun Su
@ 2024-01-16 11:58 ` Pohsun Su
2024-01-21 13:27 ` kernel test robot
1 sibling, 1 reply; 5+ messages in thread
From: Pohsun Su @ 2024-01-16 11:58 UTC (permalink / raw)
To: daniel.lezcano, tglx, thierry.reding, jonathanh
Cc: sumitg, linux-kernel, linux-tegra, Pohsun Su
This change removes watchdog self-pinging behavior.
The timer irq handler is triggered due to the 1st expiration,
the handler disables and enables watchdog but also implicitly
clears the expiration count so the count can only be 0 or 1.
Since this watchdog supports opened, configured, or pinged by
systemd, We remove this behavior or the watchdog may not bark
when systemd crashes since the 5th expiration never comes.
Signed-off-by: Pohsun Su <pohsuns@nvidia.com>
---
drivers/clocksource/timer-tegra186.c | 24 ++----------------------
1 file changed, 2 insertions(+), 22 deletions(-)
diff --git a/drivers/clocksource/timer-tegra186.c b/drivers/clocksource/timer-tegra186.c
index 685c6689a2da..963c12c81f4d 100644
--- a/drivers/clocksource/timer-tegra186.c
+++ b/drivers/clocksource/timer-tegra186.c
@@ -174,7 +174,8 @@ static void tegra186_wdt_enable(struct tegra186_wdt *wdt)
value |= WDTCR_PERIOD(1);
/* enable local interrupt for WDT petting */
- value |= WDTCR_LOCAL_INT_ENABLE;
+ if (0)
+ value |= WDTCR_LOCAL_INT_ENABLE;
/* enable local FIQ and remote interrupt for debug dump */
if (0)
@@ -406,18 +407,6 @@ static int tegra186_timer_usec_init(struct tegra186_timer *tegra)
return clocksource_register_hz(&tegra->usec, USEC_PER_SEC);
}
-static irqreturn_t tegra186_timer_irq(int irq, void *data)
-{
- struct tegra186_timer *tegra = data;
-
- if (watchdog_active(&tegra->wdt->base)) {
- tegra186_wdt_disable(tegra->wdt);
- tegra186_wdt_enable(tegra->wdt);
- }
-
- return IRQ_HANDLED;
-}
-
static int tegra186_timer_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -469,17 +458,8 @@ static int tegra186_timer_probe(struct platform_device *pdev)
goto unregister_osc;
}
- err = devm_request_irq(dev, irq, tegra186_timer_irq, 0,
- "tegra186-timer", tegra);
- if (err < 0) {
- dev_err(dev, "failed to request IRQ#%u: %d\n", irq, err);
- goto unregister_usec;
- }
-
return 0;
-unregister_usec:
- clocksource_unregister(&tegra->usec);
unregister_osc:
clocksource_unregister(&tegra->osc);
unregister_tsc:
--
2.17.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] clocksource/drivers/timer-tegra186: add WDIOC_GETTIMELEFT support
2024-01-16 11:58 ` [PATCH 1/2] clocksource/drivers/timer-tegra186: add WDIOC_GETTIMELEFT support Pohsun Su
@ 2024-01-17 12:26 ` kernel test robot
0 siblings, 0 replies; 5+ messages in thread
From: kernel test robot @ 2024-01-17 12:26 UTC (permalink / raw)
To: Pohsun Su, daniel.lezcano, tglx, thierry.reding, jonathanh
Cc: oe-kbuild-all, sumitg, linux-kernel, linux-tegra, Pohsun Su
Hi Pohsun,
kernel test robot noticed the following build errors:
[auto build test ERROR on tip/timers/core]
[also build test ERROR on linus/master v6.7 next-20240117]
[cannot apply to daniel-lezcano/clockevents/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Pohsun-Su/clocksource-drivers-timer-tegra186-add-WDIOC_GETTIMELEFT-support/20240116-200217
base: tip/timers/core
patch link: https://lore.kernel.org/r/20240116115838.16544-2-pohsuns%40nvidia.com
patch subject: [PATCH 1/2] clocksource/drivers/timer-tegra186: add WDIOC_GETTIMELEFT support
config: loongarch-allyesconfig (https://download.01.org/0day-ci/archive/20240117/202401172015.KdPd7tda-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240117/202401172015.KdPd7tda-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202401172015.KdPd7tda-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/clocksource/timer-tegra186.c: In function 'tegra186_wdt_get_timeleft':
>> drivers/clocksource/timer-tegra186.c:263:22: error: implicit declaration of function 'FIELD_GET' [-Werror=implicit-function-declaration]
263 | expiration = FIELD_GET(WDTSR_CURRENT_EXPIRATION_COUNT, readl_relaxed(wdt->regs + WDTSR));
| ^~~~~~~~~
cc1: some warnings being treated as errors
vim +/FIELD_GET +263 drivers/clocksource/timer-tegra186.c
240
241 static unsigned int tegra186_wdt_get_timeleft(struct watchdog_device *wdd)
242 {
243 struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
244 u32 timeleft;
245 u32 expiration;
246
247 if (!watchdog_active(&wdt->base)) {
248 /* return zero if the watchdog timer is not activated. */
249 return 0;
250 }
251
252 /*
253 * System power-on reset occurs on the fifth expiration of the watchdog timer and so
254 * when the watchdog timer is configured, the actual value programmed into the counter
255 * is 1/5 of the timeout value. Once the counter reaches 0, expiration count will be
256 * increased by 1 and the down counter restarts.
257 * Hence to get the time left before system reset we must combine 2 parts:
258 * 1. value of the current down counter
259 * 2. (number of counter expirations remaining) * (timeout/5)
260 */
261
262 /* Get the current number of counter expirations. Should be a value between 0 and 4. */
> 263 expiration = FIELD_GET(WDTSR_CURRENT_EXPIRATION_COUNT, readl_relaxed(wdt->regs + WDTSR));
264
265 /* Convert the current counter value to seconds, rounding up to the nearest second. */
266 timeleft = FIELD_GET(TMRSR_PCV, readl_relaxed(wdt->tmr->regs + TMRSR));
267 timeleft = (timeleft + USEC_PER_SEC / 2) / USEC_PER_SEC;
268
269 /*
270 * Calculate the time remaining by adding the time for the counter value
271 * to the time of the counter expirations that remain.
272 */
273 timeleft += wdt->base.timeout * (4 - expiration) / 5;
274 return timeleft;
275 }
276
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] clocksource/drivers/timer-tegra186: fix watchdog self-pinging.
2024-01-16 11:58 ` [PATCH 2/2] clocksource/drivers/timer-tegra186: fix watchdog self-pinging Pohsun Su
@ 2024-01-21 13:27 ` kernel test robot
0 siblings, 0 replies; 5+ messages in thread
From: kernel test robot @ 2024-01-21 13:27 UTC (permalink / raw)
To: Pohsun Su, daniel.lezcano, tglx, thierry.reding, jonathanh
Cc: llvm, oe-kbuild-all, sumitg, linux-kernel, linux-tegra, Pohsun Su
Hi Pohsun,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tip/timers/core]
[also build test WARNING on linus/master v6.7 next-20240119]
[cannot apply to daniel-lezcano/clockevents/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Pohsun-Su/clocksource-drivers-timer-tegra186-add-WDIOC_GETTIMELEFT-support/20240116-200217
base: tip/timers/core
patch link: https://lore.kernel.org/r/20240116115838.16544-3-pohsuns%40nvidia.com
patch subject: [PATCH 2/2] clocksource/drivers/timer-tegra186: fix watchdog self-pinging.
config: x86_64-allyesconfig (https://download.01.org/0day-ci/archive/20240121/202401212150.DUcfhGzx-lkp@intel.com/config)
compiler: ClangBuiltLinux clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240121/202401212150.DUcfhGzx-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202401212150.DUcfhGzx-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/clocksource/timer-tegra186.c:264:15: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
264 | expiration = FIELD_GET(WDTSR_CURRENT_EXPIRATION_COUNT, readl_relaxed(wdt->regs + WDTSR));
| ^
>> drivers/clocksource/timer-tegra186.c:414:15: warning: variable 'irq' set but not used [-Wunused-but-set-variable]
414 | unsigned int irq;
| ^
1 warning and 1 error generated.
vim +/irq +414 drivers/clocksource/timer-tegra186.c
42cee19a9f839f Thierry Reding 2022-07-04 241
3d6bf45a82fb12 Pohsun Su 2024-01-16 242 static unsigned int tegra186_wdt_get_timeleft(struct watchdog_device *wdd)
3d6bf45a82fb12 Pohsun Su 2024-01-16 243 {
3d6bf45a82fb12 Pohsun Su 2024-01-16 244 struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
3d6bf45a82fb12 Pohsun Su 2024-01-16 245 u32 timeleft;
3d6bf45a82fb12 Pohsun Su 2024-01-16 246 u32 expiration;
3d6bf45a82fb12 Pohsun Su 2024-01-16 247
3d6bf45a82fb12 Pohsun Su 2024-01-16 248 if (!watchdog_active(&wdt->base)) {
3d6bf45a82fb12 Pohsun Su 2024-01-16 249 /* return zero if the watchdog timer is not activated. */
3d6bf45a82fb12 Pohsun Su 2024-01-16 250 return 0;
3d6bf45a82fb12 Pohsun Su 2024-01-16 251 }
3d6bf45a82fb12 Pohsun Su 2024-01-16 252
3d6bf45a82fb12 Pohsun Su 2024-01-16 253 /*
3d6bf45a82fb12 Pohsun Su 2024-01-16 254 * System power-on reset occurs on the fifth expiration of the watchdog timer and so
3d6bf45a82fb12 Pohsun Su 2024-01-16 255 * when the watchdog timer is configured, the actual value programmed into the counter
3d6bf45a82fb12 Pohsun Su 2024-01-16 256 * is 1/5 of the timeout value. Once the counter reaches 0, expiration count will be
3d6bf45a82fb12 Pohsun Su 2024-01-16 257 * increased by 1 and the down counter restarts.
3d6bf45a82fb12 Pohsun Su 2024-01-16 258 * Hence to get the time left before system reset we must combine 2 parts:
3d6bf45a82fb12 Pohsun Su 2024-01-16 259 * 1. value of the current down counter
3d6bf45a82fb12 Pohsun Su 2024-01-16 260 * 2. (number of counter expirations remaining) * (timeout/5)
3d6bf45a82fb12 Pohsun Su 2024-01-16 261 */
3d6bf45a82fb12 Pohsun Su 2024-01-16 262
3d6bf45a82fb12 Pohsun Su 2024-01-16 263 /* Get the current number of counter expirations. Should be a value between 0 and 4. */
3d6bf45a82fb12 Pohsun Su 2024-01-16 @264 expiration = FIELD_GET(WDTSR_CURRENT_EXPIRATION_COUNT, readl_relaxed(wdt->regs + WDTSR));
3d6bf45a82fb12 Pohsun Su 2024-01-16 265
3d6bf45a82fb12 Pohsun Su 2024-01-16 266 /* Convert the current counter value to seconds, rounding up to the nearest second. */
3d6bf45a82fb12 Pohsun Su 2024-01-16 267 timeleft = FIELD_GET(TMRSR_PCV, readl_relaxed(wdt->tmr->regs + TMRSR));
3d6bf45a82fb12 Pohsun Su 2024-01-16 268 timeleft = (timeleft + USEC_PER_SEC / 2) / USEC_PER_SEC;
3d6bf45a82fb12 Pohsun Su 2024-01-16 269
3d6bf45a82fb12 Pohsun Su 2024-01-16 270 /*
3d6bf45a82fb12 Pohsun Su 2024-01-16 271 * Calculate the time remaining by adding the time for the counter value
3d6bf45a82fb12 Pohsun Su 2024-01-16 272 * to the time of the counter expirations that remain.
3d6bf45a82fb12 Pohsun Su 2024-01-16 273 */
3d6bf45a82fb12 Pohsun Su 2024-01-16 274 timeleft += wdt->base.timeout * (4 - expiration) / 5;
3d6bf45a82fb12 Pohsun Su 2024-01-16 275 return timeleft;
3d6bf45a82fb12 Pohsun Su 2024-01-16 276 }
3d6bf45a82fb12 Pohsun Su 2024-01-16 277
42cee19a9f839f Thierry Reding 2022-07-04 278 static const struct watchdog_ops tegra186_wdt_ops = {
42cee19a9f839f Thierry Reding 2022-07-04 279 .owner = THIS_MODULE,
42cee19a9f839f Thierry Reding 2022-07-04 280 .start = tegra186_wdt_start,
42cee19a9f839f Thierry Reding 2022-07-04 281 .stop = tegra186_wdt_stop,
42cee19a9f839f Thierry Reding 2022-07-04 282 .ping = tegra186_wdt_ping,
42cee19a9f839f Thierry Reding 2022-07-04 283 .set_timeout = tegra186_wdt_set_timeout,
3d6bf45a82fb12 Pohsun Su 2024-01-16 284 .get_timeleft = tegra186_wdt_get_timeleft,
42cee19a9f839f Thierry Reding 2022-07-04 285 };
42cee19a9f839f Thierry Reding 2022-07-04 286
42cee19a9f839f Thierry Reding 2022-07-04 287 static struct tegra186_wdt *tegra186_wdt_create(struct tegra186_timer *tegra,
42cee19a9f839f Thierry Reding 2022-07-04 288 unsigned int index)
42cee19a9f839f Thierry Reding 2022-07-04 289 {
42cee19a9f839f Thierry Reding 2022-07-04 290 unsigned int offset = 0x10000, source;
42cee19a9f839f Thierry Reding 2022-07-04 291 struct tegra186_wdt *wdt;
42cee19a9f839f Thierry Reding 2022-07-04 292 u32 value;
42cee19a9f839f Thierry Reding 2022-07-04 293 int err;
42cee19a9f839f Thierry Reding 2022-07-04 294
42cee19a9f839f Thierry Reding 2022-07-04 295 offset += tegra->soc->num_timers * 0x10000 + index * 0x10000;
42cee19a9f839f Thierry Reding 2022-07-04 296
42cee19a9f839f Thierry Reding 2022-07-04 297 wdt = devm_kzalloc(tegra->dev, sizeof(*wdt), GFP_KERNEL);
42cee19a9f839f Thierry Reding 2022-07-04 298 if (!wdt)
42cee19a9f839f Thierry Reding 2022-07-04 299 return ERR_PTR(-ENOMEM);
42cee19a9f839f Thierry Reding 2022-07-04 300
42cee19a9f839f Thierry Reding 2022-07-04 301 wdt->regs = tegra->regs + offset;
42cee19a9f839f Thierry Reding 2022-07-04 302 wdt->index = index;
42cee19a9f839f Thierry Reding 2022-07-04 303
42cee19a9f839f Thierry Reding 2022-07-04 304 /* read the watchdog configuration since it might be locked down */
42cee19a9f839f Thierry Reding 2022-07-04 305 value = wdt_readl(wdt, WDTCR);
42cee19a9f839f Thierry Reding 2022-07-04 306
42cee19a9f839f Thierry Reding 2022-07-04 307 if (value & WDTCR_LOCAL_INT_ENABLE)
42cee19a9f839f Thierry Reding 2022-07-04 308 wdt->locked = true;
42cee19a9f839f Thierry Reding 2022-07-04 309
42cee19a9f839f Thierry Reding 2022-07-04 310 source = value & WDTCR_TIMER_SOURCE_MASK;
42cee19a9f839f Thierry Reding 2022-07-04 311
42cee19a9f839f Thierry Reding 2022-07-04 312 wdt->tmr = tegra186_tmr_create(tegra, source);
42cee19a9f839f Thierry Reding 2022-07-04 313 if (IS_ERR(wdt->tmr))
42cee19a9f839f Thierry Reding 2022-07-04 314 return ERR_CAST(wdt->tmr);
42cee19a9f839f Thierry Reding 2022-07-04 315
42cee19a9f839f Thierry Reding 2022-07-04 316 wdt->base.info = &tegra186_wdt_info;
42cee19a9f839f Thierry Reding 2022-07-04 317 wdt->base.ops = &tegra186_wdt_ops;
42cee19a9f839f Thierry Reding 2022-07-04 318 wdt->base.min_timeout = 1;
42cee19a9f839f Thierry Reding 2022-07-04 319 wdt->base.max_timeout = 255;
42cee19a9f839f Thierry Reding 2022-07-04 320 wdt->base.parent = tegra->dev;
42cee19a9f839f Thierry Reding 2022-07-04 321
42cee19a9f839f Thierry Reding 2022-07-04 322 err = watchdog_init_timeout(&wdt->base, 5, tegra->dev);
42cee19a9f839f Thierry Reding 2022-07-04 323 if (err < 0) {
42cee19a9f839f Thierry Reding 2022-07-04 324 dev_err(tegra->dev, "failed to initialize timeout: %d\n", err);
42cee19a9f839f Thierry Reding 2022-07-04 325 return ERR_PTR(err);
42cee19a9f839f Thierry Reding 2022-07-04 326 }
42cee19a9f839f Thierry Reding 2022-07-04 327
42cee19a9f839f Thierry Reding 2022-07-04 328 err = devm_watchdog_register_device(tegra->dev, &wdt->base);
42cee19a9f839f Thierry Reding 2022-07-04 329 if (err < 0) {
42cee19a9f839f Thierry Reding 2022-07-04 330 dev_err(tegra->dev, "failed to register WDT: %d\n", err);
42cee19a9f839f Thierry Reding 2022-07-04 331 return ERR_PTR(err);
42cee19a9f839f Thierry Reding 2022-07-04 332 }
42cee19a9f839f Thierry Reding 2022-07-04 333
42cee19a9f839f Thierry Reding 2022-07-04 334 return wdt;
42cee19a9f839f Thierry Reding 2022-07-04 335 }
42cee19a9f839f Thierry Reding 2022-07-04 336
42cee19a9f839f Thierry Reding 2022-07-04 337 static u64 tegra186_timer_tsc_read(struct clocksource *cs)
42cee19a9f839f Thierry Reding 2022-07-04 338 {
42cee19a9f839f Thierry Reding 2022-07-04 339 struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
42cee19a9f839f Thierry Reding 2022-07-04 340 tsc);
42cee19a9f839f Thierry Reding 2022-07-04 341 u32 hi, lo, ss;
42cee19a9f839f Thierry Reding 2022-07-04 342
42cee19a9f839f Thierry Reding 2022-07-04 343 hi = readl_relaxed(tegra->regs + TKETSC1);
42cee19a9f839f Thierry Reding 2022-07-04 344
42cee19a9f839f Thierry Reding 2022-07-04 345 /*
42cee19a9f839f Thierry Reding 2022-07-04 346 * The 56-bit value of the TSC is spread across two registers that are
42cee19a9f839f Thierry Reding 2022-07-04 347 * not synchronized. In order to read them atomically, ensure that the
42cee19a9f839f Thierry Reding 2022-07-04 348 * high 24 bits match before and after reading the low 32 bits.
42cee19a9f839f Thierry Reding 2022-07-04 349 */
42cee19a9f839f Thierry Reding 2022-07-04 350 do {
42cee19a9f839f Thierry Reding 2022-07-04 351 /* snapshot the high 24 bits */
42cee19a9f839f Thierry Reding 2022-07-04 352 ss = hi;
42cee19a9f839f Thierry Reding 2022-07-04 353
42cee19a9f839f Thierry Reding 2022-07-04 354 lo = readl_relaxed(tegra->regs + TKETSC0);
42cee19a9f839f Thierry Reding 2022-07-04 355 hi = readl_relaxed(tegra->regs + TKETSC1);
42cee19a9f839f Thierry Reding 2022-07-04 356 } while (hi != ss);
42cee19a9f839f Thierry Reding 2022-07-04 357
42cee19a9f839f Thierry Reding 2022-07-04 358 return (u64)hi << 32 | lo;
42cee19a9f839f Thierry Reding 2022-07-04 359 }
42cee19a9f839f Thierry Reding 2022-07-04 360
42cee19a9f839f Thierry Reding 2022-07-04 361 static int tegra186_timer_tsc_init(struct tegra186_timer *tegra)
42cee19a9f839f Thierry Reding 2022-07-04 362 {
42cee19a9f839f Thierry Reding 2022-07-04 363 tegra->tsc.name = "tsc";
42cee19a9f839f Thierry Reding 2022-07-04 364 tegra->tsc.rating = 300;
42cee19a9f839f Thierry Reding 2022-07-04 365 tegra->tsc.read = tegra186_timer_tsc_read;
42cee19a9f839f Thierry Reding 2022-07-04 366 tegra->tsc.mask = CLOCKSOURCE_MASK(56);
42cee19a9f839f Thierry Reding 2022-07-04 367 tegra->tsc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
42cee19a9f839f Thierry Reding 2022-07-04 368
42cee19a9f839f Thierry Reding 2022-07-04 369 return clocksource_register_hz(&tegra->tsc, 31250000);
42cee19a9f839f Thierry Reding 2022-07-04 370 }
42cee19a9f839f Thierry Reding 2022-07-04 371
42cee19a9f839f Thierry Reding 2022-07-04 372 static u64 tegra186_timer_osc_read(struct clocksource *cs)
42cee19a9f839f Thierry Reding 2022-07-04 373 {
42cee19a9f839f Thierry Reding 2022-07-04 374 struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
42cee19a9f839f Thierry Reding 2022-07-04 375 osc);
42cee19a9f839f Thierry Reding 2022-07-04 376
42cee19a9f839f Thierry Reding 2022-07-04 377 return readl_relaxed(tegra->regs + TKEOSC);
42cee19a9f839f Thierry Reding 2022-07-04 378 }
42cee19a9f839f Thierry Reding 2022-07-04 379
42cee19a9f839f Thierry Reding 2022-07-04 380 static int tegra186_timer_osc_init(struct tegra186_timer *tegra)
42cee19a9f839f Thierry Reding 2022-07-04 381 {
42cee19a9f839f Thierry Reding 2022-07-04 382 tegra->osc.name = "osc";
42cee19a9f839f Thierry Reding 2022-07-04 383 tegra->osc.rating = 300;
42cee19a9f839f Thierry Reding 2022-07-04 384 tegra->osc.read = tegra186_timer_osc_read;
42cee19a9f839f Thierry Reding 2022-07-04 385 tegra->osc.mask = CLOCKSOURCE_MASK(32);
42cee19a9f839f Thierry Reding 2022-07-04 386 tegra->osc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
42cee19a9f839f Thierry Reding 2022-07-04 387
42cee19a9f839f Thierry Reding 2022-07-04 388 return clocksource_register_hz(&tegra->osc, 38400000);
42cee19a9f839f Thierry Reding 2022-07-04 389 }
42cee19a9f839f Thierry Reding 2022-07-04 390
42cee19a9f839f Thierry Reding 2022-07-04 391 static u64 tegra186_timer_usec_read(struct clocksource *cs)
42cee19a9f839f Thierry Reding 2022-07-04 392 {
42cee19a9f839f Thierry Reding 2022-07-04 393 struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
42cee19a9f839f Thierry Reding 2022-07-04 394 usec);
42cee19a9f839f Thierry Reding 2022-07-04 395
42cee19a9f839f Thierry Reding 2022-07-04 396 return readl_relaxed(tegra->regs + TKEUSEC);
42cee19a9f839f Thierry Reding 2022-07-04 397 }
42cee19a9f839f Thierry Reding 2022-07-04 398
42cee19a9f839f Thierry Reding 2022-07-04 399 static int tegra186_timer_usec_init(struct tegra186_timer *tegra)
42cee19a9f839f Thierry Reding 2022-07-04 400 {
42cee19a9f839f Thierry Reding 2022-07-04 401 tegra->usec.name = "usec";
42cee19a9f839f Thierry Reding 2022-07-04 402 tegra->usec.rating = 300;
42cee19a9f839f Thierry Reding 2022-07-04 403 tegra->usec.read = tegra186_timer_usec_read;
42cee19a9f839f Thierry Reding 2022-07-04 404 tegra->usec.mask = CLOCKSOURCE_MASK(32);
42cee19a9f839f Thierry Reding 2022-07-04 405 tegra->usec.flags = CLOCK_SOURCE_IS_CONTINUOUS;
42cee19a9f839f Thierry Reding 2022-07-04 406
42cee19a9f839f Thierry Reding 2022-07-04 407 return clocksource_register_hz(&tegra->usec, USEC_PER_SEC);
42cee19a9f839f Thierry Reding 2022-07-04 408 }
42cee19a9f839f Thierry Reding 2022-07-04 409
42cee19a9f839f Thierry Reding 2022-07-04 410 static int tegra186_timer_probe(struct platform_device *pdev)
42cee19a9f839f Thierry Reding 2022-07-04 411 {
42cee19a9f839f Thierry Reding 2022-07-04 412 struct device *dev = &pdev->dev;
42cee19a9f839f Thierry Reding 2022-07-04 413 struct tegra186_timer *tegra;
42cee19a9f839f Thierry Reding 2022-07-04 @414 unsigned int irq;
42cee19a9f839f Thierry Reding 2022-07-04 415 int err;
42cee19a9f839f Thierry Reding 2022-07-04 416
42cee19a9f839f Thierry Reding 2022-07-04 417 tegra = devm_kzalloc(dev, sizeof(*tegra), GFP_KERNEL);
42cee19a9f839f Thierry Reding 2022-07-04 418 if (!tegra)
42cee19a9f839f Thierry Reding 2022-07-04 419 return -ENOMEM;
42cee19a9f839f Thierry Reding 2022-07-04 420
42cee19a9f839f Thierry Reding 2022-07-04 421 tegra->soc = of_device_get_match_data(dev);
42cee19a9f839f Thierry Reding 2022-07-04 422 dev_set_drvdata(dev, tegra);
42cee19a9f839f Thierry Reding 2022-07-04 423 tegra->dev = dev;
42cee19a9f839f Thierry Reding 2022-07-04 424
42cee19a9f839f Thierry Reding 2022-07-04 425 tegra->regs = devm_platform_ioremap_resource(pdev, 0);
42cee19a9f839f Thierry Reding 2022-07-04 426 if (IS_ERR(tegra->regs))
42cee19a9f839f Thierry Reding 2022-07-04 427 return PTR_ERR(tegra->regs);
42cee19a9f839f Thierry Reding 2022-07-04 428
42cee19a9f839f Thierry Reding 2022-07-04 429 err = platform_get_irq(pdev, 0);
42cee19a9f839f Thierry Reding 2022-07-04 430 if (err < 0)
42cee19a9f839f Thierry Reding 2022-07-04 431 return err;
42cee19a9f839f Thierry Reding 2022-07-04 432
42cee19a9f839f Thierry Reding 2022-07-04 433 irq = err;
42cee19a9f839f Thierry Reding 2022-07-04 434
42cee19a9f839f Thierry Reding 2022-07-04 435 /* create a watchdog using a preconfigured timer */
42cee19a9f839f Thierry Reding 2022-07-04 436 tegra->wdt = tegra186_wdt_create(tegra, 0);
42cee19a9f839f Thierry Reding 2022-07-04 437 if (IS_ERR(tegra->wdt)) {
42cee19a9f839f Thierry Reding 2022-07-04 438 err = PTR_ERR(tegra->wdt);
42cee19a9f839f Thierry Reding 2022-07-04 439 dev_err(dev, "failed to create WDT: %d\n", err);
42cee19a9f839f Thierry Reding 2022-07-04 440 return err;
42cee19a9f839f Thierry Reding 2022-07-04 441 }
42cee19a9f839f Thierry Reding 2022-07-04 442
42cee19a9f839f Thierry Reding 2022-07-04 443 err = tegra186_timer_tsc_init(tegra);
42cee19a9f839f Thierry Reding 2022-07-04 444 if (err < 0) {
42cee19a9f839f Thierry Reding 2022-07-04 445 dev_err(dev, "failed to register TSC counter: %d\n", err);
42cee19a9f839f Thierry Reding 2022-07-04 446 return err;
42cee19a9f839f Thierry Reding 2022-07-04 447 }
42cee19a9f839f Thierry Reding 2022-07-04 448
42cee19a9f839f Thierry Reding 2022-07-04 449 err = tegra186_timer_osc_init(tegra);
42cee19a9f839f Thierry Reding 2022-07-04 450 if (err < 0) {
42cee19a9f839f Thierry Reding 2022-07-04 451 dev_err(dev, "failed to register OSC counter: %d\n", err);
42cee19a9f839f Thierry Reding 2022-07-04 452 goto unregister_tsc;
42cee19a9f839f Thierry Reding 2022-07-04 453 }
42cee19a9f839f Thierry Reding 2022-07-04 454
42cee19a9f839f Thierry Reding 2022-07-04 455 err = tegra186_timer_usec_init(tegra);
42cee19a9f839f Thierry Reding 2022-07-04 456 if (err < 0) {
42cee19a9f839f Thierry Reding 2022-07-04 457 dev_err(dev, "failed to register USEC counter: %d\n", err);
42cee19a9f839f Thierry Reding 2022-07-04 458 goto unregister_osc;
42cee19a9f839f Thierry Reding 2022-07-04 459 }
42cee19a9f839f Thierry Reding 2022-07-04 460
42cee19a9f839f Thierry Reding 2022-07-04 461 return 0;
42cee19a9f839f Thierry Reding 2022-07-04 462
42cee19a9f839f Thierry Reding 2022-07-04 463 unregister_osc:
42cee19a9f839f Thierry Reding 2022-07-04 464 clocksource_unregister(&tegra->osc);
42cee19a9f839f Thierry Reding 2022-07-04 465 unregister_tsc:
42cee19a9f839f Thierry Reding 2022-07-04 466 clocksource_unregister(&tegra->tsc);
42cee19a9f839f Thierry Reding 2022-07-04 467 return err;
42cee19a9f839f Thierry Reding 2022-07-04 468 }
42cee19a9f839f Thierry Reding 2022-07-04 469
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-01-21 13:27 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-01-16 11:58 [PATCH 0/2] clocksource: fix Tegra234 SoC Watchdog Timer Pohsun Su
2024-01-16 11:58 ` [PATCH 1/2] clocksource/drivers/timer-tegra186: add WDIOC_GETTIMELEFT support Pohsun Su
2024-01-17 12:26 ` kernel test robot
2024-01-16 11:58 ` [PATCH 2/2] clocksource/drivers/timer-tegra186: fix watchdog self-pinging Pohsun Su
2024-01-21 13:27 ` kernel test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).