This implements a simple way to express the case of IRQ routing where there is one in-kernel PIC and the system interrupts (GSIs) are routed 1-1 to the corresponding pins of the PIC. This is expressed by having kvm->irq_routing == NULL with a skeleton irq routing entry in the new kvm->default_irq_route field.
This provides a convenient way to provide backwards compatibility when adding IRQ routing capability to an existing in-kernel PIC, such as the XICS emulation on powerpc. Signed-off-by: Paul Mackerras <pau...@samba.org> --- include/linux/kvm_host.h | 1 + virt/kvm/eventfd.c | 4 ++++ virt/kvm/irqchip.c | 23 ++++++++++++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 749bdb1..609f587 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -394,6 +394,7 @@ struct kvm { * if configured, irqfds.lock. */ struct kvm_irq_routing_table __rcu *irq_routing; + struct kvm_kernel_irq_routing_entry default_irq_route; struct hlist_head mask_notifier_list; struct hlist_head irq_ack_notifier_list; #endif diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index abe4d60..7010cb3 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c @@ -272,6 +272,10 @@ static void irqfd_update(struct kvm *kvm, struct _irqfd *irqfd, { struct kvm_kernel_irq_routing_entry *e; + if (!irq_rt) { + rcu_assign_pointer(irqfd->irq_entry, NULL); + return; + } if (irqfd->gsi >= irq_rt->nr_rt_entries) { rcu_assign_pointer(irqfd->irq_entry, NULL); return; diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c index 20dc9e4..ebc2941 100644 --- a/virt/kvm/irqchip.c +++ b/virt/kvm/irqchip.c @@ -30,13 +30,24 @@ #include <trace/events/kvm.h> #include "irq.h" +static inline int pin_to_gsi(struct kvm *kvm, unsigned irqchip, unsigned pin) +{ + struct kvm_irq_routing_table *rt; + int gsi = pin; + + rt = rcu_dereference(kvm->irq_routing); + if (rt) + gsi = rt->chip[irqchip][pin]; + return gsi; +} + bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin) { struct kvm_irq_ack_notifier *kian; int gsi; rcu_read_lock(); - gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; + gsi = pin_to_gsi(kvm, irqchip, pin); if (gsi != -1) hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, link) @@ -59,7 +70,7 @@ void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) trace_kvm_ack_irq(irqchip, pin); rcu_read_lock(); - gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; + gsi = pin_to_gsi(kvm, irqchip, pin); if (gsi != -1) hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, link) @@ -126,7 +137,13 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, */ rcu_read_lock(); irq_rt = rcu_dereference(kvm->irq_routing); - if (irq < irq_rt->nr_rt_entries) + if (!irq_rt) { + if (kvm->default_irq_route.set) { + irq_set[i] = kvm->default_irq_route; + irq_set[i].gsi = irq; + irq_set[i++].irqchip.pin = irq; + } + } else if (irq < irq_rt->nr_rt_entries) hlist_for_each_entry(e, &irq_rt->map[irq], link) irq_set[i++] = *e; rcu_read_unlock(); -- 1.8.4.rc3 -- To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html