Skip to contentSkip to conversation

Consolidate and improve NVIDIA Tegra CPUIDLE driver(s)

PATCH Superseded Dmitry Osipenko 2 participants 52 messages Feb 12, 2020 – Feb 24, 2020

Subsystems (4)

v9 of 11 Superseded Latest is v11 →

lore
Share & tools
lore
#0 lore raw

v9 cover Consolidate and improve NVIDIA Tegra CPUIDLE driver(s)

Hello,

This series does the following:

1. Unifies Tegra20/30/114 drivers into a single driver and moves it out into common drivers/cpuidle/ directory.

2. Enables CPU cluster power-down idling state on Tegra30.

In the end there is a quite nice clean up of the Tegra CPUIDLE drivers and of the Tegra's arch code in general. Please apply, thanks!

!!!WARNING!!! This series was made on top of the cpufreq patches [1]. But it
should be fine as long as Thierry Reding would pick up this and the cpufreq patchsets via the Tegra tree, otherwise there will one minor merge-conflict.

[1] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=158206

Changelog:

v9: - Added acks from Peter De Schrijver.

- Added tested-by from Peter Geis, Jasper Korten and David Heidelberg who tested these patches on Ouya, TF300T and Nexus 7 devices.

- Temporarily dropped the "cpuidle: tegra: Support CPU cluster power-down state on Tegra30" patch because Michał Mirosław reported that it didn't work well on his TF300T. After some testing we found that changing a way in which firmware performs L2 cache maintenance helps, but later on we also found that the current v9 series works just fine without the extra firmware changes using recent linux-next and the reason why v8 didn't work before is still unknown (need more testing). So I decided that it will be better to postpone the dropped patch until we know for sure that it works well for everyone in every possible configuration.

- Rebased this series on top of recent linux-next, in a result dropped the "cpuidle: Avoid NULL dereference in cpuidle_driver_state_disabled()" patch because it's not needed anymore.

v8: - Rebased on recent linux-next, now making use of
cpuidle_driver_state_disabled(). Added new patch to make this new API usable by the updated Tegra cpuidle driver:

cpuidle: Avoid NULL dereference in cpuidle_driver_state_disabled()

- Added new patch to handle case where LP2 isn't available:

cpuidle: tegra: Disable CC6 state if LP2 unavailable

v7: - drivers/cpuidle/cpuidle-tegra.c now includes an explicit comment that
clarifies the new terminology that is used for naming of the idling states. This change was suggested by Peter De Schrijver in the review comment to v6. See the comment to struct tegra_idle_driver in the code.

- (!) This series is now based on top of the "NVIDIA Tegra20 CPUFreq driver major update" patchset. The conflict between these two series is trivial to resolve, but still it's worth to mention about that.

v6: - Addressed request from Thierry Reding to change the way patches are
organized by making changes in a more incremental manner.

- tegra_sleep_cpu() now checks for the secondary CPUs to be offline in the "Make outer_disable() open-coded" patch.

v5: - Rebased on a recent linux-next, fixed one minor conflict in Kconfig.

- Improved commit's message of the "Support CPU cluster power-down state on Tegra30" patch.

- The "Support CPU cluster power-down state on Tegra30" patch is also got split and now there is additional "Make outer_disable() open-coded" patch.

- Made minor cosmetic changes to the "Introduce unified driver for NVIDIA Tegra SoCs" patch by improving error message and renaming one variable.

v4: - Fixed compilation with !CONFIG_CACHE_L2X0 (and tested that it still
works).

- Replaced ktime_compare() with ktime_before() in the new driver, for consistency.

v3: - Addressed review comments that were made by Jon Hunter to v2 by
splitting patches into smaller (and simpler) chunks, better documenting changes in the commit messages and using proper error codes in the code.

Warnings are replaced with a useful error messages in the code of "Introduce unified driver for NVIDIA Tegra SoCs" patch.

Secondary CPUs parking timeout increased to 100ms because I found that it actually may happen to take more than 1ms if CPU is running on a *very* low frequency.

Added diagnostic messages that are reporting Flow Controller state when CPU parking fails.

Further polished cpuidle driver's code.

The coupled state entering is now aborted if there is a pending SGI (Software Generated Interrupt) because it will be lost after GIC's power-cycling. Like it was done by the old Tegra20 CPUIDLE driver.

v2: - Added patches to enable the new cpuidle driver in the defconfigs:

ARM: multi_v7_defconfig: Enable Tegra cpuidle driver
ARM: tegra: Enable Tegra cpuidle driver in tegra_defconfig

- Dropped patches that removed CPUIDLE_FLAG_TIMER_STOP from the idling states because that flag actually doesn't have any negative effects, but still is correct for the case of a local CPU timer on older Tegra SoCs:

cpuidle: tegra: Remove CPUIDLE_FLAG_TIMER_STOP from Tegra114/124 idle-state
cpuidle: tegra: Remove CPUIDLE_FLAG_TIMER_STOP from all states

- The "Add unified driver for NVIDIA Tegra SoCs" patch got more polish. Tegra30 and Terga114 states are now squashed into a single common C7 state (following Parker TRM terminology, see 17.2.2.2 Power Management States), more comments added, etc minor changes.

Dmitry Osipenko (17):
ARM: tegra: Compile sleep-tegra20/30.S unconditionally
ARM: tegra: Add tegra_pm_park_secondary_cpu()
ARM: tegra: Remove pen-locking from cpuidle-tegra20
ARM: tegra: Change tegra_set_cpu_in_lp2() type to void
ARM: tegra: Propagate error from tegra_idle_lp2_last()
ARM: tegra: Expose PM functions required for new cpuidle driver
ARM: tegra: Rename some of the newly exposed PM functions
ARM: tegra: Make outer_disable() open-coded
arm: tegra20: cpuidle: Handle case where secondary CPU hangs on
entering LP2
arm: tegra20: cpuidle: Make abort_flag atomic
arm: tegra20/30: cpuidle: Remove unnecessary memory barrier
cpuidle: Refactor and move out NVIDIA Tegra20 driver into
drivers/cpuidle
cpuidle: tegra: Squash Tegra30 driver into the common driver
cpuidle: tegra: Squash Tegra114 driver into the common driver
cpuidle: tegra: Disable CC6 state if LP2 unavailable
ARM: multi_v7_defconfig: Enable Tegra cpuidle driver
ARM: tegra: Enable Tegra cpuidle driver in tegra_defconfig

 arch/arm/configs/multi_v7_defconfig           |   1 +
 arch/arm/configs/tegra_defconfig              |   1 +
 arch/arm/mach-tegra/Makefile                  |  19 +-
 arch/arm/mach-tegra/cpuidle-tegra114.c        |  89 ----
 arch/arm/mach-tegra/cpuidle-tegra20.c         | 212 ----------
 arch/arm/mach-tegra/cpuidle-tegra30.c         | 132 ------
 arch/arm/mach-tegra/cpuidle.c                 |  50 ---
 arch/arm/mach-tegra/cpuidle.h                 |  21 -
 arch/arm/mach-tegra/irq.c                     |   3 +-
 arch/arm/mach-tegra/pm.c                      |  54 ++-
 arch/arm/mach-tegra/pm.h                      |   4 -
 arch/arm/mach-tegra/reset-handler.S           |  11 -
 arch/arm/mach-tegra/reset.h                   |   9 +-
 arch/arm/mach-tegra/sleep-tegra20.S           | 170 --------
 arch/arm/mach-tegra/sleep-tegra30.S           |   6 +-
 arch/arm/mach-tegra/sleep.h                   |  15 -
 arch/arm/mach-tegra/tegra.c                   |   7 +-
 drivers/cpuidle/Kconfig.arm                   |   8 +
 drivers/cpuidle/Makefile                      |   1 +
 drivers/cpuidle/cpuidle-tegra.c               | 389 ++++++++++++++++++
 include/soc/tegra/cpuidle.h                   |   2 +-
 .../mach-tegra => include/soc/tegra}/irq.h    |   8 +-
 include/soc/tegra/pm.h                        |  31 ++
 23 files changed, 482 insertions(+), 761 deletions(-)
 delete mode 100644 arch/arm/mach-tegra/cpuidle-tegra114.c
 delete mode 100644 arch/arm/mach-tegra/cpuidle-tegra20.c
 delete mode 100644 arch/arm/mach-tegra/cpuidle-tegra30.c
 delete mode 100644 arch/arm/mach-tegra/cpuidle.c
 delete mode 100644 arch/arm/mach-tegra/cpuidle.h
 create mode 100644 drivers/cpuidle/cpuidle-tegra.c
 rename {arch/arm/mach-tegra => include/soc/tegra}/irq.h (59%)
Signature · 1 line
2.24.0
#1 lore raw

PATCH v9 1/17 ARM: tegra: Compile sleep-tegra20/30.S unconditionally

The sleep-tegra*.S provides functionality required for suspend/resume and CPU hotplugging. The new unified CPUIDLE driver will support multiple hardware generations starting from Terga20 and ending with Tegra124, the driver will utilize functions that are provided by the assembly and thus it is cleaner to compile that code without any build-dependencies in order to avoid churning with #ifdef's.

---
 arch/arm/mach-tegra/Makefile | 6 ++----
 arch/arm/mach-tegra/sleep.h  | 2 --
 2 files changed, 2 insertions(+), 6 deletions(-)
arch/arm/mach-tegra/Makefile +2 -4
index 6c1dff2eccc2..965862608ff6 100644
@@ -8,13 +8,13 @@ obj-y					+= reset.o
 obj-y					+= reset-handler.o
 obj-y					+= sleep.o
 obj-y					+= tegra.o
+obj-y					+= sleep-tegra20.o
+obj-y					+= sleep-tegra30.o
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= sleep-tegra20.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= pm-tegra20.o
 ifeq ($(CONFIG_CPU_IDLE),y)
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= cpuidle-tegra20.o
 endif
-obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= sleep-tegra30.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= pm-tegra30.o
 ifeq ($(CONFIG_CPU_IDLE),y)
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= cpuidle-tegra30.o
@@ -22,12 +22,10 @@ endif
 obj-$(CONFIG_SMP)			+= platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
 
-obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= sleep-tegra30.o
 obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= pm-tegra30.o
 ifeq ($(CONFIG_CPU_IDLE),y)
 obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= cpuidle-tegra114.o
 endif
-obj-$(CONFIG_ARCH_TEGRA_124_SOC)	+= sleep-tegra30.o
 obj-$(CONFIG_ARCH_TEGRA_124_SOC)	+= pm-tegra30.o
 ifeq ($(CONFIG_CPU_IDLE),y)
 obj-$(CONFIG_ARCH_TEGRA_124_SOC)	+= cpuidle-tegra114.o
arch/arm/mach-tegra/sleep.h +0 -2
index 78ef32a907c8..63e2205cbc82 100644
@@ -120,10 +120,8 @@ void tegra_resume(void);
 int tegra_sleep_cpu_finish(unsigned long);
 void tegra_disable_clean_inv_dcache(u32 flag);
 
-#ifdef CONFIG_HOTPLUG_CPU
 void tegra20_hotplug_shutdown(void);
 void tegra30_hotplug_shutdown(void);
-#endif
 
 void tegra20_cpu_shutdown(int cpu);
 int tegra20_cpu_is_resettable_soon(void);
Signature · 1 line
2.24.0
#2 lore raw

PATCH v9 2/17 ARM: tegra: Add tegra_pm_park_secondary_cpu()

In reply to Dmitry Osipenko

This function resembles tegra_cpu_die() of the hotplug code, but this variant is more suitable to be used for CPU PM because it's made specifically to be used by cpu_suspend(). In short this function puts secondary CPU offline, it will be used by the new CPUIDLE driver.

---
 arch/arm/mach-tegra/pm.c | 14 ++++++++++++++
 arch/arm/mach-tegra/pm.h |  5 +++++
 2 files changed, 19 insertions(+)
arch/arm/mach-tegra/pm.c +14 -0
index 3cab81b82866..f5ff3dd1dd81 100644
@@ -436,4 +436,18 @@ void __init tegra_init_suspend(void)
 
 	suspend_set_ops(&tegra_suspend_ops);
 }
+
+int tegra_pm_park_secondary_cpu(unsigned long cpu)
+{
+	if (cpu > 0) {
+		tegra_disable_clean_inv_dcache(TEGRA_FLUSH_CACHE_LOUIS);
+
+		if (tegra_get_chip_id() == TEGRA20)
+			tegra20_hotplug_shutdown();
+		else
+			tegra30_hotplug_shutdown();
+	}
+
+	return -EINVAL;
+}
 #endif
arch/arm/mach-tegra/pm.h +5 -0
index 569151b3edc0..9a790f00237f 100644
@@ -31,8 +31,13 @@ extern void (*tegra_tear_down_cpu)(void);
 
 #ifdef CONFIG_PM_SLEEP
 void tegra_init_suspend(void);
+int tegra_pm_park_secondary_cpu(unsigned long cpu);
 #else
 static inline void tegra_init_suspend(void) {}
+static inline int tegra_pm_park_secondary_cpu(unsigned long cpu)
+{
+	return -ENOTSUPP;
+}
 #endif
 
 #endif /* _MACH_TEGRA_PM_H_ */
Signature · 1 line
2.24.0
#3 lore raw

PATCH v9 3/17 ARM: tegra: Remove pen-locking from cpuidle-tegra20

In reply to Dmitry Osipenko

Pen-locking is meant to block CPU0 if CPU1 wakes up during of entering into LP2 because of some interrupt firing up, preventing unnecessary LP2 enter that will be resumed immediately. Apparently this case doesn't happen often in practice, I checked how often it takes place and found that after ~20 hours of browsing web, managing email, watching videos and idling (15+ hours) there is only a dozen of early LP2 entering abortions and they all happened while device was idling. Thus let's remove the pen-locking and make LP2 entering uninterruptible, simplifying code quite a lot. This will also become very handy for the upcoming unified cpuidle driver, allowing to have a common LP2 code-path across of different hardware generations.

---
 arch/arm/mach-tegra/cpuidle-tegra20.c |  46 +------
 arch/arm/mach-tegra/pm.c              |   7 --
 arch/arm/mach-tegra/pm.h              |   1 -
 arch/arm/mach-tegra/reset-handler.S   |  11 --
 arch/arm/mach-tegra/reset.h           |   9 +-
 arch/arm/mach-tegra/sleep-tegra20.S   | 170 --------------------------
 arch/arm/mach-tegra/sleep.h           |  12 --
 7 files changed, 5 insertions(+), 251 deletions(-)
arch/arm/mach-tegra/cpuidle-tegra20.c +3 -43
index 69f3fa270fbe..f7d5041e73cc 100644
@@ -15,6 +15,7 @@
 #include <linux/cpuidle.h>
 #include <linux/cpu_pm.h>
 #include <linux/kernel.h>
+#include <linux/ktime.h>
 #include <linux/module.h>
 
 #include <soc/tegra/flowctrl.h>
@@ -65,28 +66,8 @@ static struct cpuidle_driver tegra_idle_driver = {
 
 #ifdef CONFIG_PM_SLEEP
 #ifdef CONFIG_SMP
-static int tegra20_reset_sleeping_cpu_1(void)
-{
-	int ret = 0;
-
-	tegra_pen_lock();
-
-	if (readb(tegra20_cpu1_resettable_status) == CPU_RESETTABLE)
-		tegra20_cpu_shutdown(1);
-	else
-		ret = -EINVAL;
-
-	tegra_pen_unlock();
-
-	return ret;
-}
-
 static void tegra20_wake_cpu1_from_reset(void)
 {
-	tegra_pen_lock();
-
-	tegra20_cpu_clear_resettable();
-
 	/* enable cpu clock on cpu */
 	tegra_enable_cpu_clock(1);
 
@@ -95,39 +76,20 @@ static void tegra20_wake_cpu1_from_reset(void)
 
 	/* unhalt the cpu */
 	flowctrl_write_cpu_halt(1, 0);
-
-	tegra_pen_unlock();
-}
-
-static int tegra20_reset_cpu_1(void)
-{
-	if (!cpu_online(1) || !tegra20_reset_sleeping_cpu_1())
-		return 0;
-
-	tegra20_wake_cpu1_from_reset();
-	return -EBUSY;
 }
 #else
 static inline void tegra20_wake_cpu1_from_reset(void)
 {
 }
-
-static inline int tegra20_reset_cpu_1(void)
-{
-	return 0;
-}
 #endif
 
 static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
 					   struct cpuidle_driver *drv,
 					   int index)
 {
-	while (tegra20_cpu_is_resettable_soon())
+	while (!tegra_cpu_rail_off_ready())
 		cpu_relax();
 
-	if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready())
-		return false;
-
 	tegra_idle_lp2_last();
 
 	if (cpu_online(1))
@@ -141,9 +103,7 @@ static bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev,
 					 struct cpuidle_driver *drv,
 					 int index)
 {
-	cpu_suspend(0, tegra20_sleep_cpu_secondary_finish);
-
-	tegra20_cpu_clear_resettable();
+	cpu_suspend(dev->cpu, tegra_pm_park_secondary_cpu);
 
 	return true;
 }
arch/arm/mach-tegra/pm.c +0 -7
index f5ff3dd1dd81..1ff499068bb1 100644
@@ -137,18 +137,11 @@ bool tegra_set_cpu_in_lp2(void)
 
 	if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask))
 		last_cpu = true;
-	else if (tegra_get_chip_id() == TEGRA20 && phy_cpu_id == 1)
-		tegra20_cpu_set_resettable_soon();
 
 	spin_unlock(&tegra_lp2_lock);
 	return last_cpu;
 }
 
-int tegra_cpu_do_idle(void)
-{
-	return cpu_do_idle();
-}
-
 static int tegra_sleep_cpu(unsigned long v2p)
 {
 	/*
arch/arm/mach-tegra/pm.h +0 -1
index 9a790f00237f..b9cc12222bb1 100644
@@ -25,7 +25,6 @@ void tegra30_sleep_core_init(void);
 
 void tegra_clear_cpu_in_lp2(void);
 bool tegra_set_cpu_in_lp2(void);
-int tegra_cpu_do_idle(void);
 void tegra_idle_lp2_last(void);
 extern void (*tegra_tear_down_cpu)(void);
 
arch/arm/mach-tegra/reset-handler.S +0 -11
index e3f34815c9da..53123ae4ac3b 100644
@@ -183,17 +183,6 @@ after_errata:
 	bleq	__die				@ CPU not present (to OS)
 #endif
 
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-	/* Are we on Tegra20? */
-	cmp	r6, #TEGRA20
-	bne	1f
-	/* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
-	mov	r0, #CPU_NOT_RESETTABLE
-	cmp	r10, #0
-	strbne	r0, [r12, #RESET_DATA(RESETTABLE_STATUS)]
-1:
-#endif
-
 	/* Waking up from LP1? */
 	ldr	r8, [r12, #RESET_DATA(MASK_LP1)]
 	tst	r8, r11				@ if in_lp1
arch/arm/mach-tegra/reset.h +2 -7
index a4cfc08159f6..51265592cb1a 100644
@@ -16,9 +16,8 @@
 #define TEGRA_RESET_STARTUP_SECONDARY	3
 #define TEGRA_RESET_STARTUP_LP2		4
 #define TEGRA_RESET_STARTUP_LP1		5
-#define TEGRA_RESET_RESETTABLE_STATUS	6
-#define TEGRA_RESET_TF_PRESENT		7
-#define TEGRA_RESET_DATA_SIZE		8
+#define TEGRA_RESET_TF_PRESENT		6
+#define TEGRA_RESET_DATA_SIZE		7
 
 #define RESET_DATA(x)	((TEGRA_RESET_##x)*4)
 
@@ -42,10 +41,6 @@ void __tegra_cpu_reset_handler_end(void);
 	(IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
 	((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP2] - \
 	 (u32)__tegra_cpu_reset_handler_start)))
-#define tegra20_cpu1_resettable_status \
-	(IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
-	((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_RESETTABLE_STATUS] - \
-	 (u32)__tegra_cpu_reset_handler_start)))
 #endif
 
 #define tegra_cpu_reset_handler_offset \
arch/arm/mach-tegra/sleep-tegra20.S +0 -170

194 lines not on this page · raw message

arch/arm/mach-tegra/sleep.h +0 -12
index 63e2205cbc82..4978def9db46 100644
@@ -114,8 +114,6 @@
 .endm
 
 #else
-void tegra_pen_lock(void);
-void tegra_pen_unlock(void);
 void tegra_resume(void);
 int tegra_sleep_cpu_finish(unsigned long);
 void tegra_disable_clean_inv_dcache(u32 flag);
@@ -123,16 +121,6 @@ void tegra_disable_clean_inv_dcache(u32 flag);
 void tegra20_hotplug_shutdown(void);
 void tegra30_hotplug_shutdown(void);
 
-void tegra20_cpu_shutdown(int cpu);
-int tegra20_cpu_is_resettable_soon(void);
-void tegra20_cpu_clear_resettable(void);
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-void tegra20_cpu_set_resettable_soon(void);
-#else
-static inline void tegra20_cpu_set_resettable_soon(void) {}
-#endif
-
-int tegra20_sleep_cpu_secondary_finish(unsigned long);
 void tegra20_tear_down_cpu(void);
 int tegra30_sleep_cpu_secondary_finish(unsigned long);
 void tegra30_tear_down_cpu(void);
Signature · 1 line
2.24.0
Acked-by on v9 3/17
#4 lore raw

Re: [PATCH v9 03/17] ARM: tegra: Remove pen-locking from cpuidle-tegra20

Quoted 12 lines · Dmitry Osipenko

Pen-locking is meant to block CPU0 if CPU1 wakes up during of entering into LP2 because of some interrupt firing up, preventing unnecessary LP2 enter that will be resumed immediately. Apparently this case doesn't happen often in practice, I checked how often it takes place and found that after ~20 hours of browsing web, managing email, watching videos and idling (15+ hours) there is only a dozen of early LP2 entering abortions and they all happened while device was idling. Thus let's remove the pen-locking and make LP2 entering uninterruptible, simplifying code quite a lot. This will also become very handy for the upcoming unified cpuidle driver, allowing to have a common LP2 code-path across of different hardware generations.

Quoted 5 lines
#5 lore raw

PATCH v9 4/17 ARM: tegra: Change tegra_set_cpu_in_lp2() type to void

In reply to Dmitry Osipenko

The Tegra30 CPUIDLE driver has intention to check whether primary CPU was the last CPU that entered LP2 (CC6) idle-state, but that functionality never got utilized because driver never supported the CC6 state for the case where any secondary CPU is online. The new cpuidle driver will properly support CC6 on Tegra30, including the case where secondary CPUs are online, and that knowledge about what CPUs entered into CC6 won't be needed at all because new driver will use different approach by making use of the coupled idle-state and explicitly parking secondary CPUs before entering into CC6. Thus this patch is just a minor cleanup change.

---
 arch/arm/mach-tegra/cpuidle-tegra30.c | 14 ++++----------
 arch/arm/mach-tegra/pm.c              |  8 +-------
 arch/arm/mach-tegra/pm.h              |  2 +-
 3 files changed, 6 insertions(+), 18 deletions(-)
arch/arm/mach-tegra/cpuidle-tegra30.c +4 -10
index c6128526877d..a3ce8dabfe18 100644
@@ -98,22 +98,16 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
 			    int index)
 {
 	bool entered_lp2 = false;
-	bool last_cpu;
 
 	local_fiq_disable();
 
-	last_cpu = tegra_set_cpu_in_lp2();
+	tegra_set_cpu_in_lp2();
 	cpu_pm_enter();
 
-	if (dev->cpu == 0) {
-		if (last_cpu)
-			entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv,
-								     index);
-		else
-			cpu_do_idle();
-	} else {
+	if (dev->cpu == 0)
+		entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv, index);
+	else
 		entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index);
-	}
 
 	cpu_pm_exit();
 	tegra_clear_cpu_in_lp2();
arch/arm/mach-tegra/pm.c +1 -7
index 1ff499068bb1..a72f9a2d3cb7 100644
@@ -123,11 +123,9 @@ void tegra_clear_cpu_in_lp2(void)
 	spin_unlock(&tegra_lp2_lock);
 }
 
-bool tegra_set_cpu_in_lp2(void)
+void tegra_set_cpu_in_lp2(void)
 {
 	int phy_cpu_id = cpu_logical_map(smp_processor_id());
-	bool last_cpu = false;
-	cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask;
 	u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
 
 	spin_lock(&tegra_lp2_lock);
@@ -135,11 +133,7 @@ bool tegra_set_cpu_in_lp2(void)
 	BUG_ON((*cpu_in_lp2 & BIT(phy_cpu_id)));
 	*cpu_in_lp2 |= BIT(phy_cpu_id);
 
-	if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask))
-		last_cpu = true;
-
 	spin_unlock(&tegra_lp2_lock);
-	return last_cpu;
 }
 
 static int tegra_sleep_cpu(unsigned long v2p)
arch/arm/mach-tegra/pm.h +1 -1
index b9cc12222bb1..2c294f6365c0 100644
@@ -24,7 +24,7 @@ void tegra30_lp1_iram_hook(void);
 void tegra30_sleep_core_init(void);
 
 void tegra_clear_cpu_in_lp2(void);
-bool tegra_set_cpu_in_lp2(void);
+void tegra_set_cpu_in_lp2(void);
 void tegra_idle_lp2_last(void);
 extern void (*tegra_tear_down_cpu)(void);
 
Signature · 1 line
2.24.0
Acked-by on v9 4/17
#6 lore raw

Re: [PATCH v9 04/17] ARM: tegra: Change tegra_set_cpu_in_lp2() type to void

Quoted 10 lines · Dmitry Osipenko

The Tegra30 CPUIDLE driver has intention to check whether primary CPU was the last CPU that entered LP2 (CC6) idle-state, but that functionality never got utilized because driver never supported the CC6 state for the case where any secondary CPU is online. The new cpuidle driver will properly support CC6 on Tegra30, including the case where secondary CPUs are online, and that knowledge about what CPUs entered into CC6 won't be needed at all because new driver will use different approach by making use of the coupled idle-state and explicitly parking secondary CPUs before entering into CC6. Thus this patch is just a minor cleanup change.

Quoted 7 lines
---
 arch/arm/mach-tegra/cpuidle-tegra30.c | 14 ++++----------

Mind to move to drivers/cpuidle ?

Quoted 80 lines
 arch/arm/mach-tegra/pm.c              |  8 +-------
 arch/arm/mach-tegra/pm.h              |  2 +-
 3 files changed, 6 insertions(+), 18 deletions(-)
arch/arm/mach-tegra/cpuidle-tegra30.c +4 -10
index c6128526877d..a3ce8dabfe18 100644
@@ -98,22 +98,16 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
 			    int index)
 {
 	bool entered_lp2 = false;
-	bool last_cpu;
 
 	local_fiq_disable();
 
-	last_cpu = tegra_set_cpu_in_lp2();
+	tegra_set_cpu_in_lp2();
 	cpu_pm_enter();
 
-	if (dev->cpu == 0) {
-		if (last_cpu)
-			entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv,
-								     index);
-		else
-			cpu_do_idle();
-	} else {
+	if (dev->cpu == 0)
+		entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv, index);
+	else
 		entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index);
-	}
 
 	cpu_pm_exit();
 	tegra_clear_cpu_in_lp2();
arch/arm/mach-tegra/pm.c +1 -7
index 1ff499068bb1..a72f9a2d3cb7 100644
@@ -123,11 +123,9 @@ void tegra_clear_cpu_in_lp2(void)
 	spin_unlock(&tegra_lp2_lock);
 }
 
-bool tegra_set_cpu_in_lp2(void)
+void tegra_set_cpu_in_lp2(void)
 {
 	int phy_cpu_id = cpu_logical_map(smp_processor_id());
-	bool last_cpu = false;
-	cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask;
 	u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
 
 	spin_lock(&tegra_lp2_lock);
@@ -135,11 +133,7 @@ bool tegra_set_cpu_in_lp2(void)
 	BUG_ON((*cpu_in_lp2 & BIT(phy_cpu_id)));
 	*cpu_in_lp2 |= BIT(phy_cpu_id);
 
-	if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask))
-		last_cpu = true;
-
 	spin_unlock(&tegra_lp2_lock);
-	return last_cpu;
 }
 
 static int tegra_sleep_cpu(unsigned long v2p)
arch/arm/mach-tegra/pm.h +1 -1
index b9cc12222bb1..2c294f6365c0 100644
@@ -24,7 +24,7 @@ void tegra30_lp1_iram_hook(void);
 void tegra30_sleep_core_init(void);
 
 void tegra_clear_cpu_in_lp2(void);
-bool tegra_set_cpu_in_lp2(void);
+void tegra_set_cpu_in_lp2(void);
 void tegra_idle_lp2_last(void);
 extern void (*tegra_tear_down_cpu)(void);
 
Signature · 1 line
2.24.0
Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#7 lore raw

PATCH v9 5/17 ARM: tegra: Propagate error from tegra_idle_lp2_last()

In reply to Dmitry Osipenko

Technically cpu_suspend() may fail and it's never good to lose information about failure. For example things like cpuidle core could correctly sample idling time in the case of failure.

---
 arch/arm/mach-tegra/cpuidle-tegra20.c | 6 ++++--
 arch/arm/mach-tegra/cpuidle-tegra30.c | 4 +---
 arch/arm/mach-tegra/pm.c              | 8 ++++++--
 arch/arm/mach-tegra/pm.h              | 2 +-
 4 files changed, 12 insertions(+), 8 deletions(-)
arch/arm/mach-tegra/cpuidle-tegra20.c +4 -2
index f7d5041e73cc..9789541adb7d 100644
@@ -87,15 +87,17 @@ static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
 					   struct cpuidle_driver *drv,
 					   int index)
 {
+	bool ret;
+
 	while (!tegra_cpu_rail_off_ready())
 		cpu_relax();
 
-	tegra_idle_lp2_last();
+	ret = !tegra_idle_lp2_last();
 
 	if (cpu_online(1))
 		tegra20_wake_cpu1_from_reset();
 
-	return true;
+	return ret;
 }
 
 #ifdef CONFIG_SMP
