diff -Nur linux-2.5.0/arch/i386/kernel/apic.c linux-2.5.0-lhcs/arch/i386/kernel/apic.c --- linux-2.5.0/arch/i386/kernel/apic.c Fri Nov 9 14:12:55 2001 +++ linux-2.5.0-lhcs/arch/i386/kernel/apic.c Wed Dec 12 10:41:15 2001 @@ -250,7 +250,7 @@ apic_write_around(APIC_LVT1, value); } -void __init setup_local_APIC (void) +void setup_local_APIC (void) { unsigned long value, ver, maxlvt; @@ -695,7 +695,7 @@ * but we do not accept timer interrupts yet. We only allow the BP * to calibrate. */ -static unsigned int __init get_8254_timer_count(void) +static unsigned int get_8254_timer_count(void) { extern spinlock_t i8253_lock; unsigned long flags; @@ -713,7 +713,7 @@ return count; } -void __init wait_8254_wraparound(void) +void wait_8254_wraparound(void) { unsigned int curr_count, prev_count=~0; int delta; @@ -781,10 +781,10 @@ * IRQ APIC event being in synchron with the APIC clock we * introduce an interrupt skew to spread out timer events. * - * The number of slices within a 'big' timeslice is smp_num_cpus+1 + * The number of slices within a 'big' timeslice is online_cpus+1 */ - slice = clocks / (smp_num_cpus+1); + slice = clocks / (num_online_cpus()+1); printk("cpu: %d, clocks: %d, slice: %d\n", smp_processor_id(), clocks, slice); @@ -894,7 +894,7 @@ static unsigned int calibration_result; -void __init setup_APIC_clocks (void) +void setup_APIC_clocks (void) { printk("Using local APIC timer interrupts.\n"); using_apic_timer = 1; diff -Nur linux-2.5.0/arch/i386/kernel/apm.c linux-2.5.0-lhcs/arch/i386/kernel/apm.c --- linux-2.5.0/arch/i386/kernel/apm.c Fri Nov 9 13:58:02 2001 +++ linux-2.5.0-lhcs/arch/i386/kernel/apm.c Wed Dec 12 10:41:15 2001 @@ -365,11 +365,7 @@ #endif static int debug; static int apm_disabled = -1; -#ifdef CONFIG_SMP -static int power_off; -#else static int power_off = 1; -#endif #ifdef CONFIG_APM_REAL_MODE_POWER_OFF static int realmode_power_off = 1; #else @@ -828,7 +824,7 @@ */ #ifdef CONFIG_SMP /* Some bioses don't like being called from CPU != 0 */ - while (cpu_number_map(smp_processor_id()) != 0) { + while (smp_processor_id() != 0) { kernel_thread(apm_magic, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); schedule(); @@ -1595,7 +1591,7 @@ p = buf; - if ((smp_num_cpus == 1) && + if ((num_online_cpus() == 1) && !(error = apm_get_power_status(&bx, &cx, &dx))) { ac_line_status = (bx >> 8) & 0xff; battery_status = bx & 0xff; @@ -1726,7 +1722,7 @@ } } - if (debug && (smp_num_cpus == 1)) { + if (debug && (num_online_cpus() == 1)) { error = apm_get_power_status(&bx, &cx, &dx); if (error) printk(KERN_INFO "apm: power status not available\n"); @@ -1770,7 +1766,7 @@ pm_power_off = apm_power_off; register_sysrq_key('o', &sysrq_poweroff_op); - if (smp_num_cpus == 1) { + if (num_online_cpus() == 1) { #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) console_blank_hook = apm_console_blank; #endif @@ -1906,10 +1902,6 @@ printk(KERN_NOTICE "apm: disabled on user request.\n"); return -ENODEV; } - if ((smp_num_cpus > 1) && !power_off) { - printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); - return -ENODEV; - } if (PM_IS_ACTIVE()) { printk(KERN_NOTICE "apm: overridden by ACPI.\n"); return -ENODEV; @@ -1960,12 +1952,6 @@ kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); - if (smp_num_cpus > 1) { - printk(KERN_NOTICE - "apm: disabled - APM is not SMP safe (power off active).\n"); - return 0; - } - misc_register(&apm_device); return 0; diff -Nur linux-2.5.0/arch/i386/kernel/bluesmoke.c linux-2.5.0-lhcs/arch/i386/kernel/bluesmoke.c --- linux-2.5.0/arch/i386/kernel/bluesmoke.c Mon Nov 12 09:59:43 2001 +++ linux-2.5.0-lhcs/arch/i386/kernel/bluesmoke.c Wed Dec 12 10:41:15 2001 @@ -208,7 +208,7 @@ -void __init mcheck_init(struct cpuinfo_x86 *c) +void mcheck_init(struct cpuinfo_x86 *c) { if(mce_disabled==1) return; diff -Nur linux-2.5.0/arch/i386/kernel/i386_ksyms.c linux-2.5.0-lhcs/arch/i386/kernel/i386_ksyms.c --- linux-2.5.0/arch/i386/kernel/i386_ksyms.c Tue Nov 13 09:13:20 2001 +++ linux-2.5.0-lhcs/arch/i386/kernel/i386_ksyms.c Wed Dec 12 10:41:15 2001 @@ -126,7 +126,6 @@ #ifdef CONFIG_SMP EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(kernel_flag); -EXPORT_SYMBOL(smp_num_cpus); EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL_NOVERS(__write_lock_failed); EXPORT_SYMBOL_NOVERS(__read_lock_failed); diff -Nur linux-2.5.0/arch/i386/kernel/irq.c linux-2.5.0-lhcs/arch/i386/kernel/irq.c --- linux-2.5.0/arch/i386/kernel/irq.c Thu Oct 25 13:53:46 2001 +++ linux-2.5.0-lhcs/arch/i386/kernel/irq.c Wed Dec 12 11:52:38 2001 @@ -138,8 +138,9 @@ char *p = buf; p += sprintf(p, " "); - for (j=0; jtypename); p += sprintf(p, " %s", action->name); @@ -162,15 +164,17 @@ *p++ = '\n'; } p += sprintf(p, "NMI: "); - for (j = 0; j < smp_num_cpus; j++) - p += sprintf(p, "%10u ", - nmi_count(cpu_logical_map(j))); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + p += sprintf(p, "%10u ", + nmi_count(j)); p += sprintf(p, "\n"); #if CONFIG_X86_LOCAL_APIC p += sprintf(p, "LOC: "); - for (j = 0; j < smp_num_cpus; j++) - p += sprintf(p, "%10u ", - apic_timer_irqs[cpu_logical_map(j)]); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + p += sprintf(p, "%10u ", + apic_timer_irqs[j]); p += sprintf(p, "\n"); #endif p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); @@ -201,14 +205,14 @@ printk("\n%s, CPU %d:\n", str, cpu); printk("irq: %d [",irqs_running()); - for(i=0;i < smp_num_cpus;i++) + for(i=0;i < NR_CPUS;i++) printk(" %d",local_irq_count(i)); printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0); - for(i=0;i < smp_num_cpus;i++) + for(i=0;i < NR_CPUS;i++) printk(" %d",local_bh_count(i)); printk(" ]\nStack dumps:"); - for(i = 0; i < smp_num_cpus; i++) { + for(i = 0; i < NR_CPUS; i++) { unsigned long esp; if (i == cpu) continue; @@ -1076,7 +1080,7 @@ static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; -static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; static int irq_affinity_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { diff -Nur linux-2.5.0/arch/i386/kernel/microcode.c linux-2.5.0-lhcs/arch/i386/kernel/microcode.c --- linux-2.5.0/arch/i386/kernel/microcode.c Tue Oct 30 15:13:17 2001 +++ linux-2.5.0-lhcs/arch/i386/kernel/microcode.c Wed Dec 12 10:41:15 2001 @@ -178,7 +178,7 @@ } do_update_one(NULL); - for (i=0; i The MTRR state information to read. @@ -1030,7 +1030,7 @@ data.smp_type = type; wait_barrier_execute = TRUE; wait_barrier_cache_enable = TRUE; - atomic_set (&undone_count, smp_num_cpus - 1); + atomic_set (&undone_count, num_online_cpus() - 1); /* Start the ball rolling on other CPUs */ if (smp_call_function (ipi_handler, &data, 1, 0) != 0) panic ("mtrr: timed out waiting for other CPUs\n"); @@ -1039,7 +1039,7 @@ /* Wait for all other CPUs to flush and disable their caches */ while (atomic_read (&undone_count) > 0) barrier (); /* Set up for completion wait and then release other CPUs to change MTRRs*/ - atomic_set (&undone_count, smp_num_cpus - 1); + atomic_set (&undone_count, num_online_cpus() - 1); wait_barrier_execute = FALSE; (*set_mtrr_up) (reg, base, size, type, FALSE); /* Now wait for other CPUs to complete the function */ @@ -1884,7 +1884,7 @@ unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 }; -static void __init cyrix_arr_init_secondary(void) +static void cyrix_arr_init_secondary(void) { struct set_mtrr_context ctxt; int i; @@ -2184,7 +2184,7 @@ } } /* End Function mtrr_init_boot_cpu */ -static void __init intel_mtrr_init_secondary_cpu(void) +static void intel_mtrr_init_secondary_cpu(void) { unsigned long mask, count; struct set_mtrr_context ctxt; @@ -2203,7 +2203,7 @@ } } /* End Function intel_mtrr_init_secondary_cpu */ -void __init mtrr_init_secondary_cpu(void) +void mtrr_init_secondary_cpu(void) { switch ( mtrr_if ) { case MTRR_IF_INTEL: diff -Nur linux-2.5.0/arch/i386/kernel/nmi.c linux-2.5.0-lhcs/arch/i386/kernel/nmi.c --- linux-2.5.0/arch/i386/kernel/nmi.c Thu Sep 20 20:55:24 2001 +++ linux-2.5.0-lhcs/arch/i386/kernel/nmi.c Wed Dec 12 11:53:01 2001 @@ -54,8 +54,9 @@ sti(); mdelay((10*1000)/nmi_hz); // wait 10 ticks - for (j = 0; j < smp_num_cpus; j++) { - cpu = cpu_logical_map(j); + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (!cpu_online(cpu)) + continue; if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 5) { printk("CPU#%d: NMI appears to be stuck!\n", cpu); return -1; @@ -255,7 +256,7 @@ * Just reset the alert counters, (other CPUs might be * spinning on locks we hold): */ - for (i = 0; i < smp_num_cpus; i++) + for (i = 0; i < NR_CPUS; i++) alert_counter[i] = 0; } diff -Nur linux-2.5.0/arch/i386/kernel/process.c linux-2.5.0-lhcs/arch/i386/kernel/process.c --- linux-2.5.0/arch/i386/kernel/process.c Thu Oct 4 18:42:54 2001 +++ linux-2.5.0-lhcs/arch/i386/kernel/process.c Wed Dec 12 10:41:15 2001 @@ -120,6 +120,9 @@ * low exit latency (ie sit in a loop waiting for * somebody to say that they'd like to reschedule) */ +extern spinlock_t cpu_start_lock; +extern void __cpu_start(void); + void cpu_idle (void) { /* endless idle loop with no priority at all */ @@ -131,6 +134,8 @@ void (*idle)(void) = pm_idle; if (!idle) idle = default_idle; + if (spin_is_locked(&cpu_start_lock)) + __cpu_start(); while (!current->need_resched) idle(); schedule(); diff -Nur linux-2.5.0/arch/i386/kernel/setup.c linux-2.5.0-lhcs/arch/i386/kernel/setup.c --- linux-2.5.0/arch/i386/kernel/setup.c Mon Nov 19 15:16:13 2001 +++ linux-2.5.0-lhcs/arch/i386/kernel/setup.c Wed Dec 12 10:46:12 2001 @@ -1067,7 +1067,7 @@ __setup("notsc", tsc_setup); #endif -static int __init get_model_name(struct cpuinfo_x86 *c) +static int get_model_name(struct cpuinfo_x86 *c) { unsigned int *v; char *p, *q; @@ -1097,7 +1097,7 @@ } -static void __init display_cacheinfo(struct cpuinfo_x86 *c) +static void display_cacheinfo(struct cpuinfo_x86 *c) { unsigned int n, dummy, ecx, edx, l2size; @@ -1169,7 +1169,7 @@ extern void vide(void); __asm__(".align 4\nvide: ret"); -static int __init init_amd(struct cpuinfo_x86 *c) +static int init_amd(struct cpuinfo_x86 *c) { u32 l, h; int mbytes = max_mapnr >> (20-PAGE_SHIFT); @@ -1360,9 +1360,9 @@ * FIXME: our newer udelay uses the tsc. We dont need to frob with SLOP */ -extern void calibrate_delay(void) __init; +extern void calibrate_delay(void); -static void __init check_cx686_slop(struct cpuinfo_x86 *c) +static void check_cx686_slop(struct cpuinfo_x86 *c) { unsigned long flags; @@ -1386,7 +1386,7 @@ } } -static void __init init_cyrix(struct cpuinfo_x86 *c) +static void init_cyrix(struct cpuinfo_x86 *c) { unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0; char *buf = c->x86_model_id; @@ -1774,7 +1774,7 @@ #endif -static void __init init_centaur(struct cpuinfo_x86 *c) +static void init_centaur(struct cpuinfo_x86 *c) { enum { ECX8=1<<1, @@ -1931,7 +1931,7 @@ } -static void __init init_transmeta(struct cpuinfo_x86 *c) +static void init_transmeta(struct cpuinfo_x86 *c) { unsigned int cap_mask, uk, max, dummy; unsigned int cms_rev1, cms_rev2; @@ -1994,7 +1994,7 @@ } -static void __init init_rise(struct cpuinfo_x86 *c) +static void init_rise(struct cpuinfo_x86 *c) { printk("CPU: Rise iDragon"); if (c->x86_model > 2) @@ -2020,7 +2020,7 @@ extern void trap_init_f00f_bug(void); -static void __init init_intel(struct cpuinfo_x86 *c) +static void init_intel(struct cpuinfo_x86 *c) { #ifndef CONFIG_M686 static int f00f_workaround_enabled = 0; @@ -2198,7 +2198,7 @@ mcheck_init(c); } -void __init get_cpu_vendor(struct cpuinfo_x86 *c) +void get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; @@ -2232,7 +2232,7 @@ /* Naming convention should be: [()] */ /* This table only is used unless init_() below doesn't set it; */ /* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */ -static struct cpu_model_info cpu_models[] __initdata = { +static struct cpu_model_info cpu_models[] = { { X86_VENDOR_INTEL, 4, { "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL", "486 SX/2", NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, @@ -2273,7 +2273,7 @@ }; /* Look up CPU names by table lookup. */ -static char __init *table_lookup_model(struct cpuinfo_x86 *c) +static char *table_lookup_model(struct cpuinfo_x86 *c) { struct cpu_model_info *info = cpu_models; int i; @@ -2313,7 +2313,7 @@ return ret; } -static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c) +static void squash_the_stupid_serial_number(struct cpuinfo_x86 *c) { if( test_bit(X86_FEATURE_PN, &c->x86_capability) && disable_x86_serial_nr ) { @@ -2369,7 +2369,7 @@ /* Probe for the CPUID instruction */ -static int __init have_cpuid_p(void) +static int have_cpuid_p(void) { return flag_is_changeable_p(X86_EFLAGS_ID); } @@ -2403,7 +2403,7 @@ /* Try to detect a CPU with disabled CPUID, and if so, enable. This routine may also be used to detect non-CPUID processors and fill in some of the information manually. */ -static int __init id_and_try_enable_cpuid(struct cpuinfo_x86 *c) +static int id_and_try_enable_cpuid(struct cpuinfo_x86 *c) { /* First of all, decide if this is a 486 or higher */ /* It's a 486 if we can modify the AC flag */ @@ -2455,7 +2455,7 @@ /* * This does the hard work of actually picking apart the CPU stuff... */ -void __init identify_cpu(struct cpuinfo_x86 *c) +void identify_cpu(struct cpuinfo_x86 *c) { int junk, i; u32 xlvl, tfms; @@ -2654,11 +2654,11 @@ /* These need to match */ -static char *cpu_vendor_names[] __initdata = { +static char *cpu_vendor_names[] = { "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" }; -void __init print_cpu_info(struct cpuinfo_x86 *c) +void print_cpu_info(struct cpuinfo_x86 *c) { char *vendor = NULL; @@ -2802,7 +2802,7 @@ show: show_cpuinfo, }; -unsigned long cpu_initialized __initdata = 0; +unsigned long cpu_initialized = 0; /* * cpu_init() initializes state that is per-CPU. Some data is already @@ -2810,7 +2810,7 @@ * and IDT. We reload them nevertheless, this function acts as a * 'CPU state barrier', nothing should get across. */ -void __init cpu_init (void) +void cpu_init (void) { int nr = smp_processor_id(); struct tss_struct * t = &init_tss[nr]; diff -Nur linux-2.5.0/arch/i386/kernel/smp.c linux-2.5.0-lhcs/arch/i386/kernel/smp.c --- linux-2.5.0/arch/i386/kernel/smp.c Tue Oct 23 14:17:10 2001 +++ linux-2.5.0-lhcs/arch/i386/kernel/smp.c Wed Dec 12 11:01:08 2001 @@ -245,18 +245,16 @@ * we get an APIC send error if we try to broadcast. * thus we have to avoid sending IPIs in this case. */ - if (!(smp_num_cpus > 1)) + if (!(num_online_cpus() > 1)) return; if (clustered_apic_mode) { // Pointless. Use send_IPI_mask to do this instead int cpu; - if (smp_num_cpus > 1) { - for (cpu = 0; cpu < smp_num_cpus; ++cpu) { - if (cpu != smp_processor_id()) - send_IPI_mask(1 << cpu, vector); - } + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (cpu_online(cpu) && cpu != smp_processor_id()) + send_IPI_mask(1 << cpu, vector); } } else { __send_IPI_shortcut(APIC_DEST_ALLBUT, vector); @@ -270,7 +268,9 @@ // Pointless. Use send_IPI_mask to do this instead int cpu; - for (cpu = 0; cpu < smp_num_cpus; ++cpu) { + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (!cpu_online(cpu)) + continue; send_IPI_mask(1 << cpu, vector); } } else { @@ -391,8 +391,11 @@ */ if (!cpumask) BUG(); + /* This can happen if a CPU is taken offline. --RR */ +#if 0 if ((cpumask & cpu_online_map) != cpumask) BUG(); +#endif if (cpumask & (1 << smp_processor_id())) BUG(); if (!mm) @@ -532,7 +535,7 @@ */ { struct call_data_struct data; - int cpus = smp_num_cpus-1; + int cpus = num_online_cpus()-1; if (!cpus) return 0; @@ -582,7 +585,6 @@ void smp_send_stop(void) { smp_call_function(stop_this_cpu, NULL, 1, 0); - smp_num_cpus = 1; __cli(); disable_local_APIC(); diff -Nur linux-2.5.0/arch/i386/kernel/smpboot.c linux-2.5.0-lhcs/arch/i386/kernel/smpboot.c --- linux-2.5.0/arch/i386/kernel/smpboot.c Wed Nov 21 10:35:48 2001 +++ linux-2.5.0-lhcs/arch/i386/kernel/smpboot.c Wed Dec 12 11:48:45 2001 @@ -53,14 +53,12 @@ /* Setup configured maximum number of CPUs to activate */ static int max_cpus = -1; -/* Total count of live CPUs */ -int smp_num_cpus = 1; - /* Bitmask of currently online CPUs */ unsigned long cpu_online_map; -static volatile unsigned long cpu_callin_map; -static volatile unsigned long cpu_callout_map; +extern unsigned long cpu_initialized; +volatile unsigned long cpu_callin_map; +volatile unsigned long cpu_callout_map; /* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; @@ -109,7 +107,7 @@ * has made sure it's suitably aligned. */ -static unsigned long __init setup_trampoline(void) +static unsigned long setup_trampoline(void) { memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data); return virt_to_phys(trampoline_base); @@ -135,7 +133,7 @@ * a given CPU */ -void __init smp_store_cpu_info(int id) +void smp_store_cpu_info(int id) { struct cpuinfo_x86 *c = cpu_data + id; @@ -170,7 +168,7 @@ static atomic_t smp_commenced = ATOMIC_INIT(0); -void __init smp_commence(void) +void smp_commence(void) { /* * Lets the callins below out of their loop. @@ -225,7 +223,7 @@ return res; } -static void __init synchronize_tsc_bp (void) +static void synchronize_tsc_bp (void) { int i; unsigned long long t0; @@ -255,7 +253,8 @@ /* * all APs synchronize but they loop on '== num_cpus' */ - while (atomic_read(&tsc_count_start) != smp_num_cpus-1) mb(); + while (atomic_read(&tsc_count_start) != num_online_cpus()-1) + mb(); atomic_set(&tsc_count_stop, 0); wmb(); /* @@ -273,21 +272,26 @@ /* * Wait for all APs to leave the synchronization point: */ - while (atomic_read(&tsc_count_stop) != smp_num_cpus-1) mb(); + while (atomic_read(&tsc_count_stop) != num_online_cpus()-1) + mb(); atomic_set(&tsc_count_start, 0); wmb(); atomic_inc(&tsc_count_stop); } sum = 0; - for (i = 0; i < smp_num_cpus; i++) { - t0 = tsc_values[i]; - sum += t0; + for (i = 0; i < NR_CPUS; i++) { + if (cpu_online(i)) { + t0 = tsc_values[i]; + sum += t0; + } } - avg = div64(sum, smp_num_cpus); + avg = div64(sum, num_online_cpus()); sum = 0; - for (i = 0; i < smp_num_cpus; i++) { + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; delta = tsc_values[i] - avg; if (delta < 0) delta = -delta; @@ -314,12 +318,12 @@ printk("passed.\n"); } -static void __init synchronize_tsc_ap (void) +static void synchronize_tsc_ap (void) { int i; /* - * smp_num_cpus is not necessarily known at the time + * cpu_online_map is not necessarily finished at the time * this gets called, so we first wait for the BP to * finish SMP initialization: */ @@ -327,14 +331,15 @@ for (i = 0; i < NR_LOOPS; i++) { atomic_inc(&tsc_count_start); - while (atomic_read(&tsc_count_start) != smp_num_cpus) mb(); + while (atomic_read(&tsc_count_start) != num_online_cpus()) + mb(); rdtscll(tsc_values[smp_processor_id()]); if (i == NR_LOOPS-1) write_tsc(0, 0); atomic_inc(&tsc_count_stop); - while (atomic_read(&tsc_count_stop) != smp_num_cpus) mb(); + while (atomic_read(&tsc_count_stop) != num_online_cpus()) mb(); } } #undef NR_LOOPS @@ -343,7 +348,7 @@ static atomic_t init_deasserted; -void __init smp_callin(void) +void smp_callin(void) { int cpuid, phys_id; unsigned long timeout; @@ -450,7 +455,7 @@ /* * Activate a secondary processor. */ -int __init start_secondary(void *unused) +int start_secondary(void *unused) { /* * Dont put anything before smp_callin(), SMP @@ -476,7 +481,7 @@ * from the task structure * This function must not return. */ -void __init initialize_secondary(void) +void initialize_secondary(void) { /* * We don't actually need to load the full TSS, @@ -495,7 +500,7 @@ unsigned short ss; } stack_start; -static int __init fork_by_hand(void) +static int fork_by_hand(void) { struct pt_regs regs; /* @@ -771,7 +776,7 @@ extern unsigned long cpu_initialized; -static void __init do_boot_cpu (int apicid) +int do_boot_cpu (int apicid, int cpu) /* * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad * (ie clustered apic addressing mode), this is a LOGICAL apic ID. @@ -779,11 +784,10 @@ { struct task_struct *idle; unsigned long boot_error = 0; - int timeout, cpu; + int timeout; unsigned long start_eip; unsigned short nmi_high, nmi_low; - cpu = ++cpucount; /* * We can't use kernel_thread since we must avoid to * reschedule the child. @@ -907,7 +911,7 @@ clear_bit(cpu, &cpu_callout_map); /* was set here (do_boot_cpu()) */ clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */ clear_bit(cpu, &cpu_online_map); /* was set in smp_callin() */ - cpucount--; + return -EINVAL; } /* mark "stuck" area as not stuck */ @@ -918,6 +922,8 @@ *((volatile unsigned short *) TRAMPOLINE_HIGH) = nmi_high; *((volatile unsigned short *) TRAMPOLINE_LOW) = nmi_low; } + + return 0; } cycles_t cacheflush_time; @@ -1028,7 +1034,6 @@ io_apic_irqs = 0; #endif cpu_online_map = phys_cpu_present_map = 1; - smp_num_cpus = 1; if (APIC_init_uniprocessor()) printk(KERN_NOTICE "Local APIC not detected." " Using dummy APIC emulation.\n"); @@ -1059,7 +1064,6 @@ io_apic_irqs = 0; #endif cpu_online_map = phys_cpu_present_map = 1; - smp_num_cpus = 1; goto smp_done; } @@ -1075,7 +1079,6 @@ io_apic_irqs = 0; #endif cpu_online_map = phys_cpu_present_map = 1; - smp_num_cpus = 1; goto smp_done; } @@ -1107,7 +1110,8 @@ if ((max_cpus >= 0) && (max_cpus <= cpucount+1)) continue; - do_boot_cpu(apicid); + if (do_boot_cpu(apicid, ++cpucount)) + cpucount--; /* * Make sure we unmap all failed CPUs @@ -1148,7 +1152,7 @@ } else { unsigned long bogosum = 0; for (cpu = 0; cpu < NR_CPUS; cpu++) - if (cpu_online_map & (1<set_affinity != NULL) + irq_desc[i].handler->set_affinity(i, val); + } + } + + clear_bit(cpu, &cpu_initialized); + clear_bit(cpu, &cpu_callin_map); + clear_bit(cpu, &cpu_callout_map); + return 0; +} + +spinlock_t cpu_start_lock = SPIN_LOCK_UNLOCKED; +static int cpu_start_no; +struct task_struct *cpu_start_task; + +void __cpu_die(unsigned int cpu) +{ + /* If the CPU has been stopped, we also assume that its dead. + */ +} + +void __cpu_start(void) +{ + int err, cpu_id, apic_id; + + cpu_id = cpu_start_no; + apic_id = cpu_2_physical_apicid[cpu_id]; + + /* Only the BP can perform this function. + */ + if (smp_processor_id() != 0) + return; + + spin_unlock(&cpu_start_lock); + + if (apic_id < 0) + panic("Processor %d has no APIC ID!\n", cpu_id); + + /* Clear the smp_commenced barrier */ + atomic_set(&smp_commenced,0); + + err = do_boot_cpu(apic_id, cpu_id); + if (err) + panic("Processor %d (APIC %d) can't spin up!\n",cpu_id, apic_id); + + setup_APIC_clocks(); + + /* + * Synchronize the TSC with the AP + */ + if (cpu_has_tsc) + synchronize_tsc_bp(); + + set_bit(cpu_id, &cpu_online_map); + + smp_commence(); + wake_up_process(cpu_start_task); + + return; +} + +int __cpu_up(unsigned int cpu) +{ + if (test_bit(cpu, &cpu_initialized)) { + Dprintk(KERN_INFO "Processor %d is alive...\n", cpu); + return 0; + } + + Dprintk(KERN_INFO "Processor %d is spinning up...\n", cpu); + + spin_lock(&cpu_start_lock); + cpu_start_no = cpu; + + Dprintk(KERN_INFO "Spinning...\n"); + cpu_start_task=current; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + + + if (! test_bit(cpu, &cpu_online_map)) { + Dprintk(KERN_INFO "Processor %d failed to come back up.\n", cpu); + return -ENODEV; + } + + Dprintk(KERN_INFO "Processor %d has spun up...\n", cpu); + return 0; } diff -Nur linux-2.5.0/arch/i386/kernel/traps.c linux-2.5.0-lhcs/arch/i386/kernel/traps.c --- linux-2.5.0/arch/i386/kernel/traps.c Sun Sep 30 12:26:08 2001 +++ linux-2.5.0-lhcs/arch/i386/kernel/traps.c Wed Dec 12 10:41:15 2001 @@ -720,7 +720,7 @@ #endif /* CONFIG_MATH_EMULATION */ #ifndef CONFIG_M686 -void __init trap_init_f00f_bug(void) +void trap_init_f00f_bug(void) { unsigned long page; pgd_t * pgd; diff -Nur linux-2.5.0/arch/ia64/kernel/ia64_ksyms.c linux-2.5.0-lhcs/arch/ia64/kernel/ia64_ksyms.c --- linux-2.5.0/arch/ia64/kernel/ia64_ksyms.c Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/arch/ia64/kernel/ia64_ksyms.c Tue Dec 11 18:37:21 2001 @@ -85,9 +85,6 @@ EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL(ia64_cpu_to_sapicid); -#include -EXPORT_SYMBOL(smp_num_cpus); - #include EXPORT_SYMBOL(kernel_flag); diff -Nur linux-2.5.0/arch/ia64/kernel/iosapic.c linux-2.5.0-lhcs/arch/ia64/kernel/iosapic.c --- linux-2.5.0/arch/ia64/kernel/iosapic.c Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/arch/ia64/kernel/iosapic.c Tue Dec 11 18:41:05 2001 @@ -212,7 +212,7 @@ int dest, pin; char *addr; - mask &= (1UL << smp_num_cpus) - 1; + mask &= cpu_online_map; if (!mask || irq >= IA64_NUM_VECTORS) return; @@ -636,8 +636,12 @@ set_rte(vector, cpu_physical_id(cpu_index) & 0xffff); cpu_index++; - if (cpu_index >= smp_num_cpus) - cpu_index = 0; + while(!cpu_online(cpu_index)) { + if (cpu_index >= NR_CPUS) + cpu_index = 0; + else + cpu_index++; + } } #endif } diff -Nur linux-2.5.0/arch/ia64/kernel/irq.c linux-2.5.0-lhcs/arch/ia64/kernel/irq.c --- linux-2.5.0/arch/ia64/kernel/irq.c Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/arch/ia64/kernel/irq.c Tue Dec 11 18:37:21 2001 @@ -139,8 +139,11 @@ char *p = buf; p += sprintf(p, " "); - for (j=0; jhandler->typename); p += sprintf(p, " %s", action->name); @@ -164,15 +170,21 @@ *p++ = '\n'; } p += sprintf(p, "NMI: "); - for (j = 0; j < smp_num_cpus; j++) + for (j = 0; j < NR_CPUS; j++) { + if (!cpu_online(j)) + continue; p += sprintf(p, "%10u ", nmi_count(cpu_logical_map(j))); + } p += sprintf(p, "\n"); #if defined(CONFIG_SMP) && defined(CONFIG_X86) p += sprintf(p, "LOC: "); - for (j = 0; j < smp_num_cpus; j++) + for (j = 0; j < NR_CPUS; j++) { + if (!cpu_online(j)) + continue; p += sprintf(p, "%10u ", apic_timer_irqs[cpu_logical_map(j)]); + } p += sprintf(p, "\n"); #endif p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); @@ -201,11 +213,17 @@ printk("\n%s, CPU %d:\n", str, cpu); printk("irq: %d [",irqs_running()); - for(i=0;i < smp_num_cpus;i++) + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; printk(" %d",irq_count(i)); + } printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0); - for(i=0;i < smp_num_cpus;i++) + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; printk(" %d",bh_count(i)); + } printk(" ]\nStack dumps:"); #if defined(CONFIG_IA64) @@ -216,9 +234,9 @@ * idea. */ #elif defined(CONFIG_X86) - for(i=0;i< smp_num_cpus;i++) { + for (i = 0; i < NR_CPUS; i++) { unsigned long esp; - if(i==cpu) + if (!cpu_online(i) || i == cpu) continue; printk("\nCPU %d:",i); esp = init_tss[i].esp0; @@ -1088,7 +1106,7 @@ static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; -static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; static int irq_affinity_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) diff -Nur linux-2.5.0/arch/ia64/kernel/mca.c linux-2.5.0-lhcs/arch/ia64/kernel/mca.c --- linux-2.5.0/arch/ia64/kernel/mca.c Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/arch/ia64/kernel/mca.c Tue Dec 11 18:37:21 2001 @@ -576,9 +576,12 @@ int cpu; /* Clear the Rendez checkin flag for all cpus */ - for(cpu = 0 ; cpu < smp_num_cpus; cpu++) + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (!cpu_online(cpu)) + continue; if (ia64_mc_info.imi_rendez_checkin[cpu] == IA64_MCA_RENDEZ_CHECKIN_DONE) ia64_mca_wakeup(cpu); + } } diff -Nur linux-2.5.0/arch/ia64/kernel/pal.S linux-2.5.0-lhcs/arch/ia64/kernel/pal.S --- linux-2.5.0/arch/ia64/kernel/pal.S Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/arch/ia64/kernel/pal.S Tue Dec 11 18:37:21 2001 @@ -245,3 +245,69 @@ br.ret.sptk.many b0 END(ia64_pal_call_phys_stacked) + +/* + * Make a PAL calls of cache_flush and halt_light in a physical mode. + */ + +GLOBAL_ENTRY(ia64_pal_call_cf_hl) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6) + alloc loc1 = ar.pfs,6,90,0,0 + movl loc2 = pal_entry_point +1: { + mov r28 = 1 // PAL_CACHE_FLUSH + mov r8 = ip // save ip to compute branch + mov loc0 = rp // save rp + } + .body + ;; + ld8 loc2 = [loc2] // loc2 <- entry point + mov r29 = 3 // PAL_CACHE_TYPE_INSTRUCTION_DATA + mov r30 = 1 // PAL_CACHE_FLUSH_INVALIDATE + mov r31 = in0 // copy arg0 (*progress) + ;; + mov loc3 = psr // save psr + adds r8 = 1f-1b,r8 // calculate return address for call + ;; + mov loc4=ar.rsc // save RSE configuration + dep.z loc2=loc2,0,61 // convert pal entry point to physical + dep.z r8=r8,0,61 // convert rp to physical + ;; + mov b7 = loc2 // install target to branch reg + mov ar.rsc=0 // put RSE in enforced lazy, LE mode + movl r16=PAL_PSR_BITS_TO_CLEAR + movl r17=PAL_PSR_BITS_TO_SET + ;; + or loc3=loc3,r17 // add in psr the bits to set + ;; + andcm r16=loc3,r16 // removes bits to clear from psr + br.call.sptk.many rp=ia64_switch_mode +.ret9: mov rp = r8 // install return address (physical) + br.cond.sptk.many b7 +1: +2: { + mov r28 = 29 // PAL_HALT_LIGHT + mov r8 = ip // save ip to compute branch + } + .body + ;; + mov r29 = 0 + mov r30 = 0 + mov r31 = 0 + ;; + mov b7 = loc2 // install target to branch reg + adds r8 = 2f-2b,r8 // calculate return address for call + ;; +.ret10: mov rp = r8 // install return address (physical) + br.cond.sptk.many b7 +2: + { + mov r8 = ip // save ip to compute branch + } + .body + ;; + mov b7 = r8 + ;; + br.cond.sptk.many b7 // tight loop // +END(ia64_pal_call_cf_hl) + diff -Nur linux-2.5.0/arch/ia64/kernel/palinfo.c linux-2.5.0-lhcs/arch/ia64/kernel/palinfo.c --- linux-2.5.0/arch/ia64/kernel/palinfo.c Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/arch/ia64/kernel/palinfo.c Tue Dec 11 18:37:21 2001 @@ -939,7 +939,7 @@ */ for (i=0; i < NR_CPUS; i++) { - if (!cpu_is_online(i)) continue; + /* if (!cpu_is_online(i)) continue; */ sprintf(cpustr,CPUSTR, i); diff -Nur linux-2.5.0/arch/ia64/kernel/perfmon.c linux-2.5.0-lhcs/arch/ia64/kernel/perfmon.c --- linux-2.5.0/arch/ia64/kernel/perfmon.c Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/arch/ia64/kernel/perfmon.c Tue Dec 11 18:37:21 2001 @@ -286,7 +286,7 @@ #define PMU_OWNER() pmu_owners[smp_processor_id()].owner #ifdef CONFIG_SMP -#define PFM_CAN_DO_LAZY() (smp_num_cpus==1 && pfs_info.pfs_sys_session==0) +#define PFM_CAN_DO_LAZY() (num_online_cpus()==1 && pfs_info.pfs_sys_session==0) #else #define PFM_CAN_DO_LAZY() (pfs_info.pfs_sys_session==0) #endif @@ -606,7 +606,7 @@ if (ctx_flags & PFM_FL_SYSTEM_WIDE) { #ifdef CONFIG_SMP - if (smp_num_cpus > 1) { + if (num_online_cpus() > 1) { printk("perfmon: system wide monitoring on SMP not yet supported\n"); return -EINVAL; } diff -Nur linux-2.5.0/arch/ia64/kernel/process.c linux-2.5.0-lhcs/arch/ia64/kernel/process.c --- linux-2.5.0/arch/ia64/kernel/process.c Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/arch/ia64/kernel/process.c Tue Dec 11 18:45:20 2001 @@ -108,21 +108,44 @@ show_stack(0); } +extern volatile unsigned long cpu_dead_mask; +extern volatile unsigned long cpu_halt_mask; + void __attribute__((noreturn)) cpu_idle (void *unused) { /* endless idle loop with no priority at all */ - init_idle(); + int cpu = smp_processor_id(); current->nice = 20; current->counter = -100; while (1) { #ifdef CONFIG_SMP + if (cpu_dead_mask & (1 << cpu)) { + extern void hotplug_cpu_halt(); + extern void ia64_cpu_cache_flush(); + + if (cpu_halt_mask & (1 << cpu)) { + printk("Halt cpu %d\n", cpu); + hotplug_cpu_halt(); /* cache flush & halt */ + } else { + printk("going to sleep on cpu %d\n", cpu); + + ia64_cpu_cache_flush(); /* CPU cache flush */ + + __cli(); + while(cpu_dead_mask & (1UL << cpu)) + __sti(); + + printk("waking up on cpu %d\n", cpu); + } + } + if (!current->need_resched) min_xtp(); #endif - while (!current->need_resched) + while (!current->need_resched && !(cpu_dead_mask & (1 << cpu))) continue; #ifdef CONFIG_SMP normal_xtp(); @@ -573,3 +596,33 @@ pm_power_off(); machine_halt(); } + +void +hotplug_cpu_halt() +{ + u64 progress = 0; + s64 rval; + struct ia64_pal_retval iprv; + extern struct ia64_pal_retval ia64_pal_call_cf_hl(u64); + + printk("Halt CPU %d\n", smp_processor_id()); + __cli(); + iprv = ia64_pal_call_cf_hl(&progress); + rval = iprv.status; + __sti(); + printk("HALT failed?? rval=%lx\n", rval); +} + +void +ia64_cpu_cache_flush() +{ + u64 progress = 0; + u64 vector; + s64 rval; + + __cli(); + rval = ia64_pal_cache_flush(PAL_CACHE_TYPE_INSTRUCTION_DATA, PAL_CACHE_FLUSH_INVALIDATE, &progress, &vector); + __sti(); + printk("CPU(%d) cache is flushed\n",smp_processor_id()); +} + diff -Nur linux-2.5.0/arch/ia64/kernel/smp.c linux-2.5.0-lhcs/arch/ia64/kernel/smp.c --- linux-2.5.0/arch/ia64/kernel/smp.c Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/arch/ia64/kernel/smp.c Tue Dec 11 18:37:21 2001 @@ -157,8 +157,8 @@ { int i; - for (i = 0; i < smp_num_cpus; i++) { - if (i != smp_processor_id()) + for (i = 0; i < NR_CPUS; i++) { + if (cpu_online(i) && i != smp_processor_id()) send_IPI_single(i, op); } } @@ -168,8 +168,11 @@ { int i; - for (i = 0; i < smp_num_cpus; i++) + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; send_IPI_single(i, op); + } } static inline void @@ -215,6 +218,9 @@ return -EBUSY; } + if (!cpu_online(cpuid)) + return -EFAULT; + data.func = func; data.info = info; atomic_set(&data.started, 0); @@ -264,7 +270,7 @@ smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wait) { struct call_data_struct data; - int cpus = smp_num_cpus-1; + int cpus = num_online_cpus()-1; if (!cpus) return 0; @@ -312,8 +318,7 @@ void smp_send_stop (void) { - send_IPI_allbutself(IPI_CPU_STOP); - smp_num_cpus = 1; + smp_call_function(stop_this_cpu, NULL, 1, 0); } int __init @@ -321,3 +326,173 @@ { return -EINVAL; } + +/* for CPU hotplug */ +static int find_another_cpu(int not_this_cpu) +{ + int i; + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + if (i != not_this_cpu) + return i; + } + + return -1; +} + +extern unsigned long irq_affinity[]; + +/* Upping and downing of CPUs */ +int __cpu_disable(unsigned int cpu) +{ + int i; + int new_cpu; + unsigned long val; + extern volatile int time_keeper_id; + + /* Remove from online map. */ + clear_bit(cpu, &cpu_online_map); + + mb(); + + /* Update Time Keeper CPU */ + if (time_keeper_id == cpu) { + new_cpu = find_another_cpu(cpu); + /* look for alternate CPU */ + if (new_cpu == -1) { + set_bit(cpu, &cpu_online_map); + return -1; + } + /* + * synchronization for time_keeper_id is needed but... + */ + time_keeper_id = new_cpu; + printk("time keeper is assigned to CPU %d\n", new_cpu); + } + + /* Route IRQS elsewhere */ + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc(i)->handler == &no_irq_type) + continue; + + if (!irq_desc(i)->handler->set_affinity) { + continue; + } + + val = irq_affinity[i]; + + if (val & (1 << cpu)) { + /* Damn need to find another CPU for this IRQ :) */ + new_cpu = find_another_cpu(cpu); + if (!(val & cpu_online_map)) { + val |= (1 << new_cpu); + } else { + val = val & ~(1 << cpu); + } + val = val & cpu_online_map; + irq_affinity[i] = val; + printk("Set IRQ affinity %d -> %x\n", i, val); + irq_desc(i)->handler->set_affinity(i, val); + } + } + + return 0; +} + +volatile unsigned long cpu_dead_mask; +volatile unsigned long cpu_halt_mask; + +void __cpu_offline(unsigned int cpu) +{ + /* We handle this in the idle loop */ + cpu_dead_mask |= (1 << cpu); + + printk("Processor %d spun down\n", cpu); +} + +void __cpu_die(unsigned int cpu) +{ + /* We handle this in the idle loop */ +#if 0 + cpu_halt_mask |= (1 << cpu); +#endif + cpu_dead_mask |= (1 << cpu); + + printk("Processor %d spun down\n", cpu); +} + +int __cpu_up(unsigned int cpu) +{ + if (cpu_halt_mask & (1 << cpu)) { + /* Currently, this operation cannot be done. */ + return -EINVAL; + } + + /* make sure cpu online or cpu hotadd */ + if (ia64_cpu_to_sapicid[cpu] == -1) { + /* hotadd! */ + return cpu_add(cpu); + } else { + /* online! */ + /* We handle this in the idle loop */ + cpu_dead_mask &= ~(1 << cpu); + + printk("Processor %d spun up\n", cpu); + + /* Add to online map. */ + set_bit(cpu, &cpu_online_map); + return 0; + } +} + +static int +cpu_add(unsigned int cpu) +{ + int timeout; + int cpucount_sv; + int sapicid; + extern int cpucount; + extern volatile int ia64_cpu_to_sapicid[]; + extern struct smp_boot_data smp_boot_data; + + if (test_bit(cpu, &cpu_online_map)) + return -1; + + /* cpu_now_booting = cpu; */ + cpucount_sv = cpucount; + cpucount = cpu; + + /* I'm not sure how to get phys_id at hot-add */ + sapicid = smp_boot_data.cpu_phys_id[cpu]; + if (sapicid == -1) + return -1; + + ia64_cpu_to_sapicid[cpu] = sapicid; + + /* Kick the AP in the butt */ + printk("Sending Wakeup Vector to AP 0x%x/0x%x.\n", cpu, sapicid); + platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); + + /* wait up to 10s for the AP to start */ + for (timeout = 0; timeout < 100000; timeout++) { + if (test_bit(cpu, &cpu_online_map)) { + + /* We handle this in the idle loop */ + cpu_dead_mask &= ~(1 << cpu); + + printk("Processor %d spun up!!\n", cpu); + cpucount = cpucount_sv; + + return 0; + } + udelay(100); + } + + printk(KERN_ERR "SMP: CPU 0x%x is stuck\n", cpu); + cpucount = cpucount_sv; + + return -1; +} + diff -Nur linux-2.5.0/arch/ia64/kernel/smpboot.c linux-2.5.0-lhcs/arch/ia64/kernel/smpboot.c --- linux-2.5.0/arch/ia64/kernel/smpboot.c Wed Nov 21 10:31:09 2001 +++ linux-2.5.0-lhcs/arch/ia64/kernel/smpboot.c Tue Dec 11 18:37:21 2001 @@ -66,7 +66,7 @@ #define DEBUG_ITC_SYNC 0 -extern void __init calibrate_delay(void); +extern void calibrate_delay(void); extern void start_ap(void); int cpucount; @@ -74,8 +74,8 @@ /* Setup configured maximum number of CPUs to activate */ static int max_cpus = -1; -/* Total count of live CPUs */ -int smp_num_cpus = 1; +/* Setup configured number of CPUs to activate at bootng */ +static int init_cpus = -1; /* Bitmask of currently online CPUs */ volatile unsigned long cpu_online_map; @@ -85,7 +85,7 @@ static volatile unsigned long cpu_callin_map; -struct smp_boot_data smp_boot_data __initdata; +struct smp_boot_data smp_boot_data; /* Set when the idlers are all forked */ volatile int smp_threads_ready; @@ -134,6 +134,15 @@ __setup("nointroute", nointroute); +static int __init +initcpus (char *str) +{ + get_option(&str, &init_cpus); + return 1; +} + +__setup("initcpus=", initcpus); + void sync_master (void *arg) { @@ -281,7 +290,7 @@ /* * Ideally sets up per-cpu profiling hooks. Doesn't do much now... */ -static inline void __init +static inline void smp_setup_percpu_timer (void) { local_cpu_data->prof_counter = 1; @@ -300,7 +309,7 @@ static volatile atomic_t smp_commenced = ATOMIC_INIT(0); -void __init +void smp_commence (void) { /* @@ -313,10 +322,10 @@ } -static void __init +static void smp_callin (void) { - int cpuid, phys_id; + int cpuid, phys_id, master_cpu; extern void ia64_init_itm(void); #ifdef CONFIG_PERFMON @@ -326,7 +335,7 @@ cpuid = smp_processor_id(); phys_id = hard_smp_processor_id(); - if (test_and_set_bit(cpuid, &cpu_online_map)) { + if (test_bit(cpuid, &cpu_callin_map)) { printk("huh, phys CPU#0x%x, CPU#0x%x already present??\n", phys_id, cpuid); BUG(); } @@ -338,7 +347,9 @@ */ Dprintk("Going to syncup ITC with BP.\n"); - ia64_sync_itc(0); + master_cpu = ffz(~cpu_online_map); + printk("call ia64_sync_itc(%d)\n", master_cpu); + ia64_sync_itc(master_cpu); /* * Get our bogomips. */ @@ -367,7 +378,7 @@ /* * Activate a secondary processor. head.S calls this. */ -int __init +int start_secondary (void *unused) { extern int cpu_idle (void); @@ -381,6 +392,10 @@ ; Dprintk("CPU %d is starting idle.\n", smp_processor_id()); + init_idle(); + set_bit(smp_processor_id(), &cpu_online_map); + printk("cpu(%d) up!\n", smp_processor_id()); + return cpu_idle(); } @@ -424,6 +439,9 @@ unhash_process(idle); init_tasks[cpu] = idle; + if (sapicid == -1) + return; + Dprintk("Sending wakeup vector %u to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid); platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); @@ -447,7 +465,7 @@ } else { printk(KERN_ERR "Processor 0x%x/0x%x is stuck.\n", cpu, sapicid); ia64_cpu_to_sapicid[cpu] = -1; - cpucount--; + /* cpucount--; */ } } @@ -459,6 +477,7 @@ { int sapicid, cpu; int boot_cpu_id = hard_smp_processor_id(); + int online_cpu_count = 0; /* * Initialize the logical to physical CPU number mapping @@ -490,7 +509,6 @@ if (!max_cpus || (max_cpus < -1)) { printk(KERN_INFO "SMP mode deactivated.\n"); cpu_online_map = 1; - smp_num_cpus = 1; goto smp_done; } if (max_cpus != -1) @@ -511,17 +529,19 @@ if ((max_cpus > 0) && (cpucount + 1 >= max_cpus)) break; + if ((init_cpus > 0) && (init_cpus <= cpu)) { + sapicid = -1; + } + do_boot_cpu(sapicid); /* * Make sure we unmap all failed CPUs */ - if (ia64_cpu_to_sapicid[cpu] == -1) - printk("phys CPU#%d not responding - cannot use it.\n", cpu); + if (ia64_cpu_to_sapicid[cpu] != -1) + online_cpu_count++; } - smp_num_cpus = cpucount + 1; - /* * Allow the user to impress friends. */ @@ -531,12 +551,14 @@ printk(KERN_ERR "Error: only one processor found.\n"); } else { unsigned long bogosum = 0; - for (cpu = 0; cpu < NR_CPUS; cpu++) - if (cpu_online_map & (1<loops_per_jiffy; + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (!cpu_online(cpu)) + continue; + bogosum += cpu_data(cpu)->loops_per_jiffy; + } printk(KERN_INFO"Total of %d processors activated (%lu.%02lu BogoMIPS).\n", - cpucount + 1, bogosum/(500000/HZ), (bogosum/(5000/HZ))%100); + online_cpu_count + 1, bogosum/(500000/HZ), (bogosum/(5000/HZ))%100); } } smp_done: @@ -566,6 +588,5 @@ printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n Forcing UP mode\n", ia64_sal_strerror(sal_ret)); max_cpus = 0; - smp_num_cpus = 1; } } diff -Nur linux-2.5.0/arch/ia64/kernel/time.c linux-2.5.0-lhcs/arch/ia64/kernel/time.c --- linux-2.5.0/arch/ia64/kernel/time.c Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/arch/ia64/kernel/time.c Tue Dec 11 18:37:21 2001 @@ -33,6 +33,8 @@ #endif +volatile int time_keeper_id = 0; + static void do_profile (unsigned long ip) { @@ -65,10 +67,12 @@ { unsigned long elapsed_cycles, lost = jiffies - wall_jiffies; unsigned long now, last_tick; -# define time_keeper_id 0 /* smp_processor_id() of time-keeper */ + int tkid; + + tkid = time_keeper_id; - last_tick = (cpu_data(time_keeper_id)->itm_next - - (lost + 1)*cpu_data(time_keeper_id)->itm_delta); + last_tick = (cpu_data(tkid)->itm_next + - (lost + 1)*cpu_data(tkid)->itm_delta); now = ia64_get_itc(); if ((long) (now - last_tick) < 0) { @@ -173,7 +177,7 @@ #endif new_itm += local_cpu_data->itm_delta; - if (smp_processor_id() == 0) { + if (smp_processor_id() == time_keeper_id) { /* * Here we are in the timer irq handler. We have irqs locally * disabled, but we don't know if the timer_bh is running on @@ -209,7 +213,7 @@ /* * Encapsulate access to the itm structure for SMP. */ -void __init +void ia64_cpu_local_tick (void) { int cpu = smp_processor_id(); @@ -231,7 +235,7 @@ ia64_set_itm(local_cpu_data->itm_next); } -void __init +void ia64_init_itm (void) { unsigned long platform_base_freq, itc_freq, drift; diff -Nur linux-2.5.0/arch/ia64/mm/init.c linux-2.5.0-lhcs/arch/ia64/mm/init.c --- linux-2.5.0/arch/ia64/mm/init.c Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/arch/ia64/mm/init.c Tue Dec 11 18:37:21 2001 @@ -258,11 +258,11 @@ return page; } -void __init +void ia64_mmu_init (void *my_cpu_data) { unsigned long flags, rid, pta, impl_va_bits; - extern void __init tlb_init (void); + extern void tlb_init (void); #ifdef CONFIG_DISABLE_VHPT # define VHPT_ENABLE_BIT 0 #else diff -Nur linux-2.5.0/arch/ia64/mm/tlb.c linux-2.5.0-lhcs/arch/ia64/mm/tlb.c --- linux-2.5.0/arch/ia64/mm/tlb.c Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/arch/ia64/mm/tlb.c Tue Dec 11 18:37:21 2001 @@ -173,7 +173,7 @@ ia64_insn_group_barrier(); } -void __init +void ia64_tlb_init (void) { ia64_ptce_info_t ptce_info; diff -Nur linux-2.5.0/arch/mips64/kernel/smp.c linux-2.5.0-lhcs/arch/mips64/kernel/smp.c --- linux-2.5.0/arch/mips64/kernel/smp.c Wed Jul 4 11:50:39 2001 +++ linux-2.5.0-lhcs/arch/mips64/kernel/smp.c Wed Dec 12 10:41:15 2001 @@ -286,3 +286,18 @@ _flush_tlb_page(vma, page); } +/* Upping and downing of CPUs */ +/* FIXME: implement. */ +int __cpu_disable(unsigned int cpu) +{ + return -ENOSYS; +} + +void __cpu_die(unsigned int cpu) +{ +} + +int __cpu_up(unsigned int cpu) +{ + return -ENOSYS; +} diff -Nur linux-2.5.0/arch/ppc/kernel/idle.c linux-2.5.0-lhcs/arch/ppc/kernel/idle.c --- linux-2.5.0/arch/ppc/kernel/idle.c Fri Nov 2 17:43:54 2001 +++ linux-2.5.0-lhcs/arch/ppc/kernel/idle.c Wed Dec 12 11:14:02 2001 @@ -45,9 +45,12 @@ atomic_t zero_sz; /* # currently pre-zero'd pages */ atomic_t zeropage_calls; /* # zero'd pages request that've been made */ +extern volatile unsigned long cpu_dead_mask; + int idled(void) { int do_power_save = 0; + int cpu = smp_processor_id(); if (cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_CAN_DOZE) do_power_save = 1; @@ -59,6 +62,16 @@ for (;;) { #ifdef CONFIG_SMP + if (cpu_dead_mask & (1 << cpu)) { + printk("going to sleep on cpu %d\n", cpu); + __cli(); + while(cpu_dead_mask & (1 << cpu)) + /* Do Nothing */ ; + + __sti(); + printk("waking up on cpu %d\n", cpu); + } + if (!do_power_save) { /* * Deal with another CPU just having chosen a thread to diff -Nur linux-2.5.0/arch/ppc/kernel/irq.c linux-2.5.0-lhcs/arch/ppc/kernel/irq.c --- linux-2.5.0/arch/ppc/kernel/irq.c Tue Aug 28 06:58:33 2001 +++ linux-2.5.0-lhcs/arch/ppc/kernel/irq.c Wed Dec 12 10:41:15 2001 @@ -380,8 +380,9 @@ struct irqaction * action; len += sprintf(buf+len, " "); - for (j=0; j>= 1) - mask |= (cpumask & 1) << smp_hw_index[i]; + for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1) { + if (cpu_online(i)) + mask |= (cpumask & 1) << smp_hw_index[i]; + } return mask; } #else diff -Nur linux-2.5.0/arch/ppc/kernel/ppc_ksyms.c linux-2.5.0-lhcs/arch/ppc/kernel/ppc_ksyms.c --- linux-2.5.0/arch/ppc/kernel/ppc_ksyms.c Fri Nov 16 10:10:08 2001 +++ linux-2.5.0-lhcs/arch/ppc/kernel/ppc_ksyms.c Wed Dec 12 10:41:15 2001 @@ -213,7 +213,7 @@ #endif EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_hw_index); -EXPORT_SYMBOL(smp_num_cpus); +EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL(synchronize_irq); #endif diff -Nur linux-2.5.0/arch/ppc/kernel/setup.c linux-2.5.0-lhcs/arch/ppc/kernel/setup.c --- linux-2.5.0/arch/ppc/kernel/setup.c Wed Nov 21 09:59:11 2001 +++ linux-2.5.0-lhcs/arch/ppc/kernel/setup.c Wed Dec 12 11:14:51 2001 @@ -149,7 +149,7 @@ /* Show summary information */ #ifdef CONFIG_SMP unsigned long bogosum = 0; - for (i = 0; i < smp_num_cpus; ++i) + for (i = 0; i < NR_CPUS; ++i) if (cpu_online_map & (1 << i)) bogosum += cpu_data[i].loops_per_jiffy; seq_printf(m, "total bogomips\t: %lu.%02lu\n", diff -Nur linux-2.5.0/arch/ppc/kernel/smp.c linux-2.5.0-lhcs/arch/ppc/kernel/smp.c --- linux-2.5.0/arch/ppc/kernel/smp.c Wed Nov 21 10:31:09 2001 +++ linux-2.5.0-lhcs/arch/ppc/kernel/smp.c Wed Dec 12 10:41:15 2001 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,6 @@ int smp_threads_ready; volatile int smp_commenced; -int smp_num_cpus = 1; int smp_tb_synchronized; struct cpuinfo_PPC cpu_data[NR_CPUS]; struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 }; @@ -58,6 +58,7 @@ /* all cpu mappings are 1-1 -- Cort */ volatile unsigned long cpu_callin_map[NR_CPUS]; +unsigned long cpu_online_map; #define TB_SYNC_PASSES 4 volatile unsigned long __initdata tb_sync_flag = 0; @@ -158,6 +159,7 @@ static void stop_this_cpu(void *dummy) { + clear_bit(smp_processor_id(), &cpu_online_map); __cli(); while (1) ; @@ -166,7 +168,6 @@ void smp_send_stop(void) { smp_call_function(stop_this_cpu, NULL, 1, 0); - smp_num_cpus = 1; } /* @@ -205,7 +206,7 @@ */ { struct call_data_struct data; - int ret = -1, cpus = smp_num_cpus-1; + int ret = -1, cpus = num_online_cpus()-1; int timeout; if (!cpus) @@ -280,7 +281,7 @@ struct task_struct *p; printk("Entering SMP Mode...\n"); - smp_num_cpus = 1; + cpu_online_map = 1; smp_store_cpu_info(0); cpu_online_map = 1UL; @@ -376,7 +377,7 @@ sprintf(buf, "found cpu %d", i); if (ppc_md.progress) ppc_md.progress(buf, 0x350+i); printk("Processor %d found.\n", i); - smp_num_cpus++; + cpu_online_map |= 1 << i; } else { char buf[32]; sprintf(buf, "didn't find cpu %d", i); @@ -388,7 +389,7 @@ /* Setup CPU 0 last (important) */ smp_ops->setup_cpu(0); - if (smp_num_cpus < 2) + if (num_online_cpus() < 2) smp_tb_synchronized = 1; } @@ -414,11 +415,11 @@ for (pass = 2; pass < 2+PASSES; pass++){ if (cpu == 0){ mb(); - for (i = j = 1; i < smp_num_cpus; i++, j++){ + for (i = 1; i < NR_CPUS; i++){ /* skip stuck cpus */ - while (!cpu_callin_map[j]) - ++j; - while (cpu_callin_map[j] != pass) + if (!cpu_callin_map[j]) + continue; + while (cpu_callin_map[i] != pass) barrier(); } mb(); @@ -488,7 +489,7 @@ * * NOTE2: this code doesn't seem to work on > 2 cpus. -- paulus/BenH */ - if (!smp_tb_synchronized && smp_num_cpus == 2) { + if (!smp_tb_synchronized && num_online_cpus() == 2) { unsigned long flags; __save_and_cli(flags); smp_software_tb_sync(0); @@ -521,7 +522,7 @@ barrier(); /* see smp_commence for more info */ - if (!smp_tb_synchronized && smp_num_cpus == 2) { + if (!smp_tb_synchronized && num_online_cpus() == 2) { smp_software_tb_sync(cpu); } __sti(); @@ -566,3 +567,83 @@ } __setup("maxcpus=", maxcpus); + +static int find_another_cpu(int not_this_cpu) +{ + int i; + + for (i = 0; i < NR_CPUS; i++) { + if (i != not_this_cpu && cpu_online(i)) + return i; + } + + return -1; +} + +extern unsigned int irq_affinity[]; + +/* Upping and downing of CPUs */ +int __cpu_disable(unsigned int cpu) +{ + int i; + unsigned long val; + + /* Remove from online map. */ + clear_bit(cpu, &cpu_online_map); + + mb(); + + /* Route IRQS elsewhere */ + for (i = 0; i < 72; i++) { + if (irq_desc[i].handler == NULL) + continue; + + if (!irq_desc[i].handler->set_affinity) + continue; + + val = irq_affinity[i]; + + if (val & (1 << cpu)) { + /* Damn need to find another CPU for this IRQ :) */ + if (!(val & cpu_online_map)) { + int new_cpu; + new_cpu = find_another_cpu(cpu); + if (new_cpu == -1) { + set_bit(cpu, &cpu_online_map); + return -1; + } + val = (1 << new_cpu); + } else { + val = val & ~(1 << cpu); + } + irq_affinity[i] = val; + irq_desc[i].handler->set_affinity(i, val); + } + } + + return 0; +} + +volatile unsigned long cpu_dead_mask; + +void __cpu_die(unsigned int cpu) +{ + /* We handle this in the idle loop */ + cpu_dead_mask |= (1 << cpu); + + printk("Processor %d spun down\n", cpu); +} + +/* Im game! */ +int __cpu_up(unsigned int cpu) +{ + /* We handle this in the idle loop */ + cpu_dead_mask &= ~(1 << cpu); + + printk("Processor %d spun up\n", cpu); + + /* Add to online map. */ + set_bit(cpu, &cpu_online_map); + + return 0; +} diff -Nur linux-2.5.0/arch/s390/kernel/irq.c linux-2.5.0-lhcs/arch/s390/kernel/irq.c --- linux-2.5.0/arch/s390/kernel/irq.c Wed Jul 25 14:12:01 2001 +++ linux-2.5.0-lhcs/arch/s390/kernel/irq.c Tue Dec 11 18:37:21 2001 @@ -68,8 +68,11 @@ p += sprintf(p, " "); - for (j=0; jirq_desc.handler->typename); p += sprintf(p, " %s", action->name); diff -Nur linux-2.5.0/arch/s390/kernel/process.c linux-2.5.0-lhcs/arch/s390/kernel/process.c --- linux-2.5.0/arch/s390/kernel/process.c Thu Oct 11 09:04:57 2001 +++ linux-2.5.0-lhcs/arch/s390/kernel/process.c Tue Dec 11 18:37:21 2001 @@ -43,6 +43,7 @@ #include #include #include +#include asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); @@ -51,21 +52,42 @@ */ static psw_t wait_psw; +volatile int no_wait_psw = 0; /* will be modified from __cpu_disable */ +extern volatile unsigned long cpu_dead_mask; int cpu_idle(void *unused) { + int cpu = smp_processor_id(); + /* endless idle loop with no priority at all */ init_idle(); current->nice = 20; current->counter = -100; wait_psw.mask = _WAIT_PSW_MASK; wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L; + + /* Add to online map. */ + set_bit(cpu, &cpu_online_map); + eieio(); + while(1) { + if (cpu_dead_mask & (1 << cpu)) { + __cli(); + no_wait_psw = 0; + /* flushing local pgt cache */ + do_check_pgt_cache(0,0); + signal_processor(cpu, sigp_stop); + /* this point will never be reached */ + while(1); + __sti(); + } if (current->need_resched) { schedule(); check_pgt_cache(); continue; } + if (no_wait_psw) + continue; /* load wait psw */ asm volatile ( diff -Nur linux-2.5.0/arch/s390/kernel/setup.c linux-2.5.0-lhcs/arch/s390/kernel/setup.c --- linux-2.5.0/arch/s390/kernel/setup.c Fri Nov 16 18:38:39 2001 +++ linux-2.5.0-lhcs/arch/s390/kernel/setup.c Tue Dec 11 18:37:21 2001 @@ -78,7 +78,7 @@ /* * cpu_init() initializes state that is per-CPU. */ -void __init cpu_init (void) +void cpu_init (void) { int nr = smp_processor_id(); int addr = hard_smp_processor_id(); @@ -102,12 +102,9 @@ current->flags &= ~PF_USEDFPU; current->used_math = 0; - /* Setup active_mm for idle_task */ - atomic_inc(&init_mm.mm_count); - current->active_mm = &init_mm; if (current->mm) BUG(); - enter_lazy_tlb(&init_mm, current, nr); + enter_lazy_tlb(current->active_mm, current, nr); } /* @@ -491,7 +488,7 @@ seq_printf(m, "vendor_id : IBM/S390\n" "# processors : %i\n" "bogomips per cpu: %lu.%02lu\n", - smp_num_cpus, loops_per_jiffy/(500000/HZ), + num_online_cpus(), loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ))%100); } else if (cpu_online_map & (1 << n)) { cpuinfo = &safe_get_cpu_lowcore(n).cpu_data; diff -Nur linux-2.5.0/arch/s390/kernel/smp.c linux-2.5.0-lhcs/arch/s390/kernel/smp.c --- linux-2.5.0/arch/s390/kernel/smp.c Wed Nov 21 10:31:09 2001 +++ linux-2.5.0-lhcs/arch/s390/kernel/smp.c Tue Dec 11 18:37:21 2001 @@ -9,15 +9,6 @@ * based on other smp stuff by * (c) 1995 Alan Cox, CymruNET Ltd * (c) 1998 Ingo Molnar - * - * We work with logical cpu numbering everywhere we can. The only - * functions using the real cpu address (got from STAP) are the sigp - * functions. For all other functions we use the identity mapping. - * That means that cpu_number_map[i] == i for every cpu. cpu_number_map is - * used e.g. to find the idle task belonging to a logical cpu. Every array - * in the kernel is sorted by the logical cpu number and not by the physical - * one which is causing all the confusion with __cpu_logical_map and - * cpu_number_map in other architectures. */ #include @@ -35,7 +26,7 @@ #include #include #include - +#include /* prototypes */ extern int cpu_idle(void * unused); @@ -46,7 +37,6 @@ * An array with a pointer the lowcore of every CPU. */ static int max_cpus = NR_CPUS; /* Setup configured maximum number of CPUs to activate */ -int smp_num_cpus; struct _lowcore *lowcore_ptr[NR_CPUS]; unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_old_multiplier[NR_CPUS]; @@ -59,6 +49,12 @@ unsigned long cpu_online_map; +unsigned long cpu_online_map; +extern int cpus_initialized; /* setup.c */ +extern unsigned long cpu_initialized; /* setup.c */ +extern volatile int no_wait_psw; /* process.c */ +extern struct semaphore cpucontrol; /* kernel/cpu.c */ + /* * Setup routine for controlling SMP activation * @@ -149,7 +145,7 @@ */ { struct call_data_struct data; - int cpus = smp_num_cpus-1; + int cpus = num_online_cpus() - 1; if (!cpus || !atomic_read(&smp_commenced)) return 0; @@ -183,6 +179,20 @@ * Various special callbacks */ +static inline int boot_cpu_id(void) +{ + int cpu; + + for(cpu = 0; cpu < NR_CPUS; cpu++){ + if (!cpu_online(cpu)) + continue; + if (__cpu_logical_map[cpu] == boot_cpu_addr) + return cpu; + } + BUG(); + return 0; +} + void do_machine_restart(void) { smp_send_stop(); @@ -191,8 +201,10 @@ void machine_restart(char * __unused) { - if (smp_processor_id() != 0) { - smp_ext_bitcall(0, ec_restart); + __u16 cpu = __cpu_logical_map[smp_processor_id()]; + + if (cpu != boot_cpu_addr) { + smp_ext_bitcall(boot_cpu_id(), ec_restart); for (;;); } else do_machine_restart(); @@ -208,8 +220,10 @@ void machine_halt(void) { - if (smp_processor_id() != 0) { - smp_ext_bitcall(0, ec_halt); + __u16 cpu = __cpu_logical_map[smp_processor_id()]; + + if (cpu != boot_cpu_addr) { + smp_ext_bitcall(boot_cpu_id(), ec_halt); for (;;); } else do_machine_halt(); @@ -225,8 +239,10 @@ void machine_power_off(void) { - if (smp_processor_id() != 0) { - smp_ext_bitcall(0, ec_power_off); + __u16 cpu = __cpu_logical_map[smp_processor_id()]; + + if (cpu != boot_cpu_addr) { + smp_ext_bitcall(boot_cpu_id(), ec_power_off); for (;;); } else do_machine_power_off(); @@ -290,7 +306,9 @@ sigp_ccode ccode; int i; - for (i = 0; i < smp_num_cpus; i++) { + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; if (smp_processor_id() == i) continue; lowcore = &get_cpu_lowcore(i); @@ -319,7 +337,9 @@ /* stop all processors */ - for (i = 0; i < smp_num_cpus; i++) { + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; if (smp_processor_id() != i) { int ccode; do { @@ -334,7 +354,9 @@ /* store status of all processors in their lowcores (real 0) */ - for (i = 0; i < smp_num_cpus; i++) { + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; if (smp_processor_id() != i) { int ccode; low_core_addr = (unsigned long)&get_cpu_lowcore(i); @@ -388,7 +410,7 @@ /* * callback for setting/clearing control bits */ -void smp_ctl_bit_callback(void *info) { +static void smp_ctl_bit_callback(void *info) { ec_creg_mask_parms *pp; u32 cregs[16]; int i; @@ -417,6 +439,11 @@ void smp_ctl_set_bit(int cr, int bit) { ec_creg_mask_parms parms; + /* We don't allow writing to control registers while + * a cpu gets detached or attached and vice versa.. + */ + + down(&cpucontrol); if (atomic_read(&smp_commenced) != 0) { parms.start_ctl = cr; parms.end_ctl = cr; @@ -425,6 +452,7 @@ smp_call_function(smp_ctl_bit_callback, &parms, 0, 1); } __ctl_set_bit(cr, bit); + up(&cpucontrol); } /* @@ -433,6 +461,7 @@ void smp_ctl_clear_bit(int cr, int bit) { ec_creg_mask_parms parms; + down(&cpucontrol); if (atomic_read(&smp_commenced) != 0) { parms.start_ctl = cr; parms.end_ctl = cr; @@ -441,6 +470,7 @@ smp_call_function(smp_ctl_bit_callback, &parms, 0, 1); } __ctl_clear_bit(cr, bit); + up(&cpucontrol); } /* @@ -452,19 +482,18 @@ int curr_cpu; current->processor = 0; - smp_num_cpus = 1; cpu_online_map = 1; for (curr_cpu = 0; - curr_cpu <= 65535 && smp_num_cpus < max_cpus; curr_cpu++) { + curr_cpu <= 65535 && num_online_cpus() < max_cpus; curr_cpu++) { if ((__u16) curr_cpu == boot_cpu_addr) continue; - __cpu_logical_map[smp_num_cpus] = (__u16) curr_cpu; - if (signal_processor(smp_num_cpus, sigp_sense) == + __cpu_logical_map[num_online_cpus()] = (__u16) curr_cpu; + if (signal_processor(num_online_cpus(), sigp_sense) == sigp_not_operational) continue; - smp_num_cpus++; + cpu_online_map |= 1 << num_online_cpus(); } - printk("Detected %d CPU's\n",(int) smp_num_cpus); + printk("Detected %d CPU's\n",(int) num_online_cpus()); printk("Boot cpu address %2X\n", boot_cpu_addr); } @@ -476,7 +505,7 @@ extern int pfault_init(void); extern int pfault_token(void); -int __init start_secondary(void *cpuvoid) +int start_secondary(void *cpuvoid) { /* Setup the cpu */ cpu_init(); @@ -513,6 +542,21 @@ return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); } +static inline void setup_lowcore(struct _lowcore *cpu_lowcore, + struct task_struct *idle){ + + cpu_lowcore->save_area[15] = idle->thread.ksp; + cpu_lowcore->kernel_stack = (__u32) idle + 8192; + __asm__ __volatile__("la 1,%0\n\t" + "stctl 0,15,0(1)\n\t" + "la 1,%1\n\t" + "stam 0,15,0(1)" + : "=m" (cpu_lowcore->cregs_save_area[0]), + "=m" (cpu_lowcore->access_regs_save_area[0]) + : : "1", "memory"); + return; +} + static void __init do_boot_cpu(int cpu) { struct task_struct *idle; @@ -533,25 +577,36 @@ idle->processor = cpu; idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */ + /* Setup active_mm for idle_task */ + atomic_inc(&init_mm.mm_count); + idle->active_mm = &init_mm; + del_from_runqueue(idle); unhash_process(idle); init_tasks[cpu] = idle; cpu_lowcore=&get_cpu_lowcore(cpu); - cpu_lowcore->save_area[15] = idle->thread.ksp; - cpu_lowcore->kernel_stack = (idle->thread.ksp | 8191) + 1; - __asm__ __volatile__("la 1,%0\n\t" - "stctl 0,15,0(1)\n\t" - "la 1,%1\n\t" - "stam 0,15,0(1)" - : "=m" (cpu_lowcore->cregs_save_area[0]), - "=m" (cpu_lowcore->access_regs_save_area[0]) - : : "1", "memory"); + + setup_lowcore(cpu_lowcore, idle); + + eieio(); + if (cpu_online(cpu)) + signal_processor(cpu,sigp_restart); +} + +static void do_boot_cpu_late(int cpu) +{ + struct task_struct *idle; + struct _lowcore *cpu_lowcore; + + idle = init_tasks[cpu]; + + cpu_lowcore=&get_cpu_lowcore(cpu); + + setup_lowcore(cpu_lowcore, idle); eieio(); signal_processor(cpu,sigp_restart); - /* Mark this cpu as online */ - set_bit(cpu, &cpu_online_map); } /* @@ -601,7 +656,7 @@ print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data); - for(i = 0; i < smp_num_cpus; i++) + for(i = 0; i < max_cpus; i++) { lowcore_ptr[i] = (struct _lowcore *) __get_free_page(GFP_KERNEL|GFP_DMA); @@ -622,8 +677,11 @@ if (smp_processor_id() == i) set_prefix((u32) lowcore_ptr[i]); else { + ccode = 0; + if (cpu_online(i)){ ccode = signal_processor_p((u32)(lowcore_ptr[i]), i, sigp_set_prefix); + } if (ccode) /* if this gets troublesome I'll have to do * something about it. */ @@ -636,6 +694,41 @@ } } +static int smp_boot_new_cpu(unsigned long cpu) +{ + sigp_ccode ccode; + int curr_cpu; + int ret = 0; + + for (curr_cpu = 0; curr_cpu <= 65535; curr_cpu++) { + __cpu_logical_map[cpu] = (__u16) curr_cpu; + if (cpu_stopped(cpu)) + break; + } + + if (!cpu_stopped(cpu)) + goto out; + + /* Cleaning up lowcore.. (these values should be zero anyway) */ + + atomic_set(&lowcore_ptr[cpu]->ext_call_fast, 0); + + ccode = signal_processor_p((u32)(lowcore_ptr[cpu]), cpu, sigp_set_prefix); + if(ccode) { + printk("ccode %d for cpu %d returned when " + "setting prefix in smp_boot_cpus not good.\n", + (int) ccode, (int) cpu); + goto out; + } + else { + do_boot_cpu_late(cpu); + ret = 1; + } + out: + return ret; +} + + /* * the frequency of the profiling timer can be changed * by writing a multiplier value into /proc/profile. @@ -699,8 +792,116 @@ } } +/* Upping and downing of CPUs */ + +volatile unsigned long cpu_dead_mask; + +int __cpu_disable(unsigned int cpu) +{ + unsigned long flags; + ec_creg_mask_parms cr_parms; + + local_irq_save(flags); + + /* Disabling all external interrupts */ + + cr_parms.start_ctl = 0; + cr_parms.end_ctl = 0; + cr_parms.orvals[0] = 0; + cr_parms.andvals[0] = ~(1<<15 | 1<<14 | 1<<13 | 1<<12 | + 1<<11 | 1<<10 | 1<< 6 | 1<< 4); + smp_ctl_bit_callback(&cr_parms); + + /* Disabling all I/O interrupts */ + + cr_parms.start_ctl = 6; + cr_parms.end_ctl = 6; + cr_parms.orvals[6] = 0; + cr_parms.andvals[6] = ~(1<<31 | 1<<30 | 1<<29 | 1<<28 | + 1<<27 | 1<<26 | 1<<25 | 1<<24); + smp_ctl_bit_callback(&cr_parms); + + /* Disabling most machine checks */ + + cr_parms.start_ctl = 14; + cr_parms.end_ctl = 14; + cr_parms.orvals[14] = 0; + cr_parms.andvals[14] = ~(1<<28 | 1<<27 | 1<<26 | 1<<25 | 1<<24); + smp_ctl_bit_callback(&cr_parms); + + /* + * Don't allow cpu_idle to get into waitstate. + * Irqs are disabled and cpu_idle would probably + * never leave waitstate again! + */ + + no_wait_psw = 1; + + /* Remove from online map. */ + clear_bit(cpu, &cpu_online_map); + eieio(); + + local_irq_restore(flags); + + return 0; +} + +void __cpu_die(unsigned int cpu) +{ + + unsigned long flags; + + /* We handle this in the idle loop */ + cpu_dead_mask |= (1 << cpu); + + /* Wait until target cpu killed itself */ + while (!cpu_stopped(cpu)); + + /* + * If we killed the boot cpu we have to make sure that + * another cpu will feel responsible for timer irqs. + */ + + local_irq_save(flags); + if (boot_cpu_addr == __cpu_logical_map[cpu]) + boot_cpu_addr = __cpu_logical_map[smp_processor_id()]; + local_irq_restore(flags); + + clear_bit(cpu, &cpu_initialized); + cpus_initialized--; + eieio(); + + printk("Processor %d spun down\n", cpu); +} + +int __cpu_up(unsigned int cpu) +{ + int ret = -EBUSY; + + if (cpu >= max_cpus) + goto out; + + /* We handle this in the idle loop */ + cpu_dead_mask &= ~(1 << cpu); + + if (!smp_boot_new_cpu(cpu)){ + /* failed to boot new cpu */ + cpu_dead_mask |= (1 << cpu); + eieio(); + goto out; + } + + /* Wait until new cpu is ready */ + while(!test_bit(cpu, &cpu_online_map)) + eieio(); + printk("Processor %d spun up\n", cpu); + ret = 0; + out: + return ret; +} + EXPORT_SYMBOL(lowcore_ptr); EXPORT_SYMBOL(kernel_flag); EXPORT_SYMBOL(smp_ctl_set_bit); EXPORT_SYMBOL(smp_ctl_clear_bit); -EXPORT_SYMBOL(smp_num_cpus); +EXPORT_SYMBOL(cpu_online_map); diff -Nur linux-2.5.0/arch/s390x/kernel/irq.c linux-2.5.0-lhcs/arch/s390x/kernel/irq.c --- linux-2.5.0/arch/s390x/kernel/irq.c Wed Jul 25 14:12:01 2001 +++ linux-2.5.0-lhcs/arch/s390x/kernel/irq.c Tue Dec 11 18:37:21 2001 @@ -68,9 +68,11 @@ p += sprintf(p, " "); - for (j=0; jirq_desc.handler->typename); p += sprintf(p, " %s", action->name); diff -Nur linux-2.5.0/arch/s390x/kernel/process.c linux-2.5.0-lhcs/arch/s390x/kernel/process.c --- linux-2.5.0/arch/s390x/kernel/process.c Thu Oct 11 09:04:57 2001 +++ linux-2.5.0-lhcs/arch/s390x/kernel/process.c Tue Dec 11 18:37:21 2001 @@ -43,6 +43,7 @@ #include #include #include +#include asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); @@ -51,21 +52,42 @@ */ static psw_t wait_psw; +volatile int no_wait_psw = 0; /* will be modified from __cpu_disable */ +extern volatile unsigned long cpu_dead_mask; int cpu_idle(void *unused) { + int cpu = smp_processor_id(); + /* endless idle loop with no priority at all */ init_idle(); current->nice = 20; current->counter = -100; wait_psw.mask = _WAIT_PSW_MASK; wait_psw.addr = (unsigned long) &&idle_wakeup; + + /* Add to online map. */ + set_bit(cpu, &cpu_online_map); + eieio(); + while(1) { + if (cpu_dead_mask & (1 << cpu)) { + __cli(); + no_wait_psw = 0; + /* Flushing local pgt cache */ + do_check_pgt_cache(0,0); + signal_processor(cpu, sigp_stop); + /* this point will never be reached */ + while(1); + __sti(); + } if (current->need_resched) { schedule(); check_pgt_cache(); continue; } + if (no_wait_psw) + continue; /* load wait psw */ asm volatile ( diff -Nur linux-2.5.0/arch/s390x/kernel/setup.c linux-2.5.0-lhcs/arch/s390x/kernel/setup.c --- linux-2.5.0/arch/s390x/kernel/setup.c Fri Nov 16 18:38:39 2001 +++ linux-2.5.0-lhcs/arch/s390x/kernel/setup.c Tue Dec 11 18:37:21 2001 @@ -78,7 +78,7 @@ /* * cpu_init() initializes state that is per-CPU. */ -void __init cpu_init (void) +void cpu_init (void) { int nr = smp_processor_id(); int addr = hard_smp_processor_id(); @@ -102,12 +102,9 @@ current->flags &= ~PF_USEDFPU; current->used_math = 0; - /* Setup active_mm for idle_task */ - atomic_inc(&init_mm.mm_count); - current->active_mm = &init_mm; if (current->mm) BUG(); - enter_lazy_tlb(&init_mm, current, nr); + enter_lazy_tlb(current->active_mm, current, nr); } /* @@ -480,7 +477,7 @@ seq_printf(m, "vendor_id : IBM/S390\n" "# processors : %i\n" "bogomips per cpu: %lu.%02lu\n", - smp_num_cpus, loops_per_jiffy/(500000/HZ), + num_online_cpus(), loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ))%100); } else if (cpu_online_map & (1 << n)) { cpuinfo = &safe_get_cpu_lowcore(n).cpu_data; diff -Nur linux-2.5.0/arch/s390x/kernel/smp.c linux-2.5.0-lhcs/arch/s390x/kernel/smp.c --- linux-2.5.0/arch/s390x/kernel/smp.c Wed Nov 21 10:31:09 2001 +++ linux-2.5.0-lhcs/arch/s390x/kernel/smp.c Tue Dec 11 18:37:21 2001 @@ -9,15 +9,6 @@ * based on other smp stuff by * (c) 1995 Alan Cox, CymruNET Ltd * (c) 1998 Ingo Molnar - * - * We work with logical cpu numbering everywhere we can. The only - * functions using the real cpu address (got from STAP) are the sigp - * functions. For all other functions we use the identity mapping. - * That means that cpu_number_map[i] == i for every cpu. cpu_number_map is - * used e.g. to find the idle task belonging to a logical cpu. Every array - * in the kernel is sorted by the logical cpu number and not by the physical - * one which is causing all the confusion with __cpu_logical_map and - * cpu_number_map in other architectures. */ #include @@ -35,18 +26,17 @@ #include #include #include +#include /* prototypes */ extern int cpu_idle(void * unused); extern __u16 boot_cpu_addr; -extern volatile int __cpu_logical_map[]; /* * An array with a pointer the lowcore of every CPU. */ static int max_cpus = NR_CPUS; /* Setup configured maximum number of CPUs to activate */ -int smp_num_cpus; struct _lowcore *lowcore_ptr[NR_CPUS]; unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_old_multiplier[NR_CPUS]; @@ -59,6 +49,11 @@ unsigned long cpu_online_map; +extern int cpus_initialized; /* setup.c */ +extern unsigned long cpu_initialized; /* setup.c */ +extern volatile int no_wait_psw; /* process.c */ +extern struct semaphore cpucontrol; /* kernel/cpu.c */ + /* * Setup routine for controlling SMP activation * @@ -149,7 +144,7 @@ */ { struct call_data_struct data; - int cpus = smp_num_cpus-1; + int cpus = num_online_cpus() - 1; if (!cpus || !atomic_read(&smp_commenced)) return 0; @@ -183,6 +178,20 @@ * Various special callbacks */ +static inline int boot_cpu_id(void) +{ + int cpu; + + for(cpu = 0; cpu < NR_CPUS; cpu++){ + if (!cpu_online(cpu)) + continue; + if (__cpu_logical_map[cpu] == boot_cpu_addr) + return cpu; + } + BUG(); + return 0; +} + void do_machine_restart(void) { smp_send_stop(); @@ -191,8 +200,10 @@ void machine_restart(char * __unused) { - if (smp_processor_id() != 0) { - smp_ext_bitcall(0, ec_restart); + __u16 cpu = __cpu_logical_map[smp_processor_id()]; + + if (cpu != boot_cpu_addr) { + smp_ext_bitcall(boot_cpu_id(), ec_restart); for (;;); } else do_machine_restart(); @@ -208,8 +219,10 @@ void machine_halt(void) { - if (smp_processor_id() != 0) { - smp_ext_bitcall(0, ec_halt); + __u16 cpu = __cpu_logical_map[smp_processor_id()]; + + if (cpu != boot_cpu_addr) { + smp_ext_bitcall(boot_cpu_id(), ec_halt); for (;;); } else do_machine_halt(); @@ -225,8 +238,10 @@ void machine_power_off(void) { - if (smp_processor_id() != 0) { - smp_ext_bitcall(0, ec_power_off); + __u16 cpu = __cpu_logical_map[smp_processor_id()]; + + if (cpu != boot_cpu_addr) { + smp_ext_bitcall(boot_cpu_id(), ec_power_off); for (;;); } else do_machine_power_off(); @@ -286,7 +301,9 @@ sigp_ccode ccode; int i; - for (i = 0; i < smp_num_cpus; i++) { + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; if (smp_processor_id() == i) continue; /* @@ -314,7 +331,9 @@ /* stop all processors */ - for (i = 0; i < smp_num_cpus; i++) { + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; if (smp_processor_id() != i) { int ccode; do { @@ -329,7 +348,9 @@ /* store status of all processors in their lowcores (real 0) */ - for (i = 0; i < smp_num_cpus; i++) { + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; if (smp_processor_id() != i) { int ccode; low_core_addr = (unsigned long)&get_cpu_lowcore(i); @@ -369,7 +390,7 @@ /* * callback for setting/clearing control bits */ -void smp_ctl_bit_callback(void *info) { +static void smp_ctl_bit_callback(void *info) { ec_creg_mask_parms *pp; u64 cregs[16]; int i; @@ -397,6 +418,11 @@ void smp_ctl_set_bit(int cr, int bit) { ec_creg_mask_parms parms; + /* We don't allow writing to control registers while + * a cpu gets detached or attached and vice versa.. + */ + + down(&cpucontrol); if (atomic_read(&smp_commenced) != 0) { parms.start_ctl = cr; parms.end_ctl = cr; @@ -405,6 +431,7 @@ smp_call_function(smp_ctl_bit_callback, &parms, 0, 1); } __ctl_set_bit(cr, bit); + up(&cpucontrol); } /* @@ -413,6 +440,7 @@ void smp_ctl_clear_bit(int cr, int bit) { ec_creg_mask_parms parms; + down(&cpucontrol); if (atomic_read(&smp_commenced) != 0) { parms.start_ctl = cr; parms.end_ctl = cr; @@ -421,6 +449,7 @@ smp_call_function(smp_ctl_bit_callback, &parms, 0, 1); } __ctl_clear_bit(cr, bit); + up(&cpucontrol); } @@ -433,18 +462,18 @@ int curr_cpu; current->processor = 0; - smp_num_cpus = 1; + cpu_online_map = 1; for (curr_cpu = 0; - curr_cpu <= 65535 && smp_num_cpus < max_cpus; curr_cpu++) { + curr_cpu <= 65535 && num_online_cpus() < max_cpus; curr_cpu++) { if ((__u16) curr_cpu == boot_cpu_addr) continue; - __cpu_logical_map[smp_num_cpus] = (__u16) curr_cpu; - if (signal_processor(smp_num_cpus, sigp_sense) == + __cpu_logical_map[num_online_cpus()] = (__u16) curr_cpu; + if (signal_processor(num_online_cpus(), sigp_sense) == sigp_not_operational) continue; - smp_num_cpus++; + cpu_online_map |= 1 << num_online_cpus(); } - printk("Detected %d CPU's\n",(int) smp_num_cpus); + printk("Detected %d CPU's\n",(int) num_online_cpus()); printk("Boot cpu address %2X\n", boot_cpu_addr); } @@ -455,7 +484,7 @@ extern void init_100hz_timer(void); extern int pfault_init(void); -int __init start_secondary(void *cpuvoid) +int start_secondary(void *cpuvoid) { /* Setup the cpu */ cpu_init(); @@ -492,6 +521,21 @@ return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); } +static inline void setup_lowcore(struct _lowcore *cpu_lowcore, + struct task_struct *idle){ + + cpu_lowcore->save_area[15] = idle->thread.ksp; + cpu_lowcore->kernel_stack = (__u64) idle + 16384; + __asm__ __volatile__("la 1,%0\n\t" + "stctg 0,15,0(1)\n\t" + "la 1,%1\n\t" + "stam 0,15,0(1)" + : "=m" (cpu_lowcore->cregs_save_area[0]), + "=m" (cpu_lowcore->access_regs_save_area[0]) + : : "1", "memory"); + return; +} + static void __init do_boot_cpu(int cpu) { struct task_struct *idle; @@ -511,21 +555,34 @@ panic("No idle process for CPU %d",cpu); idle->processor = cpu; idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */ + /* Setup active_mm for idle_task */ + atomic_inc(&init_mm.mm_count); + idle->active_mm = &init_mm; del_from_runqueue(idle); unhash_process(idle); init_tasks[cpu] = idle; cpu_lowcore=&get_cpu_lowcore(cpu); - cpu_lowcore->save_area[15] = idle->thread.ksp; - cpu_lowcore->kernel_stack = (idle->thread.ksp | 16383) + 1; - __asm__ __volatile__("la 1,%0\n\t" - "stctg 0,15,0(1)\n\t" - "la 1,%1\n\t" - "stam 0,15,0(1)" - : "=m" (cpu_lowcore->cregs_save_area[0]), - "=m" (cpu_lowcore->access_regs_save_area[0]) - : : "1", "memory"); + + setup_lowcore(cpu_lowcore, idle); + + eieio(); + + if (cpu_online(cpu)) + signal_processor(cpu,sigp_restart); +} + +static void do_boot_cpu_late(int cpu) +{ + struct task_struct *idle; + struct _lowcore *cpu_lowcore; + + idle = init_tasks[cpu]; + + cpu_lowcore=&get_cpu_lowcore(cpu); + + setup_lowcore(cpu_lowcore, idle); eieio(); signal_processor(cpu,sigp_restart); @@ -581,8 +638,7 @@ print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data); - for(i = 0; i < smp_num_cpus; i++) - { + for(i = 0; i < max_cpus; i++){ curr_lowcore = (struct _lowcore *) __get_free_pages(GFP_KERNEL|GFP_DMA, 1); if (curr_lowcore == NULL) { @@ -606,8 +662,11 @@ if (smp_processor_id() == i) set_prefix((u32)(u64)curr_lowcore); else { + ccode = 0; + if (cpu_online(i)){ ccode = signal_processor_p((u64)(curr_lowcore), i, sigp_set_prefix); + } if(ccode) { /* if this gets troublesome I'll have to do * something about it. */ @@ -621,6 +680,44 @@ } } +static int smp_boot_new_cpu(unsigned long cpu) +{ + struct _lowcore *curr_lowcore; + sigp_ccode ccode; + int curr_cpu; + int ret = 0; + + for (curr_cpu = 0; curr_cpu <= 65535; curr_cpu++) { + __cpu_logical_map[cpu] = (__u16) curr_cpu; + if (cpu_stopped(cpu)) + break; + } + + if (!cpu_stopped(cpu)) + goto out; + + curr_lowcore = &get_cpu_lowcore(cpu); + + /* Cleaning up lowcore.. (these values should be zero anyway) */ + + curr_lowcore->ext_call_fast = 0; + + ccode = signal_processor_p((u64)(curr_lowcore), cpu, sigp_set_prefix); + if(ccode) { + printk("ccode %d for cpu %d returned when " + "setting prefix in smp_boot_cpus not good.\n", + (int) ccode, (int) cpu); + goto out; + } + else { + do_boot_cpu_late(cpu); + ret = 1; + } + out: + return ret; +} + + /* * the frequency of the profiling timer can be changed * by writing a multiplier value into /proc/profile. @@ -682,8 +779,118 @@ } } + +/* Upping and downing of CPUs */ + +volatile unsigned long cpu_dead_mask; + +int __cpu_disable(unsigned int cpu) +{ + unsigned long flags; + ec_creg_mask_parms cr_parms; + + local_irq_save(flags); + + /* Disabling all external interrupts */ + + cr_parms.start_ctl = 0; + cr_parms.end_ctl = 0; + cr_parms.orvals[0] = 0; + cr_parms.andvals[0] = ~(1<<15 | 1<<14 | 1<<13 | 1<<12 | + 1<<11 | 1<<10 | 1<< 6 | 1<< 4); + smp_ctl_bit_callback(&cr_parms); + + /* Disabling all I/O interrupts */ + + cr_parms.start_ctl = 6; + cr_parms.end_ctl = 6; + cr_parms.orvals[6] = 0; + cr_parms.andvals[6] = ~(1<<31 | 1<<30 | 1<<29 | 1<<28 | + 1<<27 | 1<<26 | 1<<25 | 1<<24); + smp_ctl_bit_callback(&cr_parms); + + /* Disabling most machine checks */ + + cr_parms.start_ctl = 14; + cr_parms.end_ctl = 14; + cr_parms.orvals[14] = 0; + cr_parms.andvals[14] = ~(1<<28 | 1<<27 | 1<<26 | 1<<25 | 1<<24); + smp_ctl_bit_callback(&cr_parms); + + /* + * Don't allow cpu_idle to get into waitstate. + * Irqs are disabled and cpu_idle would probably + * never leave waitstate again! + */ + + no_wait_psw = 1; + + /* Remove from online map. */ + clear_bit(cpu, &cpu_online_map); + eieio(); + + local_irq_restore(flags); + + return 0; +} + +void __cpu_die(unsigned int cpu) +{ + + unsigned long flags; + + /* We handle this in the idle loop */ + cpu_dead_mask |= (1 << cpu); + + /* Wait until target cpu killed itself */ + while (!cpu_stopped(cpu)); + + /* + * If we killed the boot cpu we have to make sure that + * another cpu will feel responsible for timer irqs. + */ + + local_irq_save(flags); + if (boot_cpu_addr == __cpu_logical_map[cpu]) + boot_cpu_addr = __cpu_logical_map[smp_processor_id()]; + local_irq_restore(flags); + + clear_bit(cpu, &cpu_initialized); + cpus_initialized--; + eieio(); + + printk("Processor %d spun down\n", cpu); +} + +int __cpu_up(unsigned int cpu) +{ + int ret = -EBUSY; + + if (cpu >= max_cpus) + goto out; + + /* We handle this in the idle loop */ + cpu_dead_mask &= ~(1 << cpu); + + if (!smp_boot_new_cpu(cpu)){ + /* failed to boot new cpu */ + cpu_dead_mask |= (1 << cpu); + eieio(); + goto out; + } + + /* Wait until new cpu is ready */ + while(!test_bit(cpu, &cpu_online_map)) + eieio(); + + printk("Processor %d spun up\n", cpu); + ret = 0; + out: + return ret; +} + EXPORT_SYMBOL(lowcore_ptr); EXPORT_SYMBOL(kernel_flag); EXPORT_SYMBOL(smp_ctl_set_bit); EXPORT_SYMBOL(smp_ctl_clear_bit); -EXPORT_SYMBOL(smp_num_cpus); +EXPORT_SYMBOL(cpu_online_map); diff -Nur linux-2.5.0/arch/sparc/kernel/smp.c linux-2.5.0-lhcs/arch/sparc/kernel/smp.c --- linux-2.5.0/arch/sparc/kernel/smp.c Tue Nov 13 09:16:05 2001 +++ linux-2.5.0-lhcs/arch/sparc/kernel/smp.c Wed Dec 12 10:41:15 2001 @@ -301,3 +301,19 @@ seq_printf(m, "CPU%d\t\t: online\n", i); } } + +/* Upping and downing of CPUs */ +/* FIXME: implement. */ +int __cpu_disable(unsigned int cpu) +{ + return -ENOSYS; +} + +void __cpu_die(unsigned int cpu) +{ +} + +int __cpu_up(unsigned int cpu) +{ + return -ENOSYS; +} diff -Nur linux-2.5.0/arch/sparc64/kernel/smp.c linux-2.5.0-lhcs/arch/sparc64/kernel/smp.c --- linux-2.5.0/arch/sparc64/kernel/smp.c Wed Nov 21 10:31:09 2001 +++ linux-2.5.0-lhcs/arch/sparc64/kernel/smp.c Wed Dec 12 10:41:15 2001 @@ -1120,3 +1120,19 @@ return 0; } + +/* Upping and downing of CPUs */ +/* FIXME: implement. */ +int __cpu_disable(unsigned int cpu) +{ + return -ENOSYS; +} + +void __cpu_die(unsigned int cpu) +{ +} + +int __cpu_up(unsigned int cpu) +{ + return -ENOSYS; +} diff -Nur linux-2.5.0/drivers/acpi/ospm/processor/prpower.c linux-2.5.0-lhcs/drivers/acpi/ospm/processor/prpower.c --- linux-2.5.0/drivers/acpi/ospm/processor/prpower.c Wed Oct 24 14:06:22 2001 +++ linux-2.5.0-lhcs/drivers/acpi/ospm/processor/prpower.c Tue Dec 11 18:37:21 2001 @@ -504,7 +504,7 @@ processor->power.state[PR_C2].latency = acpi_fadt.plvl2_lat; #ifdef CONFIG_SMP - if (smp_num_cpus == 1) { + if (num_online_cpus() == 1) { #endif /*CONFIG_SMP*/ if (acpi_fadt.plvl2_lat <= PR_MAX_C2_LATENCY) { processor->power.state[PR_C2].is_valid = TRUE; @@ -531,7 +531,7 @@ processor->power.state[PR_C3].latency = acpi_fadt.plvl3_lat; #ifdef CONFIG_SMP - if (smp_num_cpus == 1) { + if (num_online_cpus() == 1) { #endif /*CONFIG_SMP*/ if ((acpi_fadt.plvl3_lat <= PR_MAX_C3_LATENCY) && bm_control) { processor->power.state[PR_C3].is_valid = TRUE; diff -Nur linux-2.5.0/drivers/char/agp/agpgart_be.c linux-2.5.0-lhcs/drivers/char/agp/agpgart_be.c --- linux-2.5.0/drivers/char/agp/agpgart_be.c Fri Nov 16 10:11:22 2001 +++ linux-2.5.0-lhcs/drivers/char/agp/agpgart_be.c Tue Dec 11 18:37:21 2001 @@ -98,7 +98,7 @@ static void smp_flush_cache(void) { - atomic_set(&cpus_waiting, smp_num_cpus - 1); + atomic_set(&cpus_waiting, num_online_cpus() - 1); if (smp_call_function(ipi_handler, NULL, 1, 0) != 0) panic(PFX "timed out waiting for the other CPUs!\n"); flush_cache(); diff -Nur linux-2.5.0/drivers/net/aironet4500_core.c linux-2.5.0-lhcs/drivers/net/aironet4500_core.c --- linux-2.5.0/drivers/net/aironet4500_core.c Sun Sep 30 12:26:06 2001 +++ linux-2.5.0-lhcs/drivers/net/aironet4500_core.c Tue Dec 11 18:37:21 2001 @@ -2669,10 +2669,8 @@ * but without it card gets screwed up */ #ifdef CONFIG_SMP - if(smp_num_cpus > 1){ both_bap_lock = 1; bap_setup_spinlock = 1; - } #endif //awc_dump_registers(dev); diff -Nur linux-2.5.0/drivers/video/fbcon.c linux-2.5.0-lhcs/drivers/video/fbcon.c --- linux-2.5.0/drivers/video/fbcon.c Mon Oct 15 13:47:13 2001 +++ linux-2.5.0-lhcs/drivers/video/fbcon.c Tue Dec 11 18:37:21 2001 @@ -2176,7 +2176,7 @@ if (p->fb_info->fbops->fb_rasterimg) p->fb_info->fbops->fb_rasterimg(p->fb_info, 1); - for (x = 0; x < smp_num_cpus * (LOGO_W + 8) && + for (x = 0; x < num_online_cpus() * (LOGO_W + 8) && x < p->var.xres - (LOGO_W + 8); x += (LOGO_W + 8)) { #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \ diff -Nur linux-2.5.0/fs/proc/array.c linux-2.5.0-lhcs/fs/proc/array.c --- linux-2.5.0/fs/proc/array.c Thu Oct 11 09:00:01 2001 +++ linux-2.5.0-lhcs/fs/proc/array.c Tue Dec 11 18:37:21 2001 @@ -685,12 +685,14 @@ task->times.tms_utime, task->times.tms_stime); - for (i = 0 ; i < smp_num_cpus; i++) + for (i = 0 ; i < NR_CPUS; i++) { + if (cpu_online(i)) len += sprintf(buffer + len, "cpu%d %lu %lu\n", i, - task->per_cpu_utime[cpu_logical_map(i)], - task->per_cpu_stime[cpu_logical_map(i)]); + task->per_cpu_utime[i], + task->per_cpu_stime[i]); + } return len; } #endif diff -Nur linux-2.5.0/fs/proc/proc_misc.c linux-2.5.0-lhcs/fs/proc/proc_misc.c --- linux-2.5.0/fs/proc/proc_misc.c Tue Nov 20 21:29:09 2001 +++ linux-2.5.0-lhcs/fs/proc/proc_misc.c Tue Dec 11 18:37:21 2001 @@ -244,29 +244,32 @@ unsigned int sum = 0, user = 0, nice = 0, system = 0; int major, disk; - for (i = 0 ; i < smp_num_cpus; i++) { - int cpu = cpu_logical_map(i), j; + for (i = 0 ; i < NR_CPUS; i++) { + int j; - user += kstat.per_cpu_user[cpu]; - nice += kstat.per_cpu_nice[cpu]; - system += kstat.per_cpu_system[cpu]; + if(!cpu_online(i)) continue; + user += kstat.per_cpu_user[i]; + nice += kstat.per_cpu_nice[i]; + system += kstat.per_cpu_system[i]; #if !defined(CONFIG_ARCH_S390) for (j = 0 ; j < NR_IRQS ; j++) - sum += kstat.irqs[cpu][j]; + sum += kstat.irqs[i][j]; #endif } len = sprintf(page, "cpu %u %u %u %lu\n", user, nice, system, - jif * smp_num_cpus - (user + nice + system)); - for (i = 0 ; i < smp_num_cpus; i++) + jif * num_online_cpus() - (user + nice + system)); + for (i = 0 ; i < NR_CPUS; i++){ + if (!cpu_online(i)) continue; len += sprintf(page + len, "cpu%d %u %u %u %lu\n", i, - kstat.per_cpu_user[cpu_logical_map(i)], - kstat.per_cpu_nice[cpu_logical_map(i)], - kstat.per_cpu_system[cpu_logical_map(i)], - jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \ - + kstat.per_cpu_nice[cpu_logical_map(i)] \ - + kstat.per_cpu_system[cpu_logical_map(i)])); + kstat.per_cpu_user[i], + kstat.per_cpu_nice[i], + kstat.per_cpu_system[i], + jif - ( kstat.per_cpu_user[i] \ + + kstat.per_cpu_nice[i] \ + + kstat.per_cpu_system[i])); + } len += sprintf(page + len, "page %u %u\n" "swap %u %u\n" diff -Nur linux-2.5.0/include/asm-i386/hardirq.h linux-2.5.0-lhcs/include/asm-i386/hardirq.h --- linux-2.5.0/include/asm-i386/hardirq.h Thu Nov 22 11:46:19 2001 +++ linux-2.5.0-lhcs/include/asm-i386/hardirq.h Wed Dec 12 15:53:20 2001 @@ -48,7 +48,7 @@ { int i; - for (i = 0; i < smp_num_cpus; i++) + for (i = 0; i < NR_CPUS; i++) if (local_irq_count(i)) return 1; return 0; diff -Nur linux-2.5.0/include/asm-i386/smp.h linux-2.5.0-lhcs/include/asm-i386/smp.h --- linux-2.5.0/include/asm-i386/smp.h Thu Nov 22 11:46:19 2001 +++ linux-2.5.0-lhcs/include/asm-i386/smp.h Wed Dec 12 15:53:20 2001 @@ -65,20 +65,6 @@ extern void zap_low_mappings (void); /* - * On x86 all CPUs are mapped 1:1 to the APIC space. - * This simplifies scheduling and IPI sending and - * compresses data structures. - */ -static inline int cpu_logical_map(int cpu) -{ - return cpu; -} -static inline int cpu_number_map(int cpu) -{ - return cpu; -} - -/* * Some lowlevel functions might want to know about * the real APIC ID <-> CPU # mapping. */ @@ -102,6 +88,12 @@ */ #define smp_processor_id() (current->processor) +#define cpu_online(cpu) (cpu_online_map & (1<<(cpu))) + +extern inline unsigned int num_online_cpus(void) +{ + return hweight32(cpu_online_map); +} static __inline int hard_smp_processor_id(void) { @@ -109,6 +101,11 @@ return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID)); } +/* Upping and downing of CPUs */ +extern int __cpu_disable(unsigned int cpu); +extern void __cpu_die(unsigned int cpu); +extern int __cpu_up(unsigned int cpu); + static __inline int logical_smp_processor_id(void) { /* we don't want to mark this access volatile - bad code generation */ diff -Nur linux-2.5.0/include/asm-ia64/hardirq.h linux-2.5.0-lhcs/include/asm-ia64/hardirq.h --- linux-2.5.0/include/asm-ia64/hardirq.h Tue Jul 31 10:30:09 2001 +++ linux-2.5.0-lhcs/include/asm-ia64/hardirq.h Tue Dec 11 18:37:21 2001 @@ -58,7 +58,7 @@ { int i; - for (i = 0; i < smp_num_cpus; i++) + for (i = 0; i < NR_CPUS; i++) if (irq_count(i)) return 1; return 0; diff -Nur linux-2.5.0/include/asm-ia64/smp.h linux-2.5.0-lhcs/include/asm-ia64/smp.h --- linux-2.5.0/include/asm-ia64/smp.h Fri Nov 9 14:26:17 2001 +++ linux-2.5.0-lhcs/include/asm-ia64/smp.h Tue Dec 11 18:37:21 2001 @@ -32,7 +32,7 @@ extern struct smp_boot_data { int cpu_count; int cpu_phys_id[NR_CPUS]; -} smp_boot_data __initdata; +} smp_boot_data; extern char no_int_routing __initdata; @@ -48,6 +48,12 @@ extern unsigned long ap_wakeup_vector; +#define cpu_online(cpu) (cpu_online_map & (1<<(cpu))) +extern inline unsigned int num_online_cpus(void) +{ + return hweight64(cpu_online_map); +} + /* * Function to map hard smp processor id to logical id. Slow, so * don't use this in performance-critical code. @@ -57,7 +63,7 @@ { int i; - for (i = 0; i < smp_num_cpus; ++i) + for (i = 0; i < NR_CPUS; ++i) if (cpu_physical_id(i) == (__u32) cpuid) break; return i; diff -Nur linux-2.5.0/include/asm-ppc/smp.h linux-2.5.0-lhcs/include/asm-ppc/smp.h --- linux-2.5.0/include/asm-ppc/smp.h Tue Aug 28 06:58:33 2001 +++ linux-2.5.0-lhcs/include/asm-ppc/smp.h Wed Dec 12 10:41:15 2001 @@ -15,6 +15,7 @@ #include #include +#include #ifdef CONFIG_SMP @@ -44,11 +45,14 @@ #define NO_PROC_ID 0xFF /* No processor magic marker */ #define PROC_CHANGE_PENALTY 20 -/* 1 to 1 mapping on PPC -- Cort */ -#define cpu_logical_map(cpu) (cpu) -#define cpu_number_map(x) (x) - +extern unsigned long cpu_online_map; #define smp_processor_id() (current->processor) +#define cpu_online(cpu) (cpu_online_map & (1<<(cpu))) + +static inline unsigned int num_online_cpus(void) +{ + return hweight32(cpu_online_map); +} extern int smp_hw_index[NR_CPUS]; #define hard_smp_processor_id() (smp_hw_index[smp_processor_id()]) @@ -62,6 +66,11 @@ #define KLOCK_HELD 0xffffffff #define KLOCK_CLEAR 0x0 +/* Upping and downing of CPUs */ +extern int __cpu_disable(unsigned int cpu); +extern void __cpu_die(unsigned int cpu); +extern int __cpu_up(unsigned int cpu); + #endif /* __ASSEMBLY__ */ #else /* !(CONFIG_SMP) */ diff -Nur linux-2.5.0/include/asm-s390/pgalloc.h linux-2.5.0-lhcs/include/asm-s390/pgalloc.h --- linux-2.5.0/include/asm-s390/pgalloc.h Thu Oct 11 09:43:38 2001 +++ linux-2.5.0-lhcs/include/asm-s390/pgalloc.h Tue Dec 11 18:37:21 2001 @@ -237,7 +237,7 @@ static inline void __flush_tlb_mm(struct mm_struct * mm) { - if ((smp_num_cpus > 1) && + if ((num_online_cpus() > 1) && ((atomic_read(&mm->mm_count) != 1) || (mm->cpu_vm_mask != (1UL << smp_processor_id())))) { mm->cpu_vm_mask = (1UL << smp_processor_id()); diff -Nur linux-2.5.0/include/asm-s390/sigp.h linux-2.5.0-lhcs/include/asm-s390/sigp.h --- linux-2.5.0/include/asm-s390/sigp.h Thu Oct 11 09:43:38 2001 +++ linux-2.5.0-lhcs/include/asm-s390/sigp.h Tue Dec 11 18:37:21 2001 @@ -129,6 +129,31 @@ return ccode; } +extern __inline__ int cpu_stopped(int cpu_addr) +{ + sigp_ccode retval = 0; + sigp_order_code order_code = sigp_sense; + + __asm__ __volatile__( + " sr 1,1\n" /* parameter=0 in gpr 1 */ + " sigp 1,%1,0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + " chi %0,0x1\n" /* test if sigp was accepted */ + " jne 0f\n" + " tml 1,0x40\n" /* test if cpu is in stopped state */ + " jno 0f\n" + " sr %0,%0\n" + " ahi %0,0x1\n" + " j 1f\n" + "0: sr %0,%0\n" + "1: \n" + : "=d" (retval) + : "d" (__cpu_logical_map[cpu_addr]), "a" (order_code) + : "cc" , "memory", "1" ); + return retval; +} + #endif __SIGP__ diff -Nur linux-2.5.0/include/asm-s390/smp.h linux-2.5.0-lhcs/include/asm-s390/smp.h --- linux-2.5.0/include/asm-s390/smp.h Thu Oct 11 09:43:38 2001 +++ linux-2.5.0-lhcs/include/asm-s390/smp.h Tue Dec 11 18:37:21 2001 @@ -14,6 +14,7 @@ #if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__) #include +#include /* s390 specific smp.c headers @@ -43,15 +44,11 @@ #define PROC_CHANGE_PENALTY 20 /* Schedule penalty */ #define smp_processor_id() (current->processor) +#define cpu_online(cpu) (cpu_online_map & (1<<(cpu))) -extern __inline__ int cpu_logical_map(int cpu) +extern __inline__ unsigned int num_online_cpus(void) { - return cpu; -} - -extern __inline__ int cpu_number_map(int cpu) -{ - return cpu; + return hweight32(cpu_online_map); } extern __inline__ __u16 hard_smp_processor_id(void) @@ -62,7 +59,10 @@ return cpu_address; } -#define cpu_logical_map(cpu) (cpu) +/* Upping and downing of CPUs */ +extern int __cpu_disable(unsigned int cpu); +extern void __cpu_die(unsigned int cpu); +extern int __cpu_up(unsigned int cpu); void smp_local_timer_interrupt(struct pt_regs * regs); diff -Nur linux-2.5.0/include/asm-s390x/pgalloc.h linux-2.5.0-lhcs/include/asm-s390x/pgalloc.h --- linux-2.5.0/include/asm-s390x/pgalloc.h Wed Jul 25 14:12:02 2001 +++ linux-2.5.0-lhcs/include/asm-s390x/pgalloc.h Tue Dec 11 18:37:21 2001 @@ -264,7 +264,7 @@ */ static inline void __flush_tlb_mm(struct mm_struct * mm) { - if ((smp_num_cpus > 1) && + if ((num_online_cpus() > 1) && ((atomic_read(&mm->mm_count) != 1) || (mm->cpu_vm_mask != (1UL << smp_processor_id())))) { mm->cpu_vm_mask = (1UL << smp_processor_id()); diff -Nur linux-2.5.0/include/asm-s390x/sigp.h linux-2.5.0-lhcs/include/asm-s390x/sigp.h --- linux-2.5.0/include/asm-s390x/sigp.h Thu Oct 11 09:43:38 2001 +++ linux-2.5.0-lhcs/include/asm-s390x/sigp.h Tue Dec 11 18:37:21 2001 @@ -130,6 +130,29 @@ return ccode; } -#endif __SIGP__ +extern __inline__ int cpu_stopped(int cpu_addr) +{ + sigp_ccode retval = 0; + sigp_order_code order_code = sigp_sense; + __asm__ __volatile__( + " sgr 1,1\n" + " sigp 1,%1,0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + " chi %0,0x1\n" + " jne 0f\n" + " tml 1,0x40\n" + " jno 0f\n" + " sgr %0,%0\n" + " ahi %0,0x1\n" + " j 1f\n" + "0: sgr %0,%0\n" + "1: \n" + : "=d" (retval) + : "d" (__cpu_logical_map[cpu_addr]), "a" (order_code) + : "cc" , "memory", "1" ); + return retval; +} +#endif __SIGP__ diff -Nur linux-2.5.0/include/asm-s390x/smp.h linux-2.5.0-lhcs/include/asm-s390x/smp.h --- linux-2.5.0/include/asm-s390x/smp.h Thu Oct 11 09:43:38 2001 +++ linux-2.5.0-lhcs/include/asm-s390x/smp.h Tue Dec 11 18:37:21 2001 @@ -14,6 +14,7 @@ #if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__) #include +#include /* s390 specific smp.c headers @@ -43,15 +44,11 @@ #define PROC_CHANGE_PENALTY 20 /* Schedule penalty */ #define smp_processor_id() (current->processor) +#define cpu_online(cpu) (cpu_online_map & (1<<(cpu))) -extern __inline__ int cpu_logical_map(int cpu) +extern __inline__ unsigned int num_online_cpus(void) { - return cpu; -} - -extern __inline__ int cpu_number_map(int cpu) -{ - return cpu; + return hweight32(cpu_online_map); } extern __inline__ __u16 hard_smp_processor_id(void) @@ -62,7 +59,10 @@ return cpu_address; } -#define cpu_logical_map(cpu) (cpu) +/* Upping and downing of CPUs */ +extern int __cpu_disable(unsigned int cpu); +extern void __cpu_die(unsigned int cpu); +extern int __cpu_up(unsigned int cpu); void smp_local_timer_interrupt(struct pt_regs * regs); diff -Nur linux-2.5.0/include/linux/kernel_stat.h linux-2.5.0-lhcs/include/linux/kernel_stat.h --- linux-2.5.0/include/linux/kernel_stat.h Thu Nov 22 11:46:19 2001 +++ linux-2.5.0-lhcs/include/linux/kernel_stat.h Wed Dec 12 15:53:20 2001 @@ -45,8 +45,8 @@ { int i, sum=0; - for (i = 0 ; i < smp_num_cpus ; i++) - sum += kstat.irqs[cpu_logical_map(i)][irq]; + for (i = 0 ; i < NR_IRQS ; i++) + sum += kstat.irqs[i][irq]; return sum; } diff -Nur linux-2.5.0/include/linux/notifier.h linux-2.5.0-lhcs/include/linux/notifier.h --- linux-2.5.0/include/linux/notifier.h Fri Feb 9 14:46:13 2001 +++ linux-2.5.0-lhcs/include/linux/notifier.h Tue Dec 11 18:37:21 2001 @@ -58,5 +58,8 @@ #define SYS_HALT 0x0002 /* Notify of system halt */ #define SYS_POWER_OFF 0x0003 /* Notify of system power off */ +#define CPU_OFFLINE 0x0001 /* CPU (unsigned)v going down */ +#define CPU_ONLINE 0x0002 /* CPU (unsigned)v coming up */ + #endif /* __KERNEL__ */ #endif /* _LINUX_NOTIFIER_H */ diff -Nur linux-2.5.0/include/linux/sched.h linux-2.5.0-lhcs/include/linux/sched.h --- linux-2.5.0/include/linux/sched.h Thu Nov 22 11:46:19 2001 +++ linux-2.5.0-lhcs/include/linux/sched.h Wed Dec 12 15:53:21 2001 @@ -788,6 +788,9 @@ extern int do_execve(char *, char **, char **, struct pt_regs *); extern int do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long); +/* Make sure something has scheduled on every cpu. User context only */ +void synchronize_kernel(void); + extern void FASTCALL(add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); diff -Nur linux-2.5.0/include/linux/smp.h linux-2.5.0-lhcs/include/linux/smp.h --- linux-2.5.0/include/linux/smp.h Thu Nov 22 11:46:19 2001 +++ linux-2.5.0-lhcs/include/linux/smp.h Wed Dec 12 15:53:20 2001 @@ -55,8 +55,6 @@ */ extern int smp_threads_ready; -extern int smp_num_cpus; - extern volatile unsigned long smp_msg_data; extern volatile int smp_src_cpu; extern volatile int smp_msg_id; @@ -77,15 +75,24 @@ * These macros fold the SMP functionality into a single CPU system */ -#define smp_num_cpus 1 #define smp_processor_id() 0 #define hard_smp_processor_id() 0 #define smp_threads_ready 1 #define kernel_lock() -#define cpu_logical_map(cpu) 0 -#define cpu_number_map(cpu) 0 #define smp_call_function(func,info,retry,wait) ({ 0; }) -#define cpu_online_map 1 +#define cpu_online(cpu) 1 +#define num_online_cpus() 1 #endif + +struct notifier_block; + +/* Need to know about CPUs going up/down? */ +extern int register_cpu_notifier(struct notifier_block *nb); +extern int unregister_cpu_notifier(struct notifier_block *nb); + +/* Bring a CPU down/up */ +int cpu_down(unsigned int cpu); +int cpu_up(unsigned int cpu); + #endif diff -Nur linux-2.5.0/init/main.c linux-2.5.0-lhcs/init/main.c --- linux-2.5.0/init/main.c Fri Nov 9 14:15:00 2001 +++ linux-2.5.0-lhcs/init/main.c Tue Dec 11 18:37:46 2001 @@ -333,7 +333,7 @@ better than 1% */ #define LPS_PREC 8 -void __init calibrate_delay(void) +void calibrate_delay(void) { unsigned long ticks, loopbit; int lps_precision = LPS_PREC; diff -Nur linux-2.5.0/kernel/Makefile linux-2.5.0-lhcs/kernel/Makefile --- linux-2.5.0/kernel/Makefile Sun Sep 16 21:22:40 2001 +++ linux-2.5.0-lhcs/kernel/Makefile Tue Dec 11 18:37:46 2001 @@ -19,6 +19,7 @@ obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_PROC_FS) += cpu.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff -Nur linux-2.5.0/kernel/cpu.c linux-2.5.0-lhcs/kernel/cpu.c --- linux-2.5.0/kernel/cpu.c Wed Dec 31 16:00:00 1969 +++ linux-2.5.0-lhcs/kernel/cpu.c Tue Dec 11 18:37:46 2001 @@ -0,0 +1,284 @@ +/* CPU control. + * (C) 2001 Rusty Russell + * This code is licenced under the GPL. + */ +#include +#include +#include +#include +#include +#include +#include /* for hotplug_path */ +#include +#include + +#ifdef CONFIG_SMP +/* This protects CPUs going up and down... */ +DECLARE_MUTEX(cpucontrol); + +static struct notifier_block *cpu_chain = NULL; + +#ifdef CONFIG_HOTPLUG +/* Notify userspace when a cpu event occurs, + * by running '/sbin/hotplug cpu' with certain + * environment variables set. + */ +static int cpu_run_sbin_hotplug(unsigned int cpu, const char *action) +{ + char *argv[3], *envp[5], cpu_str[12], action_str[32]; + int i; + + sprintf(cpu_str, "CPU=%d", cpu); + sprintf(action_str, "ACTION=%s", action); + + i = 0; + argv[i++] = hotplug_path; + argv[i++] = "cpu"; + argv[i] = NULL; + + i = 0; + /* minimal command environment */ + envp [i++] = "HOME=/"; + envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + envp [i++] = cpu_str; + envp [i++] = action_str; + envp [i] = NULL; + + return call_usermodehelper(argv [0], argv, envp); +} +#else +#define cpu_run_sbin_hotplug(cpu, action) 0 +#endif + +/* Should really be in a header somewhere. */ +asmlinkage long sys_sched_get_priority_max(int policy); + +/* We could keep a schedule count for each CPU and make idle tasks + schedule (some don't unless need_resched), but this scales quite + well (eg. 64 processors, average time to wait for first schedule = + jiffie/64. Total time for all processors = jiffie/63 + jiffie/62... + + At 1024 cpus, this is about 7.5 jiffies. And that assumes noone + schedules early. --RR */ +static void __synchronize_kernel(void) +{ + unsigned long cpus_allowed, policy, rt_priority; + unsigned int i; + + cpus_allowed = current->cpus_allowed; + policy = current->policy; + rt_priority = current->rt_priority; + + /* Create an unreal time task. */ + current->policy = SCHED_FIFO; + current->rt_priority = 1001 + sys_sched_get_priority_max(SCHED_FIFO); + + /* Make us schedulable on all other online CPUs */ + current->cpus_allowed = 0; + for (i = 0; i < NR_CPUS; i++) + if (cpu_online(i) && i != smp_processor_id()) + current->cpus_allowed |= (1 << i); + + while (current->cpus_allowed) { + /* Change CPUs */ + schedule(); + /* Eliminate this one */ + current->cpus_allowed &= ~(1 << smp_processor_id()); + } + + /* Back to normal. */ + current->cpus_allowed = cpus_allowed; + current->policy = policy; + current->rt_priority = rt_priority; +} + +void synchronize_kernel(void) +{ + /* Let's not worry about CPUs bouncing during this. */ + down(&cpucontrol); + __synchronize_kernel(); + up(&cpucontrol); +} + +/* Need to know about CPUs going up/down? */ +int register_cpu_notifier(struct notifier_block *nb) +{ + return notifier_chain_register(&cpu_chain, nb); +} + +int unregister_cpu_notifier(struct notifier_block *nb) +{ + return notifier_chain_unregister(&cpu_chain,nb); +} + +int cpu_down(unsigned int cpu) +{ + int ret; + + if ((ret = down_interruptible(&cpucontrol)) != 0) + return ret; + + if (!cpu_online(cpu)) { + ret = -EINVAL; + goto out; + } + + if (num_online_cpus() == 1) { + ret = -EBUSY; + goto out; + } + + /* Schedule ourselves on dying CPU. */ + current->cpus_allowed = (1<cpus_allowed = -1; + + /* Take out of mask, reprogram APICs and other arch_specifics. */ + ret = __cpu_disable(cpu); + if (ret != 0) goto out; + + if (cpu_online(cpu)) + BUG(); + + /* Wait for changes to propogate everywhere (also moves us to + another CPU). */ + __synchronize_kernel(); + + /* Now call notifiers */ + notifier_call_chain(&cpu_chain, CPU_OFFLINE, (void *)cpu); + + /* Die, CPU, die! */ + __cpu_die(cpu); + +/* cpu_run_sbin_hotplug(cpu, "remove"); */ + + out: + up(&cpucontrol); + return ret; +} + +int cpu_up(unsigned int cpu) +{ + int ret; + + if ((ret = down_interruptible(&cpucontrol)) != 0) + return ret; + + if (cpu_online(cpu)) { + ret = -EINVAL; + goto out; + } + + /* Arch-specific enabling code. */ + ret = __cpu_up(cpu); + if (ret != 0) goto out; + + /* Now call notifier in preparation. */ + notifier_call_chain(&cpu_chain, CPU_ONLINE, (void *)cpu); + + /* Friendly to make sure everyone knows it's up before we + return */ + __synchronize_kernel(); + +/* cpu_run_sbin_hotplug(cpu, "add"); */ + + out: + up(&cpucontrol); + return ret; +} + +#else /* CONFIG_SMP */ +/* There's a small part of me saying... c'mon, let them down the CPU + on UP... */ +int cpu_down(unsigned int cpu) +{ + return -EBUSY; +} + +int cpu_up(unsigned int cpu) +{ + return -EBUSY; +} + +void synchronize_kernel(void) { } + +int register_cpu_notifier(struct notifier_block *nb) { } + +int unregister_cpu_notifier(struct notifier_block *nb) { } +#endif /*CONFIG_SMP*/ + +/* There may be worse design braindamage than sysctl inside the + kernel, but if there is I haven't found it yet. I'm speechless. + Whoever "designed" this interface must have pictures of Linus + molesting children or something, to get this into the mainstream + kernel. + + I give up, and am using proc directly, which is a little + better. --RR */ +int read_online(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + unsigned int cpu = (unsigned int)data; + char *p = page; + int len; + + p += sprintf(p, "%u\n", cpu_online(cpu) ? 1 : 0); + len = (p - page) - off; + if (len < 0) + len = 0; + + *eof = (len <= count) ? 1 : 0; + *start = page + off; + + return len; +} + +int write_online(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned int cpu = (unsigned int)data; + char input; + int ret = -EINVAL; + + strncpy_from_user(&input, buffer, 1); + + if (input == '0' && (ret = cpu_down(cpu)) == 0) + ret = count; + if (input == '1' && (ret = cpu_up(cpu)) == 0) + ret = count; + + return ret; +} + +static void __init create_entries(struct proc_dir_entry *parent, + unsigned int cpu) +{ + struct proc_dir_entry *e; + + e = create_proc_entry("online", 0644, parent); + e->data = (void *)cpu; + e->read_proc = &read_online; + e->write_proc = &write_online; +} + +static int __init create_per_cpu_entries(void) +{ + unsigned int i; + struct proc_dir_entry *cpudir, *dir; + + cpudir = proc_mkdir("sys/kernel/cpu", NULL); + for (i = 0; i < NR_CPUS; i++) { + char cpuname[20]; + + sprintf(cpuname, "%i", i); + dir = proc_mkdir(cpuname, cpudir); + + create_entries(dir, i); + } + return 0; +} + +__initcall(create_per_cpu_entries); diff -Nur linux-2.5.0/kernel/fork.c linux-2.5.0-lhcs/kernel/fork.c --- linux-2.5.0/kernel/fork.c Wed Nov 21 10:18:42 2001 +++ linux-2.5.0-lhcs/kernel/fork.c Tue Dec 11 18:37:46 2001 @@ -641,7 +641,7 @@ p->cpus_runnable = ~0UL; p->processor = current->processor; /* ?? should we just memset this ?? */ - for(i = 0; i < smp_num_cpus; i++) + for(i = 0; i < NR_CPUS; i++) p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; spin_lock_init(&p->sigmask_lock); } diff -Nur linux-2.5.0/kernel/sched.c linux-2.5.0-lhcs/kernel/sched.c --- linux-2.5.0/kernel/sched.c Wed Nov 21 16:25:48 2001 +++ linux-2.5.0-lhcs/kernel/sched.c Tue Dec 11 18:37:46 2001 @@ -76,7 +76,7 @@ * via the SMP irq return path. */ -struct task_struct * init_tasks[NR_CPUS] = {&init_task, }; +struct task_struct * init_tasks[NR_CPUS] = {[ 0 ... NR_CPUS-1 ] = &init_task }; /* * The tasklist_lock protects the linked list of processes. @@ -114,9 +114,10 @@ #ifdef CONFIG_SMP -#define idle_task(cpu) (init_tasks[cpu_number_map(cpu)]) +#define idle_task(cpu) (init_tasks[cpu]) #define can_schedule(p,cpu) \ - ((p)->cpus_runnable & (p)->cpus_allowed & (1 << cpu)) + (((p)->cpus_runnable & (p)->cpus_allowed & (1 << cpu)) && \ + cpu_online(cpu)) #else @@ -214,7 +215,7 @@ #ifdef CONFIG_SMP int this_cpu = smp_processor_id(); struct task_struct *tsk, *target_tsk; - int cpu, best_cpu, i, max_prio; + int cpu, best_cpu, max_prio; cycles_t oldest_idle; /* @@ -251,8 +252,7 @@ target_tsk = NULL; max_prio = 0; - for (i = 0; i < smp_num_cpus; i++) { - cpu = cpu_logical_map(i); + for (cpu = 0; cpu < NR_CPUS; cpu++) { if (!can_schedule(p, cpu)) continue; tsk = cpu_curr(cpu); @@ -1031,9 +1031,8 @@ int i; // Subtract non-idle processes running on other CPUs. - for (i = 0; i < smp_num_cpus; i++) { - int cpu = cpu_logical_map(i); - if (aligned_data[cpu].schedule_data.curr != idle_task(cpu)) + for (i = 0; i < NR_CPUS; i++) { + if (aligned_data[i].schedule_data.curr != idle_task(i)) nr_pending--; } #else @@ -1284,7 +1283,7 @@ extern unsigned long wait_init_idle; -void __init init_idle(void) +void init_idle(void) { struct schedule_data * sched_data; sched_data = &aligned_data[smp_processor_id()].schedule_data; diff -Nur linux-2.5.0/kernel/softirq.c linux-2.5.0-lhcs/kernel/softirq.c --- linux-2.5.0/kernel/softirq.c Wed Oct 31 10:26:02 2001 +++ linux-2.5.0-lhcs/kernel/softirq.c Tue Dec 11 18:57:34 2001 @@ -16,6 +16,12 @@ #include #include #include +#include +#include +#include + +asmlinkage long sys_sched_get_priority_max(int policy); +extern struct task_struct *child_reaper; /* - No shared variables, all the data are CPU local. @@ -361,22 +367,25 @@ static int ksoftirqd(void * __bind_cpu) { - int bind_cpu = (int) (long) __bind_cpu; - int cpu = cpu_logical_map(bind_cpu); + int cpu = (int) (long) __bind_cpu; + struct task_struct *this_process = current; + + if (ksoftirqd_task(cpu)) + return -EBUSY; daemonize(); + reparent_to_init(); current->nice = 19; - sigfillset(¤t->blocked); + sigfillset(&this_process->blocked); + + sprintf(current->comm, "ksoftirqd_CPU%d", cpu); /* Migrate to the right CPU */ current->cpus_allowed = 1UL << cpu; while (smp_processor_id() != cpu) schedule(); - sprintf(current->comm, "ksoftirqd_CPU%d", bind_cpu); - - __set_current_state(TASK_INTERRUPTIBLE); - mb(); + set_current_state(TASK_INTERRUPTIBLE); ksoftirqd_task(cpu) = current; @@ -384,28 +393,36 @@ if (!softirq_pending(cpu)) schedule(); - __set_current_state(TASK_RUNNING); + set_current_state(TASK_RUNNING); + + if (!cpu_online(cpu)) break; while (softirq_pending(cpu)) { do_softirq(); if (current->need_resched) schedule(); } + if (!cpu_online(cpu)) break; - __set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_INTERRUPTIBLE); } + ksoftirqd_task(cpu) = NULL; + + return 0; } static __init int spawn_ksoftirqd(void) { int cpu; - for (cpu = 0; cpu < smp_num_cpus; cpu++) { + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (!cpu_online(cpu)) continue; + if (kernel_thread(ksoftirqd, (void *) (long) cpu, CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) printk("spawn_ksoftirqd() failed for cpu %d\n", cpu); else { - while (!ksoftirqd_task(cpu_logical_map(cpu))) { + while (!ksoftirqd_task(cpu)) { current->policy |= SCHED_YIELD; schedule(); } @@ -416,3 +433,88 @@ } __initcall(spawn_ksoftirqd); + +static int softirq_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) +{ + int hotcpu = (unsigned long) hcpu; + int ret = NOTIFY_OK; + + if (action == CPU_ONLINE) + { + if (kernel_thread(ksoftirqd, (void *) (long) hotcpu, + CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) + ret = NOTIFY_BAD; + else { + while (!ksoftirqd_task(hotcpu)) { + current->policy |= SCHED_YIELD; + schedule(); + } + } + goto out; + } + + if (action == CPU_OFFLINE) + { + __u32 pending; + unsigned long flags; + unsigned int cpu = smp_processor_id(); + struct tasklet_struct *list, *t; + struct task_struct * kd_tsk; + int i; + + local_irq_save(flags); + + pending = softirq_pending(hotcpu); + softirq_pending(hotcpu) = 0; + + /* move pending softirqs */ + + for (i=0; i<32; i++) + if (pending & (1<next != NULL) + list = list->next; + list->next = tasklet_vec[cpu].list; + tasklet_vec[cpu].list = t; + tasklet_vec[hotcpu].list = NULL; + } + + list = tasklet_hi_vec[hotcpu].list; + if (list != NULL) { + t = list; + while (list->next != NULL) + list = list->next; + list->next = tasklet_hi_vec[cpu].list; + tasklet_hi_vec[cpu].list = t; + tasklet_hi_vec[hotcpu].list = NULL; + } + local_irq_restore(flags); + + kd_tsk = ksoftirqd_task(hotcpu); + if (kd_tsk) { + write_lock_irq(&tasklist_lock); + kd_tsk->cpus_allowed = 1UL << cpu; + write_unlock_irq(&tasklist_lock); + wakeup_softirqd(hotcpu); + while(ksoftirqd_task(hotcpu)){ + current->policy |= SCHED_YIELD; + schedule(); + } + } + } + out: + return ret; +} + +static struct notifier_block cpu_callback_nfb = {&softirq_cpu_callback, NULL, 0}; + +static int __init softirq_cpu_callback_init(void) +{ + register_cpu_notifier(&cpu_callback_nfb); + return 0; +} + +__initcall(softirq_cpu_callback_init); diff -Nur linux-2.5.0/lib/brlock.c linux-2.5.0-lhcs/lib/brlock.c --- linux-2.5.0/lib/brlock.c Fri Nov 9 14:11:15 2001 +++ linux-2.5.0-lhcs/lib/brlock.c Tue Dec 11 18:37:46 2001 @@ -24,16 +24,16 @@ { int i; - for (i = 0; i < smp_num_cpus; i++) - write_lock(&__brlock_array[cpu_logical_map(i)][idx]); + for (i = 0; i < NR_CPUS; i++) + write_lock(&__brlock_array[i][idx]); } void __br_write_unlock (enum brlock_indices idx) { int i; - for (i = 0; i < smp_num_cpus; i++) - write_unlock(&__brlock_array[cpu_logical_map(i)][idx]); + for (i = 0; i < NR_CPUS; i++) + write_unlock(&__brlock_array[i][idx]); } #else /* ! __BRLOCK_USE_ATOMICS */ @@ -50,8 +50,8 @@ again: spin_lock(&__br_write_locks[idx].lock); - for (i = 0; i < smp_num_cpus; i++) - if (__brlock_array[cpu_logical_map(i)][idx] != 0) { + for (i = 0; i < NR_CPUS; i++) + if (__brlock_array[i][idx] != 0) { spin_unlock(&__br_write_locks[idx].lock); barrier(); cpu_relax(); diff -Nur linux-2.5.0/mm/slab.c linux-2.5.0-lhcs/mm/slab.c --- linux-2.5.0/mm/slab.c Tue Sep 18 14:16:26 2001 +++ linux-2.5.0-lhcs/mm/slab.c Tue Dec 11 18:37:46 2001 @@ -892,8 +892,8 @@ down(&cache_chain_sem); smp_call_function_all_cpus(do_ccupdate_local, (void *)&new); - for (i = 0; i < smp_num_cpus; i++) { - cpucache_t* ccold = new.new[cpu_logical_map(i)]; + for (i = 0; i < NR_CPUS; i++) { + cpucache_t* ccold = new.new[i]; if (!ccold || (ccold->avail == 0)) continue; local_irq_disable(); @@ -1625,16 +1625,18 @@ memset(&new.new,0,sizeof(new.new)); if (limit) { - for (i = 0; i< smp_num_cpus; i++) { + for (i = 0; i < NR_CPUS; i++) { cpucache_t* ccnew; ccnew = kmalloc(sizeof(void*)*limit+ sizeof(cpucache_t), GFP_KERNEL); - if (!ccnew) - goto oom; + if (!ccnew) { + for (i--; i >= 0; i--) kfree(new.new[i]); + return -ENOMEM; + } ccnew->limit = limit; ccnew->avail = 0; - new.new[cpu_logical_map(i)] = ccnew; + new.new[i] = ccnew; } } new.cachep = cachep; @@ -1644,8 +1646,8 @@ smp_call_function_all_cpus(do_ccupdate_local, (void *)&new); - for (i = 0; i < smp_num_cpus; i++) { - cpucache_t* ccold = new.new[cpu_logical_map(i)]; + for (i = 0; i < NR_CPUS; i++) { + cpucache_t* ccold = new.new[i]; if (!ccold) continue; local_irq_disable(); @@ -1654,10 +1656,6 @@ kfree(ccold); } return 0; -oom: - for (i--; i >= 0; i--) - kfree(new.new[cpu_logical_map(i)]); - return -ENOMEM; } static void enable_cpucache (kmem_cache_t *cachep) diff -Nur linux-2.5.0/net/core/dev.c linux-2.5.0-lhcs/net/core/dev.c --- linux-2.5.0/net/core/dev.c Wed Nov 7 14:39:36 2001 +++ linux-2.5.0-lhcs/net/core/dev.c Tue Dec 11 18:37:46 2001 @@ -100,6 +100,7 @@ #include #include #include +#include #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) #include /* Note : will define WIRELESS_EXT */ #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ @@ -1758,11 +1759,11 @@ static int dev_proc_stats(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { - int i, lcpu; + int i; int len=0; - for (lcpu=0; lcpunext != NULL) + list_sk = list_sk->next; + list_sk->next = softnet_data[cpu].completion_queue; + softnet_data[cpu].completion_queue = sk_head; + softnet_data[oldcpu].completion_queue = NULL; + } + + /* Move output_queue */ + + list_net = softnet_data[oldcpu].output_queue; + if (list_net != NULL) { + net_head = list_net; + while (list_net->next != NULL) + list_net = list_net->next_sched; + list_net->next_sched = softnet_data[cpu].output_queue; + softnet_data[cpu].output_queue = net_head; + softnet_data[oldcpu].output_queue = NULL; + } + + local_irq_restore(flags); + + /* Move input_pkt_queue */ + + queue = &softnet_data[oldcpu]; + for (;;) { + skb = __skb_dequeue(&queue->input_pkt_queue); + if (skb == NULL) + break; + netif_rx(skb); + } + + return 0; +} + +static struct notifier_block cpu_callback_nfb = {&dev_cpu_callback, NULL, 0 }; + +static int __init dev_cpu_callback_init(void) +{ + register_cpu_notifier(&cpu_callback_nfb); + return 0; +} + +__initcall(dev_cpu_callback_init); diff -Nur linux-2.5.0/net/ipv4/netfilter/ip_tables.c linux-2.5.0-lhcs/net/ipv4/netfilter/ip_tables.c --- linux-2.5.0/net/ipv4/netfilter/ip_tables.c Tue Oct 30 15:08:12 2001 +++ linux-2.5.0-lhcs/net/ipv4/netfilter/ip_tables.c Tue Dec 11 18:37:46 2001 @@ -281,8 +281,7 @@ read_lock_bh(&table->lock); IP_NF_ASSERT(table->valid_hooks & (1 << hook)); table_base = (void *)table->private->entries - + TABLE_OFFSET(table->private, - cpu_number_map(smp_processor_id())); + + TABLE_OFFSET(table->private, smp_processor_id()); e = get_entry(table_base, table->private->hook_entry[hook]); #ifdef CONFIG_NETFILTER_DEBUG @@ -858,7 +857,7 @@ } /* And one copy for every other CPU */ - for (i = 1; i < smp_num_cpus; i++) { + for (i = 1; i < NR_CPUS; i++) { memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i, newinfo->entries, SMP_ALIGN(newinfo->size)); @@ -880,7 +879,7 @@ struct ipt_entry *table_base; unsigned int i; - for (i = 0; i < smp_num_cpus; i++) { + for (i = 0; i < NR_CPUS; i++) { table_base = (void *)newinfo->entries + TABLE_OFFSET(newinfo, i); @@ -926,7 +925,7 @@ unsigned int cpu; unsigned int i; - for (cpu = 0; cpu < smp_num_cpus; cpu++) { + for (cpu = 0; cpu < NR_CPUS; cpu++) { i = 0; IPT_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu), t->size, @@ -1064,7 +1063,7 @@ return -ENOMEM; newinfo = vmalloc(sizeof(struct ipt_table_info) - + SMP_ALIGN(tmp.size) * smp_num_cpus); + + SMP_ALIGN(tmp.size) * NR_CPUS); if (!newinfo) return -ENOMEM; @@ -1367,7 +1366,7 @@ MOD_INC_USE_COUNT; newinfo = vmalloc(sizeof(struct ipt_table_info) - + SMP_ALIGN(table->table->size) * smp_num_cpus); + + SMP_ALIGN(table->table->size) * NR_CPUS); if (!newinfo) { ret = -ENOMEM; MOD_DEC_USE_COUNT; diff -Nur linux-2.5.0/net/ipv4/netfilter/ipchains_core.c linux-2.5.0-lhcs/net/ipv4/netfilter/ipchains_core.c --- linux-2.5.0/net/ipv4/netfilter/ipchains_core.c Sun Sep 30 12:26:08 2001 +++ linux-2.5.0-lhcs/net/ipv4/netfilter/ipchains_core.c Tue Dec 11 18:37:46 2001 @@ -151,11 +151,11 @@ #endif #ifdef CONFIG_SMP -#define SLOT_NUMBER() (cpu_number_map(smp_processor_id())*2 + !in_interrupt()) +#define SLOT_NUMBER() (smp_processor_id()*2 + !in_interrupt()) #else /* !SMP */ #define SLOT_NUMBER() (!in_interrupt()) #endif /* CONFIG_SMP */ -#define NUM_SLOTS (smp_num_cpus*2) +#define NUM_SLOTS (NR_CPUS*2) #define SIZEOF_STRUCT_IP_CHAIN (sizeof(struct ip_chain) \ + NUM_SLOTS*sizeof(struct ip_reent)) @@ -1109,7 +1109,7 @@ label->chain = NULL; label->refcount = ref; label->policy = policy; - for (i = 0; i < smp_num_cpus*2; i++) { + for (i = 0; i < NUM_SLOTS; i++) { label->reent[i].counters.pcnt = label->reent[i].counters.bcnt = 0; label->reent[i].prevchain = NULL; diff -Nur linux-2.5.0/net/ipv4/proc.c linux-2.5.0-lhcs/net/ipv4/proc.c --- linux-2.5.0/net/ipv4/proc.c Wed May 16 10:21:45 2001 +++ linux-2.5.0-lhcs/net/ipv4/proc.c Tue Dec 11 18:37:46 2001 @@ -55,8 +55,8 @@ int res = 0; int cpu; - for (cpu=0; cpustats[cpu_logical_map(cpu)].inuse; + for (cpu=0; cpustats[cpu].inuse; return res; } @@ -103,9 +103,9 @@ sz /= sizeof(unsigned long); - for (i=0; i 1 || cpu_logical_map(0) != 0) { + /* Alexey, be ashamed: speed gained, horror unleashed. --RR */ + if (num_online_cpus() > 1 || !cpu_online(0)) { int i; int cnt = length / 4; - for (i = 0; i < smp_num_cpus; i++) { - int cpu = cpu_logical_map(i); + for (i = 1; i < NR_CPUS; i++) { int k; - if (cpu == 0) - continue; - src = (u32*)(((u8*)ip_rt_acct) + offset + - cpu * 256 * sizeof(struct ip_rt_acct)); + i * 256 * sizeof(struct ip_rt_acct)); for (k = 0; k < cnt; k++) dst[k] += src[k]; diff -Nur linux-2.5.0/net/ipv6/netfilter/ip6_tables.c linux-2.5.0-lhcs/net/ipv6/netfilter/ip6_tables.c --- linux-2.5.0/net/ipv6/netfilter/ip6_tables.c Tue Oct 30 15:08:12 2001 +++ linux-2.5.0-lhcs/net/ipv6/netfilter/ip6_tables.c Tue Dec 11 18:37:46 2001 @@ -905,7 +905,7 @@ } /* And one copy for every other CPU */ - for (i = 1; i < smp_num_cpus; i++) { + for (i = 1; i < NR_CPUS; i++) { memcpy(newinfo->entries + SMP_ALIGN(newinfo->size*i), newinfo->entries, SMP_ALIGN(newinfo->size)); @@ -927,7 +927,7 @@ struct ip6t_entry *table_base; unsigned int i; - for (i = 0; i < smp_num_cpus; i++) { + for (i = 0; i < NR_CPUS; i++) { table_base = (void *)newinfo->entries + TABLE_OFFSET(newinfo, i); @@ -973,7 +973,7 @@ unsigned int cpu; unsigned int i; - for (cpu = 0; cpu < smp_num_cpus; cpu++) { + for (cpu = 0; cpu < NR_CPUS; cpu++) { i = 0; IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu), t->size, @@ -1107,7 +1107,7 @@ return -ENOMEM; newinfo = vmalloc(sizeof(struct ip6t_table_info) - + SMP_ALIGN(tmp.size) * smp_num_cpus); + + SMP_ALIGN(tmp.size) * NR_CPUS); if (!newinfo) return -ENOMEM; @@ -1410,7 +1410,7 @@ MOD_INC_USE_COUNT; newinfo = vmalloc(sizeof(struct ip6t_table_info) - + SMP_ALIGN(table->table->size) * smp_num_cpus); + + SMP_ALIGN(table->table->size) * NR_CPUS); if (!newinfo) { ret = -ENOMEM; MOD_DEC_USE_COUNT; diff -Nur linux-2.5.0/net/ipv6/proc.c linux-2.5.0-lhcs/net/ipv6/proc.c --- linux-2.5.0/net/ipv6/proc.c Sun Jul 9 22:30:41 2000 +++ linux-2.5.0-lhcs/net/ipv6/proc.c Tue Dec 11 18:37:46 2001 @@ -31,8 +31,8 @@ int res = 0; int cpu; - for (cpu=0; cpustats[cpu_logical_map(cpu)].inuse; + for (cpu=0; cpustats[cpu].inuse; return res; } @@ -140,9 +140,9 @@ unsigned long res = 0; int i; - for (i=0; i