diff options
| author | Andrew Morton <akpm@osdl.org> | 2004-05-14 05:44:45 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-05-14 05:44:45 -0700 |
| commit | fda94eff9b081a5e498d7d9aabf7d418f5249b0d (patch) | |
| tree | 3bc75d533ccb2273eb47a1b5ade4a317ba0cf271 | |
| parent | 4af52c2390574f7cb34cbf04a159238ee2c873fe (diff) | |
[PATCH] Revisited: ia64-cpu-hotplug-cpu_present.patch
From: Paul Jackson <pj@sgi.com>
With a hotplug capable kernel, there is a requirement to distinguish a
possible CPU from one actually present. The set of possible CPU numbers
doesn't change during a single system boot, but the set of present CPUs
changes as CPUs are physically inserted into or removed from a system. The
cpu_possible_map does not change once initialized at boot, but the
cpu_present_map changes dynamically as CPUs are inserted or removed.
Paul Jackson <pj@sgi.com> provided an expanded explanation:
Ashok's cpu hot plug patch adds a cpu_present_map, resulting in the following
cpu maps being available. All the following maps are fixed size bitmaps of
size NR_CPUS.
#ifdef CONFIG_HOTPLUG_CPU
cpu_possible_map - map with all NR_CPUS bits set
cpu_present_map - map with bit 'cpu' set iff cpu is populated
cpu_online_map - map with bit 'cpu' set iff cpu available to scheduler
#else
cpu_possible_map - map with bit 'cpu' set iff cpu is populated
cpu_present_map - copy of cpu_possible_map
cpu_online_map - map with bit 'cpu' set iff cpu available to scheduler
#endif
In either case, NR_CPUS is fixed at compile time, as the static size of these
bitmaps. The cpu_possible_map is fixed at boot time, as the set of CPU id's
that it is possible might ever be plugged in at anytime during the life of
that system boot. The cpu_present_map is dynamic(*), representing which CPUs
are currently plugged in. And cpu_online_map is the dynamic subset of
cpu_present_map, indicating those CPUs available for scheduling.
If HOTPLUG is enabled, then cpu_possible_map is forced to have all NR_CPUS
bits set, otherwise it is just the set of CPUs that ACPI reports present at
boot.
If HOTPLUG is enabled, then cpu_present_map varies dynamically, depending on
what ACPI reports as currently plugged in, otherwise cpu_present_map is just a
copy of cpu_possible_map.
(*) Well, cpu_present_map is dynamic in the hotplug case. If not hotplug,
it's the same as cpu_possible_map, hence fixed at boot.
| -rw-r--r-- | arch/ia64/kernel/smpboot.c | 22 | ||||
| -rw-r--r-- | fs/buffer.c | 2 | ||||
| -rw-r--r-- | fs/proc/proc_misc.c | 4 | ||||
| -rw-r--r-- | include/asm-ia64/smp.h | 3 | ||||
| -rw-r--r-- | include/linux/cpumask.h | 11 | ||||
| -rw-r--r-- | init/main.c | 23 | ||||
| -rw-r--r-- | kernel/cpu.c | 10 | ||||
| -rw-r--r-- | kernel/fork.c | 2 | ||||
| -rw-r--r-- | kernel/sched.c | 6 | ||||
| -rw-r--r-- | kernel/timer.c | 2 |
10 files changed, 62 insertions, 23 deletions
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 0182b7022c11..81b372a7ae56 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -75,11 +75,11 @@ extern unsigned long ia64_iobase; task_t *task_for_booting_cpu; -/* Bitmask of currently online CPUs */ +/* Bitmasks of currently online, and possible CPUs */ cpumask_t cpu_online_map; EXPORT_SYMBOL(cpu_online_map); -cpumask_t phys_cpu_present_map; -EXPORT_SYMBOL(phys_cpu_present_map); +cpumask_t cpu_possible_map; +EXPORT_SYMBOL(cpu_possible_map); /* which logical CPU number maps to which CPU (physical APIC ID) */ volatile int ia64_cpu_to_sapicid[NR_CPUS]; @@ -99,6 +99,7 @@ static int __init nointroute (char *str) { no_int_routing = 1; + printk ("no_int_routing on\n"); return 1; } @@ -441,14 +442,15 @@ smp_build_cpu_map (void) ia64_cpu_to_sapicid[cpu] = -1; ia64_cpu_to_sapicid[0] = boot_cpu_id; - cpus_clear(phys_cpu_present_map); - cpu_set(0, phys_cpu_present_map); - + cpus_clear(cpu_present_map); + cpu_set(0, cpu_present_map); + cpu_set(0, cpu_possible_map); for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) { sapicid = smp_boot_data.cpu_phys_id[i]; if (sapicid == boot_cpu_id) continue; - cpu_set(cpu, phys_cpu_present_map); + cpu_set(cpu, cpu_present_map); + cpu_set(cpu, cpu_possible_map); ia64_cpu_to_sapicid[cpu] = sapicid; cpu++; } @@ -529,9 +531,11 @@ smp_prepare_cpus (unsigned int max_cpus) if (!max_cpus) { printk(KERN_INFO "SMP mode deactivated.\n"); cpus_clear(cpu_online_map); - cpus_clear(phys_cpu_present_map); + cpus_clear(cpu_present_map); + cpus_clear(cpu_possible_map); cpu_set(0, cpu_online_map); - cpu_set(0, phys_cpu_present_map); + cpu_set(0, cpu_present_map); + cpu_set(0, cpu_possible_map); return; } } diff --git a/fs/buffer.c b/fs/buffer.c index 655b249c92d7..8c6abdcb22cf 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -3019,7 +3019,7 @@ static void recalc_bh_state(void) if (__get_cpu_var(bh_accounting).ratelimit++ < 4096) return; __get_cpu_var(bh_accounting).ratelimit = 0; - for_each_cpu(i) + for_each_online_cpu(i) tot += per_cpu(bh_accounting, i).nr; buffer_heads_over_limit = (tot > max_buffer_heads); } diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index d6b65c00e089..14f1a8fe6a03 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -368,7 +368,7 @@ int show_stat(struct seq_file *p, void *v) if (wall_to_monotonic.tv_nsec) --jif; - for_each_cpu(i) { + for_each_online_cpu(i) { int j; user += kstat_cpu(i).cpustat.user; @@ -390,7 +390,7 @@ int show_stat(struct seq_file *p, void *v) (unsigned long long)jiffies_64_to_clock_t(iowait), (unsigned long long)jiffies_64_to_clock_t(irq), (unsigned long long)jiffies_64_to_clock_t(softirq)); - for_each_cpu(i) { + for_each_online_cpu(i) { /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ user = kstat_cpu(i).cpustat.user; diff --git a/include/asm-ia64/smp.h b/include/asm-ia64/smp.h index a34d67b96dd9..a54e5959f7a2 100644 --- a/include/asm-ia64/smp.h +++ b/include/asm-ia64/smp.h @@ -38,7 +38,6 @@ extern struct smp_boot_data { extern char no_int_routing __devinitdata; -extern cpumask_t phys_cpu_present_map; extern cpumask_t cpu_online_map; extern unsigned long ipi_base_addr; extern unsigned char smp_int_redirect; @@ -48,8 +47,6 @@ extern volatile int ia64_cpu_to_sapicid[]; extern unsigned long ap_wakeup_vector; -#define cpu_possible_map phys_cpu_present_map - /* * Function to map hard smp processor id to logical id. Slow, so don't use this in * performance-critical code. diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 090c3f2dc6ec..ee773803e0a3 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -10,11 +10,15 @@ extern cpumask_t cpu_online_map; extern cpumask_t cpu_possible_map; +extern cpumask_t cpu_present_map; #define num_online_cpus() cpus_weight(cpu_online_map) #define num_possible_cpus() cpus_weight(cpu_possible_map) +#define num_present_cpus() cpus_weight(cpu_present_map) + #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) #define cpu_possible(cpu) cpu_isset(cpu, cpu_possible_map) +#define cpu_present(cpu) cpu_isset(cpu, cpu_present_map) #define for_each_cpu_mask(cpu, mask) \ for (cpu = first_cpu_const(mk_cpumask_const(mask)); \ @@ -23,16 +27,23 @@ extern cpumask_t cpu_possible_map; #define for_each_cpu(cpu) for_each_cpu_mask(cpu, cpu_possible_map) #define for_each_online_cpu(cpu) for_each_cpu_mask(cpu, cpu_online_map) +#define for_each_present_cpu(cpu) for_each_cpu_mask(cpu, cpu_present_map) #else #define cpu_online_map cpumask_of_cpu(0) #define cpu_possible_map cpumask_of_cpu(0) +#define cpu_present_map cpumask_of_cpu(0) + #define num_online_cpus() 1 #define num_possible_cpus() 1 +#define num_present_cpus() 1 + #define cpu_online(cpu) ({ BUG_ON((cpu) != 0); 1; }) #define cpu_possible(cpu) ({ BUG_ON((cpu) != 0); 1; }) +#define cpu_present(cpu) ({ BUG_ON((cpu) != 0); 1; }) #define for_each_cpu(cpu) for (cpu = 0; cpu < 1; cpu++) #define for_each_online_cpu(cpu) for (cpu = 0; cpu < 1; cpu++) +#define for_each_present_cpu(cpu) for (cpu = 0; cpu < 1; cpu++) #endif #define cpumask_scnprintf(buf, buflen, map) \ diff --git a/init/main.c b/init/main.c index 8ee50fc72594..6913e1acfc04 100644 --- a/init/main.c +++ b/init/main.c @@ -354,10 +354,10 @@ static void __init smp_init(void) unsigned j = 1; /* FIXME: This should be done in userspace --RR */ - for (i = 0; i < NR_CPUS; i++) { + for_each_present_cpu(i) { if (num_online_cpus() >= max_cpus) break; - if (cpu_possible(i) && !cpu_online(i)) { + if (!cpu_online(i)) { cpu_up(i); j++; } @@ -583,6 +583,24 @@ static void run_init_process(char *init_filename) execve(init_filename, argv_init, envp_init); } +static inline void fixup_cpu_present_map(void) +{ +#ifdef CONFIG_SMP + int i; + + /* + * If arch is not hotplug ready and did not populate + * cpu_present_map, just make cpu_present_map same as cpu_possible_map + * for other cpu bringup code to function as normal. e.g smp_init() etc. + */ + if (cpus_empty(cpu_present_map)) { + for_each_cpu(i) { + cpu_set(i, cpu_present_map); + } + } +#endif +} + static int init(void * unused) { lock_kernel(); @@ -601,6 +619,7 @@ static int init(void * unused) do_pre_smp_initcalls(); + fixup_cpu_present_map(); smp_init(); sched_init_smp(); diff --git a/kernel/cpu.c b/kernel/cpu.c index a2e44b4e7df1..72b984c67eb3 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -20,6 +20,14 @@ DECLARE_MUTEX(cpucontrol); static struct notifier_block *cpu_chain; +/* + * Represents all cpu's present in the system + * In systems capable of hotplug, this map could dynamically grow + * as new cpu's are detected in the system via any platform specific + * method, such as ACPI for e.g. + */ +cpumask_t cpu_present_map; +EXPORT_SYMBOL(cpu_present_map); /* Need to know about CPUs going up/down? */ int register_cpu_notifier(struct notifier_block *nb) @@ -180,7 +188,7 @@ int __devinit cpu_up(unsigned int cpu) if ((ret = down_interruptible(&cpucontrol)) != 0) return ret; - if (cpu_online(cpu)) { + if (cpu_online(cpu) || !cpu_present(cpu)) { ret = -EINVAL; goto out; } diff --git a/kernel/fork.c b/kernel/fork.c index 0c0f1ffc8932..a42ffd46532f 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -61,7 +61,7 @@ int nr_processes(void) int cpu; int total = 0; - for_each_cpu(cpu) + for_each_online_cpu(cpu) total += per_cpu(process_counts, cpu); return total; diff --git a/kernel/sched.c b/kernel/sched.c index af614e52e1b9..fa73c9675abc 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1079,7 +1079,7 @@ unsigned long nr_uninterruptible(void) { unsigned long i, sum = 0; - for_each_cpu(i) + for_each_online_cpu(i) sum += cpu_rq(i)->nr_uninterruptible; return sum; @@ -1089,7 +1089,7 @@ unsigned long long nr_context_switches(void) { unsigned long long i, sum = 0; - for_each_cpu(i) + for_each_online_cpu(i) sum += cpu_rq(i)->nr_switches; return sum; @@ -1099,7 +1099,7 @@ unsigned long nr_iowait(void) { unsigned long i, sum = 0; - for_each_cpu(i) + for_each_online_cpu(i) sum += atomic_read(&cpu_rq(i)->nr_iowait); return sum; diff --git a/kernel/timer.c b/kernel/timer.c index 08cec6ae76e3..5bc2d78ba903 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -332,7 +332,7 @@ int del_timer_sync(struct timer_list *timer) del_again: ret += del_timer(timer); - for_each_cpu(i) { + for_each_online_cpu(i) { base = &per_cpu(tvec_bases, i); if (base->running_timer == timer) { while (base->running_timer == timer) { |
