Commit 74f4d227 authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'qemu-kvm/uq/master' into staging

* qemu-kvm/uq/master:
  virtio/vhost: Add support for KVM in-kernel MSI injection
  msix: Add msix_nr_vectors_allocated
  kvm: Enable use of kvm_irqchip_in_kernel in hwlib code
  kvm: Introduce kvm_irqchip_add/remove_irqfd
  kvm: Make kvm_irqchip_commit_routes an internal service
  kvm: Publicize kvm_irqchip_release_virq
  kvm: Introduce kvm_irqchip_add_msi_route
  kvm: Rename kvm_irqchip_add_route to kvm_irqchip_add_irq_route
  msix: Introduce vector notifiers
  msix: Invoke msix_handle_mask_update on msix_mask_all
  msix: Factor out msix_get_message
  kvm: update vmxcap for EPT A/D, INVPCID, RDRAND, VMFUNC
  kvm: Enable in-kernel irqchip support by default
  kvm: Add support for direct MSI injections
  kvm: Update kernel headers
  kvm: x86: Wire up MSI support for in-kernel irqchip
  pc: Enable MSI support at APIC level
  kvm: Introduce basic MSI support for in-kernel irqchips
  Introduce MSIMessage structure
  kvm: Refactor KVMState::max_gsi to gsi_count
parents 2eb02f28 7d37d351
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "apic_internal.h"
#include "apic.h"
#include "ioapic.h"
#include "msi.h"
#include "host-utils.h"
#include "trace.h"
#include "pc.h"
@@ -862,6 +863,8 @@ static void apic_init(APICCommonState *s)

    s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s);
    local_apics[s->idx] = s;

    msi_supported = true;
}

static void apic_class_init(ObjectClass *klass, void *data)
+32 −2
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
 * See the COPYING file in the top-level directory.
 */
#include "hw/apic_internal.h"
#include "hw/msi.h"
#include "kvm.h"

static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic,
@@ -145,10 +146,39 @@ static void kvm_apic_external_nmi(APICCommonState *s)
    run_on_cpu(s->cpu_env, do_inject_external_nmi, s);
}

static uint64_t kvm_apic_mem_read(void *opaque, target_phys_addr_t addr,
                                  unsigned size)
{
    return ~(uint64_t)0;
}

static void kvm_apic_mem_write(void *opaque, target_phys_addr_t 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));
    }
}

static const MemoryRegionOps kvm_apic_io_ops = {
    .read = kvm_apic_mem_read,
    .write = kvm_apic_mem_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
};

static void kvm_apic_init(APICCommonState *s)
{
    memory_region_init_reservation(&s->io_memory, "kvm-apic-msi",
    memory_region_init_io(&s->io_memory, &kvm_apic_io_ops, s, "kvm-apic-msi",
                          MSI_SPACE_SIZE);

    if (kvm_has_gsi_routing()) {
        msi_supported = true;
    }
}

static void kvm_apic_class_init(ObjectClass *klass, void *data)
+5 −0
Original line number Diff line number Diff line
@@ -24,6 +24,11 @@
#include "qemu-common.h"
#include "pci.h"

struct MSIMessage {
    uint64_t address;
    uint32_t data;
};

extern bool msi_supported;

bool msi_enabled(const PCIDevice *dev);
+115 −6
Original line number Diff line number Diff line
@@ -35,6 +35,15 @@
#define MSIX_PAGE_PENDING (MSIX_PAGE_SIZE / 2)
#define MSIX_MAX_ENTRIES 32

static MSIMessage msix_get_message(PCIDevice *dev, unsigned vector)
{
    uint8_t *table_entry = dev->msix_table_page + vector * PCI_MSIX_ENTRY_SIZE;
    MSIMessage msg;

    msg.address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
    msg.data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
    return msg;
}

/* Add MSI-X capability to the config space for the device. */
/* Given a bar and its size, add MSI-X table on top of it
@@ -130,13 +139,34 @@ static bool msix_is_masked(PCIDevice *dev, int vector)
    return msix_vector_masked(dev, vector, dev->msix_function_masked);
}

static void msix_fire_vector_notifier(PCIDevice *dev,
                                      unsigned int vector, bool is_masked)
{
    MSIMessage msg;
    int ret;

    if (!dev->msix_vector_use_notifier) {
        return;
    }
    if (is_masked) {
        dev->msix_vector_release_notifier(dev, vector);
    } else {
        msg = msix_get_message(dev, vector);
        ret = dev->msix_vector_use_notifier(dev, vector, msg);
        assert(ret >= 0);
    }
}

static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked)
{
    bool is_masked = msix_is_masked(dev, vector);

    if (is_masked == was_masked) {
        return;
    }

    msix_fire_vector_notifier(dev, vector, is_masked);

    if (!is_masked && msix_is_pending(dev, vector)) {
        msix_clr_pending(dev, vector);
        msix_notify(dev, vector);
@@ -222,10 +252,14 @@ static void msix_mmio_setup(PCIDevice *d, MemoryRegion *bar)
static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
{
    int vector;

    for (vector = 0; vector < nentries; ++vector) {
        unsigned offset =
            vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
        bool was_masked = msix_is_masked(dev, vector);

        dev->msix_table_page[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
        msix_handle_mask_update(dev, vector, was_masked);
    }
}

@@ -317,6 +351,7 @@ void msix_save(PCIDevice *dev, QEMUFile *f)
void msix_load(PCIDevice *dev, QEMUFile *f)
{
    unsigned n = dev->msix_entries_nr;
    unsigned int vector;

    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
        return;
@@ -326,6 +361,10 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
    qemu_get_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
    qemu_get_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
    msix_update_function_masked(dev);

    for (vector = 0; vector < n; vector++) {
        msix_handle_mask_update(dev, vector, true);
    }
}

/* Does device support MSI-X? */
@@ -352,9 +391,7 @@ uint32_t msix_bar_size(PCIDevice *dev)
/* Send an MSI-X message */
void msix_notify(PCIDevice *dev, unsigned vector)
{
    uint8_t *table_entry = dev->msix_table_page + vector * PCI_MSIX_ENTRY_SIZE;
    uint64_t address;
    uint32_t data;
    MSIMessage msg;

    if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
        return;
@@ -363,9 +400,9 @@ void msix_notify(PCIDevice *dev, unsigned vector)
        return;
    }

    address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
    data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
    stl_le_phys(address, data);
    msg = msix_get_message(dev, vector);

    stl_le_phys(msg.address, msg.data);
}

