qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping
@ 2016-08-10 19:42 David Kiarie
  2016-08-10 19:42 ` [Qemu-devel] [V1 1/4] hw/iommu: Prepare for AMD IOMMU interrupt remapping David Kiarie
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: David Kiarie @ 2016-08-10 19:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: jan.kiszka, valentine.sinitsyn, mst, pbonzini, ehabkost,
	peter.maydell, David Kiarie

Hello all,

The following patchset adds AMD-Vi interrupt remapping logic
to Qemu and hooks it onto existing interrupt remapping infrastructure.It has 
a dependency on "Explicit SID for IOAPIC" patchset though.

I would appreciate your feedback!

For quick testing https://github.com/aslaq/qemu IR

David Kiarie (4):
  hw/iommu: Prepare for AMD IOMMU interrupt remapping
  hw/iommu: AMD IOMMU interrupt remapping
  hw/acpi: report IOAPIC on IVRS
  hw/iommu: share common between IOMMUs

 hw/i386/acpi-build.c  |   2 +
 hw/i386/amd_iommu.c   | 226 +++++++++++++++++++++++++++++++++++++++++++++++++-
 hw/i386/amd_iommu.h   |  74 +++++++++++++++++
 hw/i386/intel_iommu.c |   9 --
 hw/i386/trace-events  |   7 ++
 hw/i386/x86-iommu.c   |   8 ++
 6 files changed, 316 insertions(+), 10 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Qemu-devel] [V1 1/4] hw/iommu: Prepare for AMD IOMMU interrupt remapping
  2016-08-10 19:42 [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping David Kiarie
@ 2016-08-10 19:42 ` David Kiarie
  2016-08-12 19:19   ` Valentine Sinitsyn
  2016-08-10 19:42 ` [Qemu-devel] [V1 2/4] hw/iommu: " David Kiarie
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: David Kiarie @ 2016-08-10 19:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: jan.kiszka, valentine.sinitsyn, mst, pbonzini, ehabkost,
	peter.maydell, David Kiarie

Introduce macros and trace events for use in AMD IOMMU
interrupt remapping

Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
---
 hw/i386/amd_iommu.h  | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/i386/trace-events |  7 +++++
 2 files changed, 79 insertions(+)

diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
index 5d0b91d..2a7f19e 100644
--- a/hw/i386/amd_iommu.h
+++ b/hw/i386/amd_iommu.h
@@ -177,6 +177,78 @@
 #define AMDVI_IOTLB_MAX_SIZE 1024
 #define AMDVI_DEVID_SHIFT    36
 
+/* interrupt types */
+#define AMDVI_MT_FIXED  0x0
+#define AMDVI_MT_ARBIT  0x1
+#define AMDVI_MT_SMI    0x2
+#define AMDVI_MT_NMI    0x3
+#define AMDVI_MT_INIT   0x4
+#define AMDVI_MT_EXTINT 0x6
+#define AMDVI_MT_LINT1  0xb
+#define AMDVI_MT_LINT0  0xe
+
+/* Ext reg, GA support */
+#define AMDVI_GASUP    (1UL << 7)
+/* MMIO control GA enable bits */
+#define AMDVI_GAEN     (1UL << 17)
+
+/* MSI interrupt type mask */
+#define AMDVI_IR_TYPE_MASK 0x300
+
+/* interrupt destination mode */
+#define AMDVI_IRDEST_MODE_MASK 0x2
+
+/* select MSI data 10:0 bits */
+#define AMDVI_IRTE_INDEX_MASK 0x7ff
+
+/* bits determining whether specific interrupts should be passed
+ * split DTE into 64-bit chunks
+ */
+#define AMDVI_DTE_INTPASS       56
+#define AMDVI_DTE_EINTPASS      57
+#define AMDVI_DTE_NMIPASS       58
+#define AMDVI_DTE_INTCTL        60
+#define AMDVI_DTE_LINT0PASS     62
+#define AMDVI_DTE_LINT1PASS     63
+
+/* interrupt data valid */
+#define AMDVI_IR_VALID          (1UL << 0)
+
+/* interrupt root table mask */
+#define AMDVI_IRTEROOT_MASK     0xffffffffffffc0
+
+/* default IRTE size */
+#define AMDVI_DEFAULT_IRTE_SIZE 0x4
+
+/* IRTE size with GASup enabled */
+#define AMDVI_IRTE_SIZE_GASUP   0x10
+
+#define AMDVI_IRTE_VECTOR_MASK    (0xffU << 16)
+#define AMDVI_IRTE_DEST_MASK      (0xffU << 8)
+#define AMDVI_IRTE_DM_MASK        (0x1U << 6)
+#define AMDVI_IRTE_RQEOI_MASK     (0x1U << 5)
+#define AMDVI_IRTE_INTTYPE_MASK   (0x7U << 2)
+#define AMDVI_IRTE_SUPIOPF_MASK   (0x1U << 1)
+#define AMDVI_IRTE_REMAP_MASK     (0x1U << 0)
+
+#define AMDVI_IR_TABLE_SIZE_MASK 0xfe
+
+/* offsets into MSI data */
+#define AMDVI_MSI_DATA_DM_RSHIFT       0x8
+#define AMDVI_MSI_DATA_LEVEL_RSHIFT    0xe
+#define AMDVI_MSI_DATA_TRM_RSHIFT      0xf
+
+/* offsets into MSI address */
+#define AMDVI_MSI_ADDR_DM_RSHIFT       0x2
+#define AMDVI_MSI_ADDR_RH_RSHIFT       0x3
+#define AMDVI_MSI_ADDR_DEST_RSHIFT     0xc
+
+#define AMDVI_BUS_NUM                  0x0
+/* AMD-Vi specific IOAPIC Device function */
+#define AMDVI_DEVFN_IOAPIC             0xa0
+
+#define AMDVI_LOCAL_APIC_ADDR     0xfee00000
+
 /* extended feature support */
 #define AMDVI_EXT_FEATURES (AMDVI_FEATURE_PREFETCH | AMDVI_FEATURE_PPR | \
         AMDVI_FEATURE_IA | AMDVI_FEATURE_GT | AMDVI_FEATURE_GA | \
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
index 592de3a..5c12c10 100644
--- a/hw/i386/trace-events
+++ b/hw/i386/trace-events
@@ -42,3 +42,10 @@ amdvi_mode_invalid(unsigned level, uint64_t addr)"error: translation level 0x%"P
 amdvi_page_fault(uint64_t addr) "error: page fault accessing guest physical address 0x%"PRIx64
 amdvi_iotlb_hit(uint16_t bus, uint16_t slot, uint16_t func, uint64_t addr, uint64_t txaddr) "hit iotlb devid %02x:%02x.%x gpa 0x%"PRIx64 " hpa 0x%"PRIx64
 amdvi_translation_result(uint16_t bus, uint16_t slot, uint16_t func, uint64_t addr, uint64_t txaddr) "devid: %02x:%02x.%x gpa 0x%"PRIx64 " hpa 0x%"PRIx64
+amdvi_irte_get_fail(uint64_t addr, uint64_t offset) "couldn't access device table entry 0x%"PRIx64" + offset 0x%"PRIx64
+amdvi_invalid_irte_entry(uint16_t devid, uint64_t offset) "devid %x requested IRTE offset 0x%"PRIx64" Outside IR table range"
+amdvi_ir_request(uint32_t data, uint64_t addr, uint16_t sid) "IR request data 0x%"PRIx32" address 0x%"PRIx64" SID %x"
+amdvi_ir_remap(uint32_t data, uint64_t addr, uint16_t sid) "IR remap data 0x%"PRIx32" address 0x%"PRIx64" SID %x"
+amdvi_ir_target_abort(uint32_t data, uint64_t addr, uint16_t sid) "IR target abort data 0x%"PRIx32" address 0x%"PRIx64" SID %x"
+amdvi_ir_write_fail(uint64_t addr, uint32_t data) "fail to write to addr 0x%"PRIx64 " value 0x%"PRIx32
+amdvi_ir_read_fail(uint64_t addr) " fail to read from addr 0x%"PRIx64
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [V1 2/4] hw/iommu: AMD IOMMU interrupt remapping
  2016-08-10 19:42 [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping David Kiarie
  2016-08-10 19:42 ` [Qemu-devel] [V1 1/4] hw/iommu: Prepare for AMD IOMMU interrupt remapping David Kiarie
@ 2016-08-10 19:42 ` David Kiarie
  2016-08-12 20:08   ` Valentine Sinitsyn
  2016-08-10 19:42 ` [Qemu-devel] [V1 3/4] hw/acpi: report IOAPIC on IVRS David Kiarie
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: David Kiarie @ 2016-08-10 19:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: jan.kiszka, valentine.sinitsyn, mst, pbonzini, ehabkost,
	peter.maydell, David Kiarie

Introduce AMD IOMMU interrupt remapping and hook it onto
the existing interrupt remapping infrastructure

Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
---
 hw/i386/amd_iommu.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 hw/i386/amd_iommu.h |   2 +
 2 files changed, 227 insertions(+), 1 deletion(-)

diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 5fab9aa..825159b 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -18,12 +18,14 @@
  * with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  * Cache implementation inspired by hw/i386/intel_iommu.c
+ *
  */
 #include "qemu/osdep.h"
 #include <math.h>
 #include "hw/pci/msi.h"
 #include "hw/i386/pc.h"
 #include "hw/i386/amd_iommu.h"
+#include "hw/i386/ioapic_internal.h"
 #include "hw/pci/pci_bus.h"
 #include "trace.h"
 
@@ -660,6 +662,11 @@ static void amdvi_inval_inttable(AMDVIState *s, CMDInvalIntrTable *inval)
         amdvi_log_illegalcom_error(s, inval->type, s->cmdbuf + s->cmdbuf_head);
         return;
     }
