linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).