# HG changeset patch
# User Keir Fraser <keir@xen.org>
# Date 1291922374 0
# Node ID d9fc83a64a82624e24876250dd88b2cd9528d266
# Parent  49d2aa5cee4ecc2411d8d638e4ee32c10e9b2761
x86: x2apic: Large cleanup
References: bnc#656369, bnc#658704

Signed-off-by: Keir Fraser <keir@xen.org>

Index: xen-4.0.2-testing/xen/arch/x86/apic.c
===================================================================
--- xen-4.0.2-testing.orig/xen/arch/x86/apic.c
+++ xen-4.0.2-testing/xen/arch/x86/apic.c
@@ -67,12 +67,12 @@ static int enable_local_apic __initdata
  */
 int apic_verbosity;
 
+static int opt_x2apic = 1;
+boolean_param("x2apic", opt_x2apic);
+
 int x2apic_enabled __read_mostly = 0;
 int directed_eoi_enabled __read_mostly = 0;
 
-/* x2APIC is enabled in BIOS */
-static int x2apic_preenabled;
-
 /*
  * The following vectors are part of the Linux architecture, there
  * is no hardware IRQ pin equivalent for them, they are triggered
@@ -942,30 +942,24 @@ no_apic:
     return -1;
 }
 
-void check_x2apic_preenabled(void)
+void x2apic_setup(void)
 {
+    struct IO_APIC_route_entry **ioapic_entries = NULL;
     u32 lo, hi;
 
-    if ( !x2apic_is_available() )
-        return;
-
-    rdmsr(MSR_IA32_APICBASE, lo, hi);
-    if ( lo & MSR_IA32_APICBASE_EXTD )
+    if ( smp_processor_id() != 0 )
     {
-        printk("x2APIC mode is already enabled by BIOS.\n");
-        x2apic_preenabled = 1;
-        x2apic_enabled = 1;
+        if ( x2apic_enabled )
+            __enable_x2apic();
+        return;
     }
-}
 
-static void enable_bsp_x2apic(void)
-{
-    struct IO_APIC_route_entry **ioapic_entries = NULL;
-    const struct genapic *x2apic_genapic = NULL;
-
-    ASSERT(smp_processor_id() == 0);
+    if ( !cpu_has_x2apic )
+        return;
 
-    if ( x2apic_preenabled )
+    /* Check whether x2apic mode was already enabled by the BIOS. */
+    rdmsr(MSR_IA32_APICBASE, lo, hi);
+    if ( lo & MSR_IA32_APICBASE_EXTD )
     {
         /*
          * Interrupt remapping should be also enabled by BIOS when
@@ -975,39 +969,33 @@ static void enable_bsp_x2apic(void)
         if ( !intremap_enabled() )
             panic("Interrupt remapping is not enabled by BIOS while "
                   "x2APIC is already enabled by BIOS!\n");
+
+        printk("x2APIC mode is already enabled by BIOS.\n");
+        x2apic_enabled = 1;
     }
 
-    x2apic_genapic = apic_x2apic_probe();
-    if ( x2apic_genapic )
-        genapic = x2apic_genapic;
-    else
+    if ( !opt_x2apic )
     {
-        if ( x2apic_cmdline_disable() )
+        if ( !x2apic_enabled )
         {
-            if ( x2apic_preenabled )
-            {
-                /* Ignore x2apic=0, and set default x2apic mode */
-                genapic = &apic_x2apic_cluster;
-                printk("x2APIC: already enabled by BIOS, ignore x2apic=0.\n");
-            }
-            else
-            {
-                printk("Not enable x2APIC due to x2apic=0 is set.\n");
-                return;
-            }
+            printk("Not enabling x2APIC: disabled by cmdline.\n");
+            return;
         }
