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