ioapic.c 16.6 KB
Newer Older
E
Eddie Dong 已提交
1 2
/*
 *  Copyright (C) 2001  MandrakeSoft S.A.
A
Avi Kivity 已提交
3
 *  Copyright 2010 Red Hat, Inc. and/or its affiliates.
E
Eddie Dong 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 *
 *    MandrakeSoft S.A.
 *    43, rue d'Aboukir
 *    75002 Paris - France
 *    http://www.linux-mandrake.com/
 *    http://www.mandrakesoft.com/
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 *  Yunhong Jiang <yunhong.jiang@intel.com>
 *  Yaozu (Eddie) Dong <eddie.dong@intel.com>
 *  Based on Xen 3.1 code.
 */

30
#include <linux/kvm_host.h>
E
Eddie Dong 已提交
31 32 33 34 35 36
#include <linux/kvm.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/smp.h>
#include <linux/hrtimer.h>
#include <linux/io.h>
37
#include <linux/slab.h>
38
#include <linux/export.h>
E
Eddie Dong 已提交
39 40 41
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/current.h>
42
#include <trace/events/kvm.h>
43 44 45

#include "ioapic.h"
#include "lapic.h"
M
Marcelo Tosatti 已提交
46
#include "irq.h"
47

48 49 50
#if 0
#define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg)
#else
E
Eddie Dong 已提交
51
#define ioapic_debug(fmt, arg...)
52
#endif
53
static int ioapic_service(struct kvm_ioapic *vioapic, int irq,
54
		bool line_status);
E
Eddie Dong 已提交
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
					  unsigned long addr,
					  unsigned long length)
{
	unsigned long result = 0;

	switch (ioapic->ioregsel) {
	case IOAPIC_REG_VERSION:
		result = ((((IOAPIC_NUM_PINS - 1) & 0xff) << 16)
			  | (IOAPIC_VERSION_ID & 0xff));
		break;

	case IOAPIC_REG_APIC_ID:
	case IOAPIC_REG_ARB_ID:
		result = ((ioapic->id & 0xf) << 24);
		break;

	default:
		{
			u32 redir_index = (ioapic->ioregsel - 0x10) >> 1;
			u64 redir_content;

78 79 80 81 82
			if (redir_index < IOAPIC_NUM_PINS)
				redir_content =
					ioapic->redirtbl[redir_index].bits;
			else
				redir_content = ~0ULL;
E
Eddie Dong 已提交
83 84 85 86 87 88 89 90 91 92 93

			result = (ioapic->ioregsel & 0x1) ?
			    (redir_content >> 32) & 0xffffffff :
			    redir_content & 0xffffffff;
			break;
		}
	}

	return result;
}

94 95 96 97 98 99
static void rtc_irq_eoi_tracking_reset(struct kvm_ioapic *ioapic)
{
	ioapic->rtc_status.pending_eoi = 0;
	bitmap_zero(ioapic->rtc_status.dest_map, KVM_MAX_VCPUS);
}

100 101 102 103 104 105 106 107
static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic);

static void rtc_status_pending_eoi_check_valid(struct kvm_ioapic *ioapic)
{
	if (WARN_ON(ioapic->rtc_status.pending_eoi < 0))
		kvm_rtc_eoi_tracking_restore_all(ioapic);
}

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
static void __rtc_irq_eoi_tracking_restore_one(struct kvm_vcpu *vcpu)
{
	bool new_val, old_val;
	struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
	union kvm_ioapic_redirect_entry *e;

	e = &ioapic->redirtbl[RTC_GSI];
	if (!kvm_apic_match_dest(vcpu, NULL, 0,	e->fields.dest_id,
				e->fields.dest_mode))
		return;

	new_val = kvm_apic_pending_eoi(vcpu, e->fields.vector);
	old_val = test_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map);

	if (new_val == old_val)
		return;

	if (new_val) {
		__set_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map);
		ioapic->rtc_status.pending_eoi++;
	} else {
		__clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map);
		ioapic->rtc_status.pending_eoi--;
