linux/arch/blackfin/mach-bf561/smp.c
<<
>>
Prefs
   1/*
   2 * Copyright 2007-2009 Analog Devices Inc.
   3 *               Philippe Gerum <rpm@xenomai.org>
   4 *
   5 * Licensed under the GPL-2 or later.
   6 */
   7
   8#include <linux/init.h>
   9#include <linux/kernel.h>
  10#include <linux/sched.h>
  11#include <linux/delay.h>
  12#include <asm/smp.h>
  13#include <asm/dma.h>
  14
  15static DEFINE_SPINLOCK(boot_lock);
  16
  17static cpumask_t cpu_callin_map;
  18
  19/*
  20 * platform_init_cpus() - Tell the world about how many cores we
  21 * have. This is called while setting up the architecture support
  22 * (setup_arch()), so don't be too demanding here with respect to
  23 * available kernel services.
  24 */
  25
  26void __init platform_init_cpus(void)
  27{
  28        cpu_set(0, cpu_possible_map); /* CoreA */
  29        cpu_set(1, cpu_possible_map); /* CoreB */
  30}
  31
  32void __init platform_prepare_cpus(unsigned int max_cpus)
  33{
  34        int len;
  35
  36        len = &coreb_trampoline_end - &coreb_trampoline_start + 1;
  37        BUG_ON(len > L1_CODE_LENGTH);
  38
  39        dma_memcpy((void *)COREB_L1_CODE_START, &coreb_trampoline_start, len);
  40
  41        /* Both cores ought to be present on a bf561! */
  42        cpu_set(0, cpu_present_map); /* CoreA */
  43        cpu_set(1, cpu_present_map); /* CoreB */
  44
  45        printk(KERN_INFO "CoreB bootstrap code to SRAM %p via DMA.\n", (void *)COREB_L1_CODE_START);
  46}
  47
  48int __init setup_profiling_timer(unsigned int multiplier) /* not supported */
  49{
  50        return -EINVAL;
  51}
  52
  53void __cpuinit platform_secondary_init(unsigned int cpu)
  54{
  55        local_irq_disable();
  56
  57        /* Clone setup for peripheral interrupt sources from CoreA. */
  58        bfin_write_SICB_IMASK0(bfin_read_SICA_IMASK0());
  59        bfin_write_SICB_IMASK1(bfin_read_SICA_IMASK1());
  60        SSYNC();
  61
  62        /* Clone setup for IARs from CoreA. */
  63        bfin_write_SICB_IAR0(bfin_read_SICA_IAR0());
  64        bfin_write_SICB_IAR1(bfin_read_SICA_IAR1());
  65        bfin_write_SICB_IAR2(bfin_read_SICA_IAR2());
  66        bfin_write_SICB_IAR3(bfin_read_SICA_IAR3());
  67        bfin_write_SICB_IAR4(bfin_read_SICA_IAR4());
  68        bfin_write_SICB_IAR5(bfin_read_SICA_IAR5());
  69        bfin_write_SICB_IAR6(bfin_read_SICA_IAR6());
  70        bfin_write_SICB_IAR7(bfin_read_SICA_IAR7());
  71        SSYNC();
  72
  73        local_irq_enable();
  74
  75        /* Calibrate loops per jiffy value. */
  76        calibrate_delay();
  77
  78        /* Store CPU-private information to the cpu_data array. */
  79        bfin_setup_cpudata(cpu);
  80
  81        /* We are done with local CPU inits, unblock the boot CPU. */
  82        cpu_set(cpu, cpu_callin_map);
  83        spin_lock(&boot_lock);
  84        spin_unlock(&boot_lock);
  85}
  86
  87int __cpuinit platform_boot_secondary(unsigned int cpu, struct task_struct *idle)
  88{
  89        unsigned long timeout;
  90
  91        /* CoreB already running?! */
  92        BUG_ON((bfin_read_SICA_SYSCR() & COREB_SRAM_INIT) == 0);
  93
  94        printk(KERN_INFO "Booting Core B.\n");
  95
  96        spin_lock(&boot_lock);
  97
  98        /* Kick CoreB, which should start execution from CORE_SRAM_BASE. */
  99        SSYNC();
 100        bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~COREB_SRAM_INIT);
 101        SSYNC();
 102
 103        timeout = jiffies + 1 * HZ;
 104        while (time_before(jiffies, timeout)) {
 105                if (cpu_isset(cpu, cpu_callin_map))
 106                        break;
 107                udelay(100);
 108                barrier();
 109        }
 110
 111        spin_unlock(&boot_lock);
 112
 113        return cpu_isset(cpu, cpu_callin_map) ? 0 : -ENOSYS;
 114}
 115
 116void __init platform_request_ipi(irq_handler_t handler)
 117{
 118        int ret;
 119
 120        ret = request_irq(IRQ_SUPPLE_0, handler, IRQF_DISABLED,
 121                          "Supplemental Interrupt0", handler);
 122        if (ret)
 123                panic("Cannot request supplemental interrupt 0 for IPI service");
 124}
 125
 126void platform_send_ipi(cpumask_t callmap)
 127{
 128        unsigned int cpu;
 129
 130        for_each_cpu_mask(cpu, callmap) {
 131                BUG_ON(cpu >= 2);
 132                SSYNC();
 133                bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (6 + cpu)));
 134                SSYNC();
 135        }
 136}
 137
 138void platform_send_ipi_cpu(unsigned int cpu)
 139{
 140        BUG_ON(cpu >= 2);
 141        SSYNC();
 142        bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (6 + cpu)));
 143        SSYNC();
 144}
 145
 146void platform_clear_ipi(unsigned int cpu)
 147{
 148        BUG_ON(cpu >= 2);
 149        SSYNC();
 150        bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + cpu)));
 151        SSYNC();
 152}
 153