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 "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;
|
||||
}
|
||||
|
@ -206,8 +206,18 @@
|
||||
|
||||
#define AMDVI_COMMAND_SIZE 16
|
||||
|
||||
#define AMDVI_INT_ADDR_FIRST 0xfee00000
|
||||
#define AMDVI_INT_ADDR_LAST 0xfeefffff
|
||||
#define AMDVI_INT_ADDR_FIRST 0xfee00000
|
||||
#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 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_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_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
|
||||
vmport_register(unsigned char command, void *func, void *opaque) "command: 0x%02x func: %p opaque: %p"
|
||||
|
Loading…
x
Reference in New Issue
Block a user