[IA64] Backup/restore ACPI tables
authorAlex Williamson <alex.williamson@hp.com>
Wed, 17 Oct 2007 16:36:31 +0000 (10:36 -0600)
committerAlex Williamson <alex.williamson@hp.com>
Wed, 17 Oct 2007 16:36:31 +0000 (10:36 -0600)
We modify some of the ACPI tables for dom0 (limiting available CPUs,
modifying id/eid, and hiding SLIT/SRAT tables).  This causes problems
when we try to kexec with different dom0 CPU counts or from Xen to
Linux.  This introduces a mechanism to save ACPI tables before
modification and restoring them before kexec.

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
Acked-by: Simon Horman <horms@verge.net.au>
xen/arch/ia64/xen/dom_fw_dom0.c
xen/arch/ia64/xen/machine_kexec.c
xen/include/asm-ia64/dom_fw_dom0.h

index 7cfa69dd51bae39eb03a461dd275627f267be4f5..68a6bae63065aaedcd84a5c6244d7e93d961b043 100644 (file)
@@ -28,6 +28,7 @@
 #include <xen/acpi.h>
 #include <xen/errno.h>
 #include <xen/sched.h>
+#include <xen/list.h>
 
 #include <asm/dom_fw.h>
 #include <asm/dom_fw_common.h>
 
 #include <linux/sort.h>
 
+struct acpi_backup_table_entry {
+       struct list_head list;
+       unsigned long pa;
+       unsigned long size;
+       unsigned char data[0];
+};
+
+static LIST_HEAD(acpi_backup_table_list);
+
 static u32 lsapic_nbr;
 
 /* Modify lsapic table.  Provides LPs.  */
@@ -100,18 +110,85 @@ acpi_update_madt_checksum(unsigned long phys_addr, unsigned long size)
        return 0;
 }
 
+static int __init
+acpi_backup_table(unsigned long phys_addr, unsigned long size)
+{
+       struct acpi_backup_table_entry *entry;
+       void *vaddr = __va(phys_addr);
+
+       if (!phys_addr || !size)
+               return -EINVAL;
+
+       entry = xmalloc_bytes(sizeof(*entry) + size);
+       if (!entry) {
+               dprintk(XENLOG_WARNING, "Failed to allocate memory for "
+                       "%.4s table backup\n",
+                       ((struct acpi_table_header *)vaddr)->signature);
+               return -ENOMEM;
+       }
+
+       entry->pa = phys_addr;
+       entry->size = size;
+
+       memcpy(entry->data, vaddr, size);
+
+       list_add(&entry->list, &acpi_backup_table_list);
+
+       printk(XENLOG_INFO "Backup %.4s table stored @0x%p\n",
+              ((struct acpi_table_header *)entry->data)->signature,
+              entry->data);
+
+       return 0;
+}
+
+void
+acpi_restore_tables()
+{
+       struct acpi_backup_table_entry *entry;
+
+       list_for_each_entry(entry, &acpi_backup_table_list, list) {
+               printk(XENLOG_INFO "Restoring backup %.4s table @0x%p\n",
+                      ((struct acpi_table_header *)entry->data)->signature,
+                      entry->data);
+
+               memcpy(__va(entry->pa), entry->data, entry->size);
+               /* Only called from kexec path, no need to free entries */
+       }
+}
+
 /* base is physical address of acpi table */
 static void __init touch_acpi_table(void)
 {
        int result;
        lsapic_nbr = 0;
 
+       /*
+        * Modify dom0 MADT:
+        *  - Disable CPUs that would exceed max vCPUs for the domain
+        *  - Virtualize id/eid for indexing into domain vCPU array
+        *  - Hide CPEI interrupt source
+        *
+        * ACPI tables must be backed-up before modification!
+        */
+       acpi_table_parse(ACPI_APIC, acpi_backup_table);
+
        if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, 0) < 0)
                printk("Error parsing MADT - no LAPIC entries\n");
        if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC,
                                  acpi_patch_plat_int_src, 0) < 0)
                printk("Error parsing MADT - no PLAT_INT_SRC entries\n");
 
+       acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum);
+
+       /*
+        * SRAT & SLIT tables aren't useful for Dom0 until
+        * we support more NUMA configuration information in Xen.
+        *
+        * NB - backup ACPI tables first.
+        */
+       acpi_table_parse(ACPI_SRAT, acpi_backup_table);
+       acpi_table_parse(ACPI_SLIT, acpi_backup_table);
+
        result = acpi_table_disable(ACPI_SRAT);
        if ( result == 0 )
                printk("Success Disabling SRAT\n");
@@ -124,8 +201,6 @@ static void __init touch_acpi_table(void)
        else if ( result != -ENOENT )
                printk("ERROR: Failed Disabling SLIT\n");
 
-       acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum);
-
        return;
 }
 
@@ -133,9 +208,9 @@ void __init efi_systable_init_dom0(struct fw_tables *tables)
 {
        int i = 1;
 
-       /* Write messages to the console.  */
        touch_acpi_table();
 
+       /* Write messages to the console.  */
        printk("Domain0 EFI passthrough:");
        if (efi.mps) {
                tables->efi_tables[i].guid = MPS_TABLE_GUID;
index 666dbc967a091f9fde771bc06305cb851cbe4d0d..b9c78fd9ed972326b1d822733588ab05711619ec 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/cpu.h>
 #include <linux/cpu.h>
 #include <linux/notifier.h>
+#include <asm/dom_fw_dom0.h>
 
 typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)(
                                        unsigned long indirection_page,
@@ -149,6 +150,7 @@ static void machine_shutdown(void)
        }
 #endif
        kexec_disable_iosapic();
+       acpi_restore_tables();
 }
 
 void machine_kexec(xen_kexec_image_t *image)
index 11e199cb5cd80e37dbb057b19866ece30712101b..cc52c908b833c4d429a1cf5423958a43e02da599 100644 (file)
@@ -26,6 +26,7 @@ struct domain;
 
 void efi_systable_init_dom0(struct fw_tables *tables);
 int complete_dom0_memmap(struct domain *d, struct fw_tables *tables);
+void acpi_restore_tables(void);
 
 #endif /* __ASM_IA64_DOM_FW_DOM0_H__ */
 /*