endchoice
-config X2APIC_PHYSICAL
- bool "x2APIC Physical Destination mode"
+choice
+ prompt "x2APIC Driver default"
+ default X2APIC_MIXED
help
- Use x2APIC Physical Destination mode by default when available.
+ Select APIC addressing when x2APIC is enabled.
+
+ The default mode is mixed which should provide the best aspects
+ of both physical and cluster modes.
+config X2APIC_PHYSICAL
+ bool "Physical Destination mode"
+ help
When using this mode APICs are addressed using the Physical
Destination mode, which allows using all dynamic vectors on each
CPU independently.
destination inter processor interrupts (IPIs) slightly slower than
Logical Destination mode.
- The mode when this option is not selected is Logical Destination.
+config X2APIC_CLUSTER
+ bool "Cluster Destination mode"
+ help
+ When using this mode APICs are addressed using the Cluster Logical
+ Destination mode.
+
+ Cluster Destination has the benefit of sending IPIs faster since
+ multiple APICs can be targeted as destinations of a single IPI.
+ However the vector space is shared between all CPUs on the cluster,
+ and hence using this mode reduces the number of available vectors
+ when compared to Physical mode.
- If unsure, say N.
+config X2APIC_MIXED
+ bool "Mixed Destination mode"
+ help
+ When using this mode APICs are addressed using the Cluster Logical
+ Destination mode for IPIs and Physical mode for external interrupts.
+
+ Should provide the best of both modes.
+
+endchoice
config GUEST
bool
.send_IPI_self = send_IPI_self_x2apic
};
+/*
+ * Mixed x2APIC mode: use physical for external (device) interrupts, and
+ * cluster for inter processor interrupts. Such mode has the benefits of not
+ * sharing the vector space with all CPUs on the cluster, while still allowing
+ * IPIs to be more efficiently delivered by not having to perform an ICR write
+ * for each target CPU.
+ */
+static const struct genapic __initconstrel apic_x2apic_mixed = {
+ APIC_INIT("x2apic_mixed", NULL),
+
+ /*
+ * The following fields are exclusively used by external interrupts and
+ * hence are set to use Physical destination mode handlers.
+ */
+ .int_delivery_mode = dest_Fixed,
+ .int_dest_mode = 0 /* physical delivery */,
+ .vector_allocation_cpumask = vector_allocation_cpumask_phys,
+ .cpu_mask_to_apicid = cpu_mask_to_apicid_phys,
+
+ /*
+ * The following fields are exclusively used by IPIs and hence are set to
+ * use Cluster Logical destination mode handlers. Note that init_apic_ldr
+ * is not used by IPIs, but the per-CPU fields it initializes are only used
+ * by the IPI hooks.
+ */
+ .init_apic_ldr = init_apic_ldr_x2apic_cluster,
+ .send_IPI_mask = send_IPI_mask_x2apic_cluster,
+ .send_IPI_self = send_IPI_self_x2apic,
+};
+
static int cf_check update_clusterinfo(
struct notifier_block *nfb, unsigned long action, void *hcpu)
{
static int8_t __initdata x2apic_phys = -1;
boolean_param("x2apic_phys", x2apic_phys);
+enum {
+ unset, physical, cluster, mixed
+} static __initdata x2apic_mode = unset;
+
+static int __init cf_check parse_x2apic_mode(const char *s)
+{
+ if ( !cmdline_strcmp(s, "physical") )
+ x2apic_mode = physical;
+ else if ( !cmdline_strcmp(s, "cluster") )
+ x2apic_mode = cluster;
+ else if ( !cmdline_strcmp(s, "mixed") )
+ x2apic_mode = mixed;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+custom_param("x2apic-mode", parse_x2apic_mode);
+
const struct genapic *__init apic_x2apic_probe(void)
{
- if ( x2apic_phys < 0 )
+ /* Honour the legacy cmdline setting if it's the only one provided. */
+ if ( x2apic_mode == unset && x2apic_phys >= 0 )
+ x2apic_mode = x2apic_phys ? physical : cluster;
+
+ if ( x2apic_mode == unset )
{
- /*
- * Force physical mode if there's no (full) interrupt remapping support:
- * The ID in clustered mode requires a 32 bit destination field due to
- * the usage of the high 16 bits to hold the cluster ID.
- */
- x2apic_phys = iommu_intremap != iommu_intremap_full ||
- (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) ||
- IS_ENABLED(CONFIG_X2APIC_PHYSICAL);
- }
- else if ( !x2apic_phys )
- switch ( iommu_intremap )
+ if ( acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL )
{
- case iommu_intremap_off:
- case iommu_intremap_restricted:
- printk("WARNING: x2APIC cluster mode is not supported %s interrupt remapping -"
- " forcing phys mode\n",
- iommu_intremap == iommu_intremap_off ? "without"
- : "with restricted");
- x2apic_phys = true;
- break;
-
- case iommu_intremap_full:
- break;
+ printk(XENLOG_INFO "ACPI FADT forcing x2APIC physical mode\n");
+ x2apic_mode = physical;
}
+ else
+ x2apic_mode = IS_ENABLED(CONFIG_X2APIC_MIXED) ? mixed
+ : (IS_ENABLED(CONFIG_X2APIC_PHYSICAL) ? physical
+ : cluster);
+ }
- if ( x2apic_phys )
+ if ( x2apic_mode == physical )
return &apic_x2apic_phys;
+ if ( x2apic_mode == cluster && iommu_intremap != iommu_intremap_full )
+ {
+ printk("WARNING: x2APIC cluster mode is not supported %s interrupt remapping -"
+ " forcing mixed mode\n",
+ iommu_intremap == iommu_intremap_off ? "without"
+ : "with restricted");
+ x2apic_mode = mixed;
+ }
+
if ( !this_cpu(cluster_cpus) )
{
update_clusterinfo(NULL, CPU_UP_PREPARE,
register_cpu_notifier(&x2apic_cpu_nfb);
}
- return &apic_x2apic_cluster;
+ return x2apic_mode == cluster ? &apic_x2apic_cluster : &apic_x2apic_mixed;
}
void __init check_x2apic_preenabled(void)