131
		rtc_status_pending_eoi_check_valid(ioapic);
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
	}
}

void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu)
{
	struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;

	spin_lock(&ioapic->lock);
	__rtc_irq_eoi_tracking_restore_one(vcpu);
	spin_unlock(&ioapic->lock);
}

static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic)
{
	struct kvm_vcpu *vcpu;
	int i;

	if (RTC_GSI >= IOAPIC_NUM_PINS)
		return;

	rtc_irq_eoi_tracking_reset(ioapic);
	kvm_for_each_vcpu(i, vcpu, ioapic->kvm)
	    __rtc_irq_eoi_tracking_restore_one(vcpu);
}

157 158
static void rtc_irq_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu)
{
159
	if (test_and_clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map)) {
160
		--ioapic->rtc_status.pending_eoi;
161 162
		rtc_status_pending_eoi_check_valid(ioapic);
	}
163 164 165 166 167 168 169 170 171 172
}

static bool rtc_irq_check_coalesced(struct kvm_ioapic *ioapic)
{
	if (ioapic->rtc_status.pending_eoi > 0)
		return true; /* coalesced */

	return false;
}

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
		int irq_level, bool line_status)
{
	union kvm_ioapic_redirect_entry entry;
	u32 mask = 1 << irq;
	u32 old_irr;
	int edge, ret;

	entry = ioapic->redirtbl[irq];
	edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG);

	if (!irq_level) {
		ioapic->irr &= ~mask;
		ret = 1;
		goto out;
	}

	/*
	 * Return 0 for coalesced interrupts; for edge-triggered interrupts,
	 * this only happens if a previous edge has not been delivered due
	 * do masking.  For level interrupts, the remote_irr field tells
	 * us if the interrupt is waiting for an EOI.
	 *
	 * RTC is special: it is edge-triggered, but userspace likes to know
	 * if it has been already ack-ed via EOI because coalesced RTC
	 * interrupts lead to time drift in Windows guests.  So we track
	 * EOI manually for the RTC interrupt.
	 */
	if (irq == RTC_GSI && line_status &&
		rtc_irq_check_coalesced(ioapic)) {
		ret = 0;
		goto out;
	}

	old_irr = ioapic->irr;
	ioapic->irr |= mask;
209 210
	if (edge)
		ioapic->irr_delivered &= ~mask;
211 212 213 214 215 216 217 218 219 220 221 222 223
	if ((edge && old_irr == ioapic->irr) ||
	    (!edge && entry.fields.remote_irr)) {
		ret = 0;
		goto out;
	}

	ret = ioapic_service(ioapic, irq, line_status);

out:
	trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0);
	return ret;
}

224 225 226 227 228 229 230 231 232 233 234 235
static void kvm_ioapic_inject_all(struct kvm_ioapic *ioapic, unsigned long irr)
{
	u32 idx;

	rtc_irq_eoi_tracking_reset(ioapic);
	for_each_set_bit(idx, &irr, IOAPIC_NUM_PINS)
		ioapic_set_irq(ioapic, idx, 1, true);

	kvm_rtc_eoi_tracking_restore_all(ioapic);
}


236
void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, ulong *ioapic_handled_vectors)
237 238 239 240 241 242 243 244
{
	struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
	union kvm_ioapic_redirect_entry *e;
	int index;

	spin_lock(&ioapic->lock);
	for (index = 0; index < IOAPIC_NUM_PINS; index++) {
		e = &ioapic->redirtbl[index];
245 246 247
		if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG ||
		    kvm_irq_has_notifier(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index) ||
		    index == RTC_GSI) {
248
			if (kvm_apic_match_dest(vcpu, NULL, 0,
249 250 251
			             e->fields.dest_id, e->fields.dest_mode) ||
			    (e->fields.trig_mode == IOAPIC_EDGE_TRIG &&
			     kvm_apic_pending_eoi(vcpu, e->fields.vector)))
252
				__set_bit(e->fields.vector,
253
					  ioapic_handled_vectors);
254 255 256 257 258
		}
	}
	spin_unlock(&ioapic->lock);
}

