apic: add send_msi() to APICCommonClass

The MMIO based interface to APIC doesn't work well with MSIs that have
upper address bits set (remapped x2APIC MSIs).  A specialized interface
is a quick and dirty way to avoid the shortcoming.

Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
This commit is contained in:
Radim Krčmář 2016-10-10 17:28:43 +02:00 committed by Eduardo Habkost
parent 2f114315dc
commit 267ee35715
4 changed files with 29 additions and 8 deletions

View File

@ -169,6 +169,17 @@ static void kvm_apic_external_nmi(APICCommonState *s)
run_on_cpu(CPU(s->cpu), do_inject_external_nmi, s);
}
static void kvm_send_msi(MSIMessage *msg)
{
int ret;
ret = kvm_irqchip_send_msi(kvm_state, *msg);
if (ret < 0) {
fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n",
strerror(-ret));
}
}
static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr,
unsigned size)
{
@ -179,13 +190,8 @@ static void kvm_apic_mem_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
MSIMessage msg = { .address = addr, .data = data };
int ret;
ret = kvm_irqchip_send_msi(kvm_state, msg);
if (ret < 0) {
fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n",
strerror(-ret));
}
kvm_send_msi(&msg);
}
static const MemoryRegionOps kvm_apic_io_ops = {
@ -232,6 +238,7 @@ static void kvm_apic_class_init(ObjectClass *klass, void *data)
k->enable_tpr_reporting = kvm_apic_enable_tpr_reporting;
k->vapic_base_update = kvm_apic_vapic_base_update;
k->external_nmi = kvm_apic_external_nmi;
k->send_msi = kvm_send_msi;
}
static const TypeInfo kvm_apic_info = {

View File

@ -68,6 +68,11 @@ static void xen_apic_external_nmi(APICCommonState *s)
{
}
static void xen_send_msi(MSIMessage *msi)
{
xen_hvm_inject_msi(msi->address, msi->data);
}
static void xen_apic_class_init(ObjectClass *klass, void *data)
{
APICCommonClass *k = APIC_COMMON_CLASS(klass);
@ -78,6 +83,7 @@ static void xen_apic_class_init(ObjectClass *klass, void *data)
k->get_tpr = xen_apic_get_tpr;
k->vapic_base_update = xen_apic_vapic_base_update;
k->external_nmi = xen_apic_external_nmi;
k->send_msi = xen_send_msi;
}
static const TypeInfo xen_apic_info = {

View File

@ -740,8 +740,10 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr)
return val;
}
static void apic_send_msi(hwaddr addr, uint32_t data)
static void apic_send_msi(MSIMessage *msi)
{
uint64_t addr = msi->address;
uint32_t data = msi->data;
uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
@ -762,7 +764,8 @@ static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val)
* APIC is connected directly to the CPU.
* Mapping them on the global bus happens to work because
* MSI registers are reserved in APIC MMIO and vice versa. */
apic_send_msi(addr, val);
MSIMessage msi = { .address = addr, .data = val };
apic_send_msi(&msi);
return;
}
@ -913,6 +916,7 @@ static void apic_class_init(ObjectClass *klass, void *data)
k->external_nmi = apic_external_nmi;
k->pre_save = apic_pre_save;
k->post_load = apic_post_load;
k->send_msi = apic_send_msi;
}
static const TypeInfo apic_info = {

View File

@ -146,6 +146,10 @@ typedef struct APICCommonClass
void (*pre_save)(APICCommonState *s);
void (*post_load)(APICCommonState *s);
void (*reset)(APICCommonState *s);
/* send_msi emulates an APIC bus and its proper place would be in a new
* device, but it's convenient to have it here for now.
*/
void (*send_msi)(MSIMessage *msi);
} APICCommonClass;
struct APICCommonState {