diff options
Diffstat (limited to 'virt')
| -rw-r--r-- | virt/kvm/ioapic.c | 80 | ||||
| -rw-r--r-- | virt/kvm/ioapic.h | 4 | ||||
| -rw-r--r-- | virt/kvm/irq_comm.c | 23 |
3 files changed, 79 insertions, 28 deletions
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 9fe140bb38e..38a2d20b89d 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c | |||
| @@ -182,6 +182,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) | |||
| 182 | union kvm_ioapic_redirect_entry entry; | 182 | union kvm_ioapic_redirect_entry entry; |
| 183 | int ret = 1; | 183 | int ret = 1; |
| 184 | 184 | ||
| 185 | mutex_lock(&ioapic->lock); | ||
| 185 | if (irq >= 0 && irq < IOAPIC_NUM_PINS) { | 186 | if (irq >= 0 && irq < IOAPIC_NUM_PINS) { |
| 186 | entry = ioapic->redirtbl[irq]; | 187 | entry = ioapic->redirtbl[irq]; |
| 187 | level ^= entry.fields.polarity; | 188 | level ^= entry.fields.polarity; |
| @@ -198,34 +199,51 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) | |||
| 198 | } | 199 | } |
| 199 | trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0); | 200 | trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0); |
| 200 | } | 201 | } |
| 202 | mutex_unlock(&ioapic->lock); | ||
| 203 | |||
| 201 | return ret; | 204 | return ret; |
| 202 | } | 205 | } |
| 203 | 206 | ||
| 204 | static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int pin, | 207 | static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int vector, |
| 205 | int trigger_mode) | 208 | int trigger_mode) |
| 206 | { | 209 | { |
| 207 | union kvm_ioapic_redirect_entry *ent; | 210 | int i; |
| 211 | |||
| 212 | for (i = 0; i < IOAPIC_NUM_PINS; i++) { | ||
| 213 | union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i]; | ||
| 208 | 214 | ||
| 209 | ent = &ioapic->redirtbl[pin]; | 215 | if (ent->fields.vector != vector) |
| 216 | continue; | ||
| 210 | 217 | ||
| 211 | kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, pin); | 218 | /* |
| 219 | * We are dropping lock while calling ack notifiers because ack | ||
| 220 | * notifier callbacks for assigned devices call into IOAPIC | ||
| 221 | * recursively. Since remote_irr is cleared only after call | ||
| 222 | * to notifiers if the same vector will be delivered while lock | ||
| 223 | * is dropped it will be put into irr and will be delivered | ||
| 224 | * after ack notifier returns. | ||
| 225 | */ | ||
| 226 | mutex_unlock(&ioapic->lock); | ||
| 227 | kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i); | ||
| 228 | mutex_lock(&ioapic->lock); | ||
| 229 | |||
| 230 | if (trigger_mode != IOAPIC_LEVEL_TRIG) | ||
| 231 | continue; | ||
| 212 | 232 | ||
| 213 | if (trigger_mode == IOAPIC_LEVEL_TRIG) { | ||
| 214 | ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); | 233 | ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); |
| 215 | ent->fields.remote_irr = 0; | 234 | ent->fields.remote_irr = 0; |
| 216 | if (!ent->fields.mask && (ioapic->irr & (1 << pin))) | 235 | if (!ent->fields.mask && (ioapic->irr & (1 << i))) |
| 217 | ioapic_service(ioapic, pin); | 236 | ioapic_service(ioapic, i); |
| 218 | } | 237 | } |
| 219 | } | 238 | } |
| 220 | 239 | ||
| 221 | void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode) | 240 | void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode) |
| 222 | { | 241 | { |
| 223 | struct kvm_ioapic *ioapic = kvm->arch.vioapic; | 242 | struct kvm_ioapic *ioapic = kvm->arch.vioapic; |
| 224 | int i; | ||
| 225 | 243 | ||
| 226 | for (i = 0; i < IOAPIC_NUM_PINS; i++) | 244 | mutex_lock(&ioapic->lock); |
| 227 | if (ioapic->redirtbl[i].fields.vector == vector) | 245 | __kvm_ioapic_update_eoi(ioapic, vector, trigger_mode); |
| 228 | __kvm_ioapic_update_eoi(ioapic, i, trigger_mode); | 246 | mutex_unlock(&ioapic->lock); |
| 229 | } | 247 | } |
| 230 | 248 | ||
| 231 | static inline struct kvm_ioapic *to_ioapic(struct kvm_io_device *dev) | 249 | static inline struct kvm_ioapic *to_ioapic(struct kvm_io_device *dev) |
| @@ -250,8 +268,8 @@ static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len, | |||
| 250 | ioapic_debug("addr %lx\n", (unsigned long)addr); | 268 | ioapic_debug("addr %lx\n", (unsigned long)addr); |
| 251 | ASSERT(!(addr & 0xf)); /* check alignment */ | 269 | ASSERT(!(addr & 0xf)); /* check alignment */ |
| 252 | 270 | ||
| 253 | mutex_lock(&ioapic->kvm->irq_lock); | ||
| 254 | addr &= 0xff; | 271 | addr &= 0xff; |
| 272 | mutex_lock(&ioapic->lock); | ||
| 255 | switch (addr) { | 273 | switch (addr) { |
| 256 | case IOAPIC_REG_SELECT: | 274 | case IOAPIC_REG_SELECT: |
| 257 | result = ioapic->ioregsel; | 275 | result = ioapic->ioregsel; |
| @@ -265,6 +283,8 @@ static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len, | |||
| 265 | result = 0; | 283 | result = 0; |
| 266 | break; | 284 | break; |
| 267 | } | 285 | } |
| 286 | mutex_unlock(&ioapic->lock); | ||
| 287 | |||
| 268 | switch (len) { | 288 | switch (len) { |
| 269 | case 8: | 289 | case 8: |
| 270 | *(u64 *) val = result; | 290 | *(u64 *) val = result; |
| @@ -277,7 +297,6 @@ static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len, | |||
| 277 | default: | 297 | default: |
| 278 | printk(KERN_WARNING "ioapic: wrong length %d\n", len); | 298 | printk(KERN_WARNING "ioapic: wrong length %d\n", len); |
| 279 | } | 299 | } |
| 280 | mutex_unlock(&ioapic->kvm->irq_lock); | ||
| 281 | return 0; | 300 | return 0; |
| 282 | } | 301 | } |
| 283 | 302 | ||
| @@ -293,15 +312,15 @@ static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len, | |||
| 293 | (void*)addr, len, val); | 312 | (void*)addr, len, val); |
| 294 | ASSERT(!(addr & 0xf)); /* check alignment */ | 313 | ASSERT(!(addr & 0xf)); /* check alignment */ |
| 295 | 314 | ||
| 296 | mutex_lock(&ioapic->kvm->irq_lock); | ||
| 297 | if (len == 4 || len == 8) | 315 | if (len == 4 || len == 8) |
| 298 | data = *(u32 *) val; | 316 | data = *(u32 *) val; |
| 299 | else { | 317 | else { |
| 300 | printk(KERN_WARNING "ioapic: Unsupported size %d\n", len); | 318 | printk(KERN_WARNING "ioapic: Unsupported size %d\n", len); |
| 301 | goto unlock; | 319 | return 0; |
| 302 | } | 320 | } |
| 303 | 321 | ||
| 304 | addr &= 0xff; | 322 | addr &= 0xff; |
| 323 | mutex_lock(&ioapic->lock); | ||
| 305 | switch (addr) { | 324 | switch (addr) { |
| 306 | case IOAPIC_REG_SELECT: | 325 | case IOAPIC_REG_SELECT: |
| 307 | ioapic->ioregsel = data; | 326 | ioapic->ioregsel = data; |
| @@ -312,15 +331,14 @@ static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len, | |||
| 312 | break; | 331 | break; |
| 313 | #ifdef CONFIG_IA64 | 332 | #ifdef CONFIG_IA64 |
| 314 | case IOAPIC_REG_EOI: | 333 | case IOAPIC_REG_EOI: |
| 315 | kvm_ioapic_update_eoi(ioapic->kvm, data, IOAPIC_LEVEL_TRIG); | 334 | __kvm_ioapic_update_eoi(ioapic, data, IOAPIC_LEVEL_TRIG); |
| 316 | break; | 335 | break; |
| 317 | #endif | 336 | #endif |
| 318 | 337 | ||
| 319 | default: | 338 | default: |
| 320 | break; | 339 | break; |
| 321 | } | 340 | } |
| 322 | unlock: | 341 | mutex_unlock(&ioapic->lock); |
| 323 | mutex_unlock(&ioapic->kvm->irq_lock); | ||
| 324 | return 0; | 342 | return 0; |
| 325 | } | 343 | } |
| 326 | 344 | ||
| @@ -349,6 +367,7 @@ int kvm_ioapic_init(struct kvm *kvm) | |||
| 349 | ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL); | 367 | ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL); |
| 350 | if (!ioapic) | 368 | if (!ioapic) |
| 351 | return -ENOMEM; | 369 | return -ENOMEM; |
| 370 | mutex_init(&ioapic->lock); | ||
| 352 | kvm->arch.vioapic = ioapic; | 371 | kvm->arch.vioapic = ioapic; |
| 353 | kvm_ioapic_reset(ioapic); | 372 | kvm_ioapic_reset(ioapic); |
| 354 | kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops); | 373 | kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops); |
| @@ -360,3 +379,26 @@ int kvm_ioapic_init(struct kvm *kvm) | |||
| 360 | return ret; | 379 | return ret; |
| 361 | } | 380 | } |
| 362 | 381 | ||
| 382 | int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state) | ||
| 383 | { | ||
| 384 | struct kvm_ioapic *ioapic = ioapic_irqchip(kvm); | ||
| 385 | if (!ioapic) | ||
| 386 | return -EINVAL; | ||
| 387 | |||
| 388 | mutex_lock(&ioapic->lock); | ||
| 389 | memcpy(state, ioapic, sizeof(struct kvm_ioapic_state)); | ||
| 390 | mutex_unlock(&ioapic->lock); | ||
| 391 | return 0; | ||
| 392 | } | ||
| 393 | |||
| 394 | int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state) | ||
| 395 | { | ||
| 396 | struct kvm_ioapic *ioapic = ioapic_irqchip(kvm); | ||
| 397 | if (!ioapic) | ||
| 398 | return -EINVAL; | ||
| 399 | |||
| 400 | mutex_lock(&ioapic->lock); | ||
| 401 | memcpy(ioapic, state, sizeof(struct kvm_ioapic_state)); | ||
| 402 | mutex_unlock(&ioapic->lock); | ||
| 403 | return 0; | ||
| 404 | } | ||
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h index 6e461ade636..419c43b667a 100644 --- a/virt/kvm/ioapic.h +++ b/virt/kvm/ioapic.h | |||
| @@ -45,6 +45,7 @@ struct kvm_ioapic { | |||
| 45 | struct kvm_io_device dev; | 45 | struct kvm_io_device dev; |
| 46 | struct kvm *kvm; | 46 | struct kvm *kvm; |
| 47 | void (*ack_notifier)(void *opaque, int irq); | 47 | void (*ack_notifier)(void *opaque, int irq); |
| 48 | struct mutex lock; | ||
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | #ifdef DEBUG | 51 | #ifdef DEBUG |
| @@ -74,4 +75,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); | |||
| 74 | void kvm_ioapic_reset(struct kvm_ioapic *ioapic); | 75 | void kvm_ioapic_reset(struct kvm_ioapic *ioapic); |
| 75 | int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, | 76 | int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, |
| 76 | struct kvm_lapic_irq *irq); | 77 | struct kvm_lapic_irq *irq); |
| 78 | int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state); | ||
| 79 | int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state); | ||
| 80 | |||
| 77 | #endif | 81 | #endif |
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index 6c946141dbc..fadf4408a82 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c | |||
| @@ -146,8 +146,8 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, | |||
| 146 | */ | 146 | */ |
| 147 | int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level) | 147 | int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level) |
| 148 | { | 148 | { |
| 149 | struct kvm_kernel_irq_routing_entry *e; | 149 | struct kvm_kernel_irq_routing_entry *e, irq_set[KVM_NR_IRQCHIPS]; |
| 150 | int ret = -1; | 150 | int ret = -1, i = 0; |
| 151 | struct kvm_irq_routing_table *irq_rt; | 151 | struct kvm_irq_routing_table *irq_rt; |
| 152 | struct hlist_node *n; | 152 | struct hlist_node *n; |
| 153 | 153 | ||
| @@ -162,14 +162,19 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level) | |||
| 162 | rcu_read_lock(); | 162 | rcu_read_lock(); |
| 163 | irq_rt = rcu_dereference(kvm->irq_routing); | 163 | irq_rt = rcu_dereference(kvm->irq_routing); |
| 164 | if (irq < irq_rt->nr_rt_entries) | 164 | if (irq < irq_rt->nr_rt_entries) |
| 165 | hlist_for_each_entry(e, n, &irq_rt->map[irq], link) { | 165 | hlist_for_each_entry(e, n, &irq_rt->map[irq], link) |
| 166 | int r = e->set(e, kvm, irq_source_id, level); | 166 | irq_set[i++] = *e; |
| 167 | if (r < 0) | ||
| 168 | continue; | ||
| 169 | |||
| 170 | ret = r + ((ret < 0) ? 0 : ret); | ||
| 171 | } | ||
| 172 | rcu_read_unlock(); | 167 | rcu_read_unlock(); |
| 168 | |||
| 169 | while(i--) { | ||
| 170 | int r; | ||
| 171 | r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level); | ||
| 172 | if (r < 0) | ||
| 173 | continue; | ||
| 174 | |||
| 175 | ret = r + ((ret < 0) ? 0 : ret); | ||
| 176 | } | ||
| 177 | |||
| 173 | return ret; | 178 | return ret; |
| 174 | } | 179 | } |
| 175 | 180 | ||
