public inbox for linux-ia64@vger.kernel.org
 help / color / mirror / Atom feed
* [patch] fix ACPI table discovery from EFI for x86
@ 2005-07-14  0:59 Matt Tolentino
  2005-08-04 22:07 ` Bjorn Helgaas
  2005-08-04 22:34 ` Tolentino, Matthew E
  0 siblings, 2 replies; 3+ messages in thread
From: Matt Tolentino @ 2005-07-14  0:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, linux-ia64, tony.luck


This patch addresses a problem on x86 EFI systems with larger memory
configurations.  Up until now, we've relied on the fact that the 
ACPI RSDT would reside somewhere in low memory that could be permanently 
mapped in kernel address space - so __va() has been sufficient.  However,
on EFI systems, the RSDT is often anywhere in the lower 4GB of physical
address space.  So, we may need to remap it on x86 systems.  

Second, this fixes some miscalculations in one of the EFI memmap 
callback functions.  

Lastly, this also removes all of the va->pa->va contortions and 
stores the physical location in the efi struct while preserving the 
validity checks.  This change is the only reason this impacts 
ia64. 

Tested on x86 EFI machines and boot tested on one ia64 machine
thanks to Tony.  Additional testing on ia64 machines would be 
appreciated!  

Problem reported and original patch proposed by Ping Wei.

Signed-off-by: Matt Tolentino <matthew.e.tolentino@intel.com>
---
diff -urNp linux-2.6.13-rc3/arch/i386/kernel/acpi/boot.c linux-2.6.13-rc3-efi/arch/i386/kernel/acpi/boot.c
--- linux-2.6.13-rc3/arch/i386/kernel/acpi/boot.c	2005-07-13 00:46:46.000000000 -0400
+++ linux-2.6.13-rc3-efi/arch/i386/kernel/acpi/boot.c	2005-07-13 10:32:54.073297792 -0400
@@ -682,10 +682,10 @@ acpi_find_rsdp (void)
 	unsigned long		rsdp_phys = 0;
 
 	if (efi_enabled) {
-		if (efi.acpi20)
-			return __pa(efi.acpi20);
-		else if (efi.acpi)
-			return __pa(efi.acpi);
+		if (efi.phys_acpi20 != EFI_INVALID_ACPI_TABLE_ADDR)
+			return efi.phys_acpi20;
+		else if (efi.phys_acpi != EFI_INVALID_ACPI_TABLE_ADDR)
+			return efi.phys_acpi;
 	}
 	/*
 	 * Scan memory looking for the RSDP signature. First search EBDA (low
diff -urNp linux-2.6.13-rc3/arch/i386/kernel/efi.c linux-2.6.13-rc3-efi/arch/i386/kernel/efi.c
--- linux-2.6.13-rc3/arch/i386/kernel/efi.c	2005-07-13 00:46:46.000000000 -0400
+++ linux-2.6.13-rc3-efi/arch/i386/kernel/efi.c	2005-07-13 10:32:04.731798840 -0400
@@ -376,17 +376,20 @@ void __init efi_init(void)
 	if (config_tables = NULL)
 		printk(KERN_ERR PFX "Could not map EFI Configuration Table!\n");
 
+	efi.phys_acpi20 = EFI_INVALID_ACPI_TABLE_ADDR;
+	efi.phys_acpi = EFI_INVALID_ACPI_TABLE_ADDR;
+
 	for (i = 0; i < num_config_tables; i++) {
 		if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) = 0) {
 			efi.mps = (void *)config_tables[i].table;
 			printk(KERN_INFO " MPS=0x%lx ", config_tables[i].table);
 		} else
 		    if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) = 0) {
-			efi.acpi20 = __va(config_tables[i].table);
+			efi.phys_acpi20 = config_tables[i].table;
 			printk(KERN_INFO " ACPI 2.0=0x%lx ", config_tables[i].table);
 		} else
 		    if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) = 0) {
-			efi.acpi = __va(config_tables[i].table);
+			efi.phys_acpi = config_tables[i].table;
 			printk(KERN_INFO " ACPI=0x%lx ", config_tables[i].table);
 		} else
 		    if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) = 0) {
diff -urNp linux-2.6.13-rc3/arch/i386/kernel/setup.c linux-2.6.13-rc3-efi/arch/i386/kernel/setup.c
--- linux-2.6.13-rc3/arch/i386/kernel/setup.c	2005-07-13 00:46:46.000000000 -0400
+++ linux-2.6.13-rc3-efi/arch/i386/kernel/setup.c	2005-07-13 10:24:25.149665944 -0400
@@ -1034,10 +1034,10 @@ static int __init
 free_available_memory(unsigned long start, unsigned long end, void *arg)
 {
 	/* check max_low_pfn */
