diff mbox series

[5/9] ARM: EXYNOS: use chipid driver

Message ID 1542294698-17470-6-git-send-email-b.zolnierkie@samsung.com (mailing list archive)
State New, archived
Headers show
Series [1/9] ARM: EXYNOS: remove secondary startup initialization from smp_prepare_cpus | expand

Commit Message

Bartlomiej Zolnierkiewicz Nov. 15, 2018, 3:11 p.m. UTC
Add soc_dev_is_exynos*() helpers and use them instead of
soc_is_exynos*() ones.

Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
---
 arch/arm/mach-exynos/common.h   |  6 ++++++
 arch/arm/mach-exynos/exynos.c   | 39 +++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/firmware.c |  8 ++++----
 arch/arm/mach-exynos/platsmp.c  | 12 ++++++------
 arch/arm/mach-exynos/pm.c       | 17 +++++++++--------
 5 files changed, 64 insertions(+), 18 deletions(-)

Comments

Krzysztof Kozlowski Nov. 16, 2018, 12:24 p.m. UTC | #1
On Thu, 15 Nov 2018 at 16:12, Bartlomiej Zolnierkiewicz
<b.zolnierkie@samsung.com> wrote:
>
> Add soc_dev_is_exynos*() helpers and use them instead of
> soc_is_exynos*() ones.
>
> Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> ---
>  arch/arm/mach-exynos/common.h   |  6 ++++++
>  arch/arm/mach-exynos/exynos.c   | 39 +++++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-exynos/firmware.c |  8 ++++----
>  arch/arm/mach-exynos/platsmp.c  | 12 ++++++------
>  arch/arm/mach-exynos/pm.c       | 17 +++++++++--------
>  5 files changed, 64 insertions(+), 18 deletions(-)
>
> diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
> index 1b8699e..20d205e 100644
> --- a/arch/arm/mach-exynos/common.h
> +++ b/arch/arm/mach-exynos/common.h
> @@ -9,8 +9,14 @@
>  #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
>  #define __ARCH_ARM_MACH_EXYNOS_COMMON_H
>
> +#include <linux/sys_soc.h>
>  #include <linux/platform_data/cpuidle-exynos.h>
>
> +extern bool soc_dev_is_exynos3250(void);
> +extern bool soc_dev_is_exynos4210_rev11(void);
> +extern bool soc_dev_is_exynos4412(void);
> +extern bool soc_dev_is_exynos542x(void);
> +
>  #define EXYNOS3250_SOC_ID      0xE3472000
>  #define EXYNOS3_SOC_MASK       0xFFFFF000
>
> diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
> index 865dcc4..463e457 100644
> --- a/arch/arm/mach-exynos/exynos.c
> +++ b/arch/arm/mach-exynos/exynos.c
> @@ -24,6 +24,45 @@
>
>  #include "common.h"
>
> +static const struct soc_device_attribute exynos3250_soc_id[] = {
> +       { .soc_id = "EXYNOS3250" },
> +       { /* sentinel */ }
> +};
> +
> +static const struct soc_device_attribute exynos4210_rev11_soc_id[] = {
> +       { .soc_id = "EXYNOS4210", .revision = "11" },
> +       { /* sentinel */ }
> +};
> +
> +static const struct soc_device_attribute exynos4412_soc_id[] = {
> +       { .soc_id = "EXYNOS4412" },
> +       { /* sentinel */ }
> +};
> +
> +static const struct soc_device_attribute exynos542x_soc_id[] = {
> +       { .soc_id = "EXYNOS5420" },
> +       { .soc_id = "EXYNOS5800" },
> +       { /* sentinel */ }
> +};
> +
> +#define SOC_DEV_IS_EXYNOS(ver)                                         \
> +bool soc_dev_is_exynos##ver(void)                                      \
> +{                                                                      \
> +       static bool init_done, is_exynos##ver;                          \
> +                                                                       \
> +       if (!init_done) {                                               \
> +               is_exynos##ver = !!soc_device_match(exynos##ver##_soc_id); \
> +               init_done = true;                                       \
> +       }                                                               \
> +                                                                       \
> +       return is_exynos##ver;                                          \
> +}
> +
> +SOC_DEV_IS_EXYNOS(3250);
> +SOC_DEV_IS_EXYNOS(4210_rev11);
> +SOC_DEV_IS_EXYNOS(4412);
> +SOC_DEV_IS_EXYNOS(542x);

Nicely compacted definition but:
1. You blow real code (4 functions doing exactly the same),
2. You break jumping to definitions in IDE (searching/indexing symbols).

