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

📄 smp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
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_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined);	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,			       0xd0 | pmac_low_i2c_read,			       0x81, &data, 1);	if (rc != 0)		goto bail;	data = (data & 0xf3) | (freeze ? 0x00 : 0x0c);       	pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,			       0xd0 | pmac_low_i2c_write,			       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_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined);	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,			       pmac_tb_pulsar_addr | pmac_low_i2c_read,			       0x2e, &data, 1);	if (rc != 0)		goto bail;	data = (data & 0x88) | (freeze ? 0x11 : 0x22);	pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,			       pmac_tb_pulsar_addr | pmac_low_i2c_write,			       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 smp_core99_give_timebase(void){	/* Open i2c bus for synchronous access */	if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0))		panic("Can't open i2c for TB sync !\n");	spin_lock(&timebase_lock);	(*pmac_tb_freeze)(1);	mb();	timebase = get_tb();	spin_unlock(&timebase_lock);	while (timebase)		barrier();	spin_lock(&timebase_lock);	(*pmac_tb_freeze)(0);	spin_unlock(&timebase_lock);	/* Close i2c bus */	pmac_low_i2c_close(pmac_tb_clock_chip_host);}static void __devinit smp_core99_take_timebase(void){	while (!timebase)		barrier();	spin_lock(&timebase_lock);	set_tb(timebase >> 32, timebase & 0xffffffff);	timebase = 0;	spin_unlock(&timebase_lock);}static void __init smp_core99_setup(int ncpus){	struct device_node *cc = NULL;		struct device_node *p;	u32 *reg;	int ok;	/* HW sync only on these platforms */	if (!machine_is_compatible("PowerMac7,2") &&	    !machine_is_compatible("PowerMac7,3") &&	    !machine_is_compatible("RackMac3,1"))		return;	/* Look for the clock chip */	while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) {		p = of_get_parent(cc);		ok = p && device_is_compatible(p, "uni-n-i2c");		of_node_put(p);		if (!ok)			continue;		reg = (u32 *)get_property(cc, "reg", NULL);		if (reg == NULL)			continue;		switch (*reg) {		case 0xd2:			if (device_is_compatible(cc, "pulsar-legacy-slewing")) {				pmac_tb_freeze = smp_core99_pulsar_tb_freeze;				pmac_tb_pulsar_addr = 0xd2;				printk(KERN_INFO "Timebase clock is Pulsar chip\n");			} else if (device_is_compatible(cc, "cy28508")) {				pmac_tb_freeze = smp_core99_cypress_tb_freeze;				printk(KERN_INFO "Timebase clock is Cypress chip\n");			}			break;		case 0xd4:			pmac_tb_freeze = smp_core99_pulsar_tb_freeze;			pmac_tb_pulsar_addr = 0xd4;			printk(KERN_INFO "Timebase clock is Pulsar chip\n");			break;		}		if (pmac_tb_freeze != NULL) {			pmac_tb_clock_chip_host = of_get_parent(cc);			of_node_put(cc);			break;		}	}	if (pmac_tb_freeze == NULL) {		smp_ops->give_timebase = smp_generic_give_timebase;		smp_ops->take_timebase = smp_generic_take_timebase;	}}/* nothing to do here, caches are already set up by service processor */static inline void __devinit core99_init_caches(int cpu){}#else /* CONFIG_PPC64 *//* * SMP G4 powermacs use a GPIO to enable/disable the timebase. */static unsigned int core99_tb_gpio;	/* Timebase freeze GPIO */static unsigned int pri_tb_hi, pri_tb_lo;static unsigned int pri_tb_stamp;/* not __init, called in sleep/wakeup code */void smp_core99_give_timebase(void){	unsigned long flags;	unsigned int t;	/* wait for the secondary to be in take_timebase */	for (t = 100000; t > 0 && !sec_tb_reset; --t)		udelay(10);	if (!sec_tb_reset) {		printk(KERN_WARNING "Timeout waiting sync on second CPU\n");		return;	}	/* freeze the timebase and read it */	/* disable interrupts so the timebase is disabled for the	   shortest possible time */	local_irq_save(flags);	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);	pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);	mb();	pri_tb_hi = get_tbu();	pri_tb_lo = get_tbl();	pri_tb_stamp = last_jiffy_stamp(smp_processor_id());	mb();	/* tell the secondary we're ready */	sec_tb_reset = 2;	mb();	/* wait for the secondary to have taken it */	/* note: can't use udelay here, since it needs the timebase running */	for (t = 10000000; t > 0 && sec_tb_reset; --t)		barrier();	if (sec_tb_reset)		/* XXX BUG_ON here? */		printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n");	/* Now, restart the timebase by leaving the GPIO to an open collector */       	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);        pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);	local_irq_restore(flags);}/* not __init, called in sleep/wakeup code */void smp_core99_take_timebase(void){	unsigned long flags;	/* tell the primary we're here */	sec_tb_reset = 1;	mb();	/* wait for the primary to set pri_tb_hi/lo */	while (sec_tb_reset < 2)		mb();	/* set our stuff the same as the primary */	local_irq_save(flags);	set_dec(1);	set_tb(pri_tb_hi, pri_tb_lo);	last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp;	mb();	/* tell the primary we're done */       	sec_tb_reset = 0;	mb();	local_irq_restore(flags);}/* 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){	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);	}}static void __init smp_core99_setup(int ncpus){	struct device_node *cpu;	u32 *tbprop = NULL;	int i;	core99_tb_gpio = KL_GPIO_TB_ENABLE;	/* default value */	cpu = of_find_node_by_type(NULL, "cpu");	if (cpu != NULL) {		tbprop = (u32 *)get_property(cpu, "timebase-enable", NULL);		if (tbprop)			core99_tb_gpio = *tbprop;		of_node_put(cpu);	}	/* XXX should get this from reg properties */	for (i = 1; i < ncpus; ++i)		smp_hw_index[i] = i;	powersave_nap = 0;}#endifstatic 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;	smp_core99_setup(ncpus);	mpic_request_ipis();	core99_init_caches(0);	return ncpus;}static void __devinit smp_core99_kick_cpu(int nr){	unsigned int save_vector;	unsigned long new_vector;	unsigned long 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);	local_irq_disable();	/* Save reset vector */	save_vector = *vector;	/* Setup fake reset vector that does		 *   b __secondary_start_pmac_0 + nr*8 - KERNELBASE	 */	new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8;	*vector = 0x48000002 + new_vector - KERNELBASE;	/* flush data cache and inval instruction cache */	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);	/* 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_POWER4		extern void g5_phy_disable_cpu1(void);		/* 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_POWER4 */		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/* 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) && defined(CONFIG_PPC32)	.cpu_disable	= smp_core99_cpu_disable,	.cpu_die	= smp_core99_cpu_die,#endif};

⌨️ 快捷键说明

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