18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * arch/ia64/kernel/machine_kexec.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Handle transition of Linux booting another kernel
68c2ecf20Sopenharmony_ci * Copyright (C) 2005 Hewlett-Packard Development Comapny, L.P.
78c2ecf20Sopenharmony_ci * Copyright (C) 2005 Khalid Aziz <khalid.aziz@hp.com>
88c2ecf20Sopenharmony_ci * Copyright (C) 2006 Intel Corp, Zou Nan hai <nanhai.zou@intel.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/mm.h>
128c2ecf20Sopenharmony_ci#include <linux/kexec.h>
138c2ecf20Sopenharmony_ci#include <linux/cpu.h>
148c2ecf20Sopenharmony_ci#include <linux/irq.h>
158c2ecf20Sopenharmony_ci#include <linux/efi.h>
168c2ecf20Sopenharmony_ci#include <linux/numa.h>
178c2ecf20Sopenharmony_ci#include <linux/mmzone.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <asm/numa.h>
208c2ecf20Sopenharmony_ci#include <asm/mmu_context.h>
218c2ecf20Sopenharmony_ci#include <asm/setup.h>
228c2ecf20Sopenharmony_ci#include <asm/delay.h>
238c2ecf20Sopenharmony_ci#include <asm/meminit.h>
248c2ecf20Sopenharmony_ci#include <asm/processor.h>
258c2ecf20Sopenharmony_ci#include <asm/sal.h>
268c2ecf20Sopenharmony_ci#include <asm/mca.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_citypedef void (*relocate_new_kernel_t)(
298c2ecf20Sopenharmony_ci					unsigned long indirection_page,
308c2ecf20Sopenharmony_ci					unsigned long start_address,
318c2ecf20Sopenharmony_ci					struct ia64_boot_param *boot_param,
328c2ecf20Sopenharmony_ci					unsigned long pal_addr) __noreturn;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct kimage *ia64_kimage;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistruct resource efi_memmap_res = {
378c2ecf20Sopenharmony_ci        .name  = "EFI Memory Map",
388c2ecf20Sopenharmony_ci        .start = 0,
398c2ecf20Sopenharmony_ci        .end   = 0,
408c2ecf20Sopenharmony_ci        .flags = IORESOURCE_BUSY | IORESOURCE_MEM
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistruct resource boot_param_res = {
448c2ecf20Sopenharmony_ci        .name  = "Boot parameter",
458c2ecf20Sopenharmony_ci        .start = 0,
468c2ecf20Sopenharmony_ci        .end   = 0,
478c2ecf20Sopenharmony_ci        .flags = IORESOURCE_BUSY | IORESOURCE_MEM
488c2ecf20Sopenharmony_ci};
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/*
528c2ecf20Sopenharmony_ci * Do what every setup is needed on image and the
538c2ecf20Sopenharmony_ci * reboot code buffer to allow us to avoid allocations
548c2ecf20Sopenharmony_ci * later.
558c2ecf20Sopenharmony_ci */
568c2ecf20Sopenharmony_ciint machine_kexec_prepare(struct kimage *image)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	void *control_code_buffer;
598c2ecf20Sopenharmony_ci	const unsigned long *func;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	func = (unsigned long *)&relocate_new_kernel;
628c2ecf20Sopenharmony_ci	/* Pre-load control code buffer to minimize work in kexec path */
638c2ecf20Sopenharmony_ci	control_code_buffer = page_address(image->control_code_page);
648c2ecf20Sopenharmony_ci	memcpy((void *)control_code_buffer, (const void *)func[0],
658c2ecf20Sopenharmony_ci			relocate_new_kernel_size);
668c2ecf20Sopenharmony_ci	flush_icache_range((unsigned long)control_code_buffer,
678c2ecf20Sopenharmony_ci			(unsigned long)control_code_buffer + relocate_new_kernel_size);
688c2ecf20Sopenharmony_ci	ia64_kimage = image;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	return 0;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_civoid machine_kexec_cleanup(struct kimage *image)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/*
788c2ecf20Sopenharmony_ci * Do not allocate memory (or fail in any way) in machine_kexec().
798c2ecf20Sopenharmony_ci * We are past the point of no return, committed to rebooting now.
808c2ecf20Sopenharmony_ci */
818c2ecf20Sopenharmony_cistatic void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct kimage *image = arg;
848c2ecf20Sopenharmony_ci	relocate_new_kernel_t rnk;
858c2ecf20Sopenharmony_ci	void *pal_addr = efi_get_pal_addr();
868c2ecf20Sopenharmony_ci	unsigned long code_addr;
878c2ecf20Sopenharmony_ci	int ii;
888c2ecf20Sopenharmony_ci	u64 fp, gp;
898c2ecf20Sopenharmony_ci	ia64_fptr_t *init_handler = (ia64_fptr_t *)ia64_os_init_on_kdump;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	BUG_ON(!image);
928c2ecf20Sopenharmony_ci	code_addr = (unsigned long)page_address(image->control_code_page);
938c2ecf20Sopenharmony_ci	if (image->type == KEXEC_TYPE_CRASH) {
948c2ecf20Sopenharmony_ci		crash_save_this_cpu();
958c2ecf20Sopenharmony_ci		current->thread.ksp = (__u64)info->sw - 16;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci		/* Register noop init handler */
988c2ecf20Sopenharmony_ci		fp = ia64_tpa(init_handler->fp);
998c2ecf20Sopenharmony_ci		gp = ia64_tpa(ia64_getreg(_IA64_REG_GP));
1008c2ecf20Sopenharmony_ci		ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, fp, gp, 0, fp, gp, 0);
1018c2ecf20Sopenharmony_ci	} else {
1028c2ecf20Sopenharmony_ci		/* Unregister init handlers of current kernel */
1038c2ecf20Sopenharmony_ci		ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, 0, 0, 0, 0, 0, 0);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	/* Unregister mca handler - No more recovery on current kernel */
1078c2ecf20Sopenharmony_ci	ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, 0, 0, 0, 0, 0, 0);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	/* Interrupts aren't acceptable while we reboot */
1108c2ecf20Sopenharmony_ci	local_irq_disable();
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	/* Mask CMC and Performance Monitor interrupts */
1138c2ecf20Sopenharmony_ci	ia64_setreg(_IA64_REG_CR_PMV, 1 << 16);
1148c2ecf20Sopenharmony_ci	ia64_setreg(_IA64_REG_CR_CMCV, 1 << 16);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	/* Mask ITV and Local Redirect Registers */
1178c2ecf20Sopenharmony_ci	ia64_set_itv(1 << 16);
1188c2ecf20Sopenharmony_ci	ia64_set_lrr0(1 << 16);
1198c2ecf20Sopenharmony_ci	ia64_set_lrr1(1 << 16);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* terminate possible nested in-service interrupts */
1228c2ecf20Sopenharmony_ci	for (ii = 0; ii < 16; ii++)
1238c2ecf20Sopenharmony_ci		ia64_eoi();
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	/* unmask TPR and clear any pending interrupts */
1268c2ecf20Sopenharmony_ci	ia64_setreg(_IA64_REG_CR_TPR, 0);
1278c2ecf20Sopenharmony_ci	ia64_srlz_d();
1288c2ecf20Sopenharmony_ci	while (ia64_get_ivr() != IA64_SPURIOUS_INT_VECTOR)
1298c2ecf20Sopenharmony_ci		ia64_eoi();
1308c2ecf20Sopenharmony_ci	rnk = (relocate_new_kernel_t)&code_addr;
1318c2ecf20Sopenharmony_ci	(*rnk)(image->head, image->start, ia64_boot_param,
1328c2ecf20Sopenharmony_ci		     GRANULEROUNDDOWN((unsigned long) pal_addr));
1338c2ecf20Sopenharmony_ci	BUG();
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_civoid machine_kexec(struct kimage *image)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	BUG_ON(!image);
1398c2ecf20Sopenharmony_ci	unw_init_running(ia64_machine_kexec, image);
1408c2ecf20Sopenharmony_ci	for(;;);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_civoid arch_crash_save_vmcoreinfo(void)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci#if defined(CONFIG_DISCONTIGMEM) || defined(CONFIG_SPARSEMEM)
1468c2ecf20Sopenharmony_ci	VMCOREINFO_SYMBOL(pgdat_list);
1478c2ecf20Sopenharmony_ci	VMCOREINFO_LENGTH(pgdat_list, MAX_NUMNODES);
1488c2ecf20Sopenharmony_ci#endif
1498c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
1508c2ecf20Sopenharmony_ci	VMCOREINFO_SYMBOL(node_memblk);
1518c2ecf20Sopenharmony_ci	VMCOREINFO_LENGTH(node_memblk, NR_NODE_MEMBLKS);
1528c2ecf20Sopenharmony_ci	VMCOREINFO_STRUCT_SIZE(node_memblk_s);
1538c2ecf20Sopenharmony_ci	VMCOREINFO_OFFSET(node_memblk_s, start_paddr);
1548c2ecf20Sopenharmony_ci	VMCOREINFO_OFFSET(node_memblk_s, size);
1558c2ecf20Sopenharmony_ci#endif
1568c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS == 3
1578c2ecf20Sopenharmony_ci	VMCOREINFO_CONFIG(PGTABLE_3);
1588c2ecf20Sopenharmony_ci#elif CONFIG_PGTABLE_LEVELS == 4
1598c2ecf20Sopenharmony_ci	VMCOREINFO_CONFIG(PGTABLE_4);
1608c2ecf20Sopenharmony_ci#endif
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
163