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