arch/arm/mach-tegra/cpuidle-tegra30.c +1 -3
index a3ce8dabfe18..17cbd118abee 100644
@@ -68,9 +68,7 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
 		return false;
 	}
 
-	tegra_idle_lp2_last();
-
-	return true;
+	return !tegra_idle_lp2_last();
 }
 
 #ifdef CONFIG_SMP
arch/arm/mach-tegra/pm.c +6 -2
index a72f9a2d3cb7..a094acaca307 100644
@@ -189,14 +189,16 @@ static void tegra_pm_set(enum tegra_suspend_mode mode)
 	tegra_pmc_enter_suspend_mode(mode);
 }
 
-void tegra_idle_lp2_last(void)
+int tegra_idle_lp2_last(void)
 {
+	int err;
+
 	tegra_pm_set(TEGRA_SUSPEND_LP2);
 
 	cpu_cluster_pm_enter();
 	suspend_cpu_complex();
 
-	cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+	err = cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
 
 	/*
 	 * Resume L2 cache if it wasn't re-enabled early during resume,
@@ -208,6 +210,8 @@ void tegra_idle_lp2_last(void)
 
 	restore_cpu_complex();
 	cpu_cluster_pm_exit();
+
+	return err;
 }
 
 enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
arch/arm/mach-tegra/pm.h +1 -1
index 2c294f6365c0..7d72f31dee77 100644
@@ -25,7 +25,7 @@ void tegra30_sleep_core_init(void);
 
 void tegra_clear_cpu_in_lp2(void);
 void tegra_set_cpu_in_lp2(void);
-void tegra_idle_lp2_last(void);
+int tegra_idle_lp2_last(void);
 extern void (*tegra_tear_down_cpu)(void);
 
 #ifdef CONFIG_PM_SLEEP
Signature · 1 line
2.24.0
#8 lore raw

Re: [PATCH v9 05/17] ARM: tegra: Propagate error from tegra_idle_lp2_last()

Quoted 10 lines · Dmitry Osipenko

Technically cpu_suspend() may fail and it's never good to lose information about failure. For example things like cpuidle core could correctly sample idling time in the case of failure.

---

[ ... ]

arch/arm/mach-tegra/pm.c void tegra_idle_lp2_last(void) · line 211

Quoted 11 lines
arch/arm/mach-tegra/pm.c +1 -1
 	cpu_cluster_pm_enter();
 	suspend_cpu_complex();
 
-	cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+	err = cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
 
 	/*
 	 * Resume L2 cache if it wasn't re-enabled early during resume,
@@ -208,6 +210,8 @@ void tegra_idle_lp2_last(void)
 
 	restore_cpu_complex();

If the cpu_suspend fails, does restore_cpu_complex() need to be called ?

Quoted 4 lines
arch/arm/mach-tegra/pm.c +2 -0
 	cpu_cluster_pm_exit();
+
+	return err;
 }

[ ... ]

Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#9 lore raw

Re: [PATCH v9 05/17] ARM: tegra: Propagate error from tegra_idle_lp2_last()

21.02.2020 18:16, Daniel Lezcano пишет:

Quoted 20 lines · Dmitry Osipenko
Quoted 10 lines

Technically cpu_suspend() may fail and it's never good to lose information about failure. For example things like cpuidle core could correctly sample idling time in the case of failure.

---

[ ... ]

Quoted 6 lines
arch/arm/mach-tegra/pm.c +1 -1
 	cpu_cluster_pm_enter();
 	suspend_cpu_complex();
 
-	cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+	err = cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
Quoted 7 lines

arch/arm/mach-tegra/pm.c void tegra_idle_lp2_last(void) · line 211

Quoted 5 lines
arch/arm/mach-tegra/pm.c +0 -0
 	/*
 	 * Resume L2 cache if it wasn't re-enabled early during resume,
@@ -208,6 +210,8 @@ void tegra_idle_lp2_last(void)
 
 	restore_cpu_complex();

If the cpu_suspend fails, does restore_cpu_complex() need to be called ?

Yes, because suspend_cpu_complex() didn't fail. I don't see any reason why restore_cpu_complex() shouldn't be called, please clarify yours thought.

#10 lore raw

Re: [PATCH v9 05/17] ARM: tegra: Propagate error from tegra_idle_lp2_last()

Quoted 25 lines · Dmitry Osipenko

21.02.2020 18:16, Daniel Lezcano пишет:

Quoted 24 lines · Dmitry Osipenko
Quoted 10 lines

Technically cpu_suspend() may fail and it's never good to lose information about failure. For example things like cpuidle core could correctly sample idling time in the case of failure.

---

[ ... ]

Quoted 10 lines
arch/arm/mach-tegra/pm.c +1 -1
 	cpu_cluster_pm_enter();
 	suspend_cpu_complex();
 
-	cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+	err = cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
 
 	/*
 	 * Resume L2 cache if it wasn't re-enabled early during resume,
@@ -208,6 +210,8 @@ void tegra_idle_lp2_last(void)
 
Quoted 6 lines
Quoted 3 lines

arch/arm/mach-tegra/pm.c void tegra_idle_lp2_last(void) · line 211

Quoted 1 line
arch/arm/mach-tegra/pm.c +0 -0
 	restore_cpu_complex();

If the cpu_suspend fails, does restore_cpu_complex() need to be called ?

Yes, because suspend_cpu_complex() didn't fail. I don't see any reason why restore_cpu_complex() shouldn't be called, please clarify yours thought.

If the suspend fails, the power down does not happen, thus the logic is not lost and then it not necessary to restore something which has not been lost.

I don't know the hardware details, so that may be partially correct.

Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#11 lore raw

Re: [PATCH v9 05/17] ARM: tegra: Propagate error from tegra_idle_lp2_last()

21.02.2020 20:40, Daniel Lezcano пишет:

Quoted 30 lines · Dmitry Osipenko
Quoted 29 lines

21.02.2020 18:16, Daniel Lezcano пишет:

Quoted 27 lines · Dmitry Osipenko
Quoted 10 lines

Technically cpu_suspend() may fail and it's never good to lose information about failure. For example things like cpuidle core could correctly sample idling time in the case of failure.

---

[ ... ]

arch/arm/mach-tegra/pm.c void tegra_idle_lp2_last(void) · line 211

Quoted 11 lines
arch/arm/mach-tegra/pm.c +1 -1
 	cpu_cluster_pm_enter();
 	suspend_cpu_complex();
 
-	cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+	err = cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
 
 	/*
 	 * Resume L2 cache if it wasn't re-enabled early during resume,
@@ -208,6 +210,8 @@ void tegra_idle_lp2_last(void)
 
 	restore_cpu_complex();

If the cpu_suspend fails, does restore_cpu_complex() need to be called ?

Quoted 7 lines
Quoted 2 lines

Yes, because suspend_cpu_complex() didn't fail. I don't see any reason why restore_cpu_complex() shouldn't be called, please clarify yours thought.

If the suspend fails, the power down does not happen, thus the logic is not lost and then it not necessary to restore something which has not been lost.

I don't know the hardware details, so that may be partially correct.

At quick glance, the restore_cpu_complex() is only used for restoring the GIC's state on Tegra.

I don't think it's really worth the effort to handle restore_cpu_complex() specially in a case of the error condition because the chance that the error will ever happen is very small and restoring the cluster's state won't cause any trouble in that case.

Let's keep this patch as-is for simplicity :)

#12 lore raw

Re: [PATCH v9 05/17] ARM: tegra: Propagate error from tegra_idle_lp2_last()

Quoted 42 lines · Dmitry Osipenko

21.02.2020 20:40, Daniel Lezcano пишет:

Quoted 30 lines · Dmitry Osipenko
Quoted 29 lines

21.02.2020 18:16, Daniel Lezcano пишет:

Quoted 27 lines · Dmitry Osipenko
Quoted 10 lines

Technically cpu_suspend() may fail and it's never good to lose information about failure. For example things like cpuidle core could correctly sample idling time in the case of failure.

---

[ ... ]

arch/arm/mach-tegra/pm.c void tegra_idle_lp2_last(void) · line 211

Quoted 11 lines
arch/arm/mach-tegra/pm.c +1 -1
 	cpu_cluster_pm_enter();
 	suspend_cpu_complex();
 
-	cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+	err = cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
 
 	/*
 	 * Resume L2 cache if it wasn't re-enabled early during resume,
@@ -208,6 +210,8 @@ void tegra_idle_lp2_last(void)
 
 	restore_cpu_complex();

If the cpu_suspend fails, does restore_cpu_complex() need to be called ?

Quoted 7 lines
Quoted 2 lines

Yes, because suspend_cpu_complex() didn't fail. I don't see any reason why restore_cpu_complex() shouldn't be called, please clarify yours thought.

If the suspend fails, the power down does not happen, thus the logic is not lost and then it not necessary to restore something which has not been lost.

I don't know the hardware details, so that may be partially correct.

At quick glance, the restore_cpu_complex() is only used for restoring the GIC's state on Tegra.

Quoted 6 lines

I don't think it's really worth the effort to handle restore_cpu_complex() specially in a case of the error condition because the chance that the error will ever happen is very small and restoring the cluster's state won't cause any trouble in that case.

Let's keep this patch as-is for simplicity :)

Yep, not a big deal.

Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#13 lore raw

PATCH v9 6/17 ARM: tegra: Expose PM functions required for new cpuidle driver

In reply to Dmitry Osipenko

The upcoming unified CPUIDLE driver will be added to the drivers/cpuidle/ directory and it will require all these exposed Tegra PM-core functions.

---
 arch/arm/mach-tegra/cpuidle-tegra114.c        |  3 +-
 arch/arm/mach-tegra/cpuidle-tegra20.c         |  2 +-
 arch/arm/mach-tegra/cpuidle-tegra30.c         |  3 +-
 arch/arm/mach-tegra/irq.c                     |  3 +-
 arch/arm/mach-tegra/pm.h                      |  8 -----
 arch/arm/mach-tegra/sleep.h                   |  1 -
 arch/arm/mach-tegra/tegra.c                   |  1 -
 .../mach-tegra => include/soc/tegra}/irq.h    |  8 +++--
 include/soc/tegra/pm.h                        | 31 +++++++++++++++++++
 9 files changed, 43 insertions(+), 17 deletions(-)
 rename {arch/arm/mach-tegra => include/soc/tegra}/irq.h (59%)
arch/arm/mach-tegra/cpuidle-tegra114.c +2 -1
index 5118f777fd66..2d8527837aeb 100644
@@ -12,13 +12,14 @@
 
 #include <linux/firmware/trusted_foundations.h>
 
+#include <soc/tegra/pm.h>
+
 #include <asm/cpuidle.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 #include <asm/psci.h>
 
 #include "cpuidle.h"
-#include "pm.h"
 #include "sleep.h"
 
 #ifdef CONFIG_PM_SLEEP
arch/arm/mach-tegra/cpuidle-tegra20.c +1 -1
index 9789541adb7d..fdfe92068e38 100644
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 
 #include <soc/tegra/flowctrl.h>
+#include <soc/tegra/pm.h>
 
 #include <asm/cpuidle.h>
 #include <asm/smp_plat.h>
@@ -27,7 +28,6 @@
 #include "cpuidle.h"
 #include "iomap.h"
 #include "irq.h"
-#include "pm.h"
 #include "reset.h"
 #include "sleep.h"
 
arch/arm/mach-tegra/cpuidle-tegra30.c +2 -1
index 17cbd118abee..3e91c29891f7 100644
@@ -17,12 +17,13 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 
+#include <soc/tegra/pm.h>
+
 #include <asm/cpuidle.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 
 #include "cpuidle.h"
-#include "pm.h"
 #include "sleep.h"
 
 #ifdef CONFIG_PM_SLEEP
arch/arm/mach-tegra/irq.c +2 -1
index ace7a390b5fe..4e1ee70b2a3f 100644
@@ -18,9 +18,10 @@
 #include <linux/of.h>
 #include <linux/syscore_ops.h>
 
+#include <soc/tegra/irq.h>
+
 #include "board.h"
 #include "iomap.h"
-#include "irq.h"
 
 #define SGI_MASK 0xFFFF
 
arch/arm/mach-tegra/pm.h +0 -8
index 7d72f31dee77..81525f5f4a44 100644
@@ -23,20 +23,12 @@ void tegra20_sleep_core_init(void);
 void tegra30_lp1_iram_hook(void);
 void tegra30_sleep_core_init(void);
 
-void tegra_clear_cpu_in_lp2(void);
-void tegra_set_cpu_in_lp2(void);
-int tegra_idle_lp2_last(void);
 extern void (*tegra_tear_down_cpu)(void);
 
 #ifdef CONFIG_PM_SLEEP
 void tegra_init_suspend(void);
-int tegra_pm_park_secondary_cpu(unsigned long cpu);
 #else
 static inline void tegra_init_suspend(void) {}
-static inline int tegra_pm_park_secondary_cpu(unsigned long cpu)
-{
-	return -ENOTSUPP;
-}
 #endif
 
 #endif /* _MACH_TEGRA_PM_H_ */
arch/arm/mach-tegra/sleep.h +0 -1
index 4978def9db46..4718a3cb45a1 100644
@@ -122,7 +122,6 @@ void tegra20_hotplug_shutdown(void);
 void tegra30_hotplug_shutdown(void);
 
 void tegra20_tear_down_cpu(void);
-int tegra30_sleep_cpu_secondary_finish(unsigned long);
 void tegra30_tear_down_cpu(void);
 
 #endif
arch/arm/mach-tegra/tegra.c +0 -1
index 1e3b85923ca3..79184a077c84 100644
@@ -42,7 +42,6 @@
 #include "common.h"
 #include "cpuidle.h"
 #include "iomap.h"
-#include "irq.h"
 #include "pm.h"
 #include "reset.h"
 #include "sleep.h"
include/soc/tegra/irq.h renamed from arch/arm/mach-tegra/irq.h +5 -3
similarity index 59%
rename from arch/arm/mach-tegra/irq.h
rename to include/soc/tegra/irq.h
index 7a94cf121448..8eb11a7109e4 100644
@@ -3,9 +3,11 @@
  * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
  */
 
-#ifndef __TEGRA_IRQ_H
-#define __TEGRA_IRQ_H
+#ifndef __SOC_TEGRA_IRQ_H
+#define __SOC_TEGRA_IRQ_H
 
+#if defined(CONFIG_ARM)
 bool tegra_pending_sgi(void);
-
 #endif
+
+#endif /* __SOC_TEGRA_IRQ_H */
include/soc/tegra/pm.h +31 -0
index 951fcd738d55..1974e8405098 100644
@@ -6,6 +6,8 @@
 #ifndef __SOC_TEGRA_PM_H__
 #define __SOC_TEGRA_PM_H__
 
+#include <linux/errno.h>
+
 enum tegra_suspend_mode {
 	TEGRA_SUSPEND_NONE = 0,
 	TEGRA_SUSPEND_LP2, /* CPU voltage off */
@@ -20,6 +22,12 @@ tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode);
 
 /* low-level resume entry point */
 void tegra_resume(void);
+
+int tegra30_sleep_cpu_secondary_finish(unsigned long arg);
+void tegra_clear_cpu_in_lp2(void);
+void tegra_set_cpu_in_lp2(void);
+int tegra_idle_lp2_last(void);
+int tegra_pm_park_secondary_cpu(unsigned long cpu);
 #else
 static inline enum tegra_suspend_mode
 tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode)
@@ -30,6 +38,29 @@ tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode)
 static inline void tegra_resume(void)
 {
 }
+
+static inline int tegra30_sleep_cpu_secondary_finish(unsigned long arg)
+{
+	return -ENOTSUPP;
+}
+
+static inline void tegra_clear_cpu_in_lp2(void)
+{
+}
+
+static inline void tegra_set_cpu_in_lp2(void)
+{
+}
+
+static inline int tegra_idle_lp2_last(void)
+{
+	return -ENOTSUPP;
+}
+
+static inline int tegra_pm_park_secondary_cpu(unsigned long cpu)
+{
+	return -ENOTSUPP;
+}
 #endif /* CONFIG_PM_SLEEP */
 
 #endif /* __SOC_TEGRA_PM_H__ */
Signature · 1 line
2.24.0
Acked-by on v9 6/17
#14 lore raw

Re: [PATCH v9 06/17] ARM: tegra: Expose PM functions required for new cpuidle driver

Quoted 8 lines · Dmitry Osipenko

The upcoming unified CPUIDLE driver will be added to the drivers/cpuidle/ directory and it will require all these exposed Tegra PM-core functions.

[ ... ]

Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#15 lore raw

PATCH v9 7/17 ARM: tegra: Rename some of the newly exposed PM functions

In reply to Dmitry Osipenko

Rename some of the recently exposed PM functions, prefixing them with "tegra_pm_" in order to make the naming of the PM functions consistent.

---
 arch/arm/mach-tegra/cpuidle-tegra114.c |  6 +++---
 arch/arm/mach-tegra/cpuidle-tegra20.c  |  6 +++---
 arch/arm/mach-tegra/cpuidle-tegra30.c  |  8 ++++----
 arch/arm/mach-tegra/pm.c               | 10 +++++-----
 arch/arm/mach-tegra/sleep-tegra30.S    |  6 +++---
 include/soc/tegra/pm.h                 | 16 ++++++++--------
 6 files changed, 26 insertions(+), 26 deletions(-)
arch/arm/mach-tegra/cpuidle-tegra114.c +3 -3
index 2d8527837aeb..858c30cc5dc7 100644
@@ -35,17 +35,17 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev,
 {
 	local_fiq_disable();
 
-	tegra_set_cpu_in_lp2();
+	tegra_pm_set_cpu_in_lp2();
 	cpu_pm_enter();
 
 	call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2);
 
 	/* Do suspend by ourselves if the firmware does not implement it */
 	if (call_firmware_op(do_idle, 0) == -ENOSYS)
-		cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
+		cpu_suspend(0, tegra30_pm_secondary_cpu_suspend);
 
 	cpu_pm_exit();
-	tegra_clear_cpu_in_lp2();
+	tegra_pm_clear_cpu_in_lp2();
 
 	local_fiq_enable();
 
arch/arm/mach-tegra/cpuidle-tegra20.c +3 -3
index fdfe92068e38..9672c619f4bc 100644
@@ -92,7 +92,7 @@ static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
 	while (!tegra_cpu_rail_off_ready())
 		cpu_relax();
 
-	ret = !tegra_idle_lp2_last();
+	ret = !tegra_pm_enter_lp2();
 
 	if (cpu_online(1))
 		tegra20_wake_cpu1_from_reset();
@@ -137,7 +137,7 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
 
 	local_fiq_disable();
 
-	tegra_set_cpu_in_lp2();
+	tegra_pm_set_cpu_in_lp2();
 	cpu_pm_enter();
 
 	if (dev->cpu == 0)
@@ -146,7 +146,7 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
 		entered_lp2 = tegra20_idle_enter_lp2_cpu_1(dev, drv, index);
 
 	cpu_pm_exit();
-	tegra_clear_cpu_in_lp2();
+	tegra_pm_clear_cpu_in_lp2();
 
 	local_fiq_enable();
 
arch/arm/mach-tegra/cpuidle-tegra30.c +4 -4
index 3e91c29891f7..a4f0add46a27 100644
@@ -69,7 +69,7 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
 		return false;
 	}
 
-	return !tegra_idle_lp2_last();
+	return !tegra_pm_enter_lp2();
 }
 
 #ifdef CONFIG_SMP
@@ -79,7 +79,7 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
 {
 	smp_wmb();
 
-	cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
+	cpu_suspend(0, tegra30_pm_secondary_cpu_suspend);
 
 	return true;
 }
@@ -100,7 +100,7 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
 
 	local_fiq_disable();
 
-	tegra_set_cpu_in_lp2();
+	tegra_pm_set_cpu_in_lp2();
 	cpu_pm_enter();
 
 	if (dev->cpu == 0)
@@ -109,7 +109,7 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
 		entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index);
 
 	cpu_pm_exit();
-	tegra_clear_cpu_in_lp2();
+	tegra_pm_clear_cpu_in_lp2();
 
 	local_fiq_enable();
 
arch/arm/mach-tegra/pm.c +5 -5
index a094acaca307..7d9ef26e52a7 100644
@@ -110,7 +110,7 @@ static void suspend_cpu_complex(void)
 	flowctrl_cpu_suspend_enter(cpu);
 }
 
-void tegra_clear_cpu_in_lp2(void)
+void tegra_pm_clear_cpu_in_lp2(void)
 {
 	int phy_cpu_id = cpu_logical_map(smp_processor_id());
 	u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
@@ -123,7 +123,7 @@ void tegra_clear_cpu_in_lp2(void)
 	spin_unlock(&tegra_lp2_lock);
 }
 
-void tegra_set_cpu_in_lp2(void)
+void tegra_pm_set_cpu_in_lp2(void)
 {
 	int phy_cpu_id = cpu_logical_map(smp_processor_id());
 	u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
@@ -189,7 +189,7 @@ static void tegra_pm_set(enum tegra_suspend_mode mode)
 	tegra_pmc_enter_suspend_mode(mode);
 }
 
-int tegra_idle_lp2_last(void)
+int tegra_pm_enter_lp2(void)
 {
 	int err;
 
@@ -356,7 +356,7 @@ static int tegra_suspend_enter(suspend_state_t state)
 		tegra_suspend_enter_lp1();
 		break;
 	case TEGRA_SUSPEND_LP2:
-		tegra_set_cpu_in_lp2();
+		tegra_pm_set_cpu_in_lp2();
 		break;
 	default:
 		break;
@@ -377,7 +377,7 @@ static int tegra_suspend_enter(suspend_state_t state)
 		tegra_suspend_exit_lp1();
 		break;
 	case TEGRA_SUSPEND_LP2:
-		tegra_clear_cpu_in_lp2();
+		tegra_pm_clear_cpu_in_lp2();
 		break;
 	default:
 		break;
arch/arm/mach-tegra/sleep-tegra30.S +3 -3
index c3946dbd0240..2667bcdb5dc6 100644
@@ -265,11 +265,11 @@ ENTRY(tegra30_sleep_core_finish)
 ENDPROC(tegra30_sleep_core_finish)
 
 /*
- * tegra30_sleep_cpu_secondary_finish(unsigned long v2p)
+ * tegra30_pm_secondary_cpu_suspend(unsigned long unused_arg)
  *
  * Enters LP2 on secondary CPU by exiting coherency and powergating the CPU.
  */
-ENTRY(tegra30_sleep_cpu_secondary_finish)
+ENTRY(tegra30_pm_secondary_cpu_suspend)
 	mov	r7, lr
 
 	/* Flush and disable the L1 data cache */
@@ -281,7 +281,7 @@ ENTRY(tegra30_sleep_cpu_secondary_finish)
 	bl	tegra30_cpu_shutdown
 	mov	r0, #1                          @ never return here
 	ret	r7
-ENDPROC(tegra30_sleep_cpu_secondary_finish)
+ENDPROC(tegra30_pm_secondary_cpu_suspend)
 
 /*
  * tegra30_tear_down_cpu
include/soc/tegra/pm.h +8 -8
index 1974e8405098..08477d7bfab9 100644
@@ -23,10 +23,10 @@ tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode);
 /* low-level resume entry point */
 void tegra_resume(void);
 
-int tegra30_sleep_cpu_secondary_finish(unsigned long arg);
-void tegra_clear_cpu_in_lp2(void);
-void tegra_set_cpu_in_lp2(void);
-int tegra_idle_lp2_last(void);
+int tegra30_pm_secondary_cpu_suspend(unsigned long arg);
+void tegra_pm_clear_cpu_in_lp2(void);
+void tegra_pm_set_cpu_in_lp2(void);
+int tegra_pm_enter_lp2(void);
 int tegra_pm_park_secondary_cpu(unsigned long cpu);
 #else
 static inline enum tegra_suspend_mode
@@ -39,20 +39,20 @@ static inline void tegra_resume(void)
 {
 }
 
-static inline int tegra30_sleep_cpu_secondary_finish(unsigned long arg)
+static inline int tegra30_pm_secondary_cpu_suspend(unsigned long arg)
 {
 	return -ENOTSUPP;
 }
 
-static inline void tegra_clear_cpu_in_lp2(void)
+static inline void tegra_pm_clear_cpu_in_lp2(void)
 {
 }
 
-static inline void tegra_set_cpu_in_lp2(void)
+static inline void tegra_pm_set_cpu_in_lp2(void)
 {
 }
 
-static inline int tegra_idle_lp2_last(void)
+static inline int tegra_pm_enter_lp2(void)
 {
 	return -ENOTSUPP;
 }
Signature · 1 line
2.24.0
Acked-by on v9 7/17
#16 lore raw

Re: [PATCH v9 07/17] ARM: tegra: Rename some of the newly exposed PM functions

Quoted 8 lines · Dmitry Osipenko

Rename some of the recently exposed PM functions, prefixing them with "tegra_pm_" in order to make the naming of the PM functions consistent.

#17 lore raw

PATCH v9 8/17 ARM: tegra: Make outer_disable() open-coded

In reply to Dmitry Osipenko

The outer_disable() of Tegra's suspend code is open-coded now since that helper produces spurious warning message about secondary CPUs being online when CPU enters into LP2 from cpuidle. The secondaries are actually halted by the cpuidle driver on entering into LP2 idle-state, but the online status is not touched by the cpuidle. This fixes a storm of warnings once LP2 idling state is enabled on Tegra30. The outer_disable() helper has sanity checks for interrupts and secondary CPUs being disabled and we are pretty confident about the interrupts state during of CPU idling / system suspend. The rail-off status check is added in this patch as equivalent for the "num_online_cpus() > 1".

---
 arch/arm/mach-tegra/pm.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
arch/arm/mach-tegra/pm.c +8 -3
index 7d9ef26e52a7..d1e1a61b12cf 100644
@@ -138,6 +138,10 @@ void tegra_pm_set_cpu_in_lp2(void)
 
 static int tegra_sleep_cpu(unsigned long v2p)
 {
+	if (tegra_cpu_car_ops->rail_off_ready &&
+	    WARN_ON(!tegra_cpu_rail_off_ready()))
+		return -EBUSY;
+
 	/*
 	 * L2 cache disabling using kernel API only allowed when all
 	 * secondary CPU's are offline. Cache have to be disabled with
@@ -146,9 +150,10 @@ static int tegra_sleep_cpu(unsigned long v2p)
 	 * if any of secondary CPU's is online and this is the LP2-idle
 	 * code-path only for Tegra20/30.
 	 */
-	if (trusted_foundations_registered())
-		outer_disable();
-
+#ifdef CONFIG_OUTER_CACHE
+	if (trusted_foundations_registered() && outer_cache.disable)
+		outer_cache.disable();
+#endif
 	/*
 	 * Note that besides of setting up CPU reset vector this firmware
 	 * call may also do the following, depending on the FW version:
Signature · 1 line
2.24.0
#18 lore raw

PATCH v9 9/17 arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

In reply to Dmitry Osipenko

It is possible that something may go wrong with the secondary CPU, in that case it is much nicer to get a dump of the flow-controller state before hanging machine.

---
 arch/arm/mach-tegra/cpuidle-tegra20.c | 47 +++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)
arch/arm/mach-tegra/cpuidle-tegra20.c +45 -2
index 9672c619f4bc..bcc158b72e67 100644
@@ -83,14 +83,57 @@ static inline void tegra20_wake_cpu1_from_reset(void)
 }
 #endif
 
+static void tegra20_report_cpus_state(void)
+{
+	unsigned long cpu, lcpu, csr;
+
+	for_each_cpu(lcpu, cpu_possible_mask) {
+		cpu = cpu_logical_map(lcpu);
+		csr = flowctrl_read_cpu_csr(cpu);
+
+		pr_err("cpu%lu: online=%d flowctrl_csr=0x%08lx\n",
+		       cpu, cpu_online(lcpu), csr);
+	}
+}
+
+static int tegra20_wait_for_secondary_cpu_parking(void)
+{
+	unsigned int retries = 3;
+
+	while (retries--) {
+		ktime_t timeout = ktime_add_ms(ktime_get(), 500);
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));
+
+		pr_err("secondary CPU taking too long to park\n");
+
+		tegra20_report_cpus_state();
+	}
+
+	pr_err("timed out waiting secondaries to park\n");
+
+	return -ETIMEDOUT;
+}
+
 static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
 					   struct cpuidle_driver *drv,
 					   int index)
 {
 	bool ret;
 
-	while (!tegra_cpu_rail_off_ready())
-		cpu_relax();
+	if (tegra20_wait_for_secondary_cpu_parking())
+		return false;
 
 	ret = !tegra_pm_enter_lp2();
 
Signature · 1 line
2.24.0
Acked-by on v9 9/17
#19 lore raw

Re: [PATCH v9 09/17] arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

Quoted 9 lines · Dmitry Osipenko

It is possible that something may go wrong with the secondary CPU, in that case it is much nicer to get a dump of the flow-controller state before hanging machine.

Quoted 71 lines
---
 arch/arm/mach-tegra/cpuidle-tegra20.c | 47 +++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)
arch/arm/mach-tegra/cpuidle-tegra20.c +45 -2
index 9672c619f4bc..bcc158b72e67 100644
@@ -83,14 +83,57 @@ static inline void tegra20_wake_cpu1_from_reset(void)
 }
 #endif
 
+static void tegra20_report_cpus_state(void)
+{
+	unsigned long cpu, lcpu, csr;
+
+	for_each_cpu(lcpu, cpu_possible_mask) {
+		cpu = cpu_logical_map(lcpu);
+		csr = flowctrl_read_cpu_csr(cpu);
+
+		pr_err("cpu%lu: online=%d flowctrl_csr=0x%08lx\n",
+		       cpu, cpu_online(lcpu), csr);
+	}
+}
+
+static int tegra20_wait_for_secondary_cpu_parking(void)
+{
+	unsigned int retries = 3;
+
+	while (retries--) {
+		ktime_t timeout = ktime_add_ms(ktime_get(), 500);
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));
+
+		pr_err("secondary CPU taking too long to park\n");
+
+		tegra20_report_cpus_state();
+	}
+
+	pr_err("timed out waiting secondaries to park\n");
+
+	return -ETIMEDOUT;
+}
+
 static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
 					   struct cpuidle_driver *drv,
 					   int index)
 {
 	bool ret;
 
-	while (!tegra_cpu_rail_off_ready())
-		cpu_relax();
+	if (tegra20_wait_for_secondary_cpu_parking())
+		return false;
 
 	ret = !tegra_pm_enter_lp2();
 
Signature · 1 line
2.24.0
Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#20 lore raw

Re: [PATCH v9 09/17] arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

In reply to Dmitry Osipenko
Quoted 30 lines · Dmitry Osipenko

It is possible that something may go wrong with the secondary CPU, in that case it is much nicer to get a dump of the flow-controller state before hanging machine.

---
 arch/arm/mach-tegra/cpuidle-tegra20.c | 47 +++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)
arch/arm/mach-tegra/cpuidle-tegra20.c +9 -0
index 9672c619f4bc..bcc158b72e67 100644
@@ -83,14 +83,57 @@ static inline void tegra20_wake_cpu1_from_reset(void)
 }
 #endif
 
+static void tegra20_report_cpus_state(void)
+{
+	unsigned long cpu, lcpu, csr;
+
+	for_each_cpu(lcpu, cpu_possible_mask) {
+		cpu = cpu_logical_map(lcpu);
+		csr = flowctrl_read_cpu_csr(cpu);
+
+		pr_err("cpu%lu: online=%d flowctrl_csr=0x%08lx\n",

arch/arm/mach-tegra/cpuidle-tegra20.c static inline void tegra20_wake_cpu1_from_reset(void) · line 104

Quoted 10 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +10 -0
+		       cpu, cpu_online(lcpu), csr);
+	}
+}
+
+static int tegra20_wait_for_secondary_cpu_parking(void)
+{
+	unsigned int retries = 3;
+
+	while (retries--) {
+		ktime_t timeout = ktime_add_ms(ktime_get(), 500);

Oops I missed this one. Do not use ktime_get() in this code path, use jiffies.

arch/arm/mach-tegra/cpuidle-tegra20.c static inline void tegra20_wake_cpu1_from_reset(void) · line 117

Quoted 13 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +13 -0
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));

So this loop will aggresively call tegra_cpu_rail_off_ready() and retry 3 times. The tegra_cpu_rail_off_ready() function can be called thoushand of times here but the function will hang 1.5s :/

I suggest something like:

	while (retries--i && !tegra_cpu_rail_off_ready()) 
		udelay(100);

So <retries> calls to tegra_cpu_rail_off_ready() and 100us x <retries> maximum impact.

Quoted 26 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +12 -2
+		pr_err("secondary CPU taking too long to park\n");
+
+		tegra20_report_cpus_state();
+	}
+
+	pr_err("timed out waiting secondaries to park\n");
+
+	return -ETIMEDOUT;
+}
+
 static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
 					   struct cpuidle_driver *drv,
 					   int index)
 {
 	bool ret;
 
-	while (!tegra_cpu_rail_off_ready())
-		cpu_relax();
+	if (tegra20_wait_for_secondary_cpu_parking())
+		return false;
 
 	ret = !tegra_pm_enter_lp2();
 
Signature · 1 line
2.24.0
Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#21 lore raw

Re: [PATCH v9 09/17] arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

Hello Daniel,

21.02.2020 18:43, Daniel Lezcano пишет:

Quoted 35 lines · Dmitry Osipenko
Quoted 34 lines

It is possible that something may go wrong with the secondary CPU, in that case it is much nicer to get a dump of the flow-controller state before hanging machine.

---
 arch/arm/mach-tegra/cpuidle-tegra20.c | 47 +++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)
arch/arm/mach-tegra/cpuidle-tegra20.c +13 -0
index 9672c619f4bc..bcc158b72e67 100644
@@ -83,14 +83,57 @@ static inline void tegra20_wake_cpu1_from_reset(void)
 }
 #endif
 
+static void tegra20_report_cpus_state(void)
+{
+	unsigned long cpu, lcpu, csr;
+
+	for_each_cpu(lcpu, cpu_possible_mask) {
+		cpu = cpu_logical_map(lcpu);
+		csr = flowctrl_read_cpu_csr(cpu);
+
+		pr_err("cpu%lu: online=%d flowctrl_csr=0x%08lx\n",
+		       cpu, cpu_online(lcpu), csr);
+	}
+}
+
Quoted 8 lines

arch/arm/mach-tegra/cpuidle-tegra20.c static inline void tegra20_wake_cpu1_from_reset(void) · line 104

Quoted 6 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +6 -0
+static int tegra20_wait_for_secondary_cpu_parking(void)
+{
+	unsigned int retries = 3;
+
+	while (retries--) {
+		ktime_t timeout = ktime_add_ms(ktime_get(), 500);

Oops I missed this one. Do not use ktime_get() in this code path, use jiffies.

Could you please explain what benefits jiffies have over the ktime_get()?

Quoted 18 lines

arch/arm/mach-tegra/cpuidle-tegra20.c static inline void tegra20_wake_cpu1_from_reset(void) · line 117

Quoted 13 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +13 -0
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));

So this loop will aggresively call tegra_cpu_rail_off_ready() and retry 3 times. The tegra_cpu_rail_off_ready() function can be called thoushand of times here but the function will hang 1.5s :/

Quoted 7 lines

I suggest something like:

	while (retries--i && !tegra_cpu_rail_off_ready()) 
		udelay(100);

So <retries> calls to tegra_cpu_rail_off_ready() and 100us x <retries> maximum impact.

But udelay() also results into CPU spinning in a busy-loop, and thus, what's the difference?

#22 lore raw

Re: [PATCH v9 09/17] arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

Quoted 14 lines · Dmitry Osipenko

Hello Daniel,

21.02.2020 18:43, Daniel Lezcano пишет:

Quoted 11 lines · Dmitry Osipenko
Quoted 10 lines

It is possible that something may go wrong with the secondary CPU, in that case it is much nicer to get a dump of the flow-controller state before hanging machine.

---

[ ... ]

Quoted 10 lines
Quoted 8 lines

arch/arm/mach-tegra/cpuidle-tegra20.c static inline void tegra20_wake_cpu1_from_reset(void) · line 104

Quoted 6 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +6 -0
+static int tegra20_wait_for_secondary_cpu_parking(void)
+{
+	unsigned int retries = 3;
+
+	while (retries--) {
+		ktime_t timeout = ktime_add_ms(ktime_get(), 500);

Oops I missed this one. Do not use ktime_get() in this code path, use jiffies.

Could you please explain what benefits jiffies have over the ktime_get()?

ktime_get() is very slow, jiffies is updated every tick.

Quoted 20 lines
Quoted 20 lines

arch/arm/mach-tegra/cpuidle-tegra20.c static inline void tegra20_wake_cpu1_from_reset(void) · line 117

Quoted 13 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +13 -0
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));

So this loop will aggresively call tegra_cpu_rail_off_ready() and retry 3 times. The tegra_cpu_rail_off_ready() function can be called thoushand of times here but the function will hang 1.5s :/

I suggest something like:

Quoted 7 lines
Quoted 5 lines
	while (retries--i && !tegra_cpu_rail_off_ready()) 
		udelay(100);

So <retries> calls to tegra_cpu_rail_off_ready() and 100us x <retries> maximum impact.

But udelay() also results into CPU spinning in a busy-loop, and thus, what's the difference?

busy looping instead of register reads with all the hardware things involved behind.

Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#23 lore raw

Re: [PATCH v9 09/17] arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

21.02.2020 20:36, Daniel Lezcano пишет:

Quoted 27 lines · Dmitry Osipenko
Quoted 14 lines

Hello Daniel,

21.02.2020 18:43, Daniel Lezcano пишет:

Quoted 11 lines · Dmitry Osipenko
Quoted 10 lines

It is possible that something may go wrong with the secondary CPU, in that case it is much nicer to get a dump of the flow-controller state before hanging machine.

---

[ ... ]

Quoted 9 lines
Quoted 8 lines

arch/arm/mach-tegra/cpuidle-tegra20.c static inline void tegra20_wake_cpu1_from_reset(void) · line 104

Quoted 6 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +6 -0
+static int tegra20_wait_for_secondary_cpu_parking(void)
+{
+	unsigned int retries = 3;
+
+	while (retries--) {
+		ktime_t timeout = ktime_add_ms(ktime_get(), 500);

Oops I missed this one. Do not use ktime_get() in this code path, use jiffies.

Quoted 3 lines
Quoted 1 line

Could you please explain what benefits jiffies have over the ktime_get()?

ktime_get() is very slow, jiffies is updated every tick.

But how jiffies are supposed to be updated if interrupts are disabled?

Aren't jiffies actually slower than ktime_get() because jiffies are updating every 10/1ms (depending on CONFIG_HZ)?

We're kinda interesting here in getting into deep-idling state as quick as possible. I was checking how much time takes the busy-loop below and it takes ~40-150us in average, which is good enough.

Quoted 23 lines
Quoted 23 lines
Quoted 23 lines

arch/arm/mach-tegra/cpuidle-tegra20.c static inline void tegra20_wake_cpu1_from_reset(void) · line 117

Quoted 13 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +13 -0
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));

So this loop will aggresively call tegra_cpu_rail_off_ready() and retry 3 times. The tegra_cpu_rail_off_ready() function can be called thoushand of times here but the function will hang 1.5s :/

I suggest something like:

	while (retries--i && !tegra_cpu_rail_off_ready()) 
		udelay(100);
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

So <retries> calls to tegra_cpu_rail_off_ready() and 100us x <retries> maximum impact.

But udelay() also results into CPU spinning in a busy-loop, and thus, what's the difference?

busy looping instead of register reads with all the hardware things involved behind.

Please notice that this code runs only on an older Cortex-A9/A15, which doesn't support WFE for the delaying, and thus, CPU always busy-loops inside udelay().

What about if I'll add cpu_relax() to the loop? Do you think it it could have any positive effect?

#24 lore raw

Re: [PATCH v9 09/17] arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

Quoted 28 lines · Dmitry Osipenko

21.02.2020 20:36, Daniel Lezcano пишет:

Quoted 27 lines · Dmitry Osipenko
Quoted 14 lines

Hello Daniel,

21.02.2020 18:43, Daniel Lezcano пишет:

Quoted 11 lines · Dmitry Osipenko
Quoted 10 lines

It is possible that something may go wrong with the secondary CPU, in that case it is much nicer to get a dump of the flow-controller state before hanging machine.

---

[ ... ]

Quoted 9 lines
Quoted 8 lines

arch/arm/mach-tegra/cpuidle-tegra20.c static inline void tegra20_wake_cpu1_from_reset(void) · line 104

Quoted 6 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +6 -0
+static int tegra20_wait_for_secondary_cpu_parking(void)
+{
+	unsigned int retries = 3;
+
+	while (retries--) {
+		ktime_t timeout = ktime_add_ms(ktime_get(), 500);

Oops I missed this one. Do not use ktime_get() in this code path, use jiffies.

Quoted 5 lines
Quoted 3 lines
Quoted 1 line

Could you please explain what benefits jiffies have over the ktime_get()?

ktime_get() is very slow, jiffies is updated every tick.

But how jiffies are supposed to be updated if interrupts are disabled?

Yeah, other cpus must not be idle in this.

Quoted 2 lines

Aren't jiffies actually slower than ktime_get() because jiffies are updating every 10/1ms (depending on CONFIG_HZ)?

They are no slower, they have a lower resolution which is 10ms or 4ms.

Given the 500ms timeout, it is fine.

Quoted 3 lines

We're kinda interesting here in getting into deep-idling state as quick as possible. I was checking how much time takes the busy-loop below and it takes ~40-150us in average, which is good enough.

ktime_get() gets a seq lock and it is very slow.

Quoted 28 lines
Quoted 28 lines
Quoted 27 lines
Quoted 18 lines

arch/arm/mach-tegra/cpuidle-tegra20.c static inline void tegra20_wake_cpu1_from_reset(void) · line 117

Quoted 13 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +13 -0
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));

So this loop will aggresively call tegra_cpu_rail_off_ready() and retry 3 times. The tegra_cpu_rail_off_ready() function can be called thoushand of times here but the function will hang 1.5s :/

Quoted 7 lines

I suggest something like:

	while (retries--i && !tegra_cpu_rail_off_ready()) 
		udelay(100);

So <retries> calls to tegra_cpu_rail_off_ready() and 100us x <retries> maximum impact.

But udelay() also results into CPU spinning in a busy-loop, and thus, what's the difference?

Quoted 8 lines
Quoted 1 line

busy looping instead of register reads with all the hardware things involved behind.

Please notice that this code runs only on an older Cortex-A9/A15, which doesn't support WFE for the delaying, and thus, CPU always busy-loops inside udelay().

What about if I'll add cpu_relax() to the loop? Do you think it it could have any positive effect?

I think udelay() has a call to cpu_relax().

Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#25 lore raw

Re: [PATCH v9 09/17] arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

21.02.2020 23:02, Daniel Lezcano пишет:

Quoted 29 lines · Dmitry Osipenko
Quoted 28 lines

21.02.2020 20:36, Daniel Lezcano пишет:

Quoted 27 lines · Dmitry Osipenko
Quoted 14 lines

Hello Daniel,

21.02.2020 18:43, Daniel Lezcano пишет:

Quoted 11 lines · Dmitry Osipenko
Quoted 10 lines

It is possible that something may go wrong with the secondary CPU, in that case it is much nicer to get a dump of the flow-controller state before hanging machine.

---

[ ... ]

Quoted 9 lines
Quoted 8 lines

arch/arm/mach-tegra/cpuidle-tegra20.c static inline void tegra20_wake_cpu1_from_reset(void) · line 104

Quoted 6 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +6 -0
+static int tegra20_wait_for_secondary_cpu_parking(void)
+{
+	unsigned int retries = 3;
+
+	while (retries--) {
+		ktime_t timeout = ktime_add_ms(ktime_get(), 500);

Oops I missed this one. Do not use ktime_get() in this code path, use jiffies.

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line

Could you please explain what benefits jiffies have over the ktime_get()?

ktime_get() is very slow, jiffies is updated every tick.

But how jiffies are supposed to be updated if interrupts are disabled?

Yeah, other cpus must not be idle in this.

Okay, then jiffies can't be used here because this function is used for the coupled / power-gated state only. All CPUs are idling in this state.

Quoted 5 lines
Quoted 2 lines

Aren't jiffies actually slower than ktime_get() because jiffies are updating every 10/1ms (depending on CONFIG_HZ)?

They are no slower, they have a lower resolution which is 10ms or 4ms.

Quoted 7 lines

Given the 500ms timeout, it is fine.

Quoted 3 lines

We're kinda interesting here in getting into deep-idling state as quick as possible. I was checking how much time takes the busy-loop below and it takes ~40-150us in average, which is good enough.

ktime_get() gets a seq lock and it is very slow.

Since all CPUs are idling here, the locking isn't a problem.

The wait_for_secondary_cpu_parking() function is called on CPU0, it waits for the secondary CPUs to enter into safe-state before CPU0 could power-gate the whole CPU cluster.

Quoted 30 lines
Quoted 30 lines
Quoted 29 lines
Quoted 20 lines
Quoted 20 lines

arch/arm/mach-tegra/cpuidle-tegra20.c static inline void tegra20_wake_cpu1_from_reset(void) · line 117

Quoted 13 lines
arch/arm/mach-tegra/cpuidle-tegra20.c +13 -0
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));

So this loop will aggresively call tegra_cpu_rail_off_ready() and retry 3 times. The tegra_cpu_rail_off_ready() function can be called thoushand of times here but the function will hang 1.5s :/

I suggest something like:

Quoted 7 lines
Quoted 5 lines
	while (retries--i && !tegra_cpu_rail_off_ready()) 
		udelay(100);

So <retries> calls to tegra_cpu_rail_off_ready() and 100us x <retries> maximum impact.

But udelay() also results into CPU spinning in a busy-loop, and thus, what's the difference?

busy looping instead of register reads with all the hardware things involved behind.

Quoted 8 lines
Quoted 6 lines

Please notice that this code runs only on an older Cortex-A9/A15, which doesn't support WFE for the delaying, and thus, CPU always busy-loops inside udelay().

What about if I'll add cpu_relax() to the loop? Do you think it it could have any positive effect?

I think udelay() has a call to cpu_relax().

Yes, my point is that udelay() doesn't bring much benefit for us here because:

1. we want to enter into power-gated state as quick as possible and udelay() just adds an unnecessary delay

2. udelay() spins in a busy-loop until delay is expired, just like we're doing it in this function already

#26 lore raw

Re: [PATCH v9 09/17] arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

21.02.2020 23:21, Dmitry Osipenko пишет:

Quoted 99 lines

21.02.2020 23:02, Daniel Lezcano пишет:

Quoted 29 lines · Dmitry Osipenko
Quoted 28 lines

21.02.2020 20:36, Daniel Lezcano пишет:

Quoted 27 lines · Dmitry Osipenko
Quoted 14 lines

Hello Daniel,

21.02.2020 18:43, Daniel Lezcano пишет:

Quoted 11 lines · Dmitry Osipenko
Quoted 10 lines

It is possible that something may go wrong with the secondary CPU, in that case it is much nicer to get a dump of the flow-controller state before hanging machine.

---

[ ... ]

Quoted 9 lines
Quoted 8 lines

Review

Quoted 6 lines
(quoted diff) +6 -0
+static int tegra20_wait_for_secondary_cpu_parking(void)
+{
+	unsigned int retries = 3;
+
+	while (retries--) {
+		ktime_t timeout = ktime_add_ms(ktime_get(), 500);

Oops I missed this one. Do not use ktime_get() in this code path, use jiffies.

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line

Could you please explain what benefits jiffies have over the ktime_get()?

ktime_get() is very slow, jiffies is updated every tick.

But how jiffies are supposed to be updated if interrupts are disabled?

Yeah, other cpus must not be idle in this.

Okay, then jiffies can't be used here because this function is used for the coupled / power-gated state only. All CPUs are idling in this state.

Quoted 5 lines
Quoted 2 lines

Aren't jiffies actually slower than ktime_get() because jiffies are updating every 10/1ms (depending on CONFIG_HZ)?

They are no slower, they have a lower resolution which is 10ms or 4ms.

Quoted 7 lines

Given the 500ms timeout, it is fine.

Quoted 3 lines

We're kinda interesting here in getting into deep-idling state as quick as possible. I was checking how much time takes the busy-loop below and it takes ~40-150us in average, which is good enough.

ktime_get() gets a seq lock and it is very slow.

Since all CPUs are idling here, the locking isn't a problem.

The wait_for_secondary_cpu_parking() function is called on CPU0, it waits for the secondary CPUs to enter into safe-state before CPU0 could power-gate the whole CPU cluster.

Quoted 30 lines
Quoted 30 lines
Quoted 29 lines
Quoted 20 lines
Quoted 20 lines

Review

Quoted 13 lines
(quoted diff) +13 -0
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));

So this loop will aggresively call tegra_cpu_rail_off_ready() and retry 3 times. The tegra_cpu_rail_off_ready() function can be called thoushand of times here but the function will hang 1.5s :/

I suggest something like:

Quoted 7 lines
Quoted 5 lines
	while (retries--i && !tegra_cpu_rail_off_ready()) 
		udelay(100);

So <retries> calls to tegra_cpu_rail_off_ready() and 100us x <retries> maximum impact.

But udelay() also results into CPU spinning in a busy-loop, and thus, what's the difference?

busy looping instead of register reads with all the hardware things involved behind.

Quoted 8 lines
Quoted 6 lines

Please notice that this code runs only on an older Cortex-A9/A15, which doesn't support WFE for the delaying, and thus, CPU always busy-loops inside udelay().

What about if I'll add cpu_relax() to the loop? Do you think it it could have any positive effect?

I think udelay() has a call to cpu_relax().

Quoted 8 lines

Yes, my point is that udelay() doesn't bring much benefit for us here because:

1. we want to enter into power-gated state as quick as possible and udelay() just adds an unnecessary delay

2. udelay() spins in a busy-loop until delay is expired, just like we're doing it in this function already

I'll try the udelay()-loop over the weekend and will see if it makes any real difference, maybe I'm missing something.

If it doesn't make any difference, I'll leave this patch as-is, okay?

#27 lore raw

Re: [PATCH v9 09/17] arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

In reply to Dmitry Osipenko
Quoted 1 line · Dmitry Osipenko

21.02.2020 23:02, Daniel Lezcano пишет:

[ ... ]

Quoted 39 lines
Quoted 30 lines
Quoted 30 lines
Quoted 29 lines
Quoted 20 lines
Quoted 20 lines

Review

Quoted 13 lines
(quoted diff) +13 -0
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));

So this loop will aggresively call tegra_cpu_rail_off_ready() and retry 3 times. The tegra_cpu_rail_off_ready() function can be called thoushand of times here but the function will hang 1.5s :/

I suggest something like:

Quoted 7 lines
Quoted 5 lines
	while (retries--i && !tegra_cpu_rail_off_ready()) 
		udelay(100);

So <retries> calls to tegra_cpu_rail_off_ready() and 100us x <retries> maximum impact.

But udelay() also results into CPU spinning in a busy-loop, and thus, what's the difference?

busy looping instead of register reads with all the hardware things involved behind.

Quoted 8 lines
Quoted 6 lines

Please notice that this code runs only on an older Cortex-A9/A15, which doesn't support WFE for the delaying, and thus, CPU always busy-loops inside udelay().

What about if I'll add cpu_relax() to the loop? Do you think it it could have any positive effect?

I think udelay() has a call to cpu_relax().

Quoted 8 lines

Yes, my point is that udelay() doesn't bring much benefit for us here because:

1. we want to enter into power-gated state as quick as possible and udelay() just adds an unnecessary delay

2. udelay() spins in a busy-loop until delay is expired, just like we're doing it in this function already

In this case why not remove ktime_get() and increase the number of retries?

Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#28 lore raw

Re: [PATCH v9 09/17] arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

21.02.2020 23:48, Daniel Lezcano пишет:

Quoted 47 lines · Dmitry Osipenko
Quoted 1 line

21.02.2020 23:02, Daniel Lezcano пишет:

[ ... ]

Quoted 42 lines
Quoted 30 lines
Quoted 30 lines
Quoted 29 lines
Quoted 20 lines
Quoted 20 lines

Review

Quoted 13 lines
(quoted diff) +13 -0
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));

So this loop will aggresively call tegra_cpu_rail_off_ready() and retry 3 times. The tegra_cpu_rail_off_ready() function can be called thoushand of times here but the function will hang 1.5s :/

I suggest something like:

Quoted 7 lines
Quoted 5 lines
	while (retries--i && !tegra_cpu_rail_off_ready()) 
		udelay(100);

So <retries> calls to tegra_cpu_rail_off_ready() and 100us x <retries> maximum impact.

But udelay() also results into CPU spinning in a busy-loop, and thus, what's the difference?

busy looping instead of register reads with all the hardware things involved behind.

Quoted 8 lines
Quoted 6 lines

Please notice that this code runs only on an older Cortex-A9/A15, which doesn't support WFE for the delaying, and thus, CPU always busy-loops inside udelay().

What about if I'll add cpu_relax() to the loop? Do you think it it could have any positive effect?

I think udelay() has a call to cpu_relax().

Yes, my point is that udelay() doesn't bring much benefit for us here because:

Quoted 7 lines
Quoted 5 lines

1. we want to enter into power-gated state as quick as possible and udelay() just adds an unnecessary delay

2. udelay() spins in a busy-loop until delay is expired, just like we're doing it in this function already

In this case why not remove ktime_get() and increase the number of retries?

Because the busy-loop performance depends on CPU's frequency, so we can't rely on a bare number of the retries.

#29 lore raw

Re: [PATCH v9 09/17] arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

Quoted 51 lines · Dmitry Osipenko

21.02.2020 23:48, Daniel Lezcano пишет:

Quoted 50 lines · Dmitry Osipenko
Quoted 1 line

21.02.2020 23:02, Daniel Lezcano пишет:

[ ... ]

Quoted 45 lines
Quoted 30 lines
Quoted 30 lines
Quoted 29 lines
Quoted 20 lines
Quoted 20 lines

Review

Quoted 13 lines
(quoted diff) +13 -0
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));

So this loop will aggresively call tegra_cpu_rail_off_ready() and retry 3 times. The tegra_cpu_rail_off_ready() function can be called thoushand of times here but the function will hang 1.5s :/

I suggest something like:

Quoted 7 lines
Quoted 5 lines
	while (retries--i && !tegra_cpu_rail_off_ready()) 
		udelay(100);

So <retries> calls to tegra_cpu_rail_off_ready() and 100us x <retries> maximum impact.

But udelay() also results into CPU spinning in a busy-loop, and thus, what's the difference?

busy looping instead of register reads with all the hardware things involved behind.

Quoted 8 lines
Quoted 6 lines

Please notice that this code runs only on an older Cortex-A9/A15, which doesn't support WFE for the delaying, and thus, CPU always busy-loops inside udelay().

What about if I'll add cpu_relax() to the loop? Do you think it it could have any positive effect?

I think udelay() has a call to cpu_relax().

Yes, my point is that udelay() doesn't bring much benefit for us here because:

1. we want to enter into power-gated state as quick as possible and udelay() just adds an unnecessary delay

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

2. udelay() spins in a busy-loop until delay is expired, just like we're doing it in this function already

In this case why not remove ktime_get() and increase the number of retries?

Because the busy-loop performance depends on CPU's frequency, so we can't rely on a bare number of the retries.

Why not if computed in the worst case scenario?

Anyway, I'll let you give a try.

Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#30 lore raw

Re: [PATCH v9 09/17] arm: tegra20: cpuidle: Handle case where secondary CPU hangs on entering LP2

22.02.2020 00:11, Daniel Lezcano пишет:

Quoted 55 lines · Dmitry Osipenko
Quoted 54 lines

21.02.2020 23:48, Daniel Lezcano пишет:

Quoted 53 lines · Dmitry Osipenko
Quoted 1 line

21.02.2020 23:02, Daniel Lezcano пишет:

[ ... ]

Quoted 47 lines
Quoted 30 lines
Quoted 30 lines
Quoted 29 lines
Quoted 20 lines
Quoted 20 lines

Review

Quoted 13 lines
(quoted diff) +13 -0
+
+		/*
+		 * The primary CPU0 core shall wait for the secondaries
+		 * shutdown in order to power-off CPU's cluster safely.
+		 * The timeout value depends on the current CPU frequency,
+		 * it takes about 40-150us  in average and over 1000us in
+		 * a worst case scenario.
+		 */
+		do {
+			if (tegra_cpu_rail_off_ready())
+				return 0;
+
+		} while (ktime_before(ktime_get(), timeout));

So this loop will aggresively call tegra_cpu_rail_off_ready() and retry 3 times. The tegra_cpu_rail_off_ready() function can be called thoushand of times here but the function will hang 1.5s :/

I suggest something like:

Quoted 7 lines
Quoted 5 lines
	while (retries--i && !tegra_cpu_rail_off_ready()) 
		udelay(100);

So <retries> calls to tegra_cpu_rail_off_ready() and 100us x <retries> maximum impact.

But udelay() also results into CPU spinning in a busy-loop, and thus, what's the difference?

busy looping instead of register reads with all the hardware things involved behind.

Quoted 8 lines
Quoted 6 lines

Please notice that this code runs only on an older Cortex-A9/A15, which doesn't support WFE for the delaying, and thus, CPU always busy-loops inside udelay().

What about if I'll add cpu_relax() to the loop? Do you think it it could have any positive effect?

I think udelay() has a call to cpu_relax().

Yes, my point is that udelay() doesn't bring much benefit for us here because:

1. we want to enter into power-gated state as quick as possible and udelay() just adds an unnecessary delay

2. udelay() spins in a busy-loop until delay is expired, just like we're doing it in this function already

Quoted 6 lines
Quoted 4 lines
Quoted 1 line

In this case why not remove ktime_get() and increase the number of retries?

Because the busy-loop performance depends on CPU's frequency, so we can't rely on a bare number of the retries.

Why not if computed in the worst case scenario?

There are always at least a few dozens of microseconds to wait, so something like udelay(10) should be a bit better variant anyways.

Quoted 1 line

Anyway, I'll let you give a try.

Turned out that udelay(10) is noticeably better when system is running on a lower freqs in comparison to ktime_get(). I'll switch to udelay in v10, thank you very much for the suggestion!

#31 lore raw

PATCH v9 10/17 arm: tegra20: cpuidle: Make abort_flag atomic

In reply to Dmitry Osipenko

Replace memory accessors with atomic API just to make code consistent with the abort_barrier. The new variant may be even more correct now since atomic_read() will prevent compiler from generating wrong things like carrying abort_flag value in a register instead of re-fetching it from memory.

---
 arch/arm/mach-tegra/cpuidle-tegra20.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
arch/arm/mach-tegra/cpuidle-tegra20.c +5 -4
index bcc158b72e67..ccb8b0aa6c46 100644
@@ -32,7 +32,7 @@
 #include "sleep.h"
 
 #ifdef CONFIG_PM_SLEEP
-static bool abort_flag;
+static atomic_t abort_flag;
 static atomic_t abort_barrier;
 static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
 				    struct cpuidle_driver *drv,
@@ -168,13 +168,14 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
 	bool entered_lp2 = false;
 
 	if (tegra_pending_sgi())
-		WRITE_ONCE(abort_flag, true);
+		atomic_set(&abort_flag, 1);
 
 	cpuidle_coupled_parallel_barrier(dev, &abort_barrier);
 
-	if (abort_flag) {
+	if (atomic_read(&abort_flag)) {
 		cpuidle_coupled_parallel_barrier(dev, &abort_barrier);
-		abort_flag = false;	/* clean flag for next coming */
+		/* clean flag for next coming */
+		atomic_set(&abort_flag, 0);
 		return -EINTR;
 	}
 
Signature · 1 line
2.24.0
Acked-by on v9 10/17
#32 lore raw

Re: [PATCH v9 10/17] arm: tegra20: cpuidle: Make abort_flag atomic

Quoted 11 lines · Dmitry Osipenko

Replace memory accessors with atomic API just to make code consistent with the abort_barrier. The new variant may be even more correct now since atomic_read() will prevent compiler from generating wrong things like carrying abort_flag value in a register instead of re-fetching it from memory.

#33 lore raw

PATCH v9 11/17 arm: tegra20/30: cpuidle: Remove unnecessary memory barrier

In reply to Dmitry Osipenko

There is no good justification for smp_rmb() after returning from LP2 because there are no memory operations that require SMP synchronization. Thus remove the confusing barrier.

---
 arch/arm/mach-tegra/cpuidle-tegra20.c | 2 --
 arch/arm/mach-tegra/cpuidle-tegra30.c | 2 --
 2 files changed, 4 deletions(-)
arch/arm/mach-tegra/cpuidle-tegra20.c +0 -2
index ccb8b0aa6c46..f8f14c0b79ff 100644
@@ -194,8 +194,6 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
 
 	local_fiq_enable();
 
-	smp_rmb();
-
 	return entered_lp2 ? index : 0;
 }
 #endif
arch/arm/mach-tegra/cpuidle-tegra30.c +0 -2
index a4f0add46a27..80ae64bcdf50 100644
@@ -113,8 +113,6 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
 
 	local_fiq_enable();
 
-	smp_rmb();
-
 	return (entered_lp2) ? index : 0;
 }
 #endif
Signature · 1 line
2.24.0
Acked-by on v9 11/17
#34 lore raw

Re: [PATCH v9 11/17] arm: tegra20/30: cpuidle: Remove unnecessary memory barrier

Quoted 9 lines · Dmitry Osipenko

There is no good justification for smp_rmb() after returning from LP2 because there are no memory operations that require SMP synchronization. Thus remove the confusing barrier.

#35 lore raw

PATCH v9 12/17 cpuidle: Refactor and move out NVIDIA Tegra20 driver into drivers/cpuidle

In reply to Dmitry Osipenko

The driver's code is refactored in a way that will make it easy to support Tegra30/114/124 SoCs by this unified driver later on. The current functionality is equal to the old Tegra20 driver, only the code's structure changed a tad. This is also a proper platform driver now.

---
 arch/arm/mach-tegra/Makefile          |   3 -
 arch/arm/mach-tegra/cpuidle-tegra20.c | 216 --------------------
 arch/arm/mach-tegra/cpuidle.c         |  14 +-
 arch/arm/mach-tegra/cpuidle.h         |   4 -
 drivers/cpuidle/Kconfig.arm           |   8 +
 drivers/cpuidle/Makefile              |   1 +
 drivers/cpuidle/cpuidle-tegra.c       | 277 ++++++++++++++++++++++++++
 include/soc/tegra/cpuidle.h           |   2 +-
 8 files changed, 289 insertions(+), 236 deletions(-)
 delete mode 100644 arch/arm/mach-tegra/cpuidle-tegra20.c
 create mode 100644 drivers/cpuidle/cpuidle-tegra.c
arch/arm/mach-tegra/Makefile +0 -3
index 965862608ff6..8425bb5608d5 100644
@@ -12,9 +12,6 @@ obj-y					+= sleep-tegra20.o
 obj-y					+= sleep-tegra30.o
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= pm-tegra20.o
-ifeq ($(CONFIG_CPU_IDLE),y)
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= cpuidle-tegra20.o
-endif
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= pm-tegra30.o
 ifeq ($(CONFIG_CPU_IDLE),y)
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= cpuidle-tegra30.o
arch/arm/mach-tegra/cpuidle-tegra20.c deleted +0 -216

216 lines not on this page · raw message

arch/arm/mach-tegra/cpuidle.c +2 -12
index d565c44cfc93..eee85d517783 100644
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include <soc/tegra/fuse.h>
 
@@ -23,8 +24,7 @@ void __init tegra_cpuidle_init(void)
 {
 	switch (tegra_get_chip_id()) {
 	case TEGRA20:
-		if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
-			tegra20_cpuidle_init();
+		platform_device_register_simple("tegra-cpuidle", -1, NULL, 0);
 		break;
 	case TEGRA30:
 		if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC))
@@ -38,13 +38,3 @@ void __init tegra_cpuidle_init(void)
 		break;
 	}
 }
