summaryrefslogtreecommitdiff
path: root/arch/mips/sgi-ip27/ip27-smp.c
blob: faa0244c8b0c636b45bd69e9a626d22daef92812 (plain)
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
 * This file is subject to the terms and conditions of the GNU General
 * Public License.  See the file "COPYING" in the main directory of this
 * archive for more details.
 *
 * Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com)
 * Copyright (C) 2000 - 2001 by Silicon Graphics, Inc.
 */
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <linux/topology.h>
#include <linux/nodemask.h>

#include <asm/page.h>
#include <asm/processor.h>
#include <asm/ptrace.h>
#include <asm/sn/arch.h>
#include <asm/sn/gda.h>
#include <asm/sn/intr.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/launch.h>
#include <asm/sn/mapped_kernel.h>
#include <asm/sn/sn_private.h>
#include <asm/sn/types.h>
#include <asm/sn/sn0/hubpi.h>
#include <asm/sn/sn0/hubio.h>
#include <asm/sn/sn0/ip27.h>

#include "ip27-common.h"

/*
 * Takes as first input the PROM assigned cpu id, and the kernel
 * assigned cpu id as the second.
 */
static void alloc_cpupda(nasid_t nasid, cpuid_t cpu, int cpunum)
{
	cputonasid(cpunum) = nasid;
	cputoslice(cpunum) = get_cpu_slice(cpu);
}

static int do_cpumask(nasid_t nasid, int highest)
{
	static int tot_cpus_found = 0;
	lboard_t *brd;
	klcpu_t *acpu;
	int cpus_found = 0;
	cpuid_t cpuid;

	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);

	do {
		acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU);
		while (acpu) {
			cpuid = acpu->cpu_info.virtid;
			/* Only let it join in if it's marked enabled */
			if ((acpu->cpu_info.flags & KLINFO_ENABLE) &&
			    (tot_cpus_found != NR_CPUS)) {
				if (cpuid > highest)
					highest = cpuid;
				set_cpu_possible(cpuid, true);
				alloc_cpupda(nasid, cpuid, tot_cpus_found);
				cpus_found++;
				tot_cpus_found++;
			}
			acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu,
								KLSTRUCT_CPU);
		}
		brd = KLCF_NEXT(brd);
		if (!brd)
			break;

		brd = find_lboard(brd, KLTYPE_IP27);
	} while (brd);

	return highest;
}

void cpu_node_probe(void)
{
	int i, highest = 0;
	gda_t *gdap = GDA;

	nodes_clear(node_online_map);
	for (i = 0; i < MAX_NUMNODES; i++) {
		nasid_t nasid = gdap->g_nasidtable[i];
		if (nasid == INVALID_NASID)
			break;
		node_set_online(nasid);
		highest = do_cpumask(nasid, highest);
	}

	printk("Discovered %d cpus on %d nodes\n", highest + 1, num_online_nodes());
}

static __init void intr_clear_all(nasid_t nasid)
{
	int i;

	REMOTE_HUB_S(nasid, PI_INT_MASK0_A, 0);
	REMOTE_HUB_S(nasid, PI_INT_MASK0_B, 0);
	REMOTE_HUB_S(nasid, PI_INT_MASK1_A, 0);
	REMOTE_HUB_S(nasid, PI_INT_MASK1_B, 0);

	for (i = 0; i < 128; i++)
		REMOTE_HUB_CLR_INTR(nasid, i);
}

static void ip27_send_ipi_single(int destid, unsigned int action)
{
	int irq;

	switch (action) {
	case SMP_RESCHEDULE_YOURSELF:
		irq = CPU_RESCHED_A_IRQ;
		break;
	case SMP_CALL_FUNCTION:
		irq = CPU_CALL_A_IRQ;
		break;
	default:
		panic("sendintr");
	}

	irq += cputoslice(destid);

	/*
	 * Set the interrupt bit associated with the CPU we want to
	 * send the interrupt to.
	 */
	REMOTE_HUB_SEND_INTR(cpu_to_node(destid), irq);
}

static void ip27_send_ipi_mask(const struct cpumask *mask, unsigned int action)
{
	unsigned int i;

	for_each_cpu(i, mask)
		ip27_send_ipi_single(i, action);
}

static void ip27_init_cpu(void)
{
	per_cpu_init();
}

static void ip27_smp_finish(void)
{
	hub_rt_clock_event_init();
	local_irq_enable();
}

/*
 * Launch a slave into smp_bootstrap().	 It doesn't take an argument, and we
 * set sp to the kernel stack of the newly created idle process, gp to the proc
 * struct so that current_thread_info() will work.
 */
static int ip27_boot_secondary(int cpu, struct task_struct *idle)
{
	unsigned long gp = (unsigned long)task_thread_info(idle);
	unsigned long sp = __KSTK_TOS(idle);

	LAUNCH_SLAVE(cputonasid(cpu), cputoslice(cpu),
		(launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap),
		0, (void *) sp, (void *) gp);
	return 0;
}

static void __init ip27_smp_setup(void)
{
	nasid_t nasid;

	for_each_online_node(nasid) {
		if (nasid == 0)
			continue;
		intr_clear_all(nasid);
	}

	replicate_kernel_text();

	/*
	 * PROM sets up system, that boot cpu is always first CPU on nasid 0
	 */
	alloc_cpupda(0, 0, 0);
}

static void __init ip27_prepare_cpus(unsigned int max_cpus)
{
	/* We already did everything necessary earlier */
}

const struct plat_smp_ops ip27_smp_ops = {
	.send_ipi_single	= ip27_send_ipi_single,
	.send_ipi_mask		= ip27_send_ipi_mask,
	.init_secondary		= ip27_init_cpu,
	.smp_finish		= ip27_smp_finish,
	.boot_secondary		= ip27_boot_secondary,
	.smp_setup		= ip27_smp_setup,
	.prepare_cpus		= ip27_prepare_cpus,
	.prepare_boot_cpu	= ip27_init_cpu,
};