efi.c revision 965e7c8affeca27f7e5de75c97954e74d3b8052d
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Extensible Firmware Interface
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
47d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * Based on Extensible Firmware Interface Specification version 0.9
57d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * April 30, 1999
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999 VA Linux Systems
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999-2003 Hewlett-Packard Co.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	David Mosberger-Tang <davidm@hpl.hp.com>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Stephane Eranian <eranian@hpl.hp.com>
1232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * (c) Copyright 2006 Hewlett-Packard Development Company, L.P.
1332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas *	Bjorn Helgaas <bjorn.helgaas@hp.com>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All EFI Runtime Services are not implemented yet as EFI only
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * supports physical mode addressing on SoftSDV. This is to be fixed
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in a future version.  --drummond 1999-07-20
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Implemented EFI runtime services and virtual mode calls.  --davidm
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Goutham Rao: <goutham.rao@intel.com>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Skip non-WB memory and ignore empty memory ranges.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
25f4a570997e71b892805a1e71303d09c327af135fHorms#include <linux/bootmem.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/time.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/efi.h>
31a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai#include <linux/kexec.h>
32ed7ed365172e27b0efe9d43cc962723c7193e34eMel Gorman#include <linux/mm.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/kregs.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/meminit.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/processor.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mca.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EFI_DEBUG	0
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern efi_status_t efi_call_phys (void *, ...);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct efi efi;
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(efi);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic efi_runtime_services_t *runtime;
48a79561134f38de12dce14ed72138f38e55ef53fcZou Nan haistatic unsigned long mem_limit = ~0UL, max_addr = ~0UL, min_addr = 0UL;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define efi_call_virt(f, args...)	(*(f))(args)
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
527d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_GET_TIME(prefix, adjust_arg)				       \
537d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t							       \
547d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc)			       \
557d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{									       \
567d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	struct ia64_fpreg fr[6];					       \
577d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_time_cap_t *atc = NULL;					       \
587d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_status_t ret;						       \
597d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis									       \
607d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	if (tc)								       \
617d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		atc = adjust_arg(tc);					       \
627d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_save_scratch_fpregs(fr);					       \
637d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time),    \
647d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				adjust_arg(tm), atc);			       \
657d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_load_scratch_fpregs(fr);					       \
667d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	return ret;							       \
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
697d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_SET_TIME(prefix, adjust_arg)				       \
707d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t							       \
717d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_set_time (efi_time_t *tm)					       \
727d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{									       \
737d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	struct ia64_fpreg fr[6];					       \
747d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_status_t ret;						       \
757d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis									       \
767d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_save_scratch_fpregs(fr);					       \
777d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ret = efi_call_##prefix((efi_set_time_t *) __va(runtime->set_time),    \
787d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				adjust_arg(tm));			       \
797d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_load_scratch_fpregs(fr);					       \
807d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	return ret;							       \
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
837d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_GET_WAKEUP_TIME(prefix, adjust_arg)			       \
847d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t							       \
857d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending,	       \
867d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			  efi_time_t *tm)				       \
877d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{									       \
887d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	struct ia64_fpreg fr[6];					       \
897d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_status_t ret;						       \
907d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis									       \
917d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_save_scratch_fpregs(fr);					       \
927d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ret = efi_call_##prefix(					       \
937d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		(efi_get_wakeup_time_t *) __va(runtime->get_wakeup_time),      \
947d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		adjust_arg(enabled), adjust_arg(pending), adjust_arg(tm));     \
957d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_load_scratch_fpregs(fr);					       \
967d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	return ret;							       \
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
997d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_SET_WAKEUP_TIME(prefix, adjust_arg)			       \
1007d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t							       \
1017d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)		       \
1027d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{									       \
1037d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	struct ia64_fpreg fr[6];					       \
1047d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_time_t *atm = NULL;						       \
1057d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_status_t ret;						       \
1067d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis									       \
1077d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	if (tm)								       \
1087d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		atm = adjust_arg(tm);					       \
1097d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_save_scratch_fpregs(fr);					       \
1107d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ret = efi_call_##prefix(					       \
1117d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		(efi_set_wakeup_time_t *) __va(runtime->set_wakeup_time),      \
1127d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		enabled, atm);						       \
1137d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_load_scratch_fpregs(fr);					       \
1147d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	return ret;							       \
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1177d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_GET_VARIABLE(prefix, adjust_arg)				       \
1187d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t							       \
1197d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,      \
1207d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		       unsigned long *data_size, void *data)		       \
1217d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{									       \
1227d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	struct ia64_fpreg fr[6];					       \
1237d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	u32 *aattr = NULL;						       \
1247d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_status_t ret;						       \
1257d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis									       \
1267d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	if (attr)							       \
1277d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		aattr = adjust_arg(attr);				       \
1287d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_save_scratch_fpregs(fr);					       \
1297d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ret = efi_call_##prefix(					       \
1307d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		(efi_get_variable_t *) __va(runtime->get_variable),	       \
1317d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		adjust_arg(name), adjust_arg(vendor), aattr,		       \
1327d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		adjust_arg(data_size), adjust_arg(data));		       \
1337d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_load_scratch_fpregs(fr);					       \
1347d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	return ret;							       \
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1377d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_GET_NEXT_VARIABLE(prefix, adjust_arg)			       \
1387d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t							       \
1397d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name,      \
1407d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			    efi_guid_t *vendor)				       \
1417d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{									       \
1427d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	struct ia64_fpreg fr[6];					       \
1437d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_status_t ret;						       \
1447d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis									       \
1457d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_save_scratch_fpregs(fr);					       \
1467d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ret = efi_call_##prefix(					       \
1477d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		(efi_get_next_variable_t *) __va(runtime->get_next_variable),  \
1487d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		adjust_arg(name_size), adjust_arg(name), adjust_arg(vendor));  \
1497d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_load_scratch_fpregs(fr);					       \
1507d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	return ret;							       \
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1537d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_SET_VARIABLE(prefix, adjust_arg)				       \
1547d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t							       \
1557d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor,		       \
1567d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		       unsigned long attr, unsigned long data_size,	       \
1577d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		       void *data)					       \
1587d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{									       \
1597d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	struct ia64_fpreg fr[6];					       \
1607d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_status_t ret;						       \
1617d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis									       \
1627d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_save_scratch_fpregs(fr);					       \
1637d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ret = efi_call_##prefix(					       \
1647d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		(efi_set_variable_t *) __va(runtime->set_variable),	       \
1657d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		adjust_arg(name), adjust_arg(vendor), attr, data_size,	       \
1667d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		adjust_arg(data));					       \
1677d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_load_scratch_fpregs(fr);					       \
1687d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	return ret;							       \
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1717d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_GET_NEXT_HIGH_MONO_COUNT(prefix, adjust_arg)		       \
1727d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t							       \
1737d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_get_next_high_mono_count (u32 *count)				       \
1747d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{									       \
1757d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	struct ia64_fpreg fr[6];					       \
1767d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_status_t ret;						       \
1777d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis									       \
1787d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_save_scratch_fpregs(fr);					       \
1797d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ret = efi_call_##prefix((efi_get_next_high_mono_count_t *)	       \
1807d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				__va(runtime->get_next_high_mono_count),       \
1817d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				adjust_arg(count));			       \
1827d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_load_scratch_fpregs(fr);					       \
1837d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	return ret;							       \
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1867d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_RESET_SYSTEM(prefix, adjust_arg)				       \
1877d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic void								       \
1887d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_reset_system (int reset_type, efi_status_t status,		       \
1897d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		       unsigned long data_size, efi_char16_t *data)	       \
1907d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{									       \
1917d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	struct ia64_fpreg fr[6];					       \
1927d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_char16_t *adata = NULL;					       \
1937d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis									       \
1947d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	if (data)							       \
1957d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		adata = adjust_arg(data);				       \
1967d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis									       \
1977d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_save_scratch_fpregs(fr);					       \
1987d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_call_##prefix(						       \
1997d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		(efi_reset_system_t *) __va(runtime->reset_system),	       \
2007d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		reset_type, status, data_size, adata);			       \
2017d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	/* should not return, but just in case... */			       \
2027d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_load_scratch_fpregs(fr);					       \
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define phys_ptr(arg)	((__typeof__(arg)) ia64_tpa(arg))
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_TIME(phys, phys_ptr)
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_SET_TIME(phys, phys_ptr)
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_WAKEUP_TIME(phys, phys_ptr)
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_SET_WAKEUP_TIME(phys, phys_ptr)
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_VARIABLE(phys, phys_ptr)
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_NEXT_VARIABLE(phys, phys_ptr)
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_SET_VARIABLE(phys, phys_ptr)
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_NEXT_HIGH_MONO_COUNT(phys, phys_ptr)
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_RESET_SYSTEM(phys, phys_ptr)
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define id(arg)	arg
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_TIME(virt, id)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_SET_TIME(virt, id)
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_WAKEUP_TIME(virt, id)
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_SET_WAKEUP_TIME(virt, id)
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_VARIABLE(virt, id)
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_NEXT_VARIABLE(virt, id)
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_SET_VARIABLE(virt, id)
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_NEXT_HIGH_MONO_COUNT(virt, id)
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_RESET_SYSTEM(virt, id)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_gettimeofday (struct timespec *ts)
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_time_t tm;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2344b07ae9b9d7b05a63e3ece32a666041949b7f421Li Zefan	if ((*efi.get_time)(&tm, NULL) != EFI_SUCCESS) {
2354b07ae9b9d7b05a63e3ece32a666041949b7f421Li Zefan		memset(ts, 0, sizeof(*ts));
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2374b07ae9b9d7b05a63e3ece32a666041949b7f421Li Zefan	}
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2397d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ts->tv_sec = mktime(tm.year, tm.month, tm.day,
2407d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			    tm.hour, tm.minute, tm.second);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ts->tv_nsec = tm.nanosecond;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
24566888a6e5ffc756b9a4115fc766ee2258eefb928Christoph Lameteris_memory_available (efi_memory_desc_t *md)
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(md->attribute & EFI_MEMORY_WB))
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (md->type) {
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      case EFI_LOADER_CODE:
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      case EFI_LOADER_DATA:
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      case EFI_BOOT_SERVICES_CODE:
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      case EFI_BOOT_SERVICES_DATA:
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      case EFI_CONVENTIONAL_MEMORY:
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Lucktypedef struct kern_memdesc {
262d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	u64 attribute;
263d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	u64 start;
264d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	u64 num_pages;
265d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck} kern_memdesc_t;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
267d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckstatic kern_memdesc_t *kern_memmap;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26980851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas#define efi_md_size(md)	(md->num_pages << EFI_PAGE_SHIFT)
27080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
27180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasstatic inline u64
27280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaaskmd_end(kern_memdesc_t *kmd)
27380851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{
27480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	return (kmd->start + (kmd->num_pages << EFI_PAGE_SHIFT));
27580851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas}
27680851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
27780851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasstatic inline u64
27880851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasefi_md_end(efi_memory_desc_t *md)
27980851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{
28080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	return (md->phys_addr + efi_md_size(md));
28180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas}
28280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
28380851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasstatic inline int
28480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasefi_wb(efi_memory_desc_t *md)
28580851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{
28680851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	return (md->attribute & EFI_MEMORY_WB);
28780851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas}
28880851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
28980851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasstatic inline int
29080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasefi_uc(efi_memory_desc_t *md)
29180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{
29280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	return (md->attribute & EFI_MEMORY_UC);
29380851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas}
29480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
296d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckwalk (efi_freemem_callback_t callback, void *arg, u64 attr)
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
298d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	kern_memdesc_t *k;
299d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	u64 start, end, voff;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	voff = (attr == EFI_MEMORY_WB) ? PAGE_OFFSET : __IA64_UNCACHED_OFFSET;
302d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	for (k = kern_memmap; k->start != ~0UL; k++) {
303d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (k->attribute != attr)
304d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			continue;
305d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		start = PAGE_ALIGN(k->start);
306d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		end = (k->start + (k->num_pages << EFI_PAGE_SHIFT)) & PAGE_MASK;
307d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (start < end)
308d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			if ((*callback)(start + voff, end + voff, arg) < 0)
309d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				return;
310d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	}
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
314965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis * Walk the EFI memory map and call CALLBACK once for each EFI memory
3157d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * descriptor that has memory that is available for OS use.
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_memmap_walk (efi_freemem_callback_t callback, void *arg)
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
320d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	walk(callback, arg, EFI_MEMORY_WB);
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
324965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis * Walk the EFI memory map and call CALLBACK once for each EFI memory
3257d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * descriptor that has memory that is available for uncached allocator.
326f14f75b81187cdbe10cc53a521bf9fdf97b59f8cJes Sorensen */
327d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckvoid
328d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckefi_memmap_walk_uc (efi_freemem_callback_t callback, void *arg)
329f14f75b81187cdbe10cc53a521bf9fdf97b59f8cJes Sorensen{
330d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	walk(callback, arg, EFI_MEMORY_UC);
331f14f75b81187cdbe10cc53a521bf9fdf97b59f8cJes Sorensen}
332f14f75b81187cdbe10cc53a521bf9fdf97b59f8cJes Sorensen
333f14f75b81187cdbe10cc53a521bf9fdf97b59f8cJes Sorensen/*
334965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis * Look for the PAL_CODE region reported by EFI and map it using an
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ITR to enable safe PAL calls in virtual mode.  See IA-64 Processor
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Abstraction Layer chapter 11 in ADAG
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid *
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_get_pal_addr (void)
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *efi_map_start, *efi_map_end, *p;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_memory_desc_t *md;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 efi_desc_size;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pal_code_count = 0;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 vaddr, mask;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_map_start = __va(ia64_boot_param->efi_memmap);
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_desc_size = ia64_boot_param->efi_memdesc_size;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		md = p;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (md->type != EFI_PAL_CODE)
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (++pal_code_count > 1) {
3577d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			printk(KERN_ERR "Too many EFI Pal Code memory ranges, "
3587d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			       "dropped @ %lx\n", md->phys_addr);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
3627d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 * The only ITLB entry in region 7 that is used is the one
3637d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 * installed by __start().  That entry covers a 64MB range.
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask  = ~((1 << KERNEL_TR_PAGE_SHIFT) - 1);
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vaddr = PAGE_OFFSET + md->phys_addr;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
3697d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 * We must check that the PAL mapping won't overlap with the
3707d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 * kernel mapping.
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
3727d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 * PAL code is guaranteed to be aligned on a power of 2 between
3737d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 * 4k and 256KB and that only one ITR is needed to map it. This
3747d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 * implies that the PAL code is always aligned on its size,
3757d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 * i.e., the closest matching page size supported by the TLB.
3767d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 * Therefore PAL code is guaranteed never to cross a 64MB unless
3777d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 * it is bigger than 64MB (very unlikely!).  So for now the
3787d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 * following test is enough to determine whether or not we need
3797d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 * a dedicated ITR for the PAL code.
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((vaddr & mask) == (KERNEL_START & mask)) {
3827d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			printk(KERN_INFO "%s: no need to install ITR for "
3837d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			       "PAL code\n", __FUNCTION__);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
387685c7f5d3629d558b17ee193b6d7f194e82aadf0Li Zefan		if (efi_md_size(md) > IA64_GRANULE_SIZE)
388965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis			panic("Whoa!  PAL code size bigger than a granule!");
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EFI_DEBUG
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask  = ~((1 << IA64_GRANULE_SHIFT) - 1);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3937d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		printk(KERN_INFO "CPU %d: mapping PAL code "
3947d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis                       "[0x%lx-0x%lx) into [0x%lx-0x%lx)\n",
3957d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis                       smp_processor_id(), md->phys_addr,
3967d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis                       md->phys_addr + efi_md_size(md),
3977d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis                       vaddr & mask, (vaddr & mask) + IA64_GRANULE_SIZE);
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return __va(md->phys_addr);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4019473252f20e8482464415d9030b3957b5593796dHorms	printk(KERN_WARNING "%s: no PAL-code memory-descriptor found\n",
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       __FUNCTION__);
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_map_pal_code (void)
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *pal_vaddr = efi_get_pal_addr ();
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 psr;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pal_vaddr)
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Cannot write to CRx with PSR.ic=1
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psr = ia64_clear_ic();
4197d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	ia64_itr(0x1, IA64_TR_PALCODE,
4207d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		 GRANULEROUNDDOWN((unsigned long) pal_vaddr),
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 pte_val(pfn_pte(__pa(pal_vaddr) >> PAGE_SHIFT, PAGE_KERNEL)),
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 IA64_GRANULE_SHIFT);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ia64_set_psr(psr);		/* restore psr */
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ia64_srlz_i();
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_init (void)
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *efi_map_start, *efi_map_end;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_config_table_t *config_tables;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_char16_t *c16;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 efi_desc_size;
4349d78f43d1fd3e028bfd37510ce847d0896f71f78Zou Nan hai	char *cp, vendor[100] = "unknown";
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4377d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	/*
438965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis	 * It's too early to be able to use the standard kernel command line
4397d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	 * support...
4407d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	 */
441a8d91b8477aa433ee0131b031d782411976e1726Alon Bar-Lev	for (cp = boot_command_line; *cp; ) {
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (memcmp(cp, "mem=", 4) == 0) {
4439d78f43d1fd3e028bfd37510ce847d0896f71f78Zou Nan hai			mem_limit = memparse(cp + 4, &cp);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (memcmp(cp, "max_addr=", 9) == 0) {
4459d78f43d1fd3e028bfd37510ce847d0896f71f78Zou Nan hai			max_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp));
446a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai		} else if (memcmp(cp, "min_addr=", 9) == 0) {
447a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai			min_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp));
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (*cp != ' ' && *cp)
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				++cp;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (*cp == ' ')
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				++cp;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
455a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai	if (min_addr != 0UL)
4567d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		printk(KERN_INFO "Ignoring memory below %luMB\n",
4577d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		       min_addr >> 20);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (max_addr != ~0UL)
4597d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		printk(KERN_INFO "Ignoring memory above %luMB\n",
4607d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		       max_addr >> 20);
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.systab = __va(ia64_boot_param->efi_systab);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Verify the EFI Table
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (efi.systab == NULL)
468965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis		panic("Whoa! Can't find EFI system table.\n");
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
470965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis		panic("Whoa! EFI system table signature incorrect\n");
471873ec746158403af82c57ce26780166aafc159e1Bjorn Helgaas	if ((efi.systab->hdr.revision >> 16) == 0)
472873ec746158403af82c57ce26780166aafc159e1Bjorn Helgaas		printk(KERN_WARNING "Warning: EFI system table version "
473873ec746158403af82c57ce26780166aafc159e1Bjorn Helgaas		       "%d.%02d, expected 1.00 or greater\n",
474873ec746158403af82c57ce26780166aafc159e1Bjorn Helgaas		       efi.systab->hdr.revision >> 16,
475873ec746158403af82c57ce26780166aafc159e1Bjorn Helgaas		       efi.systab->hdr.revision & 0xffff);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	config_tables = __va(efi.systab->tables);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Show what we know for posterity */
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c16 = __va(efi.systab->fw_vendor);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (c16) {
482ecdd5dabd33d67066d476467e447cdcadab90550Zou Nan hai		for (i = 0;i < (int) sizeof(vendor) - 1 && *c16; ++i)
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			vendor[i] = *c16++;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vendor[i] = '\0';
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "EFI v%u.%.02u by %s:",
4887d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	       efi.systab->hdr.revision >> 16,
4897d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	       efi.systab->hdr.revision & 0xffff, vendor);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas	efi.mps        = EFI_INVALID_TABLE_ADDR;
492b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas	efi.acpi       = EFI_INVALID_TABLE_ADDR;
493b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas	efi.acpi20     = EFI_INVALID_TABLE_ADDR;
494b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas	efi.smbios     = EFI_INVALID_TABLE_ADDR;
495b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas	efi.sal_systab = EFI_INVALID_TABLE_ADDR;
496b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas	efi.boot_info  = EFI_INVALID_TABLE_ADDR;
497b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas	efi.hcdp       = EFI_INVALID_TABLE_ADDR;
498b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas	efi.uga        = EFI_INVALID_TABLE_ADDR;
499b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < (int) efi.systab->nr_tables; i++) {
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) {
502b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas			efi.mps = config_tables[i].table;
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" MPS=0x%lx", config_tables[i].table);
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) {
505b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas			efi.acpi20 = config_tables[i].table;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" ACPI 2.0=0x%lx", config_tables[i].table);
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) {
508b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas			efi.acpi = config_tables[i].table;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" ACPI=0x%lx", config_tables[i].table);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) {
511b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas			efi.smbios = config_tables[i].table;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" SMBIOS=0x%lx", config_tables[i].table);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) {
514b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas			efi.sal_systab = config_tables[i].table;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" SALsystab=0x%lx", config_tables[i].table);
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
517b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas			efi.hcdp = config_tables[i].table;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" HCDP=0x%lx", config_tables[i].table);
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("\n");
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	runtime = __va(efi.systab->runtime);
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.get_time = phys_get_time;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.set_time = phys_set_time;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.get_wakeup_time = phys_get_wakeup_time;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.set_wakeup_time = phys_set_wakeup_time;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.get_variable = phys_get_variable;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.get_next_variable = phys_get_next_variable;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.set_variable = phys_set_variable;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.get_next_high_mono_count = phys_get_next_high_mono_count;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.reset_system = phys_reset_system;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_map_start = __va(ia64_boot_param->efi_memmap);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_desc_size = ia64_boot_param->efi_memdesc_size;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EFI_DEBUG
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* print EFI memory map: */
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		efi_memory_desc_t *md;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		void *p;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5447d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		for (i = 0, p = efi_map_start; p < efi_map_end;
5457d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		     ++i, p += efi_desc_size)
5467d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		{
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			md = p;
5487d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			printk("mem%02u: type=%u, attr=0x%lx, "
5497d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			       "range=[0x%016lx-0x%016lx) (%luMB)\n",
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       i, md->type, md->attribute, md->phys_addr,
551685c7f5d3629d558b17ee193b6d7f194e82aadf0Li Zefan			       md->phys_addr + efi_md_size(md),
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       md->num_pages >> (20 - EFI_PAGE_SHIFT));
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_map_pal_code();
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_enter_virtual_mode();
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_enter_virtual_mode (void)
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *efi_map_start, *efi_map_end, *p;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_memory_desc_t *md;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_status_t status;
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 efi_desc_size;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_map_start = __va(ia64_boot_param->efi_memmap);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_desc_size = ia64_boot_param->efi_memdesc_size;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		md = p;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (md->attribute & EFI_MEMORY_RUNTIME) {
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
5777d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			 * Some descriptors have multiple bits set, so the
5787d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			 * order of the tests is relevant.
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (md->attribute & EFI_MEMORY_WB) {
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				md->virt_addr = (u64) __va(md->phys_addr);
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (md->attribute & EFI_MEMORY_UC) {
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				md->virt_addr = (u64) ioremap(md->phys_addr, 0);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (md->attribute & EFI_MEMORY_WC) {
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
5867d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				md->virt_addr = ia64_remap(md->phys_addr,
5877d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis							   (_PAGE_A |
5887d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis							    _PAGE_P |
5897d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis							    _PAGE_D |
5907d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis							    _PAGE_MA_WC |
5917d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis							    _PAGE_PL_0 |
5927d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis							    _PAGE_AR_RW));
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(KERN_INFO "EFI_MEMORY_WC mapping\n");
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				md->virt_addr = (u64) ioremap(md->phys_addr, 0);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (md->attribute & EFI_MEMORY_WT) {
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
5997d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				md->virt_addr = ia64_remap(md->phys_addr,
6007d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis							   (_PAGE_A |
6017d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis							    _PAGE_P |
6027d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis							    _PAGE_D |
6037d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis							    _PAGE_MA_WT |
6047d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis							    _PAGE_PL_0 |
6057d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis							    _PAGE_AR_RW));
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(KERN_INFO "EFI_MEMORY_WT mapping\n");
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				md->virt_addr = (u64) ioremap(md->phys_addr, 0);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = efi_call_phys(__va(runtime->set_virtual_address_map),
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ia64_boot_param->efi_memmap_size,
6167d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			       efi_desc_size,
6177d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			       ia64_boot_param->efi_memdesc_version,
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ia64_boot_param->efi_memmap);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status != EFI_SUCCESS) {
6207d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		printk(KERN_WARNING "warning: unable to switch EFI into "
6217d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		       "virtual mode (status=%lu)\n", status);
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6267d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	 * Now that EFI is in virtual mode, we call the EFI functions more
6277d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	 * efficiently:
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.get_time = virt_get_time;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.set_time = virt_set_time;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.get_wakeup_time = virt_get_wakeup_time;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.set_wakeup_time = virt_set_wakeup_time;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.get_variable = virt_get_variable;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.get_next_variable = virt_get_next_variable;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.set_variable = virt_set_variable;
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.get_next_high_mono_count = virt_get_next_high_mono_count;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi.reset_system = virt_reset_system;
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6417d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * Walk the EFI memory map looking for the I/O port range.  There can only be
6427d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * one entry of this type, other I/O port ranges should be described via ACPI.
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu64
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_get_iobase (void)
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *efi_map_start, *efi_map_end, *p;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_memory_desc_t *md;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 efi_desc_size;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_map_start = __va(ia64_boot_param->efi_memmap);
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_desc_size = ia64_boot_param->efi_memdesc_size;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		md = p;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) {
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (md->attribute & EFI_MEMORY_UC)
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return md->phys_addr;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
66532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasstatic struct kern_memdesc *
66632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaaskern_memory_descriptor (unsigned long phys_addr)
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
66832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	struct kern_memdesc *md;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	for (md = kern_memmap; md->start != ~0UL; md++) {
67132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		if (phys_addr - md->start < (md->num_pages << EFI_PAGE_SHIFT))
67280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas			 return md;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
674e037cda559547e6353c5a792802963572d0b750eKeith Owens	return NULL;
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasstatic efi_memory_desc_t *
67832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasefi_memory_descriptor (unsigned long phys_addr)
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *efi_map_start, *efi_map_end, *p;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_memory_desc_t *md;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 efi_desc_size;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_map_start = __va(ia64_boot_param->efi_memmap);
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_desc_size = ia64_boot_param->efi_memdesc_size;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		md = p;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691685c7f5d3629d558b17ee193b6d7f194e82aadf0Li Zefan		if (phys_addr - md->phys_addr < efi_md_size(md))
69232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas			 return md;
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
694e037cda559547e6353c5a792802963572d0b750eKeith Owens	return NULL;
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
69680851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
6976d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaasstatic int
6986d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaasefi_memmap_intersects (unsigned long phys_addr, unsigned long size)
6996d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas{
7006d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	void *efi_map_start, *efi_map_end, *p;
7016d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	efi_memory_desc_t *md;
7026d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	u64 efi_desc_size;
7036d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	unsigned long end;
7046d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas
7056d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	efi_map_start = __va(ia64_boot_param->efi_memmap);
7066d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
7076d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	efi_desc_size = ia64_boot_param->efi_memdesc_size;
7086d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas
7096d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	end = phys_addr + size;
7106d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas
7116d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
7126d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas		md = p;
7136d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas		if (md->phys_addr < end && efi_md_end(md) > phys_addr)
7146d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas			return 1;
7156d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	}
7166d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	return 0;
7176d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas}
7186d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas
71980851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasu32
72080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasefi_mem_type (unsigned long phys_addr)
72180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{
72280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	efi_memory_desc_t *md = efi_memory_descriptor(phys_addr);
72380851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
72480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	if (md)
72580851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas		return md->type;
72680851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	return 0;
72780851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas}
72880851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
72980851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasu64
73080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasefi_mem_attributes (unsigned long phys_addr)
73180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{
73280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	efi_memory_desc_t *md = efi_memory_descriptor(phys_addr);
73380851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
73480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	if (md)
73580851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas		return md->attribute;
73680851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	return 0;
73780851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas}
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(efi_mem_attributes);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
74032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasu64
74132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasefi_mem_attribute (unsigned long phys_addr, unsigned long size)
74280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{
743136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas	unsigned long end = phys_addr + size;
74480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	efi_memory_desc_t *md = efi_memory_descriptor(phys_addr);
74532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	u64 attr;
74632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas
74732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	if (!md)
74832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		return 0;
74932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas
75032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	/*
75132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * EFI_MEMORY_RUNTIME is not a memory attribute; it just tells
75232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * the kernel that firmware needs this region mapped.
75332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 */
75432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	attr = md->attribute & ~EFI_MEMORY_RUNTIME;
75532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	do {
75632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		unsigned long md_end = efi_md_end(md);
75732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas
75832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		if (end <= md_end)
75932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas			return attr;
76032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas
76132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		md = efi_memory_descriptor(md_end);
76232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		if (!md || (md->attribute & ~EFI_MEMORY_RUNTIME) != attr)
76332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas			return 0;
76432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	} while (md);
76532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	return 0;
76632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas}
76732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas
76832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasu64
76932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaaskern_mem_attribute (unsigned long phys_addr, unsigned long size)
77032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas{
77132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	unsigned long end = phys_addr + size;
77232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	struct kern_memdesc *md;
77332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	u64 attr;
77480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
775136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas	/*
77632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * This is a hack for ioremap calls before we set up kern_memmap.
77732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * Maybe we should do efi_memmap_init() earlier instead.
778136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas	 */
77932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	if (!kern_memmap) {
78032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		attr = efi_mem_attribute(phys_addr, size);
78132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		if (attr & EFI_MEMORY_WB)
78232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas			return EFI_MEMORY_WB;
78380851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas		return 0;
784136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas	}
78580851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
78632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	md = kern_memory_descriptor(phys_addr);
78732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	if (!md)
78832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		return 0;
78932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas
79032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	attr = md->attribute;
79180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	do {
79232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		unsigned long md_end = kmd_end(md);
793136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas
794136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas		if (end <= md_end)
79532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas			return attr;
79680851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
79732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		md = kern_memory_descriptor(md_end);
79832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		if (!md || md->attribute != attr)
799136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas			return 0;
80080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	} while (md);
80180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas	return 0;
80280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas}
80332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn HelgaasEXPORT_SYMBOL(kern_mem_attribute);
80480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
806136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaasvalid_phys_addr_range (unsigned long phys_addr, unsigned long size)
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
80832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	u64 attr;
80932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas
81032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	/*
81132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * /dev/mem reads and writes use copy_to_user(), which implicitly
81232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * uses a granule-sized kernel identity mapping.  It's really
81332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * only safe to do this for regions in kern_memmap.  For more
81432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * details, see Documentation/ia64/aliasing.txt.
81532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 */
81632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	attr = kern_mem_attribute(phys_addr, size);
81732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC)
81832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		return 1;
81932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	return 0;
82080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas}
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
82280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasint
82306c67befeeb16f2995c11b0e04a348103ddbfab1Lennert Buytenhekvalid_mmap_phys_addr_range (unsigned long pfn, unsigned long size)
82480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{
8256d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	unsigned long phys_addr = pfn << PAGE_SHIFT;
8266d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	u64 attr;
8276d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas
8286d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	attr = efi_mem_attribute(phys_addr, size);
8296d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas
83032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	/*
8316d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	 * /dev/mem mmap uses normal user pages, so we don't need the entire
8326d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	 * granule, but the entire region we're mapping must support the same
8336d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	 * attribute.
83432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 */
8356d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC)
8366d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas		return 1;
8376d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas
8386d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	/*
8396d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	 * Intel firmware doesn't tell us about all the MMIO regions, so
8406d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	 * in general we have to allow mmap requests.  But if EFI *does*
8416d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	 * tell us about anything inside this region, we should deny it.
8426d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	 * The user can always map a smaller region to avoid the overlap.
8436d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	 */
8446d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas	if (efi_memmap_intersects(phys_addr, size))
8456d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas		return 0;
8466d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas
84732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	return 1;
84832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas}
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
85032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaaspgprot_t
85132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasphys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size,
85232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		     pgprot_t vma_prot)
85332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas{
85432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	unsigned long phys_addr = pfn << PAGE_SHIFT;
85532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	u64 attr;
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
85732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	/*
85832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * For /dev/mem mmap, we use user mappings, but if the region is
85932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * in kern_memmap (and hence may be covered by a kernel mapping),
86032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * we must use the same attribute as the kernel mapping.
86132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 */
86232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	attr = kern_mem_attribute(phys_addr, size);
86332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	if (attr & EFI_MEMORY_WB)
86432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		return pgprot_cacheable(vma_prot);
86532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	else if (attr & EFI_MEMORY_UC)
86632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		return pgprot_noncached(vma_prot);
86732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas
86832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	/*
86932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * Some chipsets don't support UC access to memory.  If
87032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 * WB is supported, we prefer that.
87132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	 */
87232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	if (efi_mem_attribute(phys_addr, size) & EFI_MEMORY_WB)
87332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas		return pgprot_cacheable(vma_prot);
87432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas
87532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas	return pgprot_noncached(vma_prot);
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_uart_console_only(void)
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_status_t status;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *s, name[] = "ConOut";
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	efi_char16_t *utf16, name_utf16[32];
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char data[1024];
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long size = sizeof(data);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct efi_generic_dev_path *hdr, *end_addr;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int uart = 0;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Convert to UTF-16 */
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	utf16 = name_utf16;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s = name;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (*s)
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*utf16++ = *s++ & 0x7f;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*utf16 = 0;
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = efi.get_variable(name_utf16, &guid, NULL, &size, data);
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status != EFI_SUCCESS) {
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "No EFI %s variable?\n", name);
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hdr = (struct efi_generic_dev_path *) data;
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end_addr = (struct efi_generic_dev_path *) ((u8 *) data + size);
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (hdr < end_addr) {
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (hdr->type == EFI_DEV_MSG &&
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    hdr->sub_type == EFI_DEV_MSG_UART)
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			uart = 1;
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (hdr->type == EFI_DEV_END_PATH ||
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  hdr->type == EFI_DEV_END_PATH2) {
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!uart)
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 0;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (hdr->sub_type == EFI_DEV_END_ENTIRE)
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 1;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			uart = 0;
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9177d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		hdr = (struct efi_generic_dev_path *)((u8 *) hdr + hdr->length);
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "Malformed %s value\n", name);
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
922d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
923d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck/*
924d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * Look for the first granule aligned memory descriptor memory
925d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * that is big enough to hold EFI memory map. Make sure this
926d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * descriptor is atleast granule sized so it does not get trimmed
927d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck */
928d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckstruct kern_memdesc *
929d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckfind_memmap_space (void)
930d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck{
931d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	u64	contig_low=0, contig_high=0;
932d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	u64	as = 0, ae;
933d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	void *efi_map_start, *efi_map_end, *p, *q;
934d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	efi_memory_desc_t *md, *pmd = NULL, *check_md;
935d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	u64	space_needed, efi_desc_size;
936d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	unsigned long total_mem = 0;
937d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
938d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	efi_map_start = __va(ia64_boot_param->efi_memmap);
939d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
940d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	efi_desc_size = ia64_boot_param->efi_memdesc_size;
941d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
942d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	/*
943d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	 * Worst case: we need 3 kernel descriptors for each efi descriptor
944d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	 * (if every entry has a WB part in the middle, and UC head and tail),
945d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	 * plus one for the end marker.
946d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	 */
947d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	space_needed = sizeof(kern_memdesc_t) *
948d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		(3 * (ia64_boot_param->efi_memmap_size/efi_desc_size) + 1);
949d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
950d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	for (p = efi_map_start; p < efi_map_end; pmd = md, p += efi_desc_size) {
951d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		md = p;
952d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (!efi_wb(md)) {
953d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			continue;
954d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		}
9557d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		if (pmd == NULL || !efi_wb(pmd) ||
9567d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		    efi_md_end(pmd) != md->phys_addr) {
957d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			contig_low = GRANULEROUNDUP(md->phys_addr);
958d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			contig_high = efi_md_end(md);
9597d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			for (q = p + efi_desc_size; q < efi_map_end;
9607d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			     q += efi_desc_size) {
961d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				check_md = q;
962d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				if (!efi_wb(check_md))
963d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck					break;
964d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				if (contig_high != check_md->phys_addr)
965d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck					break;
966d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				contig_high = efi_md_end(check_md);
967d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			}
968d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			contig_high = GRANULEROUNDDOWN(contig_high);
969d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		}
97066888a6e5ffc756b9a4115fc766ee2258eefb928Christoph Lameter		if (!is_memory_available(md) || md->type == EFI_LOADER_DATA)
971d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			continue;
972d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
973d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		/* Round ends inward to granule boundaries */
974d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		as = max(contig_low, md->phys_addr);
975d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		ae = min(contig_high, efi_md_end(md));
976d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
977a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai		/* keep within max_addr= and min_addr= command line arg */
978a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai		as = max(as, min_addr);
979d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		ae = min(ae, max_addr);
980d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (ae <= as)
981d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			continue;
982d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
983d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		/* avoid going over mem= command line arg */
984d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (total_mem + (ae - as) > mem_limit)
985d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			ae -= total_mem + (ae - as) - mem_limit;
986d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
987d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (ae <= as)
988d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			continue;
989d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
990d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (ae - as > space_needed)
991d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			break;
992d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	}
993d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	if (p >= efi_map_end)
994d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		panic("Can't allocate space for kernel memory descriptors");
995d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
996d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	return __va(as);
997d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck}
998d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
999d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck/*
1000d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * Walk the EFI memory map and gather all memory available for kernel
1001d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * to use.  We can allocate partial granules only if the unavailable
1002d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * parts exist, and are WB.
1003d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck */
1004cb3808532eeb1719667356157fac9222ccb2c4ffBernhard Walleunsigned long
1005d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckefi_memmap_init(unsigned long *s, unsigned long *e)
1006d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck{
1007e037cda559547e6353c5a792802963572d0b750eKeith Owens	struct kern_memdesc *k, *prev = NULL;
1008d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	u64	contig_low=0, contig_high=0;
1009d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	u64	as, ae, lim;
1010d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	void *efi_map_start, *efi_map_end, *p, *q;
1011d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	efi_memory_desc_t *md, *pmd = NULL, *check_md;
1012d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	u64	efi_desc_size;
1013d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	unsigned long total_mem = 0;
1014d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
1015d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	k = kern_memmap = find_memmap_space();
1016d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
1017d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	efi_map_start = __va(ia64_boot_param->efi_memmap);
1018d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
1019d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	efi_desc_size = ia64_boot_param->efi_memdesc_size;
1020d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
1021d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	for (p = efi_map_start; p < efi_map_end; pmd = md, p += efi_desc_size) {
1022d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		md = p;
1023d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (!efi_wb(md)) {
10247d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			if (efi_uc(md) &&
10257d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			    (md->type == EFI_CONVENTIONAL_MEMORY ||
10267d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			     md->type == EFI_BOOT_SERVICES_DATA)) {
1027d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				k->attribute = EFI_MEMORY_UC;
1028d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				k->start = md->phys_addr;
1029d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				k->num_pages = md->num_pages;
1030d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				k++;
1031d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			}
1032d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			continue;
1033d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		}
10347d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		if (pmd == NULL || !efi_wb(pmd) ||
10357d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		    efi_md_end(pmd) != md->phys_addr) {
1036d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			contig_low = GRANULEROUNDUP(md->phys_addr);
1037d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			contig_high = efi_md_end(md);
10387d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			for (q = p + efi_desc_size; q < efi_map_end;
10397d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			     q += efi_desc_size) {
1040d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				check_md = q;
1041d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				if (!efi_wb(check_md))
1042d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck					break;
1043d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				if (contig_high != check_md->phys_addr)
1044d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck					break;
1045d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				contig_high = efi_md_end(check_md);
1046d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			}
1047d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			contig_high = GRANULEROUNDDOWN(contig_high);
1048d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		}
104966888a6e5ffc756b9a4115fc766ee2258eefb928Christoph Lameter		if (!is_memory_available(md))
1050d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			continue;
1051d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
1052e55fdf11f3029bcd41b1b9547ad9db12c27eea76Tony Luck#ifdef CONFIG_CRASH_DUMP
1053e55fdf11f3029bcd41b1b9547ad9db12c27eea76Tony Luck		/* saved_max_pfn should ignore max_addr= command line arg */
1054e55fdf11f3029bcd41b1b9547ad9db12c27eea76Tony Luck		if (saved_max_pfn < (efi_md_end(md) >> PAGE_SHIFT))
1055e55fdf11f3029bcd41b1b9547ad9db12c27eea76Tony Luck			saved_max_pfn = (efi_md_end(md) >> PAGE_SHIFT);
1056e55fdf11f3029bcd41b1b9547ad9db12c27eea76Tony Luck#endif
1057d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		/*
1058d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		 * Round ends inward to granule boundaries
1059d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		 * Give trimmings to uncached allocator
1060d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		 */
1061d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (md->phys_addr < contig_low) {
1062d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			lim = min(efi_md_end(md), contig_low);
1063d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			if (efi_uc(md)) {
10647d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				if (k > kern_memmap &&
10657d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				    (k-1)->attribute == EFI_MEMORY_UC &&
1066d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				    kmd_end(k-1) == md->phys_addr) {
10677d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis					(k-1)->num_pages +=
10687d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis						(lim - md->phys_addr)
10697d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis						>> EFI_PAGE_SHIFT;
1070d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				} else {
1071d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck					k->attribute = EFI_MEMORY_UC;
1072d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck					k->start = md->phys_addr;
10737d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis					k->num_pages = (lim - md->phys_addr)
10747d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis						>> EFI_PAGE_SHIFT;
1075d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck					k++;
1076d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				}
1077d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			}
1078d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			as = contig_low;
1079d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		} else
1080d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			as = md->phys_addr;
1081d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
1082d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (efi_md_end(md) > contig_high) {
1083d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			lim = max(md->phys_addr, contig_high);
1084d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			if (efi_uc(md)) {
1085d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				if (lim == md->phys_addr && k > kern_memmap &&
1086d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				    (k-1)->attribute == EFI_MEMORY_UC &&
1087d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				    kmd_end(k-1) == md->phys_addr) {
1088d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck					(k-1)->num_pages += md->num_pages;
1089d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				} else {
1090d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck					k->attribute = EFI_MEMORY_UC;
1091d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck					k->start = lim;
10927d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis					k->num_pages = (efi_md_end(md) - lim)
10937d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis						>> EFI_PAGE_SHIFT;
1094d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck					k++;
1095d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck				}
1096d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			}
1097d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			ae = contig_high;
1098d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		} else
1099d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			ae = efi_md_end(md);
1100d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
1101a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai		/* keep within max_addr= and min_addr= command line arg */
1102a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai		as = max(as, min_addr);
1103d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		ae = min(ae, max_addr);
1104d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (ae <= as)
1105d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			continue;
1106d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
1107d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		/* avoid going over mem= command line arg */
1108d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (total_mem + (ae - as) > mem_limit)
1109d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			ae -= total_mem + (ae - as) - mem_limit;
1110d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
1111d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (ae <= as)
1112d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			continue;
1113d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		if (prev && kmd_end(prev) == md->phys_addr) {
1114d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			prev->num_pages += (ae - as) >> EFI_PAGE_SHIFT;
1115d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			total_mem += ae - as;
1116d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck			continue;
1117d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		}
1118d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		k->attribute = EFI_MEMORY_WB;
1119d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		k->start = as;
1120d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		k->num_pages = (ae - as) >> EFI_PAGE_SHIFT;
1121d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		total_mem += ae - as;
1122d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck		prev = k++;
1123d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	}
1124d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	k->start = ~0L; /* end-marker */
1125d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck
1126d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	/* reserve the memory we are using for kern_memmap */
1127d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	*s = (u64)kern_memmap;
1128d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck	*e = (u64)++k;
1129cb3808532eeb1719667356157fac9222ccb2c4ffBernhard Walle
1130cb3808532eeb1719667356157fac9222ccb2c4ffBernhard Walle	return total_mem;
1131d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck}
1132be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1133be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Azizvoid
1134be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Azizefi_initialize_iomem_resources(struct resource *code_resource,
113500bf4098beb15ca174b54f3af1f1e1908d7d18a3Bernhard Walle			       struct resource *data_resource,
113600bf4098beb15ca174b54f3af1f1e1908d7d18a3Bernhard Walle			       struct resource *bss_resource)
1137be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz{
1138be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz	struct resource *res;
1139be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz	void *efi_map_start, *efi_map_end, *p;
1140be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz	efi_memory_desc_t *md;
1141be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz	u64 efi_desc_size;
1142be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz	char *name;
1143be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz	unsigned long flags;
1144be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1145be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz	efi_map_start = __va(ia64_boot_param->efi_memmap);
1146be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
1147be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz	efi_desc_size = ia64_boot_param->efi_memdesc_size;
1148be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1149be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz	res = NULL;
1150be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1151be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
1152be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz		md = p;
1153be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1154be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz		if (md->num_pages == 0) /* should not happen */
1155be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			continue;
1156be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1157887c3cb18865a4f9e0786e5a5b3ef47ff469b956Yasunori Goto		flags = IORESOURCE_MEM | IORESOURCE_BUSY;
1158be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz		switch (md->type) {
1159be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1160be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_MEMORY_MAPPED_IO:
1161be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
1162be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz				continue;
1163be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1164be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_LOADER_CODE:
1165be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_LOADER_DATA:
1166be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_BOOT_SERVICES_DATA:
1167be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_BOOT_SERVICES_CODE:
1168be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_CONVENTIONAL_MEMORY:
1169be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz				if (md->attribute & EFI_MEMORY_WP) {
1170be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz					name = "System ROM";
1171be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz					flags |= IORESOURCE_READONLY;
1172be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz				} else {
1173be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz					name = "System RAM";
1174be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz				}
1175be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz				break;
1176be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1177be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_ACPI_MEMORY_NVS:
1178be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz				name = "ACPI Non-volatile Storage";
1179be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz				break;
1180be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1181be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_UNUSABLE_MEMORY:
1182be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz				name = "reserved";
1183887c3cb18865a4f9e0786e5a5b3ef47ff469b956Yasunori Goto				flags |= IORESOURCE_DISABLED;
1184be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz				break;
1185be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1186be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_RESERVED_TYPE:
1187be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_RUNTIME_SERVICES_CODE:
1188be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_RUNTIME_SERVICES_DATA:
1189be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			case EFI_ACPI_RECLAIM_MEMORY:
1190be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			default:
1191be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz				name = "reserved";
1192be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz				break;
1193be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz		}
1194be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
11957d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		if ((res = kzalloc(sizeof(struct resource),
11967d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				   GFP_KERNEL)) == NULL) {
11977d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			printk(KERN_ERR
1198965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis			       "failed to allocate resource for iomem\n");
1199be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			return;
1200be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz		}
1201be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1202be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz		res->name = name;
1203be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz		res->start = md->phys_addr;
1204685c7f5d3629d558b17ee193b6d7f194e82aadf0Li Zefan		res->end = md->phys_addr + efi_md_size(md) - 1;
1205be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz		res->flags = flags;
1206be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz
1207be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz		if (insert_resource(&iomem_resource, res) < 0)
1208be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			kfree(res);
1209be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz		else {
1210be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			/*
1211be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			 * We don't know which region contains
1212be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			 * kernel data so we try it repeatedly and
1213be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			 * let the resource manager test it.
1214be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			 */
1215be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			insert_resource(res, code_resource);
1216be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz			insert_resource(res, data_resource);
121700bf4098beb15ca174b54f3af1f1e1908d7d18a3Bernhard Walle			insert_resource(res, bss_resource);
1218a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai#ifdef CONFIG_KEXEC
1219a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai                        insert_resource(res, &efi_memmap_res);
1220a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai                        insert_resource(res, &boot_param_res);
1221a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai			if (crashk_res.end > crashk_res.start)
1222a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai				insert_resource(res, &crashk_res);
1223a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai#endif
1224be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz		}
1225be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz	}
1226be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz}
1227a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai
1228a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai#ifdef CONFIG_KEXEC
1229a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai/* find a block of memory aligned to 64M exclude reserved regions
1230a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai   rsvd_regions are sorted
1231a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai */
12322a3a2827c7cbe464610116cc17ca4fac63245a43Hormsunsigned long __init
12337d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffiskdump_find_rsvd_region (unsigned long size, struct rsvd_region *r, int n)
1234a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai{
12357d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	int i;
12367d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	u64 start, end;
12377d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	u64 alignment = 1UL << _PAGE_SIZE_64M;
12387d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	void *efi_map_start, *efi_map_end, *p;
12397d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_memory_desc_t *md;
12407d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	u64 efi_desc_size;
12417d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis
12427d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_map_start = __va(ia64_boot_param->efi_memmap);
12437d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
12447d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	efi_desc_size = ia64_boot_param->efi_memdesc_size;
12457d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis
12467d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
12477d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		md = p;
12487d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		if (!efi_wb(md))
12497d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			continue;
12507d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		start = ALIGN(md->phys_addr, alignment);
12517d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		end = efi_md_end(md);
12527d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		for (i = 0; i < n; i++) {
12537d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			if (__pa(r[i].start) >= start && __pa(r[i].end) < end) {
12547d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				if (__pa(r[i].start) > start + size)
12557d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis					return start;
12567d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				start = ALIGN(__pa(r[i].end), alignment);
12577d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				if (i < n-1 &&
12587d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				    __pa(r[i+1].start) < start + size)
12597d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis					continue;
12607d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis				else
12617d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis					break;
12627d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			}
1263a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai		}
12647d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis		if (end > start + size)
12657d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis			return start;
12667d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	}
12677d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis
12687d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	printk(KERN_WARNING
12697d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	       "Cannot reserve 0x%lx byte of memory for crashdump\n", size);
12707d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis	return ~0UL;
1271a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai}
1272a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai#endif
1273cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm
1274cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm#ifdef CONFIG_PROC_VMCORE
1275cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm/* locate the size find a the descriptor at a certain address */
12761775fe851632fd906bc5e5c6f77494d8f7ef1275Simon Hormanunsigned long __init
1277cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Dammvmcore_find_descriptor_size (unsigned long address)
1278cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm{
1279cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm	void *efi_map_start, *efi_map_end, *p;
1280cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm	efi_memory_desc_t *md;
1281cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm	u64 efi_desc_size;
1282cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm	unsigned long ret = 0;
1283cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm
1284cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm	efi_map_start = __va(ia64_boot_param->efi_memmap);
1285cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
1286cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm	efi_desc_size = ia64_boot_param->efi_memdesc_size;
1287cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm
1288cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
1289cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm		md = p;
1290cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm		if (efi_wb(md) && md->type == EFI_LOADER_DATA
1291cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm		    && md->phys_addr == address) {
1292cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm			ret = efi_md_size(md);
1293cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm			break;
1294cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm		}
1295cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm	}
1296cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm
1297cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm	if (ret == 0)
1298cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm		printk(KERN_WARNING "Cannot locate EFI vmcore descriptor\n");
1299cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm
1300cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm	return ret;
1301cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm}
1302cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm#endif
1303