mirror of https://github.com/xemu-project/xemu.git
x86_iommu/amd: Prepare for interrupt remap support
Register the interrupt remapping callback and read/write ops for the amd-iommu-ir memory region. amd-iommu-ir is set to higher priority to ensure that this region won't be masked out by other memory regions. Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> Cc: Peter Xu <peterx@redhat.com> Cc: "Michael S. Tsirkin" <mst@redhat.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Richard Henderson <rth@twiddle.net> Cc: Eduardo Habkost <ehabkost@redhat.com> Cc: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> Cc: Tom Lendacky <Thomas.Lendacky@amd.com> Cc: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> Reviewed-by: Peter Xu <peterx@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
53244386b0
commit
577c470f43
|
@ -26,6 +26,7 @@
|
||||||
#include "amd_iommu.h"
|
#include "amd_iommu.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
#include "hw/i386/apic_internal.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
/* used AMD-Vi MMIO registers */
|
/* used AMD-Vi MMIO registers */
|
||||||
|
@ -1031,6 +1032,99 @@ static IOMMUTLBEntry amdvi_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Interrupt remapping for MSI/MSI-X entry */
|
||||||
|
static int amdvi_int_remap_msi(AMDVIState *iommu,
|
||||||
|
MSIMessage *origin,
|
||||||
|
MSIMessage *translated,
|
||||||
|
uint16_t sid)
|
||||||
|
{
|
||||||
|
assert(origin && translated);
|
||||||
|
|
||||||
|
trace_amdvi_ir_remap_msi_req(origin->address, origin->data, sid);
|
||||||
|
|
||||||
|
if (!iommu || !X86_IOMMU_DEVICE(iommu)->intr_supported) {
|
||||||
|
memcpy(translated, origin, sizeof(*origin));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (origin->address & AMDVI_MSI_ADDR_HI_MASK) {
|
||||||
|
trace_amdvi_err("MSI address high 32 bits non-zero when "
|
||||||
|
"Interrupt Remapping enabled.");
|
||||||
|
return -AMDVI_IR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((origin->address & AMDVI_MSI_ADDR_LO_MASK) != APIC_DEFAULT_ADDRESS) {
|
||||||
|
trace_amdvi_err("MSI is not from IOAPIC.");
|
||||||
|
return -AMDVI_IR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
trace_amdvi_ir_remap_msi(origin->address, origin->data,
|
||||||
|
translated->address, translated->data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amdvi_int_remap(X86IOMMUState *iommu,
|
||||||
|
MSIMessage *origin,
|
||||||
|
MSIMessage *translated,
|
||||||
|
uint16_t sid)
|
||||||
|
{
|
||||||
|
return amdvi_int_remap_msi(AMD_IOMMU_DEVICE(iommu), origin,
|
||||||
|
translated, sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemTxResult amdvi_mem_ir_write(void *opaque, hwaddr addr,
|
||||||
|
uint64_t value, unsigned size,
|
||||||
|
MemTxAttrs attrs)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
MSIMessage from = { 0, 0 }, to = { 0, 0 };
|
||||||
|
uint16_t sid = AMDVI_IOAPIC_SB_DEVID;
|
||||||
|
|
||||||
|
from.address = (uint64_t) addr + AMDVI_INT_ADDR_FIRST;
|
||||||
|
from.data = (uint32_t) value;
|
||||||
|
|
||||||
|
trace_amdvi_mem_ir_write_req(addr, value, size);
|
||||||
|
|
||||||
|
if (!attrs.unspecified) {
|
||||||
|
/* We have explicit Source ID */
|
||||||
|
sid = attrs.requester_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = amdvi_int_remap_msi(opaque, &from, &to, sid);
|
||||||
|
if (ret < 0) {
|
||||||
|
/* TODO: log the event using IOMMU log event interface */
|
||||||
|
error_report_once("failed to remap interrupt from devid 0x%x", sid);
|
||||||
|
return MEMTX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
apic_get_class()->send_msi(&to);
|
||||||
|
|
||||||
|
trace_amdvi_mem_ir_write(to.address, to.data);
|
||||||
|
return MEMTX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemTxResult amdvi_mem_ir_read(void *opaque, hwaddr addr,
|
||||||
|
uint64_t *data, unsigned size,
|
||||||
|
MemTxAttrs attrs)
|
||||||
|
{
|
||||||
|
return MEMTX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps amdvi_ir_ops = {
|
||||||
|
.read_with_attrs = amdvi_mem_ir_read,
|
||||||
|
.write_with_attrs = amdvi_mem_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)
|
static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
||||||
{
|
{
|
||||||
char name[128];
|
char name[128];
|
||||||
|
@ -1066,6 +1160,7 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
||||||
* |-----------------+-------------------+----------+
|
* |-----------------+-------------------+----------+
|
||||||
* | amdvi_root | 00000000-ffffffff | 0 |
|
* | amdvi_root | 00000000-ffffffff | 0 |
|
||||||
* | amdvi_iommu | 00000000-ffffffff | 1 |
|
* | amdvi_iommu | 00000000-ffffffff | 1 |
|
||||||
|
* | amdvi_iommu_ir | fee00000-feefffff | 64 |
|
||||||
* |-----------------+-------------------+----------|
|
* |-----------------+-------------------+----------|
|
||||||
*/
|
*/
|
||||||
memory_region_init_iommu(&amdvi_dev_as->iommu,
|
memory_region_init_iommu(&amdvi_dev_as->iommu,
|
||||||
|
@ -1076,6 +1171,13 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
||||||
memory_region_init(&amdvi_dev_as->root, OBJECT(s),
|
memory_region_init(&amdvi_dev_as->root, OBJECT(s),
|
||||||
"amdvi_root", UINT64_MAX);
|
"amdvi_root", UINT64_MAX);
|
||||||
address_space_init(&amdvi_dev_as->as, &amdvi_dev_as->root, name);
|
address_space_init(&amdvi_dev_as->as, &amdvi_dev_as->root, name);
|
||||||
|
memory_region_init_io(&amdvi_dev_as->iommu_ir, OBJECT(s),
|
||||||
|
&amdvi_ir_ops, s, "amd_iommu_ir",
|
||||||
|
AMDVI_INT_ADDR_SIZE);
|
||||||
|
memory_region_add_subregion_overlap(&amdvi_dev_as->root,
|
||||||
|
AMDVI_INT_ADDR_FIRST,
|
||||||
|
&amdvi_dev_as->iommu_ir,
|
||||||
|
64);
|
||||||
memory_region_add_subregion_overlap(&amdvi_dev_as->root, 0,
|
memory_region_add_subregion_overlap(&amdvi_dev_as->root, 0,
|
||||||
MEMORY_REGION(&amdvi_dev_as->iommu),
|
MEMORY_REGION(&amdvi_dev_as->iommu),
|
||||||
1);
|
1);
|
||||||
|
@ -1196,6 +1298,9 @@ static void amdvi_realize(DeviceState *dev, Error **err)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Pseudo address space under root PCI bus. */
|
||||||
|
pcms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVID);
|
||||||
|
|
||||||
/* set up MMIO */
|
/* set up MMIO */
|
||||||
memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio",
|
memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio",
|
||||||
AMDVI_MMIO_SIZE);
|
AMDVI_MMIO_SIZE);
|
||||||
|
@ -1229,6 +1334,7 @@ static void amdvi_class_init(ObjectClass *klass, void* data)
|
||||||
dc->vmsd = &vmstate_amdvi;
|
dc->vmsd = &vmstate_amdvi;
|
||||||
dc->hotpluggable = false;
|
dc->hotpluggable = false;
|
||||||
dc_class->realize = amdvi_realize;
|
dc_class->realize = amdvi_realize;
|
||||||
|
dc_class->int_remap = amdvi_int_remap;
|
||||||
/* Supported by the pc-q35-* machine types */
|
/* Supported by the pc-q35-* machine types */
|
||||||
dc->user_creatable = true;
|
dc->user_creatable = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,8 +206,18 @@
|
||||||
|
|
||||||
#define AMDVI_COMMAND_SIZE 16
|
#define AMDVI_COMMAND_SIZE 16
|
||||||
|
|
||||||
#define AMDVI_INT_ADDR_FIRST 0xfee00000
|
#define AMDVI_INT_ADDR_FIRST 0xfee00000
|
||||||
#define AMDVI_INT_ADDR_LAST 0xfeefffff
|
#define AMDVI_INT_ADDR_LAST 0xfeefffff
|
||||||
|
#define AMDVI_INT_ADDR_SIZE (AMDVI_INT_ADDR_LAST - AMDVI_INT_ADDR_FIRST + 1)
|
||||||
|
#define AMDVI_MSI_ADDR_HI_MASK (0xffffffff00000000ULL)
|
||||||
|
#define AMDVI_MSI_ADDR_LO_MASK (0x00000000ffffffffULL)
|
||||||
|
|
||||||
|
/* SB IOAPIC is always on this device in AMD systems */
|
||||||
|
#define AMDVI_IOAPIC_SB_DEVID PCI_BUILD_BDF(0, PCI_DEVFN(0x14, 0))
|
||||||
|
|
||||||
|
/* Interrupt remapping errors */
|
||||||
|
#define AMDVI_IR_ERR 0x1
|
||||||
|
|
||||||
|
|
||||||
#define TYPE_AMD_IOMMU_DEVICE "amd-iommu"
|
#define TYPE_AMD_IOMMU_DEVICE "amd-iommu"
|
||||||
#define AMD_IOMMU_DEVICE(obj)\
|
#define AMD_IOMMU_DEVICE(obj)\
|
||||||
|
|
|
@ -101,6 +101,11 @@ amdvi_mode_invalid(uint8_t level, uint64_t addr)"error: translation level 0x%"PR
|
||||||
amdvi_page_fault(uint64_t addr) "error: page fault accessing guest physical address 0x%"PRIx64
|
amdvi_page_fault(uint64_t addr) "error: page fault accessing guest physical address 0x%"PRIx64
|
||||||
amdvi_iotlb_hit(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "hit iotlb devid %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64
|
amdvi_iotlb_hit(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "hit iotlb devid %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64
|
||||||
amdvi_translation_result(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "devid: %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64
|
amdvi_translation_result(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "devid: %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64
|
||||||
|
amdvi_mem_ir_write_req(uint64_t addr, uint64_t val, uint32_t size) "addr 0x%"PRIx64" data 0x%"PRIx64" size 0x%"PRIx32
|
||||||
|
amdvi_mem_ir_write(uint64_t addr, uint64_t val) "addr 0x%"PRIx64" data 0x%"PRIx64
|
||||||
|
amdvi_ir_remap_msi_req(uint64_t addr, uint64_t data, uint8_t devid) "addr 0x%"PRIx64" data 0x%"PRIx64" devid 0x%"PRIx8
|
||||||
|
amdvi_ir_remap_msi(uint64_t addr, uint64_t data, uint64_t addr2, uint64_t data2) "(addr 0x%"PRIx64", data 0x%"PRIx64") -> (addr 0x%"PRIx64", data 0x%"PRIx64")"
|
||||||
|
amdvi_err(const char *str) "%s"
|
||||||
|
|
||||||
# hw/i386/vmport.c
|
# hw/i386/vmport.c
|
||||||
vmport_register(unsigned char command, void *func, void *opaque) "command: 0x%02x func: %p opaque: %p"
|
vmport_register(unsigned char command, void *func, void *opaque) "command: 0x%02x func: %p opaque: %p"
|
||||||
|
|
Loading…
Reference in New Issue