void msix_reset(PCIDevice *dev)
@@ -414,3 +451,75 @@ void msix_unuse_all_vectors(PCIDevice *dev)
        return;
    msix_free_irq_entries(dev);
}

unsigned int msix_nr_vectors_allocated(const PCIDevice *dev)
{
    return dev->msix_entries_nr;
}

static int msix_set_notifier_for_vector(PCIDevice *dev, unsigned int vector)
{
    MSIMessage msg;

    if (msix_is_masked(dev, vector)) {
        return 0;
    }
    msg = msix_get_message(dev, vector);
    return dev->msix_vector_use_notifier(dev, vector, msg);
}

static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int vector)
{
    if (msix_is_masked(dev, vector)) {
        return;
    }
    dev->msix_vector_release_notifier(dev, vector);
}

int msix_set_vector_notifiers(PCIDevice *dev,
                              MSIVectorUseNotifier use_notifier,
                              MSIVectorReleaseNotifier release_notifier)
{
    int vector, ret;

    assert(use_notifier && release_notifier);

    dev->msix_vector_use_notifier = use_notifier;
    dev->msix_vector_release_notifier = release_notifier;

    if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
        (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) {
        for (vector = 0; vector < dev->msix_entries_nr; vector++) {
            ret = msix_set_notifier_for_vector(dev, vector);
            if (ret < 0) {
                goto undo;
            }
        }
    }
    return 0;

undo:
    while (--vector >= 0) {
        msix_unset_notifier_for_vector(dev, vector);
    }
    dev->msix_vector_use_notifier = NULL;
    dev->msix_vector_release_notifier = NULL;
    return ret;
}

void msix_unset_vector_notifiers(PCIDevice *dev)
{
    int vector;

    assert(dev->msix_vector_use_notifier &&
           dev->msix_vector_release_notifier);

    if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
        (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) {
        for (vector = 0; vector < dev->msix_entries_nr; vector++) {
            msix_unset_notifier_for_vector(dev, vector);
        }
    }
    dev->msix_vector_use_notifier = NULL;
    dev->msix_vector_release_notifier = NULL;
}
+6 −0
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@ void msix_write_config(PCIDevice *pci_dev, uint32_t address,

int msix_uninit(PCIDevice *d, MemoryRegion *bar);

unsigned int msix_nr_vectors_allocated(const PCIDevice *dev);

void msix_save(PCIDevice *dev, QEMUFile *f);
void msix_load(PCIDevice *dev, QEMUFile *f);

@@ -29,4 +31,8 @@ void msix_notify(PCIDevice *dev, unsigned vector);

void msix_reset(PCIDevice *dev);

int msix_set_vector_notifiers(PCIDevice *dev,
                              MSIVectorUseNotifier use_notifier,
                              MSIVectorReleaseNotifier release_notifier);
void msix_unset_vector_notifiers(PCIDevice *dev);
#endif
Loading