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

📄 smp.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/* smp.c: Sparc64 SMP support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/pagemap.h>#include <linux/threads.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/interrupt.h>#include <linux/kernel_stat.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/fs.h>#include <linux/seq_file.h>#include <linux/cache.h>#include <linux/timer.h>#include <asm/head.h>#include <asm/ptrace.h>#include <asm/atomic.h>#include <asm/irq.h>#include <asm/page.h>#include <asm/pgtable.h>#include <asm/oplib.h>#include <asm/hardirq.h>#include <asm/softirq.h>#include <asm/uaccess.h>#include <asm/timer.h>#include <asm/starfire.h>#define __KERNEL_SYSCALLS__#include <linux/unistd.h>extern int linux_num_cpus;extern void calibrate_delay(void);extern unsigned prom_cpu_nodes[];cpuinfo_sparc cpu_data[NR_CPUS];volatile int __cpu_number_map[NR_CPUS]  __attribute__ ((aligned (SMP_CACHE_BYTES)));volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (SMP_CACHE_BYTES)));/* Please don't make this stuff initdata!!!  --DaveM */static unsigned char boot_cpu_id;static int smp_activated;/* Kernel spinlock */spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;volatile int smp_processors_ready = 0;unsigned long cpu_present_map = 0;int smp_num_cpus = 1;int smp_threads_ready = 0;void __init smp_setup(char *str, int *ints){	/* XXX implement me XXX */}static int max_cpus = NR_CPUS;static int __init maxcpus(char *str){	get_option(&str, &max_cpus);	return 1;}__setup("maxcpus=", maxcpus);void smp_info(struct seq_file *m){	int i;		seq_printf(m, "State:\n");	for (i = 0; i < NR_CPUS; i++) {		if (cpu_present_map & (1UL << i))			seq_printf(m,				   "CPU%d:\t\tonline\n", i);	}}void smp_bogo(struct seq_file *m){	int i;		for (i = 0; i < NR_CPUS; i++)		if (cpu_present_map & (1UL << i))			seq_printf(m,				   "Cpu%dBogo\t: %lu.%02lu\n"				   "Cpu%dClkTck\t: %016lx\n",				   i, cpu_data[i].udelay_val / (500000/HZ),				   (cpu_data[i].udelay_val / (5000/HZ)) % 100,				   i, cpu_data[i].clock_tick);}void __init smp_store_cpu_info(int id){	int i, no;	/* multiplier and counter set by	   smp_setup_percpu_timer()  */	cpu_data[id].udelay_val			= loops_per_jiffy;	for (no = 0; no < linux_num_cpus; no++)		if (linux_cpus[no].mid == id)			break;	cpu_data[id].clock_tick = prom_getintdefault(linux_cpus[no].prom_node,						     "clock-frequency", 0);	cpu_data[id].pgcache_size		= 0;	cpu_data[id].pte_cache[0]		= NULL;	cpu_data[id].pte_cache[1]		= NULL;	cpu_data[id].pgdcache_size		= 0;	cpu_data[id].pgd_cache			= NULL;	cpu_data[id].idle_volume		= 1;	for (i = 0; i < 16; i++)		cpu_data[id].irq_worklists[i] = 0;}void __init smp_commence(void){}static void smp_setup_percpu_timer(void);static volatile unsigned long callin_flag = 0;extern void inherit_locked_prom_mappings(int save_p);extern void cpu_probe(void);void __init smp_callin(void){	int cpuid = hard_smp_processor_id();	extern int bigkernel;	extern unsigned long kern_locked_tte_data;	if (bigkernel) {		prom_dtlb_load(sparc64_highest_locked_tlbent()-1, 			kern_locked_tte_data + 0x400000, KERNBASE + 0x400000);		prom_itlb_load(sparc64_highest_locked_tlbent()-1, 			kern_locked_tte_data + 0x400000, KERNBASE + 0x400000);	}	inherit_locked_prom_mappings(0);	__flush_cache_all();	__flush_tlb_all();	cpu_probe();	smp_setup_percpu_timer();	__sti();	calibrate_delay();	smp_store_cpu_info(cpuid);	callin_flag = 1;	__asm__ __volatile__("membar #Sync\n\t"			     "flush  %%g6" : : : "memory");	/* Clear this or we will die instantly when we	 * schedule back to this idler...	 */	current->thread.flags &= ~(SPARC_FLAG_NEWCHILD);	/* Attach to the address space of init_task. */	atomic_inc(&init_mm.mm_count);	current->active_mm = &init_mm;	while (!smp_threads_ready)		membar("#LoadLoad");}extern int cpu_idle(void);extern void init_IRQ(void);int start_secondary(void *unused){	trap_init();	init_IRQ();	return cpu_idle();}void cpu_panic(void){	printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());	panic("SMP bolixed\n");}static unsigned long current_tick_offset;/* This tick register synchronization scheme is taken entirely from * the ia64 port, see arch/ia64/kernel/smpboot.c for details and credit. * * The only change I've made is to rework it so that the master * initiates the synchonization instead of the slave. -DaveM */#define MASTER	0#define SLAVE	(SMP_CACHE_BYTES/sizeof(unsigned long))#define NUM_ROUNDS	64	/* magic value */#define NUM_ITERS	5	/* likewise */static spinlock_t itc_sync_lock = SPIN_LOCK_UNLOCKED;static unsigned long go[SLAVE + 1];#define DEBUG_TICK_SYNC	0static inline long get_delta (long *rt, long *master){	unsigned long best_t0 = 0, best_t1 = ~0UL, best_tm = 0;	unsigned long tcenter, t0, t1, tm;	unsigned long i;	for (i = 0; i < NUM_ITERS; i++) {		t0 = tick_ops->get_tick();		go[MASTER] = 1;		membar("#StoreLoad");		while (!(tm = go[SLAVE]))			membar("#LoadLoad");		go[SLAVE] = 0;		membar("#StoreStore");		t1 = tick_ops->get_tick();		if (t1 - t0 < best_t1 - best_t0)			best_t0 = t0, best_t1 = t1, best_tm = tm;	}	*rt = best_t1 - best_t0;	*master = best_tm - best_t0;	/* average best_t0 and best_t1 without overflow: */	tcenter = (best_t0/2 + best_t1/2);	if (best_t0 % 2 + best_t1 % 2 == 2)		tcenter++;	return tcenter - best_tm;}void smp_synchronize_tick_client(void){	long i, delta, adj, adjust_latency = 0, done = 0;	unsigned long flags, rt, master_time_stamp, bound;#if DEBUG_TICK_SYNC	struct {		long rt;	/* roundtrip time */		long master;	/* master's timestamp */		long diff;	/* difference between midpoint and master's timestamp */		long lat;	/* estimate of itc adjustment latency */	} t[NUM_ROUNDS];#endif	go[MASTER] = 1;	while (go[MASTER])		membar("#LoadLoad");	local_irq_save(flags);	{		for (i = 0; i < NUM_ROUNDS; i++) {			delta = get_delta(&rt, &master_time_stamp);			if (delta == 0) {				done = 1;	/* let's lock on to this... */				bound = rt;			}			if (!done) {				if (i > 0) {					adjust_latency += -delta;					adj = -delta + adjust_latency/4;				} else					adj = -delta;				tick_ops->add_tick(adj, current_tick_offset);			}#if DEBUG_TICK_SYNC			t[i].rt = rt;			t[i].master = master_time_stamp;			t[i].diff = delta;			t[i].lat = adjust_latency/4;#endif		}	}	local_irq_restore(flags);#if DEBUG_TICK_SYNC	for (i = 0; i < NUM_ROUNDS; i++)		printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n",		       t[i].rt, t[i].master, t[i].diff, t[i].lat);#endif	printk(KERN_INFO "CPU %d: synchronized TICK with master CPU (last diff %ld cycles,"	       "maxerr %lu cycles)\n", smp_processor_id(), delta, rt);}static void smp_start_sync_tick_client(int cpu);static void smp_synchronize_one_tick(int cpu){	unsigned long flags, i;	go[MASTER] = 0;	smp_start_sync_tick_client(cpu);	/* wait for client to be ready */	while (!go[MASTER])		membar("#LoadLoad");	/* now let the client proceed into his loop */	go[MASTER] = 0;	membar("#StoreLoad");	spin_lock_irqsave(&itc_sync_lock, flags);	{		for (i = 0; i < NUM_ROUNDS*NUM_ITERS; i++) {			while (!go[MASTER])				membar("#LoadLoad");			go[MASTER] = 0;			membar("#StoreStore");			go[SLAVE] = tick_ops->get_tick();			membar("#StoreLoad");		}	}	spin_unlock_irqrestore(&itc_sync_lock, flags);}static void smp_synchronize_tick(void){	int cpu = smp_processor_id();	int i;	for (i = 0; i < NR_CPUS; i++) {		if (cpu_present_map & (1UL << i)) {			if (i == cpu)				continue;			smp_synchronize_one_tick(i);		}	}}extern struct prom_cpuinfo linux_cpus[64];extern unsigned long sparc64_cpu_startup;/* The OBP cpu startup callback truncates the 3rd arg cookie to * 32-bits (I think) so to be safe we have it read the pointer * contained here so we work on >4GB machines. -DaveM */static struct task_struct *cpu_new_task = NULL;void __init smp_boot_cpus(void){	int cpucount = 0, i;	printk("Entering UltraSMPenguin Mode...\n");	__sti();	smp_store_cpu_info(boot_cpu_id);	init_idle();	if (linux_num_cpus == 1)		return;	for (i = 0; i < NR_CPUS; i++) {		if (i == boot_cpu_id)			continue;		if ((cpucount + 1) == max_cpus)			goto ignorecpu;		if (cpu_present_map & (1UL << i)) {			unsigned long entry = (unsigned long)(&sparc64_cpu_startup);			unsigned long cookie = (unsigned long)(&cpu_new_task);			struct task_struct *p;			int timeout;			int no;			prom_printf("Starting CPU %d... ", i);			kernel_thread(start_secondary, NULL, CLONE_PID);			cpucount++;			p = init_task.prev_task;			init_tasks[cpucount] = p;			p->processor = i;			p->cpus_runnable = 1UL << i; /* we schedule the first task manually */			del_from_runqueue(p);			unhash_process(p);			callin_flag = 0;			for (no = 0; no < linux_num_cpus; no++)				if (linux_cpus[no].mid == i)					break;			cpu_new_task = p;			prom_startcpu(linux_cpus[no].prom_node,				      entry, cookie);			for (timeout = 0; timeout < 5000000; timeout++) {				if (callin_flag)					break;				udelay(100);			}			if (callin_flag) {				__cpu_number_map[i] = cpucount;				__cpu_logical_map[cpucount] = i;				prom_cpu_nodes[i] = linux_cpus[no].prom_node;				prom_printf("OK\n");			} else {				cpucount--;				printk("Processor %d is stuck.\n", i);				prom_printf("FAILED\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -