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

📄 smp.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	local_irq_restore(flags);}static void __devinit smp_core99_take_timebase(void){	unsigned long flags;	local_irq_save(flags);	tb_req = 1;	mb();	while (!timebase)		barrier();	mb();	set_tb(timebase >> 32, timebase & 0xffffffff);	timebase = 0;	mb();	set_dec(tb_ticks_per_jiffy/2);	local_irq_restore(flags);}#ifdef CONFIG_PPC64/* * G5s enable/disable the timebase via an i2c-connected clock chip. */static struct pmac_i2c_bus *pmac_tb_clock_chip_host;static u8 pmac_tb_pulsar_addr;static void smp_core99_cypress_tb_freeze(int freeze){	u8 data;	int rc;	/* Strangely, the device-tree says address is 0xd2, but darwin	 * accesses 0xd0 ...	 */	pmac_i2c_setmode(pmac_tb_clock_chip_host,			 pmac_i2c_mode_combined);	rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,			   0xd0 | pmac_i2c_read,			   1, 0x81, &data, 1);	if (rc != 0)		goto bail;	data = (data & 0xf3) | (freeze ? 0x00 : 0x0c);       	pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);	rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,			   0xd0 | pmac_i2c_write,			   1, 0x81, &data, 1); bail:	if (rc != 0) {		printk("Cypress Timebase %s rc: %d\n",		       freeze ? "freeze" : "unfreeze", rc);		panic("Timebase freeze failed !\n");	}}static void smp_core99_pulsar_tb_freeze(int freeze){	u8 data;	int rc;	pmac_i2c_setmode(pmac_tb_clock_chip_host,			 pmac_i2c_mode_combined);	rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,			   pmac_tb_pulsar_addr | pmac_i2c_read,			   1, 0x2e, &data, 1);	if (rc != 0)		goto bail;	data = (data & 0x88) | (freeze ? 0x11 : 0x22);	pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);	rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,			   pmac_tb_pulsar_addr | pmac_i2c_write,			   1, 0x2e, &data, 1); bail:	if (rc != 0) {		printk(KERN_ERR "Pulsar Timebase %s rc: %d\n",		       freeze ? "freeze" : "unfreeze", rc);		panic("Timebase freeze failed !\n");	}}static void __init smp_core99_setup_i2c_hwsync(int ncpus){	struct device_node *cc = NULL;		struct device_node *p;	const char *name = NULL;	const u32 *reg;	int ok;	/* Look for the clock chip */	while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) {		p = of_get_parent(cc);		ok = p && of_device_is_compatible(p, "uni-n-i2c");		of_node_put(p);		if (!ok)			continue;		pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc);		if (pmac_tb_clock_chip_host == NULL)			continue;		reg = of_get_property(cc, "reg", NULL);		if (reg == NULL)			continue;		switch (*reg) {		case 0xd2:			if (of_device_is_compatible(cc,"pulsar-legacy-slewing")) {				pmac_tb_freeze = smp_core99_pulsar_tb_freeze;				pmac_tb_pulsar_addr = 0xd2;				name = "Pulsar";			} else if (of_device_is_compatible(cc, "cy28508")) {				pmac_tb_freeze = smp_core99_cypress_tb_freeze;				name = "Cypress";			}			break;		case 0xd4:			pmac_tb_freeze = smp_core99_pulsar_tb_freeze;			pmac_tb_pulsar_addr = 0xd4;			name = "Pulsar";			break;		}		if (pmac_tb_freeze != NULL)			break;	}	if (pmac_tb_freeze != NULL) {		/* Open i2c bus for synchronous access */		if (pmac_i2c_open(pmac_tb_clock_chip_host, 1)) {			printk(KERN_ERR "Failed top open i2c bus for clock"			       " sync, fallback to software sync !\n");			goto no_i2c_sync;		}		printk(KERN_INFO "Processor timebase sync using %s i2c clock\n",		       name);		return;	} no_i2c_sync:	pmac_tb_freeze = NULL;	pmac_tb_clock_chip_host = NULL;}/* * Newer G5s uses a platform function */static void smp_core99_pfunc_tb_freeze(int freeze){	struct device_node *cpus;	struct pmf_args args;	cpus = of_find_node_by_path("/cpus");	BUG_ON(cpus == NULL);	args.count = 1;	args.u[0].v = !freeze;	pmf_call_function(cpus, "cpu-timebase", &args);	of_node_put(cpus);}#else /* CONFIG_PPC64 *//* * SMP G4 use a GPIO to enable/disable the timebase. */static unsigned int core99_tb_gpio;	/* Timebase freeze GPIO */static void smp_core99_gpio_tb_freeze(int freeze){	if (freeze)		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);	else		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);	pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);}#endif /* !CONFIG_PPC64 *//* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */volatile static long int core99_l2_cache;volatile static long int core99_l3_cache;static void __devinit core99_init_caches(int cpu){#ifndef CONFIG_PPC64	if (!cpu_has_feature(CPU_FTR_L2CR))		return;	if (cpu == 0) {		core99_l2_cache = _get_L2CR();		printk("CPU0: L2CR is %lx\n", core99_l2_cache);	} else {		printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());		_set_L2CR(0);		_set_L2CR(core99_l2_cache);		printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);	}	if (!cpu_has_feature(CPU_FTR_L3CR))		return;	if (cpu == 0){		core99_l3_cache = _get_L3CR();		printk("CPU0: L3CR is %lx\n", core99_l3_cache);	} else {		printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());		_set_L3CR(0);		_set_L3CR(core99_l3_cache);		printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);	}#endif /* !CONFIG_PPC64 */}static void __init smp_core99_setup(int ncpus){#ifdef CONFIG_PPC64	/* i2c based HW sync on some G5s */	if (machine_is_compatible("PowerMac7,2") ||	    machine_is_compatible("PowerMac7,3") ||	    machine_is_compatible("RackMac3,1"))		smp_core99_setup_i2c_hwsync(ncpus);	/* pfunc based HW sync on recent G5s */	if (pmac_tb_freeze == NULL) {		struct device_node *cpus =			of_find_node_by_path("/cpus");		if (cpus &&		    of_get_property(cpus, "platform-cpu-timebase", NULL)) {			pmac_tb_freeze = smp_core99_pfunc_tb_freeze;			printk(KERN_INFO "Processor timebase sync using"			       " platform function\n");		}	}#else /* CONFIG_PPC64 */	/* GPIO based HW sync on ppc32 Core99 */	if (pmac_tb_freeze == NULL && !machine_is_compatible("MacRISC4")) {		struct device_node *cpu;		const u32 *tbprop = NULL;		core99_tb_gpio = KL_GPIO_TB_ENABLE;	/* default value */		cpu = of_find_node_by_type(NULL, "cpu");		if (cpu != NULL) {			tbprop = of_get_property(cpu, "timebase-enable", NULL);			if (tbprop)				core99_tb_gpio = *tbprop;			of_node_put(cpu);		}		pmac_tb_freeze = smp_core99_gpio_tb_freeze;		printk(KERN_INFO "Processor timebase sync using"		       " GPIO 0x%02x\n", core99_tb_gpio);	}#endif /* CONFIG_PPC64 */	/* No timebase sync, fallback to software */	if (pmac_tb_freeze == NULL) {		smp_ops->give_timebase = smp_generic_give_timebase;		smp_ops->take_timebase = smp_generic_take_timebase;		printk(KERN_INFO "Processor timebase sync using software\n");	}#ifndef CONFIG_PPC64	{		int i;		/* XXX should get this from reg properties */		for (i = 1; i < ncpus; ++i)			smp_hw_index[i] = i;	}#endif	/* 32 bits SMP can't NAP */	if (!machine_is_compatible("MacRISC4"))		powersave_nap = 0;}static int __init smp_core99_probe(void){	struct device_node *cpus;	int ncpus = 0;	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);	/* Count CPUs in the device-tree */       	for (cpus = NULL; (cpus = of_find_node_by_type(cpus, "cpu")) != NULL;)	       	++ncpus;	printk(KERN_INFO "PowerMac SMP probe found %d cpus\n", ncpus);	/* Nothing more to do if less than 2 of them */	if (ncpus <= 1)		return 1;	/* We need to perform some early initialisations before we can start	 * setting up SMP as we are running before initcalls	 */	pmac_pfunc_base_install();	pmac_i2c_init();	/* Setup various bits like timebase sync method, ability to nap, ... */	smp_core99_setup(ncpus);	/* Install IPIs */	mpic_request_ipis();	/* Collect l2cr and l3cr values from CPU 0 */	core99_init_caches(0);	return ncpus;}static void __devinit smp_core99_kick_cpu(int nr){	unsigned int save_vector;	unsigned long target, flags;	volatile unsigned int *vector		 = ((volatile unsigned int *)(KERNELBASE+0x100));	if (nr < 0 || nr > 3)		return;	if (ppc_md.progress)		ppc_md.progress("smp_core99_kick_cpu", 0x346);	local_irq_save(flags);	/* Save reset vector */	save_vector = *vector;	/* Setup fake reset vector that does	 *   b __secondary_start_pmac_0 + nr*8 - KERNELBASE	 */	target = (unsigned long) __secondary_start_pmac_0 + nr * 8;	create_branch((unsigned long)vector, target, BRANCH_SET_LINK);	/* Put some life in our friend */	pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);	/* FIXME: We wait a bit for the CPU to take the exception, I should	 * instead wait for the entry code to set something for me. Well,	 * ideally, all that crap will be done in prom.c and the CPU left	 * in a RAM-based wait loop like CHRP.	 */	mdelay(1);	/* Restore our exception vector */	*vector = save_vector;	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);	local_irq_restore(flags);	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);}static void __devinit smp_core99_setup_cpu(int cpu_nr){	/* Setup L2/L3 */	if (cpu_nr != 0)		core99_init_caches(cpu_nr);	/* Setup openpic */	mpic_setup_this_cpu();	if (cpu_nr == 0) {#ifdef CONFIG_PPC64		extern void g5_phy_disable_cpu1(void);		/* Close i2c bus if it was used for tb sync */		if (pmac_tb_clock_chip_host) {			pmac_i2c_close(pmac_tb_clock_chip_host);			pmac_tb_clock_chip_host	= NULL;		}		/* If we didn't start the second CPU, we must take		 * it off the bus		 */		if (machine_is_compatible("MacRISC4") &&		    num_online_cpus() < 2)					g5_phy_disable_cpu1();#endif /* CONFIG_PPC64 */		if (ppc_md.progress)			ppc_md.progress("core99_setup_cpu 0 done", 0x349);	}}#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32)int smp_core99_cpu_disable(void){	cpu_clear(smp_processor_id(), cpu_online_map);	/* XXX reset cpu affinity here */	mpic_cpu_set_priority(0xf);	asm volatile("mtdec %0" : : "r" (0x7fffffff));	mb();	udelay(20);	asm volatile("mtdec %0" : : "r" (0x7fffffff));	return 0;}extern void low_cpu_die(void) __attribute__((noreturn)); /* in sleep.S */static int cpu_dead[NR_CPUS];void cpu_die(void){	local_irq_disable();	cpu_dead[smp_processor_id()] = 1;	mb();	low_cpu_die();}void smp_core99_cpu_die(unsigned int cpu){	int timeout;	timeout = 1000;	while (!cpu_dead[cpu]) {		if (--timeout == 0) {			printk("CPU %u refused to die!\n", cpu);			break;		}		msleep(1);	}	cpu_dead[cpu] = 0;}#endif /* CONFIG_HOTPLUG_CPU && CONFIG_PP32 *//* Core99 Macs (dual G4s and G5s) */struct smp_ops_t core99_smp_ops = {	.message_pass	= smp_mpic_message_pass,	.probe		= smp_core99_probe,	.kick_cpu	= smp_core99_kick_cpu,	.setup_cpu	= smp_core99_setup_cpu,	.give_timebase	= smp_core99_give_timebase,	.take_timebase	= smp_core99_take_timebase,#if defined(CONFIG_HOTPLUG_CPU)# if defined(CONFIG_PPC32)	.cpu_disable	= smp_core99_cpu_disable,	.cpu_die	= smp_core99_cpu_die,# endif# if defined(CONFIG_PPC64)	.cpu_disable	= generic_cpu_disable,	.cpu_die	= generic_cpu_die,	/* intentionally do *NOT* assign cpu_enable,	 * the generic code will use kick_cpu then! */# endif#endif};

⌨️ 快捷键说明

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