Re: [Qemu-devel] [V7 2/4] hw/i386: ACPI table for AMD IOMMU

2016-03-14 Thread Marcel Apfelbaum

On 03/14/2016 02:24 AM, David Kiarie wrote:

Add IVRS table for AMD IOMMU. Generate IVRS or DMAR
depending on emulated IOMMU

Signed-off-by: David Kiarie 
---
  hw/i386/acpi-build.c  | 98 ++-
  include/hw/acpi/acpi-defs.h   | 55 


Added Igor to CC, maybe he can have a look to the ACPI code.

Thanks,
Marcel



  include/hw/i386/intel_iommu.h |  1 +
  3 files changed, 143 insertions(+), 11 deletions(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index b888008..f6ab533 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)
  {
@@ -2542,6 +2549,78 @@ build_dmar_q35(GArray *table_data, GArray *linker)
   "DMAR", table_data->len - dmar_start, 1, NULL, NULL);
  }

+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, _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, NULL);
+}
+
+static iommu_type has_iommu(void)
+{
+bool ambiguous;
+
+if (object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, )
+&& !ambiguous)
+return TYPE_AMD;
+else if (object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, )
+&& !ambiguous)
+return TYPE_INTEL;
+else
+return TYPE_NONE;
+}
+
  static GArray *
  build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
  {
@@ -2600,16 +2679,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,
-   );
-return intel_iommu && !ambiguous;
-}
-
  static bool acpi_has_nvdimm(void)
  {
  PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
@@ -2630,6 +2699,7 @@ void acpi_build(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;
  AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL };
@@ -2696,7 +2766,13 @@ void acpi_build(AcpiBuildTables *tables)
  acpi_add_table(table_offsets, tables_blob);
  build_mcfg_q35(tables_blob, tables->linker, );
  }
-if (acpi_has_iommu()) {
+
+if (type == TYPE_AMD) {
+

[Qemu-devel] [V7 2/4] hw/i386: ACPI table for AMD IOMMU

2016-03-13 Thread David Kiarie
Add IVRS table for AMD IOMMU. Generate IVRS or DMAR
depending on emulated IOMMU

Signed-off-by: David Kiarie 
---
 hw/i386/acpi-build.c  | 98 ++-
 include/hw/acpi/acpi-defs.h   | 55 
 include/hw/i386/intel_iommu.h |  1 +
 3 files changed, 143 insertions(+), 11 deletions(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index b888008..f6ab533 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)
 {
@@ -2542,6 +2549,78 @@ build_dmar_q35(GArray *table_data, GArray *linker)
  "DMAR", table_data->len - dmar_start, 1, NULL, NULL);
 }
 
+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, _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, NULL);
+}
+
+static iommu_type has_iommu(void)
+{
+bool ambiguous;
+
+if (object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, )
+&& !ambiguous)
+return TYPE_AMD;
+else if (object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, )
+&& !ambiguous)
+return TYPE_INTEL;
+else
+return TYPE_NONE;
+}
+
 static GArray *
 build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
 {
@@ -2600,16 +2679,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,
-   );
-return intel_iommu && !ambiguous;
-}
-
 static bool acpi_has_nvdimm(void)
 {
 PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
@@ -2630,6 +2699,7 @@ void acpi_build(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;
 AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL };
@@ -2696,7 +2766,13 @@ void acpi_build(AcpiBuildTables *tables)
 acpi_add_table(table_offsets, tables_blob);
 build_mcfg_q35(tables_blob, tables->linker, );
 }
-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) {