-        else
+        printk("x2APIC: Already enabled by BIOS: Ignoring cmdline disable.\n");
+    }
+
+    if ( !iommu_supports_eim() )
+    {
+        if ( !x2apic_enabled )
         {
-            if ( x2apic_preenabled )
-                panic("x2APIC: already enabled by BIOS, but "
-                      "iommu_supports_eim failed!\n");
-            printk("Not enabling x2APIC: depends oniommu_supports_eim\n");
+            printk("Not enabling x2APIC: depends on iommu_supports_eim.\n");
             return;
         }
+        panic("x2APIC: already enabled by BIOS, but "
+              "iommu_supports_eim failed!\n");
     }
 
-    ioapic_entries = alloc_ioapic_entries();
-    if ( !ioapic_entries )
+    if ( (ioapic_entries = alloc_ioapic_entries()) == NULL )
     {
         printk("Allocate ioapic_entries failed\n");
         goto out;
@@ -1029,13 +1017,13 @@ static void enable_bsp_x2apic(void)
         goto restore_out;
     }
 
-    x2apic_enabled = 1;
+    genapic = apic_x2apic_probe();
     printk("Switched to APIC driver %s.\n", genapic->name);
 
-    if ( !x2apic_preenabled )
+    if ( !x2apic_enabled )
     {
+        x2apic_enabled = 1;
         __enable_x2apic();
-        printk("x2APIC mode enabled.\n");
     }
 
 restore_out:
@@ -1047,24 +1035,6 @@ out:
         free_ioapic_entries(ioapic_entries);
 }
 
