Commit 1ba66a87 authored by Jan Beulich's avatar Jan Beulich

AMD/IOMMU: without XT, x2APIC needs to be forced into physical mode

The wider cluster mode APIC IDs aren't generally representable. Convert
the iommu_intremap variable into a tristate, allowing the AMD IOMMU
driver to signal this special restriction to the apic_x2apic_probe().
(Note: assignments to the variable get adjusted, while existing
consumers - all assuming a boolean property - are left alone.)

While we are not aware of any hardware/firmware with this as a
restriction, it is a situation which could be created on fully x2apic-
capable systems via firmware settings.
Signed-off-by: default avatarJan Beulich <jbeulich@suse.com>
Reviewed-by: default avatarAndrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: default avatarRoger Pau Monné <roger.pau@citrix.com>
Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
parent 99f1c935
......@@ -236,12 +236,21 @@ const struct genapic *__init apic_x2apic_probe(void)
x2apic_phys = !iommu_intremap ||
(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL);
}
else if ( !x2apic_phys && !iommu_intremap )
{
printk("WARNING: x2APIC cluster mode is not supported without interrupt remapping\n"
"x2APIC: forcing phys mode\n");
x2apic_phys = true;
}
else if ( !x2apic_phys )
switch ( iommu_intremap )
{
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;
}
if ( x2apic_phys )
return &apic_x2apic_phys;
......
......@@ -1139,7 +1139,7 @@ static void __init amd_iommu_init_cleanup(void)
iommu_enabled = 0;
iommu_hwdom_passthrough = false;
iommu_intremap = 0;
iommu_intremap = iommu_intremap_off;
iommuv2_enabled = 0;
}
......@@ -1413,6 +1413,9 @@ int __init amd_iommu_prepare(bool xt)
iommu->ctrl.int_cap_xt_en = xt && has_xt;
}
if ( iommu_intremap && !has_xt )
iommu_intremap = iommu_intremap_restricted;
rc = amd_iommu_update_ivrs_mapping_acpi();
error_out:
......
......@@ -157,7 +157,7 @@ int __init acpi_ivrs_init(void)
if ( (amd_iommu_detect_acpi() !=0) || (iommu_found() == 0) )
{
iommu_intremap = 0;
iommu_intremap = iommu_intremap_off;
return -ENODEV;
}
......
......@@ -35,7 +35,7 @@ bool __read_mostly iommu_quarantine = true;
bool_t __read_mostly iommu_igfx = 1;
bool_t __read_mostly iommu_snoop = 1;
bool_t __read_mostly iommu_qinval = 1;
bool_t __read_mostly iommu_intremap = 1;
enum iommu_intremap __read_mostly iommu_intremap = iommu_intremap_full;
bool_t __read_mostly iommu_crash_disable;
static bool __hwdom_initdata iommu_hwdom_none;
......@@ -91,7 +91,7 @@ static int __init parse_iommu_param(const char *s)
else if ( (val = parse_boolean("qinval", s, ss)) >= 0 )
iommu_qinval = val;
else if ( (val = parse_boolean("intremap", s, ss)) >= 0 )
iommu_intremap = val;
iommu_intremap = val ? iommu_intremap_full : iommu_intremap_off;
else if ( (val = parse_boolean("intpost", s, ss)) >= 0 )
iommu_intpost = val;
#ifdef CONFIG_KEXEC
......@@ -475,7 +475,7 @@ int __init iommu_setup(void)
iommu_enabled = (rc == 0);
}
if ( !iommu_enabled )
iommu_intremap = 0;
iommu_intremap = iommu_intremap_off;
if ( (force_iommu && !iommu_enabled) ||
(force_intremap && !iommu_intremap) )
......@@ -557,7 +557,8 @@ void iommu_crash_shutdown(void)
if ( iommu_enabled )
iommu_get_ops()->crash_shutdown();
iommu_enabled = iommu_intremap = iommu_intpost = 0;
iommu_enabled = iommu_intpost = 0;
iommu_intremap = iommu_intremap_off;
}
int iommu_get_reserved_device_memory(iommu_grdm_t *func, void *ctxt)
......
......@@ -2177,7 +2177,7 @@ static int __must_check init_vtd_hw(void)
{
if ( ioapic_to_iommu(IO_APIC_ID(apic)) == NULL )
{
iommu_intremap = 0;
iommu_intremap = iommu_intremap_off;
dprintk(XENLOG_ERR VTDPREFIX,
"ioapic_to_iommu: ioapic %#x (id: %#x) is NULL! "
"Will not try to enable Interrupt Remapping.\n",
......@@ -2193,7 +2193,7 @@ static int __must_check init_vtd_hw(void)
iommu = drhd->iommu;
if ( enable_intremap(iommu, 0) != 0 )
{
iommu_intremap = 0;
iommu_intremap = iommu_intremap_off;
dprintk(XENLOG_WARNING VTDPREFIX,
"Interrupt Remapping not enabled\n");
......@@ -2295,7 +2295,7 @@ static int __init vtd_setup(void)
iommu_qinval = 0;
if ( iommu_intremap && !ecap_intr_remap(iommu->ecap) )
iommu_intremap = 0;
iommu_intremap = iommu_intremap_off;
/*
* We cannot use posted interrupt if X86_FEATURE_CX16 is
......@@ -2320,7 +2320,7 @@ static int __init vtd_setup(void)
if ( !iommu_qinval && iommu_intremap )
{
iommu_intremap = 0;
iommu_intremap = iommu_intremap_off;
dprintk(XENLOG_WARNING VTDPREFIX, "Interrupt Remapping disabled "
"since Queued Invalidation isn't supported or enabled.\n");
}
......@@ -2347,7 +2347,7 @@ static int __init vtd_setup(void)
iommu_snoop = 0;
iommu_hwdom_passthrough = false;
iommu_qinval = 0;
iommu_intremap = 0;
iommu_intremap = iommu_intremap_off;
iommu_intpost = 0;
return ret;
}
......
......@@ -54,7 +54,22 @@ static inline bool_t dfn_eq(dfn_t x, dfn_t y)
extern bool_t iommu_enable, iommu_enabled;
extern bool force_iommu, iommu_quarantine, iommu_verbose, iommu_igfx;
extern bool_t iommu_snoop, iommu_qinval, iommu_intremap, iommu_intpost;
extern bool_t iommu_snoop, iommu_qinval, iommu_intpost;
extern enum __packed iommu_intremap {
/*
* In order to allow traditional boolean uses of the iommu_intremap
* variable, the "off" value has to come first (yielding a value of zero).
*/
iommu_intremap_off,
#ifdef CONFIG_X86
/*
* Interrupt remapping enabled, but only able to generate interrupts
* with an 8-bit APIC ID.
*/
iommu_intremap_restricted,
#endif
iommu_intremap_full,
} iommu_intremap;
#if defined(CONFIG_IOMMU_FORCE_PT_SHARE)
#define iommu_hap_pt_share true
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment