⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smpboot.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
		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 void __init do_boot_cpu (int apicid){	struct task_struct *idle;	unsigned long send_status, accept_status, boot_status, maxlvt;	int timeout, num_starts, j, cpu;	unsigned long start_eip;	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;	x86_cpu_to_apicid[cpu] = apicid;	x86_apicid_to_cpu[apicid] = cpu;	idle->has_cpu = 1; /* we schedule the first task manually */	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");	CMOS_WRITE(0xa, 0xf);	local_flush_tlb();	Dprintk("1.\n");	*((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4;	Dprintk("2.\n");	*((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf;	Dprintk("3.\n");	/*	 * Be paranoid about clearing APIC errors.	 */	if (APIC_INTEGRATED(apic_version[apicid])) {		apic_read_around(APIC_SPIV);		apic_write(APIC_ESR, 0);		apic_read(APIC_ESR);	}	/*	 * Status is now clean	 */	send_status = 0;	accept_status = 0;	boot_status = 0;	/*	 * Starting actual IPI sequence...	 */	Dprintk("Asserting INIT.\n");	/*	 * Turn INIT on target chip	 */	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(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(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[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(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);	if (!send_status && !accept_status) {		/*		 * 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_status = 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			inquire_remote_apic(apicid);#endif		}	}	if (send_status || accept_status || boot_status) {		x86_cpu_to_apicid[cpu] = -1;		x86_apicid_to_cpu[apicid] = -1;		cpucount--;	}	/* mark "stuck" area as not stuck */	*((volatile unsigned long *)phys_to_virt(8192)) = 0;}cycles_t cacheflush_time;extern unsigned long cpu_khz;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];void __init smp_boot_cpus(void){	int apicid, cpu;#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 (apicid = 0; apicid < NR_CPUS; apicid++) {		x86_apicid_to_cpu[apicid] = -1;		prof_counter[apicid] = 1;		prof_old_multiplier[apicid] = 1;		prof_multiplier[apicid] = 1;	}	/*	 * 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);	x86_apicid_to_cpu[boot_cpu_id] = 0;	x86_cpu_to_apicid[0] = boot_cpu_id;	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. Using 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;	}	/*	 * Should not be necessary because the MP table should list the boot	 * CPU too, but we do it for the sake of robustness anyway.	 */	if (!test_bit(boot_cpu_id, &phys_cpu_present_map)) {		printk("weird, boot CPU (#%d) not listed by the BIOS.\n",								 boot_cpu_id);		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_id]) &&	    !test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability)) {		printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",			boot_cpu_id);		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_id)		BUG();	/*	 * Now scan the CPU present map and fire up the other CPUs.	 */	Dprintk("CPU present map: %lx\n", phys_cpu_present_map);	for (apicid = 0; apicid < NR_CPUS; apicid++) {		/*		 * Don't even attempt to start the boot CPU!		 */		if (apicid == boot_cpu_id)			continue;		if (!(phys_cpu_present_map & (1 << apicid)))			continue;		if ((max_cpus >= 0) && (max_cpus <= cpucount+1))			continue;		do_boot_cpu(apicid);		/*		 * Make sure we unmap all failed CPUs		 */		if ((x86_apicid_to_cpu[apicid] == -1) &&				(phys_cpu_present_map & (1 << apicid)))			printk("phys 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");#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)		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 + -