linux/arch/powerpc/platforms/85xx/smp.c
<<
>>
Prefs
   1/*
   2 * Author: Andy Fleming <afleming@freescale.com>
   3 *         Kumar Gala <galak@kernel.crashing.org>
   4 *
   5 * Copyright 2006-2008, 2011 Freescale Semiconductor Inc.
   6 *
   7 * This program is free software; you can redistribute  it and/or modify it
   8 * under  the terms of  the GNU General  Public License as published by the
   9 * Free Software Foundation;  either version 2 of the  License, or (at your
  10 * option) any later version.
  11 */
  12
  13#include <linux/stddef.h>
  14#include <linux/kernel.h>
  15#include <linux/init.h>
  16#include <linux/delay.h>
  17#include <linux/of.h>
  18#include <linux/kexec.h>
  19#include <linux/highmem.h>
  20
  21#include <asm/machdep.h>
  22#include <asm/pgtable.h>
  23#include <asm/page.h>
  24#include <asm/mpic.h>
  25#include <asm/cacheflush.h>
  26#include <asm/dbell.h>
  27
  28#include <sysdev/fsl_soc.h>
  29#include <sysdev/mpic.h>
  30#include "smp.h"
  31
  32extern void __early_start(void);
  33
  34#define BOOT_ENTRY_ADDR_UPPER   0
  35#define BOOT_ENTRY_ADDR_LOWER   1
  36#define BOOT_ENTRY_R3_UPPER     2
  37#define BOOT_ENTRY_R3_LOWER     3
  38#define BOOT_ENTRY_RESV         4
  39#define BOOT_ENTRY_PIR          5
  40#define BOOT_ENTRY_R6_UPPER     6
  41#define BOOT_ENTRY_R6_LOWER     7
  42#define NUM_BOOT_ENTRY          8
  43#define SIZE_BOOT_ENTRY         (NUM_BOOT_ENTRY * sizeof(u32))
  44
  45static int __init
  46smp_85xx_kick_cpu(int nr)
  47{
  48        unsigned long flags;
  49        const u64 *cpu_rel_addr;
  50        __iomem u32 *bptr_vaddr;
  51        struct device_node *np;
  52        int n = 0, hw_cpu = get_hard_smp_processor_id(nr);
  53        int ioremappable;
  54
  55        WARN_ON(nr < 0 || nr >= NR_CPUS);
  56        WARN_ON(hw_cpu < 0 || hw_cpu >= NR_CPUS);
  57
  58        pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr);
  59
  60        np = of_get_cpu_node(nr, NULL);
  61        cpu_rel_addr = of_get_property(np, "cpu-release-addr", NULL);
  62
  63        if (cpu_rel_addr == NULL) {
  64                printk(KERN_ERR "No cpu-release-addr for cpu %d\n", nr);
  65                return -ENOENT;
  66        }
  67
  68        /*
  69         * A secondary core could be in a spinloop in the bootpage
  70         * (0xfffff000), somewhere in highmem, or somewhere in lowmem.
  71         * The bootpage and highmem can be accessed via ioremap(), but
  72         * we need to directly access the spinloop if its in lowmem.
  73         */
  74        ioremappable = *cpu_rel_addr > virt_to_phys(high_memory);
  75
  76        /* Map the spin table */
  77        if (ioremappable)
  78                bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
  79        else
  80                bptr_vaddr = phys_to_virt(*cpu_rel_addr);
  81
  82        local_irq_save(flags);
  83
  84        out_be32(bptr_vaddr + BOOT_ENTRY_PIR, hw_cpu);
  85#ifdef CONFIG_PPC32
  86        out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
  87
  88        if (!ioremappable)
  89                flush_dcache_range((ulong)bptr_vaddr,
  90                                (ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
  91
  92        /* Wait a bit for the CPU to ack. */
  93        while ((__secondary_hold_acknowledge != hw_cpu) && (++n < 1000))
  94                mdelay(1);
  95#else
  96        smp_generic_kick_cpu(nr);
  97
  98        out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER),
  99                __pa((u64)*((unsigned long long *) generic_secondary_smp_init)));
 100
 101        if (!ioremappable)
 102                flush_dcache_range((ulong)bptr_vaddr,
 103                                (ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
 104#endif
 105
 106        local_irq_restore(flags);
 107
 108        if (ioremappable)
 109                iounmap(bptr_vaddr);
 110
 111        pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
 112
 113        return 0;
 114}
 115
 116struct smp_ops_t smp_85xx_ops = {
 117        .kick_cpu = smp_85xx_kick_cpu,
 118#ifdef CONFIG_KEXEC
 119        .give_timebase  = smp_generic_give_timebase,
 120        .take_timebase  = smp_generic_take_timebase,
 121#endif
 122};
 123
 124#ifdef CONFIG_KEXEC
 125atomic_t kexec_down_cpus = ATOMIC_INIT(0);
 126
 127void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary)
 128{
 129        local_irq_disable();
 130
 131        if (secondary) {
 132                atomic_inc(&kexec_down_cpus);
 133                /* loop forever */
 134                while (1);
 135        }
 136}
 137
 138static void mpc85xx_smp_kexec_down(void *arg)
 139{
 140        if (ppc_md.kexec_cpu_down)
 141                ppc_md.kexec_cpu_down(0,1);
 142}
 143
 144static void map_and_flush(unsigned long paddr)
 145{
 146        struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
 147        unsigned long kaddr  = (unsigned long)kmap(page);
 148
 149        flush_dcache_range(kaddr, kaddr + PAGE_SIZE);
 150        kunmap(page);
 151}
 152
 153/**
 154 * Before we reset the other cores, we need to flush relevant cache
 155 * out to memory so we don't get anything corrupted, some of these flushes
 156 * are performed out of an overabundance of caution as interrupts are not
 157 * disabled yet and we can switch cores
 158 */
 159static void mpc85xx_smp_flush_dcache_kexec(struct kimage *image)
 160{
 161        kimage_entry_t *ptr, entry;
 162        unsigned long paddr;
 163        int i;
 164
 165        if (image->type == KEXEC_TYPE_DEFAULT) {
 166                /* normal kexec images are stored in temporary pages */
 167                for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE);
 168                     ptr = (entry & IND_INDIRECTION) ?
 169                                phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
 170                        if (!(entry & IND_DESTINATION)) {
 171                                map_and_flush(entry);
 172                        }
 173                }
 174                /* flush out last IND_DONE page */
 175                map_and_flush(entry);
 176        } else {
 177                /* crash type kexec images are copied to the crash region */
 178                for (i = 0; i < image->nr_segments; i++) {
 179                        struct kexec_segment *seg = &image->segment[i];
 180                        for (paddr = seg->mem; paddr < seg->mem + seg->memsz;
 181                             paddr += PAGE_SIZE) {
 182                                map_and_flush(paddr);
 183                        }
 184                }
 185        }
 186
 187        /* also flush the kimage struct to be passed in as well */
 188        flush_dcache_range((unsigned long)image,
 189                           (unsigned long)image + sizeof(*image));
 190}
 191
 192static void mpc85xx_smp_machine_kexec(struct kimage *image)
 193{
 194        int timeout = INT_MAX;
 195        int i, num_cpus = num_present_cpus();
 196
 197        mpc85xx_smp_flush_dcache_kexec(image);
 198
 199        if (image->type == KEXEC_TYPE_DEFAULT)
 200                smp_call_function(mpc85xx_smp_kexec_down, NULL, 0);
 201
 202        while ( (atomic_read(&kexec_down_cpus) != (num_cpus - 1)) &&
 203                ( timeout > 0 ) )
 204        {
 205                timeout--;
 206        }
 207
 208        if ( !timeout )
 209                printk(KERN_ERR "Unable to bring down secondary cpu(s)");
 210
 211        for_each_online_cpu(i)
 212        {
 213                if ( i == smp_processor_id() ) continue;
 214                mpic_reset_core(i);
 215        }
 216
 217        default_machine_kexec(image);
 218}
 219#endif /* CONFIG_KEXEC */
 220
 221static void __init
 222smp_85xx_setup_cpu(int cpu_nr)
 223{
 224        if (smp_85xx_ops.probe == smp_mpic_probe)
 225                mpic_setup_this_cpu();
 226
 227        if (cpu_has_feature(CPU_FTR_DBELL))
 228                doorbell_setup_this_cpu();
 229}
 230
 231void __init mpc85xx_smp_init(void)
 232{
 233        struct device_node *np;
 234
 235        smp_85xx_ops.setup_cpu = smp_85xx_setup_cpu;
 236
 237        np = of_find_node_by_type(NULL, "open-pic");
 238        if (np) {
 239                smp_85xx_ops.probe = smp_mpic_probe;
 240                smp_85xx_ops.message_pass = smp_mpic_message_pass;
 241        }
 242
 243        if (cpu_has_feature(CPU_FTR_DBELL)) {
 244                /*
 245                 * If left NULL, .message_pass defaults to
 246                 * smp_muxed_ipi_message_pass
 247                 */
 248                smp_85xx_ops.message_pass = NULL;
 249                smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
 250        }
 251
 252        smp_ops = &smp_85xx_ops;
 253
 254#ifdef CONFIG_KEXEC
 255        ppc_md.kexec_cpu_down = mpc85xx_smp_kexec_cpu_down;
 256        ppc_md.machine_kexec = mpc85xx_smp_machine_kexec;
 257#endif
 258}
 259