Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: Change irq routing table to use gsi indexed array

Use gsi indexed array instead of scanning all entries on each interrupt
injection.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>

authored by

Gleb Natapov and committed by
Avi Kivity
46e624b9 1a6e4a8c

+71 -39
+18 -3
include/linux/kvm_host.h
··· 128 128 } irqchip; 129 129 struct msi_msg msi; 130 130 }; 131 - struct list_head link; 131 + struct hlist_node link; 132 + }; 133 + 134 + struct kvm_irq_routing_table { 135 + struct kvm_kernel_irq_routing_entry *rt_entries; 136 + u32 nr_rt_entries; 137 + /* 138 + * Array indexed by gsi. Each entry contains list of irq chips 139 + * the gsi is connected to. 140 + */ 141 + struct hlist_head map[0]; 132 142 }; 133 143 134 144 struct kvm { ··· 176 166 177 167 struct mutex irq_lock; 178 168 #ifdef CONFIG_HAVE_KVM_IRQCHIP 179 - struct list_head irq_routing; /* of kvm_kernel_irq_routing_entry */ 169 + struct kvm_irq_routing_table *irq_routing; 180 170 struct hlist_head mask_notifier_list; 181 171 #endif 182 172 ··· 400 390 struct kvm_irq_mask_notifier *kimn); 401 391 void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask); 402 392 403 - int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level); 393 + #ifdef __KVM_HAVE_IOAPIC 394 + void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic, 395 + union kvm_ioapic_redirect_entry *entry, 396 + unsigned long *deliver_bitmask); 397 + #endif 398 + int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level); 404 399 void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin); 405 400 void kvm_register_irq_ack_notifier(struct kvm *kvm, 406 401 struct kvm_irq_ack_notifier *kian);
+53 -35
virt/kvm/irq_comm.c
··· 144 144 * = 0 Interrupt was coalesced (previous irq is still pending) 145 145 * > 0 Number of CPUs interrupt was delivered to 146 146 */ 147 - int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level) 147 + int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level) 148 148 { 149 149 struct kvm_kernel_irq_routing_entry *e; 150 150 int ret = -1; 151 + struct kvm_irq_routing_table *irq_rt; 152 + struct hlist_node *n; 151 153 152 154 trace_kvm_set_irq(irq, level, irq_source_id); 153 155 ··· 159 157 * IOAPIC. So set the bit in both. The guest will ignore 160 158 * writes to the unused one. 161 159 */ 162 - list_for_each_entry(e, &kvm->irq_routing, link) 163 - if (e->gsi == irq) { 160 + irq_rt = kvm->irq_routing; 161 + if (irq < irq_rt->nr_rt_entries) 162 + hlist_for_each_entry(e, n, &irq_rt->map[irq], link) { 164 163 int r = e->set(e, kvm, irq_source_id, level); 165 164 if (r < 0) 166 165 continue; ··· 173 170 174 171 void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) 175 172 { 176 - struct kvm_kernel_irq_routing_entry *e; 177 173 struct kvm_irq_ack_notifier *kian; 178 174 struct hlist_node *n; 179 175 unsigned gsi = pin; 176 + int i; 180 177 181 178 trace_kvm_ack_irq(irqchip, pin); 182 179 183 - list_for_each_entry(e, &kvm->irq_routing, link) 180 + for (i = 0; i < kvm->irq_routing->nr_rt_entries; i++) { 181 + struct kvm_kernel_irq_routing_entry *e; 182 + e = &kvm->irq_routing->rt_entries[i]; 184 183 if (e->type == KVM_IRQ_ROUTING_IRQCHIP && 185 184 e->irqchip.irqchip == irqchip && 186 185 e->irqchip.pin == pin) { 187 186 gsi = e->gsi; 188 187 break; 189 188 } 189 + } 190 190 191 191 hlist_for_each_entry(kian, n, &kvm->arch.irq_ack_notifier_list, link) 192 192 if (kian->gsi == gsi) ··· 286 280 kimn->func(kimn, mask); 287 281 } 288 282 289 - static void __kvm_free_irq_routing(struct list_head *irq_routing) 290 - { 291 - struct kvm_kernel_irq_routing_entry *e, *n; 292 - 293 - list_for_each_entry_safe(e, n, irq_routing, link) 294 - kfree(e); 295 - } 296 - 297 283 void kvm_free_irq_routing(struct kvm *kvm) 298 284 { 299 285 mutex_lock(&kvm->irq_lock); 300 - __kvm_free_irq_routing(&kvm->irq_routing); 286 + kfree(kvm->irq_routing); 301 287 mutex_unlock(&kvm->irq_lock); 302 288 } 303 289 304 - static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e, 290 + static int setup_routing_entry(struct kvm_irq_routing_table *rt, 291 + struct kvm_kernel_irq_routing_entry *e, 305 292 const struct kvm_irq_routing_entry *ue) 306 293 { 307 294 int r = -EINVAL; 308 295 int delta; 296 + struct kvm_kernel_irq_routing_entry *ei; 297 + struct hlist_node *n; 298 + 299 + /* 300 + * Do not allow GSI to be mapped to the same irqchip more than once. 301 + * Allow only one to one mapping between GSI and MSI. 302 + */ 303 + hlist_for_each_entry(ei, n, &rt->map[ue->gsi], link) 304 + if (ei->type == KVM_IRQ_ROUTING_MSI || 305 + ue->u.irqchip.irqchip == ei->irqchip.irqchip) 306 + return r; 309 307 310 308 e->gsi = ue->gsi; 311 309 e->type = ue->type; ··· 342 332 default: 343 333 goto out; 344 334 } 335 + 336 + hlist_add_head(&e->link, &rt->map[e->gsi]); 345 337 r = 0; 346 338 out: 347 339 return r; ··· 355 343 unsigned nr, 356 344 unsigned flags) 357 345 { 358 - struct list_head irq_list = LIST_HEAD_INIT(irq_list); 359 - struct list_head tmp = LIST_HEAD_INIT(tmp); 360 - struct kvm_kernel_irq_routing_entry *e = NULL; 361 - unsigned i; 346 + struct kvm_irq_routing_table *new, *old; 347 + u32 i, nr_rt_entries = 0; 362 348 int r; 363 349 364 350 for (i = 0; i < nr; ++i) { 351 + if (ue[i].gsi >= KVM_MAX_IRQ_ROUTES) 352 + return -EINVAL; 353 + nr_rt_entries = max(nr_rt_entries, ue[i].gsi); 354 + } 355 + 356 + nr_rt_entries += 1; 357 + 358 + new = kzalloc(sizeof(*new) + (nr_rt_entries * sizeof(struct hlist_head)) 359 + + (nr * sizeof(struct kvm_kernel_irq_routing_entry)), 360 + GFP_KERNEL); 361 + 362 + if (!new) 363 + return -ENOMEM; 364 + 365 + new->rt_entries = (void *)&new->map[nr_rt_entries]; 366 + 367 + new->nr_rt_entries = nr_rt_entries; 368 + 369 + for (i = 0; i < nr; ++i) { 365 370 r = -EINVAL; 366 - if (ue->gsi >= KVM_MAX_IRQ_ROUTES) 367 - goto out; 368 371 if (ue->flags) 369 372 goto out; 370 - r = -ENOMEM; 371 - e = kzalloc(sizeof(*e), GFP_KERNEL); 372 - if (!e) 373 - goto out; 374 - r = setup_routing_entry(e, ue); 373 + r = setup_routing_entry(new, &new->rt_entries[i], ue); 375 374 if (r) 376 375 goto out; 377 376 ++ue; 378 - list_add(&e->link, &irq_list); 379 - e = NULL; 380 377 } 381 378 382 379 mutex_lock(&kvm->irq_lock); 383 - list_splice(&kvm->irq_routing, &tmp); 384 - INIT_LIST_HEAD(&kvm->irq_routing); 385 - list_splice(&irq_list, &kvm->irq_routing); 386 - INIT_LIST_HEAD(&irq_list); 387 - list_splice(&tmp, &irq_list); 380 + old = kvm->irq_routing; 381 + kvm->irq_routing = new; 388 382 mutex_unlock(&kvm->irq_lock); 389 383 384 + new = old; 390 385 r = 0; 391 386 392 387 out: 393 - kfree(e); 394 - __kvm_free_irq_routing(&irq_list); 388 + kfree(new); 395 389 return r; 396 390 } 397 391
-1
virt/kvm/kvm_main.c
··· 957 957 if (IS_ERR(kvm)) 958 958 goto out; 959 959 #ifdef CONFIG_HAVE_KVM_IRQCHIP 960 - INIT_LIST_HEAD(&kvm->irq_routing); 961 960 INIT_HLIST_HEAD(&kvm->mask_notifier_list); 962 961 #endif 963 962