1 /* 2 * KVM coalesced MMIO 3 * 4 * Copyright (c) 2008 Bull S.A.S. 5 * 6 * Author: Laurent Vivier <Laurent.Vivier@bull.net> 7 * 8 */ 9 10 #include "iodev.h" 11 12 #include <linux/kvm_host.h> 13 #include <linux/slab.h> 14 #include <linux/kvm.h> 15 16 #include "coalesced_mmio.h" 17 18 static inline struct kvm_coalesced_mmio_dev *to_mmio(struct kvm_io_device *dev) 19 { 20 return container_of(dev, struct kvm_coalesced_mmio_dev, dev); 21 } 22 23 static int coalesced_mmio_in_range(struct kvm_coalesced_mmio_dev *dev, 24 gpa_t addr, int len) 25 { 26 struct kvm_coalesced_mmio_zone *zone; 27 struct kvm_coalesced_mmio_ring *ring; 28 unsigned avail; 29 int i; 30 31 /* Are we able to batch it ? */ 32 33 /* last is the first free entry 34 * check if we don't meet the first used entry 35 * there is always one unused entry in the buffer 36 */ 37 ring = dev->kvm->coalesced_mmio_ring; 38 avail = (ring->first - ring->last - 1) % KVM_COALESCED_MMIO_MAX; 39 if (avail < KVM_MAX_VCPUS) { 40 /* full */ 41 return 0; 42 } 43 44 /* is it in a batchable area ? */ 45 46 for (i = 0; i < dev->nb_zones; i++) { 47 zone = &dev->zone[i]; 48 49 /* (addr,len) is fully included in 50 * (zone->addr, zone->size) 51 */ 52 53 if (zone->addr <= addr && 54 addr + len <= zone->addr + zone->size) 55 return 1; 56 } 57 return 0; 58 } 59 60 static int coalesced_mmio_write(struct kvm_io_device *this, 61 gpa_t addr, int len, const void *val) 62 { 63 struct kvm_coalesced_mmio_dev *dev = to_mmio(this); 64 struct kvm_coalesced_mmio_ring *ring = dev->kvm->coalesced_mmio_ring; 65 if (!coalesced_mmio_in_range(dev, addr, len)) 66 return -EOPNOTSUPP; 67 68 spin_lock(&dev->lock); 69 70 /* copy data in first free entry of the ring */ 71 72 ring->coalesced_mmio[ring->last].phys_addr = addr; 73 ring->coalesced_mmio[ring->last].len = len; 74 memcpy(ring->coalesced_mmio[ring->last].data, val, len); 75 smp_wmb(); 76 ring->last = (ring->last + 1) % KVM_COALESCED_MMIO_MAX; 77 spin_unlock(&dev->lock); 78 return 0; 79 } 80 81 static void coalesced_mmio_destructor(struct kvm_io_device *this) 82 { 83 struct kvm_coalesced_mmio_dev *dev = to_mmio(this); 84 85 kfree(dev); 86 } 87 88 static const struct kvm_io_device_ops coalesced_mmio_ops = { 89 .write = coalesced_mmio_write, 90 .destructor = coalesced_mmio_destructor, 91 }; 92 93 int kvm_coalesced_mmio_init(struct kvm *kvm) 94 { 95 struct kvm_coalesced_mmio_dev *dev; 96 struct page *page; 97 int ret; 98 99 ret = -ENOMEM; 100 page = alloc_page(GFP_KERNEL | __GFP_ZERO); 101 if (!page) 102 goto out_err; 103 kvm->coalesced_mmio_ring = page_address(page); 104 105 ret = -ENOMEM; 106 dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev), GFP_KERNEL); 107 if (!dev) 108 goto out_free_page; 109 spin_lock_init(&dev->lock); 110 kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops); 111 dev->kvm = kvm; 112 kvm->coalesced_mmio_dev = dev; 113 114 mutex_lock(&kvm->slots_lock); 115 ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, &dev->dev); 116 mutex_unlock(&kvm->slots_lock); 117 if (ret < 0) 118 goto out_free_dev; 119 120 return ret; 121 122 out_free_dev: 123 kvm->coalesced_mmio_dev = NULL; 124 kfree(dev); 125 out_free_page: 126 kvm->coalesced_mmio_ring = NULL; 127 __free_page(page); 128 out_err: 129 return ret; 130 } 131 132 void kvm_coalesced_mmio_free(struct kvm *kvm) 133 { 134 if (kvm->coalesced_mmio_ring) 135 free_page((unsigned long)kvm->coalesced_mmio_ring); 136 } 137 138 int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm, 139 struct kvm_coalesced_mmio_zone *zone) 140 { 141 struct kvm_coalesced_mmio_dev *dev = kvm->coalesced_mmio_dev; 142 143 if (dev == NULL) 144 return -ENXIO; 145 146 mutex_lock(&kvm->slots_lock); 147 if (dev->nb_zones >= KVM_COALESCED_MMIO_ZONE_MAX) { 148 mutex_unlock(&kvm->slots_lock); 149 return -ENOBUFS; 150 } 151 152 dev->zone[dev->nb_zones] = *zone; 153 dev->nb_zones++; 154 155 mutex_unlock(&kvm->slots_lock); 156 return 0; 157 } 158 159 int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm, 160 struct kvm_coalesced_mmio_zone *zone) 161 { 162 int i; 163 struct kvm_coalesced_mmio_dev *dev = kvm->coalesced_mmio_dev; 164 struct kvm_coalesced_mmio_zone *z; 165 166 if (dev == NULL) 167 return -ENXIO; 168 169 mutex_lock(&kvm->slots_lock); 170 171 i = dev->nb_zones; 172 while (i) { 173 z = &dev->zone[i - 1]; 174 175 /* unregister all zones 176 * included in (zone->addr, zone->size) 177 */ 178 179 if (zone->addr <= z->addr && 180 z->addr + z->size <= zone->addr + zone->size) { 181 dev->nb_zones--; 182 *z = dev->zone[dev->nb_zones]; 183 } 184 i--; 185 } 186 187 mutex_unlock(&kvm->slots_lock); 188 189 return 0; 190 } 191