18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General
38c2ecf20Sopenharmony_ci * Public License.  See the file "COPYING" in the main directory of this
48c2ecf20Sopenharmony_ci * archive for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com)
78c2ecf20Sopenharmony_ci * Copyright (C) 2000 - 2001 by Silicon Graphics, Inc.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/sched.h>
128c2ecf20Sopenharmony_ci#include <linux/smp.h>
138c2ecf20Sopenharmony_ci#include <linux/mm.h>
148c2ecf20Sopenharmony_ci#include <linux/export.h>
158c2ecf20Sopenharmony_ci#include <linux/cpumask.h>
168c2ecf20Sopenharmony_ci#include <asm/bootinfo.h>
178c2ecf20Sopenharmony_ci#include <asm/cpu.h>
188c2ecf20Sopenharmony_ci#include <asm/io.h>
198c2ecf20Sopenharmony_ci#include <asm/sgialib.h>
208c2ecf20Sopenharmony_ci#include <asm/time.h>
218c2ecf20Sopenharmony_ci#include <asm/sn/agent.h>
228c2ecf20Sopenharmony_ci#include <asm/sn/types.h>
238c2ecf20Sopenharmony_ci#include <asm/sn/klconfig.h>
248c2ecf20Sopenharmony_ci#include <asm/sn/ioc3.h>
258c2ecf20Sopenharmony_ci#include <asm/mipsregs.h>
268c2ecf20Sopenharmony_ci#include <asm/sn/gda.h>
278c2ecf20Sopenharmony_ci#include <asm/sn/intr.h>
288c2ecf20Sopenharmony_ci#include <asm/current.h>
298c2ecf20Sopenharmony_ci#include <asm/processor.h>
308c2ecf20Sopenharmony_ci#include <asm/mmu_context.h>
318c2ecf20Sopenharmony_ci#include <asm/thread_info.h>
328c2ecf20Sopenharmony_ci#include <asm/sn/launch.h>
338c2ecf20Sopenharmony_ci#include <asm/sn/mapped_kernel.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include "ip27-common.h"
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#define CPU_NONE		(cpuid_t)-1
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic DECLARE_BITMAP(hub_init_mask, MAX_NUMNODES);
408c2ecf20Sopenharmony_cinasid_t master_nasid = INVALID_NASID;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct cpuinfo_ip27 sn_cpu_info[NR_CPUS];
438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sn_cpu_info);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic void per_hub_init(nasid_t nasid)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	struct hub_data *hub = hub_data(nasid);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	cpumask_set_cpu(smp_processor_id(), &hub->h_cpus);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	if (test_and_set_bit(nasid, hub_init_mask))
528c2ecf20Sopenharmony_ci		return;
538c2ecf20Sopenharmony_ci	/*
548c2ecf20Sopenharmony_ci	 * Set CRB timeout at 5ms, (< PI timeout of 10ms)
558c2ecf20Sopenharmony_ci	 */
568c2ecf20Sopenharmony_ci	REMOTE_HUB_S(nasid, IIO_ICTP, 0x800);
578c2ecf20Sopenharmony_ci	REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	hub_rtc_init(nasid);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	if (nasid) {
628c2ecf20Sopenharmony_ci		/* copy exception handlers from first node to current node */
638c2ecf20Sopenharmony_ci		memcpy((void *)NODE_OFFSET_TO_K0(nasid, 0),
648c2ecf20Sopenharmony_ci		       (void *)CKSEG0, 0x200);
658c2ecf20Sopenharmony_ci		__flush_cache_all();
668c2ecf20Sopenharmony_ci		/* switch to node local exception handlers */
678c2ecf20Sopenharmony_ci		REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K);
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_civoid per_cpu_init(void)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	int cpu = smp_processor_id();
748c2ecf20Sopenharmony_ci	nasid_t nasid = get_nasid();
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	clear_c0_status(ST0_IM);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	per_hub_init(nasid);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	pr_info("CPU %d clock is %dMHz.\n", cpu, sn_cpu_info[cpu].p_speed);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	install_ipi();
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	/* Install our NMI handler if symmon hasn't installed one. */
858c2ecf20Sopenharmony_ci	install_cpu_nmi_handler(cputoslice(cpu));
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	enable_percpu_irq(IP27_HUB_PEND0_IRQ, IRQ_TYPE_NONE);
888c2ecf20Sopenharmony_ci	enable_percpu_irq(IP27_HUB_PEND1_IRQ, IRQ_TYPE_NONE);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_civoid __init plat_mem_setup(void)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	u64 p, e, n_mode;
948c2ecf20Sopenharmony_ci	nasid_t nid;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	register_smp_ops(&ip27_smp_ops);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	ip27_reboot_setup();
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	/*
1018c2ecf20Sopenharmony_ci	 * hub_rtc init and cpu clock intr enabled for later calibrate_delay.
1028c2ecf20Sopenharmony_ci	 */
1038c2ecf20Sopenharmony_ci	nid = get_nasid();
1048c2ecf20Sopenharmony_ci	printk("IP27: Running on node %d.\n", nid);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	p = LOCAL_HUB_L(PI_CPU_PRESENT_A) & 1;
1078c2ecf20Sopenharmony_ci	e = LOCAL_HUB_L(PI_CPU_ENABLE_A) & 1;
1088c2ecf20Sopenharmony_ci	printk("Node %d has %s primary CPU%s.\n", nid,
1098c2ecf20Sopenharmony_ci	       p ? "a" : "no",
1108c2ecf20Sopenharmony_ci	       e ? ", CPU is running" : "");
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	p = LOCAL_HUB_L(PI_CPU_PRESENT_B) & 1;
1138c2ecf20Sopenharmony_ci	e = LOCAL_HUB_L(PI_CPU_ENABLE_B) & 1;
1148c2ecf20Sopenharmony_ci	printk("Node %d has %s secondary CPU%s.\n", nid,
1158c2ecf20Sopenharmony_ci	       p ? "a" : "no",
1168c2ecf20Sopenharmony_ci	       e ? ", CPU is running" : "");
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/*
1198c2ecf20Sopenharmony_ci	 * Try to catch kernel missconfigurations and give user an
1208c2ecf20Sopenharmony_ci	 * indication what option to select.
1218c2ecf20Sopenharmony_ci	 */
1228c2ecf20Sopenharmony_ci	n_mode = LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_MORENODES_MASK;
1238c2ecf20Sopenharmony_ci	printk("Machine is in %c mode.\n", n_mode ? 'N' : 'M');
1248c2ecf20Sopenharmony_ci#ifdef CONFIG_SGI_SN_N_MODE
1258c2ecf20Sopenharmony_ci	if (!n_mode)
1268c2ecf20Sopenharmony_ci		panic("Kernel compiled for M mode.");
1278c2ecf20Sopenharmony_ci#else
1288c2ecf20Sopenharmony_ci	if (n_mode)
1298c2ecf20Sopenharmony_ci		panic("Kernel compiled for N mode.");
1308c2ecf20Sopenharmony_ci#endif
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	ioport_resource.start = 0;
1338c2ecf20Sopenharmony_ci	ioport_resource.end = ~0UL;
1348c2ecf20Sopenharmony_ci	set_io_port_base(IO_BASE);
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ciconst char *get_system_type(void)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	return "SGI Origin";
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_civoid __init prom_init(void)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	prom_init_cmdline(fw_arg0, (LONG *)fw_arg1);
1458c2ecf20Sopenharmony_ci	prom_meminit();
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
148