Re: [Qemu-devel] [V4 3/4] hw/i386: ACPI table for AMD IO MMU
On 2016-02-17 20:09, David Kiarie wrote: > Add IVRS table for AMD IO MMU. Also reverve MMIO > region for IO MMU via ACPI > > Signed-off-by: David Kiarie > --- > hw/i386/acpi-build.c| 98 > - > include/hw/acpi/acpi-defs.h | 55 + > 2 files changed, 142 insertions(+), 11 deletions(-) > > diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c > index 739cfa3..b8cd091 100644 > --- a/hw/i386/acpi-build.c > +++ b/hw/i386/acpi-build.c > @@ -51,6 +51,7 @@ > #include "hw/pci/pci_bus.h" > #include "hw/pci-host/q35.h" > #include "hw/i386/intel_iommu.h" > +#include "hw/i386/amd_iommu.h" > #include "hw/timer/hpet.h" > > #include "hw/acpi/aml-build.h" > @@ -121,6 +122,12 @@ typedef struct AcpiBuildPciBusHotplugState { > bool pcihp_bridge_en; > } AcpiBuildPciBusHotplugState; > > +typedef enum iommu_type { > +TYPE_AMD, > +TYPE_INTEL, > +TYPE_NONE > +} iommu_type; > + > static > int acpi_add_cpu_info(Object *o, void *opaque) > { > @@ -2423,6 +2430,78 @@ build_dmar_q35(GArray *table_data, GArray *linker) > } > > static void > +build_amd_iommu(GArray *table_data, GArray *linker) > +{ > +int iommu_start = table_data->len; > +bool iommu_ambig; > + > +AcpiAMDIOMMUIVRS *ivrs; > +AcpiAMDIOMMUHardwareUnit *iommu; > + > +/* IVRS definition */ > +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); > +ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); > +ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); > +ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); > + > +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", > +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); > + > +/* IVDB definition - type 10h */ > +iommu = acpi_data_push(table_data, sizeof(*iommu)); > +if (!iommu_ambig) { > +iommu->type = cpu_to_le16(0x10); > +/* IVHD flags */ > +iommu->flags = cpu_to_le16(iommu->flags); > +iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | > IVHD_IOTLBSUP > + | IVHD_PREFSUP); > +iommu->length = cpu_to_le16(sizeof(*iommu)); > +iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); > +iommu->capability_offset = cpu_to_le16(s->capab_offset); > +iommu->mmio_base = cpu_to_le64(s->mmio.addr); > +iommu->pci_segment = 0; > +iommu->interrupt_info = 0; > +/* EFR features */ > +iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS > + | IVHD_EFR_GATS); > +iommu->efr_register = cpu_to_le64(iommu->efr_register); > +/* device entries */ > +memset(iommu->dev_entries, 0, 20); > +/* Add device flags here > + * This is are 4-byte device entries currently reporting the range > of > + * devices 00h - h; all devices > + * > + * Device setting affecting all devices should be made here > + * > + * Refer to > + * (http://developer.amd.com/wordpress/media/2012/10/488821.pdf) > + * 5.2.2.1 > + */ > +iommu->dev_entries[12] = 3; > +iommu->dev_entries[16] = 4; > +iommu->dev_entries[17] = 0xff; > +iommu->dev_entries[18] = 0xff; > +} > + > +build_header(linker, table_data, (void *)(table_data->data + > iommu_start), > + "IVRS", table_data->len - iommu_start, 1, NULL); Requires rebasing over master (to append another NULL here). Jan signature.asc Description: OpenPGP digital signature
[Qemu-devel] [V4 3/4] hw/i386: ACPI table for AMD IO MMU
Add IVRS table for AMD IO MMU. Also reverve MMIO region for IO MMU via ACPI Signed-off-by: David Kiarie --- hw/i386/acpi-build.c| 98 - include/hw/acpi/acpi-defs.h | 55 + 2 files changed, 142 insertions(+), 11 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 739cfa3..b8cd091 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -51,6 +51,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" @@ -121,6 +122,12 @@ typedef struct AcpiBuildPciBusHotplugState { bool pcihp_bridge_en; } AcpiBuildPciBusHotplugState; +typedef enum iommu_type { +TYPE_AMD, +TYPE_INTEL, +TYPE_NONE +} iommu_type; + static int acpi_add_cpu_info(Object *o, void *opaque) { @@ -2423,6 +2430,78 @@ build_dmar_q35(GArray *table_data, GArray *linker) } static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; + +AcpiAMDIOMMUIVRS *ivrs; +AcpiAMDIOMMUHardwareUnit *iommu; + +/* IVRS definition */ +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); +ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); +ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); +ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); + +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition - type 10h */ +iommu = acpi_data_push(table_data, sizeof(*iommu)); +if (!iommu_ambig) { +iommu->type = cpu_to_le16(0x10); +/* IVHD flags */ +iommu->flags = cpu_to_le16(iommu->flags); +iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | IVHD_IOTLBSUP + | IVHD_PREFSUP); +iommu->length = cpu_to_le16(sizeof(*iommu)); +iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); +iommu->capability_offset = cpu_to_le16(s->capab_offset); +iommu->mmio_base = cpu_to_le64(s->mmio.addr); +iommu->pci_segment = 0; +iommu->interrupt_info = 0; +/* EFR features */ +iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS + | IVHD_EFR_GATS); +iommu->efr_register = cpu_to_le64(iommu->efr_register); +/* device entries */ +memset(iommu->dev_entries, 0, 20); +/* Add device flags here + * This is are 4-byte device entries currently reporting the range of + * devices 00h - h; all devices + * + * Device setting affecting all devices should be made here + * + * Refer to + * (http://developer.amd.com/wordpress/media/2012/10/488821.pdf) + * 5.2.2.1 + */ +iommu->dev_entries[12] = 3; +iommu->dev_entries[16] = 4; +iommu->dev_entries[17] = 0xff; +iommu->dev_entries[18] = 0xff; +} + +build_header(linker, table_data, (void *)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1, NULL); +} + +static iommu_type has_iommu(void) +{ +bool ambiguous; + +if (object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, &ambiguous) +&& !ambiguous) +return TYPE_AMD; +else if (object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, &ambiguous) +&& !ambiguous) +return TYPE_INTEL; +else +return TYPE_NONE; +} + +static void build_dsdt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, AcpiMiscInfo *misc) { @@ -2590,16 +2669,6 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) return true; } -static bool acpi_has_iommu(void) -{ -bool ambiguous; -Object *intel_iommu; - -intel_iommu = object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, - &ambiguous); -return intel_iommu && !ambiguous; -} - static bool acpi_has_nvdimm(void) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); @@ -2618,6 +2687,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) AcpiMcfgInfo mcfg; PcPciInfo pci; uint8_t *u; +iommu_type type = has_iommu(); size_t aml_len = 0; GArray *tables_blob = tables->table_data; @@ -2685,7 +2755,13 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_mcfg_q35(tables_blob, tables->linker, &mcfg); } -if (acpi_has_iommu()) { + +if (type == TYPE_AMD) { +acpi_add_table(table_offsets, tables_blob); +build_amd_iommu(tables_blob, tables->linker); +} + +if (type == TYPE_INTEL) { acpi_add_table(table_offsets, tables_blob); build_dmar_q35(tables_blob, tables->linke
Re: [Qemu-devel] [V4 3/4] hw/i386: ACPI table for AMD IO MMU
On Sun, Feb 14, 2016 at 4:07 PM, Michael S. Tsirkin wrote: > On Sun, Feb 14, 2016 at 02:54:36PM +0200, Marcel Apfelbaum wrote: >> On 01/18/2016 05:25 PM, David Kiarie wrote: >> >Add IVRS table for AMD IO MMU. >> > >> >Signed-off-by: David Kiarie >> >--- >> > hw/i386/acpi-build.c| 70 >> > + >> > include/hw/acpi/acpi-defs.h | 55 +++ >> > 2 files changed, 125 insertions(+) >> > >> >diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c >> >index 78758e2..5c0d6b7 100644 >> >--- a/hw/i386/acpi-build.c >> >+++ b/hw/i386/acpi-build.c >> >@@ -52,6 +52,7 @@ >> > #include "hw/pci/pci_bus.h" >> > #include "hw/pci-host/q35.h" >> > #include "hw/i386/intel_iommu.h" >> >+#include "hw/i386/amd_iommu.h" >> > #include "hw/timer/hpet.h" >> > >> > #include "hw/acpi/aml-build.h" >> >@@ -2424,6 +2425,70 @@ build_dmar_q35(GArray *table_data, GArray *linker) >> > } >> > >> > static void >> >+build_amd_iommu(GArray *table_data, GArray *linker) >> >+{ >> >+int iommu_start = table_data->len; >> >+bool iommu_ambig; >> >+ >> >+AcpiAMDIOMMUIVRS *ivrs; >> >+AcpiAMDIOMMUHardwareUnit *iommu; >> >+ >> >+/* IVRS definition */ >> >+ivrs = acpi_data_push(table_data, sizeof(*ivrs)); >> >+ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); >> >+ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); >> >+ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); >> >+ >> >+AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", >> >+TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); >> >+ >> >+/* IVDB definition */ >> >+iommu = acpi_data_push(table_data, sizeof(*iommu)); >> >+if (!iommu_ambig) { >> >> Hi, >> >> If the reference to AMD IOMMU is ambiguous and the table is not added to ACPI >> I think we should report the error to user, something like error_report. >> >> >+iommu->type = cpu_to_le16(0x10); >> >+/* IVHD flags */ >> >+iommu->flags = cpu_to_le16(iommu->flags); >> >+iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | >> >IVHD_IOTLBSUP >> >+ | IVHD_PREFSUP); >> >+iommu->length = cpu_to_le16(sizeof(*iommu)); >> >+iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); >> >+iommu->capability_offset = cpu_to_le16(s->capab_offset); >> >+iommu->mmio_base = cpu_to_le64(s->mmio.addr); >> >+iommu->pci_segment = 0; >> >+iommu->interrupt_info = 0; >> >+/* EFR features */ >> >+iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS >> >+ | IVHD_EFR_GATS); >> >+iommu->efr_register = cpu_to_le64(iommu->efr_register); >> >+/* device entries */ >> >+memset(iommu->dev_entries, 0, 20); >> >+/* Add device flags here >> >+ * create entries for devices to be treated specially by IO MMU, >> >+ * currently we report all devices to IO MMU with no special flags >> >+ * DTE settings made here apply to all devices >> >+ * Refer to AMD IOMMU spec Table 97 >> >+ */ >> >+iommu->dev_entries[12] = 3; >> >+iommu->dev_entries[16] = 4; >> >+iommu->dev_entries[17] = 0xff; >> >+iommu->dev_entries[18] = 0xff; >> >+} >> >+ >> >+build_header(linker, table_data, (void *)(table_data->data + >> >iommu_start), >> >+ "IVRS", table_data->len - iommu_start, 1, NULL); >> >+} >> >+ >> >+static bool acpi_has_amd_iommu(void) >> >+{ >> >+bool ambiguous; >> >+Object *amd_iommu; >> >+ >> >+amd_iommu = object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, >> >+ &ambiguous); >> >+return amd_iommu && !ambiguous; >> >+} >> >+ >> >+static void >> > build_dsdt(GArray *table_data, GArray *linker, >> > AcpiPmInfo *pm, AcpiMiscInfo *misc) >> > { >> >@@ -2691,6 +2756,11 @@ void acpi_build(PcGuestInfo *guest_info, >> >AcpiBuildTables *tables) >> > build_dmar_q35(tables_blob, tables->linker); >> > } >> > >> >+if (acpi_has_amd_iommu() && !acpi_has_iommu()) { >> >> Since we have the acpi_has_amd_iommu function now, maybe is time to rename >> acpi_has_iommu to acpi_has_intel_iommu or better have a standard has_iommu >> that >> returns an enum type (NONE/INTEL/AMD). >> >> By the way, do we really need to check !acpi_has_iommu() if there is >> an AMD IOMMU in the system? Having both in the same system is a not (yet) >> supported configuration, >> right? >> >> Thanks, >> Marcel >> > > Long term the right thing to do is to add description > for each IOMMU present in the system. > For example, we might have multiple intel iommus. Yeah, we could have multiple AMD IO MMUs in a system too but I don't see a generic way to add multiple descriptions since they could have different settings. > >> >+acpi_add_table(table_offsets, tables_blob);
Re: [Qemu-devel] [V4 3/4] hw/i386: ACPI table for AMD IO MMU
On Sun, Feb 14, 2016 at 02:54:36PM +0200, Marcel Apfelbaum wrote: > On 01/18/2016 05:25 PM, David Kiarie wrote: > >Add IVRS table for AMD IO MMU. > > > >Signed-off-by: David Kiarie > >--- > > hw/i386/acpi-build.c| 70 > > + > > include/hw/acpi/acpi-defs.h | 55 +++ > > 2 files changed, 125 insertions(+) > > > >diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c > >index 78758e2..5c0d6b7 100644 > >--- a/hw/i386/acpi-build.c > >+++ b/hw/i386/acpi-build.c > >@@ -52,6 +52,7 @@ > > #include "hw/pci/pci_bus.h" > > #include "hw/pci-host/q35.h" > > #include "hw/i386/intel_iommu.h" > >+#include "hw/i386/amd_iommu.h" > > #include "hw/timer/hpet.h" > > > > #include "hw/acpi/aml-build.h" > >@@ -2424,6 +2425,70 @@ build_dmar_q35(GArray *table_data, GArray *linker) > > } > > > > static void > >+build_amd_iommu(GArray *table_data, GArray *linker) > >+{ > >+int iommu_start = table_data->len; > >+bool iommu_ambig; > >+ > >+AcpiAMDIOMMUIVRS *ivrs; > >+AcpiAMDIOMMUHardwareUnit *iommu; > >+ > >+/* IVRS definition */ > >+ivrs = acpi_data_push(table_data, sizeof(*ivrs)); > >+ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); > >+ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); > >+ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); > >+ > >+AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", > >+TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); > >+ > >+/* IVDB definition */ > >+iommu = acpi_data_push(table_data, sizeof(*iommu)); > >+if (!iommu_ambig) { > > Hi, > > If the reference to AMD IOMMU is ambiguous and the table is not added to ACPI > I think we should report the error to user, something like error_report. > > >+iommu->type = cpu_to_le16(0x10); > >+/* IVHD flags */ > >+iommu->flags = cpu_to_le16(iommu->flags); > >+iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | > >IVHD_IOTLBSUP > >+ | IVHD_PREFSUP); > >+iommu->length = cpu_to_le16(sizeof(*iommu)); > >+iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); > >+iommu->capability_offset = cpu_to_le16(s->capab_offset); > >+iommu->mmio_base = cpu_to_le64(s->mmio.addr); > >+iommu->pci_segment = 0; > >+iommu->interrupt_info = 0; > >+/* EFR features */ > >+iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS > >+ | IVHD_EFR_GATS); > >+iommu->efr_register = cpu_to_le64(iommu->efr_register); > >+/* device entries */ > >+memset(iommu->dev_entries, 0, 20); > >+/* Add device flags here > >+ * create entries for devices to be treated specially by IO MMU, > >+ * currently we report all devices to IO MMU with no special flags > >+ * DTE settings made here apply to all devices > >+ * Refer to AMD IOMMU spec Table 97 > >+ */ > >+iommu->dev_entries[12] = 3; > >+iommu->dev_entries[16] = 4; > >+iommu->dev_entries[17] = 0xff; > >+iommu->dev_entries[18] = 0xff; > >+} > >+ > >+build_header(linker, table_data, (void *)(table_data->data + > >iommu_start), > >+ "IVRS", table_data->len - iommu_start, 1, NULL); > >+} > >+ > >+static bool acpi_has_amd_iommu(void) > >+{ > >+bool ambiguous; > >+Object *amd_iommu; > >+ > >+amd_iommu = object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, > >+ &ambiguous); > >+return amd_iommu && !ambiguous; > >+} > >+ > >+static void > > build_dsdt(GArray *table_data, GArray *linker, > > AcpiPmInfo *pm, AcpiMiscInfo *misc) > > { > >@@ -2691,6 +2756,11 @@ void acpi_build(PcGuestInfo *guest_info, > >AcpiBuildTables *tables) > > build_dmar_q35(tables_blob, tables->linker); > > } > > > >+if (acpi_has_amd_iommu() && !acpi_has_iommu()) { > > Since we have the acpi_has_amd_iommu function now, maybe is time to rename > acpi_has_iommu to acpi_has_intel_iommu or better have a standard has_iommu > that > returns an enum type (NONE/INTEL/AMD). > > By the way, do we really need to check !acpi_has_iommu() if there is > an AMD IOMMU in the system? Having both in the same system is a not (yet) > supported configuration, > right? > > Thanks, > Marcel > Long term the right thing to do is to add description for each IOMMU present in the system. For example, we might have multiple intel iommus. > >+acpi_add_table(table_offsets, tables_blob); > >+build_amd_iommu(tables_blob, tables->linker); > >+} > >+ > > if (acpi_has_nvdimm()) { > > nvdimm_build_acpi(table_offsets, tables_blob, tables->linker); > > } > >diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h > >index c7a03d4..a161358 100644 > >--- a/include/hw/acpi/acpi-defs.h > >+++
Re: [Qemu-devel] [V4 3/4] hw/i386: ACPI table for AMD IO MMU
On 01/18/2016 05:25 PM, David Kiarie wrote: Add IVRS table for AMD IO MMU. Signed-off-by: David Kiarie --- hw/i386/acpi-build.c| 70 + include/hw/acpi/acpi-defs.h | 55 +++ 2 files changed, 125 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 78758e2..5c0d6b7 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -52,6 +52,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" @@ -2424,6 +2425,70 @@ build_dmar_q35(GArray *table_data, GArray *linker) } static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; + +AcpiAMDIOMMUIVRS *ivrs; +AcpiAMDIOMMUHardwareUnit *iommu; + +/* IVRS definition */ +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); +ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); +ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); +ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); + +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition */ +iommu = acpi_data_push(table_data, sizeof(*iommu)); +if (!iommu_ambig) { Hi, If the reference to AMD IOMMU is ambiguous and the table is not added to ACPI I think we should report the error to user, something like error_report. +iommu->type = cpu_to_le16(0x10); +/* IVHD flags */ +iommu->flags = cpu_to_le16(iommu->flags); +iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | IVHD_IOTLBSUP + | IVHD_PREFSUP); +iommu->length = cpu_to_le16(sizeof(*iommu)); +iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); +iommu->capability_offset = cpu_to_le16(s->capab_offset); +iommu->mmio_base = cpu_to_le64(s->mmio.addr); +iommu->pci_segment = 0; +iommu->interrupt_info = 0; +/* EFR features */ +iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS + | IVHD_EFR_GATS); +iommu->efr_register = cpu_to_le64(iommu->efr_register); +/* device entries */ +memset(iommu->dev_entries, 0, 20); +/* Add device flags here + * create entries for devices to be treated specially by IO MMU, + * currently we report all devices to IO MMU with no special flags + * DTE settings made here apply to all devices + * Refer to AMD IOMMU spec Table 97 + */ +iommu->dev_entries[12] = 3; +iommu->dev_entries[16] = 4; +iommu->dev_entries[17] = 0xff; +iommu->dev_entries[18] = 0xff; +} + +build_header(linker, table_data, (void *)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1, NULL); +} + +static bool acpi_has_amd_iommu(void) +{ +bool ambiguous; +Object *amd_iommu; + +amd_iommu = object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, + &ambiguous); +return amd_iommu && !ambiguous; +} + +static void build_dsdt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, AcpiMiscInfo *misc) { @@ -2691,6 +2756,11 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) build_dmar_q35(tables_blob, tables->linker); } +if (acpi_has_amd_iommu() && !acpi_has_iommu()) { Since we have the acpi_has_amd_iommu function now, maybe is time to rename acpi_has_iommu to acpi_has_intel_iommu or better have a standard has_iommu that returns an enum type (NONE/INTEL/AMD). By the way, do we really need to check !acpi_has_iommu() if there is an AMD IOMMU in the system? Having both in the same system is a not (yet) supported configuration, right? Thanks, Marcel +acpi_add_table(table_offsets, tables_blob); +build_amd_iommu(tables_blob, tables->linker); +} + if (acpi_has_nvdimm()) { nvdimm_build_acpi(table_offsets, tables_blob, tables->linker); } diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index c7a03d4..a161358 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -570,4 +570,59 @@ typedef struct AcpiDmarHardwareUnit AcpiDmarHardwareUnit; /* Masks for Flags field above */ #define ACPI_DMAR_INCLUDE_PCI_ALL 1 +/* IVRS constants */ +#define ACPI_IOMMU_HARDWAREUNIT_TYPE 0x10 +#define ACPI_IOMMU_IVRS_TYPE 0x1 +#define AMD_IOMMU_HOST_ADDRESS_WIDTH 39UL + +/* AMD IOMMU IVRS table */ +struct AcpiAMDIOMMUIVRS { +ACPI_TABLE_HEADER_DEF +uint32_t v_common_info; /* common virtualization information */ +uint64_t reserved; /* reserved */ +} QEMU_PACKED; +typedef struct
[Qemu-devel] [V4 3/4] hw/i386: ACPI table for AMD IO MMU
Add IVRS table for AMD IO MMU. Signed-off-by: David Kiarie --- hw/i386/acpi-build.c| 70 + include/hw/acpi/acpi-defs.h | 55 +++ 2 files changed, 125 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 78758e2..5c0d6b7 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -52,6 +52,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" @@ -2424,6 +2425,70 @@ build_dmar_q35(GArray *table_data, GArray *linker) } static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; + +AcpiAMDIOMMUIVRS *ivrs; +AcpiAMDIOMMUHardwareUnit *iommu; + +/* IVRS definition */ +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); +ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); +ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); +ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); + +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition */ +iommu = acpi_data_push(table_data, sizeof(*iommu)); +if (!iommu_ambig) { +iommu->type = cpu_to_le16(0x10); +/* IVHD flags */ +iommu->flags = cpu_to_le16(iommu->flags); +iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | IVHD_IOTLBSUP + | IVHD_PREFSUP); +iommu->length = cpu_to_le16(sizeof(*iommu)); +iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); +iommu->capability_offset = cpu_to_le16(s->capab_offset); +iommu->mmio_base = cpu_to_le64(s->mmio.addr); +iommu->pci_segment = 0; +iommu->interrupt_info = 0; +/* EFR features */ +iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS + | IVHD_EFR_GATS); +iommu->efr_register = cpu_to_le64(iommu->efr_register); +/* device entries */ +memset(iommu->dev_entries, 0, 20); +/* Add device flags here + * create entries for devices to be treated specially by IO MMU, + * currently we report all devices to IO MMU with no special flags + * DTE settings made here apply to all devices + * Refer to AMD IOMMU spec Table 97 + */ +iommu->dev_entries[12] = 3; +iommu->dev_entries[16] = 4; +iommu->dev_entries[17] = 0xff; +iommu->dev_entries[18] = 0xff; +} + +build_header(linker, table_data, (void *)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1, NULL); +} + +static bool acpi_has_amd_iommu(void) +{ +bool ambiguous; +Object *amd_iommu; + +amd_iommu = object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, + &ambiguous); +return amd_iommu && !ambiguous; +} + +static void build_dsdt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, AcpiMiscInfo *misc) { @@ -2691,6 +2756,11 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) build_dmar_q35(tables_blob, tables->linker); } +if (acpi_has_amd_iommu() && !acpi_has_iommu()) { +acpi_add_table(table_offsets, tables_blob); +build_amd_iommu(tables_blob, tables->linker); +} + if (acpi_has_nvdimm()) { nvdimm_build_acpi(table_offsets, tables_blob, tables->linker); } diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index c7a03d4..a161358 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -570,4 +570,59 @@ typedef struct AcpiDmarHardwareUnit AcpiDmarHardwareUnit; /* Masks for Flags field above */ #define ACPI_DMAR_INCLUDE_PCI_ALL 1 +/* IVRS constants */ +#define ACPI_IOMMU_HARDWAREUNIT_TYPE 0x10 +#define ACPI_IOMMU_IVRS_TYPE 0x1 +#define AMD_IOMMU_HOST_ADDRESS_WIDTH 39UL + +/* AMD IOMMU IVRS table */ +struct AcpiAMDIOMMUIVRS { +ACPI_TABLE_HEADER_DEF +uint32_t v_common_info; /* common virtualization information */ +uint64_t reserved; /* reserved */ +} QEMU_PACKED; +typedef struct AcpiAMDIOMMUIVRS AcpiAMDIOMMUIVRS; + +/* flags in the IVHD headers */ +#define IVHD_HT_TUNEN(1UL << 0) +#define IVHD_PASS_PW (1UL << 1) +#define IVHD_RESPASS_PW (1UL << 2) +#define IVHD_ISOC(1UL << 3) +#define IVHD_IOTLBSUP(1UL << 4) +#define IVHD_COHERENT(1UL << 5) +#define IVHD_PREFSUP (1UL << 6) +#define IVHD_PPRSUP (1UL << 7) + +/* features in the IVHD headers */ +#define IVHD_EFR_HATS 48 +#define IVHD_EFR_GATS 48 +#define IVHD_EFR_MSI_NUM +#define IVHD_EFR_PNBANKS +#define IVHD_EFR_PNCOUNTERS +#define IVHD_EFR_PASMAX +#define IVHD_EFR_HESUP (1UL << 7) +#de