build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
const char *oem_table_id)
{
- int ivhd_table_len = 24;
AMDVIState *s = AMD_IOMMU_DEVICE(x86_iommu_get_default());
GArray *ivhd_blob = g_array_new(false, true, 1);
AcpiTable table = { .sig = "IVRS", .rev = 1, .oem_id = oem_id,
.oem_table_id = oem_table_id };
+ uint64_t feature_report;
acpi_table_begin(&table, table_data);
/* IVinfo - IO virtualization information common to all
* IOMMU units in a system
*/
- build_append_int_noprefix(table_data, 40UL << 8/* PASize */, 4);
+ build_append_int_noprefix(table_data,
+ (1UL << 0) | /* EFRSup */
+ (40UL << 8), /* PASize */
+ 4);
/* reserved */
build_append_int_noprefix(table_data, 0, 8);
- /* IVHD definition - type 10h */
- build_append_int_noprefix(table_data, 0x10, 1);
- /* virtualization flags */
- build_append_int_noprefix(table_data,
- (1UL << 0) | /* HtTunEn */
- (1UL << 4) | /* iotblSup */
- (1UL << 6) | /* PrefSup */
- (1UL << 7), /* PPRSup */
- 1);
-
/*
* A PCI bus walk, for each PCI host bridge, is necessary to create a
* complete set of IVHD entries. Do this into a separate blob so that we
build_append_int_noprefix(ivhd_blob, 0x0000001, 4);
}
- ivhd_table_len += ivhd_blob->len;
-
/*
* When interrupt remapping is supported, we add a special IVHD device
- * for type IO-APIC.
+ * for type IO-APIC
+ * Refer to spec - Table 95: IVHD device entry type codes
+ *
+ * Linux IOMMU driver checks for the special IVHD device (type IO-APIC).
+ * See Linux kernel commit 'c2ff5cf5294bcbd7fa50f7d860e90a66db7e5059'
*/
if (x86_iommu_ir_supported(x86_iommu_get_default())) {
- ivhd_table_len += 8;
+ build_append_int_noprefix(ivhd_blob,
+ (0x1ull << 56) | /* type IOAPIC */
+ (IOAPIC_SB_DEVID << 40) | /* IOAPIC devid */
+ 0x48, /* special device */
+ 8);
}
+ /* IVHD definition - type 10h */
+ build_append_int_noprefix(table_data, 0x10, 1);
+ /* virtualization flags */
+ build_append_int_noprefix(table_data,
+ (1UL << 0) | /* HtTunEn */
+ (1UL << 4) | /* iotblSup */
+ (1UL << 6) | /* PrefSup */
+ (1UL << 7), /* PPRSup */
+ 1);
+
/* IVHD length */
- build_append_int_noprefix(table_data, ivhd_table_len, 2);
+ build_append_int_noprefix(table_data, ivhd_blob->len + 24, 2);
/* DeviceID */
build_append_int_noprefix(table_data,
object_property_get_int(OBJECT(&s->pci), "addr",
/* IOMMU info */
build_append_int_noprefix(table_data, 0, 2);
/* IOMMU Feature Reporting */
+ feature_report = (48UL << 30) | /* HATS */
+ (48UL << 28) | /* GATS */
+ (1UL << 2) | /* GTSup */
+ (1UL << 6); /* GASup */
+ if (s->xtsup) {
+ feature_report |= (1UL << 0); /* XTSup */
+ }
+ build_append_int_noprefix(table_data, feature_report, 4);
+
+ /* IVHD entries as found above */
+ g_array_append_vals(table_data, ivhd_blob->data, ivhd_blob->len);
+
+ /* IVHD definition - type 11h */
+ build_append_int_noprefix(table_data, 0x11, 1);
+ /* virtualization flags */
build_append_int_noprefix(table_data,
- (48UL << 30) | /* HATS */
- (48UL << 28) | /* GATS */
- (1UL << 2) | /* GTSup */
- (1UL << 6), /* GASup */
- 4);
+ (1UL << 0) | /* HtTunEn */
+ (1UL << 4), /* iotblSup */
+ 1);
+
+ /* IVHD length */
+ build_append_int_noprefix(table_data, ivhd_blob->len + 40, 2);
+ /* DeviceID */
+ build_append_int_noprefix(table_data,
+ object_property_get_int(OBJECT(&s->pci), "addr",
+ &error_abort), 2);
+ /* Capability offset */
+ build_append_int_noprefix(table_data, s->pci.capab_offset, 2);
+ /* IOMMU base address */
+ build_append_int_noprefix(table_data, s->mmio.addr, 8);
+ /* PCI Segment Group */
+ build_append_int_noprefix(table_data, 0, 2);
+ /* IOMMU info */
+ build_append_int_noprefix(table_data, 0, 2);
+ /* IOMMU Attributes */
+ build_append_int_noprefix(table_data, 0, 4);
+ /* EFR Register Image */
+ build_append_int_noprefix(table_data,
+ amdvi_extended_feature_register(s),
+ 8);
+ /* EFR Register Image 2 */
+ build_append_int_noprefix(table_data, 0, 8);
/* IVHD entries as found above */
g_array_append_vals(table_data, ivhd_blob->data, ivhd_blob->len);
- g_array_free(ivhd_blob, TRUE);
- /*
- * Add a special IVHD device type.
- * Refer to spec - Table 95: IVHD device entry type codes
- *
- * Linux IOMMU driver checks for the special IVHD device (type IO-APIC).
- * See Linux kernel commit 'c2ff5cf5294bcbd7fa50f7d860e90a66db7e5059'
- */
- if (x86_iommu_ir_supported(x86_iommu_get_default())) {
- build_append_int_noprefix(table_data,
- (0x1ull << 56) | /* type IOAPIC */
- (IOAPIC_SB_DEVID << 40) | /* IOAPIC devid */
- 0x48, /* special device */
- 8);
- }
+ g_array_free(ivhd_blob, TRUE);
acpi_table_end(linker, &table);
}
#include "hw/i386/apic_internal.h"
#include "trace.h"
#include "hw/i386/apic-msidef.h"
+#include "hw/qdev-properties.h"
/* used AMD-Vi MMIO registers */
const char *amdvi_mmio_low[] = {
uint64_t page_mask; /* physical page size */
} AMDVIIOTLBEntry;
+uint64_t amdvi_extended_feature_register(AMDVIState *s)
+{
+ uint64_t feature = AMDVI_DEFAULT_EXT_FEATURES;
+ if (s->xtsup) {
+ feature |= AMDVI_FEATURE_XT;
+ }
+
+ return feature;
+}
+
/* configure MMIO registers at startup/reset */
static void amdvi_set_quad(AMDVIState *s, hwaddr addr, uint64_t val,
uint64_t romask, uint64_t w1cmask)
irq->vector = irte.hi.fields.vector;
irq->dest_mode = irte.lo.fields_remap.dm;
irq->redir_hint = irte.lo.fields_remap.rq_eoi;
- irq->dest = irte.lo.fields_remap.destination;
+ if (iommu->xtsup) {
+ irq->dest = irte.lo.fields_remap.destination |
+ (irte.hi.fields.destination_hi << 24);
+ } else {
+ irq->dest = irte.lo.fields_remap.destination & 0xff;
+ }
return 0;
}
/* reset MMIO */
memset(s->mmior, 0, AMDVI_MMIO_SIZE);
- amdvi_set_quad(s, AMDVI_MMIO_EXT_FEATURES, AMDVI_EXT_FEATURES,
- 0xffffffffffffffef, 0);
+ amdvi_set_quad(s, AMDVI_MMIO_EXT_FEATURES,
+ amdvi_extended_feature_register(s),
+ 0xffffffffffffffef, 0);
amdvi_set_quad(s, AMDVI_MMIO_STATUS, 0, 0x98, 0x67);
}
amdvi_init(s);
}
+static Property amdvi_properties[] = {
+ DEFINE_PROP_BOOL("xtsup", AMDVIState, xtsup, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static const VMStateDescription vmstate_amdvi_sysbus = {
.name = "amd-iommu",
.unmigratable = 1
dc->user_creatable = true;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->desc = "AMD IOMMU (AMD-Vi) DMA Remapping device";
+ device_class_set_props(dc, amdvi_properties);
}
static const TypeInfo amdvi_sysbus = {