diff mbox

[05/11] ARM: Introduce CPU_METHOD_OF_DECLARE() for cpu hotplug/smp

Message ID 1383343739-23080-6-git-send-email-sboyd@codeaurora.org (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Stephen Boyd Nov. 1, 2013, 10:08 p.m. UTC
The goal of multi-platform kernels is to remove the need for mach
directories and machine descriptors. To further that goal,
introduce CPU_METHOD_OF_DECLARE() to allow cpu hotplug/smp
support to be separated from the machine descriptors.
Implementers should specify an enable-method property in their
cpus node and then implement a matching set of smp_ops in their
hotplug/smp code, wiring it up with the CPU_METHOD_OF_DECLARE()
macro. When the kernel is compiled we'll collect all the
enable-method smp_ops into one section for use at boot.

At boot time we'll look for an enable-method in each cpu node and
try to match that against all known CPU enable methods in the
kernel. If there are no enable-methods in the cpu nodes we
fallback to the cpus node and try to use any enable-method found
there. If that doesn't work we fall back to the old way of using
the machine descriptor.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: <devicetree@vger.kernel.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 arch/arm/include/asm/smp.h        |  9 +++++++++
 arch/arm/kernel/devtree.c         | 38 ++++++++++++++++++++++++++++++++++++++
 include/asm-generic/vmlinux.lds.h | 10 ++++++++++
 3 files changed, 57 insertions(+)

Comments

Kumar Gala Nov. 5, 2013, 5:24 p.m. UTC | #1
On Nov 1, 2013, at 5:08 PM, Stephen Boyd wrote:

> The goal of multi-platform kernels is to remove the need for mach
> directories and machine descriptors. To further that goal,
> introduce CPU_METHOD_OF_DECLARE() to allow cpu hotplug/smp
> support to be separated from the machine descriptors.
> Implementers should specify an enable-method property in their
> cpus node and then implement a matching set of smp_ops in their
> hotplug/smp code, wiring it up with the CPU_METHOD_OF_DECLARE()
> macro. When the kernel is compiled we'll collect all the
> enable-method smp_ops into one section for use at boot.
> 
> At boot time we'll look for an enable-method in each cpu node and
> try to match that against all known CPU enable methods in the
> kernel. If there are no enable-methods in the cpu nodes we
> fallback to the cpus node and try to use any enable-method found
> there. If that doesn't work we fall back to the old way of using
> the machine descriptor.
> 
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: <devicetree@vger.kernel.org>
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> ---
> arch/arm/include/asm/smp.h        |  9 +++++++++
> arch/arm/kernel/devtree.c         | 38 ++++++++++++++++++++++++++++++++++++++
> include/asm-generic/vmlinux.lds.h | 10 ++++++++++
> 3 files changed, 57 insertions(+)
> 
> diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
> index a8cae71c..c27ec55 100644
> --- a/arch/arm/include/asm/smp.h
> +++ b/arch/arm/include/asm/smp.h
> @@ -112,6 +112,15 @@ struct smp_operations {
> #endif
> };
> 
> +struct of_cpu_method {
> +	const char *method;
> +	struct smp_operations *ops;
> +};
> +
> +#define CPU_METHOD_OF_DECLARE(name, _method, _ops)			\
> +	static const struct of_cpu_method __cpu_method_of_table_##name	\
> +		__used __section(__cpu_method_of_table)			\
> +		= { .method = _method, .ops = _ops }
> /*
>  * set platform specific SMP operations
>  */
> diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
> index f35906b..71a8592 100644
> --- a/arch/arm/kernel/devtree.c
> +++ b/arch/arm/kernel/devtree.c
> @@ -25,6 +25,7 @@
> #include <asm/smp_plat.h>
> #include <asm/mach/arch.h>
> #include <asm/mach-types.h>
> +#include <asm/smp.h>
> 
> void __init early_init_dt_add_memory_arch(u64 base, u64 size)
> {
> @@ -63,6 +64,36 @@ void __init arm_dt_memblock_reserve(void)
> 	}
> }
> 
> +#ifdef CONFIG_SMP
> +extern struct of_cpu_method __cpu_method_of_table[];
> +
> +static const struct of_cpu_method __cpu_method_of_table_sentinel
> +	__used __section(__cpu_method_of_table_end);
> +
> +static int __init set_smp_ops_by_method(struct device_node *node)
> +{
> +	const char *method;
> +	struct of_cpu_method *m = __cpu_method_of_table;
> +
> +	if (of_property_read_string(node, "enable-method", &method))
> +		return 0;
> +
> +	for (; m != &__cpu_method_of_table_sentinel; m++)
> +		if (!strcmp(m->method, method)) {
> +			smp_set_ops(m->ops);
> +			return 1;
> +		}
> +
> +	return 0;
> +}
> +#else
> +static inline int set_smp_ops_by_method(struct device_node *node)
> +{
> +	return 1;
> +}
> +#endif
> +
> +
> /*
>  * arm_dt_init_cpu_maps - Function retrieves cpu nodes from the device tree
>  * and builds the cpu logical map array containing MPIDR values related to
> @@ -79,6 +110,7 @@ void __init arm_dt_init_cpu_maps(void)
> 	 * read as 0.
> 	 */
> 	struct device_node *cpu, *cpus;
> +	int found_method = 0;
> 	u32 i, j, cpuidx = 1;
> 	u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
> 
> @@ -150,8 +182,14 @@ void __init arm_dt_init_cpu_maps(void)
> 		}
> 
> 		tmp_map[i] = hwid;
> +
> +		if (!found_method)
> +			found_method = set_smp_ops_by_method(cpu);
> 	}
> 
> +	if (!found_method)
> +		set_smp_ops_by_method(cpus);
> +

I assume this if for the case that the enable method is in the cpus{ } container but not in a specific cpu node?

If so, the binding is not clear that we allow this.  Also a comment would probably be nice.

> 	if (!bootcpu_valid) {
> 		pr_warn("DT missing boot CPU MPIDR[23:0], fall back to default cpu_logical_map\n");
> 		return;

- k
Stephen Boyd Nov. 5, 2013, 5:27 p.m. UTC | #2
On 11/05/13 09:24, Kumar Gala wrote:
> On Nov 1, 2013, at 5:08 PM, Stephen Boyd wrote:
>
>> @@ -150,8 +182,14 @@ void __init arm_dt_init_cpu_maps(void)
>> 		}
>>
>> 		tmp_map[i] = hwid;
>> +
>> +		if (!found_method)
>> +			found_method = set_smp_ops_by_method(cpu);
>> 	}
>>
>> +	if (!found_method)
>> +		set_smp_ops_by_method(cpus);
>> +
> I assume this if for the case that the enable method is in the cpus{ } container but not in a specific cpu node?
>
> If so, the binding is not clear that we allow this.  Also a comment would probably be nice.

Sure I'll add a comment to that effect and clarify the binding.
Josh Cartwright Nov. 7, 2013, 1:50 a.m. UTC | #3
Hey Stephen-

Nit/suggestion below:

On Fri, Nov 01, 2013 at 03:08:53PM -0700, Stephen Boyd wrote:
[..]
> diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
> index a8cae71c..c27ec55 100644
> --- a/arch/arm/include/asm/smp.h
> +++ b/arch/arm/include/asm/smp.h
> @@ -112,6 +112,15 @@ struct smp_operations {
>  #endif
>  };
>  
> +struct of_cpu_method {
> +	const char *method;
> +	struct smp_operations *ops;
> +};
> +
> +#define CPU_METHOD_OF_DECLARE(name, _method, _ops)			\
> +	static const struct of_cpu_method __cpu_method_of_table_##name	\
> +		__used __section(__cpu_method_of_table)			\
> +		= { .method = _method, .ops = _ops }
>  /*
>   * set platform specific SMP operations
>   */
> diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
> index f35906b..71a8592 100644
> --- a/arch/arm/kernel/devtree.c
> +++ b/arch/arm/kernel/devtree.c
> @@ -25,6 +25,7 @@
>  #include <asm/smp_plat.h>
>  #include <asm/mach/arch.h>
>  #include <asm/mach-types.h>
> +#include <asm/smp.h>
>  
>  void __init early_init_dt_add_memory_arch(u64 base, u64 size)
>  {
> @@ -63,6 +64,36 @@ void __init arm_dt_memblock_reserve(void)
>  	}
>  }
>  
> +#ifdef CONFIG_SMP
> +extern struct of_cpu_method __cpu_method_of_table[];
> +
> +static const struct of_cpu_method __cpu_method_of_table_sentinel
> +	__used __section(__cpu_method_of_table_end);

Having a sentinel allocated into the linked image makes a lot of sense
in other cases (IRQCHIP/CLOCKSOURCE_OF_DECLARE, etc), where it's used to
terminate an of_device_id table (as is expected by of_match_table and
friends).

In this case, however, you aren't building a match table, so having a
sentinel allocated isn't necessary.  I'd suggest bookending the table
with a VMLINUX_SYMBOL(__cpu_method_of_table_end) instead.

A whole 2 pointers worth of savings!
Stephen Boyd Nov. 7, 2013, 10:34 p.m. UTC | #4
On 11/06/13 17:50, Josh Cartwright wrote:
> On Fri, Nov 01, 2013 at 03:08:53PM -0700, Stephen Boyd wrote:
>> diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
>> index f35906b..71a8592 100644
>> --- a/arch/arm/kernel/devtree.c
>> +++ b/arch/arm/kernel/devtree.c
>> @@ -25,6 +25,7 @@
>>  #include <asm/smp_plat.h>
>>  #include <asm/mach/arch.h>
>>  #include <asm/mach-types.h>
>> +#include <asm/smp.h>
>>  
>>  void __init early_init_dt_add_memory_arch(u64 base, u64 size)
>>  {
>> @@ -63,6 +64,36 @@ void __init arm_dt_memblock_reserve(void)
>>  	}
>>  }
>>  
>> +#ifdef CONFIG_SMP
>> +extern struct of_cpu_method __cpu_method_of_table[];
>> +
>> +static const struct of_cpu_method __cpu_method_of_table_sentinel
>> +	__used __section(__cpu_method_of_table_end);
> Having a sentinel allocated into the linked image makes a lot of sense
> in other cases (IRQCHIP/CLOCKSOURCE_OF_DECLARE, etc), where it's used to
> terminate an of_device_id table (as is expected by of_match_table and
> friends).
>
> In this case, however, you aren't building a match table, so having a
> sentinel allocated isn't necessary.  I'd suggest bookending the table
> with a VMLINUX_SYMBOL(__cpu_method_of_table_end) instead.
>
> A whole 2 pointers worth of savings!
>

Yes, will do. Thanks.
diff mbox

Patch

diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index a8cae71c..c27ec55 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -112,6 +112,15 @@  struct smp_operations {
 #endif
 };
 
+struct of_cpu_method {
+	const char *method;
+	struct smp_operations *ops;
+};
+
+#define CPU_METHOD_OF_DECLARE(name, _method, _ops)			\
+	static const struct of_cpu_method __cpu_method_of_table_##name	\
+		__used __section(__cpu_method_of_table)			\
+		= { .method = _method, .ops = _ops }
 /*
  * set platform specific SMP operations
  */
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index f35906b..71a8592 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -25,6 +25,7 @@ 
 #include <asm/smp_plat.h>
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
+#include <asm/smp.h>
 
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
@@ -63,6 +64,36 @@  void __init arm_dt_memblock_reserve(void)
 	}
 }
 
+#ifdef CONFIG_SMP
+extern struct of_cpu_method __cpu_method_of_table[];
+
+static const struct of_cpu_method __cpu_method_of_table_sentinel
+	__used __section(__cpu_method_of_table_end);
+
+static int __init set_smp_ops_by_method(struct device_node *node)
+{
+	const char *method;
+	struct of_cpu_method *m = __cpu_method_of_table;
+
+	if (of_property_read_string(node, "enable-method", &method))
+		return 0;
+
+	for (; m != &__cpu_method_of_table_sentinel; m++)
+		if (!strcmp(m->method, method)) {
+			smp_set_ops(m->ops);
+			return 1;
+		}
+
+	return 0;
+}
+#else
+static inline int set_smp_ops_by_method(struct device_node *node)
+{
+	return 1;
+}
+#endif
+
+
 /*
  * arm_dt_init_cpu_maps - Function retrieves cpu nodes from the device tree
  * and builds the cpu logical map array containing MPIDR values related to
@@ -79,6 +110,7 @@  void __init arm_dt_init_cpu_maps(void)
 	 * read as 0.
 	 */
 	struct device_node *cpu, *cpus;
+	int found_method = 0;
 	u32 i, j, cpuidx = 1;
 	u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
 
@@ -150,8 +182,14 @@  void __init arm_dt_init_cpu_maps(void)
 		}
 
 		tmp_map[i] = hwid;
+
+		if (!found_method)
+			found_method = set_smp_ops_by_method(cpu);
 	}
 
+	if (!found_method)
+		set_smp_ops_by_method(cpus);
+
 	if (!bootcpu_valid) {
 		pr_warn("DT missing boot CPU MPIDR[23:0], fall back to default cpu_logical_map\n");
 		return;
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 83e2c31..918b1b5 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -167,6 +167,15 @@ 
 #define CLK_OF_TABLES()
 #endif
 
+#ifdef CONFIG_SMP
+#define CPU_METHOD_OF_TABLES() . = ALIGN(8);				\
+			   VMLINUX_SYMBOL(__cpu_method_of_table) = .;	\
+			   *(__cpu_method_of_table)			\
+			   *(__cpu_method_of_table_end)
+#else
+#define CPU_METHOD_OF_TABLES()
+#endif
+
 #define KERNEL_DTB()							\
 	STRUCT_ALIGN();							\
 	VMLINUX_SYMBOL(__dtb_start) = .;				\
@@ -490,6 +499,7 @@ 
 	MEM_DISCARD(init.rodata)					\
 	CLK_OF_TABLES()							\
 	CLKSRC_OF_TABLES()						\
+	CPU_METHOD_OF_TABLES()						\
 	KERNEL_DTB()							\
 	IRQCHIP_OF_MATCH_TABLE()