From: Matt Tolentino <metolent@snoqualmie.dp.intel.com>

1. Adds CONFIG_EFI option to boot on EFI platforms, but also continue
   to boot on existing platforms depending on the boot parameters.  

2. Kernels w/o CONFIG_EFI are smaller (nearly 8k, although I can
   probably move some more stuff around for greater savings).  

This was accomplished through the following changes:

+ Removed CONFIG_ACPI_EFI.  I've substituted the efi_enabled flag which
  is set depending on CONFIG_EFI at build time, but also dynamically at
  runtime through inspection of the boot parameters.

  Note, I haven't run this change by Len or David for input from the ACPI
  or IA64 perspectives.  However, this does allow for the behavior we need
  on x86.  I need to do one more ia64 specific patch (something like add
  int efi_enabled = 1; and a CONFIG_EFI option to always be on in Kconfig)
  to ensure this doesn't break itanium builds, but I wanted to get your
  input first.  

+ reorganized some of the functions in time.c.  I removed the
  efi_get_time and efi_set_rtc_mmss and put them as inline into efi.c.  I
  think the manner in which these are called makes more sense now and
  ensures that they aren't even compiled without CONFIG_EFI.  

I was able to boot both kernels (EFI and non-EFI) on several machines with
regular BIOS.  The ACPI tables were detected correctly, interrupts looked
like they were routed correctly, etc., so give a try.  



 arch/i386/Kconfig            |   15 +++++
 arch/i386/kernel/Makefile    |    3 -
 arch/i386/kernel/acpi/boot.c |   10 ++-
 arch/i386/kernel/efi.c       |   51 +++++++++++++++++++-
 arch/i386/kernel/setup.c     |   10 +++
 arch/i386/kernel/time.c      |   79 ++++++-------------------------
 drivers/acpi/Kconfig         |   12 ----
 drivers/acpi/osl.c           |  108 ++++++++++++++++++++-----------------------
 include/linux/efi.h          |    7 ++
 9 files changed, 155 insertions(+), 140 deletions(-)

diff -puN arch/i386/Kconfig~ia32-efi-config-option arch/i386/Kconfig
--- 25/arch/i386/Kconfig~ia32-efi-config-option	2003-10-24 20:55:51.000000000 -0700
+++ 25-akpm/arch/i386/Kconfig	2003-10-24 20:55:51.000000000 -0700
@@ -784,6 +784,18 @@ config MTRR
 
 	  See <file:Documentation/mtrr.txt> for more information.
 
+config EFI
+	bool "Boot from EFI support (EXPERIMENTAL)"
+	depends on ACPI
+	default n
+	---help---
+	This enables the the kernel to boot on EFI platforms using system configuration
+	passed to it from the firmware.  This also enables the EFI runtime services to be
+	invoked.
+
+	This option is only useful on systems that have EFI firmware. In addition, you
+	must use the latest ELILO loader available at ftp.hpl.hp.com/pub/linux-ia64/.
+
 config HAVE_DEC_LOCK
 	bool
 	depends on (SMP || PREEMPT) && X86_CMPXCHG
@@ -793,8 +805,7 @@ config HAVE_DEC_LOCK
 # Summit needs it only when NUMA is on
 config BOOT_IOREMAP
 	bool
-	depends on X86_PC
-# depends on (((X86_SUMMIT || X86_GENERICARCH) && NUMA)) || X86_GENERICARCH
+	depends on (((X86_SUMMIT || X86_GENERICARCH) && NUMA) || (X86 && EFI))
 	default y
 
 endmenu