+
+    if (s->ir_cache) {
+        x86_iommu_iec_notify_all(X86_IOMMU_DEVICE(s), true, 0, 0);
+    }
+
     trace_amdvi_intr_inval();
 }
 
@@ -1221,6 +1228,207 @@ static IOMMUTLBEntry amdvi_translate(MemoryRegion *iommu, hwaddr addr,
     return ret;
 }
 
+static inline int amdvi_ir_pass(MSIMessage *src, MSIMessage *dst, uint8_t bit,
+                                uint64_t dte)
+{
+    if ((dte & (1UL << bit))) {
+        /* passing interrupt enabled */
+        dst->address = src->address;
+        dst->data = src->data;
+    } else {
+        /* should be target aborted */
+        return -AMDVI_TARGET_ABORT;
+    }
+    return 0;
+}
+
+static int amdvi_remap_ir_intctl(uint64_t dte, uint32_t irte,
+                                 MSIMessage *src, MSIMessage *dst)
+{
+    int ret = 0;
+
+    switch ((dte >> AMDVI_DTE_INTCTL ) & 3UL) {
+    case 1:
+        /* pass */
+        memcpy(dst, src, sizeof(*dst));
+        break;
+    case 2:
+        /* remap */
+        if (irte & AMDVI_IRTE_REMAP_MASK) {
+            /* LOCAL APIC address */
+            dst->address = AMDVI_LOCAL_APIC_ADDR;
+            /* destination mode */
+            dst->address |= (((irte & AMDVI_IRTE_DM_MASK) >> 6) <<
+                    AMDVI_MSI_ADDR_DM_RSHIFT);
+            /* RH */
+            dst->address |= ((irte & AMDVI_IRTE_RQEOI_MASK) >> 5) <<
+                AMDVI_MSI_ADDR_RH_RSHIFT;
+            /* Destination ID */
+            dst->address |= ((irte & AMDVI_IRTE_DEST_MASK) >> 8) <<
+                AMDVI_MSI_ADDR_DEST_RSHIFT;
+            /* construct data - vector */
+            dst->data |= (irte & AMDVI_IRTE_VECTOR_MASK) >> 16;
+            /* Interrupt type */
+            dst->data |= ((irte & AMDVI_IRTE_INTTYPE_MASK) >> 2) <<
+                AMDVI_MSI_DATA_DM_RSHIFT;
+        } else  {
+            ret = -AMDVI_TARGET_ABORT;
+        }
+        break;
+    case 0:
+    case 3:
+    default:
+        ret = -AMDVI_TARGET_ABORT;
+    }
+    return ret;
+}
+/*
+ * We don't support guest virtual APIC so IRTE size will most likely always be 4
+ */
+static int amdvi_irte_get(AMDVIState *s, MSIMessage *src, uint32_t *irte,
+                          uint64_t *dte, uint16_t devid)
+{
+    uint64_t irte_root, offset = devid * AMDVI_DEVTAB_ENTRY_SIZE,
+             irte_size = AMDVI_DEFAULT_IRTE_SIZE,
+             ir_table_size;
+
+    /* check for GASup and if it's enabled */
+    if ((amdvi_readq(s, AMDVI_EXT_FEATURES) & AMDVI_GASUP)
+        && (amdvi_readq(s, AMDVI_MMIO_CONTROL) & AMDVI_GAEN)) {
+        /* set a different IRTE size */
+        irte_size = AMDVI_IRTE_SIZE_GASUP;
+    }
+    if (dma_memory_read(&address_space_memory, s->devtab + offset, dte,
+                        AMDVI_DEVTAB_ENTRY_SIZE)) {
+        trace_amdvi_dte_get_fail(s->devtab, offset);
+        return -AMDVI_DEV_TAB_HW;
+    }
+
+    irte_root = dte[2] & AMDVI_IRTEROOT_MASK;
+    offset = (src->data & AMDVI_IRTE_INDEX_MASK) << 2;
+    ir_table_size = pow(2, dte[2] & AMDVI_IR_TABLE_SIZE_MASK);
+    /* enforce IR table size */
+    if (offset > (ir_table_size * irte_size)) {
+        trace_amdvi_invalid_irte_entry(offset, ir_table_size);
+        return -AMDVI_TARGET_ABORT;
+    }
+    /* read IRTE */
+    if (dma_memory_read(&address_space_memory, irte_root + offset,
+        irte, sizeof(*irte))) {
+        trace_amdvi_irte_get_fail(irte_root, offset);
+        return -AMDVI_DEV_TAB_HW;
+    }
+    return 0;
+}
+
+static int amdvi_int_remap(X86IOMMUState *iommu, MSIMessage *src,
+                           MSIMessage *dst, uint16_t sid)
+{
+    trace_amdvi_ir_request(src->data, src->address, sid);
+
+    AMDVIState *s = AMD_IOMMU_DEVICE(iommu);
+    int ret = 0;
+    uint64_t dte[4];
+    uint32_t ir_enabled, irte;
+
+    ret = amdvi_irte_get(s, src, &irte, dte, sid);
+    if (ret < 0) {
+        goto no_remap;
+    }
+    /* interrupt remapping disabled */
+    if (!(dte[2] & AMDVI_IR_VALID)) {
+        memcpy(dst, src, sizeof(*src));
+        return ret;
+    }
+    switch (src->data & AMDVI_IR_TYPE_MASK) {
+    case AMDVI_MT_FIXED:
+    case AMDVI_MT_ARBIT:
+        ret = amdvi_remap_ir_intctl(dte[2], irte, src, dst);
+        if (ret < 0) {
+            goto no_remap;
+        } else {
+            s->ir_cache = true;
+            trace_amdvi_ir_remap(dst->data, dst->address, sid);
+            return ret;
+        }
+    /* not handling SMI currently */
+    case AMDVI_MT_SMI:
+        goto no_remap;
+    case AMDVI_MT_NMI:
+        ir_enabled = AMDVI_DTE_NMIPASS;
+        break;
+    case AMDVI_MT_INIT:
+        ir_enabled = AMDVI_DTE_INTPASS;
+        break;
+    case AMDVI_MT_EXTINT:
+        ir_enabled = AMDVI_DTE_EINTPASS;
+        break;
+    case AMDVI_MT_LINT1:
+        ir_enabled = AMDVI_DTE_LINT1PASS;
+        break;
+    case AMDVI_MT_LINT0:
+        ir_enabled = AMDVI_DTE_LINT0PASS;
+    }
+
+    ret = amdvi_ir_pass(src, dst, ir_enabled, dte[2]);
+    if (ret < 0){
+        goto no_remap;
+    }
+    s->ir_cache = true;
+    trace_amdvi_ir_remap(dst->data, dst->address, sid);
+    return ret;
+no_remap:
+    memcpy(dst, src, sizeof(*src));
+    trace_amdvi_ir_target_abort(dst->data, dst->address, sid);
+    return ret;
+}
+
+static MemTxResult amdvi_ir_read(void *opaque, hwaddr addr,
+                                 uint64_t *data, unsigned size,
+                                 MemTxAttrs attrs)
+{
+    return MEMTX_OK;
+}
+
+static MemTxResult amdvi_ir_write(void *opaque, hwaddr addr, uint64_t val,
+                                  unsigned size, MemTxAttrs attrs)
+{
+    AMDVIAddressSpace *as = opaque;
+    MSIMessage from = { addr + AMDVI_INT_ADDR_FIRST, val }, to = { 0, 0};
+    uint16_t sid = PCI_BUILD_BDFi(as->bus_num, as->devfn);
+    int ret = 0;
+
+    ret  = amdvi_int_remap(X86_IOMMU_DEVICE(as->iommu_state), &from, &to,
+                           attrs.requester_id);
+
+    if (ret < 0) {
+        trace_amdvi_ir_target_abort(from.data, from.address,
+                                    attrs.requester_id);
+        return MEMTX_ERROR;
+    }
+
+    if(dma_memory_write(&address_space_memory, to.address, &to.data, size)) {
+        trace_amdvi_ir_write_fail(to.address, to.data);
+        return MEMTX_ERROR;
+    }
+
+    return MEMTX_OK;
+}
+
+static const MemoryRegionOps amdvi_ir_ops = {
+    .read_with_attrs = amdvi_ir_read,
+    .write_with_attrs = amdvi_ir_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
 static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
 {
     AMDVIState *s = opaque;
@@ -1244,6 +1452,12 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
 
         memory_region_init_iommu(&iommu_as[devfn]->iommu, OBJECT(s),
                                  &s->iommu_ops, "amd-iommu", UINT64_MAX);
+        memory_region_init_io(&iommu_as[devfn]->iommu_ir, OBJECT(s),
+                              &amdvi_ir_ops, iommu_as[devfn], "amd-iommu-ir",
+                              AMDVI_INT_ADDR_SIZE);
+        memory_region_add_subregion(&iommu_as[devfn]->iommu,
+                                    AMDVI_INT_ADDR_FIRST,
+                                    &iommu_as[devfn]->iommu_ir);
         address_space_init(&iommu_as[devfn]->as, &iommu_as[devfn]->iommu,
                            "amd-iommu");
     }
@@ -1292,6 +1506,7 @@ static void amdvi_init(AMDVIState *s)
     s->enabled = false;
     s->ats_enabled = false;
     s->cmdbuf_enabled = false;
+    s->ir_cache = false;
 
     /* reset MMIO */
     memset(s->mmior, 0, AMDVI_MMIO_SIZE);
@@ -1331,11 +1546,15 @@ 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;
+    PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
     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 */
+    /* AMD IOMMU has Interrupt Remapping on by default */
+    x86_iommu->intr_supported = true;
     x86_iommu->type = TYPE_AMD;
+
+    /* This device should take care of IOMMU PCI properties */
     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,
@@ -1347,9 +1566,13 @@ static void amdvi_realize(DeviceState *dev, Error **err)
     memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio",
                           AMDVI_MMIO_SIZE);
 
