X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc64%2Fkernel%2Fpmac_smp.c;h=e0b37079943c5ad5af472b8c19dc9e768286305c;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=fb6ab40147ed1f65168e969559ce4e264f669474;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c index fb6ab4014..e0b370799 100644 --- a/arch/ppc64/kernel/pmac_smp.c +++ b/arch/ppc64/kernel/pmac_smp.c @@ -21,6 +21,9 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ + +#undef DEBUG + #include #include #include @@ -28,10 +31,10 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -47,42 +50,180 @@ #include #include #include +#include + +#include "mpic.h" -#include "open_pic.h" +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif extern void pmac_secondary_start_1(void); extern void pmac_secondary_start_2(void); extern void pmac_secondary_start_3(void); -extern void smp_openpic_message_pass(int target, int msg); - extern struct smp_ops_t *smp_ops; +static void (*pmac_tb_freeze)(int freeze); +static struct device_node *pmac_tb_clock_chip_host; +static DEFINE_SPINLOCK(timebase_lock); +static unsigned long timebase; + +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; + + /* 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, + 0xd4 | 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, + 0xd4 | 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 int __init smp_core99_probe(void) { - struct device_node *cpus; - int ncpus = 1; + struct device_node *cpus; + struct device_node *cc; + int ncpus = 0; /* Maybe use systemconfiguration here ? */ if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); - cpus = find_type_devices("cpu"); - if (cpus == NULL) - return 0; - while ((cpus = cpus->next) != NULL) + /* 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); - if (ncpus > 1) - openpic_request_IPIs(); + /* Nothing more to do if less than 2 of them */ + if (ncpus <= 1) + return 1; + + /* Look for the clock chip */ + for (cc = NULL; (cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL;) { + struct device_node *p = of_get_parent(cc); + u32 *reg; + int ok; + ok = p && device_is_compatible(p, "uni-n-i2c"); + if (!ok) + goto next; + reg = (u32 *)get_property(cc, "reg", NULL); + if (reg == NULL) + goto next; + switch (*reg) { + case 0xd2: + 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; + printk(KERN_INFO "Timebase clock is Pulsar chip\n"); + break; + } + if (pmac_tb_freeze != NULL) { + pmac_tb_clock_chip_host = p; + smp_ops->give_timebase = smp_core99_give_timebase; + smp_ops->take_timebase = smp_core99_take_timebase; + break; + } + next: + of_node_put(p); + } + + mpic_request_ipis(); return ncpus; } static void __init smp_core99_kick_cpu(int nr) { - int save_vector; + int save_vector, j; unsigned long new_vector; unsigned long flags; volatile unsigned int *vector @@ -102,15 +243,16 @@ static void __init smp_core99_kick_cpu(int nr) * b .pmac_secondary_start - KERNELBASE */ switch(nr) { - case 1: - new_vector = (unsigned long)pmac_secondary_start_1; - break; - case 2: - new_vector = (unsigned long)pmac_secondary_start_2; - break; - case 3: - new_vector = (unsigned long)pmac_secondary_start_3; - break; + case 1: + new_vector = (unsigned long)pmac_secondary_start_1; + break; + case 2: + new_vector = (unsigned long)pmac_secondary_start_2; + break; + case 3: + default: + new_vector = (unsigned long)pmac_secondary_start_3; + break; } *vector = 0x48000002 + (new_vector - KERNELBASE); @@ -126,7 +268,8 @@ static void __init smp_core99_kick_cpu(int nr) * ideally, all that crap will be done in prom.c and the CPU left * in a RAM-based wait loop like CHRP. */ - mdelay(1); + for (j = 1; j < 1000000; j++) + mb(); /* Restore our exception vector */ *vector = save_vector; @@ -138,8 +281,8 @@ static void __init smp_core99_kick_cpu(int nr) static void __init smp_core99_setup_cpu(int cpu_nr) { - /* Setup openpic */ - do_openpic_setup_cpu(); + /* Setup MPIC */ + mpic_setup_this_cpu(); if (cpu_nr == 0) { extern void g5_phy_disable_cpu1(void); @@ -149,15 +292,12 @@ static void __init smp_core99_setup_cpu(int cpu_nr) */ if (num_online_cpus() < 2) g5_phy_disable_cpu1(); - if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349); + if (ppc_md.progress) ppc_md.progress("smp_core99_setup_cpu 0 done", 0x349); } } -extern void smp_generic_give_timebase(void); -extern void smp_generic_take_timebase(void); - struct smp_ops_t core99_smp_ops __pmacdata = { - .message_pass = smp_openpic_message_pass, + .message_pass = smp_mpic_message_pass, .probe = smp_core99_probe, .kick_cpu = smp_core99_kick_cpu, .setup_cpu = smp_core99_setup_cpu,