KVM: x86: Clear apic tsc-deadline after deadline
[sfrench/cifs-2.6.git] / virt / kvm / irqchip.c
index b43c275775cd5a1d9e5bbc7f842ceaa81f2a0c69..7f256f31df102e36da59a8ebed636f1c9615cb00 100644 (file)
 #include <trace/events/kvm.h>
 #include "irq.h"
 
-bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin)
-{
-       struct kvm_irq_ack_notifier *kian;
-       int gsi, idx;
-
-       idx = srcu_read_lock(&kvm->irq_srcu);
-       gsi = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu)->chip[irqchip][pin];
-       if (gsi != -1)
-               hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list,
-                                        link)
-                       if (kian->gsi == gsi) {
-                               srcu_read_unlock(&kvm->irq_srcu, idx);
-                               return true;
-                       }
-
-       srcu_read_unlock(&kvm->irq_srcu, idx);
-
-       return false;
-}
-EXPORT_SYMBOL_GPL(kvm_irq_has_notifier);
+struct kvm_irq_routing_table {
+       int chip[KVM_NR_IRQCHIPS][KVM_IRQCHIP_NUM_PINS];
+       struct kvm_kernel_irq_routing_entry *rt_entries;
+       u32 nr_rt_entries;
+       /*
+        * Array indexed by gsi. Each entry contains list of irq chips
+        * the gsi is connected to.
+        */
+       struct hlist_head map[0];
+};
 
-void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin)
+int kvm_irq_map_gsi(struct kvm *kvm,
+                   struct kvm_kernel_irq_routing_entry *entries, int gsi)
 {
-       struct kvm_irq_ack_notifier *kian;
-       int gsi, idx;
-
-       trace_kvm_ack_irq(irqchip, pin);
+       struct kvm_irq_routing_table *irq_rt;
+       struct kvm_kernel_irq_routing_entry *e;
+       int n = 0;
+
+       irq_rt = srcu_dereference_check(kvm->irq_routing, &kvm->irq_srcu,
+                                       lockdep_is_held(&kvm->irq_lock));
+       if (gsi < irq_rt->nr_rt_entries) {
+               hlist_for_each_entry(e, &irq_rt->map[gsi], link) {
+                       entries[n] = *e;
+                       ++n;
+               }
+       }
 
-       idx = srcu_read_lock(&kvm->irq_srcu);
-       gsi = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu)->chip[irqchip][pin];
-       if (gsi != -1)
-               hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list,
-                                        link)
-                       if (kian->gsi == gsi)
-                               kian->irq_acked(kian);
-       srcu_read_unlock(&kvm->irq_srcu, idx);
+       return n;
 }
 
-void kvm_register_irq_ack_notifier(struct kvm *kvm,
-                                  struct kvm_irq_ack_notifier *kian)
+int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
 {
-       mutex_lock(&kvm->irq_lock);
-       hlist_add_head_rcu(&kian->link, &kvm->irq_ack_notifier_list);
-       mutex_unlock(&kvm->irq_lock);
-#ifdef __KVM_HAVE_IOAPIC
-       kvm_vcpu_request_scan_ioapic(kvm);
-#endif
-}
+       struct kvm_irq_routing_table *irq_rt;
 
-void kvm_unregister_irq_ack_notifier(struct kvm *kvm,
-                                   struct kvm_irq_ack_notifier *kian)
-{
-       mutex_lock(&kvm->irq_lock);
-       hlist_del_init_rcu(&kian->link);
-       mutex_unlock(&kvm->irq_lock);
-       synchronize_srcu(&kvm->irq_srcu);
-#ifdef __KVM_HAVE_IOAPIC
-       kvm_vcpu_request_scan_ioapic(kvm);
-#endif
+       irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
+       return irq_rt->chip[irqchip][pin];
 }
 
 int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
@@ -115,9 +92,8 @@ int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
 int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,
                bool line_status)
 {
-       struct kvm_kernel_irq_routing_entry *e, irq_set[KVM_NR_IRQCHIPS];
-       int ret = -1, i = 0, idx;
-       struct kvm_irq_routing_table *irq_rt;
+       struct kvm_kernel_irq_routing_entry irq_set[KVM_NR_IRQCHIPS];
+       int ret = -1, i, idx;
 
        trace_kvm_set_irq(irq, level, irq_source_id);
 
@@ -126,10 +102,7 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,
         * writes to the unused one.
         */
        idx = srcu_read_lock(&kvm->irq_srcu);
-       irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
-       if (irq < irq_rt->nr_rt_entries)
-               hlist_for_each_entry(e, &irq_rt->map[irq], link)
-                       irq_set[i++] = *e;
+       i = kvm_irq_map_gsi(kvm, irq_set, irq);
        srcu_read_unlock(&kvm->irq_srcu, idx);
 
        while(i--) {
@@ -171,9 +144,11 @@ static int setup_routing_entry(struct kvm_irq_routing_table *rt,
 
        e->gsi = ue->gsi;
        e->type = ue->type;
-       r = kvm_set_routing_entry(rt, e, ue);
+       r = kvm_set_routing_entry(e, ue);
        if (r)
                goto out;
+       if (e->type == KVM_IRQ_ROUTING_IRQCHIP)
+               rt->chip[e->irqchip.irqchip][e->irqchip.pin] = e->gsi;
 
        hlist_add_head(&e->link, &rt->map[e->gsi]);
        r = 0;
@@ -224,7 +199,8 @@ int kvm_set_irq_routing(struct kvm *kvm,
 
        mutex_lock(&kvm->irq_lock);
        old = kvm->irq_routing;
-       kvm_irq_routing_update(kvm, new);
+       rcu_assign_pointer(kvm->irq_routing, new);
+       kvm_irq_routing_update(kvm);
        mutex_unlock(&kvm->irq_lock);
 
        synchronize_srcu_expedited(&kvm->irq_srcu);