2013-02-22 21:42:01 +00:00
|
|
|
# HG changeset patch
|
|
|
|
# User Tomasz Wroblewski <tomasz.wroblewski@citrix.com>
|
|
|
|
# Date 1358933464 -3600
|
|
|
|
# Node ID 9efe4c0bf9c8d3ecf03868c69c24dad3218523a4
|
|
|
|
# Parent 7c6ecf2c1831a1c7f63a96f119a8891891463e54
|
|
|
|
fix acpi_dmar_zap/reinstate() (fixes S3 regression)
|
|
|
|
|
|
|
|
Fix S3 regression introduced by cs 23013:65d26504e843 (ACPI: large
|
|
|
|
cleanup). The dmar virtual pointer returned from acpi_get_table cannot
|
|
|
|
be safely stored away and used later, as the underlying
|
|
|
|
acpi_os_map_memory / __acpi_map_table functions overwrite the mapping
|
|
|
|
causing it to point to different tables than dmar (last fetched table is
|
|
|
|
used). This subsequently causes acpi_dmar_reinstate() and
|
|
|
|
acpi_dmar_zap() to write data to wrong table, causing its corruption and
|
|
|
|
problems with consecutive s3 resumes.
|
|
|
|
|
|
|
|
Added a new function to fetch ACPI table physical address, and
|
|
|
|
establishing separate static mapping for dmar_table pointer instead of
|
|
|
|
using acpi_get_table().
|
|
|
|
|
|
|
|
Signed-off-by: Tomasz Wroblewski <tomasz.wroblewski@citrix.com>
|
|
|
|
|
|
|
|
Added call to acpi_tb_verify_table(). Fixed page count passed to
|
|
|
|
map_pages_to_xen(). Cosmetic changes.
|
|
|
|
|
|
|
|
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
|
|
|
Committed-by: Jan Beulich <jbeulich@suse.com>
|
|
|
|
|
|
|
|
--- a/xen/drivers/acpi/tables/tbxface.c
|
|
|
|
+++ b/xen/drivers/acpi/tables/tbxface.c
|
|
|
|
@@ -205,3 +205,51 @@ acpi_get_table(char *signature,
|
|
|
|
|
|
|
|
return (AE_NOT_FOUND);
|
|
|
|
}
|
|
|
|
+
|
|
|
|
+/******************************************************************************
|
|
|
|
+ *
|
|
|
|
+ * FUNCTION: acpi_get_table_phys
|
|
|
|
+ *
|
|
|
|
+ * PARAMETERS: signature - ACPI signature of needed table
|
|
|
|
+ * instance - Which instance (for SSDTs)
|
|
|
|
+ * addr - Where the table's physical address is returned
|
|
|
|
+ * len - Where the length of table is returned
|
|
|
|
+ *
|
|
|
|
+ * RETURN: Status, pointer and length of table
|
|
|
|
+ *
|
|
|
|
+ * DESCRIPTION: Finds physical address and length of ACPI table
|
|
|
|
+ *
|
|
|
|
+ *****************************************************************************/
|
|
|
|
+acpi_status __init
|
|
|
|
+acpi_get_table_phys(acpi_string signature, acpi_native_uint instance,
|
|
|
|
+ acpi_physical_address *addr, acpi_native_uint *len)
|
|
|
|
+{
|
|
|
|
+ acpi_native_uint i, j;
|
|
|
|
+ acpi_status status;
|
|
|
|
+
|
|
|
|
+ if (!signature || !addr || !len)
|
|
|
|
+ return AE_BAD_PARAMETER;
|
|
|
|
+
|
|
|
|
+ for (i = j = 0; i < acpi_gbl_root_table_list.count; i++) {
|
|
|
|
+ if (!ACPI_COMPARE_NAME(
|
|
|
|
+ &acpi_gbl_root_table_list.tables[i].signature,
|
|
|
|
+ signature))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (++j < instance)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ status =
|
|
|
|
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]);
|
|
|
|
+ if (ACPI_SUCCESS(status)) {
|
|
|
|
+ *addr = acpi_gbl_root_table_list.tables[i].address;
|
|
|
|
+ *len = acpi_gbl_root_table_list.tables[i].length;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ acpi_gbl_root_table_list.tables[i].pointer = NULL;
|
|
|
|
+
|
|
|
|
+ return status;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return AE_NOT_FOUND;
|
|
|
|
+}
|
|
|
|
--- a/xen/drivers/passthrough/vtd/dmar.c
|
|
|
|
+++ b/xen/drivers/passthrough/vtd/dmar.c
|
2013-03-21 22:43:53 +00:00
|
|
|
@@ -776,6 +776,7 @@ out:
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_X86
|
|
|
|
+#include <asm/fixmap.h>
|
|
|
|
#include <asm/tboot.h>
|
|
|
|
/* ACPI tables may not be DMA protected by tboot, so use DMAR copy */
|
|
|
|
/* SINIT saved in SinitMleData in TXT heap (which is DMA protected) */
|
|
|
|
@@ -786,7 +787,32 @@ out:
|
2013-02-22 21:42:01 +00:00
|
|
|
|
|
|
|
int __init acpi_dmar_init(void)
|
|
|
|
{
|
|
|
|
- acpi_get_table(ACPI_SIG_DMAR, 0, &dmar_table);
|
|
|
|
+ acpi_physical_address dmar_addr;
|
|
|
|
+ acpi_native_uint dmar_len;
|
|
|
|
+
|
|
|
|
+ if ( ACPI_SUCCESS(acpi_get_table_phys(ACPI_SIG_DMAR, 0,
|
|
|
|
+ &dmar_addr, &dmar_len)) )
|
|
|
|
+ {
|
2013-03-21 22:43:53 +00:00
|
|
|
+#ifdef CONFIG_X86_32
|
|
|
|
+ if ( dmar_addr + dmar_len > (DIRECTMAP_MBYTES << 20) )
|
|
|
|
+ {
|
|
|
|
+ unsigned long offset = dmar_addr & (PAGE_SIZE - 1);
|
|
|
|
+ unsigned long mapped_size = PAGE_SIZE - offset;
|
|
|
|
+
|
|
|
|
+ set_fixmap(FIX_DMAR_ZAP_LO, dmar_addr);
|
|
|
|
+ if ( mapped_size < sizeof(*dmar_table) )
|
|
|
|
+ set_fixmap(FIX_DMAR_ZAP_HI, dmar_addr + PAGE_SIZE);
|
|
|
|
+ dmar_table = (void *)fix_to_virt(FIX_DMAR_ZAP_LO) + offset;
|
|
|
|
+ goto exit;
|
|
|
|
+ }
|
|
|
|
+#endif
|
2013-02-22 21:42:01 +00:00
|
|
|
+ map_pages_to_xen((unsigned long)__va(dmar_addr), PFN_DOWN(dmar_addr),
|
|
|
|
+ PFN_UP(dmar_addr + dmar_len) - PFN_DOWN(dmar_addr),
|
|
|
|
+ PAGE_HYPERVISOR);
|
|
|
|
+ dmar_table = __va(dmar_addr);
|
|
|
|
+ }
|
|
|
|
+
|
2013-03-21 22:43:53 +00:00
|
|
|
+ exit: __attribute__((__unused__))
|
2013-02-22 21:42:01 +00:00
|
|
|
return parse_dmar_table(acpi_parse_dmar);
|
|
|
|
}
|
|
|
|
|
|
|
|
--- a/xen/include/acpi/acpixf.h
|
|
|
|
+++ b/xen/include/acpi/acpixf.h
|
|
|
|
@@ -77,6 +77,9 @@ acpi_status
|
|
|
|
acpi_get_table(acpi_string signature,
|
|
|
|
acpi_native_uint instance, struct acpi_table_header **out_table);
|
|
|
|
|
|
|
|
+acpi_status
|
|
|
|
+acpi_get_table_phys(acpi_string signature, acpi_native_uint instance,
|
|
|
|
+ acpi_physical_address *addr, acpi_native_uint *len);
|
|
|
|
/*
|
|
|
|
* Namespace and name interfaces
|
|
|
|
*/
|
2013-03-21 22:43:53 +00:00
|
|
|
--- a/xen/include/asm-x86/fixmap.h
|
|
|
|
+++ b/xen/include/asm-x86/fixmap.h
|
|
|
|
@@ -50,6 +50,8 @@ enum fixed_addresses {
|
|
|
|
FIX_PAE_HIGHMEM_END = FIX_PAE_HIGHMEM_0 + NR_CPUS-1,
|
|
|
|
#define FIX_VGC_END FIX_PAE_HIGHMEM_0
|
|
|
|
#define FIX_VGC_BEGIN FIX_PAE_HIGHMEM_END
|
|
|
|
+ FIX_DMAR_ZAP_HI,
|
|
|
|
+ FIX_DMAR_ZAP_LO,
|
|
|
|
#else
|
|
|
|
FIX_VGC_END,
|
|
|
|
FIX_VGC_BEGIN = FIX_VGC_END
|