-
-void tegra_cpuidle_pcie_irqs_in_use(void)
-{
-	switch (tegra_get_chip_id()) {
-	case TEGRA20:
-		if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
-			tegra20_cpuidle_pcie_irqs_in_use();
-		break;
-	}
-}
arch/arm/mach-tegra/cpuidle.h +0 -4
index 4e1f459f5bd8..eeb37baf18e1 100644
@@ -7,15 +7,11 @@
 #define __MACH_TEGRA_CPUIDLE_H
 
 #ifdef CONFIG_CPU_IDLE
-int tegra20_cpuidle_init(void);
-void tegra20_cpuidle_pcie_irqs_in_use(void);
 int tegra30_cpuidle_init(void);
 int tegra114_cpuidle_init(void);
 void tegra_cpuidle_init(void);
-void tegra_cpuidle_pcie_irqs_in_use(void);
 #else
 static inline void tegra_cpuidle_init(void) {}
-static inline void tegra_cpuidle_pcie_irqs_in_use(void) {}
 #endif
 
 #endif
drivers/cpuidle/Kconfig.arm +8 -0
index 62272ecfa771..99a2d72ac02b 100644
@@ -86,3 +86,11 @@ config ARM_MVEBU_V7_CPUIDLE
 	depends on (ARCH_MVEBU || COMPILE_TEST) && !ARM64
 	help
 	  Select this to enable cpuidle on Armada 370, 38x and XP processors.