+    x86_iommu->ioapic_bdf = PCI_BUILD_BDF(AMDVI_BUS_NUM,
+             AMDVI_DEVFN_IOAPIC);
+
     sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio);
     sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, AMDVI_BASE_ADDR);
     pci_setup_iommu(bus, amdvi_host_dma_iommu, s);
+    pcms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_DEVFN_IOAPIC);
     s->devid = object_property_get_int(OBJECT(&s->pci), "addr", err);
     msi_init(&s->pci.dev, 0, 1, true, false, err);
     amdvi_init(s);
@@ -1376,6 +1599,7 @@ static void amdvi_class_init(ObjectClass *klass, void* data)
     dc->vmsd = &vmstate_amdvi;
     dc->hotpluggable = false;
     dc_class->realize = amdvi_realize;
+    dc_class->int_remap = amdvi_int_remap;
 }
 
 static const TypeInfo amdvi = {
diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
index 2a7f19e..f0e23a8 100644
--- a/hw/i386/amd_iommu.h
+++ b/hw/i386/amd_iommu.h
@@ -356,6 +356,8 @@ typedef struct AMDVIState {
     uint32_t evtlog_len;         /* event log length             */
     uint32_t evtlog_head;        /* current IOMMU write position */
     uint32_t evtlog_tail;        /* current Software read position */
+    /* whether we have remapped any interrupts and hence IR cache */
+    bool ir_cache;
 
     /* unused for now */
     hwaddr excl_base;            /* base DVA - IOMMU exclusion range */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [V1 3/4] hw/acpi: report IOAPIC on IVRS
  2016-08-10 19:42 [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping David Kiarie
  2016-08-10 19:42 ` [Qemu-devel] [V1 1/4] hw/iommu: Prepare for AMD IOMMU interrupt remapping David Kiarie
  2016-08-10 19:42 ` [Qemu-devel] [V1 2/4] hw/iommu: " David Kiarie
@ 2016-08-10 19:42 ` David Kiarie
  2016-08-12 20:14   ` Valentine Sinitsyn
  2016-08-10 19:42 ` [Qemu-devel] [V1 4/4] hw/iommu: share common between IOMMUs David Kiarie
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: David Kiarie @ 2016-08-10 19:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: jan.kiszka, valentine.sinitsyn, mst, pbonzini, ehabkost,
	peter.maydell, David Kiarie

Report IOAPIC via IVRS which effectively allows linux AMD-Vi
driver to enable interrupt remapping

Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
---
 hw/i386/acpi-build.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 49bd183..da602c3 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -2615,6 +2615,8 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker)
      *   Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte)
      */
     build_append_int_noprefix(table_data, 0x0000001, 4);
+    /* IOAPIC represented as an 8-byte entry. Spec v2.62 Tables 97 */
+    build_append_int_noprefix(table_data, 0x0100a000ff000048, 8);
 
     build_header(linker, table_data, (void *)(table_data->data + iommu_start),
                  "IVRS", table_data->len - iommu_start, 1, NULL, NULL);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [V1 4/4] hw/iommu: share common between IOMMUs
  2016-08-10 19:42 [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping David Kiarie
                   ` (2 preceding siblings ...)
  2016-08-10 19:42 ` [Qemu-devel] [V1 3/4] hw/acpi: report IOAPIC on IVRS David Kiarie
@ 2016-08-10 19:42 ` David Kiarie
  2016-08-10 19:46 ` [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping David Kiarie
  2016-08-11  6:39 ` Valentine Sinitsyn
  5 siblings, 0 replies; 13+ messages in thread
From: David Kiarie @ 2016-08-10 19:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: jan.kiszka, valentine.sinitsyn, mst, pbonzini, ehabkost,
	peter.maydell, David Kiarie

Enabling interrupt remapping with kernel_irqchip=on should
result in error for both VT-d and AMD-Vi

Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
---
 hw/i386/intel_iommu.c | 9 ---------
 hw/i386/x86-iommu.c   | 8 ++++++++
 2 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 7c80907..857f9f1 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -30,7 +30,6 @@
 #include "hw/boards.h"
 #include "hw/i386/x86-iommu.h"
 #include "hw/pci-host/q35.h"
-#include "sysemu/kvm.h"
 
 #define DEBUG_INTEL_IOMMU
 #ifdef DEBUG_INTEL_IOMMU
@@ -2472,14 +2471,6 @@ static void vtd_realize(DeviceState *dev, Error **errp)
         Q35_PSEUDO_DEVFN_IOAPIC;
     /* Pseudo address space under root PCI bus. */
     pcms->ioapic_as = vtd_host_dma_iommu(bus, s, Q35_PSEUDO_DEVFN_IOAPIC);
-
-    /* Currently Intel IOMMU IR only support "kernel-irqchip={off|split}" */
-    if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() &&
-        !kvm_irqchip_is_split()) {
-        error_report("Intel Interrupt Remapping cannot work with "
-                     "kernel-irqchip=on, please use 'split|off'.");
-        exit(1);
-    }
 }
 
 static void vtd_class_init(ObjectClass *klass, void *data)
diff --git a/hw/i386/x86-iommu.c b/hw/i386/x86-iommu.c
index 2278af7..66510f7 100644
--- a/hw/i386/x86-iommu.c
+++ b/hw/i386/x86-iommu.c
@@ -21,6 +21,7 @@
 #include "hw/sysbus.h"
 #include "hw/boards.h"
 #include "hw/i386/x86-iommu.h"
+#include "sysemu/kvm.h"
 #include "qemu/error-report.h"
 #include "trace.h"
 
@@ -84,6 +85,13 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
     if (x86_class->realize) {
         x86_class->realize(dev, errp);
     }
+    /* Currently IOMMU IR only support "kernel-irqchip={off|split}" */
+    if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() &&
+        !kvm_irqchip_is_split()) {
+        error_report("Interrupt Remapping cannot work with "
+                     "kernel-irqchip=on, please use 'split|off'.");
+        exit(1);
+    }
 
     x86_iommu_set_default(X86_IOMMU_DEVICE(dev));
 }
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping
  2016-08-10 19:42 [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping David Kiarie
                   ` (3 preceding siblings ...)
  2016-08-10 19:42 ` [Qemu-devel] [V1 4/4] hw/iommu: share common between IOMMUs David Kiarie
@ 2016-08-10 19:46 ` David Kiarie
  2016-08-11  6:39 ` Valentine Sinitsyn
  5 siblings, 0 replies; 13+ messages in thread
From: David Kiarie @ 2016-08-10 19:46 UTC (permalink / raw)
  To: QEMU Developers, Peter Xu
  Cc: J. Kiszka, Valentine Sinitsyn, Michael S. Tsirkin, Paolo Bonzini,
	Eduardo Habkost, Peter Maydell, David Kiarie

On Wed, Aug 10, 2016 at 10:42 PM, David Kiarie <davidkiarie4@gmail.com>
wrote:

Sorry, forgot to cc Peter.

Hello all,
>
> The following patchset adds AMD-Vi interrupt remapping logic
> to Qemu and hooks it onto existing interrupt remapping infrastructure.It
> has
> a dependency on "Explicit SID for IOAPIC" patchset though.
>
> I would appreciate your feedback!
>
> For quick testing https://github.com/aslaq/qemu IR
>
> David Kiarie (4):
>   hw/iommu: Prepare for AMD IOMMU interrupt remapping
>   hw/iommu: AMD IOMMU interrupt remapping
>   hw/acpi: report IOAPIC on IVRS
>   hw/iommu: share common between IOMMUs
>
>  hw/i386/acpi-build.c  |   2 +
>  hw/i386/amd_iommu.c   | 226 ++++++++++++++++++++++++++++++
> +++++++++++++++++++-
>  hw/i386/amd_iommu.h   |  74 +++++++++++++++++
>  hw/i386/intel_iommu.c |   9 --
>  hw/i386/trace-events  |   7 ++
>  hw/i386/x86-iommu.c   |   8 ++
>  6 files changed, 316 insertions(+), 10 deletions(-)
>
> --
> 2.1.4
>
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping
  2016-08-10 19:42 [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping David Kiarie
                   ` (4 preceding siblings ...)
  2016-08-10 19:46 ` [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping David Kiarie
@ 2016-08-11  6:39 ` Valentine Sinitsyn
  2016-08-11  8:07   ` David Kiarie
  5 siblings, 1 reply; 13+ messages in thread
From: Valentine Sinitsyn @ 2016-08-11  6:39 UTC (permalink / raw)
  To: David Kiarie, qemu-devel
  Cc: jan.kiszka, mst, pbonzini, ehabkost, peter.maydell

Hi David,

On 11.08.2016 00:42, David Kiarie wrote:
> Hello all,
>
> The following patchset adds AMD-Vi interrupt remapping logic
> to Qemu and hooks it onto existing interrupt remapping infrastructure.It has
> a dependency on "Explicit SID for IOAPIC" patchset though.
>
> I would appreciate your feedback!
Nice work! I'll look into it deeper in a few days.

In the meantime, I'm not able to apply this on top of your V15 IOMMU 
series applied to the current master. Am I missing anything?

Valentine

>
> For quick testing https://github.com/aslaq/qemu IR
>
> David Kiarie (4):
>   hw/iommu: Prepare for AMD IOMMU interrupt remapping
>   hw/iommu: AMD IOMMU interrupt remapping
>   hw/acpi: report IOAPIC on IVRS
>   hw/iommu: share common between IOMMUs
>
>  hw/i386/acpi-build.c  |   2 +
>  hw/i386/amd_iommu.c   | 226 +++++++++++++++++++++++++++++++++++++++++++++++++-
>  hw/i386/amd_iommu.h   |  74 +++++++++++++++++
>  hw/i386/intel_iommu.c |   9 --
>  hw/i386/trace-events  |   7 ++
>  hw/i386/x86-iommu.c   |   8 ++
>  6 files changed, 316 insertions(+), 10 deletions(-)
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping
  2016-08-11  6:39 ` Valentine Sinitsyn
@ 2016-08-11  8:07   ` David Kiarie
  0 siblings, 0 replies; 13+ messages in thread
From: David Kiarie @ 2016-08-11  8:07 UTC (permalink / raw)
  To: Valentine Sinitsyn
  Cc: QEMU Developers, J. Kiszka, Michael S. Tsirkin, Paolo Bonzini,
	Eduardo Habkost, Peter Maydell

On Thu, Aug 11, 2016 at 9:39 AM, Valentine Sinitsyn <
valentine.sinitsyn@gmail.com> wrote:

> Hi David,
>
> On 11.08.2016 00:42, David Kiarie wrote:
>
>> Hello all,
>>
>> The following patchset adds AMD-Vi interrupt remapping logic
>> to Qemu and hooks it onto existing interrupt remapping infrastructure.It
>> has
>> a dependency on "Explicit SID for IOAPIC" patchset though.
>>
>> I would appreciate your feedback!
>>
> Nice work! I'll look into it deeper in a few days.
>
> In the meantime, I'm not able to apply this on top of your V15 IOMMU
> series applied to the current master. Am I missing anything?


I think it got stale already. You can test from here though
https://github.com/aslaq/qemu v15


>
> Valentine
>
>
>
>> For quick testing https://github.com/aslaq/qemu IR
>>
>> David Kiarie (4):
>>   hw/iommu: Prepare for AMD IOMMU interrupt remapping
>>   hw/iommu: AMD IOMMU interrupt remapping
>>   hw/acpi: report IOAPIC on IVRS
>>   hw/iommu: share common between IOMMUs
>>
>>  hw/i386/acpi-build.c  |   2 +
>>  hw/i386/amd_iommu.c   | 226 ++++++++++++++++++++++++++++++
>> +++++++++++++++++++-
>>  hw/i386/amd_iommu.h   |  74 +++++++++++++++++
>>  hw/i386/intel_iommu.c |   9 --
>>  hw/i386/trace-events  |   7 ++
>>  hw/i386/x86-iommu.c   |   8 ++
>>  6 files changed, 316 insertions(+), 10 deletions(-)
>>
>>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [V1 1/4] hw/iommu: Prepare for AMD IOMMU interrupt remapping
  2016-08-10 19:42 ` [Qemu-devel] [V1 1/4] hw/iommu: Prepare for AMD IOMMU interrupt remapping David Kiarie
@ 2016-08-12 19:19   ` Valentine Sinitsyn
  0 siblings, 0 replies; 13+ messages in thread
From: Valentine Sinitsyn @ 2016-08-12 19:19 UTC (permalink / raw)
  To: David Kiarie, qemu-devel
  Cc: jan.kiszka, mst, pbonzini, ehabkost, peter.maydell

On 11.08.2016 00:42, David Kiarie wrote:
> Introduce macros and trace events for use in AMD IOMMU
> interrupt remapping
>
> Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
> ---
>  hw/i386/amd_iommu.h  | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/i386/trace-events |  7 +++++
>  2 files changed, 79 insertions(+)
>
> diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
> index 5d0b91d..2a7f19e 100644
> --- a/hw/i386/amd_iommu.h
> +++ b/hw/i386/amd_iommu.h
> @@ -177,6 +177,78 @@
>  #define AMDVI_IOTLB_MAX_SIZE 1024
>  #define AMDVI_DEVID_SHIFT    36
>
> +/* interrupt types */
> +#define AMDVI_MT_FIXED  0x0
> +#define AMDVI_MT_ARBIT  0x1
> +#define AMDVI_MT_SMI    0x2
> +#define AMDVI_MT_NMI    0x3
> +#define AMDVI_MT_INIT   0x4
> +#define AMDVI_MT_EXTINT 0x6
> +#define AMDVI_MT_LINT1  0xb
> +#define AMDVI_MT_LINT0  0xe
> +
> +/* Ext reg, GA support */
> +#define AMDVI_GASUP    (1UL << 7)
> +/* MMIO control GA enable bits */
> +#define AMDVI_GAEN     (1UL << 17)
> +
> +/* MSI interrupt type mask */
> +#define AMDVI_IR_TYPE_MASK 0x300
> +
> +/* interrupt destination mode */
> +#define AMDVI_IRDEST_MODE_MASK 0x2
> +
> +/* select MSI data 10:0 bits */
> +#define AMDVI_IRTE_INDEX_MASK 0x7ff
> +
> +/* bits determining whether specific interrupts should be passed
> + * split DTE into 64-bit chunks
> + */
> +#define AMDVI_DTE_INTPASS       56
> +#define AMDVI_DTE_EINTPASS      57
> +#define AMDVI_DTE_NMIPASS       58
> +#define AMDVI_DTE_INTCTL        60
> +#define AMDVI_DTE_LINT0PASS     62
> +#define AMDVI_DTE_LINT1PASS     63
I suggest adding _SHIFT prefix, to make the meaning clearer.

> +
> +/* interrupt data valid */
> +#define AMDVI_IR_VALID          (1UL << 0)
> +
> +/* interrupt root table mask */
> +#define AMDVI_IRTEROOT_MASK     0xffffffffffffc0
> +
> +/* default IRTE size */
> +#define AMDVI_DEFAULT_IRTE_SIZE 0x4
> +
> +/* IRTE size with GASup enabled */
> +#define AMDVI_IRTE_SIZE_GASUP   0x10
We don't have Virtual APIC, and perhaps this is not needed (see comments 
in the next patch).

> +
> +#define AMDVI_IRTE_VECTOR_MASK    (0xffU << 16)
> +#define AMDVI_IRTE_DEST_MASK      (0xffU << 8)
> +#define AMDVI_IRTE_DM_MASK        (0x1U << 6)
> +#define AMDVI_IRTE_RQEOI_MASK     (0x1U << 5)
> +#define AMDVI_IRTE_INTTYPE_MASK   (0x7U << 2)
> +#define AMDVI_IRTE_SUPIOPF_MASK   (0x1U << 1)
> +#define AMDVI_IRTE_REMAP_MASK     (0x1U << 0)
> +
> +#define AMDVI_IR_TABLE_SIZE_MASK 0xfe
> +
> +/* offsets into MSI data */
> +#define AMDVI_MSI_DATA_DM_RSHIFT       0x8
> +#define AMDVI_MSI_DATA_LEVEL_RSHIFT    0xe
> +#define AMDVI_MSI_DATA_TRM_RSHIFT      0xf
> +
> +/* offsets into MSI address */
> +#define AMDVI_MSI_ADDR_DM_RSHIFT       0x2
> +#define AMDVI_MSI_ADDR_RH_RSHIFT       0x3
> +#define AMDVI_MSI_ADDR_DEST_RSHIFT     0xc
> +
> +#define AMDVI_BUS_NUM                  0x0
> +/* AMD-Vi specific IOAPIC Device function */
> +#define AMDVI_DEVFN_IOAPIC             0xa0
So you decided not to keep these as a single 
AMDVI_SOUTHBRIDGE_IOAPIC_ID, or similar?

Valentine

> +
> +#define AMDVI_LOCAL_APIC_ADDR     0xfee00000
> +
>  /* extended feature support */
>  #define AMDVI_EXT_FEATURES (AMDVI_FEATURE_PREFETCH | AMDVI_FEATURE_PPR | \
>          AMDVI_FEATURE_IA | AMDVI_FEATURE_GT | AMDVI_FEATURE_GA | \
> diff --git a/hw/i386/trace-events b/hw/i386/trace-events
> index 592de3a..5c12c10 100644
> --- a/hw/i386/trace-events
> +++ b/hw/i386/trace-events
> @@ -42,3 +42,10 @@ amdvi_mode_invalid(unsigned level, uint64_t addr)"error: translation level 0x%"P
>  amdvi_page_fault(uint64_t addr) "error: page fault accessing guest physical address 0x%"PRIx64
>  amdvi_iotlb_hit(uint16_t bus, uint16_t slot, uint16_t func, uint64_t addr, uint64_t txaddr) "hit iotlb devid %02x:%02x.%x gpa 0x%"PRIx64 " hpa 0x%"PRIx64
>  amdvi_translation_result(uint16_t bus, uint16_t slot, uint16_t func, uint64_t addr, uint64_t txaddr) "devid: %02x:%02x.%x gpa 0x%"PRIx64 " hpa 0x%"PRIx64
> +amdvi_irte_get_fail(uint64_t addr, uint64_t offset) "couldn't access device table entry 0x%"PRIx64" + offset 0x%"PRIx64
> +amdvi_invalid_irte_entry(uint16_t devid, uint64_t offset) "devid %x requested IRTE offset 0x%"PRIx64" Outside IR table range"
> +amdvi_ir_request(uint32_t data, uint64_t addr, uint16_t sid) "IR request data 0x%"PRIx32" address 0x%"PRIx64" SID %x"
> +amdvi_ir_remap(uint32_t data, uint64_t addr, uint16_t sid) "IR remap data 0x%"PRIx32" address 0x%"PRIx64" SID %x"
> +amdvi_ir_target_abort(uint32_t data, uint64_t addr, uint16_t sid) "IR target abort data 0x%"PRIx32" address 0x%"PRIx64" SID %x"
> +amdvi_ir_write_fail(uint64_t addr, uint32_t data) "fail to write to addr 0x%"PRIx64 " value 0x%"PRIx32
> +amdvi_ir_read_fail(uint64_t addr) " fail to read from addr 0x%"PRIx64
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [V1 2/4] hw/iommu: AMD IOMMU interrupt remapping
  2016-08-10 19:42 ` [Qemu-devel] [V1 2/4] hw/iommu: " David Kiarie
@ 2016-08-12 20:08   ` Valentine Sinitsyn
  2016-08-12 20:30     ` David Kiarie
  0 siblings, 1 reply; 13+ messages in thread
From: Valentine Sinitsyn @ 2016-08-12 20:08 UTC (permalink / raw)
  To: David Kiarie, qemu-devel
  Cc: jan.kiszka, mst, pbonzini, ehabkost, peter.maydell

On 11.08.2016 00:42, David Kiarie wrote:
> Introduce AMD IOMMU interrupt remapping and hook it onto
> the existing interrupt remapping infrastructure
>
> Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
> ---
>  hw/i386/amd_iommu.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++-
>  hw/i386/amd_iommu.h |   2 +
>  2 files changed, 227 insertions(+), 1 deletion(-)
>
> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
> index 5fab9aa..825159b 100644
> --- a/hw/i386/amd_iommu.c
> +++ b/hw/i386/amd_iommu.c
> @@ -18,12 +18,14 @@
>   * with this program; if not, see <http://www.gnu.org/licenses/>.
>   *
>   * Cache implementation inspired by hw/i386/intel_iommu.c
> + *
>   */
>  #include "qemu/osdep.h"
>  #include <math.h>
>  #include "hw/pci/msi.h"
>  #include "hw/i386/pc.h"
>  #include "hw/i386/amd_iommu.h"
> +#include "hw/i386/ioapic_internal.h"
>  #include "hw/pci/pci_bus.h"
>  #include "trace.h"
>
> @@ -660,6 +662,11 @@ static void amdvi_inval_inttable(AMDVIState *s, CMDInvalIntrTable *inval)
>          amdvi_log_illegalcom_error(s, inval->type, s->cmdbuf + s->cmdbuf_head);
>          return;
>      }
> +
> +    if (s->ir_cache) {
> +        x86_iommu_iec_notify_all(X86_IOMMU_DEVICE(s), true, 0, 0);
> +    }
> +
>      trace_amdvi_intr_inval();
>  }
>
> @@ -1221,6 +1228,207 @@ static IOMMUTLBEntry amdvi_translate(MemoryRegion *iommu, hwaddr addr,
>      return ret;
>  }
>
> +static inline int amdvi_ir_pass(MSIMessage *src, MSIMessage *dst, uint8_t bit,
> +                                uint64_t dte)
The name is misleading. Actually, this function handles non-vectored 
interrupts (either passes or target aborts them). Maybe call it 
amdvi_ir_handle_non_vectored() ?

> +{
> +    if ((dte & (1UL << bit))) {
> +        /* passing interrupt enabled */
> +        dst->address = src->address;
> +        dst->data = src->data;
> +    } else {
> +        /* should be target aborted */
> +        return -AMDVI_TARGET_ABORT;
> +    }
> +    return 0;
> +}
> +
> +static int amdvi_remap_ir_intctl(uint64_t dte, uint32_t irte,
> +                                 MSIMessage *src, MSIMessage *dst)
> +{
> +    int ret = 0;
> +
> +    switch ((dte >> AMDVI_DTE_INTCTL ) & 3UL) {
AMDVI_DTE_INTCTL_SHIFT? Yes, I should have mentioned it in a previous 
patch, sorry. Maybe also introduce macros for 3UL and 1, 2, 3 in switch 
branches below.

> +    case 1:
> +        /* pass */
> +        memcpy(dst, src, sizeof(*dst));
> +        break;
> +    case 2:
> +        /* remap */
> +        if (irte & AMDVI_IRTE_REMAP_MASK) {
> +            /* LOCAL APIC address */
> +            dst->address = AMDVI_LOCAL_APIC_ADDR;
> +            /* destination mode */
> +            dst->address |= (((irte & AMDVI_IRTE_DM_MASK) >> 6) <<
> +                    AMDVI_MSI_ADDR_DM_RSHIFT);
> +            /* RH */
> +            dst->address |= ((irte & AMDVI_IRTE_RQEOI_MASK) >> 5) <<
> +                AMDVI_MSI_ADDR_RH_RSHIFT;
> +            /* Destination ID */
> +            dst->address |= ((irte & AMDVI_IRTE_DEST_MASK) >> 8) <<
> +                AMDVI_MSI_ADDR_DEST_RSHIFT;
> +            /* construct data - vector */
> +            dst->data |= (irte & AMDVI_IRTE_VECTOR_MASK) >> 16;
> +            /* Interrupt type */
> +            dst->data |= ((irte & AMDVI_IRTE_INTTYPE_MASK) >> 2) <<
> +                AMDVI_MSI_DATA_DM_RSHIFT;
These bit operations look scary. Did you considered using bitfields or 
wrapping them in macros?
> +        } else  {
> +            ret = -AMDVI_TARGET_ABORT;
> +        }
> +        break;
> +    case 0:
> +    case 3:
In fact, you should report this as event when IR == 1.

> +    default:
> +        ret = -AMDVI_TARGET_ABORT;
> +    }
> +    return ret;
> +}
> +/*
> + * We don't support guest virtual APIC so IRTE size will most likely always be 4
> + */
> +static int amdvi_irte_get(AMDVIState *s, MSIMessage *src, uint32_t *irte,
> +                          uint64_t *dte, uint16_t devid)
> +{
> +    uint64_t irte_root, offset = devid * AMDVI_DEVTAB_ENTRY_SIZE,
> +             irte_size = AMDVI_DEFAULT_IRTE_SIZE,
> +             ir_table_size;
> +
> +    /* check for GASup and if it's enabled */
> +    if ((amdvi_readq(s, AMDVI_EXT_FEATURES) & AMDVI_GASUP)
> +        && (amdvi_readq(s, AMDVI_MMIO_CONTROL) & AMDVI_GAEN)) {
> +        /* set a different IRTE size */
> +        irte_size = AMDVI_IRTE_SIZE_GASUP;
> +    }
As I said, this is likely the only place where we account for Virtual 
APIC. You don't seem to handle Virtual APIC Root in DTE, for instance. 
Maybe drop this incomplete support altogether, and print some warning 
here instead?

> +    if (dma_memory_read(&address_space_memory, s->devtab + offset, dte,
> +                        AMDVI_DEVTAB_ENTRY_SIZE)) {
> +        trace_amdvi_dte_get_fail(s->devtab, offset);
> +        return -AMDVI_DEV_TAB_HW;
> +    }
> +
> +    irte_root = dte[2] & AMDVI_IRTEROOT_MASK;
> +    offset = (src->data & AMDVI_IRTE_INDEX_MASK) << 2;
> +    ir_table_size = pow(2, dte[2] & AMDVI_IR_TABLE_SIZE_MASK);
1 << dte[2] & AMDVI_IR_TABLE_SIZE_MASK ?

> +    /* enforce IR table size */
> +    if (offset > (ir_table_size * irte_size)) {
> +        trace_amdvi_invalid_irte_entry(offset, ir_table_size);
> +        return -AMDVI_TARGET_ABORT;
> +    }
> +    /* read IRTE */
> +    if (dma_memory_read(&address_space_memory, irte_root + offset,
> +        irte, sizeof(*irte))) {
> +        trace_amdvi_irte_get_fail(irte_root, offset);
> +        return -AMDVI_DEV_TAB_HW;
> +    }
> +    return 0;
> +}
> +
> +static int amdvi_int_remap(X86IOMMUState *iommu, MSIMessage *src,
> +                           MSIMessage *dst, uint16_t sid)
> +{
> +    trace_amdvi_ir_request(src->data, src->address, sid);
> +
> +    AMDVIState *s = AMD_IOMMU_DEVICE(iommu);
> +    int ret = 0;
> +    uint64_t dte[4];
> +    uint32_t ir_enabled, irte;
> +
> +    ret = amdvi_irte_get(s, src, &irte, dte, sid);
> +    if (ret < 0) {
> +        goto no_remap;
> +    }
> +    /* interrupt remapping disabled */
> +    if (!(dte[2] & AMDVI_IR_VALID)) {
> +        memcpy(dst, src, sizeof(*src));
> +        return ret;
> +    }
> +    switch (src->data & AMDVI_IR_TYPE_MASK) {
> +    case AMDVI_MT_FIXED:
> +    case AMDVI_MT_ARBIT:
> +        ret = amdvi_remap_ir_intctl(dte[2], irte, src, dst);
> +        if (ret < 0) {
> +            goto no_remap;
> +        } else {
> +            s->ir_cache = true;
> +            trace_amdvi_ir_remap(dst->data, dst->address, sid);
> +            return ret;
> +        }
> +    /* not handling SMI currently */
> +    case AMDVI_MT_SMI:
Maybe also add some warning here so we'd know when to implement SMI Filter.

> +        goto no_remap;
> +    case AMDVI_MT_NMI:
> +        ir_enabled = AMDVI_DTE_NMIPASS;
> +        break;
> +    case AMDVI_MT_INIT:
> +        ir_enabled = AMDVI_DTE_INTPASS;
> +        break;
> +    case AMDVI_MT_EXTINT:
> +        ir_enabled = AMDVI_DTE_EINTPASS;
> +        break;
> +    case AMDVI_MT_LINT1:
> +        ir_enabled = AMDVI_DTE_LINT1PASS;
> +        break;
> +    case AMDVI_MT_LINT0:
> +        ir_enabled = AMDVI_DTE_LINT0PASS;
> +    }
> +
> +    ret = amdvi_ir_pass(src, dst, ir_enabled, dte[2]);
> +    if (ret < 0){
> +        goto no_remap;
> +    }
> +    s->ir_cache = true;
> +    trace_amdvi_ir_remap(dst->data, dst->address, sid);
> +    return ret;
> +no_remap:
> +    memcpy(dst, src, sizeof(*src));
Do you need this memcpy()?  The original request is target aborted as 
soon as this returns.

> +    trace_amdvi_ir_target_abort(dst->data, dst->address, sid);
> +    return ret;
> +}
> +
> +static MemTxResult amdvi_ir_read(void *opaque, hwaddr addr,
> +                                 uint64_t *data, unsigned size,
> +                                 MemTxAttrs attrs)
> +{
> +    return MEMTX_OK;
> +}
> +
> +static MemTxResult amdvi_ir_write(void *opaque, hwaddr addr, uint64_t val,
> +                                  unsigned size, MemTxAttrs attrs)
> +{
> +    AMDVIAddressSpace *as = opaque;
> +    MSIMessage from = { addr + AMDVI_INT_ADDR_FIRST, val }, to = { 0, 0};
> +    uint16_t sid = PCI_BUILD_BDFi(as->bus_num, as->devfn);
'BDFi' reads like a typo

> +    int ret = 0;
> +
> +    ret  = amdvi_int_remap(X86_IOMMU_DEVICE(as->iommu_state), &from, &to,
> +                           attrs.requester_id);
> +
> +    if (ret < 0) {
> +        trace_amdvi_ir_target_abort(from.data, from.address,
> +                                    attrs.requester_id);
> +        return MEMTX_ERROR;
> +    }
> +
> +    if(dma_memory_write(&address_space_memory, to.address, &to.data, size)) {
> +        trace_amdvi_ir_write_fail(to.address, to.data);
> +        return MEMTX_ERROR;
> +    }
> +
> +    return MEMTX_OK;
> +}
> +
> +static const MemoryRegionOps amdvi_ir_ops = {
> +    .read_with_attrs = amdvi_ir_read,
> +    .write_with_attrs = amdvi_ir_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    },
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    }
> +};
> +
>  static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
>  {
>      AMDVIState *s = opaque;
> @@ -1244,6 +1452,12 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
>
>          memory_region_init_iommu(&iommu_as[devfn]->iommu, OBJECT(s),
>                                   &s->iommu_ops, "amd-iommu", UINT64_MAX);
> +        memory_region_init_io(&iommu_as[devfn]->iommu_ir, OBJECT(s),
> +                              &amdvi_ir_ops, iommu_as[devfn], "amd-iommu-ir",
> +                              AMDVI_INT_ADDR_SIZE);
> +        memory_region_add_subregion(&iommu_as[devfn]->iommu,
> +                                    AMDVI_INT_ADDR_FIRST,
> +                                    &iommu_as[devfn]->iommu_ir);
>          address_space_init(&iommu_as[devfn]->as, &iommu_as[devfn]->iommu,
>                             "amd-iommu");
>      }
> @@ -1292,6 +1506,7 @@ static void amdvi_init(AMDVIState *s)
>      s->enabled = false;
>      s->ats_enabled = false;
>      s->cmdbuf_enabled = false;
> +    s->ir_cache = false;
>
>      /* reset MMIO */
>      memset(s->mmior, 0, AMDVI_MMIO_SIZE);
> @@ -1331,11 +1546,15 @@ 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;
> +    PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
>      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 */
> +    /* AMD IOMMU has Interrupt Remapping on by default */
> +    x86_iommu->intr_supported = true;
>      x86_iommu->type = TYPE_AMD;
> +
> +    /* This device should take care of IOMMU PCI properties */
>      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,
> @@ -1347,9 +1566,13 @@ static void amdvi_realize(DeviceState *dev, Error **err)
>      memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio",
>                            AMDVI_MMIO_SIZE);
>
> +    x86_iommu->ioapic_bdf = PCI_BUILD_BDF(AMDVI_BUS_NUM,
> +             AMDVI_DEVFN_IOAPIC);
> +
>      sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio);
>      sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, AMDVI_BASE_ADDR);
>      pci_setup_iommu(bus, amdvi_host_dma_iommu, s);
> +    pcms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_DEVFN_IOAPIC);
>      s->devid = object_property_get_int(OBJECT(&s->pci), "addr", err);
>      msi_init(&s->pci.dev, 0, 1, true, false, err);
>      amdvi_init(s);
> @@ -1376,6 +1599,7 @@ static void amdvi_class_init(ObjectClass *klass, void* data)
>      dc->vmsd = &vmstate_amdvi;
>      dc->hotpluggable = false;
>      dc_class->realize = amdvi_realize;
> +    dc_class->int_remap = amdvi_int_remap;
>  }
>
>  static const TypeInfo amdvi = {
> diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
> index 2a7f19e..f0e23a8 100644
> --- a/hw/i386/amd_iommu.h
> +++ b/hw/i386/amd_iommu.h
> @@ -356,6 +356,8 @@ typedef struct AMDVIState {
>      uint32_t evtlog_len;         /* event log length             */
>      uint32_t evtlog_head;        /* current IOMMU write position */
>      uint32_t evtlog_tail;        /* current Software read position */
> +    /* whether we have remapped any interrupts and hence IR cache */
> +    bool ir_cache;
>
>      /* unused for now */
>      hwaddr excl_base;            /* base DVA - IOMMU exclusion range */
>

Valentine

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [V1 3/4] hw/acpi: report IOAPIC on IVRS
  2016-08-10 19:42 ` [Qemu-devel] [V1 3/4] hw/acpi: report IOAPIC on IVRS David Kiarie
@ 2016-08-12 20:14   ` Valentine Sinitsyn
  2016-08-12 20:23     ` David Kiarie
  0 siblings, 1 reply; 13+ messages in thread
From: Valentine Sinitsyn @ 2016-08-12 20:14 UTC (permalink / raw)
  To: David Kiarie, qemu-devel
  Cc: jan.kiszka, mst, pbonzini, ehabkost, peter.maydell

On 11.08.2016 00:42, David Kiarie wrote:
> Report IOAPIC via IVRS which effectively allows linux AMD-Vi
> driver to enable interrupt remapping
>
> Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
> ---
>  hw/i386/acpi-build.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 49bd183..da602c3 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -2615,6 +2615,8 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker)
>       *   Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte)
>       */
>      build_append_int_noprefix(table_data, 0x0000001, 4);
> +    /* IOAPIC represented as an 8-byte entry. Spec v2.62 Tables 97 */
> +    build_append_int_noprefix(table_data, 0x0100a000ff000048, 8);
Nit: bit 3 in DTE Setting is reserved (Table 97 in the spec), while you 
set them all with 0xff.

