linux/arch/mips/sgi-ip30/ip30-smp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * ip30-smp.c: SMP on IP30 architecture.
   4 * Based off of the original IP30 SMP code, with inspiration from ip27-smp.c
   5 * and smp-bmips.c.
   6 *
   7 * Copyright (C) 2005-2007 Stanislaw Skowronek <skylark@unaligned.org>
   8 *               2006-2007, 2014-2015 Joshua Kinard <kumba@gentoo.org>
   9 *               2009 Johannes Dickgreber <tanzy@gmx.de>
  10 */
  11
  12#include <linux/init.h>
  13#include <linux/sched.h>
  14#include <linux/sched/task_stack.h>
  15
  16#include <asm/time.h>
  17#include <asm/sgi/heart.h>
  18
  19#include "ip30-common.h"
  20
  21#define MPCONF_MAGIC    0xbaddeed2
  22#define MPCONF_ADDR     0xa800000000000600L
  23#define MPCONF_SIZE     0x80
  24#define MPCONF(x)       (MPCONF_ADDR + (x) * MPCONF_SIZE)
  25
  26/* HEART can theoretically do 4 CPUs, but only 2 are physically possible */
  27#define MP_NCPU         2
  28
  29struct mpconf {
  30        u32 magic;
  31        u32 prid;
  32        u32 physid;
  33        u32 virtid;
  34        u32 scachesz;
  35        u16 fanloads;
  36        u16 res;
  37        void *launch;
  38        void *rendezvous;
  39        u64 res2[3];
  40        void *stackaddr;
  41        void *lnch_parm;
  42        void *rndv_parm;
  43        u32 idleflag;
  44};
  45
  46static void ip30_smp_send_ipi_single(int cpu, u32 action)
  47{
  48        int irq;
  49
  50        switch (action) {
  51        case SMP_RESCHEDULE_YOURSELF:
  52                irq = HEART_L2_INT_RESCHED_CPU_0;
  53                break;
  54        case SMP_CALL_FUNCTION:
  55                irq = HEART_L2_INT_CALL_CPU_0;
  56                break;
  57        default:
  58                panic("IP30: Unknown action value in %s!\n", __func__);
  59        }
  60
  61        irq += cpu;
  62
  63        /* Poke the other CPU -- it's got mail! */
  64        heart_write(BIT_ULL(irq), &heart_regs->set_isr);
  65}
  66
  67static void ip30_smp_send_ipi_mask(const struct cpumask *mask, u32 action)
  68{
  69        u32 i;
  70
  71        for_each_cpu(i, mask)
  72                ip30_smp_send_ipi_single(i, action);
  73}
  74
  75static void __init ip30_smp_setup(void)
  76{
  77        int i;
  78        int ncpu = 0;
  79        struct mpconf *mpc;
  80
  81        init_cpu_possible(cpumask_of(0));
  82
  83        /* Scan the MPCONF structure and enumerate available CPUs. */
  84        for (i = 0; i < MP_NCPU; i++) {
  85                mpc = (struct mpconf *)MPCONF(i);
  86                if (mpc->magic == MPCONF_MAGIC) {
  87                        set_cpu_possible(i, true);
  88                        __cpu_number_map[i] = ++ncpu;
  89                        __cpu_logical_map[ncpu] = i;
  90                        pr_info("IP30: Slot: %d, PrID: %.8x, PhyID: %d, VirtID: %d\n",
  91                                i, mpc->prid, mpc->physid, mpc->virtid);
  92                }
  93        }
  94        pr_info("IP30: Detected %d CPU(s) present.\n", ncpu);
  95
  96        /*
  97         * Set the coherency algorithm to '5' (cacheable coherent
  98         * exclusive on write).  This is needed on IP30 SMP, especially
  99         * for R14000 CPUs, otherwise, instruction bus errors will
 100         * occur upon reaching userland.
 101         */
 102        change_c0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_COW);
 103}
 104
 105static void __init ip30_smp_prepare_cpus(unsigned int max_cpus)
 106{
 107        /* nothing to do here */
 108}
 109
 110static int __init ip30_smp_boot_secondary(int cpu, struct task_struct *idle)
 111{
 112        struct mpconf *mpc = (struct mpconf *)MPCONF(cpu);
 113
 114        /* Stack pointer (sp). */
 115        mpc->stackaddr = (void *)__KSTK_TOS(idle);
 116
 117        /* Global pointer (gp). */
 118        mpc->lnch_parm = task_thread_info(idle);
 119
 120        mb(); /* make sure stack and lparm are written */
 121
 122        /* Boot CPUx. */
 123        mpc->launch = smp_bootstrap;
 124
 125        /* CPUx now executes smp_bootstrap, then ip30_smp_finish */
 126        return 0;
 127}
 128
 129static void __init ip30_smp_init_cpu(void)
 130{
 131        ip30_per_cpu_init();
 132}
 133
 134static void __init ip30_smp_finish(void)
 135{
 136        enable_percpu_irq(get_c0_compare_int(), IRQ_TYPE_NONE);
 137        local_irq_enable();
 138}
 139
 140struct plat_smp_ops __read_mostly ip30_smp_ops = {
 141        .send_ipi_single        = ip30_smp_send_ipi_single,
 142        .send_ipi_mask          = ip30_smp_send_ipi_mask,
 143        .smp_setup              = ip30_smp_setup,
 144        .prepare_cpus           = ip30_smp_prepare_cpus,
 145        .boot_secondary         = ip30_smp_boot_secondary,
 146        .init_secondary         = ip30_smp_init_cpu,
 147        .smp_finish             = ip30_smp_finish,
 148        .prepare_boot_cpu       = ip30_smp_init_cpu,
 149};
 150