AMD IOMMU uses MMIO registers 0x170-0x180 to generate the interrupts when guest enables xt support through control register [IntCapXTEn]. The guest programs these registers with appropriate vector and destination ID instead of writing to PCI MSI capability.
Current AMD vIOMMU is capable of generating interrupts only through PCI MSI capability and does not care about xt mode. Because of this AMD vIOMMU cannot generate event log interrupts when the guest has enabled xt mode. Introduce a new flag "intcapxten" which is set when guest writes control register [IntCapXTEn] (bit 51) and use vector and destination field in the XT MMIO register (0x170) to support XT mode. Signed-off-by: Sairaj Kodilkar <[email protected]> --- hw/i386/amd_iommu.c | 51 ++++++++++++++++++++++++++++++++++++++------ hw/i386/amd_iommu.h | 3 +++ hw/i386/trace-events | 1 + 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 7f08fc31111a..c6bc13c93679 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -200,18 +200,52 @@ static void amdvi_assign_andq(AMDVIState *s, hwaddr addr, uint64_t val) amdvi_writeq_raw(s, addr, amdvi_readq(s, addr) & val); } +union mmio_xt_intr { + uint64_t val; + struct { + uint64_t rsvd_1:2, + destination_mode:1, + rsvd_2:5, + destination_lo:24, + vector:8, + delivery_mode:1, + rsvd_3:15, + destination_hi:8; + }; +}; + +static void amdvi_build_xt_msi_msg(AMDVIState *s, MSIMessage *msg) +{ + union mmio_xt_intr xt_reg; + struct X86IOMMUIrq irq; + + xt_reg.val = amdvi_readq(s, AMDVI_MMIO_XT_GEN_INTR); + + irq.vector = xt_reg.vector; + irq.delivery_mode = xt_reg.delivery_mode; + irq.dest_mode = xt_reg.destination_mode; + irq.dest = (xt_reg.destination_hi << 24) | xt_reg.destination_lo; + irq.trigger_mode = 0; + irq.redir_hint = 0; + + x86_iommu_irq_to_msi_message(&irq, msg); +} + static void amdvi_generate_msi_interrupt(AMDVIState *s) { MSIMessage msg = {}; - MemTxAttrs attrs = { - .requester_id = pci_requester_id(&s->pci->dev) - }; - if (msi_enabled(&s->pci->dev)) { + if (s->intcapxten) { + trace_amdvi_generate_msi_interrupt("XT GEN"); + amdvi_build_xt_msi_msg(s, &msg); + } else if (msi_enabled(&s->pci->dev)) { + trace_amdvi_generate_msi_interrupt("MSI"); msg = msi_get_message(&s->pci->dev, 0); - address_space_stl_le(&address_space_memory, msg.address, msg.data, - attrs, NULL); + } else { + trace_amdvi_generate_msi_interrupt("NO MSI"); + return; } + apic_get_class(NULL)->send_msi(&msg); } static uint32_t get_next_eventlog_entry(AMDVIState *s) @@ -1490,6 +1524,7 @@ static inline void amdvi_mmio_get_name(hwaddr addr, MMIO_REG_TO_STRING(AMDVI_MMIO_PPR_BASE, name) MMIO_REG_TO_STRING(AMDVI_MMIO_PPR_HEAD, name) MMIO_REG_TO_STRING(AMDVI_MMIO_PPR_TAIL, name) + MMIO_REG_TO_STRING(AMDVI_MMIO_XT_GEN_INTR, name) default: name = "UNHANDLED"; } @@ -1549,6 +1584,7 @@ static void amdvi_handle_control_write(AMDVIState *s) AMDVI_MMIO_CONTROL_CMDBUFLEN); s->ga_enabled = !!(control & AMDVI_MMIO_CONTROL_GAEN); s->xten = !!(control & AMDVI_MMIO_CONTROL_XTEN) && s->xtsup; + s->intcapxten = !!(control & AMDVI_MMIO_CONTROL_INTCAPXTEN) && s->xtsup; /* update the flags depending on the control register */ if (s->cmdbuf_enabled) { @@ -1755,6 +1791,9 @@ static void amdvi_mmio_write(void *opaque, hwaddr addr, uint64_t val, case AMDVI_MMIO_STATUS: amdvi_mmio_reg_write(s, size, val, addr); break; + case AMDVI_MMIO_XT_GEN_INTR: + amdvi_mmio_reg_write(s, size, val, addr); + break; } } diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 32467d0bc241..399a4fb748e5 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -57,6 +57,7 @@ #define AMDVI_MMIO_EXCL_BASE 0x0020 #define AMDVI_MMIO_EXCL_LIMIT 0x0028 #define AMDVI_MMIO_EXT_FEATURES 0x0030 +#define AMDVI_MMIO_XT_GEN_INTR 0x0170 #define AMDVI_MMIO_COMMAND_HEAD 0x2000 #define AMDVI_MMIO_COMMAND_TAIL 0x2008 #define AMDVI_MMIO_EVENT_HEAD 0x2010 @@ -107,6 +108,7 @@ #define AMDVI_MMIO_CONTROL_CMDBUFLEN (1ULL << 12) #define AMDVI_MMIO_CONTROL_GAEN (1ULL << 17) #define AMDVI_MMIO_CONTROL_XTEN (1ULL << 50) +#define AMDVI_MMIO_CONTROL_INTCAPXTEN (1ULL << 51) /* MMIO status register bits */ #define AMDVI_MMIO_STATUS_CMDBUF_RUN (1 << 4) @@ -421,6 +423,7 @@ struct AMDVIState { bool ga_enabled; bool xtsup; /* xtsup=on command line */ bool xten; /* Enable x2apic */ + bool intcapxten; /* Enable IOMMU x2apic interrupt generation */ /* DMA address translation */ bool dma_remap; diff --git a/hw/i386/trace-events b/hw/i386/trace-events index b704f4f90c3d..fe7aea4507ae 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -114,6 +114,7 @@ amdvi_ir_intctl(uint8_t val) "int_ctl 0x%"PRIx8 amdvi_ir_target_abort(const char *str) "%s" amdvi_ir_delivery_mode(const char *str) "%s" amdvi_ir_irte_ga_val(uint64_t hi, uint64_t lo) "hi 0x%"PRIx64" lo 0x%"PRIx64 +amdvi_generate_msi_interrupt(const char *str) "Mode: %s" # vmport.c vmport_register(unsigned char command, void *func, void *opaque) "command: 0x%02x func: %p opaque: %p" -- 2.34.1
