Path: blob/master/arch/powerpc/platforms/powermac/smp.c
10818 views
/*1* SMP support for power macintosh.2*3* We support both the old "powersurge" SMP architecture4* and the current Core99 (G4 PowerMac) machines.5*6* Note that we don't support the very first rev. of7* Apple/DayStar 2 CPUs board, the one with the funky8* watchdog. Hopefully, none of these should be there except9* maybe internally to Apple. I should probably still add some10* code to detect this card though and disable SMP. --BenH.11*12* Support Macintosh G4 SMP by Troy Benjegerdes ([email protected])13* and Ben Herrenschmidt <[email protected]>.14*15* Support for DayStar quad CPU cards16* Copyright (C) XLR8, Inc. 1994-200017*18* This program is free software; you can redistribute it and/or19* modify it under the terms of the GNU General Public License20* as published by the Free Software Foundation; either version21* 2 of the License, or (at your option) any later version.22*/23#include <linux/kernel.h>24#include <linux/sched.h>25#include <linux/smp.h>26#include <linux/interrupt.h>27#include <linux/kernel_stat.h>28#include <linux/delay.h>29#include <linux/init.h>30#include <linux/spinlock.h>31#include <linux/errno.h>32#include <linux/hardirq.h>33#include <linux/cpu.h>34#include <linux/compiler.h>3536#include <asm/ptrace.h>37#include <asm/atomic.h>38#include <asm/code-patching.h>39#include <asm/irq.h>40#include <asm/page.h>41#include <asm/pgtable.h>42#include <asm/sections.h>43#include <asm/io.h>44#include <asm/prom.h>45#include <asm/smp.h>46#include <asm/machdep.h>47#include <asm/pmac_feature.h>48#include <asm/time.h>49#include <asm/mpic.h>50#include <asm/cacheflush.h>51#include <asm/keylargo.h>52#include <asm/pmac_low_i2c.h>53#include <asm/pmac_pfunc.h>5455#include "pmac.h"5657#undef DEBUG5859#ifdef DEBUG60#define DBG(fmt...) udbg_printf(fmt)61#else62#define DBG(fmt...)63#endif6465extern void __secondary_start_pmac_0(void);66extern int pmac_pfunc_base_install(void);6768static void (*pmac_tb_freeze)(int freeze);69static u64 timebase;70static int tb_req;7172#ifdef CONFIG_PPC_PMAC32_PSURGE7374/*75* Powersurge (old powermac SMP) support.76*/7778/* Addresses for powersurge registers */79#define HAMMERHEAD_BASE 0xf800000080#define HHEAD_CONFIG 0x9081#define HHEAD_SEC_INTR 0xc08283/* register for interrupting the primary processor on the powersurge */84/* N.B. this is actually the ethernet ROM! */85#define PSURGE_PRI_INTR 0xf30190008687/* register for storing the start address for the secondary processor */88/* N.B. this is the PCI config space address register for the 1st bridge */89#define PSURGE_START 0xf28000009091/* Daystar/XLR8 4-CPU card */92#define PSURGE_QUAD_REG_ADDR 0xf88000009394#define PSURGE_QUAD_IRQ_SET 095#define PSURGE_QUAD_IRQ_CLR 196#define PSURGE_QUAD_IRQ_PRIMARY 297#define PSURGE_QUAD_CKSTOP_CTL 398#define PSURGE_QUAD_PRIMARY_ARB 499#define PSURGE_QUAD_BOARD_ID 6100#define PSURGE_QUAD_WHICH_CPU 7101#define PSURGE_QUAD_CKSTOP_RDBK 8102#define PSURGE_QUAD_RESET_CTL 11103104#define PSURGE_QUAD_OUT(r, v) (out_8(quad_base + ((r) << 4) + 4, (v)))105#define PSURGE_QUAD_IN(r) (in_8(quad_base + ((r) << 4) + 4) & 0x0f)106#define PSURGE_QUAD_BIS(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))107#define PSURGE_QUAD_BIC(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))108109/* virtual addresses for the above */110static volatile u8 __iomem *hhead_base;111static volatile u8 __iomem *quad_base;112static volatile u32 __iomem *psurge_pri_intr;113static volatile u8 __iomem *psurge_sec_intr;114static volatile u32 __iomem *psurge_start;115116/* values for psurge_type */117#define PSURGE_NONE -1118#define PSURGE_DUAL 0119#define PSURGE_QUAD_OKEE 1120#define PSURGE_QUAD_COTTON 2121#define PSURGE_QUAD_ICEGRASS 3122123/* what sort of powersurge board we have */124static int psurge_type = PSURGE_NONE;125126/* irq for secondary cpus to report */127static struct irq_host *psurge_host;128int psurge_secondary_virq;129130/*131* Set and clear IPIs for powersurge.132*/133static inline void psurge_set_ipi(int cpu)134{135if (psurge_type == PSURGE_NONE)136return;137if (cpu == 0)138in_be32(psurge_pri_intr);139else if (psurge_type == PSURGE_DUAL)140out_8(psurge_sec_intr, 0);141else142PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu);143}144145static inline void psurge_clr_ipi(int cpu)146{147if (cpu > 0) {148switch(psurge_type) {149case PSURGE_DUAL:150out_8(psurge_sec_intr, ~0);151case PSURGE_NONE:152break;153default:154PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);155}156}157}158159/*160* On powersurge (old SMP powermac architecture) we don't have161* separate IPIs for separate messages like openpic does. Instead162* use the generic demux helpers163* -- paulus.164*/165static irqreturn_t psurge_ipi_intr(int irq, void *d)166{167psurge_clr_ipi(smp_processor_id());168smp_ipi_demux();169170return IRQ_HANDLED;171}172173static void smp_psurge_cause_ipi(int cpu, unsigned long data)174{175psurge_set_ipi(cpu);176}177178static int psurge_host_map(struct irq_host *h, unsigned int virq,179irq_hw_number_t hw)180{181irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_percpu_irq);182183return 0;184}185186struct irq_host_ops psurge_host_ops = {187.map = psurge_host_map,188};189190static int psurge_secondary_ipi_init(void)191{192int rc = -ENOMEM;193194psurge_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,195&psurge_host_ops, 0);196197if (psurge_host)198psurge_secondary_virq = irq_create_direct_mapping(psurge_host);199200if (psurge_secondary_virq)201rc = request_irq(psurge_secondary_virq, psurge_ipi_intr,202IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL);203204if (rc)205pr_err("Failed to setup secondary cpu IPI\n");206207return rc;208}209210/*211* Determine a quad card presence. We read the board ID register, we212* force the data bus to change to something else, and we read it again.213* It it's stable, then the register probably exist (ugh !)214*/215static int __init psurge_quad_probe(void)216{217int type;218unsigned int i;219220type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID);221if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS222|| type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))223return PSURGE_DUAL;224225/* looks OK, try a slightly more rigorous test */226/* bogus is not necessarily cacheline-aligned,227though I don't suppose that really matters. -- paulus */228for (i = 0; i < 100; i++) {229volatile u32 bogus[8];230bogus[(0+i)%8] = 0x00000000;231bogus[(1+i)%8] = 0x55555555;232bogus[(2+i)%8] = 0xFFFFFFFF;233bogus[(3+i)%8] = 0xAAAAAAAA;234bogus[(4+i)%8] = 0x33333333;235bogus[(5+i)%8] = 0xCCCCCCCC;236bogus[(6+i)%8] = 0xCCCCCCCC;237bogus[(7+i)%8] = 0x33333333;238wmb();239asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory");240mb();241if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))242return PSURGE_DUAL;243}244return type;245}246247static void __init psurge_quad_init(void)248{249int procbits;250251if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351);252procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU);253if (psurge_type == PSURGE_QUAD_ICEGRASS)254PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);255else256PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits);257mdelay(33);258out_8(psurge_sec_intr, ~0);259PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits);260PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);261if (psurge_type != PSURGE_QUAD_ICEGRASS)262PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits);263PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits);264mdelay(33);265PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits);266mdelay(33);267PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits);268mdelay(33);269}270271static int __init smp_psurge_probe(void)272{273int i, ncpus;274struct device_node *dn;275276/* We don't do SMP on the PPC601 -- paulus */277if (PVR_VER(mfspr(SPRN_PVR)) == 1)278return 1;279280/*281* The powersurge cpu board can be used in the generation282* of powermacs that have a socket for an upgradeable cpu card,283* including the 7500, 8500, 9500, 9600.284* The device tree doesn't tell you if you have 2 cpus because285* OF doesn't know anything about the 2nd processor.286* Instead we look for magic bits in magic registers,287* in the hammerhead memory controller in the case of the288* dual-cpu powersurge board. -- paulus.289*/290dn = of_find_node_by_name(NULL, "hammerhead");291if (dn == NULL)292return 1;293of_node_put(dn);294295hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);296quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);297psurge_sec_intr = hhead_base + HHEAD_SEC_INTR;298299psurge_type = psurge_quad_probe();300if (psurge_type != PSURGE_DUAL) {301psurge_quad_init();302/* All released cards using this HW design have 4 CPUs */303ncpus = 4;304/* No sure how timebase sync works on those, let's use SW */305smp_ops->give_timebase = smp_generic_give_timebase;306smp_ops->take_timebase = smp_generic_take_timebase;307} else {308iounmap(quad_base);309if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {310/* not a dual-cpu card */311iounmap(hhead_base);312psurge_type = PSURGE_NONE;313return 1;314}315ncpus = 2;316}317318if (psurge_secondary_ipi_init())319return 1;320321psurge_start = ioremap(PSURGE_START, 4);322psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);323324/* This is necessary because OF doesn't know about the325* secondary cpu(s), and thus there aren't nodes in the326* device tree for them, and smp_setup_cpu_maps hasn't327* set their bits in cpu_present_mask.328*/329if (ncpus > NR_CPUS)330ncpus = NR_CPUS;331for (i = 1; i < ncpus ; ++i)332set_cpu_present(i, true);333334if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);335336return ncpus;337}338339static int __init smp_psurge_kick_cpu(int nr)340{341unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8;342unsigned long a, flags;343int i, j;344345/* Defining this here is evil ... but I prefer hiding that346* crap to avoid giving people ideas that they can do the347* same.348*/349extern volatile unsigned int cpu_callin_map[NR_CPUS];350351/* may need to flush here if secondary bats aren't setup */352for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)353asm volatile("dcbf 0,%0" : : "r" (a) : "memory");354asm volatile("sync");355356if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);357358/* This is going to freeze the timeebase, we disable interrupts */359local_irq_save(flags);360361out_be32(psurge_start, start);362mb();363364psurge_set_ipi(nr);365366/*367* We can't use udelay here because the timebase is now frozen.368*/369for (i = 0; i < 2000; ++i)370asm volatile("nop" : : : "memory");371psurge_clr_ipi(nr);372373/*374* Also, because the timebase is frozen, we must not return to the375* caller which will try to do udelay's etc... Instead, we wait -here-376* for the CPU to callin.377*/378for (i = 0; i < 100000 && !cpu_callin_map[nr]; ++i) {379for (j = 1; j < 10000; j++)380asm volatile("nop" : : : "memory");381asm volatile("sync" : : : "memory");382}383if (!cpu_callin_map[nr])384goto stuck;385386/* And we do the TB sync here too for standard dual CPU cards */387if (psurge_type == PSURGE_DUAL) {388while(!tb_req)389barrier();390tb_req = 0;391mb();392timebase = get_tb();393mb();394while (timebase)395barrier();396mb();397}398stuck:399/* now interrupt the secondary, restarting both TBs */400if (psurge_type == PSURGE_DUAL)401psurge_set_ipi(1);402403if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);404405return 0;406}407408static struct irqaction psurge_irqaction = {409.handler = psurge_ipi_intr,410.flags = IRQF_DISABLED|IRQF_PERCPU,411.name = "primary IPI",412};413414static void __init smp_psurge_setup_cpu(int cpu_nr)415{416if (cpu_nr != 0)417return;418419/* reset the entry point so if we get another intr we won't420* try to startup again */421out_be32(psurge_start, 0x100);422if (setup_irq(irq_create_mapping(NULL, 30), &psurge_irqaction))423printk(KERN_ERR "Couldn't get primary IPI interrupt");424}425426void __init smp_psurge_take_timebase(void)427{428if (psurge_type != PSURGE_DUAL)429return;430431tb_req = 1;432mb();433while (!timebase)434barrier();435mb();436set_tb(timebase >> 32, timebase & 0xffffffff);437timebase = 0;438mb();439set_dec(tb_ticks_per_jiffy/2);440}441442void __init smp_psurge_give_timebase(void)443{444/* Nothing to do here */445}446447/* PowerSurge-style Macs */448struct smp_ops_t psurge_smp_ops = {449.message_pass = smp_muxed_ipi_message_pass,450.cause_ipi = smp_psurge_cause_ipi,451.probe = smp_psurge_probe,452.kick_cpu = smp_psurge_kick_cpu,453.setup_cpu = smp_psurge_setup_cpu,454.give_timebase = smp_psurge_give_timebase,455.take_timebase = smp_psurge_take_timebase,456};457#endif /* CONFIG_PPC_PMAC32_PSURGE */458459/*460* Core 99 and later support461*/462463464static void smp_core99_give_timebase(void)465{466unsigned long flags;467468local_irq_save(flags);469470while(!tb_req)471barrier();472tb_req = 0;473(*pmac_tb_freeze)(1);474mb();475timebase = get_tb();476mb();477while (timebase)478barrier();479mb();480(*pmac_tb_freeze)(0);481mb();482483local_irq_restore(flags);484}485486487static void __devinit smp_core99_take_timebase(void)488{489unsigned long flags;490491local_irq_save(flags);492493tb_req = 1;494mb();495while (!timebase)496barrier();497mb();498set_tb(timebase >> 32, timebase & 0xffffffff);499timebase = 0;500mb();501502local_irq_restore(flags);503}504505#ifdef CONFIG_PPC64506/*507* G5s enable/disable the timebase via an i2c-connected clock chip.508*/509static struct pmac_i2c_bus *pmac_tb_clock_chip_host;510static u8 pmac_tb_pulsar_addr;511512static void smp_core99_cypress_tb_freeze(int freeze)513{514u8 data;515int rc;516517/* Strangely, the device-tree says address is 0xd2, but darwin518* accesses 0xd0 ...519*/520pmac_i2c_setmode(pmac_tb_clock_chip_host,521pmac_i2c_mode_combined);522rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,5230xd0 | pmac_i2c_read,5241, 0x81, &data, 1);525if (rc != 0)526goto bail;527528data = (data & 0xf3) | (freeze ? 0x00 : 0x0c);529530pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);531rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,5320xd0 | pmac_i2c_write,5331, 0x81, &data, 1);534535bail:536if (rc != 0) {537printk("Cypress Timebase %s rc: %d\n",538freeze ? "freeze" : "unfreeze", rc);539panic("Timebase freeze failed !\n");540}541}542543544static void smp_core99_pulsar_tb_freeze(int freeze)545{546u8 data;547int rc;548549pmac_i2c_setmode(pmac_tb_clock_chip_host,550pmac_i2c_mode_combined);551rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,552pmac_tb_pulsar_addr | pmac_i2c_read,5531, 0x2e, &data, 1);554if (rc != 0)555goto bail;556557data = (data & 0x88) | (freeze ? 0x11 : 0x22);558559pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);560rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,561pmac_tb_pulsar_addr | pmac_i2c_write,5621, 0x2e, &data, 1);563bail:564if (rc != 0) {565printk(KERN_ERR "Pulsar Timebase %s rc: %d\n",566freeze ? "freeze" : "unfreeze", rc);567panic("Timebase freeze failed !\n");568}569}570571static void __init smp_core99_setup_i2c_hwsync(int ncpus)572{573struct device_node *cc = NULL;574struct device_node *p;575const char *name = NULL;576const u32 *reg;577int ok;578579/* Look for the clock chip */580while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) {581p = of_get_parent(cc);582ok = p && of_device_is_compatible(p, "uni-n-i2c");583of_node_put(p);584if (!ok)585continue;586587pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc);588if (pmac_tb_clock_chip_host == NULL)589continue;590reg = of_get_property(cc, "reg", NULL);591if (reg == NULL)592continue;593switch (*reg) {594case 0xd2:595if (of_device_is_compatible(cc,"pulsar-legacy-slewing")) {596pmac_tb_freeze = smp_core99_pulsar_tb_freeze;597pmac_tb_pulsar_addr = 0xd2;598name = "Pulsar";599} else if (of_device_is_compatible(cc, "cy28508")) {600pmac_tb_freeze = smp_core99_cypress_tb_freeze;601name = "Cypress";602}603break;604case 0xd4:605pmac_tb_freeze = smp_core99_pulsar_tb_freeze;606pmac_tb_pulsar_addr = 0xd4;607name = "Pulsar";608break;609}610if (pmac_tb_freeze != NULL)611break;612}613if (pmac_tb_freeze != NULL) {614/* Open i2c bus for synchronous access */615if (pmac_i2c_open(pmac_tb_clock_chip_host, 1)) {616printk(KERN_ERR "Failed top open i2c bus for clock"617" sync, fallback to software sync !\n");618goto no_i2c_sync;619}620printk(KERN_INFO "Processor timebase sync using %s i2c clock\n",621name);622return;623}624no_i2c_sync:625pmac_tb_freeze = NULL;626pmac_tb_clock_chip_host = NULL;627}628629630631/*632* Newer G5s uses a platform function633*/634635static void smp_core99_pfunc_tb_freeze(int freeze)636{637struct device_node *cpus;638struct pmf_args args;639640cpus = of_find_node_by_path("/cpus");641BUG_ON(cpus == NULL);642args.count = 1;643args.u[0].v = !freeze;644pmf_call_function(cpus, "cpu-timebase", &args);645of_node_put(cpus);646}647648#else /* CONFIG_PPC64 */649650/*651* SMP G4 use a GPIO to enable/disable the timebase.652*/653654static unsigned int core99_tb_gpio; /* Timebase freeze GPIO */655656static void smp_core99_gpio_tb_freeze(int freeze)657{658if (freeze)659pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);660else661pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);662pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);663}664665666#endif /* !CONFIG_PPC64 */667668/* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */669volatile static long int core99_l2_cache;670volatile static long int core99_l3_cache;671672static void __devinit core99_init_caches(int cpu)673{674#ifndef CONFIG_PPC64675if (!cpu_has_feature(CPU_FTR_L2CR))676return;677678if (cpu == 0) {679core99_l2_cache = _get_L2CR();680printk("CPU0: L2CR is %lx\n", core99_l2_cache);681} else {682printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());683_set_L2CR(0);684_set_L2CR(core99_l2_cache);685printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);686}687688if (!cpu_has_feature(CPU_FTR_L3CR))689return;690691if (cpu == 0){692core99_l3_cache = _get_L3CR();693printk("CPU0: L3CR is %lx\n", core99_l3_cache);694} else {695printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());696_set_L3CR(0);697_set_L3CR(core99_l3_cache);698printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);699}700#endif /* !CONFIG_PPC64 */701}702703static void __init smp_core99_setup(int ncpus)704{705#ifdef CONFIG_PPC64706707/* i2c based HW sync on some G5s */708if (of_machine_is_compatible("PowerMac7,2") ||709of_machine_is_compatible("PowerMac7,3") ||710of_machine_is_compatible("RackMac3,1"))711smp_core99_setup_i2c_hwsync(ncpus);712713/* pfunc based HW sync on recent G5s */714if (pmac_tb_freeze == NULL) {715struct device_node *cpus =716of_find_node_by_path("/cpus");717if (cpus &&718of_get_property(cpus, "platform-cpu-timebase", NULL)) {719pmac_tb_freeze = smp_core99_pfunc_tb_freeze;720printk(KERN_INFO "Processor timebase sync using"721" platform function\n");722}723}724725#else /* CONFIG_PPC64 */726727/* GPIO based HW sync on ppc32 Core99 */728if (pmac_tb_freeze == NULL && !of_machine_is_compatible("MacRISC4")) {729struct device_node *cpu;730const u32 *tbprop = NULL;731732core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */733cpu = of_find_node_by_type(NULL, "cpu");734if (cpu != NULL) {735tbprop = of_get_property(cpu, "timebase-enable", NULL);736if (tbprop)737core99_tb_gpio = *tbprop;738of_node_put(cpu);739}740pmac_tb_freeze = smp_core99_gpio_tb_freeze;741printk(KERN_INFO "Processor timebase sync using"742" GPIO 0x%02x\n", core99_tb_gpio);743}744745#endif /* CONFIG_PPC64 */746747/* No timebase sync, fallback to software */748if (pmac_tb_freeze == NULL) {749smp_ops->give_timebase = smp_generic_give_timebase;750smp_ops->take_timebase = smp_generic_take_timebase;751printk(KERN_INFO "Processor timebase sync using software\n");752}753754#ifndef CONFIG_PPC64755{756int i;757758/* XXX should get this from reg properties */759for (i = 1; i < ncpus; ++i)760set_hard_smp_processor_id(i, i);761}762#endif763764/* 32 bits SMP can't NAP */765if (!of_machine_is_compatible("MacRISC4"))766powersave_nap = 0;767}768769static int __init smp_core99_probe(void)770{771struct device_node *cpus;772int ncpus = 0;773774if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);775776/* Count CPUs in the device-tree */777for (cpus = NULL; (cpus = of_find_node_by_type(cpus, "cpu")) != NULL;)778++ncpus;779780printk(KERN_INFO "PowerMac SMP probe found %d cpus\n", ncpus);781782/* Nothing more to do if less than 2 of them */783if (ncpus <= 1)784return 1;785786/* We need to perform some early initialisations before we can start787* setting up SMP as we are running before initcalls788*/789pmac_pfunc_base_install();790pmac_i2c_init();791792/* Setup various bits like timebase sync method, ability to nap, ... */793smp_core99_setup(ncpus);794795/* Install IPIs */796mpic_request_ipis();797798/* Collect l2cr and l3cr values from CPU 0 */799core99_init_caches(0);800801return ncpus;802}803804static int __devinit smp_core99_kick_cpu(int nr)805{806unsigned int save_vector;807unsigned long target, flags;808unsigned int *vector = (unsigned int *)(PAGE_OFFSET+0x100);809810if (nr < 0 || nr > 3)811return -ENOENT;812813if (ppc_md.progress)814ppc_md.progress("smp_core99_kick_cpu", 0x346);815816local_irq_save(flags);817818/* Save reset vector */819save_vector = *vector;820821/* Setup fake reset vector that does822* b __secondary_start_pmac_0 + nr*8823*/824target = (unsigned long) __secondary_start_pmac_0 + nr * 8;825patch_branch(vector, target, BRANCH_SET_LINK);826827/* Put some life in our friend */828pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);829830/* FIXME: We wait a bit for the CPU to take the exception, I should831* instead wait for the entry code to set something for me. Well,832* ideally, all that crap will be done in prom.c and the CPU left833* in a RAM-based wait loop like CHRP.834*/835mdelay(1);836837/* Restore our exception vector */838*vector = save_vector;839flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);840841local_irq_restore(flags);842if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);843844return 0;845}846847static void __devinit smp_core99_setup_cpu(int cpu_nr)848{849/* Setup L2/L3 */850if (cpu_nr != 0)851core99_init_caches(cpu_nr);852853/* Setup openpic */854mpic_setup_this_cpu();855}856857#ifdef CONFIG_PPC64858#ifdef CONFIG_HOTPLUG_CPU859static int smp_core99_cpu_notify(struct notifier_block *self,860unsigned long action, void *hcpu)861{862int rc;863864switch(action) {865case CPU_UP_PREPARE:866case CPU_UP_PREPARE_FROZEN:867/* Open i2c bus if it was used for tb sync */868if (pmac_tb_clock_chip_host) {869rc = pmac_i2c_open(pmac_tb_clock_chip_host, 1);870if (rc) {871pr_err("Failed to open i2c bus for time sync\n");872return notifier_from_errno(rc);873}874}875break;876case CPU_ONLINE:877case CPU_UP_CANCELED:878/* Close i2c bus if it was used for tb sync */879if (pmac_tb_clock_chip_host)880pmac_i2c_close(pmac_tb_clock_chip_host);881break;882default:883break;884}885return NOTIFY_OK;886}887888static struct notifier_block __cpuinitdata smp_core99_cpu_nb = {889.notifier_call = smp_core99_cpu_notify,890};891#endif /* CONFIG_HOTPLUG_CPU */892893static void __init smp_core99_bringup_done(void)894{895extern void g5_phy_disable_cpu1(void);896897/* Close i2c bus if it was used for tb sync */898if (pmac_tb_clock_chip_host)899pmac_i2c_close(pmac_tb_clock_chip_host);900901/* If we didn't start the second CPU, we must take902* it off the bus.903*/904if (of_machine_is_compatible("MacRISC4") &&905num_online_cpus() < 2) {906set_cpu_present(1, false);907g5_phy_disable_cpu1();908}909#ifdef CONFIG_HOTPLUG_CPU910register_cpu_notifier(&smp_core99_cpu_nb);911#endif912913if (ppc_md.progress)914ppc_md.progress("smp_core99_bringup_done", 0x349);915}916#endif /* CONFIG_PPC64 */917918#ifdef CONFIG_HOTPLUG_CPU919920static int smp_core99_cpu_disable(void)921{922int rc = generic_cpu_disable();923if (rc)924return rc;925926mpic_cpu_set_priority(0xf);927928return 0;929}930931#ifdef CONFIG_PPC32932933static void pmac_cpu_die(void)934{935int cpu = smp_processor_id();936937local_irq_disable();938idle_task_exit();939pr_debug("CPU%d offline\n", cpu);940generic_set_cpu_dead(cpu);941smp_wmb();942mb();943low_cpu_die();944}945946#else /* CONFIG_PPC32 */947948static void pmac_cpu_die(void)949{950int cpu = smp_processor_id();951952local_irq_disable();953idle_task_exit();954955/*956* turn off as much as possible, we'll be957* kicked out as this will only be invoked958* on core99 platforms for now ...959*/960961printk(KERN_INFO "CPU#%d offline\n", cpu);962generic_set_cpu_dead(cpu);963smp_wmb();964965/*966* Re-enable interrupts. The NAP code needs to enable them967* anyways, do it now so we deal with the case where one already968* happened while soft-disabled.969* We shouldn't get any external interrupts, only decrementer, and the970* decrementer handler is safe for use on offline CPUs971*/972local_irq_enable();973974while (1) {975/* let's not take timer interrupts too often ... */976set_dec(0x7fffffff);977978/* Enter NAP mode */979power4_idle();980}981}982983#endif /* else CONFIG_PPC32 */984#endif /* CONFIG_HOTPLUG_CPU */985986/* Core99 Macs (dual G4s and G5s) */987struct smp_ops_t core99_smp_ops = {988.message_pass = smp_mpic_message_pass,989.probe = smp_core99_probe,990#ifdef CONFIG_PPC64991.bringup_done = smp_core99_bringup_done,992#endif993.kick_cpu = smp_core99_kick_cpu,994.setup_cpu = smp_core99_setup_cpu,995.give_timebase = smp_core99_give_timebase,996.take_timebase = smp_core99_take_timebase,997#if defined(CONFIG_HOTPLUG_CPU)998.cpu_disable = smp_core99_cpu_disable,999.cpu_die = generic_cpu_die,1000#endif1001};10021003void __init pmac_setup_smp(void)1004{1005struct device_node *np;10061007/* Check for Core99 */1008np = of_find_node_by_name(NULL, "uni-n");1009if (!np)1010np = of_find_node_by_name(NULL, "u3");1011if (!np)1012np = of_find_node_by_name(NULL, "u4");1013if (np) {1014of_node_put(np);1015smp_ops = &core99_smp_ops;1016}1017#ifdef CONFIG_PPC_PMAC32_PSURGE1018else {1019/* We have to set bits in cpu_possible_mask here since the1020* secondary CPU(s) aren't in the device tree. Various1021* things won't be initialized for CPUs not in the possible1022* map, so we really need to fix it up here.1023*/1024int cpu;10251026for (cpu = 1; cpu < 4 && cpu < NR_CPUS; ++cpu)1027set_cpu_possible(cpu, true);1028smp_ops = &psurge_smp_ops;1029}1030#endif /* CONFIG_PPC_PMAC32_PSURGE */10311032#ifdef CONFIG_HOTPLUG_CPU1033ppc_md.cpu_die = pmac_cpu_die;1034#endif1035}10361037103810391040