+
+config ARM_TEGRA_CPUIDLE
+	bool "CPU Idle Driver for NVIDIA Tegra SoCs"
+	depends on ARCH_TEGRA && !ARM64
+	select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
+	select ARM_CPU_SUSPEND
+	help
+	  Select this to enable cpuidle for NVIDIA Tegra20/30/114/124 SoCs.
drivers/cpuidle/Makefile +1 -0
index cc8c769d7fa9..55a464f6a78b 100644
@@ -24,6 +24,7 @@ obj-$(CONFIG_ARM_CPUIDLE)		+= cpuidle-arm.o
 obj-$(CONFIG_ARM_PSCI_CPUIDLE)		+= cpuidle_psci.o
 cpuidle_psci-y				:= cpuidle-psci.o
 cpuidle_psci-$(CONFIG_PM_GENERIC_DOMAINS_OF) += cpuidle-psci-domain.o
+obj-$(CONFIG_ARM_TEGRA_CPUIDLE)		+= cpuidle-tegra.o
 
 ###############################################################################
 # MIPS drivers
drivers/cpuidle/cpuidle-tegra.c new file +277 -0

277 lines not on this page · raw message

include/soc/tegra/cpuidle.h +1 -1
index 029ba1f4b2cc..5665975015d8 100644
@@ -6,7 +6,7 @@
 #ifndef __SOC_TEGRA_CPUIDLE_H__
 #define __SOC_TEGRA_CPUIDLE_H__
 
-#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_TEGRA) && defined(CONFIG_CPU_IDLE)
+#ifdef CONFIG_ARM_TEGRA_CPUIDLE
 void tegra_cpuidle_pcie_irqs_in_use(void);
 #else
 static inline void tegra_cpuidle_pcie_irqs_in_use(void)
Signature · 1 line
2.24.0
#36 lore raw

Re: [PATCH v9 12/17] cpuidle: Refactor and move out NVIDIA Tegra20 driver into drivers/cpuidle

Quoted 8 lines · Dmitry Osipenko

The driver's code is refactored in a way that will make it easy to support Tegra30/114/124 SoCs by this unified driver later on. The current functionality is equal to the old Tegra20 driver, only the code's structure changed a tad. This is also a proper platform driver now.

Quoted 8 lines
---
 arch/arm/mach-tegra/Makefile          |   3 -
 arch/arm/mach-tegra/cpuidle-tegra20.c | 216 --------------------
 arch/arm/mach-tegra/cpuidle.c         |  14 +-
 arch/arm/mach-tegra/cpuidle.h         |   4 -
 drivers/cpuidle/Kconfig.arm           |   8 +
 drivers/cpuidle/Makefile              |   1 +
 drivers/cpuidle/cpuidle-tegra.c       | 277 ++++++++++++++++++++++++++

Is it possible to use -M option here to make the review easier?

#37 lore raw

PATCH v9 13/17 cpuidle: tegra: Squash Tegra30 driver into the common driver

In reply to Dmitry Osipenko

Tegra20 and Terga30 SoCs have common C1 and CC6 idling states and thus share the same code paths, there is no point in having separate drivers for a similar hardware. This patch merely moves functionality of the old driver into the new, although the CC6 state is kept disabled for now since old driver had a rudimentary support for this state (allowing to enter into CC6 only when secondary CPUs are put offline), while new driver can provide a full-featured support. The new feature will be enabled by another patch.

---
 arch/arm/mach-tegra/Makefile          |   3 -
 arch/arm/mach-tegra/cpuidle-tegra30.c | 123 --------------------------
 arch/arm/mach-tegra/cpuidle.c         |   5 +-
 arch/arm/mach-tegra/cpuidle.h         |   1 -
 drivers/cpuidle/cpuidle-tegra.c       |  74 ++++++++++++++--
 5 files changed, 70 insertions(+), 136 deletions(-)
 delete mode 100644 arch/arm/mach-tegra/cpuidle-tegra30.c
arch/arm/mach-tegra/Makefile +0 -3
index 8425bb5608d5..99c5f4274e5c 100644
@@ -13,9 +13,6 @@ obj-y					+= sleep-tegra30.o
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= pm-tegra20.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= pm-tegra30.o
-ifeq ($(CONFIG_CPU_IDLE),y)
-obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= cpuidle-tegra30.o
-endif
 obj-$(CONFIG_SMP)			+= platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
 
arch/arm/mach-tegra/cpuidle-tegra30.c deleted +0 -123

123 lines not on this page · raw message

arch/arm/mach-tegra/cpuidle.c +1 -4
index eee85d517783..fa0dcf3c2c45 100644
@@ -24,11 +24,8 @@ void __init tegra_cpuidle_init(void)
 {
 	switch (tegra_get_chip_id()) {
 	case TEGRA20:
-		platform_device_register_simple("tegra-cpuidle", -1, NULL, 0);
-		break;
 	case TEGRA30:
-		if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC))
-			tegra30_cpuidle_init();
+		platform_device_register_simple("tegra-cpuidle", -1, NULL, 0);
 		break;
 	case TEGRA114:
 	case TEGRA124:
arch/arm/mach-tegra/cpuidle.h +0 -1
index eeb37baf18e1..5423a05a69f6 100644
@@ -7,7 +7,6 @@
 #define __MACH_TEGRA_CPUIDLE_H
 
 #ifdef CONFIG_CPU_IDLE
-int tegra30_cpuidle_init(void);
 int tegra114_cpuidle_init(void);
 void tegra_cpuidle_init(void);
 #else
drivers/cpuidle/cpuidle-tegra.c +69 -5

117 lines not on this page · raw message

Signature · 1 line
2.24.0
#38 lore raw

Re: [PATCH v9 13/17] cpuidle: tegra: Squash Tegra30 driver into the common driver

Quoted 9 lines · Dmitry Osipenko

Tegra20 and Terga30 SoCs have common C1 and CC6 idling states and thus share the same code paths, there is no point in having separate drivers for a similar hardware. This patch merely moves functionality of the old driver into the new, although the CC6 state is kept disabled for now since old driver had a rudimentary support for this state (allowing to enter into CC6 only when secondary CPUs are put offline), while new driver can provide a full-featured support. The new feature will be enabled by another patch.

Quoted 8 lines
---
 arch/arm/mach-tegra/Makefile          |   3 -
 arch/arm/mach-tegra/cpuidle-tegra30.c | 123 --------------------------

Add the -M option when resending please.

#39 lore raw

Re: [PATCH v9 13/17] cpuidle: tegra: Squash Tegra30 driver into the common driver

21.02.2020 19:29, Daniel Lezcano пишет:

Quoted 19 lines · Dmitry Osipenko
Quoted 9 lines

Tegra20 and Terga30 SoCs have common C1 and CC6 idling states and thus share the same code paths, there is no point in having separate drivers for a similar hardware. This patch merely moves functionality of the old driver into the new, although the CC6 state is kept disabled for now since old driver had a rudimentary support for this state (allowing to enter into CC6 only when secondary CPUs are put offline), while new driver can provide a full-featured support. The new feature will be enabled by another patch.

Quoted 8 lines
---
 arch/arm/mach-tegra/Makefile          |   3 -
 arch/arm/mach-tegra/cpuidle-tegra30.c | 123 --------------------------
Quoted 1 line

Add the -M option when resending please.

Okay, thank you very much for taking a look at the patches!

#40 lore raw

Re: [PATCH v9 13/17] cpuidle: tegra: Squash Tegra30 driver into the common driver

Quoted 20 lines · Dmitry Osipenko

21.02.2020 19:29, Daniel Lezcano пишет:

Quoted 19 lines · Dmitry Osipenko
Quoted 17 lines

Tegra20 and Terga30 SoCs have common C1 and CC6 idling states and thus share the same code paths, there is no point in having separate drivers for a similar hardware. This patch merely moves functionality of the old driver into the new, although the CC6 state is kept disabled for now since old driver had a rudimentary support for this state (allowing to enter into CC6 only when secondary CPUs are put offline), while new driver can provide a full-featured support. The new feature will be enabled by another patch.

---
 arch/arm/mach-tegra/Makefile          |   3 -
 arch/arm/mach-tegra/cpuidle-tegra30.c | 123 --------------------------
Quoted 3 lines
Quoted 1 line

Add the -M option when resending please.

Okay, thank you very much for taking a look at the patches!

Yeah, sorry for the delay. Nice cleanup BTW.

Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#41 lore raw

Re: [PATCH v9 13/17] cpuidle: tegra: Squash Tegra30 driver into the common driver

21.02.2020 20:41, Daniel Lezcano пишет:

Quoted 21 lines · Dmitry Osipenko
Quoted 20 lines

21.02.2020 19:29, Daniel Lezcano пишет:

