18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Ported from IRIX to Linux by Kanoj Sarcar, 06/08/00.
48c2ecf20Sopenharmony_ci * Copyright 2000 - 2001 Silicon Graphics, Inc.
58c2ecf20Sopenharmony_ci * Copyright 2000 - 2001 Kanoj Sarcar (kanoj@sgi.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/init.h>
88c2ecf20Sopenharmony_ci#include <linux/mm.h>
98c2ecf20Sopenharmony_ci#include <linux/mmzone.h>
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/nodemask.h>
128c2ecf20Sopenharmony_ci#include <linux/string.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <asm/page.h>
158c2ecf20Sopenharmony_ci#include <asm/sections.h>
168c2ecf20Sopenharmony_ci#include <asm/sn/types.h>
178c2ecf20Sopenharmony_ci#include <asm/sn/arch.h>
188c2ecf20Sopenharmony_ci#include <asm/sn/gda.h>
198c2ecf20Sopenharmony_ci#include <asm/sn/mapped_kernel.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "ip27-common.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic nodemask_t ktext_repmask;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/*
268c2ecf20Sopenharmony_ci * XXX - This needs to be much smarter about where it puts copies of the
278c2ecf20Sopenharmony_ci * kernel.  For example, we should never put a copy on a headless node,
288c2ecf20Sopenharmony_ci * and we should respect the topology of the machine.
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_civoid __init setup_replication_mask(void)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	/* Set only the master cnode's bit.  The master cnode is always 0. */
338c2ecf20Sopenharmony_ci	nodes_clear(ktext_repmask);
348c2ecf20Sopenharmony_ci	node_set(0, ktext_repmask);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#ifdef CONFIG_REPLICATE_KTEXT
378c2ecf20Sopenharmony_ci#ifndef CONFIG_MAPPED_KERNEL
388c2ecf20Sopenharmony_ci#error Kernel replication works with mapped kernel support. No calias support.
398c2ecf20Sopenharmony_ci#endif
408c2ecf20Sopenharmony_ci	{
418c2ecf20Sopenharmony_ci		nasid_t nasid;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci		for_each_online_node(nasid) {
448c2ecf20Sopenharmony_ci			if (nasid == 0)
458c2ecf20Sopenharmony_ci				continue;
468c2ecf20Sopenharmony_ci			/* Advertise that we have a copy of the kernel */
478c2ecf20Sopenharmony_ci			node_set(nasid, ktext_repmask);
488c2ecf20Sopenharmony_ci		}
498c2ecf20Sopenharmony_ci	}
508c2ecf20Sopenharmony_ci#endif
518c2ecf20Sopenharmony_ci	/* Set up a GDA pointer to the replication mask. */
528c2ecf20Sopenharmony_ci	GDA->g_ktext_repmask = &ktext_repmask;
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic __init void set_ktext_source(nasid_t client_nasid, nasid_t server_nasid)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	kern_vars_t *kvp;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	kvp = &hub_data(client_nasid)->kern_vars;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	KERN_VARS_ADDR(client_nasid) = (unsigned long)kvp;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	kvp->kv_magic = KV_MAGIC;
658c2ecf20Sopenharmony_ci	kvp->kv_ro_nasid = server_nasid;
668c2ecf20Sopenharmony_ci	kvp->kv_rw_nasid = master_nasid;
678c2ecf20Sopenharmony_ci	kvp->kv_ro_baseaddr = NODE_CAC_BASE(server_nasid);
688c2ecf20Sopenharmony_ci	kvp->kv_rw_baseaddr = NODE_CAC_BASE(master_nasid);
698c2ecf20Sopenharmony_ci	printk("REPLICATION: ON nasid %d, ktext from nasid %d, kdata from nasid %d\n", client_nasid, server_nasid, master_nasid);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/* XXX - When the BTE works, we should use it instead of this. */
738c2ecf20Sopenharmony_cistatic __init void copy_kernel(nasid_t dest_nasid)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	unsigned long dest_kern_start, source_start, source_end, kern_size;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	source_start = (unsigned long) _stext;
788c2ecf20Sopenharmony_ci	source_end = (unsigned long) _etext;
798c2ecf20Sopenharmony_ci	kern_size = source_end - source_start;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	dest_kern_start = CHANGE_ADDR_NASID(MAPPED_KERN_RO_TO_K0(source_start),
828c2ecf20Sopenharmony_ci					    dest_nasid);
838c2ecf20Sopenharmony_ci	memcpy((void *)dest_kern_start, (void *)source_start, kern_size);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_civoid __init replicate_kernel_text(void)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	nasid_t client_nasid;
898c2ecf20Sopenharmony_ci	nasid_t server_nasid;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	server_nasid = master_nasid;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	/* Record where the master node should get its kernel text */
948c2ecf20Sopenharmony_ci	set_ktext_source(master_nasid, master_nasid);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	for_each_online_node(client_nasid) {
978c2ecf20Sopenharmony_ci		if (client_nasid == 0)
988c2ecf20Sopenharmony_ci			continue;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci		/* Check if this node should get a copy of the kernel */
1018c2ecf20Sopenharmony_ci		if (node_isset(client_nasid, ktext_repmask)) {
1028c2ecf20Sopenharmony_ci			server_nasid = client_nasid;
1038c2ecf20Sopenharmony_ci			copy_kernel(server_nasid);
1048c2ecf20Sopenharmony_ci		}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci		/* Record where this node should get its kernel text */
1078c2ecf20Sopenharmony_ci		set_ktext_source(client_nasid, server_nasid);
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/*
1128c2ecf20Sopenharmony_ci * Return pfn of first free page of memory on a node. PROM may allocate
1138c2ecf20Sopenharmony_ci * data structures on the first couple of pages of the first slot of each
1148c2ecf20Sopenharmony_ci * node. If this is the case, getfirstfree(node) > getslotstart(node, 0).
1158c2ecf20Sopenharmony_ci */
1168c2ecf20Sopenharmony_ciunsigned long node_getfirstfree(nasid_t nasid)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	unsigned long loadbase = REP_BASE;
1198c2ecf20Sopenharmony_ci	unsigned long offset;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci#ifdef CONFIG_MAPPED_KERNEL
1228c2ecf20Sopenharmony_ci	loadbase += 16777216;
1238c2ecf20Sopenharmony_ci#endif
1248c2ecf20Sopenharmony_ci	offset = PAGE_ALIGN((unsigned long)(&_end)) - loadbase;
1258c2ecf20Sopenharmony_ci	if ((nasid == 0) || (node_isset(nasid, ktext_repmask)))
1268c2ecf20Sopenharmony_ci		return TO_NODE(nasid, offset) >> PAGE_SHIFT;
1278c2ecf20Sopenharmony_ci	else
1288c2ecf20Sopenharmony_ci		return KDM_TO_PHYS(PAGE_ALIGN(SYMMON_STK_ADDR(nasid, 0))) >> PAGE_SHIFT;
1298c2ecf20Sopenharmony_ci}
130