-static void enable_ap_x2apic(void)
-{
-    ASSERT(smp_processor_id() != 0);
-
-    /* APs only enable x2apic when BSP did so. */
-    BUG_ON(!x2apic_enabled);
-
-    __enable_x2apic();
-}
-
-void enable_x2apic(void)
-{
-    if ( smp_processor_id() == 0 )
-        enable_bsp_x2apic();
-    else
-        enable_ap_x2apic();
-}
-
 void __init init_apic_mappings(void)
 {
     unsigned long apic_phys;
Index: xen-4.0.2-testing/xen/arch/x86/cpu/common.c
===================================================================
--- xen-4.0.2-testing.orig/xen/arch/x86/cpu/common.c
+++ xen-4.0.2-testing/xen/arch/x86/cpu/common.c
@@ -252,8 +252,8 @@ static void __init early_cpu_detect(void
 
 	c->x86 = 4;
 	if (c->cpuid_level >= 0x00000001) {
-		u32 junk, tfms, cap0, misc;
-		cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
+		u32 cap4, tfms, cap0, misc;
+		cpuid(0x00000001, &tfms, &misc, &cap4, &cap0);
 		c->x86 = (tfms >> 8) & 15;
 		c->x86_model = (tfms >> 4) & 15;
 		if (c->x86 == 0xf)
@@ -262,9 +262,12 @@ static void __init early_cpu_detect(void
 			c->x86_model += ((tfms >> 16) & 0xF) << 4;
 		c->x86_mask = tfms & 15;
 		cap0 &= ~cleared_caps[0];
+		cap4 &= ~cleared_caps[4];
 		if (cap0 & (1<<19))
 			c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8;
-		c->x86_capability[0] = cap0; /* Added for Xen bootstrap */
+		/* Leaf 0x1 capabilities filled in early for Xen. */
+		c->x86_capability[0] = cap0;
+		c->x86_capability[4] = cap4;
 	}
 }
 
Index: xen-4.0.2-testing/xen/arch/x86/genapic/x2apic.c
===================================================================
--- xen-4.0.2-testing.orig/xen/arch/x86/genapic/x2apic.c
+++ xen-4.0.2-testing/xen/arch/x86/genapic/x2apic.c
@@ -23,89 +23,44 @@
 #include <xen/smp.h>
 #include <asm/mach-default/mach_mpparse.h>
 
-static int x2apic = 1;
-boolean_param("x2apic", x2apic);
-
-static int  x2apic_phys; /* By default we use logical cluster mode. */
+static int x2apic_phys; /* By default we use logical cluster mode. */
 boolean_param("x2apic_phys", x2apic_phys);
 
-int x2apic_cmdline_disable(void)
-{
-    return (x2apic == 0);
-}
-
-static int probe_x2apic_phys(void)
+static void init_apic_ldr_x2apic_phys(void)
 {
-    return x2apic && x2apic_phys && x2apic_is_available() &&
-        iommu_supports_eim();
 }
 
-static int probe_x2apic_cluster(void)
-{
-    return x2apic && !x2apic_phys && x2apic_is_available() &&
-        iommu_supports_eim();
-}
-
-const struct genapic apic_x2apic_phys = {
-    APIC_INIT("x2apic_phys", probe_x2apic_phys),
-    GENAPIC_X2APIC_PHYS
-};
-
-const struct genapic apic_x2apic_cluster = {
-    APIC_INIT("x2apic_cluster", probe_x2apic_cluster),
-    GENAPIC_X2APIC_CLUSTER
-};
-
-const struct genapic *apic_x2apic_probe(void)
-{
-    if ( !x2apic || !x2apic_is_available() )
-        return NULL;
-
-    if ( !iommu_supports_eim() )
-        return NULL;
-
-    if ( x2apic_phys )
-        return &apic_x2apic_phys;
-    else
-        return &apic_x2apic_cluster;
-}
-
-void init_apic_ldr_x2apic_phys(void)
-{
-    return;
-}
-
-void init_apic_ldr_x2apic_cluster(void)
+static void init_apic_ldr_x2apic_cluster(void)
 {
     int cpu = smp_processor_id();
     cpu_2_logical_apicid[cpu] = apic_read(APIC_LDR);
 }
-void clustered_apic_check_x2apic(void)
+
+static void clustered_apic_check_x2apic(void)
 {
-    return;
 }
 
-cpumask_t target_cpus_x2apic(void)
+static cpumask_t target_cpus_x2apic(void)
 {
     return cpu_online_map;
 }
 
-cpumask_t vector_allocation_domain_x2apic(int cpu)
+static cpumask_t vector_allocation_domain_x2apic(int cpu)
 {
 	return cpumask_of_cpu(cpu);
 }
 
-unsigned int cpu_mask_to_apicid_x2apic_phys(cpumask_t cpumask)
+static unsigned int cpu_mask_to_apicid_x2apic_phys(cpumask_t cpumask)
 {
     return cpu_physical_id(first_cpu(cpumask));
 }
 
-unsigned int cpu_mask_to_apicid_x2apic_cluster(cpumask_t cpumask)
+static unsigned int cpu_mask_to_apicid_x2apic_cluster(cpumask_t cpumask)
 {
     return cpu_2_logical_apicid[first_cpu(cpumask)];
 }
 
-void send_IPI_mask_x2apic_phys(const cpumask_t *cpumask, int vector)
+static void send_IPI_mask_x2apic_phys(const cpumask_t *cpumask, int vector)
 {
     unsigned int cpu, cfg;
     unsigned long flags;
@@ -132,7 +87,7 @@ void send_IPI_mask_x2apic_phys(const cpu
     local_irq_restore(flags);
 }
 
-void send_IPI_mask_x2apic_cluster(const cpumask_t *cpumask, int vector)
+static void send_IPI_mask_x2apic_cluster(const cpumask_t *cpumask, int vector)
 {
     unsigned int cpu, cfg;
     unsigned long flags;
@@ -148,3 +103,34 @@ void send_IPI_mask_x2apic_cluster(const
 
     local_irq_restore(flags);
 }
+
+static const struct genapic apic_x2apic_phys = {
+    APIC_INIT("x2apic_phys", NULL),
+    .int_delivery_mode = dest_Fixed,
+    .int_dest_mode = 0 /* physical delivery */,
+    .init_apic_ldr = init_apic_ldr_x2apic_phys,
+    .clustered_apic_check = clustered_apic_check_x2apic,
+    .target_cpus = target_cpus_x2apic,
+    .vector_allocation_domain = vector_allocation_domain_x2apic,
+    .cpu_mask_to_apicid = cpu_mask_to_apicid_x2apic_phys,
+    .send_IPI_mask = send_IPI_mask_x2apic_phys,
+    .send_IPI_self = send_IPI_self_x2apic
+};
+
+static const struct genapic apic_x2apic_cluster = {
+    APIC_INIT("x2apic_cluster", NULL),
+    .int_delivery_mode = dest_LowestPrio,
+    .int_dest_mode = 1 /* logical delivery */,
+    .init_apic_ldr = init_apic_ldr_x2apic_cluster,
+    .clustered_apic_check = clustered_apic_check_x2apic,
+    .target_cpus = target_cpus_x2apic,
+    .vector_allocation_domain = vector_allocation_domain_x2apic,
+    .cpu_mask_to_apicid = cpu_mask_to_apicid_x2apic_cluster,
+    .send_IPI_mask = send_IPI_mask_x2apic_cluster,
+    .send_IPI_self = send_IPI_self_x2apic
+};
+
+const struct genapic *apic_x2apic_probe(void)
+{
+    return x2apic_phys ? &apic_x2apic_phys : &apic_x2apic_cluster;
+}
Index: xen-4.0.2-testing/xen/arch/x86/setup.c
===================================================================
--- xen-4.0.2-testing.orig/xen/arch/x86/setup.c
+++ xen-4.0.2-testing/xen/arch/x86/setup.c
@@ -1006,9 +1006,6 @@ void __init __start_xen(unsigned long mb
 
     tboot_probe();
 
-    /* Check if x2APIC is already enabled in BIOS */
-    check_x2apic_preenabled();
-
     /* Unmap the first page of CPU0's stack. */
     memguard_guard_stack(cpu0_stack);
 
@@ -1039,8 +1036,7 @@ void __init __start_xen(unsigned long mb
 
     init_apic_mappings();
 
-    if ( x2apic_is_available() )
-        enable_x2apic();
+    x2apic_setup();
 
     percpu_free_unused_areas();
 
Index: xen-4.0.2-testing/xen/arch/x86/smpboot.c
===================================================================
--- xen-4.0.2-testing.orig/xen/arch/x86/smpboot.c
+++ xen-4.0.2-testing/xen/arch/x86/smpboot.c
@@ -326,8 +326,7 @@ void __devinit smp_callin(void)
 	 */
 	wait_for_init_deassert(&init_deasserted);
 
-	if ( x2apic_enabled )
-		enable_x2apic();
+	x2apic_setup();
 
 	/*
 	 * (This works even if the APIC is not enabled.)
Index: xen-4.0.2-testing/xen/drivers/passthrough/vtd/intremap.c
===================================================================
--- xen-4.0.2-testing.orig/xen/drivers/passthrough/vtd/intremap.c
+++ xen-4.0.2-testing/xen/drivers/passthrough/vtd/intremap.c
@@ -129,15 +129,10 @@ int iommu_supports_eim(void)
     struct acpi_drhd_unit *drhd;
     int apic;
 
-    if ( !iommu_enabled || !iommu_qinval || !iommu_intremap )
+    if ( !iommu_enabled || !iommu_qinval || !iommu_intremap ||
+         list_empty(&acpi_drhd_units) )
         return 0;
 
-    if ( list_empty(&acpi_drhd_units) )
-    {
-        dprintk(XENLOG_WARNING VTDPREFIX, "VT-d is not supported\n");
-        return 0;
-    }
-
     /* We MUST have a DRHD unit for each IOAPIC. */
     for ( apic = 0; apic < nr_ioapics; apic++ )
         if ( !ioapic_to_drhd(IO_APIC_ID(apic)) )
Index: xen-4.0.2-testing/xen/include/asm-x86/apic.h
===================================================================
--- xen-4.0.2-testing.orig/xen/include/asm-x86/apic.h
+++ xen-4.0.2-testing/xen/include/asm-x86/apic.h
@@ -25,21 +25,8 @@ extern int apic_verbosity;
 extern int x2apic_enabled;
 extern int directed_eoi_enabled;
 
-extern void check_x2apic_preenabled(void);
-extern int x2apic_cmdline_disable(void);
-extern void enable_x2apic(void);
-
-static __inline int x2apic_is_available(void)
-{
-    unsigned int op = 1, eax, ecx;
-
-    asm ( "cpuid"
-          : "=a" (eax), "=c" (ecx)
-          : "0" (op)
-          : "bx", "dx" );
-
-    return (ecx & (1U << 21));
-}
+void x2apic_setup(void);
+const struct genapic *apic_x2apic_probe(void);
 
 /*
  * Define the default level of output to be very little
Index: xen-4.0.2-testing/xen/include/asm-x86/genapic.h
===================================================================
--- xen-4.0.2-testing.orig/xen/include/asm-x86/genapic.h
+++ xen-4.0.2-testing/xen/include/asm-x86/genapic.h
@@ -49,8 +49,6 @@ struct genapic {
 	APICFUNC(acpi_madt_oem_check)
 
 extern const struct genapic *genapic;
-extern const struct genapic apic_x2apic_phys;
-extern const struct genapic apic_x2apic_cluster;
 
 void init_apic_ldr_flat(void);
 void clustered_apic_check_flat(void);
@@ -70,39 +68,6 @@ cpumask_t vector_allocation_domain_flat(
 	.send_IPI_mask = send_IPI_mask_flat, \
 	.send_IPI_self = send_IPI_self_flat
 
-const struct genapic *apic_x2apic_probe(void);
-void init_apic_ldr_x2apic_phys(void);
-void init_apic_ldr_x2apic_cluster(void);
-void clustered_apic_check_x2apic(void);
-cpumask_t target_cpus_x2apic(void);
-unsigned int cpu_mask_to_apicid_x2apic_phys(cpumask_t cpumask);
-unsigned int cpu_mask_to_apicid_x2apic_cluster(cpumask_t cpumask);
-void send_IPI_mask_x2apic_phys(const cpumask_t *mask, int vector);
-void send_IPI_mask_x2apic_cluster(const cpumask_t *mask, int vector);
-void send_IPI_self_x2apic(int vector);
-cpumask_t vector_allocation_domain_x2apic(int cpu);
-#define GENAPIC_X2APIC_PHYS \
-	.int_delivery_mode = dest_Fixed, \
-	.int_dest_mode = 0 /* physical delivery */, \
-	.init_apic_ldr = init_apic_ldr_x2apic_phys, \
-	.clustered_apic_check = clustered_apic_check_x2apic, \
-	.target_cpus = target_cpus_x2apic, \
-	.vector_allocation_domain = vector_allocation_domain_x2apic, \
-	.cpu_mask_to_apicid = cpu_mask_to_apicid_x2apic_phys, \
-	.send_IPI_mask = send_IPI_mask_x2apic_phys,       \
-	.send_IPI_self = send_IPI_self_x2apic
-
-#define GENAPIC_X2APIC_CLUSTER \
-    .int_delivery_mode = dest_LowestPrio, \
-    .int_dest_mode = 1 /* logical delivery */, \
-    .init_apic_ldr = init_apic_ldr_x2apic_cluster, \
-    .clustered_apic_check = clustered_apic_check_x2apic, \
-    .target_cpus = target_cpus_x2apic, \
-    .vector_allocation_domain = vector_allocation_domain_x2apic, \
-    .cpu_mask_to_apicid = cpu_mask_to_apicid_x2apic_cluster, \
-    .send_IPI_mask = send_IPI_mask_x2apic_cluster,       \
-    .send_IPI_self = send_IPI_self_x2apic
-
 void init_apic_ldr_phys(void);
 void clustered_apic_check_phys(void);
 cpumask_t target_cpus_phys(void);
@@ -121,4 +86,6 @@ cpumask_t vector_allocation_domain_phys(
 	.send_IPI_mask = send_IPI_mask_phys, \
 	.send_IPI_self = send_IPI_self_phys
 
+void send_IPI_self_x2apic(int vector);
+
 #endif