259
void kvm_vcpu_request_scan_ioapic(struct kvm *kvm)
260 261 262
{
	struct kvm_ioapic *ioapic = kvm->arch.vioapic;

263
	if (!ioapic)
264
		return;
265
	kvm_make_scan_ioapic_request(kvm);
266 267
}

E
Eddie Dong 已提交
268 269 270
static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
{
	unsigned index;
271
	bool mask_before, mask_after;
272
	union kvm_ioapic_redirect_entry *e;
E
Eddie Dong 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288

	switch (ioapic->ioregsel) {
	case IOAPIC_REG_VERSION:
		/* Writes are ignored. */
		break;

	case IOAPIC_REG_APIC_ID:
		ioapic->id = (val >> 24) & 0xf;
		break;

	case IOAPIC_REG_ARB_ID:
		break;

	default:
		index = (ioapic->ioregsel - 0x10) >> 1;

289
		ioapic_debug("change redir index %x val %x\n", index, val);
E
Eddie Dong 已提交
290 291
		if (index >= IOAPIC_NUM_PINS)
			return;
292 293
		e = &ioapic->redirtbl[index];
		mask_before = e->fields.mask;
E
Eddie Dong 已提交
294
		if (ioapic->ioregsel & 1) {
295 296
			e->bits &= 0xffffffff;
			e->bits |= (u64) val << 32;
E
Eddie Dong 已提交
297
		} else {
298 299 300
			e->bits &= ~0xffffffffULL;
			e->bits |= (u32) val;
			e->fields.remote_irr = 0;
E
Eddie Dong 已提交
301
		}
302
		mask_after = e->fields.mask;
303
		if (mask_before != mask_after)
304
			kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
305
		if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG
306
		    && ioapic->irr & (1 << index))
307
			ioapic_service(ioapic, index, false);
308
		kvm_vcpu_request_scan_ioapic(ioapic->kvm);
E
Eddie Dong 已提交
309 310 311 312
		break;
	}
}

313
static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
314
{
315 316
	union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
	struct kvm_lapic_irq irqe;
317
	int ret;
318

319 320 321
	if (entry->fields.mask)
		return -1;

322 323
	ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
		     "vector=%x trig_mode=%x\n",
324
		     entry->fields.dest_id, entry->fields.dest_mode,
325 326 327 328 329 330 331 332 333 334
		     entry->fields.delivery_mode, entry->fields.vector,
		     entry->fields.trig_mode);

	irqe.dest_id = entry->fields.dest_id;
	irqe.vector = entry->fields.vector;
	irqe.dest_mode = entry->fields.dest_mode;
	irqe.trig_mode = entry->fields.trig_mode;
	irqe.delivery_mode = entry->fields.delivery_mode << 8;
	irqe.level = 1;
	irqe.shorthand = 0;
335
	irqe.msi_redir_hint = false;
336

337
	if (irqe.trig_mode == IOAPIC_EDGE_TRIG)
338
		ioapic->irr_delivered |= 1 << irq;
339

340
	if (irq == RTC_GSI && line_status) {
341 342 343 344 345 346
		/*
		 * pending_eoi cannot ever become negative (see
		 * rtc_status_pending_eoi_check_valid) and the caller
		 * ensures that it is only called if it is >= zero, namely
		 * if rtc_irq_check_coalesced returns false).
		 */
347 348 349
		BUG_ON(ioapic->rtc_status.pending_eoi != 0);
		ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe,
				ioapic->rtc_status.dest_map);
350
		ioapic->rtc_status.pending_eoi = (ret < 0 ? 0 : ret);
351 352 353
	} else
		ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, NULL);

354 355 356
	if (ret && irqe.trig_mode == IOAPIC_LEVEL_TRIG)
		entry->fields.remote_irr = 1;

357
	return ret;
358 359
}

360
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
361
		       int level, bool line_status)
