diff options
author | David Kiarie <davidkiarie4@gmail.com> | 2016-09-20 18:42:34 +0300 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2016-09-24 01:02:01 +0300 |
commit | fb9f592623b0f9bb82a88d68d7921fb581918ef5 (patch) | |
tree | 5e727dd26add4568812f6dda16cb927dc64494b0 /hw/i386 | |
parent | d29a09ca68428b5708024ea2e9143de0a031081d (diff) |
hw/i386: AMD IOMMU IVRS table
Add IVRS table for AMD IOMMU. Generate IVRS or DMAR
depending on emulated IOMMU.
Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/i386')
-rw-r--r-- | hw/i386/acpi-build.c | 76 | ||||
-rw-r--r-- | hw/i386/amd_iommu.c | 2 | ||||
-rw-r--r-- | hw/i386/intel_iommu.c | 1 | ||||
-rw-r--r-- | hw/i386/x86-iommu.c | 6 |
4 files changed, 76 insertions, 9 deletions
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 433febafdd..c20bc71a67 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -59,7 +59,8 @@ #include "qapi/qmp/qint.h" #include "qom/qom-qobject.h" -#include "hw/i386/x86-iommu.h" +#include "hw/i386/amd_iommu.h" +#include "hw/i386/intel_iommu.h" #include "hw/acpi/ipmi.h" @@ -2562,6 +2563,62 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker) build_header(linker, table_data, (void *)(table_data->data + dmar_start), "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } +/* + * IVRS table as specified in AMD IOMMU Specification v2.62, Section 5.2 + * accessible here http://support.amd.com/TechDocs/48882_IOMMU.pdf + */ +static void +build_amd_iommu(GArray *table_data, BIOSLinker *linker) +{ + int iommu_start = table_data->len; + AMDVIState *s = AMD_IOMMU_DEVICE(x86_iommu_get_default()); + + /* IVRS header */ + acpi_data_push(table_data, sizeof(AcpiTableHeader)); + /* IVinfo - IO virtualization information common to all + * IOMMU units in a system + */ + build_append_int_noprefix(table_data, 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); + /* IVHD length */ + build_append_int_noprefix(table_data, 0x24, 2); + /* DeviceID */ + build_append_int_noprefix(table_data, s->devid, 2); + /* Capability offset */ + build_append_int_noprefix(table_data, s->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 Feature Reporting */ + build_append_int_noprefix(table_data, + (48UL << 30) | /* HATS */ + (48UL << 28) | /* GATS */ + (1UL << 2), /* GTSup */ + 4); + /* + * Type 1 device entry reporting all devices + * These are 4-byte device entries currently reporting the range of + * Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte) + */ + build_append_int_noprefix(table_data, 0x0000001, 4); + + build_header(linker, table_data, (void *)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1, NULL, NULL); +} static GArray * build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset) @@ -2622,11 +2679,6 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) return true; } -static bool acpi_has_iommu(void) -{ - return !!x86_iommu_get_default(); -} - static void acpi_build(AcpiBuildTables *tables, MachineState *machine) { @@ -2706,9 +2758,15 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) acpi_add_table(table_offsets, tables_blob); build_mcfg_q35(tables_blob, tables->linker, &mcfg); } - if (acpi_has_iommu()) { - acpi_add_table(table_offsets, tables_blob); - build_dmar_q35(tables_blob, tables->linker); + if (x86_iommu_get_default()) { + IommuType IOMMUType = x86_iommu_get_type(); + if (IOMMUType == TYPE_AMD) { + acpi_add_table(table_offsets, tables_blob); + build_amd_iommu(tables_blob, tables->linker); + } else if (IOMMUType == TYPE_INTEL) { + acpi_add_table(table_offsets, tables_blob); + build_dmar_q35(tables_blob, tables->linker); + } } if (pcms->acpi_nvdimm_state.is_enabled) { nvdimm_build_acpi(table_offsets, tables_blob, tables->linker, diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 4eec9b80ed..a91a1798cb 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1130,11 +1130,13 @@ static void amdvi_reset(DeviceState *dev) static void amdvi_realize(DeviceState *dev, Error **err) { AMDVIState *s = AMD_IOMMU_DEVICE(dev); + X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev); PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus; s->iotlb = g_hash_table_new_full(amdvi_uint64_hash, amdvi_uint64_equal, g_free, g_free); /* This device should take care of IOMMU PCI properties */ + x86_iommu->type = TYPE_AMD; qdev_set_parent_bus(DEVICE(&s->pci), &bus->qbus); object_property_set_bool(OBJECT(&s->pci), true, "realized", err); s->capab_offset = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0, diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 28c31a2cdf..d6e02c821a 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2453,6 +2453,7 @@ static void vtd_realize(DeviceState *dev, Error **errp) X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev); VTD_DPRINTF(GENERAL, ""); + x86_iommu->type = TYPE_INTEL; memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num)); memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s, "intel_iommu", DMAR_REG_SIZE); diff --git a/hw/i386/x86-iommu.c b/hw/i386/x86-iommu.c index ce26b2a71d..2278af7c32 100644 --- a/hw/i386/x86-iommu.c +++ b/hw/i386/x86-iommu.c @@ -71,6 +71,11 @@ X86IOMMUState *x86_iommu_get_default(void) return x86_iommu_default; } +IommuType x86_iommu_get_type(void) +{ + return x86_iommu_default->type; +} + static void x86_iommu_realize(DeviceState *dev, Error **errp) { X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev); @@ -79,6 +84,7 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp) if (x86_class->realize) { x86_class->realize(dev, errp); } + x86_iommu_set_default(X86_IOMMU_DEVICE(dev)); } |