smpboot.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 1,256 行 · 第 1/3 页
C
1,256 行
if (test_bit(cpuid, &cpu_callout_map)) break; rep_nop(); } if (!time_before(jiffies, timeout)) { printk("BUG: CPU%d started up but did not get a callout!\n", cpuid); BUG(); } /* * the boot CPU has finished the init stage and is spinning * on callin_map until we finish. We are free to set up this * CPU, first the APIC. (this is probably redundant on most * boards) */ Dprintk("CALLIN, before setup_local_APIC().\n"); /* * Because we use NMIs rather than the INIT-STARTUP sequence to * bootstrap the CPUs, the APIC may be in a wierd state. Kick it. */ if (clustered_apic_mode) clear_local_APIC(); setup_local_APIC(); __sti();#ifdef CONFIG_MTRR /* * Must be done before calibration delay is computed */ mtrr_init_secondary_cpu ();#endif /* * Get our bogomips. */ calibrate_delay(); Dprintk("Stack at about %p\n",&cpuid); /* * Save our processor parameters */ smp_store_cpu_info(cpuid); disable_APIC_timer(); /* * Allow the master to continue. */ set_bit(cpuid, &cpu_callin_map); /* * Synchronize the TSC with the BP */ if (cpu_has_tsc) synchronize_tsc_ap();}int cpucount;extern int cpu_idle(void);/* * Activate a secondary processor. */int __init start_secondary(void *unused){ /* * Dont put anything before smp_callin(), SMP * booting is too fragile that we want to limit the * things done here to the most necessary things. */ cpu_init(); smp_callin(); while (!atomic_read(&smp_commenced)) rep_nop(); enable_APIC_timer(); /* * low-memory mappings have been cleared, flush them from * the local TLBs too. */ local_flush_tlb(); return cpu_idle();}/* * Everything has been set up for the secondary * CPUs - they just need to reload everything * from the task structure * This function must not return. */void __init initialize_secondary(void){ /* * 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" : :"r" (current->thread.esp),"r" (current->thread.eip));}extern struct { void * esp; unsigned short ss;} stack_start;static int __init fork_by_hand(void){ struct pt_regs regs; /* * don't care about the eip and regs settings since * we'll never reschedule the forked task. */ return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0);}/* which physical APIC ID maps to which logical CPU number */volatile int physical_apicid_2_cpu[MAX_APICID];/* which logical CPU number maps to which physical APIC ID */volatile int cpu_2_physical_apicid[NR_CPUS];/* which logical APIC ID maps to which logical CPU number */volatile int logical_apicid_2_cpu[MAX_APICID];/* which logical CPU number maps to which logical APIC ID */volatile int cpu_2_logical_apicid[NR_CPUS];static inline void init_cpu_to_apicid(void)/* Initialize all maps between cpu number and apicids */{ int apicid, cpu; for (apicid = 0; apicid < MAX_APICID; apicid++) { physical_apicid_2_cpu[apicid] = -1; logical_apicid_2_cpu[apicid] = -1; } for (cpu = 0; cpu < NR_CPUS; cpu++) { cpu_2_physical_apicid[cpu] = -1; cpu_2_logical_apicid[cpu] = -1; }}static inline void map_cpu_to_boot_apicid(int cpu, int apicid)/* * set up a mapping between cpu and apicid. Uses logical apicids for multiquad, * else physical apic ids */{ if (clustered_apic_mode) { logical_apicid_2_cpu[apicid] = cpu; cpu_2_logical_apicid[cpu] = apicid; } else { physical_apicid_2_cpu[apicid] = cpu; cpu_2_physical_apicid[cpu] = apicid; }}static inline void unmap_cpu_to_boot_apicid(int cpu, int apicid)/* * undo a mapping between cpu and apicid. Uses logical apicids for multiquad, * else physical apic ids */{ if (clustered_apic_mode) { logical_apicid_2_cpu[apicid] = -1; cpu_2_logical_apicid[cpu] = -1; } else { physical_apicid_2_cpu[apicid] = -1; cpu_2_physical_apicid[cpu] = -1; }}#if APIC_DEBUGstatic 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, status; printk("Inquiring remote APIC #%d...\n", apicid); for (i = 0; i < sizeof(regs) / sizeof(*regs); i++) { printk("... APIC #%d %s: ", apicid, names[i]); /* * Wait for idle. */ apic_wait_icr_idle(); 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("%08x\n", status); break; default: printk("failed\n"); } }}#endifstatic int wakeup_secondary_via_NMI(int logical_apicid)/* * Poke the other CPU in the eye 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. */{ 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 = prev_task(&init_task); if (!idle) panic("No idle process for CPU %d", cpu); init_idle(idle, cpu); map_cpu_to_boot_apicid(cpu, apicid);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?