aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSasha Levin <levinsasha928@gmail.com>2011-07-27 09:00:48 -0400
committerAvi Kivity <avi@redhat.com>2011-09-25 12:17:59 -0400
commit743eeb0b01d2fbf4154bf87bff1ebb6fb18aeb7a (patch)
tree5392464930f7e77131d65f32ba96ce4665307629
parent0d460ffc0956d2dbe12ca9f5f6aa0f8701ea9d73 (diff)
KVM: Intelligent device lookup on I/O bus
Currently the method of dealing with an IO operation on a bus (PIO/MMIO) is to call the read or write callback for each device registered on the bus until we find a device which handles it. Since the number of devices on a bus can be significant due to ioeventfds and coalesced MMIO zones, this leads to a lot of overhead on each IO operation. Instead of registering devices, we now register ranges which points to a device. Lookup is done using an efficient bsearch instead of a linear search. Performance test was conducted by comparing exit count per second with 200 ioeventfds created on one byte and the guest is trying to access a different byte continuously (triggering usermode exits). Before the patch the guest has achieved 259k exits per second, after the patch the guest does 274k exits per second. Cc: Avi Kivity <avi@redhat.com> Cc: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Sasha Levin <levinsasha928@gmail.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/x86/kvm/i8254.c6
-rw-r--r--arch/x86/kvm/i8259.c108
-rw-r--r--arch/x86/kvm/irq.h4
-rw-r--r--arch/x86/kvm/x86.c6
-rw-r--r--include/linux/kvm_host.h18
-rw-r--r--virt/kvm/coalesced_mmio.c3
-rw-r--r--virt/kvm/eventfd.c3
-rw-r--r--virt/kvm/ioapic.c3
-rw-r--r--virt/kvm/kvm_main.c112
9 files changed, 216 insertions, 47 deletions
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index efad72385058..76e3f1cd0369 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -713,14 +713,16 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
713 kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier); 713 kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
714 714
715 kvm_iodevice_init(&pit->dev, &pit_dev_ops); 715 kvm_iodevice_init(&pit->dev, &pit_dev_ops);
716 ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, &pit->dev); 716 ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, KVM_PIT_BASE_ADDRESS,
717 KVM_PIT_MEM_LENGTH, &pit->dev);
717 if (ret < 0) 718 if (ret < 0)
718 goto fail; 719 goto fail;
719 720
720 if (flags & KVM_PIT_SPEAKER_DUMMY) { 721 if (flags & KVM_PIT_SPEAKER_DUMMY) {
721 kvm_iodevice_init(&pit->speaker_dev, &speaker_dev_ops); 722 kvm_iodevice_init(&pit->speaker_dev, &speaker_dev_ops);
722 ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 723 ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS,
723 &pit->speaker_dev); 724 KVM_SPEAKER_BASE_ADDRESS, 4,
725 &pit->speaker_dev);
724 if (ret < 0) 726 if (ret < 0)
725 goto fail_unregister; 727 goto fail_unregister;
726 } 728 }
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index 19fe855e7953..6b869ce0cc19 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -459,15 +459,9 @@ static int picdev_in_range(gpa_t addr)
459 } 459 }
460} 460}
461 461
462static inline struct kvm_pic *to_pic(struct kvm_io_device *dev) 462static int picdev_write(struct kvm_pic *s,
463{
464 return container_of(dev, struct kvm_pic, dev);
465}
466
467static int picdev_write(struct kvm_io_device *this,
468 gpa_t addr, int len, const void *val) 463 gpa_t addr, int len, const void *val)
469{ 464{
470 struct kvm_pic *s = to_pic(this);
471 unsigned char data = *(unsigned char *)val; 465 unsigned char data = *(unsigned char *)val;
472 if (!picdev_in_range(addr)) 466 if (!picdev_in_range(addr))
473 return -EOPNOTSUPP; 467 return -EOPNOTSUPP;
@@ -494,10 +488,9 @@ static int picdev_write(struct kvm_io_device *this,
494 return 0; 488 return 0;
495} 489}
496 490
497static int picdev_read(struct kvm_io_device *this, 491static int picdev_read(struct kvm_pic *s,
498 gpa_t addr, int len, void *val) 492 gpa_t addr, int len, void *val)
499{ 493{
500 struct kvm_pic *s = to_pic(this);
501 unsigned char data = 0; 494 unsigned char data = 0;
502 if (!picdev_in_range(addr)) 495 if (!picdev_in_range(addr))
503 return -EOPNOTSUPP; 496 return -EOPNOTSUPP;
@@ -525,6 +518,48 @@ static int picdev_read(struct kvm_io_device *this,
525 return 0; 518 return 0;
526} 519}
527 520
521static int picdev_master_write(struct kvm_io_device *dev,
522 gpa_t addr, int len, const void *val)
523{
524 return picdev_write(container_of(dev, struct kvm_pic, dev_master),
525 addr, len, val);
526}
527
528static int picdev_master_read(struct kvm_io_device *dev,
529 gpa_t addr, int len, void *val)
530{
531 return picdev_read(container_of(dev, struct kvm_pic, dev_master),
532 addr, len, val);
533}
534
535static int picdev_slave_write(struct kvm_io_device *dev,
536 gpa_t addr, int len, const void *val)
537{
538 return picdev_write(container_of(dev, struct kvm_pic, dev_slave),
539 addr, len, val);
540}
541
542static int picdev_slave_read(struct kvm_io_device *dev,
543 gpa_t addr, int len, void *val)
544{
545 return picdev_read(container_of(dev, struct kvm_pic, dev_slave),
546 addr, len, val);
547}
548
549static int picdev_eclr_write(struct kvm_io_device *dev,
550 gpa_t addr, int len, const void *val)
551{
552 return picdev_write(container_of(dev, struct kvm_pic, dev_eclr),
553 addr, len, val);
554}
555
556static int picdev_eclr_read(struct kvm_io_device *dev,
557 gpa_t addr, int len, void *val)
558{
559 return picdev_read(container_of(dev, struct kvm_pic, dev_eclr),
560 addr, len, val);
561}
562
528/* 563/*
529 * callback when PIC0 irq status changed 564 * callback when PIC0 irq status changed
530 */ 565 */
@@ -537,9 +572,19 @@ static void pic_irq_request(struct kvm *kvm, int level)
537 s->output = level; 572 s->output = level;
538} 573}
539 574
540static const struct kvm_io_device_ops picdev_ops = { 575static const struct kvm_io_device_ops picdev_master_ops = {
541 .read = picdev_read, 576 .read = picdev_master_read,
542 .write = picdev_write, 577 .write = picdev_master_write,
578};
579
580static const struct kvm_io_device_ops picdev_slave_ops = {
581 .read = picdev_slave_read,
582 .write = picdev_slave_write,
583};
584
585static const struct kvm_io_device_ops picdev_eclr_ops = {
586 .read = picdev_eclr_read,
587 .write = picdev_eclr_write,
543}; 588};
544 589
545struct kvm_pic *kvm_create_pic(struct kvm *kvm) 590struct kvm_pic *kvm_create_pic(struct kvm *kvm)
@@ -560,16 +605,39 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
560 /* 605 /*
561 * Initialize PIO device 606 * Initialize PIO device
562 */ 607 */
563 kvm_iodevice_init(&s->dev, &picdev_ops); 608 kvm_iodevice_init(&s->dev_master, &picdev_master_ops);
609 kvm_iodevice_init(&s->dev_slave, &picdev_slave_ops);
610 kvm_iodevice_init(&s->dev_eclr, &picdev_eclr_ops);
564 mutex_lock(&kvm->slots_lock); 611 mutex_lock(&kvm->slots_lock);
565 ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, &s->dev); 612 ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x20, 2,
613 &s->dev_master);
614 if (ret < 0)
615 goto fail_unlock;
616
617 ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0xa0, 2, &s->dev_slave);
618 if (ret < 0)
619 goto fail_unreg_2;
620
621 ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x4d0, 2, &s->dev_eclr);
622 if (ret < 0)
623 goto fail_unreg_1;
624
566 mutex_unlock(&kvm->slots_lock); 625 mutex_unlock(&kvm->slots_lock);
567 if (ret < 0) {
568 kfree(s);
569 return NULL;
570 }
571 626
572 return s; 627 return s;
628
629fail_unreg_1:
630 kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &s->dev_slave);
631
632fail_unreg_2:
633 kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &s->dev_master);
634
635fail_unlock:
636 mutex_unlock(&kvm->slots_lock);
637
638 kfree(s);
639
640 return NULL;
573} 641}
574 642
575void kvm_destroy_pic(struct kvm *kvm) 643void kvm_destroy_pic(struct kvm *kvm)
@@ -577,7 +645,9 @@ void kvm_destroy_pic(struct kvm *kvm)
577 struct kvm_pic *vpic = kvm->arch.vpic; 645 struct kvm_pic *vpic = kvm->arch.vpic;
578 646
579 if (vpic) { 647 if (vpic) {
580 kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev); 648 kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev_master);
649 kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev_slave);
650 kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev_eclr);
581 kvm->arch.vpic = NULL; 651 kvm->arch.vpic = NULL;
582 kfree(vpic); 652 kfree(vpic);
583 } 653 }
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index 53e2d084bffb..2086f2bfba33 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -66,7 +66,9 @@ struct kvm_pic {
66 struct kvm *kvm; 66 struct kvm *kvm;
67 struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */ 67 struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */
68 int output; /* intr from master PIC */ 68 int output; /* intr from master PIC */
69 struct kvm_io_device dev; 69 struct kvm_io_device dev_master;
70 struct kvm_io_device dev_slave;
71 struct kvm_io_device dev_eclr;
70 void (*ack_notifier)(void *opaque, int irq); 72 void (*ack_notifier)(void *opaque, int irq);
71 unsigned long irq_states[16]; 73 unsigned long irq_states[16];
72}; 74};
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6cb353c83a12..d28dff749dfd 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3562,7 +3562,11 @@ long kvm_arch_vm_ioctl(struct file *filp,
3562 if (r) { 3562 if (r) {
3563 mutex_lock(&kvm->slots_lock); 3563 mutex_lock(&kvm->slots_lock);
3564 kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, 3564 kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
3565 &vpic->dev); 3565 &vpic->dev_master);
3566 kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
3567 &vpic->dev_slave);
3568 kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
3569 &vpic->dev_eclr);
3566 mutex_unlock(&kvm->slots_lock); 3570 mutex_unlock(&kvm->slots_lock);
3567 kfree(vpic); 3571 kfree(vpic);
3568 goto create_irqchip_unlock; 3572 goto create_irqchip_unlock;
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index ff4d4062af9d..d0e42f30edf6 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -55,16 +55,16 @@ struct kvm;
55struct kvm_vcpu; 55struct kvm_vcpu;
56extern struct kmem_cache *kvm_vcpu_cache; 56extern struct kmem_cache *kvm_vcpu_cache;
57 57
58/* 58struct kvm_io_range {
59 * It would be nice to use something smarter than a linear search, TBD... 59 gpa_t addr;
60 * Thankfully we dont expect many devices to register (famous last words :), 60 int len;
61 * so until then it will suffice. At least its abstracted so we can change 61 struct kvm_io_device *dev;
62 * in one place. 62};
63 */ 63
64struct kvm_io_bus { 64struct kvm_io_bus {
65 int dev_count; 65 int dev_count;
66#define NR_IOBUS_DEVS 300 66#define NR_IOBUS_DEVS 300
67 struct kvm_io_device *devs[NR_IOBUS_DEVS]; 67 struct kvm_io_range range[NR_IOBUS_DEVS];
68}; 68};
69 69
70enum kvm_bus { 70enum kvm_bus {
@@ -77,8 +77,8 @@ int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
77 int len, const void *val); 77 int len, const void *val);
78int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, int len, 78int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, int len,
79 void *val); 79 void *val);
80int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, 80int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
81 struct kvm_io_device *dev); 81 int len, struct kvm_io_device *dev);
82int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx, 82int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
83 struct kvm_io_device *dev); 83 struct kvm_io_device *dev);
84 84
diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c
index 2316ec1aadc4..a6ec206f36ba 100644
--- a/virt/kvm/coalesced_mmio.c
+++ b/virt/kvm/coalesced_mmio.c
@@ -141,7 +141,8 @@ int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
141 dev->zone = *zone; 141 dev->zone = *zone;
142 142
143 mutex_lock(&kvm->slots_lock); 143 mutex_lock(&kvm->slots_lock);
144 ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, &dev->dev); 144 ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, zone->addr,
145 zone->size, &dev->dev);
145 if (ret < 0) 146 if (ret < 0)
146 goto out_free_dev; 147 goto out_free_dev;
147 list_add_tail(&dev->list, &kvm->coalesced_zones); 148 list_add_tail(&dev->list, &kvm->coalesced_zones);
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
index 73358d256fa2..f59c1e8de7a2 100644
--- a/virt/kvm/eventfd.c
+++ b/virt/kvm/eventfd.c
@@ -586,7 +586,8 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
586 586
587 kvm_iodevice_init(&p->dev, &ioeventfd_ops); 587 kvm_iodevice_init(&p->dev, &ioeventfd_ops);
588 588
589 ret = kvm_io_bus_register_dev(kvm, bus_idx, &p->dev); 589 ret = kvm_io_bus_register_dev(kvm, bus_idx, p->addr, p->length,
590 &p->dev);
590 if (ret < 0) 591 if (ret < 0)
591 goto unlock_fail; 592 goto unlock_fail;
592 593
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 8df1ca104a7f..3eed61eb4867 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -394,7 +394,8 @@ int kvm_ioapic_init(struct kvm *kvm)
394 kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops); 394 kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
395 ioapic->kvm = kvm; 395 ioapic->kvm = kvm;
396 mutex_lock(&kvm->slots_lock); 396 mutex_lock(&kvm->slots_lock);
397 ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, &ioapic->dev); 397 ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, ioapic->base_address,
398 IOAPIC_MEM_LENGTH, &ioapic->dev);
398 mutex_unlock(&kvm->slots_lock); 399 mutex_unlock(&kvm->slots_lock);
399 if (ret < 0) { 400 if (ret < 0) {
400 kvm->arch.vioapic = NULL; 401 kvm->arch.vioapic = NULL;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index aefdda390f5e..d9cfb782cb81 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -47,6 +47,8 @@
47#include <linux/srcu.h> 47#include <linux/srcu.h>
48#include <linux/hugetlb.h> 48#include <linux/hugetlb.h>
49#include <linux/slab.h> 49#include <linux/slab.h>
50#include <linux/sort.h>
51#include <linux/bsearch.h>
50 52
51#include <asm/processor.h> 53#include <asm/processor.h>
52#include <asm/io.h> 54#include <asm/io.h>
@@ -2391,24 +2393,92 @@ static void kvm_io_bus_destroy(struct kvm_io_bus *bus)
2391 int i; 2393 int i;
2392 2394
2393 for (i = 0; i < bus->dev_count; i++) { 2395 for (i = 0; i < bus->dev_count; i++) {
2394 struct kvm_io_device *pos = bus->devs[i]; 2396 struct kvm_io_device *pos = bus->range[i].dev;
2395 2397
2396 kvm_iodevice_destructor(pos); 2398 kvm_iodevice_destructor(pos);
2397 } 2399 }
2398 kfree(bus); 2400 kfree(bus);
2399} 2401}
2400 2402
2403int kvm_io_bus_sort_cmp(const void *p1, const void *p2)
2404{
2405 const struct kvm_io_range *r1 = p1;
2406 const struct kvm_io_range *r2 = p2;
2407
2408 if (r1->addr < r2->addr)
2409 return -1;
2410 if (r1->addr + r1->len > r2->addr + r2->len)
2411 return 1;
2412 return 0;
2413}
2414
2415int kvm_io_bus_insert_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev,
2416 gpa_t addr, int len)
2417{
2418 if (bus->dev_count == NR_IOBUS_DEVS)
2419 return -ENOSPC;
2420
2421 bus->range[bus->dev_count++] = (struct kvm_io_range) {
2422 .addr = addr,
2423 .len = len,
2424 .dev = dev,
2425 };
2426
2427 sort(bus->range, bus->dev_count, sizeof(struct kvm_io_range),
2428 kvm_io_bus_sort_cmp, NULL);
2429
2430 return 0;
2431}
2432
2433int kvm_io_bus_get_first_dev(struct kvm_io_bus *bus,
2434 gpa_t addr, int len)
2435{
2436 struct kvm_io_range *range, key;
2437 int off;
2438
2439 key = (struct kvm_io_range) {
2440 .addr = addr,
2441 .len = len,
2442 };
2443
2444 range = bsearch(&key, bus->range, bus->dev_count,
2445 sizeof(struct kvm_io_range), kvm_io_bus_sort_cmp);
2446 if (range == NULL)
2447 return -ENOENT;
2448
2449 off = range - bus->range;
2450
2451 while (off > 0 && kvm_io_bus_sort_cmp(&key, &bus->range[off-1]) == 0)
2452 off--;
2453
2454 return off;
2455}
2456
2401/* kvm_io_bus_write - called under kvm->slots_lock */ 2457/* kvm_io_bus_write - called under kvm->slots_lock */
2402int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, 2458int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
2403 int len, const void *val) 2459 int len, const void *val)
2404{ 2460{
2405 int i; 2461 int idx;
2406 struct kvm_io_bus *bus; 2462 struct kvm_io_bus *bus;
2463 struct kvm_io_range range;
2464
2465 range = (struct kvm_io_range) {
2466 .addr = addr,
2467 .len = len,
2468 };
2407 2469
2408 bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); 2470 bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
2409 for (i = 0; i < bus->dev_count; i++) 2471 idx = kvm_io_bus_get_first_dev(bus, addr, len);
2410 if (!kvm_iodevice_write(bus->devs[i], addr, len, val)) 2472 if (idx < 0)
2473 return -EOPNOTSUPP;
2474
2475 while (idx < bus->dev_count &&
2476 kvm_io_bus_sort_cmp(&range, &bus->range[idx]) == 0) {
2477 if (!kvm_iodevice_write(bus->range[idx].dev, addr, len, val))
2411 return 0; 2478 return 0;
2479 idx++;
2480 }
2481
2412 return -EOPNOTSUPP; 2482 return -EOPNOTSUPP;
2413} 2483}
2414 2484
@@ -2416,19 +2486,33 @@ int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
2416int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, 2486int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
2417 int len, void *val) 2487 int len, void *val)
2418{ 2488{
2419 int i; 2489 int idx;
2420 struct kvm_io_bus *bus; 2490 struct kvm_io_bus *bus;
2491 struct kvm_io_range range;
2492
2493 range = (struct kvm_io_range) {
2494 .addr = addr,
2495 .len = len,
2496 };
2421 2497
2422 bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); 2498 bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
2423 for (i = 0; i < bus->dev_count; i++) 2499 idx = kvm_io_bus_get_first_dev(bus, addr, len);
2424 if (!kvm_iodevice_read(bus->devs[i], addr, len, val)) 2500 if (idx < 0)
2501 return -EOPNOTSUPP;
2502
2503 while (idx < bus->dev_count &&
2504 kvm_io_bus_sort_cmp(&range, &bus->range[idx]) == 0) {
2505 if (!kvm_iodevice_read(bus->range[idx].dev, addr, len, val))
2425 return 0; 2506 return 0;
2507 idx++;
2508 }
2509
2426 return -EOPNOTSUPP; 2510 return -EOPNOTSUPP;
2427} 2511}
2428 2512
2429/* Caller must hold slots_lock. */ 2513/* Caller must hold slots_lock. */
2430int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, 2514int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
2431 struct kvm_io_device *dev) 2515 int len, struct kvm_io_device *dev)
2432{ 2516{
2433 struct kvm_io_bus *new_bus, *bus; 2517 struct kvm_io_bus *new_bus, *bus;
2434 2518
@@ -2440,7 +2524,7 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx,
2440 if (!new_bus) 2524 if (!new_bus)
2441 return -ENOMEM; 2525 return -ENOMEM;
2442 memcpy(new_bus, bus, sizeof(struct kvm_io_bus)); 2526 memcpy(new_bus, bus, sizeof(struct kvm_io_bus));
2443 new_bus->devs[new_bus->dev_count++] = dev; 2527 kvm_io_bus_insert_dev(new_bus, dev, addr, len);
2444 rcu_assign_pointer(kvm->buses[bus_idx], new_bus); 2528 rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
2445 synchronize_srcu_expedited(&kvm->srcu); 2529 synchronize_srcu_expedited(&kvm->srcu);
2446 kfree(bus); 2530 kfree(bus);
@@ -2464,9 +2548,13 @@ int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
2464 2548
2465 r = -ENOENT; 2549 r = -ENOENT;
2466 for (i = 0; i < new_bus->dev_count; i++) 2550 for (i = 0; i < new_bus->dev_count; i++)
2467 if (new_bus->devs[i] == dev) { 2551 if (new_bus->range[i].dev == dev) {
2468 r = 0; 2552 r = 0;
2469 new_bus->devs[i] = new_bus->devs[--new_bus->dev_count]; 2553 new_bus->dev_count--;
2554 new_bus->range[i] = new_bus->range[new_bus->dev_count];
2555 sort(new_bus->range, new_bus->dev_count,
2556 sizeof(struct kvm_io_range),
2557 kvm_io_bus_sort_cmp, NULL);
2470 break; 2558 break;
2471 } 2559 }
2472 2560