>
>      build_header(linker, table_data, (void *)(table_data->data + iommu_start),
>                   "IVRS", table_data->len - iommu_start, 1, NULL, NULL);
>

Valentine

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [V1 3/4] hw/acpi: report IOAPIC on IVRS
  2016-08-12 20:14   ` Valentine Sinitsyn
@ 2016-08-12 20:23     ` David Kiarie
  0 siblings, 0 replies; 13+ messages in thread
From: David Kiarie @ 2016-08-12 20:23 UTC (permalink / raw)
  To: Valentine Sinitsyn
  Cc: QEMU Developers, J. Kiszka, Michael S. Tsirkin, Paolo Bonzini,
	Eduardo Habkost, Peter Maydell

On Fri, Aug 12, 2016 at 11:14 PM, Valentine Sinitsyn <
valentine.sinitsyn@gmail.com> wrote:

> On 11.08.2016 00:42, David Kiarie wrote:
>
>> Report IOAPIC via IVRS which effectively allows linux AMD-Vi
>> driver to enable interrupt remapping
>>
>> Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
>> ---
>>  hw/i386/acpi-build.c | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> index 49bd183..da602c3 100644
>> --- a/hw/i386/acpi-build.c
>> +++ b/hw/i386/acpi-build.c
>> @@ -2615,6 +2615,8 @@ build_amd_iommu(GArray *table_data, BIOSLinker
>> *linker)
>>       *   Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte)
>>       */
>>      build_append_int_noprefix(table_data, 0x0000001, 4);
>> +    /* IOAPIC represented as an 8-byte entry. Spec v2.62 Tables 97 */
>> +    build_append_int_noprefix(table_data, 0x0100a000ff000048, 8);
>>
> Nit: bit 3 in DTE Setting is reserved (Table 97 in the spec), while you
> set them all with 0xff.


Noted, thanks!


>
>
>
>>      build_header(linker, table_data, (void *)(table_data->data +
>> iommu_start),
>>                   "IVRS", table_data->len - iommu_start, 1, NULL, NULL);
>>
>>
> Valentine
>
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [V1 2/4] hw/iommu: AMD IOMMU interrupt remapping
  2016-08-12 20:08   ` Valentine Sinitsyn
@ 2016-08-12 20:30     ` David Kiarie
  0 siblings, 0 replies; 13+ messages in thread
From: David Kiarie @ 2016-08-12 20:30 UTC (permalink / raw)
  To: Valentine Sinitsyn
  Cc: QEMU Developers, J. Kiszka, Michael S. Tsirkin, Paolo Bonzini,
	Eduardo Habkost, Peter Maydell

On Fri, Aug 12, 2016 at 11:08 PM, Valentine Sinitsyn <
valentine.sinitsyn@gmail.com> wrote:

> On 11.08.2016 00:42, David Kiarie wrote:
>
>> Introduce AMD IOMMU interrupt remapping and hook it onto
>
>
>> +static inline int amdvi_ir_pass(MSIMessage *src, MSIMessage *dst,
>> uint8_t bit,
>> +                                uint64_t dte)
>>
> The name is misleading. Actually, this function handles non-vectored
> interrupts (either passes or target aborts them). Maybe call it
> amdvi_ir_handle_non_vectored() ?
>
> +{
>> +    if ((dte & (1UL << bit))) {
>> +        /* passing interrupt enabled */
>> +        dst->address = src->address;
>> +        dst->data = src->data;
>> +    } else {
>> +        /* should be target aborted */
>> +        return -AMDVI_TARGET_ABORT;
>> +    }
>> +    return 0;
>> +}
>> +
>> +static int amdvi_remap_ir_intctl(uint64_t dte, uint32_t irte,
>> +                                 MSIMessage *src, MSIMessage *dst)
>> +{
>> +    int ret = 0;
>> +
>> +    switch ((dte >> AMDVI_DTE_INTCTL ) & 3UL) {
>>
> AMDVI_DTE_INTCTL_SHIFT? Yes, I should have mentioned it in a previous
> patch, sorry. Maybe also introduce macros for 3UL and 1, 2, 3 in switch
> branches below.
>
> +    case 1:
>> +        /* pass */
>> +        memcpy(dst, src, sizeof(*dst));
>> +        break;
>> +    case 2:
>> +        /* remap */
>> +        if (irte & AMDVI_IRTE_REMAP_MASK) {
>> +            /* LOCAL APIC address */
>> +            dst->address = AMDVI_LOCAL_APIC_ADDR;
>> +            /* destination mode */
>> +            dst->address |= (((irte & AMDVI_IRTE_DM_MASK) >> 6) <<
>> +                    AMDVI_MSI_ADDR_DM_RSHIFT);
>> +            /* RH */
>> +            dst->address |= ((irte & AMDVI_IRTE_RQEOI_MASK) >> 5) <<
>> +                AMDVI_MSI_ADDR_RH_RSHIFT;
>> +            /* Destination ID */
>> +            dst->address |= ((irte & AMDVI_IRTE_DEST_MASK) >> 8) <<
>> +                AMDVI_MSI_ADDR_DEST_RSHIFT;
>> +            /* construct data - vector */
>> +            dst->data |= (irte & AMDVI_IRTE_VECTOR_MASK) >> 16;
>> +            /* Interrupt type */
>> +            dst->data |= ((irte & AMDVI_IRTE_INTTYPE_MASK) >> 2) <<
>> +                AMDVI_MSI_DATA_DM_RSHIFT;
>>
> These bit operations look scary. Did you considered using bitfields or
> wrapping them in macros?


Will look at introducing macros to cover this comment and the previous one.


>
> +        } else  {
>> +            ret = -AMDVI_TARGET_ABORT;
>> +        }
>> +        break;
>> +    case 0:
>> +    case 3:
>>
> In fact, you should report this as event when IR == 1.
>
> +    default:
>> +        ret = -AMDVI_TARGET_ABORT;
>> +    }
>> +    return ret;
>> +}
>> +/*
>> + * We don't support guest virtual APIC so IRTE size will most likely
>> always be 4
>> + */
>> +static int amdvi_irte_get(AMDVIState *s, MSIMessage *src, uint32_t *irte,
>> +                          uint64_t *dte, uint16_t devid)
>> +{
>> +    uint64_t irte_root, offset = devid * AMDVI_DEVTAB_ENTRY_SIZE,
>> +             irte_size = AMDVI_DEFAULT_IRTE_SIZE,
>> +             ir_table_size;
>> +
>> +    /* check for GASup and if it's enabled */
>> +    if ((amdvi_readq(s, AMDVI_EXT_FEATURES) & AMDVI_GASUP)
>> +        && (amdvi_readq(s, AMDVI_MMIO_CONTROL) & AMDVI_GAEN)) {
>> +        /* set a different IRTE size */
>> +        irte_size = AMDVI_IRTE_SIZE_GASUP;
>> +    }
>>
> As I said, this is likely the only place where we account for Virtual
> APIC. You don't seem to handle Virtual APIC Root in DTE, for instance.
> Maybe drop this incomplete support altogether, and print some warning here
> instead?


I'll drop everything and print a warning instead.


>
>
> +    if (dma_memory_read(&address_space_memory, s->devtab + offset, dte,
>> +                        AMDVI_DEVTAB_ENTRY_SIZE)) {
>> +        trace_amdvi_dte_get_fail(s->devtab, offset);
>> +        return -AMDVI_DEV_TAB_HW;
>> +    }
>> +
>> +    irte_root = dte[2] & AMDVI_IRTEROOT_MASK;
>> +    offset = (src->data & AMDVI_IRTE_INDEX_MASK) << 2;
>> +    ir_table_size = pow(2, dte[2] & AMDVI_IR_TABLE_SIZE_MASK);
>>
> 1 << dte[2] & AMDVI_IR_TABLE_SIZE_MASK ?
>
>
> +    /* enforce IR table size */
>> +    if (offset > (ir_table_size * irte_size)) {
>> +        trace_amdvi_invalid_irte_entry(offset, ir_table_size);
>> +        return -AMDVI_TARGET_ABORT;
>> +    }
>> +    /* read IRTE */
>> +    if (dma_memory_read(&address_space_memory, irte_root + offset,
>> +        irte, sizeof(*irte))) {
>> +        trace_amdvi_irte_get_fail(irte_root, offset);
>> +        return -AMDVI_DEV_TAB_HW;
>> +    }
>> +    return 0;
>> +}
>> +
>> +static int amdvi_int_remap(X86IOMMUState *iommu, MSIMessage *src,
>> +                           MSIMessage *dst, uint16_t sid)
>> +{
>> +    trace_amdvi_ir_request(src->data, src->address, sid);
>> +
>> +    AMDVIState *s = AMD_IOMMU_DEVICE(iommu);
>> +    int ret = 0;
>> +    uint64_t dte[4];
>> +    uint32_t ir_enabled, irte;
>> +
>> +    ret = amdvi_irte_get(s, src, &irte, dte, sid);
>> +    if (ret < 0) {
>> +        goto no_remap;
>> +    }
>> +    /* interrupt remapping disabled */
>> +    if (!(dte[2] & AMDVI_IR_VALID)) {
>> +        memcpy(dst, src, sizeof(*src));
>> +        return ret;
>> +    }
>> +    switch (src->data & AMDVI_IR_TYPE_MASK) {
>> +    case AMDVI_MT_FIXED:
>> +    case AMDVI_MT_ARBIT:
>> +        ret = amdvi_remap_ir_intctl(dte[2], irte, src, dst);
>> +        if (ret < 0) {
>> +            goto no_remap;
>> +        } else {
>> +            s->ir_cache = true;
>> +            trace_amdvi_ir_remap(dst->data, dst->address, sid);
>> +            return ret;
>> +        }
>> +    /* not handling SMI currently */
>> +    case AMDVI_MT_SMI:
>>
> Maybe also add some warning here so we'd know when to implement SMI Filter.
>
>
> +        goto no_remap;
>> +    case AMDVI_MT_NMI:
>> +        ir_enabled = AMDVI_DTE_NMIPASS;
>> +        break;
>> +    case AMDVI_MT_INIT:
>> +        ir_enabled = AMDVI_DTE_INTPASS;
>> +        break;
>> +    case AMDVI_MT_EXTINT:
>> +        ir_enabled = AMDVI_DTE_EINTPASS;
>> +        break;
>> +    case AMDVI_MT_LINT1:
>> +        ir_enabled = AMDVI_DTE_LINT1PASS;
>> +        break;
>> +    case AMDVI_MT_LINT0:
>> +        ir_enabled = AMDVI_DTE_LINT0PASS;
>> +    }
>> +
>> +    ret = amdvi_ir_pass(src, dst, ir_enabled, dte[2]);
>> +    if (ret < 0){
>> +        goto no_remap;
>> +    }
>> +    s->ir_cache = true;
>> +    trace_amdvi_ir_remap(dst->data, dst->address, sid);
>> +    return ret;
>> +no_remap:
>> +    memcpy(dst, src, sizeof(*src));
>>
> Do you need this memcpy()?  The original request is target aborted as soon
> as this returns.
>
> +    trace_amdvi_ir_target_abort(dst->data, dst->address, sid);
>> +    return ret;
>> +}
>> +
>> +static MemTxResult amdvi_ir_read(void *opaque, hwaddr addr,
>> +                                 uint64_t *data, unsigned size,
>> +                                 MemTxAttrs attrs)
>> +{
>> +    return MEMTX_OK;
>> +}
>> +
>> +static MemTxResult amdvi_ir_write(void *opaque, hwaddr addr, uint64_t
>> val,
>> +                                  unsigned size, MemTxAttrs attrs)
>> +{
>> +    AMDVIAddressSpace *as = opaque;
>> +    MSIMessage from = { addr + AMDVI_INT_ADDR_FIRST, val }, to = { 0, 0};
>> +    uint16_t sid = PCI_BUILD_BDFi(as->bus_num, as->devfn);
>>
> 'BDFi' reads like a typo


Right, typo even I am not sure how it got this far.

Overall, thanks for review all comments will be covered in next version.


>
>
> +    int ret = 0;
>> +
>> +    ret  = amdvi_int_remap(X86_IOMMU_DEVICE(as->iommu_state), &from,
>> &to,
>> +                           attrs.requester_id);
>> +
>> +    if (ret < 0) {
>> +        trace_amdvi_ir_target_abort(from.data, from.address,
>> +                                    attrs.requester_id);
>> +        return MEMTX_ERROR;
>> +    }
>> +
>> +    if(dma_memory_write(&address_space_memory, to.address, &to.data,
>> size)) {
>> +        trace_amdvi_ir_write_fail(to.address, to.data);
>> +        return MEMTX_ERROR;
>> +    }
>> +
>> +    return MEMTX_OK;
>> +}
>> +
>> +static const MemoryRegionOps amdvi_ir_ops = {
>> +    .read_with_attrs = amdvi_ir_read,
>> +    .write_with_attrs = amdvi_ir_write,
>> +    .endianness = DEVICE_LITTLE_ENDIAN,
>> +    .impl = {
>> +        .min_access_size = 4,
>> +        .max_access_size = 4,
>> +    },
>> +    .valid = {
>> +        .min_access_size = 4,
>> +        .max_access_size = 4,
>> +    }
>> +};
>> +
>>  static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int
>> devfn)
>>  {
>>      AMDVIState *s = opaque;
>> @@ -1244,6 +1452,12 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus
>> *bus, void *opaque, int devfn)
>>
>>          memory_region_init_iommu(&iommu_as[devfn]->iommu, OBJECT(s),
>>                                   &s->iommu_ops, "amd-iommu", UINT64_MAX);
>> +        memory_region_init_io(&iommu_as[devfn]->iommu_ir, OBJECT(s),
>> +                              &amdvi_ir_ops, iommu_as[devfn],
>> "amd-iommu-ir",
>> +                              AMDVI_INT_ADDR_SIZE);
>> +        memory_region_add_subregion(&iommu_as[devfn]->iommu,
>> +                                    AMDVI_INT_ADDR_FIRST,
>> +                                    &iommu_as[devfn]->iommu_ir);
>>          address_space_init(&iommu_as[devfn]->as,
>> &iommu_as[devfn]->iommu,
>>                             "amd-iommu");
>>      }
>> @@ -1292,6 +1506,7 @@ static void amdvi_init(AMDVIState *s)
>>      s->enabled = false;
>>      s->ats_enabled = false;
>>      s->cmdbuf_enabled = false;
>> +    s->ir_cache = false;
>>
>>      /* reset MMIO */
>>      memset(s->mmior, 0, AMDVI_MMIO_SIZE);
>> @@ -1331,11 +1546,15 @@ 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;
>> +    PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
>>      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 */
>> +    /* AMD IOMMU has Interrupt Remapping on by default */
>> +    x86_iommu->intr_supported = true;
>>      x86_iommu->type = TYPE_AMD;
>> +
>> +    /* This device should take care of IOMMU PCI properties */
>>      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,
>> @@ -1347,9 +1566,13 @@ static void amdvi_realize(DeviceState *dev, Error
>> **err)
>>      memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s,
>> "amdvi-mmio",
>>                            AMDVI_MMIO_SIZE);
>>
>> +    x86_iommu->ioapic_bdf = PCI_BUILD_BDF(AMDVI_BUS_NUM,
>> +             AMDVI_DEVFN_IOAPIC);
>> +
>>      sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio);
>>      sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, AMDVI_BASE_ADDR);
>>      pci_setup_iommu(bus, amdvi_host_dma_iommu, s);
>> +    pcms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_DEVFN_IOAPIC);
>>      s->devid = object_property_get_int(OBJECT(&s->pci), "addr", err);
>>      msi_init(&s->pci.dev, 0, 1, true, false, err);
>>      amdvi_init(s);
>> @@ -1376,6 +1599,7 @@ static void amdvi_class_init(ObjectClass *klass,
>> void* data)
>>      dc->vmsd = &vmstate_amdvi;
>>      dc->hotpluggable = false;
>>      dc_class->realize = amdvi_realize;
>> +    dc_class->int_remap = amdvi_int_remap;
>>  }
>>
>>  static const TypeInfo amdvi = {
>> diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
>> index 2a7f19e..f0e23a8 100644
>> --- a/hw/i386/amd_iommu.h
>> +++ b/hw/i386/amd_iommu.h
>> @@ -356,6 +356,8 @@ typedef struct AMDVIState {
>>      uint32_t evtlog_len;         /* event log length             */
>>      uint32_t evtlog_head;        /* current IOMMU write position */
>>      uint32_t evtlog_tail;        /* current Software read position */
>> +    /* whether we have remapped any interrupts and hence IR cache */
>> +    bool ir_cache;
>>
>>      /* unused for now */
>>      hwaddr excl_base;            /* base DVA - IOMMU exclusion range */
>>
>>
> Valentine
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2016-08-12 20:30 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-08-10 19:42 [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping David Kiarie
2016-08-10 19:42 ` [Qemu-devel] [V1 1/4] hw/iommu: Prepare for AMD IOMMU interrupt remapping David Kiarie
2016-08-12 19:19   ` Valentine Sinitsyn
2016-08-10 19:42 ` [Qemu-devel] [V1 2/4] hw/iommu: " David Kiarie
2016-08-12 20:08   ` Valentine Sinitsyn
2016-08-12 20:30     ` David Kiarie
2016-08-10 19:42 ` [Qemu-devel] [V1 3/4] hw/acpi: report IOAPIC on IVRS David Kiarie
2016-08-12 20:14   ` Valentine Sinitsyn
2016-08-12 20:23     ` David Kiarie
2016-08-10 19:42 ` [Qemu-devel] [V1 4/4] hw/iommu: share common between IOMMUs David Kiarie
2016-08-10 19:46 ` [Qemu-devel] [V1 0/4] AMD-Vi Interrupt Remapping David Kiarie
2016-08-11  6:39 ` Valentine Sinitsyn
2016-08-11  8:07   ` David Kiarie

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).