* [PATCHv2] qemu-kvm: enable msi with irqchip
@ 2009-07-05 13:04 Michael S. Tsirkin
2009-07-05 15:13 ` Avi Kivity
0 siblings, 1 reply; 2+ messages in thread
From: Michael S. Tsirkin @ 2009-07-05 13:04 UTC (permalink / raw)
To: avi, kvm
Support msi-x with irqchip in kernel: allocate entries
when they are used, and update when they are unmasked.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
Avi, please consider merging this in qemu-kvm.git.
Changes since v1:
add braces as per CODING_STYLE
hw/apic.c | 4 +--
hw/msix.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
hw/pci.h | 3 ++
libkvm-all.h | 14 ++++++++
qemu-kvm.c | 54 +++++++++++++++++++++++++++++++++
5 files changed, 163 insertions(+), 6 deletions(-)
diff --git a/hw/apic.c b/hw/apic.c
index 778a853..cdb5972 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -1088,9 +1088,7 @@ int apic_init(CPUState *env)
s->cpu_env = env;
apic_reset(s);
- if (!kvm_enabled() || !qemu_kvm_irqchip_in_kernel()) {
- msix_supported = 1;
- }
+ msix_supported = 1;
/* XXX: mapping more APICs at the same memory location */
if (apic_io_memory == 0) {
diff --git a/hw/msix.c b/hw/msix.c
index 4224d8f..743d852 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -14,6 +14,7 @@
#include "hw.h"
#include "msix.h"
#include "pci.h"
+#include "qemu-kvm.h"
/* Declaration from linux/pci_regs.h */
#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
@@ -109,6 +110,18 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
static void msix_free_irq_entries(PCIDevice *dev)
{
int vector;
+ if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) {
+ int changed = 0;
+ for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
+ if (dev->msix_entry_used[vector]) {
+ kvm_del_routing_entry(kvm_context, &dev->msix_irq_entries[vector]);
+ changed = 1;
+ }
+ }
+ if (changed) {
+ kvm_commit_irq_routes(kvm_context);
+ }
+ }
for (vector = 0; vector < dev->msix_entries_nr; ++vector)
dev->msix_entry_used[vector] = 0;
@@ -181,7 +194,36 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
PCIDevice *dev = opaque;
unsigned int offset = addr & (MSIX_PAGE_SIZE - 1);
int vector = offset / MSIX_ENTRY_SIZE;
+ int was_masked = msix_is_masked(dev, vector);
memcpy(dev->msix_table_page + offset, &val, 4);
+ if (kvm_enabled() && qemu_kvm_irqchip_in_kernel() &&
+ was_masked && !msix_is_masked(dev, vector) &&
+ dev->msix_entry_used[vector]) {
+ struct kvm_irq_routing_entry e, *entry;
+ uint8_t *table;
+ table = dev->msix_table_page + vector * MSIX_ENTRY_SIZE;
+ entry = dev->msix_irq_entries + vector;
+ e.gsi = entry->gsi;
+ e.type = entry->type;
+ e.flags = entry->flags;
+ e.u.msi.address_lo = pci_get_long(table + MSIX_MSG_ADDR);
+ e.u.msi.address_hi = pci_get_long(table + MSIX_MSG_UPPER_ADDR);
+ e.u.msi.data = pci_get_long(table + MSIX_MSG_DATA);
+ if (memcmp(&entry->u.msi, &e.u.msi, sizeof entry->u.msi)) {
+ int r;
+ r = kvm_update_routing_entry(kvm_context, entry, &e);
+ if (r) {
+ perror("msix_mmio_writel: kvm_update_routing_entry failed: ");
+ exit(1);
+ }
+ memcpy(&entry->u.msi, &e.u.msi, sizeof entry->u.msi);
+ r = kvm_commit_irq_routes(kvm_context);
+ if (r) {
+ perror("msix_mmio_writel: kvm_commit_irq_routes failed: ");
+ exit(1);
+ }
+ }
+ }
if (!msix_is_masked(dev, vector) && msix_is_pending(dev, vector)) {
msix_clr_pending(dev, vector);
msix_notify(dev, vector);
@@ -234,6 +276,10 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
if (nentries > MSIX_MAX_ENTRIES)
return -EINVAL;
+ if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) {
+ dev->msix_irq_entries = qemu_malloc(nentries *
+ sizeof *dev->msix_irq_entries);
+ }
dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES *
sizeof *dev->msix_entry_used);
@@ -278,6 +324,8 @@ int msix_uninit(PCIDevice *dev)
dev->msix_table_page = NULL;
qemu_free(dev->msix_entry_used);
dev->msix_entry_used = NULL;
+ qemu_free(dev->msix_irq_entries);
+ dev->msix_irq_entries = NULL;
dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
return 0;
}
@@ -340,6 +388,10 @@ void msix_notify(PCIDevice *dev, unsigned vector)
msix_set_pending(dev, vector);
return;
}
+ if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) {
+ kvm_set_irq(dev->msix_irq_entries[vector].gsi, 1, NULL);
+ return;
+ }
address = pci_get_long(table_entry + MSIX_MSG_UPPER_ADDR);
address = (address << 32) | pci_get_long(table_entry + MSIX_MSG_ADDR);
@@ -369,13 +421,49 @@ int msix_vector_use(PCIDevice *dev, unsigned vector)
{
if (vector >= dev->msix_entries_nr)
return -EINVAL;
- dev->msix_entry_used[vector]++;
+ if (dev->msix_entry_used[vector]++)
+ return 0;
+ if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) {
+ uint8_t *table_entry = dev->msix_table_page + vector * MSIX_ENTRY_SIZE;
+ struct kvm_irq_routing_entry *entry = dev->msix_irq_entries + vector;
+ int r;
+
+ r = kvm_get_irq_route_gsi(kvm_context);
+ if (r < 0) {
+ perror("msix_vector_use: kvm_get_irq_route_gsi failed: ");
+ return r;
+ }
+
+ entry->gsi = r;
+ entry->type = KVM_IRQ_ROUTING_MSI;
+ entry->flags = 0;
+ entry->u.msi.address_lo = pci_get_long(table_entry + MSIX_MSG_ADDR);
+ entry->u.msi.address_hi = pci_get_long(table_entry + MSIX_MSG_UPPER_ADDR);
+ entry->u.msi.data = pci_get_long(table_entry + MSIX_MSG_DATA);
+ r = kvm_add_routing_entry(kvm_context, entry);
+ if (r < 0) {
+ perror("msix_vector_use: kvm_add_routing_entry failed: ");
+ return r;
+ }
+
+ r = kvm_commit_irq_routes(kvm_context);
+ if (r < 0) {
+ perror("msix_vector_use: kvm_add_routing_entry failed: ");
+ return r;
+ }
+ }
return 0;
}
/* Mark vector as unused. */
void msix_vector_unuse(PCIDevice *dev, unsigned vector)
{
- if (vector < dev->msix_entries_nr && dev->msix_entry_used[vector])
- --dev->msix_entry_used[vector];
+ if (vector < dev->msix_entries_nr && dev->msix_entry_used[vector]) {
+ if (--dev->msix_entry_used[vector])
+ return;
+ if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) {
+ kvm_del_routing_entry(kvm_context, &dev->msix_irq_entries[vector]);
+ kvm_commit_irq_routes(kvm_context);
+ }
+ }
}
diff --git a/hw/pci.h b/hw/pci.h
index 7ae9c93..66235e4 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -5,6 +5,8 @@
#include "qdev.h"
+struct kvm_irq_routing_entry;
+
/* PCI includes legacy ISA access. */
#include "isa.h"
@@ -232,6 +234,7 @@ struct PCIDevice {
unsigned *msix_entry_used;
/* Region including the MSI-X table */
uint32_t msix_bar_size;
+ struct kvm_irq_routing_entry *msix_irq_entries;
/* Device capability configuration space */
struct {
diff --git a/libkvm-all.h b/libkvm-all.h
index ecd3065..4a98bcb 100644
--- a/libkvm-all.h
+++ b/libkvm-all.h
@@ -898,6 +898,20 @@ int kvm_del_routing_entry(kvm_context_t kvm,
struct kvm_irq_routing_entry* entry);
/*!
+ * \brief Updates a routing in the temporary irq routing table
+ *
+ * Update a routing in the temporary irq routing table
+ * with a new value. entry type and GSI can not be changed.
+ * Nothing is committed to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_update_routing_entry(kvm_context_t kvm,
+ struct kvm_irq_routing_entry* entry,
+ struct kvm_irq_routing_entry* newentry
+);
+
+/*!
* \brief Commit the temporary irq routing table
*
* Commit the temporary irq routing table to the running VM.
diff --git a/qemu-kvm.c b/qemu-kvm.c
index c5cd038..9086ace 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -1448,6 +1448,60 @@ int kvm_del_routing_entry(kvm_context_t kvm,
#endif
}
+int kvm_update_routing_entry(kvm_context_t kvm,
+ struct kvm_irq_routing_entry* entry,
+ struct kvm_irq_routing_entry* newentry)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+ struct kvm_irq_routing_entry *e;
+ int i, gsi, found = 0;
+
+ if (entry->gsi != newentry->gsi ||
+ entry->type != newentry->type) {
+ return -EINVAL;
+ }
+ gsi = entry->gsi;
+
+ for (i = 0; i < kvm->irq_routes->nr; ++i) {
+ e = &kvm->irq_routes->entries[i];
+ if (e->type != entry->type || e->gsi != gsi) {
+ continue;
+ }
+ switch (e->type)
+ {
+ case KVM_IRQ_ROUTING_IRQCHIP: {
+ if (e->u.irqchip.irqchip ==
+ entry->u.irqchip.irqchip
+ && e->u.irqchip.pin ==
+ entry->u.irqchip.pin) {
+ found = 1;
+ }
+ break;
+ }
+ case KVM_IRQ_ROUTING_MSI: {
+ if (e->u.msi.address_lo ==
+ entry->u.msi.address_lo
+ && e->u.msi.address_hi ==
+ entry->u.msi.address_hi
+ && e->u.msi.data == entry->u.msi.data) {
+ found = 1;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (found) {
+ memcpy(e, entry, sizeof *e);
+ return 0;
+ }
+ }
+ return -ESRCH;
+#else
+ return -ENOSYS;
+#endif
+}
+
int kvm_del_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin)
{
#ifdef KVM_CAP_IRQ_ROUTING
--
1.6.2.2
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCHv2] qemu-kvm: enable msi with irqchip
2009-07-05 13:04 [PATCHv2] qemu-kvm: enable msi with irqchip Michael S. Tsirkin
@ 2009-07-05 15:13 ` Avi Kivity
0 siblings, 0 replies; 2+ messages in thread
From: Avi Kivity @ 2009-07-05 15:13 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: kvm
On 07/05/2009 04:04 PM, Michael S. Tsirkin wrote:
> Support msi-x with irqchip in kernel: allocate entries
> when they are used, and update when they are unmasked.
>
>
> /* Declaration from linux/pci_regs.h */
> #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
> @@ -109,6 +110,18 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
> static void msix_free_irq_entries(PCIDevice *dev)
> {
> int vector;
> + if (kvm_enabled()&& qemu_kvm_irqchip_in_kernel()) {
> + int changed = 0;
> + for (vector = 0; vector< dev->msix_entries_nr; ++vector) {
> + if (dev->msix_entry_used[vector]) {
> + kvm_del_routing_entry(kvm_context,&dev->msix_irq_entries[vector]);
> + changed = 1;
> + }
> + }
> + if (changed) {
> + kvm_commit_irq_routes(kvm_context);
> + }
> + }
>
Please move this into a helper. Ditto all the code hunks in msix functions.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2009-07-05 15:10 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-07-05 13:04 [PATCHv2] qemu-kvm: enable msi with irqchip Michael S. Tsirkin
2009-07-05 15:13 ` Avi Kivity
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).