E
Eddie Dong 已提交
362
{
363 364 365
	int ret, irq_level;

	BUG_ON(irq < 0 || irq >= IOAPIC_NUM_PINS);
E
Eddie Dong 已提交
366

367
	spin_lock(&ioapic->lock);
368 369
	irq_level = __kvm_irq_line_state(&ioapic->irq_states[irq],
					 irq_source_id, level);
370
	ret = ioapic_set_irq(ioapic, irq, irq_level, line_status);
371

372
	spin_unlock(&ioapic->lock);
G
Gleb Natapov 已提交
373

374
	return ret;
E
Eddie Dong 已提交
375 376
}

377 378 379 380 381 382 383 384 385 386
void kvm_ioapic_clear_all(struct kvm_ioapic *ioapic, int irq_source_id)
{
	int i;

	spin_lock(&ioapic->lock);
	for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++)
		__clear_bit(irq_source_id, &ioapic->irq_states[i]);
	spin_unlock(&ioapic->lock);
}

387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
static void kvm_ioapic_eoi_inject_work(struct work_struct *work)
{
	int i;
	struct kvm_ioapic *ioapic = container_of(work, struct kvm_ioapic,
						 eoi_inject.work);
	spin_lock(&ioapic->lock);
	for (i = 0; i < IOAPIC_NUM_PINS; i++) {
		union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];

		if (ent->fields.trig_mode != IOAPIC_LEVEL_TRIG)
			continue;

		if (ioapic->irr & (1 << i) && !ent->fields.remote_irr)
			ioapic_service(ioapic, i, false);
	}
	spin_unlock(&ioapic->lock);
}

#define IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT 10000

407 408
static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
			struct kvm_ioapic *ioapic, int vector, int trigger_mode)
E
Eddie Dong 已提交
409
{
G
Gleb Natapov 已提交
410
	int i;
411
	struct kvm_lapic *apic = vcpu->arch.apic;
G
Gleb Natapov 已提交
412 413 414

	for (i = 0; i < IOAPIC_NUM_PINS; i++) {
		union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
E
Eddie Dong 已提交
415

G
Gleb Natapov 已提交
416 417
		if (ent->fields.vector != vector)
			continue;
E
Eddie Dong 已提交
418

419 420
		if (i == RTC_GSI)
			rtc_irq_eoi(ioapic, vcpu);
G
Gleb Natapov 已提交
421 422 423 424 425 426 427 428
		/*
		 * We are dropping lock while calling ack notifiers because ack
		 * notifier callbacks for assigned devices call into IOAPIC
		 * recursively. Since remote_irr is cleared only after call
		 * to notifiers if the same vector will be delivered while lock
		 * is dropped it will be put into irr and will be delivered
		 * after ack notifier returns.
		 */
429
		spin_unlock(&ioapic->lock);
G
Gleb Natapov 已提交
430
		kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i);
431
		spin_lock(&ioapic->lock);
G
Gleb Natapov 已提交
432

433 434
		if (trigger_mode != IOAPIC_LEVEL_TRIG ||
		    kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
G
Gleb Natapov 已提交
435
			continue;
M
Marcelo Tosatti 已提交
436 437 438

		ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
		ent->fields.remote_irr = 0;
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
		if (!ent->fields.mask && (ioapic->irr & (1 << i))) {
			++ioapic->irq_eoi[i];
			if (ioapic->irq_eoi[i] == IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT) {
				/*
				 * Real hardware does not deliver the interrupt
				 * immediately during eoi broadcast, and this
				 * lets a buggy guest make slow progress
				 * even if it does not correctly handle a
				 * level-triggered interrupt.  Emulate this
				 * behavior if we detect an interrupt storm.
				 */
				schedule_delayed_work(&ioapic->eoi_inject, HZ / 100);
				ioapic->irq_eoi[i] = 0;
				trace_kvm_ioapic_delayed_eoi_inj(ent->bits);
			} else {
				ioapic_service(ioapic, i, false);
			}
		} else {
			ioapic->irq_eoi[i] = 0;
		}
M
Marcelo Tosatti 已提交
459
	}
E
Eddie Dong 已提交
460 461
}

462
void kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, int vector, int trigger_mode)
463
{
464
	struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
465

466
	spin_lock(&ioapic->lock);
467
	__kvm_ioapic_update_eoi(vcpu, ioapic, vector, trigger_mode);
468
	spin_unlock(&ioapic->lock);
469 470
}

G
Gregory Haskins 已提交
471 472 473 474 475
static inline struct kvm_ioapic *to_ioapic(struct kvm_io_device *dev)
{
	return container_of(dev, struct kvm_ioapic, dev);
}

476
static inline int ioapic_in_range(struct kvm_ioapic *ioapic, gpa_t addr)
E
Eddie Dong 已提交
477 478 479 480 481
{
	return ((addr >= ioapic->base_address &&
		 (addr < ioapic->base_address + IOAPIC_MEM_LENGTH)));
}

482 483
static int ioapic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
				gpa_t addr, int len, void *val)
E
Eddie Dong 已提交
484
{
G
Gregory Haskins 已提交
485
	struct kvm_ioapic *ioapic = to_ioapic(this);
E
Eddie Dong 已提交
486
	u32 result;
487 488
	if (!ioapic_in_range(ioapic, addr))
		return -EOPNOTSUPP;
E
Eddie Dong 已提交
489

490
	ioapic_debug("addr %lx\n", (unsigned long)addr);
E
Eddie Dong 已提交
491 492 493
	ASSERT(!(addr & 0xf));	/* check alignment */

	addr &= 0xff;
494
	spin_lock(&ioapic->lock);
E
Eddie Dong 已提交
495 496 497 498 499 500 501 502 503 504 505 506 507
	switch (addr) {
	case IOAPIC_REG_SELECT:
		result = ioapic->ioregsel;
		break;

	case IOAPIC_REG_WINDOW:
		result = ioapic_read_indirect(ioapic, addr, len);
		break;

	default:
		result = 0;
		break;
	}
508
	spin_unlock(&ioapic->lock);
G
Gleb Natapov 已提交
509

E
Eddie Dong 已提交
510 511 512 513 514 515 516 517 518 519 520 521
	switch (len) {
	case 8:
		*(u64 *) val = result;
		break;
	case 1:
	case 2:
	case 4:
		memcpy(val, (char *)&result, len);
		break;
	default:
		printk(KERN_WARNING "ioapic: wrong length %d\n", len);
	}
522
	return 0;
E
Eddie Dong 已提交
523 524
}

525 526
static int ioapic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
				 gpa_t addr, int len, const void *val)
E
Eddie Dong 已提交
527
{
G
Gregory Haskins 已提交
528
	struct kvm_ioapic *ioapic = to_ioapic(this);
E
Eddie Dong 已提交
529
	u32 data;
530 531
	if (!ioapic_in_range(ioapic, addr))
		return -EOPNOTSUPP;
E
Eddie Dong 已提交
532

533 534
	ioapic_debug("ioapic_mmio_write addr=%p len=%d val=%p\n",
		     (void*)addr, len, val);
E
Eddie Dong 已提交
535
	ASSERT(!(addr & 0xf));	/* check alignment */
536

537 538 539
	switch (len) {
	case 8:
	case 4:
E
Eddie Dong 已提交
540
		data = *(u32 *) val;
541 542 543 544 545 546 547 548
		break;
	case 2:
		data = *(u16 *) val;
		break;
	case 1:
		data = *(u8  *) val;
		break;
	default:
E
Eddie Dong 已提交
549
		printk(KERN_WARNING "ioapic: Unsupported size %d\n", len);
G
Gleb Natapov 已提交
550
		return 0;
E
Eddie Dong 已提交
551 552 553
	}

	addr &= 0xff;
554
	spin_lock(&ioapic->lock);
E
Eddie Dong 已提交
555 556
	switch (addr) {
	case IOAPIC_REG_SELECT:
557
		ioapic->ioregsel = data & 0xFF; /* 8-bit register */
E
Eddie Dong 已提交
558 559 560 561 562 563 564 565 566
		break;

	case IOAPIC_REG_WINDOW:
		ioapic_write_indirect(ioapic, data);
		break;

	default:
		break;
	}
567
	spin_unlock(&ioapic->lock);
568
	return 0;
E
Eddie Dong 已提交
569 570
}

