📄 smpboot_32.c
字号:
{ /* * We don't actually need to load the full TSS, * basically just the stack pointer and the eip. */ asm volatile( "movl %0,%%esp\n\t" "jmp *%1" : :"m" (current->thread.esp),"m" (current->thread.eip));}/* Static state in head.S used to set up a CPU */extern struct { void * esp; unsigned short ss;} stack_start;#ifdef CONFIG_NUMA/* which logical CPUs are on which nodes */cpumask_t node_2_cpu_mask[MAX_NUMNODES] __read_mostly = { [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE };EXPORT_SYMBOL(node_2_cpu_mask);/* which node each logical CPU is on */int cpu_2_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 };EXPORT_SYMBOL(cpu_2_node);/* set up a mapping between cpu and node. */static inline void map_cpu_to_node(int cpu, int node){ printk("Mapping cpu %d to node %d\n", cpu, node); cpu_set(cpu, node_2_cpu_mask[node]); cpu_2_node[cpu] = node;}/* undo a mapping between cpu and node. */static inline void unmap_cpu_to_node(int cpu){ int node; printk("Unmapping cpu %d from all nodes\n", cpu); for (node = 0; node < MAX_NUMNODES; node ++) cpu_clear(cpu, node_2_cpu_mask[node]); cpu_2_node[cpu] = 0;}#else /* !CONFIG_NUMA */#define map_cpu_to_node(cpu, node) ({})#define unmap_cpu_to_node(cpu) ({})#endif /* CONFIG_NUMA */u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };static void map_cpu_to_logical_apicid(void){ int cpu = smp_processor_id(); int apicid = logical_smp_processor_id(); int node = apicid_to_node(apicid); if (!node_online(node)) node = first_online_node; cpu_2_logical_apicid[cpu] = apicid; map_cpu_to_node(cpu, node);}static void unmap_cpu_to_logical_apicid(int cpu){ cpu_2_logical_apicid[cpu] = BAD_APICID; unmap_cpu_to_node(cpu);}static inline void __inquire_remote_apic(int apicid){ int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 }; char *names[] = { "ID", "VERSION", "SPIV" }; int timeout; unsigned long status; printk("Inquiring remote APIC #%d...\n", apicid); for (i = 0; i < ARRAY_SIZE(regs); i++) { printk("... APIC #%d %s: ", apicid, names[i]); /* * Wait for idle. */ status = safe_apic_wait_icr_idle(); if (status) printk("a previous APIC delivery may have failed\n"); apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]); timeout = 0; do { udelay(100); status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK; } while (status == APIC_ICR_RR_INPROG && timeout++ < 1000); switch (status) { case APIC_ICR_RR_VALID: status = apic_read(APIC_RRR); printk("%lx\n", status); break; default: printk("failed\n"); } }}#ifdef WAKE_SECONDARY_VIA_NMI/* * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this * won't ... remember to clear down the APIC, etc later. */static int __devinitwakeup_secondary_cpu(int logical_apicid, unsigned long start_eip){ unsigned long send_status, accept_status = 0; int 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"); send_status = safe_apic_wait_icr_idle(); /* * Give the other CPU some time to accept the IPI. */ udelay(200); /* * Due to the Pentium erratum 3AP. */ maxlvt = lapic_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);}#endif /* WAKE_SECONDARY_VIA_NMI */#ifdef WAKE_SECONDARY_VIA_INITstatic int __devinitwakeup_secondary_cpu(int phys_apicid, unsigned long start_eip){ unsigned long send_status, accept_status = 0; int maxlvt, num_starts, j; /* * Be paranoid about clearing APIC errors. */ if (APIC_INTEGRATED(apic_version[phys_apicid])) { apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); } 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"); send_status = safe_apic_wait_icr_idle(); 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"); send_status = safe_apic_wait_icr_idle(); 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; /* * Paravirt / VMI wants a startup IPI hook here to set up the * target processor state. */ startup_ipi_hook(phys_apicid, (unsigned long) start_secondary, (unsigned long) stack_start.esp); /* * Run STARTUP IPI loop. */ Dprintk("#startup loops: %d.\n", num_starts); maxlvt = lapic_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"); send_status = safe_apic_wait_icr_idle(); /* * 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);}#endif /* WAKE_SECONDARY_VIA_INIT */extern cpumask_t cpu_initialized;static inline int alloc_cpu_id(void){ cpumask_t tmp_map; int cpu; cpus_complement(tmp_map, cpu_present_map); cpu = first_cpu(tmp_map); if (cpu >= NR_CPUS) return -ENODEV; return cpu;}#ifdef CONFIG_HOTPLUG_CPUstatic struct task_struct * __cpuinitdata cpu_idle_tasks[NR_CPUS];static inline struct task_struct * __cpuinit alloc_idle_task(int cpu){ struct task_struct *idle; if ((idle = cpu_idle_tasks[cpu]) != NULL) { /* initialize thread_struct. we really want to avoid destroy * idle tread */ idle->thread.esp = (unsigned long)task_pt_regs(idle); init_idle(idle, cpu); return idle; } idle = fork_idle(cpu); if (!IS_ERR(idle)) cpu_idle_tasks[cpu] = idle; return idle;}#else#define alloc_idle_task(cpu) fork_idle(cpu)#endifstatic int __cpuinit 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. * Returns zero if CPU booted OK, else error code from wakeup_secondary_cpu. */{ struct task_struct *idle; unsigned long boot_error; int timeout; unsigned long start_eip; unsigned short nmi_high = 0, nmi_low = 0; /* * Save current MTRR state in case it was changed since early boot * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync: */ mtrr_save_state(); /* * We can't use kernel_thread since we must avoid to * reschedule the child. */ idle = alloc_idle_task(cpu); if (IS_ERR(idle)) panic("failed fork for CPU %d", cpu); init_gdt(cpu); per_cpu(current_task, cpu) = idle; early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); idle->thread.eip = (unsigned long) start_secondary; /* start_eip had better be page-aligned! */ start_eip = setup_trampoline(); ++cpucount; alternatives_smp_switch(1); /* So we see what's up */ printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip); /* Stack for startup_32 can be just as for start_secondary onwards */ stack_start.esp = (void *) idle->thread.esp; irq_ctx_init(cpu); per_cpu(x86_cpu_to_apicid, cpu) = apicid; /* * This grunge runs the startup process for * the targeted processor. */ atomic_set(&init_deasserted, 0); Dprintk("Setting warm reset code and vector.\n"); store_NMI_vector(&nmi_high, &nmi_low); smpboot_setup_warm_reset_vector(start_eip); /* * Starting actual IPI sequence... */ boot_error = wakeup_secondary_cpu(apicid, start_eip); if (!boot_error) { /* * allow APs to start initializing. */ Dprintk("Before Callout %d.\n", cpu); cpu_set(cpu, cpu_callout_map); Dprintk("After Callout %d.\n", cpu); /* * Wait 5s total for a response */ for (timeout = 0; timeout < 50000; timeout++) { if (cpu_isset(cpu, cpu_callin_map)) break; /* It has booted */ udelay(100); } if (cpu_isset(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 *)trampoline_base) == 0xA5) /* trampoline started but...? */ printk("Stuck ??\n"); else /* trampoline code not run */ printk("Not responding.\n"); inquire_remote_apic(apicid); } } if (boot_error) { /* Try to put things back the way they were before ... */ unmap_cpu_to_logical_apicid(cpu); cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */ cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */ cpucount--; } else { per_cpu(x86_cpu_to_apicid, cpu) = apicid; cpu_set(cpu, cpu_present_map); } /* mark "stuck" area as not stuck */ *((volatile unsigned long *)trampoline_base) = 0; return boot_error;}#ifdef CONFIG_HOTPLUG_CPUvoid cpu_exit_clear(void){ int cpu = raw_smp_processor_id(); idle_task_exit();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -