diff options
author | Paul Mackerras <paulus@samba.org> | 2014-06-30 06:51:11 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-08-05 08:26:20 -0400 |
commit | 9957c86d659a4d5a2bed25ccbd3bfc9c3f25e658 (patch) | |
tree | 27bd3fc644da983d63e34bb1ed54c8dcdab5fe0d /virt/kvm/irqchip.c | |
parent | 8ba918d488caded2c4368b0b922eb905fe3bb101 (diff) |
KVM: Move all accesses to kvm::irq_routing into irqchip.c
Now that struct _irqfd does not keep a reference to storage pointed
to by the irq_routing field of struct kvm, we can move the statement
that updates it out from under the irqfds.lock and put it in
kvm_set_irq_routing() instead. That means we then have to take a
srcu_read_lock on kvm->irq_srcu around the irqfd_update call in
kvm_irqfd_assign(), since holding the kvm->irqfds.lock no longer
ensures that that the routing can't change.
Combined with changing kvm_irq_map_gsi() and kvm_irq_map_chip_pin()
to take a struct kvm * argument instead of the pointer to the routing
table, this allows us to to move all references to kvm->irq_routing
into irqchip.c. That in turn allows us to move the definition of the
kvm_irq_routing_table struct into irqchip.c as well.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Tested-by: Eric Auger <eric.auger@linaro.org>
Tested-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'virt/kvm/irqchip.c')
-rw-r--r-- | virt/kvm/irqchip.c | 39 |
1 files changed, 25 insertions, 14 deletions
diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c index f4648dd94888..04faac50cef5 100644 --- a/virt/kvm/irqchip.c +++ b/virt/kvm/irqchip.c | |||
@@ -31,12 +31,26 @@ | |||
31 | #include <trace/events/kvm.h> | 31 | #include <trace/events/kvm.h> |
32 | #include "irq.h" | 32 | #include "irq.h" |
33 | 33 | ||
34 | int kvm_irq_map_gsi(struct kvm_kernel_irq_routing_entry *entries, | 34 | struct kvm_irq_routing_table { |
35 | struct kvm_irq_routing_table *irq_rt, int gsi) | 35 | int chip[KVM_NR_IRQCHIPS][KVM_IRQCHIP_NUM_PINS]; |
36 | struct kvm_kernel_irq_routing_entry *rt_entries; | ||
37 | u32 nr_rt_entries; | ||
38 | /* | ||
39 | * Array indexed by gsi. Each entry contains list of irq chips | ||
40 | * the gsi is connected to. | ||
41 | */ | ||
42 | struct hlist_head map[0]; | ||
43 | }; | ||
44 | |||
45 | int kvm_irq_map_gsi(struct kvm *kvm, | ||
46 | struct kvm_kernel_irq_routing_entry *entries, int gsi) | ||
36 | { | 47 | { |
48 | struct kvm_irq_routing_table *irq_rt; | ||
37 | struct kvm_kernel_irq_routing_entry *e; | 49 | struct kvm_kernel_irq_routing_entry *e; |
38 | int n = 0; | 50 | int n = 0; |
39 | 51 | ||
52 | irq_rt = srcu_dereference_check(kvm->irq_routing, &kvm->irq_srcu, | ||
53 | lockdep_is_held(&kvm->irq_lock)); | ||
40 | if (gsi < irq_rt->nr_rt_entries) { | 54 | if (gsi < irq_rt->nr_rt_entries) { |
41 | hlist_for_each_entry(e, &irq_rt->map[gsi], link) { | 55 | hlist_for_each_entry(e, &irq_rt->map[gsi], link) { |
42 | entries[n] = *e; | 56 | entries[n] = *e; |
@@ -47,21 +61,21 @@ int kvm_irq_map_gsi(struct kvm_kernel_irq_routing_entry *entries, | |||
47 | return n; | 61 | return n; |
48 | } | 62 | } |
49 | 63 | ||
50 | int kvm_irq_map_chip_pin(struct kvm_irq_routing_table *irq_rt, | 64 | int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin) |
51 | unsigned irqchip, unsigned pin) | ||
52 | { | 65 | { |
66 | struct kvm_irq_routing_table *irq_rt; | ||
67 | |||
68 | irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu); | ||
53 | return irq_rt->chip[irqchip][pin]; | 69 | return irq_rt->chip[irqchip][pin]; |
54 | } | 70 | } |
55 | 71 | ||
56 | bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin) | 72 | bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin) |
57 | { | 73 | { |
58 | struct kvm_irq_routing_table *irq_rt; | ||
59 | struct kvm_irq_ack_notifier *kian; | 74 | struct kvm_irq_ack_notifier *kian; |
60 | int gsi, idx; | 75 | int gsi, idx; |
61 | 76 | ||
62 | idx = srcu_read_lock(&kvm->irq_srcu); | 77 | idx = srcu_read_lock(&kvm->irq_srcu); |
63 | irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu); | 78 | gsi = kvm_irq_map_chip_pin(kvm, irqchip, pin); |
64 | gsi = kvm_irq_map_chip_pin(irq_rt, irqchip, pin); | ||
65 | if (gsi != -1) | 79 | if (gsi != -1) |
66 | hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, | 80 | hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, |
67 | link) | 81 | link) |
@@ -78,15 +92,13 @@ EXPORT_SYMBOL_GPL(kvm_irq_has_notifier); | |||
78 | 92 | ||
79 | void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) | 93 | void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) |
80 | { | 94 | { |
81 | struct kvm_irq_routing_table *irq_rt; | ||
82 | struct kvm_irq_ack_notifier *kian; | 95 | struct kvm_irq_ack_notifier *kian; |
83 | int gsi, idx; | 96 | int gsi, idx; |
84 | 97 | ||
85 | trace_kvm_ack_irq(irqchip, pin); | 98 | trace_kvm_ack_irq(irqchip, pin); |
86 | 99 | ||
87 | idx = srcu_read_lock(&kvm->irq_srcu); | 100 | idx = srcu_read_lock(&kvm->irq_srcu); |
88 | irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu); | 101 | gsi = kvm_irq_map_chip_pin(kvm, irqchip, pin); |
89 | gsi = kvm_irq_map_chip_pin(irq_rt, irqchip, pin); | ||
90 | if (gsi != -1) | 102 | if (gsi != -1) |
91 | hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, | 103 | hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, |
92 | link) | 104 | link) |
@@ -143,7 +155,6 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, | |||
143 | { | 155 | { |
144 | struct kvm_kernel_irq_routing_entry irq_set[KVM_NR_IRQCHIPS]; | 156 | struct kvm_kernel_irq_routing_entry irq_set[KVM_NR_IRQCHIPS]; |
145 | int ret = -1, i, idx; | 157 | int ret = -1, i, idx; |
146 | struct kvm_irq_routing_table *irq_rt; | ||
147 | 158 | ||
148 | trace_kvm_set_irq(irq, level, irq_source_id); | 159 | trace_kvm_set_irq(irq, level, irq_source_id); |
149 | 160 | ||
@@ -152,8 +163,7 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, | |||
152 | * writes to the unused one. | 163 | * writes to the unused one. |
153 | */ | 164 | */ |
154 | idx = srcu_read_lock(&kvm->irq_srcu); | 165 | idx = srcu_read_lock(&kvm->irq_srcu); |
155 | irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu); | 166 | i = kvm_irq_map_gsi(kvm, irq_set, irq); |
156 | i = kvm_irq_map_gsi(irq_set, irq_rt, irq); | ||
157 | srcu_read_unlock(&kvm->irq_srcu, idx); | 167 | srcu_read_unlock(&kvm->irq_srcu, idx); |
158 | 168 | ||
159 | while(i--) { | 169 | while(i--) { |
@@ -250,7 +260,8 @@ int kvm_set_irq_routing(struct kvm *kvm, | |||
250 | 260 | ||
251 | mutex_lock(&kvm->irq_lock); | 261 | mutex_lock(&kvm->irq_lock); |
252 | old = kvm->irq_routing; | 262 | old = kvm->irq_routing; |
253 | kvm_irq_routing_update(kvm, new); | 263 | rcu_assign_pointer(kvm->irq_routing, new); |
264 | kvm_irq_routing_update(kvm); | ||
254 | mutex_unlock(&kvm->irq_lock); | 265 | mutex_unlock(&kvm->irq_lock); |
255 | 266 | ||
256 | synchronize_srcu_expedited(&kvm->irq_srcu); | 267 | synchronize_srcu_expedited(&kvm->irq_srcu); |