-	if (start >= ((max_low_pfn + 1) << PAGE_SHIFT))
+	if (start >= (max_low_pfn << PAGE_SHIFT))
 		return 0;
-	if (end >= ((max_low_pfn + 1) << PAGE_SHIFT))
-		end = (max_low_pfn + 1) << PAGE_SHIFT;
+	if (end >= (max_low_pfn << PAGE_SHIFT))
+		end = max_low_pfn << PAGE_SHIFT;
 	if (start < end)
 		free_bootmem(start, end - start);
 
diff -urNp linux-2.6.13-rc3/arch/ia64/kernel/acpi.c linux-2.6.13-rc3-efi/arch/ia64/kernel/acpi.c
--- linux-2.6.13-rc3/arch/ia64/kernel/acpi.c	2005-07-13 00:46:46.000000000 -0400
+++ linux-2.6.13-rc3-efi/arch/ia64/kernel/acpi.c	2005-07-13 10:33:51.614550192 -0400
@@ -615,9 +615,9 @@ acpi_find_rsdp (void)
 {
 	unsigned long rsdp_phys = 0;
 
-	if (efi.acpi20)
-		rsdp_phys = __pa(efi.acpi20);
-	else if (efi.acpi)
+	if (efi.phys_acpi20 != EFI_INVALID_ACPI_TABLE_ADDR)
+		rsdp_phys = efi.phys_acpi20;
+	else if (efi.phys_acpi != EFI_INVALID_ACPI_TABLE_ADDR)
 		printk(KERN_WARNING PREFIX "v1.0/r0.71 tables no longer supported\n");
 	return rsdp_phys;
 }
diff -urNp linux-2.6.13-rc3/arch/ia64/kernel/efi.c linux-2.6.13-rc3-efi/arch/ia64/kernel/efi.c
--- linux-2.6.13-rc3/arch/ia64/kernel/efi.c	2005-07-13 00:46:46.000000000 -0400
+++ linux-2.6.13-rc3-efi/arch/ia64/kernel/efi.c	2005-07-13 10:33:32.002531672 -0400
@@ -596,15 +596,18 @@ efi_init (void)
 	printk(KERN_INFO "EFI v%u.%.02u by %s:",
 	       efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, vendor);
 
