📄 smpboot.c
字号:
unsigned long send_status = 0, accept_status = 0; int timeout, maxlvt; /* Target chip */ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid)); /* Boot on the stack */ /* Kick the second */ apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL); Dprintk("Waiting for send to finish...\n"); timeout = 0; do { Dprintk("+"); udelay(100); send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; } while (send_status && (timeout++ < 1000)); /* * Give the other CPU some time to accept the IPI. */ udelay(200); /* * Due to the Pentium erratum 3AP. */ maxlvt = get_maxlvt(); if (maxlvt > 3) { apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); } accept_status = (apic_read(APIC_ESR) & 0xEF); Dprintk("NMI sent.\n"); if (send_status) printk("APIC never delivered???\n"); if (accept_status) printk("APIC delivery error (%lx).\n", accept_status); return (send_status | accept_status);}static int wakeup_secondary_via_INIT(int phys_apicid, unsigned long start_eip){ unsigned long send_status = 0, accept_status = 0; int maxlvt, timeout, num_starts, j; Dprintk("Asserting INIT.\n"); /* * Turn INIT on target chip */ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); /* * Send IPI */ apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT); Dprintk("Waiting for send to finish...\n"); timeout = 0; do { Dprintk("+"); udelay(100); send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; } while (send_status && (timeout++ < 1000)); mdelay(10); Dprintk("Deasserting INIT.\n"); /* Target chip */ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); /* Send IPI */ apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); Dprintk("Waiting for send to finish...\n"); timeout = 0; do { Dprintk("+"); udelay(100); send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; } while (send_status && (timeout++ < 1000)); atomic_set(&init_deasserted, 1); /* * Should we send STARTUP IPIs ? * * Determine this based on the APIC version. * If we don't have an integrated APIC, don't send the STARTUP IPIs. */ if (APIC_INTEGRATED(apic_version[phys_apicid])) num_starts = 2; else num_starts = 0; /* * Run STARTUP IPI loop. */ Dprintk("#startup loops: %d.\n", num_starts); maxlvt = get_maxlvt(); for (j = 1; j <= num_starts; j++) { Dprintk("Sending STARTUP #%d.\n",j); apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); Dprintk("After apic_write.\n"); /* * STARTUP IPI */ /* Target chip */ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); /* Boot on the stack */ /* Kick the second */ apic_write_around(APIC_ICR, APIC_DM_STARTUP | (start_eip >> 12)); /* * Give the other CPU some time to accept the IPI. */ udelay(300); Dprintk("Startup point 1.\n"); Dprintk("Waiting for send to finish...\n"); timeout = 0; do { Dprintk("+"); udelay(100); send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; } while (send_status && (timeout++ < 1000)); /* * Give the other CPU some time to accept the IPI. */ udelay(200); /* * Due to the Pentium erratum 3AP. */ if (maxlvt > 3) { apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); } accept_status = (apic_read(APIC_ESR) & 0xEF); if (send_status || accept_status) break; } Dprintk("After Startup.\n"); if (send_status) printk("APIC never delivered???\n"); if (accept_status) printk("APIC delivery error (%lx).\n", accept_status); return (send_status | accept_status);}extern unsigned long cpu_initialized;static void __init do_boot_cpu (int apicid) /* * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad * (ie clustered apic addressing mode), this is a LOGICAL apic ID. */{ struct task_struct *idle; unsigned long boot_error = 0; int timeout, cpu; 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. */ if (fork_by_hand() < 0) panic("failed fork for CPU %d", cpu); /* * We remove it from the pidhash and the runqueue * once we got the process: */ idle = init_task.prev_task; if (!idle) panic("No idle process for CPU %d", cpu); idle->processor = cpu; idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */ map_cpu_to_boot_apicid(cpu, apicid); idle->thread.eip = (unsigned long) start_secondary; del_from_runqueue(idle); unhash_process(idle); init_tasks[cpu] = idle; /* start_eip had better be page-aligned! */ start_eip = setup_trampoline(); /* So we see what's up */ printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip); stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle); /* * This grunge runs the startup process for * the targeted processor. */ atomic_set(&init_deasserted, 0); Dprintk("Setting warm reset code and vector.\n"); if (clustered_apic_mode) { /* stash the current NMI vector, so we can put things back */ nmi_high = *((volatile unsigned short *) TRAMPOLINE_HIGH); nmi_low = *((volatile unsigned short *) TRAMPOLINE_LOW); } CMOS_WRITE(0xa, 0xf); local_flush_tlb(); Dprintk("1.\n"); *((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4; Dprintk("2.\n"); *((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf; Dprintk("3.\n"); /* * Be paranoid about clearing APIC errors. */ if (!clustered_apic_mode && APIC_INTEGRATED(apic_version[apicid])) { apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); } /* * Status is now clean */ boot_error = 0; /* * Starting actual IPI sequence... */ if (clustered_apic_mode) boot_error = wakeup_secondary_via_NMI(apicid); else boot_error = wakeup_secondary_via_INIT(apicid, start_eip); if (!boot_error) { /* * allow APs to start initializing. */ Dprintk("Before Callout %d.\n", cpu); set_bit(cpu, &cpu_callout_map); Dprintk("After Callout %d.\n", cpu); /* * Wait 5s total for a response */ for (timeout = 0; timeout < 50000; timeout++) { if (test_bit(cpu, &cpu_callin_map)) break; /* It has booted */ udelay(100); } if (test_bit(cpu, &cpu_callin_map)) { /* number CPUs logically, starting from 1 (BSP is 0) */ Dprintk("OK.\n"); printk("CPU%d: ", cpu); print_cpu_info(&cpu_data[cpu]); Dprintk("CPU has booted.\n"); } else { boot_error= 1; if (*((volatile unsigned char *)phys_to_virt(8192)) == 0xA5) /* trampoline started but...? */ printk("Stuck ??\n"); else /* trampoline code not run */ printk("Not responding.\n");#if APIC_DEBUG if (!clustered_apic_mode) inquire_remote_apic(apicid);#endif } } if (boot_error) { /* Try to put things back the way they were before ... */ unmap_cpu_to_boot_apicid(cpu, apicid); 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--; } /* mark "stuck" area as not stuck */ *((volatile unsigned long *)phys_to_virt(8192)) = 0; if(clustered_apic_mode) { printk("Restoring NMI vector\n"); *((volatile unsigned short *) TRAMPOLINE_HIGH) = nmi_high; *((volatile unsigned short *) TRAMPOLINE_LOW) = nmi_low; }}cycles_t cacheflush_time;static void smp_tune_scheduling (void){ unsigned long cachesize; /* kB */ unsigned long bandwidth = 350; /* MB/s */ /* * Rough estimation for SMP scheduling, this is the number of * cycles it takes for a fully memory-limited process to flush * the SMP-local cache. * * (For a P5 this pretty much means we will choose another idle * CPU almost always at wakeup time (this is due to the small * L1 cache), on PIIs it's around 50-100 usecs, depending on * the cache size) */ if (!cpu_khz) { /* * this basically disables processor-affinity * scheduling on SMP without a TSC. */ cacheflush_time = 0; return; } else { cachesize = boot_cpu_data.x86_cache_size; if (cachesize == -1) { cachesize = 16; /* Pentiums, 2x8kB cache */ bandwidth = 100; } cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth; } printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n", (long)cacheflush_time/(cpu_khz/1000), ((long)cacheflush_time*100/(cpu_khz/1000)) % 100);}/* * Cycle through the processors sending APIC IPIs to boot each. */extern int prof_multiplier[NR_CPUS];extern int prof_old_multiplier[NR_CPUS];extern int prof_counter[NR_CPUS];static int boot_cpu_logical_apicid;/* Where the IO area was mapped on multiquad, always 0 otherwise */void *xquad_portio = NULL;int cpu_sibling_map[NR_CPUS] __cacheline_aligned;void __init smp_boot_cpus(void){ int apicid, cpu, bit; if (clustered_apic_mode) { /* remap the 1st quad's 256k range for cross-quad I/O */ xquad_portio = ioremap (XQUAD_PORTIO_BASE, XQUAD_PORTIO_LEN); printk("Cross quad port I/O vaddr 0x%08lx, len %08lx\n", (u_long) xquad_portio, (u_long) XQUAD_PORTIO_LEN); }#ifdef CONFIG_MTRR /* Must be done before other processors booted */ mtrr_init_boot_cpu ();#endif /* * Initialize the logical to physical CPU number mapping * and the per-CPU profiling counter/multiplier */ for (cpu = 0; cpu < NR_CPUS; cpu++) { prof_counter[cpu] = 1; prof_old_multiplier[cpu] = 1; prof_multiplier[cpu] = 1; } init_cpu_to_apicid(); /* * Setup boot CPU information */ smp_store_cpu_info(0); /* Final full version of the data */ printk("CPU%d: ", 0); print_cpu_info(&cpu_data[0]); /* * We have the boot CPU online for sure. */ set_bit(0, &cpu_online_map); boot_cpu_logical_apicid = logical_smp_processor_id(); map_cpu_to_boot_apicid(0, boot_cpu_apicid); global_irq_holder = 0; current->processor = 0; init_idle(); smp_tune_scheduling(); /* * If we couldnt find an SMP configuration at boot time, * get out of here now! */ if (!smp_found_config) { printk(KERN_NOTICE "SMP motherboard not detected.\n");#ifndef CONFIG_VISWS 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"); goto smp_done; } /* * Should not be necessary because the MP table should list the boot * CPU too, but we do it for the sake of robustness anyway. * Makes no sense to do this check in clustered apic mode, so skip it */ if (!clustered_apic_mode && !test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map)) { printk("weird, boot CPU (#%d) not listed by the BIOS.\n", boot_cpu_physical_apicid); phys_cpu_present_map |= (1 << hard_smp_processor_id()); } /* * If we couldn't find a local APIC, then get out of here now! */ if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) && !test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability)) { printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", boot_cpu_physical_apicid); printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");#ifndef CONFIG_VISWS io_apic_irqs = 0;#endif cpu_online_map = phys_cpu_present_map = 1; smp_num_cpus = 1; goto smp_done; } verify_local_APIC(); /* * If SMP should be disabled, then really disable it! */ if (!max_cpus) { smp_found_config = 0; printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");#ifndef CONFIG_VISWS io_apic_irqs = 0;#endif cpu_online_map = phys_cpu_present_map = 1; smp_num_cpus = 1; goto smp_done; } connect_bsp_APIC(); setup_local_APIC(); if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid) BUG(); /* * Scan the CPU present map and fire up the other CPUs via do_boot_cpu * * In clustered apic mode, phys_cpu_present_map is a constructed thus: * bits 0-3 are quad0, 4-7 are quad1, etc. A perverse twist on the * clustered apic ID. */ Dprintk("CPU present map: %lx\n", phys_cpu_present_map); for (bit = 0; bit < NR_CPUS; bit++) { apicid = cpu_present_to_apicid(bit); /* * Don't even attempt to start the boot CPU! */ if (apicid == boot_cpu_apicid) continue; if (!(phys_cpu_present_map & (1 << bit))) continue; if ((max_cpus >= 0) && (max_cpus <= cpucount+1)) continue; do_boot_cpu(apicid); /* * Make sure we unmap all failed CPUs */ if ((boot_apicid_to_cpu(apicid) == -1) && (phys_cpu_present_map & (1 << bit))) printk("CPU #%d not responding - cannot use it.\n", apicid); } /* * Cleanup possible dangling ends... */#ifndef CONFIG_VISWS { /* * Install writable page 0 entry to set BIOS data area. */ local_flush_tlb(); /* * Paranoid: Set warm reset code and vector here back * to default values. */ CMOS_WRITE(0, 0xf); *((volatile long *) phys_to_virt(0x467)) = 0; }#endif /* * Allow the user to impress friends. */ Dprintk("Before bogomips.\n"); if (!cpucount) { 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<<cpu)) 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); Dprintk("Before bogocount - setting activated=1.\n"); } smp_num_cpus = cpucount + 1; if (smp_b_stepping) printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n"); Dprintk("Boot done.\n"); /* * If Hyper-Threading is avaialble, construct cpu_sibling_map[], so * that we can tell the sibling CPU efficiently. */ if (test_bit(X86_FEATURE_HT, boot_cpu_data.x86_capability) && smp_num_siblings > 1) { for (cpu = 0; cpu < NR_CPUS; cpu++) cpu_sibling_map[cpu] = NO_PROC_ID; for (cpu = 0; cpu < smp_num_cpus; cpu++) { int i; for (i = 0; i < smp_num_cpus; i++) { if (i == cpu) continue; if (phys_proc_id[cpu] == phys_proc_id[i]) { cpu_sibling_map[cpu] = i; printk("cpu_sibling_map[%d] = %d\n", cpu, cpu_sibling_map[cpu]); break; } } if (cpu_sibling_map[cpu] == NO_PROC_ID) { smp_num_siblings = 1; printk(KERN_WARNING "WARNING: No sibling found for CPU %d.\n", cpu); } } } #ifndef CONFIG_VISWS /* * Here we can be sure that there is an IO-APIC in the system. Let's * go and set it up: */ if (!skip_ioapic_setup && nr_ioapics) setup_IO_APIC();#endif /* * Set up all local APIC timers in the system: */ setup_APIC_clocks(); /* * Synchronize the TSC with the AP */ if (cpu_has_tsc && cpucount) synchronize_tsc_bp();smp_done: zap_low_mappings();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -