Path: blob/master/arch/powerpc/platforms/powermac/smp.c
26481 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* SMP support for power macintosh.3*4* We support both the old "powersurge" SMP architecture5* and the current Core99 (G4 PowerMac) machines.6*7* Note that we don't support the very first rev. of8* Apple/DayStar 2 CPUs board, the one with the funky9* watchdog. Hopefully, none of these should be there except10* maybe internally to Apple. I should probably still add some11* code to detect this card though and disable SMP. --BenH.12*13* Support Macintosh G4 SMP by Troy Benjegerdes ([email protected])14* and Ben Herrenschmidt <[email protected]>.15*16* Support for DayStar quad CPU cards17* Copyright (C) XLR8, Inc. 1994-200018*/19#include <linux/kernel.h>20#include <linux/sched.h>21#include <linux/sched/hotplug.h>22#include <linux/smp.h>23#include <linux/interrupt.h>24#include <linux/irqdomain.h>25#include <linux/kernel_stat.h>26#include <linux/delay.h>27#include <linux/init.h>28#include <linux/spinlock.h>29#include <linux/errno.h>30#include <linux/hardirq.h>31#include <linux/cpu.h>32#include <linux/compiler.h>33#include <linux/pgtable.h>3435#include <asm/ptrace.h>36#include <linux/atomic.h>37#include <asm/text-patching.h>38#include <asm/irq.h>39#include <asm/page.h>40#include <asm/sections.h>41#include <asm/io.h>42#include <asm/smp.h>43#include <asm/machdep.h>44#include <asm/pmac_feature.h>45#include <asm/time.h>46#include <asm/mpic.h>47#include <asm/cacheflush.h>48#include <asm/keylargo.h>49#include <asm/pmac_low_i2c.h>50#include <asm/pmac_pfunc.h>51#include <asm/inst.h>5253#include "pmac.h"5455#undef DEBUG5657#ifdef DEBUG58#define DBG(fmt...) udbg_printf(fmt)59#else60#define DBG(fmt...)61#endif6263extern void __secondary_start_pmac_0(void);6465static void (*pmac_tb_freeze)(int freeze);66static u64 timebase;67static int tb_req;6869#ifdef CONFIG_PPC_PMAC32_PSURGE7071/*72* Powersurge (old powermac SMP) support.73*/7475/* Addresses for powersurge registers */76#define HAMMERHEAD_BASE 0xf800000077#define HHEAD_CONFIG 0x9078#define HHEAD_SEC_INTR 0xc07980/* register for interrupting the primary processor on the powersurge */81/* N.B. this is actually the ethernet ROM! */82#define PSURGE_PRI_INTR 0xf30190008384/* register for storing the start address for the secondary processor */85/* N.B. this is the PCI config space address register for the 1st bridge */86#define PSURGE_START 0xf28000008788/* Daystar/XLR8 4-CPU card */89#define PSURGE_QUAD_REG_ADDR 0xf88000009091#define PSURGE_QUAD_IRQ_SET 092#define PSURGE_QUAD_IRQ_CLR 193#define PSURGE_QUAD_IRQ_PRIMARY 294#define PSURGE_QUAD_CKSTOP_CTL 395#define PSURGE_QUAD_PRIMARY_ARB 496#define PSURGE_QUAD_BOARD_ID 697#define PSURGE_QUAD_WHICH_CPU 798#define PSURGE_QUAD_CKSTOP_RDBK 899#define PSURGE_QUAD_RESET_CTL 11100101#define PSURGE_QUAD_OUT(r, v) (out_8(quad_base + ((r) << 4) + 4, (v)))102#define PSURGE_QUAD_IN(r) (in_8(quad_base + ((r) << 4) + 4) & 0x0f)103#define PSURGE_QUAD_BIS(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))104#define PSURGE_QUAD_BIC(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))105106/* virtual addresses for the above */107static volatile u8 __iomem *hhead_base;108static volatile u8 __iomem *quad_base;109static volatile u32 __iomem *psurge_pri_intr;110static volatile u8 __iomem *psurge_sec_intr;111static volatile u32 __iomem *psurge_start;112113/* values for psurge_type */114#define PSURGE_NONE -1115#define PSURGE_DUAL 0116#define PSURGE_QUAD_OKEE 1117#define PSURGE_QUAD_COTTON 2118#define PSURGE_QUAD_ICEGRASS 3119120/* what sort of powersurge board we have */121static int psurge_type = PSURGE_NONE;122123/* irq for secondary cpus to report */124static struct irq_domain *psurge_host;125int psurge_secondary_virq;126127/*128* Set and clear IPIs for powersurge.129*/130static inline void psurge_set_ipi(int cpu)131{132if (psurge_type == PSURGE_NONE)133return;134if (cpu == 0)135in_be32(psurge_pri_intr);136else if (psurge_type == PSURGE_DUAL)137out_8(psurge_sec_intr, 0);138else139PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu);140}141142static inline void psurge_clr_ipi(int cpu)143{144if (cpu > 0) {145switch(psurge_type) {146case PSURGE_DUAL:147out_8(psurge_sec_intr, ~0);148break;149case PSURGE_NONE:150break;151default:152PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);153}154}155}156157/*158* On powersurge (old SMP powermac architecture) we don't have159* separate IPIs for separate messages like openpic does. Instead160* use the generic demux helpers161* -- paulus.162*/163static irqreturn_t psurge_ipi_intr(int irq, void *d)164{165psurge_clr_ipi(smp_processor_id());166smp_ipi_demux();167168return IRQ_HANDLED;169}170171static void smp_psurge_cause_ipi(int cpu)172{173psurge_set_ipi(cpu);174}175176static int psurge_host_map(struct irq_domain *h, unsigned int virq,177irq_hw_number_t hw)178{179irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_percpu_irq);180181return 0;182}183184static const struct irq_domain_ops psurge_host_ops = {185.map = psurge_host_map,186};187188static int __init psurge_secondary_ipi_init(void)189{190int rc = -ENOMEM;191192psurge_host = irq_domain_create_nomap(NULL, ~0, &psurge_host_ops, NULL);193194if (psurge_host)195psurge_secondary_virq = irq_create_direct_mapping(psurge_host);196197if (psurge_secondary_virq)198rc = request_irq(psurge_secondary_virq, psurge_ipi_intr,199IRQF_PERCPU | IRQF_NO_THREAD, "IPI", NULL);200201if (rc)202pr_err("Failed to setup secondary cpu IPI\n");203204return rc;205}206207/*208* Determine a quad card presence. We read the board ID register, we209* force the data bus to change to something else, and we read it again.210* It it's stable, then the register probably exist (ugh !)211*/212static int __init psurge_quad_probe(void)213{214int type;215unsigned int i;216217type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID);218if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS219|| type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))220return PSURGE_DUAL;221222/* looks OK, try a slightly more rigorous test */223/* bogus is not necessarily cacheline-aligned,224though I don't suppose that really matters. -- paulus */225for (i = 0; i < 100; i++) {226volatile u32 bogus[8];227bogus[(0+i)%8] = 0x00000000;228bogus[(1+i)%8] = 0x55555555;229bogus[(2+i)%8] = 0xFFFFFFFF;230bogus[(3+i)%8] = 0xAAAAAAAA;231bogus[(4+i)%8] = 0x33333333;232bogus[(5+i)%8] = 0xCCCCCCCC;233bogus[(6+i)%8] = 0xCCCCCCCC;234bogus[(7+i)%8] = 0x33333333;235wmb();236asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory");237mb();238if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))239return PSURGE_DUAL;240}241return type;242}243244static void __init psurge_quad_init(void)245{246int procbits;247248if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351);249procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU);250if (psurge_type == PSURGE_QUAD_ICEGRASS)251PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);252else253PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits);254mdelay(33);255out_8(psurge_sec_intr, ~0);256PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits);257PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);258if (psurge_type != PSURGE_QUAD_ICEGRASS)259PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits);260PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits);261mdelay(33);262PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits);263mdelay(33);264PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits);265mdelay(33);266}267268static void __init smp_psurge_probe(void)269{270int i, ncpus;271struct device_node *dn;272273/*274* The powersurge cpu board can be used in the generation275* of powermacs that have a socket for an upgradeable cpu card,276* including the 7500, 8500, 9500, 9600.277* The device tree doesn't tell you if you have 2 cpus because278* OF doesn't know anything about the 2nd processor.279* Instead we look for magic bits in magic registers,280* in the hammerhead memory controller in the case of the281* dual-cpu powersurge board. -- paulus.282*/283dn = of_find_node_by_name(NULL, "hammerhead");284if (dn == NULL)285return;286of_node_put(dn);287288hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);289quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);290psurge_sec_intr = hhead_base + HHEAD_SEC_INTR;291292psurge_type = psurge_quad_probe();293if (psurge_type != PSURGE_DUAL) {294psurge_quad_init();295/* All released cards using this HW design have 4 CPUs */296ncpus = 4;297/* No sure how timebase sync works on those, let's use SW */298smp_ops->give_timebase = smp_generic_give_timebase;299smp_ops->take_timebase = smp_generic_take_timebase;300} else {301iounmap(quad_base);302if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {303/* not a dual-cpu card */304iounmap(hhead_base);305psurge_type = PSURGE_NONE;306return;307}308ncpus = 2;309}310311if (psurge_secondary_ipi_init())312return;313314psurge_start = ioremap(PSURGE_START, 4);315psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);316317/* This is necessary because OF doesn't know about the318* secondary cpu(s), and thus there aren't nodes in the319* device tree for them, and smp_setup_cpu_maps hasn't320* set their bits in cpu_present_mask.321*/322if (ncpus > NR_CPUS)323ncpus = NR_CPUS;324for (i = 1; i < ncpus ; ++i)325set_cpu_present(i, true);326327if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);328}329330static int __init smp_psurge_kick_cpu(int nr)331{332unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8;333unsigned long a, flags;334int i, j;335336/* Defining this here is evil ... but I prefer hiding that337* crap to avoid giving people ideas that they can do the338* same.339*/340extern volatile unsigned int cpu_callin_map[NR_CPUS];341342/* may need to flush here if secondary bats aren't setup */343for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)344asm volatile("dcbf 0,%0" : : "r" (a) : "memory");345asm volatile("sync");346347if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);348349/* This is going to freeze the timeebase, we disable interrupts */350local_irq_save(flags);351352out_be32(psurge_start, start);353mb();354355psurge_set_ipi(nr);356357/*358* We can't use udelay here because the timebase is now frozen.359*/360for (i = 0; i < 2000; ++i)361asm volatile("nop" : : : "memory");362psurge_clr_ipi(nr);363364/*365* Also, because the timebase is frozen, we must not return to the366* caller which will try to do udelay's etc... Instead, we wait -here-367* for the CPU to callin.368*/369for (i = 0; i < 100000 && !cpu_callin_map[nr]; ++i) {370for (j = 1; j < 10000; j++)371asm volatile("nop" : : : "memory");372asm volatile("sync" : : : "memory");373}374if (!cpu_callin_map[nr])375goto stuck;376377/* And we do the TB sync here too for standard dual CPU cards */378if (psurge_type == PSURGE_DUAL) {379while(!tb_req)380barrier();381tb_req = 0;382mb();383timebase = get_tb();384mb();385while (timebase)386barrier();387mb();388}389stuck:390/* now interrupt the secondary, restarting both TBs */391if (psurge_type == PSURGE_DUAL)392psurge_set_ipi(1);393394if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);395396return 0;397}398399static void __init smp_psurge_setup_cpu(int cpu_nr)400{401unsigned long flags = IRQF_PERCPU | IRQF_NO_THREAD;402int irq;403404if (cpu_nr != 0 || !psurge_start)405return;406407/* reset the entry point so if we get another intr we won't408* try to startup again */409out_be32(psurge_start, 0x100);410irq = irq_create_mapping(NULL, 30);411if (request_irq(irq, psurge_ipi_intr, flags, "primary IPI", NULL))412printk(KERN_ERR "Couldn't get primary IPI interrupt");413}414415static void __init smp_psurge_take_timebase(void)416{417if (psurge_type != PSURGE_DUAL)418return;419420tb_req = 1;421mb();422while (!timebase)423barrier();424mb();425set_tb(timebase >> 32, timebase & 0xffffffff);426timebase = 0;427mb();428set_dec(tb_ticks_per_jiffy/2);429}430431static void __init smp_psurge_give_timebase(void)432{433/* Nothing to do here */434}435436/* PowerSurge-style Macs */437struct smp_ops_t psurge_smp_ops = {438.message_pass = NULL, /* Use smp_muxed_ipi_message_pass */439.cause_ipi = smp_psurge_cause_ipi,440.cause_nmi_ipi = NULL,441.probe = smp_psurge_probe,442.kick_cpu = smp_psurge_kick_cpu,443.setup_cpu = smp_psurge_setup_cpu,444.give_timebase = smp_psurge_give_timebase,445.take_timebase = smp_psurge_take_timebase,446};447#endif /* CONFIG_PPC_PMAC32_PSURGE */448449/*450* Core 99 and later support451*/452453454static void smp_core99_give_timebase(void)455{456unsigned long flags;457458local_irq_save(flags);459460while(!tb_req)461barrier();462tb_req = 0;463(*pmac_tb_freeze)(1);464mb();465timebase = get_tb();466mb();467while (timebase)468barrier();469mb();470(*pmac_tb_freeze)(0);471mb();472473local_irq_restore(flags);474}475476477static void smp_core99_take_timebase(void)478{479unsigned long flags;480481local_irq_save(flags);482483tb_req = 1;484mb();485while (!timebase)486barrier();487mb();488set_tb(timebase >> 32, timebase & 0xffffffff);489timebase = 0;490mb();491492local_irq_restore(flags);493}494495#ifdef CONFIG_PPC64496/*497* G5s enable/disable the timebase via an i2c-connected clock chip.498*/499static struct pmac_i2c_bus *pmac_tb_clock_chip_host;500static u8 pmac_tb_pulsar_addr;501502static void smp_core99_cypress_tb_freeze(int freeze)503{504u8 data;505int rc;506507/* Strangely, the device-tree says address is 0xd2, but darwin508* accesses 0xd0 ...509*/510pmac_i2c_setmode(pmac_tb_clock_chip_host,511pmac_i2c_mode_combined);512rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,5130xd0 | pmac_i2c_read,5141, 0x81, &data, 1);515if (rc != 0)516goto bail;517518data = (data & 0xf3) | (freeze ? 0x00 : 0x0c);519520pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);521rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,5220xd0 | pmac_i2c_write,5231, 0x81, &data, 1);524525bail:526if (rc != 0) {527printk("Cypress Timebase %s rc: %d\n",528freeze ? "freeze" : "unfreeze", rc);529panic("Timebase freeze failed !\n");530}531}532533534static void smp_core99_pulsar_tb_freeze(int freeze)535{536u8 data;537int rc;538539pmac_i2c_setmode(pmac_tb_clock_chip_host,540pmac_i2c_mode_combined);541rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,542pmac_tb_pulsar_addr | pmac_i2c_read,5431, 0x2e, &data, 1);544if (rc != 0)545goto bail;546547data = (data & 0x88) | (freeze ? 0x11 : 0x22);548549pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);550rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,551pmac_tb_pulsar_addr | pmac_i2c_write,5521, 0x2e, &data, 1);553bail:554if (rc != 0) {555printk(KERN_ERR "Pulsar Timebase %s rc: %d\n",556freeze ? "freeze" : "unfreeze", rc);557panic("Timebase freeze failed !\n");558}559}560561static void __init smp_core99_setup_i2c_hwsync(int ncpus)562{563struct device_node *cc = NULL;564struct device_node *p;565const char *name = NULL;566const u32 *reg;567int ok;568569/* Look for the clock chip */570for_each_node_by_name(cc, "i2c-hwclock") {571p = of_get_parent(cc);572ok = p && of_device_is_compatible(p, "uni-n-i2c");573of_node_put(p);574if (!ok)575continue;576577pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc);578if (pmac_tb_clock_chip_host == NULL)579continue;580reg = of_get_property(cc, "reg", NULL);581if (reg == NULL)582continue;583switch (*reg) {584case 0xd2:585if (of_device_is_compatible(cc,"pulsar-legacy-slewing")) {586pmac_tb_freeze = smp_core99_pulsar_tb_freeze;587pmac_tb_pulsar_addr = 0xd2;588name = "Pulsar";589} else if (of_device_is_compatible(cc, "cy28508")) {590pmac_tb_freeze = smp_core99_cypress_tb_freeze;591name = "Cypress";592}593break;594case 0xd4:595pmac_tb_freeze = smp_core99_pulsar_tb_freeze;596pmac_tb_pulsar_addr = 0xd4;597name = "Pulsar";598break;599}600if (pmac_tb_freeze != NULL) {601of_node_put(cc);602break;603}604}605if (pmac_tb_freeze != NULL) {606/* Open i2c bus for synchronous access */607if (pmac_i2c_open(pmac_tb_clock_chip_host, 1)) {608printk(KERN_ERR "Failed top open i2c bus for clock"609" sync, fallback to software sync !\n");610goto no_i2c_sync;611}612printk(KERN_INFO "Processor timebase sync using %s i2c clock\n",613name);614return;615}616no_i2c_sync:617pmac_tb_freeze = NULL;618pmac_tb_clock_chip_host = NULL;619}620621622623/*624* Newer G5s uses a platform function625*/626627static void smp_core99_pfunc_tb_freeze(int freeze)628{629struct device_node *cpus;630struct pmf_args args;631632cpus = of_find_node_by_path("/cpus");633BUG_ON(cpus == NULL);634args.count = 1;635args.u[0].v = !freeze;636pmf_call_function(cpus, "cpu-timebase", &args);637of_node_put(cpus);638}639640#else /* CONFIG_PPC64 */641642/*643* SMP G4 use a GPIO to enable/disable the timebase.644*/645646static unsigned int core99_tb_gpio; /* Timebase freeze GPIO */647648static void smp_core99_gpio_tb_freeze(int freeze)649{650if (freeze)651pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);652else653pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);654pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);655}656657658#endif /* !CONFIG_PPC64 */659660static void core99_init_caches(int cpu)661{662#ifndef CONFIG_PPC64663/* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */664static long int core99_l2_cache;665static long int core99_l3_cache;666667if (!cpu_has_feature(CPU_FTR_L2CR))668return;669670if (cpu == 0) {671core99_l2_cache = _get_L2CR();672printk("CPU0: L2CR is %lx\n", core99_l2_cache);673} else {674printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());675_set_L2CR(0);676_set_L2CR(core99_l2_cache);677printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);678}679680if (!cpu_has_feature(CPU_FTR_L3CR))681return;682683if (cpu == 0){684core99_l3_cache = _get_L3CR();685printk("CPU0: L3CR is %lx\n", core99_l3_cache);686} else {687printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());688_set_L3CR(0);689_set_L3CR(core99_l3_cache);690printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);691}692#endif /* !CONFIG_PPC64 */693}694695static void __init smp_core99_setup(int ncpus)696{697#ifdef CONFIG_PPC64698699/* i2c based HW sync on some G5s */700if (of_machine_is_compatible("PowerMac7,2") ||701of_machine_is_compatible("PowerMac7,3") ||702of_machine_is_compatible("RackMac3,1"))703smp_core99_setup_i2c_hwsync(ncpus);704705/* pfunc based HW sync on recent G5s */706if (pmac_tb_freeze == NULL) {707struct device_node *cpus =708of_find_node_by_path("/cpus");709if (cpus &&710of_property_read_bool(cpus, "platform-cpu-timebase")) {711pmac_tb_freeze = smp_core99_pfunc_tb_freeze;712printk(KERN_INFO "Processor timebase sync using"713" platform function\n");714}715of_node_put(cpus);716}717718#else /* CONFIG_PPC64 */719720/* GPIO based HW sync on ppc32 Core99 */721if (pmac_tb_freeze == NULL && !of_machine_is_compatible("MacRISC4")) {722struct device_node *cpu;723const u32 *tbprop = NULL;724725core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */726cpu = of_find_node_by_type(NULL, "cpu");727if (cpu != NULL) {728tbprop = of_get_property(cpu, "timebase-enable", NULL);729if (tbprop)730core99_tb_gpio = *tbprop;731of_node_put(cpu);732}733pmac_tb_freeze = smp_core99_gpio_tb_freeze;734printk(KERN_INFO "Processor timebase sync using"735" GPIO 0x%02x\n", core99_tb_gpio);736}737738#endif /* CONFIG_PPC64 */739740/* No timebase sync, fallback to software */741if (pmac_tb_freeze == NULL) {742smp_ops->give_timebase = smp_generic_give_timebase;743smp_ops->take_timebase = smp_generic_take_timebase;744printk(KERN_INFO "Processor timebase sync using software\n");745}746747#ifndef CONFIG_PPC64748{749int i;750751/* XXX should get this from reg properties */752for (i = 1; i < ncpus; ++i)753set_hard_smp_processor_id(i, i);754}755#endif756757/* 32 bits SMP can't NAP */758if (!of_machine_is_compatible("MacRISC4"))759powersave_nap = 0;760}761762static void __init smp_core99_probe(void)763{764struct device_node *cpus;765int ncpus = 0;766767if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);768769/* Count CPUs in the device-tree */770for_each_node_by_type(cpus, "cpu")771++ncpus;772773printk(KERN_INFO "PowerMac SMP probe found %d cpus\n", ncpus);774775/* Nothing more to do if less than 2 of them */776if (ncpus <= 1)777return;778779/* We need to perform some early initialisations before we can start780* setting up SMP as we are running before initcalls781*/782pmac_pfunc_base_install();783pmac_i2c_init();784785/* Setup various bits like timebase sync method, ability to nap, ... */786smp_core99_setup(ncpus);787788/* Install IPIs */789mpic_request_ipis();790791/* Collect l2cr and l3cr values from CPU 0 */792core99_init_caches(0);793}794795static int smp_core99_kick_cpu(int nr)796{797unsigned int save_vector;798unsigned long target, flags;799unsigned int *vector = (unsigned int *)(PAGE_OFFSET+0x100);800801if (nr < 0 || nr > 3)802return -ENOENT;803804if (ppc_md.progress)805ppc_md.progress("smp_core99_kick_cpu", 0x346);806807local_irq_save(flags);808809/* Save reset vector */810save_vector = *vector;811812/* Setup fake reset vector that does813* b __secondary_start_pmac_0 + nr*8814*/815target = (unsigned long) __secondary_start_pmac_0 + nr * 8;816patch_branch(vector, target, BRANCH_SET_LINK);817818/* Put some life in our friend */819pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);820821/* FIXME: We wait a bit for the CPU to take the exception, I should822* instead wait for the entry code to set something for me. Well,823* ideally, all that crap will be done in prom.c and the CPU left824* in a RAM-based wait loop like CHRP.825*/826mdelay(1);827828/* Restore our exception vector */829patch_uint(vector, save_vector);830831local_irq_restore(flags);832if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);833834return 0;835}836837static void smp_core99_setup_cpu(int cpu_nr)838{839/* Setup L2/L3 */840if (cpu_nr != 0)841core99_init_caches(cpu_nr);842843/* Setup openpic */844mpic_setup_this_cpu();845}846847#ifdef CONFIG_PPC64848#ifdef CONFIG_HOTPLUG_CPU849static unsigned int smp_core99_host_open;850851static int smp_core99_cpu_prepare(unsigned int cpu)852{853int rc;854855/* Open i2c bus if it was used for tb sync */856if (pmac_tb_clock_chip_host && !smp_core99_host_open) {857rc = pmac_i2c_open(pmac_tb_clock_chip_host, 1);858if (rc) {859pr_err("Failed to open i2c bus for time sync\n");860return notifier_from_errno(rc);861}862smp_core99_host_open = 1;863}864return 0;865}866867static int smp_core99_cpu_online(unsigned int cpu)868{869/* Close i2c bus if it was used for tb sync */870if (pmac_tb_clock_chip_host && smp_core99_host_open) {871pmac_i2c_close(pmac_tb_clock_chip_host);872smp_core99_host_open = 0;873}874return 0;875}876#endif /* CONFIG_HOTPLUG_CPU */877878static void __init smp_core99_bringup_done(void)879{880/* Close i2c bus if it was used for tb sync */881if (pmac_tb_clock_chip_host)882pmac_i2c_close(pmac_tb_clock_chip_host);883884/* If we didn't start the second CPU, we must take885* it off the bus.886*/887if (of_machine_is_compatible("MacRISC4") &&888num_online_cpus() < 2) {889set_cpu_present(1, false);890g5_phy_disable_cpu1();891}892#ifdef CONFIG_HOTPLUG_CPU893cpuhp_setup_state_nocalls(CPUHP_POWERPC_PMAC_PREPARE,894"powerpc/pmac:prepare", smp_core99_cpu_prepare,895NULL);896cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "powerpc/pmac:online",897smp_core99_cpu_online, NULL);898#endif899900if (ppc_md.progress)901ppc_md.progress("smp_core99_bringup_done", 0x349);902}903#endif /* CONFIG_PPC64 */904905#ifdef CONFIG_HOTPLUG_CPU906907static int smp_core99_cpu_disable(void)908{909int rc = generic_cpu_disable();910if (rc)911return rc;912913mpic_cpu_set_priority(0xf);914915cleanup_cpu_mmu_context();916917return 0;918}919920#ifdef CONFIG_PPC32921922static void pmac_cpu_offline_self(void)923{924int cpu = smp_processor_id();925926local_irq_disable();927idle_task_exit();928pr_debug("CPU%d offline\n", cpu);929generic_set_cpu_dead(cpu);930smp_wmb();931mb();932low_cpu_offline_self();933}934935#else /* CONFIG_PPC32 */936937static void pmac_cpu_offline_self(void)938{939int cpu = smp_processor_id();940941local_irq_disable();942idle_task_exit();943944/*945* turn off as much as possible, we'll be946* kicked out as this will only be invoked947* on core99 platforms for now ...948*/949950printk(KERN_INFO "CPU#%d offline\n", cpu);951generic_set_cpu_dead(cpu);952smp_wmb();953954/*955* Re-enable interrupts. The NAP code needs to enable them956* anyways, do it now so we deal with the case where one already957* happened while soft-disabled.958* We shouldn't get any external interrupts, only decrementer, and the959* decrementer handler is safe for use on offline CPUs960*/961local_irq_enable();962963while (1) {964/* let's not take timer interrupts too often ... */965set_dec(0x7fffffff);966967/* Enter NAP mode */968power4_idle();969}970}971972#endif /* else CONFIG_PPC32 */973#endif /* CONFIG_HOTPLUG_CPU */974975/* Core99 Macs (dual G4s and G5s) */976static struct smp_ops_t core99_smp_ops = {977.message_pass = smp_mpic_message_pass,978.probe = smp_core99_probe,979#ifdef CONFIG_PPC64980.bringup_done = smp_core99_bringup_done,981#endif982.kick_cpu = smp_core99_kick_cpu,983.setup_cpu = smp_core99_setup_cpu,984.give_timebase = smp_core99_give_timebase,985.take_timebase = smp_core99_take_timebase,986#if defined(CONFIG_HOTPLUG_CPU)987.cpu_disable = smp_core99_cpu_disable,988.cpu_die = generic_cpu_die,989#endif990};991992void __init pmac_setup_smp(void)993{994struct device_node *np;995996/* Check for Core99 */997np = of_find_node_by_name(NULL, "uni-n");998if (!np)999np = of_find_node_by_name(NULL, "u3");1000if (!np)1001np = of_find_node_by_name(NULL, "u4");1002if (np) {1003of_node_put(np);1004smp_ops = &core99_smp_ops;1005}1006#ifdef CONFIG_PPC_PMAC32_PSURGE1007else {1008/* We have to set bits in cpu_possible_mask here since the1009* secondary CPU(s) aren't in the device tree. Various1010* things won't be initialized for CPUs not in the possible1011* map, so we really need to fix it up here.1012*/1013int cpu;10141015for (cpu = 1; cpu < 4 && cpu < NR_CPUS; ++cpu)1016set_cpu_possible(cpu, true);1017smp_ops = &psurge_smp_ops;1018}1019#endif /* CONFIG_PPC_PMAC32_PSURGE */10201021#ifdef CONFIG_HOTPLUG_CPU1022smp_ops->cpu_offline_self = pmac_cpu_offline_self;1023#endif1024}10251026102710281029