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:
Singh, Brijesh 2018-10-01 19:44:37 +00:00 committed by Michael S. Tsirkin
parent 53244386b0
commit 577c470f43
3 changed files with 123 additions and 2 deletions

View file

@ -26,6 +26,7 @@
#include "amd_iommu.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "hw/i386/apic_internal.h"
#include "trace.h"
/* used AMD-Vi MMIO registers */
@ -1031,6 +1032,99 @@ static IOMMUTLBEntry amdvi_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
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)
{
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_iommu | 00000000-ffffffff | 1 |
* | amdvi_iommu_ir | fee00000-feefffff | 64 |
* |-----------------+-------------------+----------|
*/
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),
"amdvi_root", UINT64_MAX);
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(&amdvi_dev_as->iommu),
1);
@ -1196,6 +1298,9 @@ static void amdvi_realize(DeviceState *dev, Error **err)
return;
}
/* Pseudo address space under root PCI bus. */
pcms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVID);
/* set up MMIO */
memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio",
AMDVI_MMIO_SIZE);
@ -1229,6 +1334,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;
/* Supported by the pc-q35-* machine types */
dc->user_creatable = true;
}