Quoted 19 lines · Dmitry Osipenko
Quoted 17 lines

Tegra20 and Terga30 SoCs have common C1 and CC6 idling states and thus share the same code paths, there is no point in having separate drivers for a similar hardware. This patch merely moves functionality of the old driver into the new, although the CC6 state is kept disabled for now since old driver had a rudimentary support for this state (allowing to enter into CC6 only when secondary CPUs are put offline), while new driver can provide a full-featured support. The new feature will be enabled by another patch.

---
 arch/arm/mach-tegra/Makefile          |   3 -
 arch/arm/mach-tegra/cpuidle-tegra30.c | 123 --------------------------
Quoted 5 lines
Quoted 3 lines
Quoted 1 line

Add the -M option when resending please.

Okay, thank you very much for taking a look at the patches!

Yeah, sorry for the delay. Nice cleanup BTW.

No problems, thank you :)

#42 lore raw

PATCH v9 14/17 cpuidle: tegra: Squash Tegra114 driver into the common driver

In reply to Dmitry Osipenko

Tegra20/30/114/124 SoCs have common idling states, thus there is no much point in having separate drivers for a similar hardware. This patch moves Tegra114/124 arch/ drivers into the common driver without any functional changes. The CC6 state is kept disabled on Tegra114/124 because the core Tegra PM code needs some more work in order to support that state.

---
 arch/arm/mach-tegra/Makefile           |  7 --
 arch/arm/mach-tegra/cpuidle-tegra114.c | 90 --------------------------
 arch/arm/mach-tegra/cpuidle.c          | 37 -----------
 arch/arm/mach-tegra/cpuidle.h          | 16 -----
 arch/arm/mach-tegra/tegra.c            |  6 +-
 drivers/cpuidle/cpuidle-tegra.c        | 45 ++++++++++++-
 6 files changed, 48 insertions(+), 153 deletions(-)
 delete mode 100644 arch/arm/mach-tegra/cpuidle-tegra114.c
 delete mode 100644 arch/arm/mach-tegra/cpuidle.c
 delete mode 100644 arch/arm/mach-tegra/cpuidle.h
arch/arm/mach-tegra/Makefile +0 -7
index 99c5f4274e5c..07572b5373b8 100644
@@ -10,19 +10,12 @@ obj-y					+= sleep.o
 obj-y					+= tegra.o
 obj-y					+= sleep-tegra20.o
 obj-y					+= sleep-tegra30.o
-obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= pm-tegra20.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= pm-tegra30.o
 obj-$(CONFIG_SMP)			+= platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
 
 obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= pm-tegra30.o
-ifeq ($(CONFIG_CPU_IDLE),y)
-obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= cpuidle-tegra114.o
-endif
 obj-$(CONFIG_ARCH_TEGRA_124_SOC)	+= pm-tegra30.o
-ifeq ($(CONFIG_CPU_IDLE),y)
-obj-$(CONFIG_ARCH_TEGRA_124_SOC)	+= cpuidle-tegra114.o
-endif
 
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= board-paz00.o
arch/arm/mach-tegra/cpuidle-tegra114.c deleted +0 -90

90 lines not on this page · raw message

arch/arm/mach-tegra/cpuidle.c deleted +0 -37
deleted file mode 100644
index fa0dcf3c2c45..000000000000
@@ -1,37 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * arch/arm/mach-tegra/cpuidle.c
- *
- * CPU idle driver for Tegra CPUs
- *
- * Copyright (c) 2010-2012, NVIDIA Corporation.
- * Copyright (c) 2011 Google, Inc.
- * Author: Colin Cross <[email protected]>
- *         Gary King <[email protected]>
- *
- * Rework for 3.3 by Peter De Schrijver <[email protected]>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <soc/tegra/fuse.h>
-
-#include "cpuidle.h"
-
-void __init tegra_cpuidle_init(void)
-{
-	switch (tegra_get_chip_id()) {
-	case TEGRA20:
-	case TEGRA30:
-		platform_device_register_simple("tegra-cpuidle", -1, NULL, 0);
-		break;
-	case TEGRA114:
-	case TEGRA124:
-		if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) ||
-		    IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC))
-			tegra114_cpuidle_init();
-		break;
-	}
-}
arch/arm/mach-tegra/cpuidle.h deleted +0 -16
deleted file mode 100644
index 5423a05a69f6..000000000000
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
- */
-
-#ifndef __MACH_TEGRA_CPUIDLE_H
-#define __MACH_TEGRA_CPUIDLE_H
-
-#ifdef CONFIG_CPU_IDLE
-int tegra114_cpuidle_init(void);
-void tegra_cpuidle_init(void);
-#else
-static inline void tegra_cpuidle_init(void) {}
-#endif
-
-#endif
arch/arm/mach-tegra/tegra.c +4 -2
index 79184a077c84..eeacff626546 100644
@@ -36,11 +36,11 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/mach-types.h>
+#include <asm/psci.h>
 #include <asm/setup.h>
 
 #include "board.h"
 #include "common.h"
-#include "cpuidle.h"
 #include "iomap.h"
 #include "pm.h"
 #include "reset.h"
@@ -85,7 +85,6 @@ static void __init tegra_dt_init(void)
 static void __init tegra_dt_init_late(void)
 {
 	tegra_init_suspend();
-	tegra_cpuidle_init();
 
 	if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) &&
 	    of_machine_is_compatible("compal,paz00"))
@@ -98,6 +97,9 @@ static void __init tegra_dt_init_late(void)
 	if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) &&
 	    of_machine_is_compatible("nvidia,tegra30"))
 		platform_device_register_simple("tegra20-cpufreq", -1, NULL, 0);
+
+	if (IS_ENABLED(CONFIG_ARM_TEGRA_CPUIDLE) && !psci_smp_available())
+		platform_device_register_simple("tegra-cpuidle", -1, NULL, 0);
 }
 
 static const char * const tegra_dt_board_compat[] = {
drivers/cpuidle/cpuidle-tegra.c +44 -1

93 lines not on this page · raw message

Signature · 1 line
2.24.0
#43 lore raw

PATCH v9 15/17 cpuidle: tegra: Disable CC6 state if LP2 unavailable

In reply to Dmitry Osipenko

LP2 suspending could be unavailable, for example if it is disabled in a device-tree. CC6 cpuidle state won't work in that case.

---
 drivers/cpuidle/cpuidle-tegra.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/cpuidle/cpuidle-tegra.c +5 -0
index b6cdad8437af..675b8a4464ba 100644
@@ -31,6 +31,7 @@
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/irq.h>
 #include <soc/tegra/pm.h>
+#include <soc/tegra/pmc.h>
 
 #include <asm/cpuidle.h>
 #include <asm/firmware.h>
@@ -334,6 +335,10 @@ static void tegra_cpuidle_setup_tegra114_c7_state(void)
 
 static int tegra_cpuidle_probe(struct platform_device *pdev)
 {
+	/* LP2 could be disabled in device-tree */
+	if (tegra_pmc_get_suspend_mode() < TEGRA_SUSPEND_LP2)
+		tegra_cpuidle_disable_state(TEGRA_CC6);
+
 	/*
 	 * Required suspend-resume functionality, which is provided by the
 	 * Tegra-arch core and PMC driver, is unavailable if PM-sleep option
Signature · 1 line
2.24.0
Acked-by on v9 15/17
#44 lore raw

Re: [PATCH v9 15/17] cpuidle: tegra: Disable CC6 state if LP2 unavailable

Quoted 5 lines · Dmitry Osipenko

LP2 suspending could be unavailable, for example if it is disabled in a device-tree. CC6 cpuidle state won't work in that case.

Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#45 lore raw

PATCH v9 16/17 ARM: multi_v7_defconfig: Enable Tegra cpuidle driver

In reply to Dmitry Osipenko

The Tegra CPU Idle driver was moved out into driver/cpuidle/ directory and it is now a proper platform driver.

---
 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)
arch/arm/configs/multi_v7_defconfig +1 -0
index 017d65f86eba..7c8a1c310bbb 100644
@@ -113,6 +113,7 @@ CONFIG_CPU_IDLE=y
 CONFIG_ARM_CPUIDLE=y
 CONFIG_ARM_ZYNQ_CPUIDLE=y
 CONFIG_ARM_EXYNOS_CPUIDLE=y
+CONFIG_ARM_TEGRA_CPUIDLE=y
 CONFIG_KERNEL_MODE_NEON=y
 CONFIG_RASPBERRYPI_FIRMWARE=y
 CONFIG_TRUSTED_FOUNDATIONS=y
Signature · 1 line
2.24.0
Acked-by on v9 16/17
#46 lore raw

Re: [PATCH v9 16/17] ARM: multi_v7_defconfig: Enable Tegra cpuidle driver

Quoted 5 lines · Dmitry Osipenko

The Tegra CPU Idle driver was moved out into driver/cpuidle/ directory and it is now a proper platform driver.

Quoted 19 lines
---
 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)
arch/arm/configs/multi_v7_defconfig +1 -0
index 017d65f86eba..7c8a1c310bbb 100644
@@ -113,6 +113,7 @@ CONFIG_CPU_IDLE=y
 CONFIG_ARM_CPUIDLE=y
 CONFIG_ARM_ZYNQ_CPUIDLE=y
 CONFIG_ARM_EXYNOS_CPUIDLE=y
+CONFIG_ARM_TEGRA_CPUIDLE=y
 CONFIG_KERNEL_MODE_NEON=y
 CONFIG_RASPBERRYPI_FIRMWARE=y
 CONFIG_TRUSTED_FOUNDATIONS=y
Signature · 1 line
2.24.0
Signature · 5 lines
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#47 lore raw

PATCH v9 17/17 ARM: tegra: Enable Tegra cpuidle driver in tegra_defconfig

In reply to Dmitry Osipenko

The Tegra CPU Idle driver was moved out into driver/cpuidle/ directory and it is now a proper platform driver.

---
 arch/arm/configs/tegra_defconfig | 1 +
 1 file changed, 1 insertion(+)
arch/arm/configs/tegra_defconfig +1 -0
index a27592d3b1fa..aa94369bdd0f 100644
@@ -25,6 +25,7 @@ CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_CPUFREQ_DT=y
 CONFIG_CPU_IDLE=y
+CONFIG_ARM_TEGRA_CPUIDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 CONFIG_TRUSTED_FOUNDATIONS=y
Signature · 1 line
2.24.0
#49 lore raw
In reply to Dmitry Osipenko

13.02.2020 02:51, Dmitry Osipenko пишет:

Quoted 17 lines

Hello,

This series does the following:

1. Unifies Tegra20/30/114 drivers into a single driver and moves it out into common drivers/cpuidle/ directory.

2. Enables CPU cluster power-down idling state on Tegra30.

In the end there is a quite nice clean up of the Tegra CPUIDLE drivers and of the Tegra's arch code in general. Please apply, thanks!

!!!WARNING!!! This series was made on top of the cpufreq patches [1]. But it
should be fine as long as Thierry Reding would pick up this and the cpufreq patchsets via the Tegra tree, otherwise there will one minor merge-conflict.

Quoted 8 lines

[1] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=158206

Changelog:

v9: - Added acks from Peter De Schrijver.

- Added tested-by from Peter Geis, Jasper Korten and David Heidelberg who tested these patches on Ouya, TF300T and Nexus 7 devices.

I forgot to mention that both cpufreq and cpuidle patchsets were also tested on AC100 by Nicolas Chauvet and I forgot to ask for the explicit t-b. Nicolas, thank you very much for all the testing of the grate-kernel! Please feel free to give yours t-b :)

Quoted 9 lines

- Temporarily dropped the "cpuidle: tegra: Support CPU cluster power-down state on Tegra30" patch because Michał Mirosław reported that it didn't work well on his TF300T. After some testing we found that changing a way in which firmware performs L2 cache maintenance helps, but later on we also found that the current v9 series works just fine without the extra firmware changes using recent linux-next and the reason why v8 didn't work before is still unknown (need more testing). So I decided that it will be better to postpone the dropped patch until we know for sure that it works well for everyone in every possible configuration.

Michał, please let me know if you'll spot any problems with the recent version of the patches and please feel free to give yours t-b if it works well.

#50 lore raw
In reply to Dmitry Osipenko

13.02.2020 02:51, Dmitry Osipenko пишет:

Quoted 18 lines

Hello,

This series does the following:

1. Unifies Tegra20/30/114 drivers into a single driver and moves it out into common drivers/cpuidle/ directory.

2. Enables CPU cluster power-down idling state on Tegra30.

In the end there is a quite nice clean up of the Tegra CPUIDLE drivers and of the Tegra's arch code in general. Please apply, thanks!

!!!WARNING!!! This series was made on top of the cpufreq patches [1]. But it
should be fine as long as Thierry Reding would pick up this and the cpufreq patchsets via the Tegra tree, otherwise there will one minor merge-conflict.

[1] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=158206

...

Quoted 5 lines

cpuidle: Refactor and move out NVIDIA Tegra20 driver into
drivers/cpuidle
cpuidle: tegra: Squash Tegra30 driver into the common driver
cpuidle: tegra: Squash Tegra114 driver into the common driver
cpuidle: tegra: Disable CC6 state if LP2 unavailable

Hello Rafael and Daniel,

Could you please let us know whether you're fine with the above patches by giving an ACK to them? My understanding is that Thierry can't take the cpuidle patches through the Tegra tree without yours ACK. Thanks in advance!

#51 lore raw
In reply to Dmitry Osipenko

13.02.2020 02:51, Dmitry Osipenko пишет:

Quoted 36 lines

Hello,

This series does the following:

1. Unifies Tegra20/30/114 drivers into a single driver and moves it out into common drivers/cpuidle/ directory.

2. Enables CPU cluster power-down idling state on Tegra30.

In the end there is a quite nice clean up of the Tegra CPUIDLE drivers and of the Tegra's arch code in general. Please apply, thanks!

!!!WARNING!!! This series was made on top of the cpufreq patches [1]. But it
should be fine as long as Thierry Reding would pick up this and the cpufreq patchsets via the Tegra tree, otherwise there will one minor merge-conflict.

[1] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=158206

Changelog:

v9: - Added acks from Peter De Schrijver.

- Added tested-by from Peter Geis, Jasper Korten and David Heidelberg who tested these patches on Ouya, TF300T and Nexus 7 devices.

- Temporarily dropped the "cpuidle: tegra: Support CPU cluster power-down state on Tegra30" patch because Michał Mirosław reported that it didn't work well on his TF300T. After some testing we found that changing a way in which firmware performs L2 cache maintenance helps, but later on we also found that the current v9 series works just fine without the extra firmware changes using recent linux-next and the reason why v8 didn't work before is still unknown (need more testing). So I decided that it will be better to postpone the dropped patch until we know for sure that it works well for everyone in every possible configuration.

Quoted 3 lines

- Rebased this series on top of recent linux-next, in a result dropped the "cpuidle: Avoid NULL dereference in cpuidle_driver_state_disabled()" patch because it's not needed anymore.

I just noticed that this patchset was versioned wrongly, it should've been v10. Sorry for the confusion, next version will be v11.