#include "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/util.h"
#include <linux/types.h>
#include <linux/rbtree.h>
#include <linux/list.h>
+#include <linux/kvm.h>
+#include <sys/ioctl.h>
#include <stddef.h>
#include <stdlib.h>
+#define IRQ_MAX_GSI 64
+#define IRQCHIP_MASTER 0
+#define IRQCHIP_SLAVE 1
+#define IRQCHIP_IOAPIC 2
+
static u8 next_line = 3;
static u8 next_dev = 1;
static struct rb_root pci_tree = RB_ROOT;
+/* First 24 GSIs are routed between IRQCHIPs and IOAPICs */
+static u32 gsi = 24;
+
+struct kvm_irq_routing *irq_routing;
+
+static int irq__add_routing(u32 gsi, u32 type, u32 irqchip, u32 pin)
+{
+ if (gsi >= IRQ_MAX_GSI)
+ return -ENOSPC;
+
+ irq_routing->entries[irq_routing->nr++] =
+ (struct kvm_irq_routing_entry) {
+ .gsi = gsi,
+ .type = type,
+ .u.irqchip.irqchip = irqchip,
+ .u.irqchip.pin = pin,
+ };
+
+ return 0;
+}
+
static struct pci_dev *search(struct rb_root *root, u32 id)
{
struct rb_node *node = root->rb_node;
return -1;
}
+void irq__init(struct kvm *kvm)
+{
+ int i, r;
+
+ irq_routing = malloc(sizeof(struct kvm_irq_routing) +
+ IRQ_MAX_GSI * sizeof(struct kvm_irq_routing_entry));
+ if (irq_routing == NULL)
+ die("Failed allocating space for GSI table");
+
+ /* Hook first 8 GSIs to master IRQCHIP */
+ for (i = 0; i < 8; i++)
+ irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_MASTER, i);
+
+ /* Hook next 8 GSIs to slave IRQCHIP */
+ for (i = 8; i < 16; i++)
+ irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_SLAVE, 8-i);
+
+ /* Last but not least, IOAPIC */
+ for (i = 0; i < 24; i++) {
+ if (i == 0)
+ irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_IOAPIC, 2);
+ else
+ irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_IOAPIC, i);
+ }
+
+ r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing);
+ if (r)
+ die("Failed setting GSI routes");
+}
+
+int irq__add_msix_route(struct kvm *kvm, u32 low, u32 high, u32 data)
+{
+ int r;
+
+ irq_routing->entries[irq_routing->nr++] =
+ (struct kvm_irq_routing_entry) {
+ .gsi = gsi,
+ .type = KVM_IRQ_ROUTING_MSI,
+ .u.msi.address_lo = low,
+ .u.msi.address_hi = high,
+ .u.msi.data = data,
+ };
+
+ r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing);
+ if (r)
+ return r;
+
+ return gsi++;
+}
+
struct rb_node *irq__get_pci_tree(void)
{
return rb_first(&pci_tree);