571
static void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
572 573 574
{
	int i;

575
	cancel_delayed_work_sync(&ioapic->eoi_inject);
576 577 578 579 580
	for (i = 0; i < IOAPIC_NUM_PINS; i++)
		ioapic->redirtbl[i].fields.mask = 1;
	ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
	ioapic->ioregsel = 0;
	ioapic->irr = 0;
581
	ioapic->irr_delivered = 0;
582
	ioapic->id = 0;
583
	memset(ioapic->irq_eoi, 0x00, IOAPIC_NUM_PINS);
584
	rtc_irq_eoi_tracking_reset(ioapic);
585 586
}

G
Gregory Haskins 已提交
587 588 589 590 591
static const struct kvm_io_device_ops ioapic_mmio_ops = {
	.read     = ioapic_mmio_read,
	.write    = ioapic_mmio_write,
};

E
Eddie Dong 已提交
592 593 594
int kvm_ioapic_init(struct kvm *kvm)
{
	struct kvm_ioapic *ioapic;
595
	int ret;
E
Eddie Dong 已提交
596 597 598 599

	ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
	if (!ioapic)
		return -ENOMEM;
600
	spin_lock_init(&ioapic->lock);
601
	INIT_DELAYED_WORK(&ioapic->eoi_inject, kvm_ioapic_eoi_inject_work);
602
	kvm->arch.vioapic = ioapic;
603
	kvm_ioapic_reset(ioapic);
G
Gregory Haskins 已提交
604
	kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
E
Eddie Dong 已提交
605
	ioapic->kvm = kvm;
606
	mutex_lock(&kvm->slots_lock);
607 608
	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, ioapic->base_address,
				      IOAPIC_MEM_LENGTH, &ioapic->dev);
609
	mutex_unlock(&kvm->slots_lock);
610 611
	if (ret < 0) {
		kvm->arch.vioapic = NULL;
612
		kfree(ioapic);
613
		return ret;
614
	}
615

616
	kvm_vcpu_request_scan_ioapic(kvm);
617
	return ret;
E
Eddie Dong 已提交
618
}
619

620 621 622 623
void kvm_ioapic_destroy(struct kvm *kvm)
{
	struct kvm_ioapic *ioapic = kvm->arch.vioapic;

624
	cancel_delayed_work_sync(&ioapic->eoi_inject);
J
Julia Lawall 已提交
625 626 627
	kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &ioapic->dev);
	kvm->arch.vioapic = NULL;
	kfree(ioapic);
628 629
}

G
Gleb Natapov 已提交
630 631 632 633 634 635
int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
{
	struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
	if (!ioapic)
		return -EINVAL;

636
	spin_lock(&ioapic->lock);
G
Gleb Natapov 已提交
637
	memcpy(state, ioapic, sizeof(struct kvm_ioapic_state));
638
	state->irr &= ~ioapic->irr_delivered;
639
	spin_unlock(&ioapic->lock);
G
Gleb Natapov 已提交
640 641 642 643 644 645 646 647 648
	return 0;
}

int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
{
	struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
	if (!ioapic)
		return -EINVAL;

649
	spin_lock(&ioapic->lock);
G
Gleb Natapov 已提交
650
	memcpy(ioapic, state, sizeof(struct kvm_ioapic_state));
651
	ioapic->irr = 0;
652
	ioapic->irr_delivered = 0;
653
	kvm_vcpu_request_scan_ioapic(kvm);
654
	kvm_ioapic_inject_all(ioapic, state->irr);
655
	spin_unlock(&ioapic->lock);
G
Gleb Natapov 已提交
656 657
	return 0;
}