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 29 struct 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 46 static 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 67 static 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 75 static 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 105 static void __init ip30_smp_prepare_cpus(unsigned int max_cpus) 106 { 107 /* nothing to do here */ 108 } 109 110 static 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 129 static void __init ip30_smp_init_cpu(void) 130 { 131 ip30_per_cpu_init(); 132 } 133 134 static void __init ip30_smp_finish(void) 135 { 136 enable_percpu_irq(get_c0_compare_int(), IRQ_TYPE_NONE); 137 local_irq_enable(); 138 } 139 140 struct 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.