Currently this can be executed on only one, specific Exynos chip. This
means that you can have only one static variable holding current soc
revision and compare against it. This might require adding some enums
and code would look like:
enum soc_exynos {
SOC_EXYNOS_3250,
SOC_EXYNOS_542X,
...
};

bool soc_dev_is_exynos(soc) {
  static bool init_done;
  enum soc_exynos exynos_type;

  if (!init_done) {
    match = soc_device_match(exynos_soc_id);
    exynos_type = match.data;
  }
  return soc == exynos_type;
}

and the callers would be:
if (soc_dev_is_exynos(EXYNOS_542x))

Other point is comment in soc_device_match():
"This function is meant as a helper in place of of_match_node() in
cases where either no device tree is available or the information in a
device node is insufficient..."
and
"For new devices, the DT binding .. that allow the use of
of_match_node() instead."

so of_match_node() is preferred instead.

> +
>  static struct platform_device exynos_cpuidle = {
>         .name              = "exynos_cpuidle",
>  #ifdef CONFIG_ARM_EXYNOS_CPUIDLE
> diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c
> index d602e3b..d526d5e 100644
> --- a/arch/arm/mach-exynos/firmware.c
> +++ b/arch/arm/mach-exynos/firmware.c
> @@ -40,7 +40,7 @@ static int exynos_do_idle(unsigned long mode)
>                 writel_relaxed(__pa_symbol(exynos_cpu_resume_ns),
>                                sysram_ns_base_addr + 0x24);
>                 writel_relaxed(EXYNOS_AFTR_MAGIC, sysram_ns_base_addr + 0x20);
> -               if (soc_is_exynos3250()) {
> +               if (soc_dev_is_exynos3250()) {
>                         flush_cache_all();
>                         exynos_smc(SMC_CMD_SAVE, OP_TYPE_CORE,
>                                    SMC_POWERSTATE_IDLE, 0);
> @@ -61,7 +61,7 @@ static int exynos_cpu_boot(int cpu)
>          * Exynos3250 doesn't need to send smc command for secondary CPU boot
>          * because Exynos3250 removes WFE in secure mode.
>          */
> -       if (soc_is_exynos3250())
> +       if (soc_dev_is_exynos3250())
>                 return 0;
>
>         /*
> @@ -85,7 +85,7 @@ static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr)
>          * additional offset for every CPU, with Exynos4412 being the only
>          * exception.
>          */
> -       if (soc_is_exynos4412())
> +       if (soc_dev_is_exynos4412())
>                 boot_reg += 4 * cpu;
>
>         writel_relaxed(boot_addr, boot_reg);
> @@ -101,7 +101,7 @@ static int exynos_get_cpu_boot_addr(int cpu, unsigned long *boot_addr)
>
>         boot_reg = sysram_ns_base_addr + 0x1c;
>
> -       if (soc_is_exynos4412())
> +       if (soc_dev_is_exynos4412())
>                 boot_reg += 4 * cpu;
>
>         *boot_addr = readl_relaxed(boot_reg);
> diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
> index c39ffd2..e2ba70f 100644
> --- a/arch/arm/mach-exynos/platsmp.c
> +++ b/arch/arm/mach-exynos/platsmp.c
> @@ -88,7 +88,7 @@ void exynos_cpu_power_down(int cpu)
>  {
>         u32 core_conf;
>
> -       if (cpu == 0 && (soc_is_exynos5420() || soc_is_exynos5800())) {
> +       if (cpu == 0 && soc_dev_is_exynos542x()) {

With new implementation you might hit again LDREX and STREX here (see
commit ca489c58ef0b ("ARM: EXYNOS: Don't use LDREX and STREX after
disabling cache coherency")) because:
soc_device_match -> bus_for_each_dev -> klist_iter_init_node ->
kref_get_unless_zero -> refcount_inc_not_zero_checked
According to previous comments and
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/CJABEHDA.html
this is not allowed with cache coherency disabled.

I think calling here soc_device_match() is unlikely because it should
be initialized before. However please check if this is really the case
and comment it in the code in both places:
1. the first place which effectively initializes
soc_dev_is_exynos542x():init_done (to be sure that no one removes this
first call)
2. here that it depends on previous call of soc_dev_is_exynos542x().

It is getting slightly error prone - usage of one function is safe
here only if it was called somewhere else before... so I am not sure
if it is worth to remove soc_is_exynos() here.

Please also check other places without cache coherency where
soc_is_exynos() is being replaced to new method.

Best regards,
Krzysztof
diff mbox series

Patch

diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 1b8699e..20d205e 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -9,8 +9,14 @@ 
 #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
 #define __ARCH_ARM_MACH_EXYNOS_COMMON_H
 
+#include <linux/sys_soc.h>
 #include <linux/platform_data/cpuidle-exynos.h>
 
+extern bool soc_dev_is_exynos3250(void);
+extern bool soc_dev_is_exynos4210_rev11(void);
+extern bool soc_dev_is_exynos4412(void);
+extern bool soc_dev_is_exynos542x(void);
+
 #define EXYNOS3250_SOC_ID	0xE3472000
 #define EXYNOS3_SOC_MASK	0xFFFFF000
 
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
index 865dcc4..463e457 100644
--- a/arch/arm/mach-exynos/exynos.c
+++ b/arch/arm/mach-exynos/exynos.c
@@ -24,6 +24,45 @@ 
 
 #include "common.h"
 
+static const struct soc_device_attribute exynos3250_soc_id[] = {
+	{ .soc_id = "EXYNOS3250" },
+	{ /* sentinel */ }
+};
+
+static const struct soc_device_attribute exynos4210_rev11_soc_id[] = {
+	{ .soc_id = "EXYNOS4210", .revision = "11" },
+	{ /* sentinel */ }
+};
+
+static const struct soc_device_attribute exynos4412_soc_id[] = {
+	{ .soc_id = "EXYNOS4412" },
+	{ /* sentinel */ }
+};
+
+static const struct soc_device_attribute exynos542x_soc_id[] = {
+	{ .soc_id = "EXYNOS5420" },
+	{ .soc_id = "EXYNOS5800" },
+	{ /* sentinel */ }
+};
+
+#define SOC_DEV_IS_EXYNOS(ver)						\
+bool soc_dev_is_exynos##ver(void)					\
+{									\
+	static bool init_done, is_exynos##ver;				\
+									\
+	if (!init_done) {						\
+		is_exynos##ver = !!soc_device_match(exynos##ver##_soc_id); \
+		init_done = true;					\
+	}								\
+									\
+	return is_exynos##ver;						\
+}
+
+SOC_DEV_IS_EXYNOS(3250);
+SOC_DEV_IS_EXYNOS(4210_rev11);
+SOC_DEV_IS_EXYNOS(4412);
+SOC_DEV_IS_EXYNOS(542x);
+
 static struct platform_device exynos_cpuidle = {
 	.name              = "exynos_cpuidle",
 #ifdef CONFIG_ARM_EXYNOS_CPUIDLE
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c
index d602e3b..d526d5e 100644
--- a/arch/arm/mach-exynos/firmware.c
+++ b/arch/arm/mach-exynos/firmware.c
@@ -40,7 +40,7 @@  static int exynos_do_idle(unsigned long mode)
 		writel_relaxed(__pa_symbol(exynos_cpu_resume_ns),
 			       sysram_ns_base_addr + 0x24);
 		writel_relaxed(EXYNOS_AFTR_MAGIC, sysram_ns_base_addr + 0x20);
-		if (soc_is_exynos3250()) {
+		if (soc_dev_is_exynos3250()) {
 			flush_cache_all();
 			exynos_smc(SMC_CMD_SAVE, OP_TYPE_CORE,
 				   SMC_POWERSTATE_IDLE, 0);
@@ -61,7 +61,7 @@  static int exynos_cpu_boot(int cpu)
 	 * Exynos3250 doesn't need to send smc command for secondary CPU boot
 	 * because Exynos3250 removes WFE in secure mode.
 	 */
-	if (soc_is_exynos3250())
+	if (soc_dev_is_exynos3250())
 		return 0;
 
 	/*
@@ -85,7 +85,7 @@  static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr)
 	 * additional offset for every CPU, with Exynos4412 being the only
 	 * exception.
 	 */
-	if (soc_is_exynos4412())
+	if (soc_dev_is_exynos4412())
 		boot_reg += 4 * cpu;
 
 	writel_relaxed(boot_addr, boot_reg);
@@ -101,7 +101,7 @@  static int exynos_get_cpu_boot_addr(int cpu, unsigned long *boot_addr)
 
 	boot_reg = sysram_ns_base_addr + 0x1c;
 
-	if (soc_is_exynos4412())
+	if (soc_dev_is_exynos4412())
 		boot_reg += 4 * cpu;
 
 	*boot_addr = readl_relaxed(boot_reg);
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index c39ffd2..e2ba70f 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -88,7 +88,7 @@  void exynos_cpu_power_down(int cpu)
 {
 	u32 core_conf;
 
-	if (cpu == 0 && (soc_is_exynos5420() || soc_is_exynos5800())) {
+	if (cpu == 0 && soc_dev_is_exynos542x()) {
 		/*
 		 * Bypass power down for CPU0 during suspend. Check for
 		 * the SYS_PWR_REG value to decide if we are suspending
@@ -115,7 +115,7 @@  void exynos_cpu_power_up(int cpu)
 {
 	u32 core_conf = S5P_CORE_LOCAL_PWR_EN;
 
-	if (soc_is_exynos3250())
+	if (soc_dev_is_exynos3250())
 		core_conf |= S5P_CORE_AUTOWAKEUP_EN;
 
 	pmu_raw_writel(core_conf,
@@ -185,7 +185,7 @@  void exynos_scu_enable(void)
 
 static void __iomem *cpu_boot_reg_base(void)
 {
-	if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_1_1)
+	if (soc_dev_is_exynos4210_rev11())
 		return pmu_base_addr + S5P_INFORM5;
 	return sysram_base_addr;
 }
@@ -197,9 +197,9 @@  static inline void __iomem *cpu_boot_reg(int cpu)
 	boot_reg = cpu_boot_reg_base();
 	if (!boot_reg)
 		return IOMEM_ERR_PTR(-ENODEV);
-	if (soc_is_exynos4412())
+	if (soc_dev_is_exynos4412())
 		boot_reg += 4*cpu;
-	else if (soc_is_exynos5420() || soc_is_exynos5800())
+	else if (soc_dev_is_exynos542x())
 		boot_reg += 4;
 	return boot_reg;
 }
@@ -371,7 +371,7 @@  static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
 
 		call_firmware_op(cpu_boot, core_id);
 
-		if (soc_is_exynos3250())
+		if (soc_dev_is_exynos3250())
 			dsb_sev();
 		else
 			arch_send_wakeup_ipi_mask(cpumask_of(cpu));
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index 48e7fb3..88c1bce 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -120,7 +120,7 @@  int exynos_pm_central_resume(void)
 static void exynos_set_wakeupmask(long mask)
 {
 	pmu_raw_writel(mask, S5P_WAKEUP_MASK);
-	if (soc_is_exynos3250())
+	if (soc_dev_is_exynos3250())
 		pmu_raw_writel(0x0, S5P_WAKEUP_MASK2);
 }
 
@@ -135,7 +135,8 @@  static int exynos_aftr_finisher(unsigned long flags)
 {
 	int ret;
 
-	exynos_set_wakeupmask(soc_is_exynos3250() ? 0x40003ffe : 0x0000ff3e);
+	exynos_set_wakeupmask(soc_dev_is_exynos3250() ? 0x40003ffe
+						      : 0x0000ff3e);
 	/* Set value of power down register for aftr mode */
 	exynos_sys_powerdown_conf(SYS_AFTR);
 
@@ -156,12 +157,12 @@  void exynos_enter_aftr(void)
 
 	cpu_pm_enter();
 
-	if (soc_is_exynos3250())
+	if (soc_dev_is_exynos3250())
 		exynos_set_boot_flag(cpuid, C2_STATE);
 
 	exynos_pm_central_suspend();
 
-	if (soc_is_exynos4412()) {
+	if (soc_dev_is_exynos4412()) {
 		/* Setting SEQ_OPTION register */
 		pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0,
 			       S5P_CENTRAL_SEQ_OPTION);
@@ -177,7 +178,7 @@  void exynos_enter_aftr(void)
 
 	exynos_pm_central_resume();
 
-	if (soc_is_exynos3250())
+	if (soc_dev_is_exynos3250())
 		exynos_clear_boot_flag(cpuid, C2_STATE);
 
 	cpu_pm_exit();
@@ -248,7 +249,7 @@  static int exynos_cpu0_enter_aftr(void)
 		while (exynos_cpu_power_state(1) != S5P_CORE_LOCAL_PWR_EN)
 			cpu_relax();
 
-		if (soc_is_exynos3250()) {
+		if (soc_dev_is_exynos3250()) {
 			while (!pmu_raw_readl(S5P_PMU_SPARE2) &&
 			       !atomic_read(&cpu1_wakeup))
 				cpu_relax();
@@ -278,7 +279,7 @@  static int exynos_cpu0_enter_aftr(void)
 
 static int exynos_wfi_finisher(unsigned long flags)
 {
-	if (soc_is_exynos3250())
+	if (soc_dev_is_exynos3250())
 		flush_cache_all();
 	cpu_do_idle();
 
@@ -300,7 +301,7 @@  static int exynos_cpu1_powerdown(void)
 	 */
 	exynos_cpu_power_down(1);
 
-	if (soc_is_exynos3250())
+	if (soc_dev_is_exynos3250())
 		pmu_raw_writel(0, S5P_PMU_SPARE2);
 
 	ret = cpu_suspend(0, exynos_wfi_finisher);