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, &regs, 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 + -
显示快捷键?