This patch series introduces a new cpumask which tracks CPUs that support hotplugging. The purpose of this patch series is to provide a simple method for kernel code to know which CPUs can be hotplugged and which ones cannot. Potential users of this code might be a thermal mitigation technique which uses hotplug to lower temperature, or a power capping mechanism which uses hotplug to lower power consumption.
All the of usual cpumask helper functions are created for this new mask. The second patch in this series simply sets the bit for elligible CPUs while they are being registered. The cpumask itself is static after boot and should not change (like the possbile mask).
Mike Turquette (2): cpumask: introduce cpumask for hotpluggable CPUs cpu: update cpu_hotpluggable_mask in register_cpu
drivers/base/cpu.c | 4 +++- include/linux/cpumask.h | 27 ++++++++++++++++++++++----- kernel/cpu.c | 18 ++++++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-)
On some platforms it is possible to have some CPUs which support CPU hotplug and some which do not. Currently the prescence of an 'online' sysfs entry in userspace is adequate for applications to know that a CPU supports hotplug, but there is no convenient way to make the same determination in the kernel.
To better model this relationship this patch introduces a new cpumask to track CPUs that support CPU hotplug operations.
This new cpumask is populated at boot-time and remains static for the life of the machine. Bits set in the mask indicate a CPU which supports hotplug, but make no guarantees about whether that CPU is currently online or not. Likewise a cleared bit in the mask indicates either a CPU which cannot hotplug or a lack of a populated CPU.
The purpose of this new cpumask is to aid kernel code which uses CPU to take CPUs online and offline. Possible uses are as a thermal event mitigation technique or as a power capping mechanism.
Signed-off-by: Mike Turquette mturquette@ti.com --- Change log: v2: fixed missing parentheses in cpumask_test_cpu and improved grammar in comments
include/linux/cpumask.h | 27 ++++++++++++++++++++++----- kernel/cpu.c | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index b24ac56..52e64a7 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -39,10 +39,11 @@ extern int nr_cpu_ids; * The following particular system cpumasks and operations manage * possible, present, active and online cpus. * - * cpu_possible_mask- has bit 'cpu' set iff cpu is populatable - * cpu_present_mask - has bit 'cpu' set iff cpu is populated - * cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler - * cpu_active_mask - has bit 'cpu' set iff cpu available to migration + * cpu_possible_mask - has bit 'cpu' set iff cpu is populatable + * cpu_hotpluggable_mask - has bit 'cpu' set iff cpu is hotpluggable + * cpu_present_mask - has bit 'cpu' set iff cpu is populated + * cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler + * cpu_active_mask - has bit 'cpu' set iff cpu available to migration * * If !CONFIG_HOTPLUG_CPU, present == possible, and active == online. * @@ -51,7 +52,11 @@ extern int nr_cpu_ids; * life of that system boot. The cpu_present_mask is dynamic(*), * representing which CPUs are currently plugged in. And * cpu_online_mask is the dynamic subset of cpu_present_mask, - * indicating those CPUs available for scheduling. + * indicating those CPUs available for scheduling. The + * cpu_hotpluggable_mask is also fixed at boot time as the set of CPU + * id's which are possible AND can hotplug. Cleared bits in this mask + * mean that either the CPU is not possible, or it is possible but does + * not support CPU hotplug operations. * * If HOTPLUG is enabled, then cpu_possible_mask is forced to have * all NR_CPUS bits set, otherwise it is just the set of CPUs that @@ -61,6 +66,9 @@ extern int nr_cpu_ids; * depending on what ACPI reports as currently plugged in, otherwise * cpu_present_mask is just a copy of cpu_possible_mask. * + * If HOTPLUG is not enabled then cpu_hotpluggable_mask is the empty + * set. + * * (*) Well, cpu_present_mask is dynamic in the hotplug case. If not * hotplug, it's a copy of cpu_possible_mask, hence fixed at boot. * @@ -76,6 +84,7 @@ extern int nr_cpu_ids; */
extern const struct cpumask *const cpu_possible_mask; +extern const struct cpumask *const cpu_hotpluggable_mask; extern const struct cpumask *const cpu_online_mask; extern const struct cpumask *const cpu_present_mask; extern const struct cpumask *const cpu_active_mask; @@ -85,19 +94,23 @@ extern const struct cpumask *const cpu_active_mask; #define num_possible_cpus() cpumask_weight(cpu_possible_mask) #define num_present_cpus() cpumask_weight(cpu_present_mask) #define num_active_cpus() cpumask_weight(cpu_active_mask) +#define num_hotpluggable_cpus() cpumask_weight(cpu_hotpluggable_mask) #define cpu_online(cpu) cpumask_test_cpu((cpu), cpu_online_mask) #define cpu_possible(cpu) cpumask_test_cpu((cpu), cpu_possible_mask) #define cpu_present(cpu) cpumask_test_cpu((cpu), cpu_present_mask) #define cpu_active(cpu) cpumask_test_cpu((cpu), cpu_active_mask) +#define cpu_hotpluggable(cpu) cpumask_test_cpu((cpu, cpu_hotpluggable_mask)) #else #define num_online_cpus() 1U #define num_possible_cpus() 1U #define num_present_cpus() 1U #define num_active_cpus() 1U +#define num_hotpluggable_cpus() 0 #define cpu_online(cpu) ((cpu) == 0) #define cpu_possible(cpu) ((cpu) == 0) #define cpu_present(cpu) ((cpu) == 0) #define cpu_active(cpu) ((cpu) == 0) +#define cpu_hotpluggable(cpu) 0 #endif
/* verify cpu argument to cpumask_* operators */ @@ -678,16 +691,20 @@ extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS); #define cpu_none_mask to_cpumask(cpu_bit_bitmap[0])
#define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask) +#define for_each_hotpluggable_cpu(cpu) \ + for_each_cpu((cpu), cpu_hotpluggable_mask) #define for_each_online_cpu(cpu) for_each_cpu((cpu), cpu_online_mask) #define for_each_present_cpu(cpu) for_each_cpu((cpu), cpu_present_mask)
/* Wrappers for arch boot code to manipulate normally-constant masks */ void set_cpu_possible(unsigned int cpu, bool possible); +void set_cpu_hotpluggable(unsigned int cpu, bool hotpluggable); void set_cpu_present(unsigned int cpu, bool present); void set_cpu_online(unsigned int cpu, bool online); void set_cpu_active(unsigned int cpu, bool active); void init_cpu_present(const struct cpumask *src); void init_cpu_possible(const struct cpumask *src); +void init_cpu_hotpluggable(const struct cpumask *src); void init_cpu_online(const struct cpumask *src);
/** diff --git a/kernel/cpu.c b/kernel/cpu.c index 12b7458..8c397c9 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -536,6 +536,11 @@ static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly; const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits); EXPORT_SYMBOL(cpu_possible_mask);
+static DECLARE_BITMAP(cpu_hotpluggable_bits, CONFIG_NR_CPUS) __read_mostly; +const struct cpumask *const cpu_hotpluggable_mask = + to_cpumask(cpu_hotpluggable_bits); +EXPORT_SYMBOL(cpu_hotpluggable_mask); + static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly; const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits); EXPORT_SYMBOL(cpu_online_mask); @@ -556,6 +561,14 @@ void set_cpu_possible(unsigned int cpu, bool possible) cpumask_clear_cpu(cpu, to_cpumask(cpu_possible_bits)); }
+void set_cpu_hotpluggable(unsigned int cpu, bool hotpluggable) +{ + if (hotpluggable) + cpumask_set_cpu(cpu, to_cpumask(cpu_hotpluggable_bits)); + else + cpumask_clear_cpu(cpu, to_cpumask(cpu_hotpluggable_bits)); +} + void set_cpu_present(unsigned int cpu, bool present) { if (present) @@ -590,6 +603,11 @@ void init_cpu_possible(const struct cpumask *src) cpumask_copy(to_cpumask(cpu_possible_bits), src); }
+void init_cpu_hotpluggable(const struct cpumask *src) +{ + cpumask_copy(to_cpumask(cpu_hotpluggable_bits), src); +} + void init_cpu_online(const struct cpumask *src) { cpumask_copy(to_cpumask(cpu_online_bits), src);
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 08/10/2011 10:03 PM, Mike Turquette wrote:
On some platforms it is possible to have some CPUs which support CPU hotplug and some which do not. Currently the prescence of an 'online' sysfs entry in userspace is adequate for applications to know that a CPU supports hotplug, but there is no convenient way to make the same determination in the kernel.
To better model this relationship this patch introduces a new cpumask to track CPUs that support CPU hotplug operations.
This new cpumask is populated at boot-time and remains static for the life of the machine. Bits set in the mask indicate a CPU which supports hotplug, but make no guarantees about whether that CPU is currently online or not. Likewise a cleared bit in the mask indicates either a CPU which cannot hotplug or a lack of a populated CPU.
The purpose of this new cpumask is to aid kernel code which uses CPU to take CPUs online and offline. Possible uses are as a thermal event mitigation technique or as a power capping mechanism.
Signed-off-by: Mike Turquette mturquette@ti.com
Reviewed-by: Daniel Lezcano daniel.lezcano@linaro.org
- -- 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
See comments inline.
On 11 Aug 10, Mike Turquette wrote:
On some platforms it is possible to have some CPUs which support CPU hotplug and some which do not. Currently the prescence of an 'online' sysfs entry in userspace is adequate for applications to know that a CPU supports hotplug, but there is no convenient way to make the same determination in the kernel.
To better model this relationship this patch introduces a new cpumask to track CPUs that support CPU hotplug operations.
This new cpumask is populated at boot-time and remains static for the life of the machine. Bits set in the mask indicate a CPU which supports hotplug, but make no guarantees about whether that CPU is currently online or not. Likewise a cleared bit in the mask indicates either a CPU which cannot hotplug or a lack of a populated CPU.
The purpose of this new cpumask is to aid kernel code which uses CPU to take CPUs online and offline. Possible uses are as a thermal event mitigation technique or as a power capping mechanism.
Signed-off-by: Mike Turquette mturquette@ti.com
Change log: v2: fixed missing parentheses in cpumask_test_cpu and improved grammar in comments
include/linux/cpumask.h | 27 ++++++++++++++++++++++----- kernel/cpu.c | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index b24ac56..52e64a7 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -39,10 +39,11 @@ extern int nr_cpu_ids;
- The following particular system cpumasks and operations manage
- possible, present, active and online cpus.
cpu_possible_mask- has bit 'cpu' set iff cpu is populatable
cpu_present_mask - has bit 'cpu' set iff cpu is populated
cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler
cpu_active_mask - has bit 'cpu' set iff cpu available to migration
cpu_possible_mask - has bit 'cpu' set iff cpu is populatable
cpu_hotpluggable_mask - has bit 'cpu' set iff cpu is hotpluggable
cpu_present_mask - has bit 'cpu' set iff cpu is populated
cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler
cpu_active_mask - has bit 'cpu' set iff cpu available to migration
- If !CONFIG_HOTPLUG_CPU, present == possible, and active == online.
@@ -51,7 +52,11 @@ extern int nr_cpu_ids;
- life of that system boot. The cpu_present_mask is dynamic(*),
- representing which CPUs are currently plugged in. And
- cpu_online_mask is the dynamic subset of cpu_present_mask,
- indicating those CPUs available for scheduling.
- indicating those CPUs available for scheduling. The
- cpu_hotpluggable_mask is also fixed at boot time as the set of CPU
- id's which are possible AND can hotplug. Cleared bits in this mask
- mean that either the CPU is not possible, or it is possible but does
- not support CPU hotplug operations.
- If HOTPLUG is enabled, then cpu_possible_mask is forced to have
- all NR_CPUS bits set, otherwise it is just the set of CPUs that
@@ -61,6 +66,9 @@ extern int nr_cpu_ids;
- depending on what ACPI reports as currently plugged in, otherwise
- cpu_present_mask is just a copy of cpu_possible_mask.
- If HOTPLUG is not enabled then cpu_hotpluggable_mask is the empty
- set.
- (*) Well, cpu_present_mask is dynamic in the hotplug case. If not
hotplug, it's a copy of cpu_possible_mask, hence fixed at boot.
@@ -76,6 +84,7 @@ extern int nr_cpu_ids; */ extern const struct cpumask *const cpu_possible_mask; +extern const struct cpumask *const cpu_hotpluggable_mask; extern const struct cpumask *const cpu_online_mask; extern const struct cpumask *const cpu_present_mask; extern const struct cpumask *const cpu_active_mask; @@ -85,19 +94,23 @@ extern const struct cpumask *const cpu_active_mask; #define num_possible_cpus() cpumask_weight(cpu_possible_mask) #define num_present_cpus() cpumask_weight(cpu_present_mask) #define num_active_cpus() cpumask_weight(cpu_active_mask) +#define num_hotpluggable_cpus() cpumask_weight(cpu_hotpluggable_mask) #define cpu_online(cpu) cpumask_test_cpu((cpu), cpu_online_mask) #define cpu_possible(cpu) cpumask_test_cpu((cpu), cpu_possible_mask) #define cpu_present(cpu) cpumask_test_cpu((cpu), cpu_present_mask) #define cpu_active(cpu) cpumask_test_cpu((cpu), cpu_active_mask) +#define cpu_hotpluggable(cpu) cpumask_test_cpu((cpu, cpu_hotpluggable_mask))
The bracket should be around cpu, like this (cpu) so that there are no side-effects when passing anything to the macro. See the other #defines above.
#else #define num_online_cpus() 1U #define num_possible_cpus() 1U #define num_present_cpus() 1U #define num_active_cpus() 1U +#define num_hotpluggable_cpus() 0 #define cpu_online(cpu) ((cpu) == 0) #define cpu_possible(cpu) ((cpu) == 0) #define cpu_present(cpu) ((cpu) == 0) #define cpu_active(cpu) ((cpu) == 0) +#define cpu_hotpluggable(cpu) 0 #endif /* verify cpu argument to cpumask_* operators */ @@ -678,16 +691,20 @@ extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS); #define cpu_none_mask to_cpumask(cpu_bit_bitmap[0]) #define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask) +#define for_each_hotpluggable_cpu(cpu) \
for_each_cpu((cpu), cpu_hotpluggable_mask)
#define for_each_online_cpu(cpu) for_each_cpu((cpu), cpu_online_mask) #define for_each_present_cpu(cpu) for_each_cpu((cpu), cpu_present_mask) /* Wrappers for arch boot code to manipulate normally-constant masks */ void set_cpu_possible(unsigned int cpu, bool possible); +void set_cpu_hotpluggable(unsigned int cpu, bool hotpluggable); void set_cpu_present(unsigned int cpu, bool present); void set_cpu_online(unsigned int cpu, bool online); void set_cpu_active(unsigned int cpu, bool active); void init_cpu_present(const struct cpumask *src); void init_cpu_possible(const struct cpumask *src); +void init_cpu_hotpluggable(const struct cpumask *src); void init_cpu_online(const struct cpumask *src); /** diff --git a/kernel/cpu.c b/kernel/cpu.c index 12b7458..8c397c9 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -536,6 +536,11 @@ static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly; const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits); EXPORT_SYMBOL(cpu_possible_mask); +static DECLARE_BITMAP(cpu_hotpluggable_bits, CONFIG_NR_CPUS) __read_mostly; +const struct cpumask *const cpu_hotpluggable_mask =
to_cpumask(cpu_hotpluggable_bits);
+EXPORT_SYMBOL(cpu_hotpluggable_mask);
static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly; const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits); EXPORT_SYMBOL(cpu_online_mask); @@ -556,6 +561,14 @@ void set_cpu_possible(unsigned int cpu, bool possible) cpumask_clear_cpu(cpu, to_cpumask(cpu_possible_bits)); } +void set_cpu_hotpluggable(unsigned int cpu, bool hotpluggable) +{
- if (hotpluggable)
cpumask_set_cpu(cpu, to_cpumask(cpu_hotpluggable_bits));
- else
cpumask_clear_cpu(cpu, to_cpumask(cpu_hotpluggable_bits));
+}
void set_cpu_present(unsigned int cpu, bool present) { if (present) @@ -590,6 +603,11 @@ void init_cpu_possible(const struct cpumask *src) cpumask_copy(to_cpumask(cpu_possible_bits), src); } +void init_cpu_hotpluggable(const struct cpumask *src) +{
- cpumask_copy(to_cpumask(cpu_hotpluggable_bits), src);
+}
Just to be clear I understand this code, init_cpu_hotpluggable will be called in arch code, right? e.g. arch/arm/kernel/smp.c or do you intend for it to be called in platform-specific code?
void init_cpu_online(const struct cpumask *src) { cpumask_copy(to_cpumask(cpu_online_bits), src); -- 1.7.4.1
On Wed, Aug 10, 2011 at 11:06 PM, Amit Kucheria amit.kucheria@linaro.org wrote:
See comments inline.
On 11 Aug 10, Mike Turquette wrote:
On some platforms it is possible to have some CPUs which support CPU hotplug and some which do not. Currently the prescence of an 'online' sysfs entry in userspace is adequate for applications to know that a CPU supports hotplug, but there is no convenient way to make the same determination in the kernel.
To better model this relationship this patch introduces a new cpumask to track CPUs that support CPU hotplug operations.
This new cpumask is populated at boot-time and remains static for the life of the machine. Bits set in the mask indicate a CPU which supports hotplug, but make no guarantees about whether that CPU is currently online or not. Likewise a cleared bit in the mask indicates either a CPU which cannot hotplug or a lack of a populated CPU.
The purpose of this new cpumask is to aid kernel code which uses CPU to take CPUs online and offline. Possible uses are as a thermal event mitigation technique or as a power capping mechanism.
Signed-off-by: Mike Turquette mturquette@ti.com
Change log: v2: fixed missing parentheses in cpumask_test_cpu and improved grammar in comments
include/linux/cpumask.h | 27 ++++++++++++++++++++++----- kernel/cpu.c | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index b24ac56..52e64a7 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -39,10 +39,11 @@ extern int nr_cpu_ids; * The following particular system cpumasks and operations manage * possible, present, active and online cpus. *
- cpu_possible_mask- has bit 'cpu' set iff cpu is populatable
- cpu_present_mask - has bit 'cpu' set iff cpu is populated
- cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler
- cpu_active_mask - has bit 'cpu' set iff cpu available to migration
- cpu_possible_mask - has bit 'cpu' set iff cpu is populatable
- cpu_hotpluggable_mask - has bit 'cpu' set iff cpu is hotpluggable
- cpu_present_mask - has bit 'cpu' set iff cpu is populated
- cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler
- cpu_active_mask - has bit 'cpu' set iff cpu available to migration
* * If !CONFIG_HOTPLUG_CPU, present == possible, and active == online. * @@ -51,7 +52,11 @@ extern int nr_cpu_ids; * life of that system boot. The cpu_present_mask is dynamic(*), * representing which CPUs are currently plugged in. And * cpu_online_mask is the dynamic subset of cpu_present_mask,
- indicating those CPUs available for scheduling.
- indicating those CPUs available for scheduling. The
- cpu_hotpluggable_mask is also fixed at boot time as the set of CPU
- id's which are possible AND can hotplug. Cleared bits in this mask
- mean that either the CPU is not possible, or it is possible but does
- not support CPU hotplug operations.
* * If HOTPLUG is enabled, then cpu_possible_mask is forced to have * all NR_CPUS bits set, otherwise it is just the set of CPUs that @@ -61,6 +66,9 @@ extern int nr_cpu_ids; * depending on what ACPI reports as currently plugged in, otherwise * cpu_present_mask is just a copy of cpu_possible_mask. *
- If HOTPLUG is not enabled then cpu_hotpluggable_mask is the empty
- set.
* (*) Well, cpu_present_mask is dynamic in the hotplug case. If not * hotplug, it's a copy of cpu_possible_mask, hence fixed at boot. * @@ -76,6 +84,7 @@ extern int nr_cpu_ids; */
extern const struct cpumask *const cpu_possible_mask; +extern const struct cpumask *const cpu_hotpluggable_mask; extern const struct cpumask *const cpu_online_mask; extern const struct cpumask *const cpu_present_mask; extern const struct cpumask *const cpu_active_mask; @@ -85,19 +94,23 @@ extern const struct cpumask *const cpu_active_mask; #define num_possible_cpus() cpumask_weight(cpu_possible_mask) #define num_present_cpus() cpumask_weight(cpu_present_mask) #define num_active_cpus() cpumask_weight(cpu_active_mask) +#define num_hotpluggable_cpus() cpumask_weight(cpu_hotpluggable_mask) #define cpu_online(cpu) cpumask_test_cpu((cpu), cpu_online_mask) #define cpu_possible(cpu) cpumask_test_cpu((cpu), cpu_possible_mask) #define cpu_present(cpu) cpumask_test_cpu((cpu), cpu_present_mask) #define cpu_active(cpu) cpumask_test_cpu((cpu), cpu_active_mask) +#define cpu_hotpluggable(cpu) cpumask_test_cpu((cpu, cpu_hotpluggable_mask))
The bracket should be around cpu, like this (cpu) so that there are no side-effects when passing anything to the macro. See the other #defines above.
Wow, not sure how that happened... will send in V3...
#else #define num_online_cpus() 1U #define num_possible_cpus() 1U #define num_present_cpus() 1U #define num_active_cpus() 1U +#define num_hotpluggable_cpus() 0 #define cpu_online(cpu) ((cpu) == 0) #define cpu_possible(cpu) ((cpu) == 0) #define cpu_present(cpu) ((cpu) == 0) #define cpu_active(cpu) ((cpu) == 0) +#define cpu_hotpluggable(cpu) 0 #endif
/* verify cpu argument to cpumask_* operators */ @@ -678,16 +691,20 @@ extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS); #define cpu_none_mask to_cpumask(cpu_bit_bitmap[0])
#define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask) +#define for_each_hotpluggable_cpu(cpu) \
- for_each_cpu((cpu), cpu_hotpluggable_mask)
#define for_each_online_cpu(cpu) for_each_cpu((cpu), cpu_online_mask) #define for_each_present_cpu(cpu) for_each_cpu((cpu), cpu_present_mask)
/* Wrappers for arch boot code to manipulate normally-constant masks */ void set_cpu_possible(unsigned int cpu, bool possible); +void set_cpu_hotpluggable(unsigned int cpu, bool hotpluggable); void set_cpu_present(unsigned int cpu, bool present); void set_cpu_online(unsigned int cpu, bool online); void set_cpu_active(unsigned int cpu, bool active); void init_cpu_present(const struct cpumask *src); void init_cpu_possible(const struct cpumask *src); +void init_cpu_hotpluggable(const struct cpumask *src); void init_cpu_online(const struct cpumask *src);
/** diff --git a/kernel/cpu.c b/kernel/cpu.c index 12b7458..8c397c9 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -536,6 +536,11 @@ static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly; const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits); EXPORT_SYMBOL(cpu_possible_mask);
+static DECLARE_BITMAP(cpu_hotpluggable_bits, CONFIG_NR_CPUS) __read_mostly; +const struct cpumask *const cpu_hotpluggable_mask =
- to_cpumask(cpu_hotpluggable_bits);
+EXPORT_SYMBOL(cpu_hotpluggable_mask);
static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly; const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits); EXPORT_SYMBOL(cpu_online_mask); @@ -556,6 +561,14 @@ void set_cpu_possible(unsigned int cpu, bool possible) cpumask_clear_cpu(cpu, to_cpumask(cpu_possible_bits)); }
+void set_cpu_hotpluggable(unsigned int cpu, bool hotpluggable) +{
- if (hotpluggable)
- cpumask_set_cpu(cpu, to_cpumask(cpu_hotpluggable_bits));
- else
- cpumask_clear_cpu(cpu, to_cpumask(cpu_hotpluggable_bits));
+}
void set_cpu_present(unsigned int cpu, bool present) { if (present) @@ -590,6 +603,11 @@ void init_cpu_possible(const struct cpumask *src) cpumask_copy(to_cpumask(cpu_possible_bits), src); }
+void init_cpu_hotpluggable(const struct cpumask *src) +{
- cpumask_copy(to_cpumask(cpu_hotpluggable_bits), src);
+}
Just to be clear I understand this code, init_cpu_hotpluggable will be called in arch code, right? e.g. arch/arm/kernel/smp.c or do you intend for it to be called in platform-specific code?
It could be called in either, though I assume arch code is a better place to call this.
This call is made redundant by patch 2 which populates the hotpluggable bits in register_cpu, but some platforms might still need it so it is included for completeness sake. x86 and ARM will not call this, for example. In fact I could not find any users of the init_cpu_xxx cpumask helpers on any architectures.
Thanks, Mike
void init_cpu_online(const struct cpumask *src) { cpumask_copy(to_cpumask(cpu_online_bits), src); -- 1.7.4.1
Update the cpu_hotpluggable_mask for each registered CPU which supports hotplug. This makes it trivial for kernel code to know which CPUs support hotplug operations.
Signed-off-by: Mike Turquette mturquette@ti.com --- Change log: v2: no change
drivers/base/cpu.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 251acea..91ddcf8 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -224,8 +224,10 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
error = sysdev_register(&cpu->sysdev);
- if (!error && cpu->hotpluggable) + if (!error && cpu->hotpluggable) { register_cpu_control(cpu); + set_cpu_hotpluggable(num, true); + } if (!error) per_cpu(cpu_sys_devices, num) = &cpu->sysdev; if (!error)
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 08/10/2011 10:03 PM, Mike Turquette wrote:
Update the cpu_hotpluggable_mask for each registered CPU which supports hotplug. This makes it trivial for kernel code to know which CPUs support hotplug operations.
Signed-off-by: Mike Turquette mturquette@ti.com
Reviewed-by: <Daniel Lezcano> daniel.lezcano@linaro.org
- -- 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
On Wed, 2011-08-10 at 13:03 -0700, Mike Turquette wrote:
This patch series introduces a new cpumask which tracks CPUs that support hotplugging. The purpose of this patch series is to provide a simple method for kernel code to know which CPUs can be hotplugged and which ones cannot. Potential users of this code might be a thermal mitigation technique which uses hotplug to lower temperature, or a power capping mechanism which uses hotplug to lower power consumption.
All the of usual cpumask helper functions are created for this new mask. The second patch in this series simply sets the bit for elligible CPUs while they are being registered. The cpumask itself is static after boot and should not change (like the possbile mask).
I still most strongly object to people using hotplug for these goals.
Why do you need to go through the entire dance of hotplug just to idle a cpu? Hotplug not only idles the cpu but tears down (and rebuilds) an insane amount of resources associated with the cpu.
Nacked-by: Peter Zijlstra a.p.zijlstra@chello.nl
On Thu, Aug 11, 2011 at 11:30 AM, Peter Zijlstra peterz@infradead.org wrote:
On Wed, 2011-08-10 at 13:03 -0700, Mike Turquette wrote:
This patch series introduces a new cpumask which tracks CPUs that support hotplugging. The purpose of this patch series is to provide a simple method for kernel code to know which CPUs can be hotplugged and which ones cannot. Potential users of this code might be a thermal mitigation technique which uses hotplug to lower temperature, or a power capping mechanism which uses hotplug to lower power consumption.
All the of usual cpumask helper functions are created for this new mask. The second patch in this series simply sets the bit for elligible CPUs while they are being registered. The cpumask itself is static after boot and should not change (like the possbile mask).
I still most strongly object to people using hotplug for these goals.
Why do you need to go through the entire dance of hotplug just to idle a cpu? Hotplug not only idles the cpu but tears down (and rebuilds) an insane amount of resources associated with the cpu.
I think you're nacking the wrong series. This patchset simply allows kernel space to know which CPUs can go offline and which one can't, which seems pretty innocuous. Are you fundamentally opposed to the kernel having better accessor functions to this data?
I'll soon be posting some code which does implement hotplug as a power-capping feature. I think *that* is the patch that you'll want to nack.
Thanks for reviewing, Mike
Nacked-by: Peter Zijlstra a.p.zijlstra@chello.nl
On Thu, 2011-08-11 at 12:25 -0700, Turquette, Mike wrote:
On Thu, Aug 11, 2011 at 11:30 AM, Peter Zijlstra peterz@infradead.org wrote:
On Wed, 2011-08-10 at 13:03 -0700, Mike Turquette wrote:
This patch series introduces a new cpumask which tracks CPUs that support hotplugging. The purpose of this patch series is to provide a simple method for kernel code to know which CPUs can be hotplugged and which ones cannot. Potential users of this code might be a thermal mitigation technique which uses hotplug to lower temperature, or a power capping mechanism which uses hotplug to lower power consumption.
All the of usual cpumask helper functions are created for this new mask. The second patch in this series simply sets the bit for elligible CPUs while they are being registered. The cpumask itself is static after boot and should not change (like the possbile mask).
I still most strongly object to people using hotplug for these goals.
Why do you need to go through the entire dance of hotplug just to idle a cpu? Hotplug not only idles the cpu but tears down (and rebuilds) an insane amount of resources associated with the cpu.
I think you're nacking the wrong series. This patchset simply allows kernel space to know which CPUs can go offline and which one can't, which seems pretty innocuous. Are you fundamentally opposed to the kernel having better accessor functions to this data?
Yeah, people might think its sane to use it..
I'll soon be posting some code which does implement hotplug as a power-capping feature. I think *that* is the patch that you'll want to nack.
That too of course..
On some platforms it is possible to have some CPUs which support CPU hotplug and some which do not. Currently the prescence of an 'online' sysfs entry in userspace is adequate for applications to know that a CPU supports hotplug, but there is no convenient way to make the same determination in the kernel.
To better model this relationship this patch introduces a new cpumask to track CPUs that support CPU hotplug operations.
This new cpumask is populated at boot-time and remains static for the life of the machine. Bits set in the mask indicate a CPU which supports hotplug, but make no guarantees about whether that CPU is currently online or not. Likewise a cleared bit in the mask indicates either a CPU which cannot hotplug or a lack of a populated CPU.
The purpose of this new cpumask is to aid kernel code which uses CPU to take CPUs online and offline. Possible uses are as a thermal event mitigation technique or as a power capping mechanism.
Signed-off-by: Mike Turquette mturquette@ti.com --- Change log: v2: fixed missing parentheses in cpumask_test_cpu and improved grammar in comments v3: really fixed the parentheses issue from v2
include/linux/cpumask.h | 27 ++++++++++++++++++++++----- kernel/cpu.c | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index b24ac56..9584807 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -39,10 +39,11 @@ extern int nr_cpu_ids; * The following particular system cpumasks and operations manage * possible, present, active and online cpus. * - * cpu_possible_mask- has bit 'cpu' set iff cpu is populatable - * cpu_present_mask - has bit 'cpu' set iff cpu is populated - * cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler - * cpu_active_mask - has bit 'cpu' set iff cpu available to migration + * cpu_possible_mask - has bit 'cpu' set iff cpu is populatable + * cpu_hotpluggable_mask - has bit 'cpu' set iff cpu is hotpluggable + * cpu_present_mask - has bit 'cpu' set iff cpu is populated + * cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler + * cpu_active_mask - has bit 'cpu' set iff cpu available to migration * * If !CONFIG_HOTPLUG_CPU, present == possible, and active == online. * @@ -51,7 +52,11 @@ extern int nr_cpu_ids; * life of that system boot. The cpu_present_mask is dynamic(*), * representing which CPUs are currently plugged in. And * cpu_online_mask is the dynamic subset of cpu_present_mask, - * indicating those CPUs available for scheduling. + * indicating those CPUs available for scheduling. The + * cpu_hotpluggable_mask is also fixed at boot time as the set of CPU + * id's which are possible AND can hotplug. Cleared bits in this mask + * mean that either the CPU is not possible, or it is possible but does + * not support CPU hotplug operations. * * If HOTPLUG is enabled, then cpu_possible_mask is forced to have * all NR_CPUS bits set, otherwise it is just the set of CPUs that @@ -61,6 +66,9 @@ extern int nr_cpu_ids; * depending on what ACPI reports as currently plugged in, otherwise * cpu_present_mask is just a copy of cpu_possible_mask. * + * If HOTPLUG is not enabled then cpu_hotpluggable_mask is the empty + * set. + * * (*) Well, cpu_present_mask is dynamic in the hotplug case. If not * hotplug, it's a copy of cpu_possible_mask, hence fixed at boot. * @@ -76,6 +84,7 @@ extern int nr_cpu_ids; */
extern const struct cpumask *const cpu_possible_mask; +extern const struct cpumask *const cpu_hotpluggable_mask; extern const struct cpumask *const cpu_online_mask; extern const struct cpumask *const cpu_present_mask; extern const struct cpumask *const cpu_active_mask; @@ -85,19 +94,23 @@ extern const struct cpumask *const cpu_active_mask; #define num_possible_cpus() cpumask_weight(cpu_possible_mask) #define num_present_cpus() cpumask_weight(cpu_present_mask) #define num_active_cpus() cpumask_weight(cpu_active_mask) +#define num_hotpluggable_cpus() cpumask_weight(cpu_hotpluggable_mask) #define cpu_online(cpu) cpumask_test_cpu((cpu), cpu_online_mask) #define cpu_possible(cpu) cpumask_test_cpu((cpu), cpu_possible_mask) #define cpu_present(cpu) cpumask_test_cpu((cpu), cpu_present_mask) #define cpu_active(cpu) cpumask_test_cpu((cpu), cpu_active_mask) +#define cpu_hotpluggable(cpu) cpumask_test_cpu((cpu), cpu_hotpluggable_mask) #else #define num_online_cpus() 1U #define num_possible_cpus() 1U #define num_present_cpus() 1U #define num_active_cpus() 1U +#define num_hotpluggable_cpus() 0 #define cpu_online(cpu) ((cpu) == 0) #define cpu_possible(cpu) ((cpu) == 0) #define cpu_present(cpu) ((cpu) == 0) #define cpu_active(cpu) ((cpu) == 0) +#define cpu_hotpluggable(cpu) 0 #endif
/* verify cpu argument to cpumask_* operators */ @@ -678,16 +691,20 @@ extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS); #define cpu_none_mask to_cpumask(cpu_bit_bitmap[0])
#define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask) +#define for_each_hotpluggable_cpu(cpu) \ + for_each_cpu((cpu), cpu_hotpluggable_mask) #define for_each_online_cpu(cpu) for_each_cpu((cpu), cpu_online_mask) #define for_each_present_cpu(cpu) for_each_cpu((cpu), cpu_present_mask)
/* Wrappers for arch boot code to manipulate normally-constant masks */ void set_cpu_possible(unsigned int cpu, bool possible); +void set_cpu_hotpluggable(unsigned int cpu, bool hotpluggable); void set_cpu_present(unsigned int cpu, bool present); void set_cpu_online(unsigned int cpu, bool online); void set_cpu_active(unsigned int cpu, bool active); void init_cpu_present(const struct cpumask *src); void init_cpu_possible(const struct cpumask *src); +void init_cpu_hotpluggable(const struct cpumask *src); void init_cpu_online(const struct cpumask *src);
/** diff --git a/kernel/cpu.c b/kernel/cpu.c index 12b7458..8c397c9 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -536,6 +536,11 @@ static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly; const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits); EXPORT_SYMBOL(cpu_possible_mask);
+static DECLARE_BITMAP(cpu_hotpluggable_bits, CONFIG_NR_CPUS) __read_mostly; +const struct cpumask *const cpu_hotpluggable_mask = + to_cpumask(cpu_hotpluggable_bits); +EXPORT_SYMBOL(cpu_hotpluggable_mask); + static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly; const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits); EXPORT_SYMBOL(cpu_online_mask); @@ -556,6 +561,14 @@ void set_cpu_possible(unsigned int cpu, bool possible) cpumask_clear_cpu(cpu, to_cpumask(cpu_possible_bits)); }
+void set_cpu_hotpluggable(unsigned int cpu, bool hotpluggable) +{ + if (hotpluggable) + cpumask_set_cpu(cpu, to_cpumask(cpu_hotpluggable_bits)); + else + cpumask_clear_cpu(cpu, to_cpumask(cpu_hotpluggable_bits)); +} + void set_cpu_present(unsigned int cpu, bool present) { if (present) @@ -590,6 +603,11 @@ void init_cpu_possible(const struct cpumask *src) cpumask_copy(to_cpumask(cpu_possible_bits), src); }
+void init_cpu_hotpluggable(const struct cpumask *src) +{ + cpumask_copy(to_cpumask(cpu_hotpluggable_bits), src); +} + void init_cpu_online(const struct cpumask *src) { cpumask_copy(to_cpumask(cpu_online_bits), src);
Update the cpu_hotpluggable_mask for each registered CPU which supports hotplug. This makes it trivial for kernel code to know which CPUs support hotplug operations.
Signed-off-by: Mike Turquette mturquette@ti.com --- Change log: v2: no change v3: no change
drivers/base/cpu.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 251acea..91ddcf8 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -224,8 +224,10 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
error = sysdev_register(&cpu->sysdev);
- if (!error && cpu->hotpluggable) + if (!error && cpu->hotpluggable) { register_cpu_control(cpu); + set_cpu_hotpluggable(num, true); + } if (!error) per_cpu(cpu_sys_devices, num) = &cpu->sysdev; if (!error)
On Thu, 2011-08-11 at 12:54 -0700, Mike Turquette wrote:
On some platforms it is possible to have some CPUs which support CPU hotplug and some which do not. Currently the prescence of an 'online' sysfs entry in userspace is adequate for applications to know that a CPU supports hotplug, but there is no convenient way to make the same determination in the kernel.
To better model this relationship this patch introduces a new cpumask to track CPUs that support CPU hotplug operations.
This new cpumask is populated at boot-time and remains static for the life of the machine. Bits set in the mask indicate a CPU which supports hotplug, but make no guarantees about whether that CPU is currently online or not. Likewise a cleared bit in the mask indicates either a CPU which cannot hotplug or a lack of a populated CPU.
The purpose of this new cpumask is to aid kernel code which uses CPU to take CPUs online and offline. Possible uses are as a thermal event mitigation technique or as a power capping mechanism.
Nacked-by: Peter Zijlstra a.p.zijlstra@chello.nl
the kernel really shouldn't be using hotplug for this (nor should userspace really). hot-unplugging random cpus wrecks things like cpusets. Furthermore hotplug does way too much work to use as a simple means to idle a cpu.
Even the availability of this mask is wrong, since that implies the information is useful, which per the above it is not, the kernel shouldn't care about this full-stop.
The only reason for the OS to unplug a CPU is imminent and unavoidable hardware failure. Thermal capping is not that (and yes ACPI-4.0 is a broken piece of shit).