162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General
362306a36Sopenharmony_ci * Public License.  See the file "COPYING" in the main directory of this
462306a36Sopenharmony_ci * archive for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com)
762306a36Sopenharmony_ci * Copyright (C) 2000 - 2001 by Silicon Graphics, Inc.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/sched.h>
1162306a36Sopenharmony_ci#include <linux/sched/task_stack.h>
1262306a36Sopenharmony_ci#include <linux/topology.h>
1362306a36Sopenharmony_ci#include <linux/nodemask.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <asm/page.h>
1662306a36Sopenharmony_ci#include <asm/processor.h>
1762306a36Sopenharmony_ci#include <asm/ptrace.h>
1862306a36Sopenharmony_ci#include <asm/sn/agent.h>
1962306a36Sopenharmony_ci#include <asm/sn/arch.h>
2062306a36Sopenharmony_ci#include <asm/sn/gda.h>
2162306a36Sopenharmony_ci#include <asm/sn/intr.h>
2262306a36Sopenharmony_ci#include <asm/sn/klconfig.h>
2362306a36Sopenharmony_ci#include <asm/sn/launch.h>
2462306a36Sopenharmony_ci#include <asm/sn/mapped_kernel.h>
2562306a36Sopenharmony_ci#include <asm/sn/types.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "ip27-common.h"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic int node_scan_cpus(nasid_t nasid, int highest)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	static int cpus_found;
3262306a36Sopenharmony_ci	lboard_t *brd;
3362306a36Sopenharmony_ci	klcpu_t *acpu;
3462306a36Sopenharmony_ci	cpuid_t cpuid;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	do {
3962306a36Sopenharmony_ci		acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU);
4062306a36Sopenharmony_ci		while (acpu) {
4162306a36Sopenharmony_ci			cpuid = acpu->cpu_info.virtid;
4262306a36Sopenharmony_ci			/* Only let it join in if it's marked enabled */
4362306a36Sopenharmony_ci			if ((acpu->cpu_info.flags & KLINFO_ENABLE) &&
4462306a36Sopenharmony_ci			    (cpus_found != NR_CPUS)) {
4562306a36Sopenharmony_ci				if (cpuid > highest)
4662306a36Sopenharmony_ci					highest = cpuid;
4762306a36Sopenharmony_ci				set_cpu_possible(cpuid, true);
4862306a36Sopenharmony_ci				cputonasid(cpus_found) = nasid;
4962306a36Sopenharmony_ci				cputoslice(cpus_found) = acpu->cpu_info.physid;
5062306a36Sopenharmony_ci				sn_cpu_info[cpus_found].p_speed =
5162306a36Sopenharmony_ci							acpu->cpu_speed;
5262306a36Sopenharmony_ci				cpus_found++;
5362306a36Sopenharmony_ci			}
5462306a36Sopenharmony_ci			acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu,
5562306a36Sopenharmony_ci								KLSTRUCT_CPU);
5662306a36Sopenharmony_ci		}
5762306a36Sopenharmony_ci		brd = KLCF_NEXT(brd);
5862306a36Sopenharmony_ci		if (!brd)
5962306a36Sopenharmony_ci			break;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		brd = find_lboard(brd, KLTYPE_IP27);
6262306a36Sopenharmony_ci	} while (brd);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return highest;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_civoid cpu_node_probe(void)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	int i, highest = 0;
7062306a36Sopenharmony_ci	gda_t *gdap = GDA;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	nodes_clear(node_online_map);
7362306a36Sopenharmony_ci	for (i = 0; i < MAX_NUMNODES; i++) {
7462306a36Sopenharmony_ci		nasid_t nasid = gdap->g_nasidtable[i];
7562306a36Sopenharmony_ci		if (nasid == INVALID_NASID)
7662306a36Sopenharmony_ci			break;
7762306a36Sopenharmony_ci		node_set_online(nasid);
7862306a36Sopenharmony_ci		highest = node_scan_cpus(nasid, highest);
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	printk("Discovered %d cpus on %d nodes\n", highest + 1, num_online_nodes());
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic __init void intr_clear_all(nasid_t nasid)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	int i;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	REMOTE_HUB_S(nasid, PI_INT_MASK0_A, 0);
8962306a36Sopenharmony_ci	REMOTE_HUB_S(nasid, PI_INT_MASK0_B, 0);
9062306a36Sopenharmony_ci	REMOTE_HUB_S(nasid, PI_INT_MASK1_A, 0);
9162306a36Sopenharmony_ci	REMOTE_HUB_S(nasid, PI_INT_MASK1_B, 0);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	for (i = 0; i < 128; i++)
9462306a36Sopenharmony_ci		REMOTE_HUB_CLR_INTR(nasid, i);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void ip27_send_ipi_single(int destid, unsigned int action)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	int irq;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	switch (action) {
10262306a36Sopenharmony_ci	case SMP_RESCHEDULE_YOURSELF:
10362306a36Sopenharmony_ci		irq = CPU_RESCHED_A_IRQ;
10462306a36Sopenharmony_ci		break;
10562306a36Sopenharmony_ci	case SMP_CALL_FUNCTION:
10662306a36Sopenharmony_ci		irq = CPU_CALL_A_IRQ;
10762306a36Sopenharmony_ci		break;
10862306a36Sopenharmony_ci	default:
10962306a36Sopenharmony_ci		panic("sendintr");
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	irq += cputoslice(destid);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/*
11562306a36Sopenharmony_ci	 * Set the interrupt bit associated with the CPU we want to
11662306a36Sopenharmony_ci	 * send the interrupt to.
11762306a36Sopenharmony_ci	 */
11862306a36Sopenharmony_ci	REMOTE_HUB_SEND_INTR(cpu_to_node(destid), irq);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic void ip27_send_ipi_mask(const struct cpumask *mask, unsigned int action)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	unsigned int i;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	for_each_cpu(i, mask)
12662306a36Sopenharmony_ci		ip27_send_ipi_single(i, action);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic void ip27_init_cpu(void)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	per_cpu_init();
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic void ip27_smp_finish(void)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	hub_rt_clock_event_init();
13762306a36Sopenharmony_ci	local_irq_enable();
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/*
14162306a36Sopenharmony_ci * Launch a slave into smp_bootstrap().	 It doesn't take an argument, and we
14262306a36Sopenharmony_ci * set sp to the kernel stack of the newly created idle process, gp to the proc
14362306a36Sopenharmony_ci * struct so that current_thread_info() will work.
14462306a36Sopenharmony_ci */
14562306a36Sopenharmony_cistatic int ip27_boot_secondary(int cpu, struct task_struct *idle)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	unsigned long gp = (unsigned long)task_thread_info(idle);
14862306a36Sopenharmony_ci	unsigned long sp = __KSTK_TOS(idle);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	LAUNCH_SLAVE(cputonasid(cpu), cputoslice(cpu),
15162306a36Sopenharmony_ci		(launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap),
15262306a36Sopenharmony_ci		0, (void *) sp, (void *) gp);
15362306a36Sopenharmony_ci	return 0;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic void __init ip27_smp_setup(void)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	nasid_t nasid;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	for_each_online_node(nasid) {
16162306a36Sopenharmony_ci		if (nasid == 0)
16262306a36Sopenharmony_ci			continue;
16362306a36Sopenharmony_ci		intr_clear_all(nasid);
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	replicate_kernel_text();
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/*
16962306a36Sopenharmony_ci	 * PROM sets up system, that boot cpu is always first CPU on nasid 0
17062306a36Sopenharmony_ci	 */
17162306a36Sopenharmony_ci	cputonasid(0) = 0;
17262306a36Sopenharmony_ci	cputoslice(0) = LOCAL_HUB_L(PI_CPU_NUM);
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic void __init ip27_prepare_cpus(unsigned int max_cpus)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	/* We already did everything necessary earlier */
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ciconst struct plat_smp_ops ip27_smp_ops = {
18162306a36Sopenharmony_ci	.send_ipi_single	= ip27_send_ipi_single,
18262306a36Sopenharmony_ci	.send_ipi_mask		= ip27_send_ipi_mask,
18362306a36Sopenharmony_ci	.init_secondary		= ip27_init_cpu,
18462306a36Sopenharmony_ci	.smp_finish		= ip27_smp_finish,
18562306a36Sopenharmony_ci	.boot_secondary		= ip27_boot_secondary,
18662306a36Sopenharmony_ci	.smp_setup		= ip27_smp_setup,
18762306a36Sopenharmony_ci	.prepare_cpus		= ip27_prepare_cpus,
18862306a36Sopenharmony_ci	.prepare_boot_cpu	= ip27_init_cpu,
18962306a36Sopenharmony_ci};
190