diff -puN arch/i386/kernel/acpi/boot.c~ia32-efi-config-option arch/i386/kernel/acpi/boot.c
--- 25/arch/i386/kernel/acpi/boot.c~ia32-efi-config-option	2003-10-24 20:55:51.000000000 -0700
+++ 25-akpm/arch/i386/kernel/acpi/boot.c	2003-10-24 20:55:51.000000000 -0700
@@ -325,10 +325,12 @@ acpi_find_rsdp (void)
 {
 	unsigned long		rsdp_phys = 0;
 
-	if (efi.acpi20)
-		return __pa(efi.acpi20);
-	else if (efi.acpi)
-		return __pa(efi.acpi);
+	if (efi_enabled) {
+		if (efi.acpi20)
+			return __pa(efi.acpi20);
+		else if (efi.acpi)
+			return __pa(efi.acpi);
+	}
 	/*
 	 * Scan memory looking for the RSDP signature. First search EBDA (low
 	 * memory) paragraphs and then search upper memory (E0000-FFFFF).
diff -puN arch/i386/kernel/efi.c~ia32-efi-config-option arch/i386/kernel/efi.c
--- 25/arch/i386/kernel/efi.c~ia32-efi-config-option	2003-10-24 20:55:51.000000000 -0700
+++ 25-akpm/arch/i386/kernel/efi.c	2003-10-24 20:55:51.000000000 -0700
@@ -174,12 +174,61 @@ phys_efi_get_time(efi_time_t *tm, efi_ti
 	return status;
 }
 
+int inline efi_set_rtc_mmss(unsigned long nowtime)
+{
+	int real_seconds, real_minutes;
+	efi_status_t 	status;
+	efi_time_t 	eft;
+	efi_time_cap_t 	cap;
+
+	spin_lock(&efi_rt_lock);
+	status = efi.get_time(&eft, &cap);
+	spin_unlock(&efi_rt_lock);
+	if (status != EFI_SUCCESS)
+		panic("Ooops, efitime: can't read time!\n");
+	real_seconds = nowtime % 60;
+	real_minutes = nowtime / 60;
+
+	if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
+		real_minutes += 30;
+	real_minutes %= 60;
+
+	eft.minute = real_minutes;
+	eft.second = real_seconds;
+
+	if (status != EFI_SUCCESS) {
+		printk("Ooops: efitime: can't read time!\n");
+		return -1;
+	}
+	return 0;
+}
+/*
+ * This should only be used during kernel init and before runtime
+ * services have been remapped, therefore, we'll need to call in physical
+ * mode.  Note, this call isn't used later, so mark it __init.
+ */
+unsigned long inline __init efi_get_time(void)
+{
+	efi_status_t status;
+	efi_time_t eft;
+	efi_time_cap_t cap;
+
+	status = phys_efi_get_time(&eft, &cap);
+	if (status != EFI_SUCCESS)
+		printk("Oops: efitime: can't read time status: 0x%lx\n", status);
+
+	return mktime(eft.year, eft.month, eft.day, eft.hour, eft.minute, eft.second);
+}
 void efi_gettimeofday(struct timespec *tv)
 {
 	efi_time_t tm;
+	efi_status_t status;
 
 	memset(tv, 0, sizeof(*tv));
-	if ((*efi.get_time) (&tm, 0) != EFI_SUCCESS)
+	spin_lock(&efi_rt_lock);
+	status = (*efi.get_time) (&tm, 0);
+	spin_unlock(&efi_rt_lock);
+	if (status != EFI_SUCCESS)
 		return;
 
 	tv->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute,
diff -puN arch/i386/kernel/Makefile~ia32-efi-config-option arch/i386/kernel/Makefile
--- 25/arch/i386/kernel/Makefile~ia32-efi-config-option	2003-10-24 20:55:51.000000000 -0700
+++ 25-akpm/arch/i386/kernel/Makefile	2003-10-24 20:56:06.000000000 -0700
@@ -7,7 +7,7 @@ extra-y := head.o init_task.o vmlinux.ld
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
 		pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \
-		doublefault.o efi.o efi_stub.o
+		doublefault.o
 
 obj-y				+= cpu/
 obj-y				+= timers/
@@ -31,6 +31,7 @@ obj-$(CONFIG_MODULES)		+= module.o
 obj-y				+= sysenter.o vsyscall.o
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
 obj-$(CONFIG_HPET_TIMER) 	+= time_hpet.o
+obj-$(CONFIG_EFI) 		+= efi.o efi_stub.o
 
 EXTRA_AFLAGS   := -traditional
 
diff -puN arch/i386/kernel/setup.c~ia32-efi-config-option arch/i386/kernel/setup.c
--- 25/arch/i386/kernel/setup.c~ia32-efi-config-option	2003-10-24 20:55:51.000000000 -0700
+++ 25-akpm/arch/i386/kernel/setup.c	2003-10-24 20:55:51.000000000 -0700
@@ -58,7 +58,9 @@ static inline char * __init machine_spec
  * Machine setup..
  */
 
+#ifdef CONFIG_EFI
 int efi_enabled = 0;
+#endif
 
 /* cpu data as detected by the assembly code in head.S */
 struct cpuinfo_x86 new_cpu_data __initdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
@@ -1046,11 +1048,17 @@ void __init setup_arch(char **cmdline_p)
 	pre_setup_arch_hook();
 	early_cpu_init();
 
-	/* FIXME: This isn't an official loader_type right
+	/*
+	 * FIXME: This isn't an official loader_type right
 	 * now but does currently work with elilo.
+	 * If we were configured as an EFI kernel, check to make
+	 * sure that we were loaded correctly from elilo and that
+	 * the system table is valid.  If not, then initialize normally.
 	 */
+#ifdef CONFIG_EFI
 	if ((LOADER_TYPE == 0x50) && EFI_SYSTAB)
 		efi_enabled = 1;
+#endif
 
  	ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
  	drive_info = DRIVE_INFO;
diff -puN arch/i386/kernel/time.c~ia32-efi-config-option arch/i386/kernel/time.c
--- 25/arch/i386/kernel/time.c~ia32-efi-config-option	2003-10-24 20:55:51.000000000 -0700
+++ 25-akpm/arch/i386/kernel/time.c	2003-10-24 20:55:51.000000000 -0700
@@ -170,43 +170,15 @@ static int set_rtc_mmss(unsigned long no
 
 	/* gets recalled with irq locally disabled */
 	spin_lock(&rtc_lock);
-	retval = mach_set_rtc_mmss(nowtime);
+	if (efi_enabled)
+		retval = efi_set_rtc_mmss(nowtime);
+	else
+		retval = mach_set_rtc_mmss(nowtime);
 	spin_unlock(&rtc_lock);
 
 	return retval;
 }
 
-static int efi_set_rtc_mmss(unsigned long nowtime)
-{
-	int real_seconds, real_minutes;
-	unsigned long 	flags;
-	efi_status_t 	status;
-	efi_time_t 	eft;
-	efi_time_cap_t 	cap;
-
-	spin_lock_irqsave(&rtc_lock, flags);
-
-	status = efi.get_time(&eft, &cap);
-	if (status != EFI_SUCCESS)
-		panic("Ooops, efitime: can't read time!\n");
-	real_seconds = nowtime % 60;
-	real_minutes = nowtime / 60;
-
-	if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
-		real_minutes += 30;
-	real_minutes %= 60;
-
-	eft.minute = real_minutes;
-	eft.second = real_seconds;
-
-	status = efi.set_time(&eft);
-	if (status != EFI_SUCCESS)
-		panic("Ooops: efitime: can't read time!\n");
-
-	spin_unlock_irqrestore(&rtc_lock, flags);
-	return 0;
-}
-
 /* last time the cmos clock got updated */
 static long last_rtc_update;
 
@@ -259,7 +231,13 @@ static inline void do_timer_interrupt(in
 			>= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
 	    (xtime.tv_nsec / 1000)
 			<= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) {
-		if ((efi_enabled && (!efi_set_rtc_mmss(xtime.tv_sec) )) || (set_rtc_mmss(xtime.tv_sec) == 0))
+		/* horrible...FIXME */
+		if (efi_enabled) {
+	 		if (efi_set_rtc_mmss(xtime.tv_sec) == 0)
+				last_rtc_update = xtime.tv_sec;
+			else
+				last_rtc_update = xtime.tv_sec - 600;
+		} else if (set_rtc_mmss(xtime.tv_sec) == 0)
 			last_rtc_update = xtime.tv_sec;
 		else
 			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
@@ -313,7 +291,10 @@ unsigned long get_cmos_time(void)
 
 	spin_lock(&rtc_lock);
 
-	retval = mach_get_cmos_time();
+	if (efi_enabled)
+		retval = efi_get_time();
+	else
+		retval = mach_get_cmos_time();
 
 	spin_unlock(&rtc_lock);
 
@@ -324,26 +305,6 @@ static struct sysdev_class pit_sysclass 
 	set_kset_name("pit"),
 };
 
-/*
- * This is called before the RT mappings are in place, so we
- * need to be able to get the time in physical mode.
- */
-unsigned long efi_get_time(void)
-{
-	efi_status_t status;
-	unsigned long flags;
-	efi_time_t eft;
-	efi_time_cap_t cap;
-
-	spin_lock_irqsave(&rtc_lock, flags);
-	status = phys_efi_get_time(&eft, &cap);
-	if (status != EFI_SUCCESS)
-		printk("Oops: efitime: can't read time status: 0x%lx\n", status);
-
-	spin_unlock_irqrestore(&rtc_lock, flags);
-
-	return mktime(eft.year, eft.month, eft.day, eft.hour, eft.minute, eft.second);
-}
 
 /* XXX this driverfs stuff should probably go elsewhere later -john */
 static struct sys_device device_i8253 = {
@@ -366,10 +327,7 @@ extern void (*late_time_init)(void);
 /* Duplicate of time_init() below, with hpet_enable part added */
 void __init hpet_time_init(void)
 {
-	if (efi_enabled)
-		xtime.tv_sec = efi_get_time();
-	else
-		xtime.tv_sec = get_cmos_time();
+	xtime.tv_sec = get_cmos_time();
 	wall_to_monotonic.tv_sec = -xtime.tv_sec;
 	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
 	wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
@@ -395,10 +353,7 @@ void __init time_init(void)
 		return;
 	}
 #endif
-	if (efi_enabled)
-		xtime.tv_sec = efi_get_time();
-	else
-		xtime.tv_sec = get_cmos_time();
+	xtime.tv_sec = get_cmos_time();
 	wall_to_monotonic.tv_sec = -xtime.tv_sec;
 	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
 	wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
diff -puN drivers/acpi/Kconfig~ia32-efi-config-option drivers/acpi/Kconfig
--- 25/drivers/acpi/Kconfig~ia32-efi-config-option	2003-10-24 20:55:51.000000000 -0700
+++ 25-akpm/drivers/acpi/Kconfig	2003-10-24 20:55:51.000000000 -0700
@@ -251,18 +251,6 @@ config ACPI_SYSTEM
 	  This driver will enable your system to shut down using ACPI, and
 	  dump your ACPI DSDT table using /proc/acpi/dsdt.
 
-config ACPI_EFI
- 	bool "Obtain RSDP from EFI Configuration Table"
-	depends on ACPI_INTERPRETER
-	depends on IA64 || X86
-  	default n
- 	help
- 	   On EFI Systems the RSDP pointer is passed to the kernel via
- 	   the EFI Configuration Table.  On Itanium systems this is
- 	   standard and required.  For IA-32, systems that have
- 	   EFI firmware should leave this enabled.  Platforms with
- 	   traditional legacy BIOS should disable this option.
-
 config ACPI_RELAXED_AML
 	bool "Relaxed AML"
 	depends on ACPI_INTERPRETER
diff -puN drivers/acpi/osl.c~ia32-efi-config-option drivers/acpi/osl.c
--- 25/drivers/acpi/osl.c~ia32-efi-config-option	2003-10-24 20:55:51.000000000 -0700
+++ 25-akpm/drivers/acpi/osl.c	2003-10-24 20:55:51.000000000 -0700
@@ -41,9 +41,7 @@
 #include <acpi/acpi_bus.h>
 #include <asm/uaccess.h>
 
-#ifdef CONFIG_ACPI_EFI
 #include <linux/efi.h>
-#endif
 
 
 #define _COMPONENT		ACPI_OS_SERVICES
@@ -139,22 +137,24 @@ acpi_os_free(void *ptr)
 acpi_status
 acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr)
 {
-#ifdef CONFIG_ACPI_EFI
-	addr->pointer_type = ACPI_PHYSICAL_POINTER;
-	if (efi.acpi20)
-		addr->pointer.physical = (acpi_physical_address) virt_to_phys(efi.acpi20);
-	else if (efi.acpi)
-		addr->pointer.physical = (acpi_physical_address) virt_to_phys(efi.acpi);
-	else {
-		printk(KERN_ERR PREFIX "System description tables not found\n");
-		return AE_NOT_FOUND;
-	}
-#else
-	if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
-		printk(KERN_ERR PREFIX "System description tables not found\n");
-		return AE_NOT_FOUND;
+	if (efi_enabled) {
+		addr->pointer_type = ACPI_PHYSICAL_POINTER;
+		if (efi.acpi20)
+			addr->pointer.physical =
+				(acpi_physical_address) virt_to_phys(efi.acpi20);
+		else if (efi.acpi)
+			addr->pointer.physical =
+				(acpi_physical_address) virt_to_phys(efi.acpi);
+		else {
+			printk(KERN_ERR PREFIX "System description tables not found\n");
+			return AE_NOT_FOUND;
+		}
+	} else {
+		if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
+			printk(KERN_ERR PREFIX "System description tables not found\n");
+			return AE_NOT_FOUND;
+		}
 	}
-#endif /*CONFIG_ACPI_EFI*/
 
 	return AE_OK;
 }
@@ -162,22 +162,22 @@ acpi_os_get_root_pointer(u32 flags, stru
 acpi_status
 acpi_os_map_memory(acpi_physical_address phys, acpi_size size, void **virt)
 {
-#ifdef CONFIG_ACPI_EFI
-	if (EFI_MEMORY_WB & efi_mem_attributes(phys)) {
-		*virt = phys_to_virt(phys);
+	if (efi_enabled) {
+		if (EFI_MEMORY_WB & efi_mem_attributes(phys)) {
+			*virt = phys_to_virt(phys);
+		} else {
+			*virt = ioremap(phys, size);
+		}
 	} else {
-		*virt = ioremap(phys, size);
-	}
-#else
-	if (phys > ULONG_MAX) {
-		printk(KERN_ERR PREFIX "Cannot map memory that high\n");
-		return AE_BAD_PARAMETER;
+		if (phys > ULONG_MAX) {
+			printk(KERN_ERR PREFIX "Cannot map memory that high\n");
+			return AE_BAD_PARAMETER;
+		}
+		/*
+	 	 * ioremap checks to ensure this is in reserved space
+	 	 */
+		*virt = ioremap((unsigned long) phys, size);
 	}
-	/*
-	 * ioremap checks to ensure this is in reserved space
-	 */
-	*virt = ioremap((unsigned long) phys, size);
-#endif
 
 	if (!*virt)
 		return AE_NO_MEMORY;
@@ -368,19 +368,17 @@ acpi_os_read_memory(
 {
 	u32			dummy;
 	void			*virt_addr;
-
-#ifdef CONFIG_ACPI_EFI
 	int			iomem = 0;
 
-	if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
+	if (efi_enabled) {
+		if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
+			virt_addr = phys_to_virt(phys_addr);
+		} else {
+			iomem = 1;
+			virt_addr = ioremap(phys_addr, width);
+		}
+	} else
 		virt_addr = phys_to_virt(phys_addr);
-	} else {
-		iomem = 1;
-		virt_addr = ioremap(phys_addr, width);
-	}
-#else
-	virt_addr = phys_to_virt(phys_addr);
-#endif
 	if (!value)
 		value = &dummy;
 
@@ -398,10 +396,10 @@ acpi_os_read_memory(
 		BUG();
 	}
 
-#ifdef CONFIG_ACPI_EFI
-	if (iomem)
-		iounmap(virt_addr);
-#endif
+	if (efi_enabled) {
+		if (iomem)
+			iounmap(virt_addr);
+	}
 
 	return AE_OK;
 }
@@ -413,19 +411,17 @@ acpi_os_write_memory(
 	u32			width)
 {
 	void			*virt_addr;
-
-#ifdef CONFIG_ACPI_EFI
 	int			iomem = 0;
 
-	if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
+	if (efi_enabled) {
+		if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
+			virt_addr = phys_to_virt(phys_addr);
+		} else {
+			iomem = 1;
+			virt_addr = ioremap(phys_addr, width);
+		}
+	} else
 		virt_addr = phys_to_virt(phys_addr);
-	} else {
-		iomem = 1;
-		virt_addr = ioremap(phys_addr, width);
-	}
-#else
-	virt_addr = phys_to_virt(phys_addr);
-#endif
 
 	switch (width) {
 	case 8:
@@ -441,10 +437,8 @@ acpi_os_write_memory(
 		BUG();
 	}
 
-#ifdef CONFIG_ACPI_EFI
 	if (iomem)
 		iounmap(virt_addr);
-#endif
 
 	return AE_OK;
 }
diff -puN include/linux/efi.h~ia32-efi-config-option include/linux/efi.h
--- 25/include/linux/efi.h~ia32-efi-config-option	2003-10-24 20:55:51.000000000 -0700
+++ 25-akpm/include/linux/efi.h	2003-10-24 20:55:51.000000000 -0700
@@ -297,8 +297,15 @@ extern u64 efi_mem_attributes (unsigned 
 extern void efi_initialize_iomem_resources(struct resource *code_resource,
 					struct resource *data_resource);
 extern efi_status_t phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc);
+extern unsigned long inline __init efi_get_time(void);
+extern int inline __init efi_set_rtc_mmss(unsigned long nowtime);
 extern struct efi_memory_map memmap;
+
+#ifdef CONFIG_EFI
 extern int efi_enabled;
+#else
+#define efi_enabled 0
+#endif
 
 /*
  * Variable Attributes

_