+	efi.phys_acpi20 = EFI_INVALID_ACPI_TABLE_ADDR;
+	efi.phys_acpi = EFI_INVALID_ACPI_TABLE_ADDR;
+
 	for (i = 0; i < (int) efi.systab->nr_tables; i++) {
 		if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) = 0) {
 			efi.mps = __va(config_tables[i].table);
 			printk(" MPS=0x%lx", config_tables[i].table);
 		} else if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) = 0) {
-			efi.acpi20 = __va(config_tables[i].table);
+			efi.phys_acpi20 = config_tables[i].table;
 			printk(" ACPI 2.0=0x%lx", config_tables[i].table);
 		} else if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) = 0) {
-			efi.acpi = __va(config_tables[i].table);
+			efi.phys_acpi = config_tables[i].table;
 			printk(" ACPI=0x%lx", config_tables[i].table);
 		} else if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) = 0) {
 			efi.smbios = __va(config_tables[i].table);
diff -urNp linux-2.6.13-rc3/drivers/acpi/osl.c linux-2.6.13-rc3-efi/drivers/acpi/osl.c
--- linux-2.6.13-rc3/drivers/acpi/osl.c	2005-07-13 00:46:46.000000000 -0400
+++ linux-2.6.13-rc3-efi/drivers/acpi/osl.c	2005-07-13 10:34:25.417411376 -0400
@@ -163,12 +163,12 @@ acpi_os_get_root_pointer(u32 flags, stru
 {
 	if (efi_enabled) {
 		addr->pointer_type = ACPI_PHYSICAL_POINTER;
-		if (efi.acpi20)
+		if (efi.phys_acpi20 != EFI_INVALID_ACPI_TABLE_ADDR)
 			addr->pointer.physical -				(acpi_physical_address) virt_to_phys(efi.acpi20);
-		else if (efi.acpi)
+				(acpi_physical_address)efi.phys_acpi20;
+		else if (efi.phys_acpi != EFI_INVALID_ACPI_TABLE_ADDR)
 			addr->pointer.physical -				(acpi_physical_address) virt_to_phys(efi.acpi);
+				(acpi_physical_address)efi.phys_acpi;
 		else {
 			printk(KERN_ERR PREFIX "System description tables not found\n");
 			return AE_NOT_FOUND;
@@ -187,7 +187,9 @@ acpi_status
 acpi_os_map_memory(acpi_physical_address phys, acpi_size size, void __iomem **virt)
 {
 	if (efi_enabled) {
-		if (EFI_MEMORY_WB & efi_mem_attributes(phys)) {
+		/* determine whether or not we need to call ioremap */
+		if ((EFI_MEMORY_WB & efi_mem_attributes(phys)) && 
+			((unsigned long)phys < (unsigned long)__pa(high_memory))) {
 			*virt = (void __iomem *) phys_to_virt(phys);
 		} else {
 			*virt = ioremap(phys, size);
diff -urNp linux-2.6.13-rc3/drivers/acpi/tables.c linux-2.6.13-rc3-efi/drivers/acpi/tables.c
--- linux-2.6.13-rc3/drivers/acpi/tables.c	2005-07-13 00:46:46.000000000 -0400
+++ linux-2.6.13-rc3-efi/drivers/acpi/tables.c	2005-07-13 10:24:25.180661232 -0400
@@ -581,7 +581,8 @@ acpi_table_init (void)
 		return -ENODEV;
 	}
 
-	rsdp = (struct acpi_table_rsdp *) __va(rsdp_phys);
+	rsdp = (struct acpi_table_rsdp *) __acpi_map_table(rsdp_phys, 
+		sizeof(struct acpi_table_rsdp));
 	if (!rsdp) {
 		printk(KERN_WARNING PREFIX "Unable to map RSDP\n");
 		return -ENODEV;
diff -urNp linux-2.6.13-rc3/drivers/firmware/efivars.c linux-2.6.13-rc3-efi/drivers/firmware/efivars.c
--- linux-2.6.13-rc3/drivers/firmware/efivars.c	2005-07-13 00:46:46.000000000 -0400
+++ linux-2.6.13-rc3-efi/drivers/firmware/efivars.c	2005-07-13 10:24:25.183660776 -0400
@@ -570,10 +570,10 @@ systab_read(struct subsystem *entry, cha
 
 	if (efi.mps)
 		str += sprintf(str, "MPS=0x%lx\n", __pa(efi.mps));
-	if (efi.acpi20)
-		str += sprintf(str, "ACPI20=0x%lx\n", __pa(efi.acpi20));
-	if (efi.acpi)
-		str += sprintf(str, "ACPI=0x%lx\n", __pa(efi.acpi));
+	if (efi.phys_acpi20 != ~0UL)
+		str += sprintf(str, "ACPI20=0x%lx\n", efi.phys_acpi20);
+	if (efi.phys_acpi != ~0UL)
+		str += sprintf(str, "ACPI=0x%lx\n", efi.phys_acpi);
 	if (efi.smbios)
 		str += sprintf(str, "SMBIOS=0x%lx\n", __pa(efi.smbios));
 	if (efi.hcdp)
diff -urNp linux-2.6.13-rc3/include/linux/efi.h linux-2.6.13-rc3-efi/include/linux/efi.h
--- linux-2.6.13-rc3/include/linux/efi.h	2005-07-13 00:46:46.000000000 -0400
+++ linux-2.6.13-rc3-efi/include/linux/efi.h	2005-07-13 10:36:24.999232176 -0400
@@ -246,14 +246,16 @@ struct efi_memory_map {
 	unsigned long desc_version;
 };
 
+#define EFI_INVALID_ACPI_TABLE_ADDR	(~0UL)
+
 /*
  * All runtime access to EFI goes through this structure:
  */
 extern struct efi {
 	efi_system_table_t *systab;	/* EFI system table */
 	void *mps;			/* MPS table */
-	void *acpi;			/* ACPI table  (IA64 ext 0.71) */
-	void *acpi20;			/* ACPI table  (ACPI 2.0) */
+	unsigned long phys_acpi;	/* ACPI table  */
+	unsigned long phys_acpi20;	/* ACPI table  (ACPI 2.0) */
 	void *smbios;			/* SM BIOS table */
 	void *sal_systab;		/* SAL system table */
 	void *boot_info;		/* boot info table */

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [patch] fix ACPI table discovery from EFI for x86
  2005-07-14  0:59 [patch] fix ACPI table discovery from EFI for x86 Matt Tolentino
@ 2005-08-04 22:07 ` Bjorn Helgaas
  2005-08-04 22:34 ` Tolentino, Matthew E
  1 sibling, 0 replies; 3+ messages in thread
From: Bjorn Helgaas @ 2005-08-04 22:07 UTC (permalink / raw)
  To: Matt Tolentino; +Cc: linux-kernel, akpm, linux-ia64, tony.luck

On Wednesday 13 July 2005 7:09 pm, Matt Tolentino wrote:
> This patch addresses a problem on x86 EFI systems with larger memory
> configurations.  Up until now, we've relied on the fact that the 
> ACPI RSDT would reside somewhere in low memory that could be permanently 
> mapped in kernel address space - so __va() has been sufficient.  However,
> on EFI systems, the RSDT is often anywhere in the lower 4GB of physical
> address space.  So, we may need to remap it on x86 systems.  

The hunk below breaks HP rx7620, rx8620, and Superdome (all ia64)
systems.  This is from 2.6.13-rc4-mm1, in

    acpi-fix-table-discovery-from-efi-for-x86.patch

> @@ -187,7 +187,9 @@ acpi_status
>  acpi_os_map_memory(acpi_physical_address phys, acpi_size size, void __iomem **virt)
>  {
>  	if (efi_enabled) {
> -		if (EFI_MEMORY_WB & efi_mem_attributes(phys)) {
> +		/* determine whether or not we need to call ioremap */
> +		if ((EFI_MEMORY_WB & efi_mem_attributes(phys)) && 
> +			((unsigned long)phys < (unsigned long)__pa(high_memory))) {
>  			*virt = (void __iomem *) phys_to_virt(phys);
>  		} else {
>  			*virt = ioremap(phys, size);

If "phys >= __pa(high_memory)", we use ioremap(), but there's no
guarantee that phys is in memory that supports UC.  On the systems
I mentioned, phys is above high_memory, but in memory that only
supports WB, which leads to an MCA.

Here's a bit of the memmap:

available  0000000100000000-00000007FDFFFFFF  00000000006FE000 0000000000000008
reserved   00000040000A0000-00000040000BFFFF  0000000000000020 0000000000000008
available  0000004080000000-00000040FED9FFFF  000000000007EDA0 0000000000000008
BS_data    00000040FEDA0000-00000040FEDA1FFF  0000000000000002 0000000000000008
available  00000040FEDA2000-00000040FEDA7FFF  0000000000000006 0000000000000008
BS_data    00000040FEDA8000-00000040FF1FFFFF  0000000000000458 0000000000000008
available  00000040FF200000-00000040FF555FFF  0000000000000356 0000000000000008
RT_code    00000040FF556000-00000040FF5BFFFF  000000000000006A 8000000000000008
BS_code    00000040FF5C0000-00000040FF5FFFFF  0000000000000040 0000000000000008
available  00000040FF600000-00000040FF641FFF  0000000000000042 0000000000000008
RT_code    00000040FF642000-00000040FF67FFFF  000000000000003E 8000000000000008
available  00000040FF680000-00000040FF7DFFFF  0000000000000160 0000000000000008
RT_data    00000040FF7E0000-00000040FF7FFFFF  0000000000000020 8000000000000008
RT_code    00000703FF000000-00000703FFFFFFFF  0000000000001000 8000000000000008
PAL_code   00000723FF000000-00000723FF03FFFF  0000000000000040 8000000000000008
RT_code    00000723FF040000-00000723FFBAFFFF  0000000000000B70 8000000000000008
reserved   00000723FFBB0000-00000723FFE8FFFF  00000000000002E0 8000000000000008
RT_code    00000723FFE90000-00000723FFFFFFFF  0000000000000170 8000000000000008
MemMapIO   00000F0000000000-00000F003FFFFFFF  0000000000040000 8000000000000001

The firmware tables are up in the reserved section at 0x723FFBB0000:

    EFI v1.10 by HP: SALsystab=0x723ff7e7640 ACPI 2.0=0x723ffbb0000 HCDP=0x723ffbf27f0 SMBIOS=0x7fffe000

But high_memory is only 0x00000040ff000000 because there's no available
memory for the OS to use above that point (there are a few pages marked
"available", but we ignore them to avoid attribute aliasing on ia64).

So we erroneously try to ioremap the ACPI tables, which causes uncached
accesses to them, which blows up because they really live in memory that
doesn't support UC.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* RE: [patch] fix ACPI table discovery from EFI for x86
  2005-07-14  0:59 [patch] fix ACPI table discovery from EFI for x86 Matt Tolentino
  2005-08-04 22:07 ` Bjorn Helgaas
@ 2005-08-04 22:34 ` Tolentino, Matthew E
  1 sibling, 0 replies; 3+ messages in thread
From: Tolentino, Matthew E @ 2005-08-04 22:34 UTC (permalink / raw)
  To: Bjorn Helgaas, Brown, Len; +Cc: linux-kernel, akpm, linux-ia64, Luck, Tony

Bjorn Helgaas <> wrote:
> On Wednesday 13 July 2005 7:09 pm, Matt Tolentino wrote:
>> This patch addresses a problem on x86 EFI systems with larger memory
>> configurations.  Up until now, we've relied on the fact that the
>> ACPI RSDT would reside somewhere in low memory that could be
>> permanently 
>> mapped in kernel address space - so __va() has been sufficient. 
>> However, 
>> on EFI systems, the RSDT is often anywhere in the lower 4GB of
>> physical 
>> address space.  So, we may need to remap it on x86 systems.
> 
> The hunk below breaks HP rx7620, rx8620, and Superdome (all ia64)
> systems.  This is from 2.6.13-rc4-mm1, in

Ugh.  Well, that's pretty ugly...

Andrew, Len, please drop this one until I look at this closer.  

>     acpi-fix-table-discovery-from-efi-for-x86.patch

Thanks for testing Bjorn.  

matt 

 

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2005-08-04 22:34 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-07-14  0:59 [patch] fix ACPI table discovery from EFI for x86 Matt Tolentino
2005-08-04 22:07 ` Bjorn Helgaas
2005-08-04 22:34 ` Tolentino, Matthew E

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox