ioapic.c 18.0 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
static int ioapic_service(struct kvm_ioapic *vioapic, int irq,
49
		bool line_status);
E
Eddie Dong 已提交
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

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;

73 74 75 76 77
			if (redir_index < IOAPIC_NUM_PINS)
				redir_content =
					ioapic->redirtbl[redir_index].bits;
			else
				redir_content = ~0ULL;
E
Eddie Dong 已提交
78 79 80 81 82 83 84 85 86 87 88

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

	return result;
}

89 90 91
static void rtc_irq_eoi_tracking_reset(struct kvm_ioapic *ioapic)
{
	ioapic->rtc_status.pending_eoi = 0;
92
	bitmap_zero(ioapic->rtc_status.dest_map.map, KVM_MAX_VCPU_ID);
93 94
}

95 96 97 98 99 100 101 102
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);
}

103 104 105 106
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;
107
	struct dest_map *dest_map = &ioapic->rtc_status.dest_map;
108 109 110 111 112 113 114 115
	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);
116
	old_val = test_bit(vcpu->vcpu_id, dest_map->map);
117 118 119 120 121

	if (new_val == old_val)
		return;

	if (new_val) {
122 123
		__set_bit(vcpu->vcpu_id, dest_map->map);
		dest_map->vectors[vcpu->vcpu_id] = e->fields.vector;
124 125
		ioapic->rtc_status.pending_eoi++;
	} else {
126
		__clear_bit(vcpu->vcpu_id, dest_map->map);
127
		ioapic->rtc_status.pending_eoi--;
128
		rtc_status_pending_eoi_check_valid(ioapic);
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
	}
}

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);
}

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

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

	return false;
}

171 172 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
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;
207
	if (edge) {
208
		ioapic->irr_delivered &= ~mask;
209 210 211 212
		if (old_irr == ioapic->irr) {
			ret = 0;
			goto out;
		}
213 214 215 216 217 218 219 220 221
	}

	ret = ioapic_service(ioapic, irq, line_status);

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

222 223 224 225 226 227 228 229 230 231 232 233
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);
}


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

	spin_lock(&ioapic->lock);
242 243 244 245 246 247

	/* Make sure we see any missing RTC EOI */
	if (test_bit(vcpu->vcpu_id, dest_map->map))
		__set_bit(dest_map->vectors[vcpu->vcpu_id],
			  ioapic_handled_vectors);

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

263
void kvm_arch_post_irq_ack_notifier_list_update(struct kvm *kvm)
264
{
265
	if (!ioapic_in_kernel(kvm))
266
		return;
267
	kvm_make_scan_ioapic_request(kvm);
268 269
}

E
Eddie Dong 已提交
270 271 272
static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
{
	unsigned index;
273
	bool mask_before, mask_after;
274
	union kvm_ioapic_redirect_entry *e;
275 276
	unsigned long vcpu_bitmap;
	int old_remote_irr, old_delivery_status, old_dest_id, old_dest_mode;
E
Eddie Dong 已提交
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

	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;

		if (index >= IOAPIC_NUM_PINS)
			return;
295 296
		e = &ioapic->redirtbl[index];
		mask_before = e->fields.mask;
297 298 299
		/* Preserve read-only fields */
		old_remote_irr = e->fields.remote_irr;
		old_delivery_status = e->fields.delivery_status;
300 301
		old_dest_id = e->fields.dest_id;
		old_dest_mode = e->fields.dest_mode;
E
Eddie Dong 已提交
302
		if (ioapic->ioregsel & 1) {
303 304
			e->bits &= 0xffffffff;
			e->bits |= (u64) val << 32;
E
Eddie Dong 已提交
305
		} else {
306 307
			e->bits &= ~0xffffffffULL;
			e->bits |= (u32) val;
E
Eddie Dong 已提交
308
		}
309 310
		e->fields.remote_irr = old_remote_irr;
		e->fields.delivery_status = old_delivery_status;
311 312 313 314 315 316 317 318 319 320

		/*
		 * Some OSes (Linux, Xen) assume that Remote IRR bit will
		 * be cleared by IOAPIC hardware when the entry is configured
		 * as edge-triggered. This behavior is used to simulate an
		 * explicit EOI on IOAPICs that don't have the EOI register.
		 */
		if (e->fields.trig_mode == IOAPIC_EDGE_TRIG)
			e->fields.remote_irr = 0;

321
		mask_after = e->fields.mask;
322
		if (mask_before != mask_after)
323
			kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
324
		if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG
325
		    && ioapic->irr & (1 << index))
326
			ioapic_service(ioapic, index, false);
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
		if (e->fields.delivery_mode == APIC_DM_FIXED) {
			struct kvm_lapic_irq irq;

			irq.shorthand = 0;
			irq.vector = e->fields.vector;
			irq.delivery_mode = e->fields.delivery_mode << 8;
			irq.dest_id = e->fields.dest_id;
			irq.dest_mode = e->fields.dest_mode;
			kvm_bitmap_or_dest_vcpus(ioapic->kvm, &irq,
						 &vcpu_bitmap);
			if (old_dest_mode != e->fields.dest_mode ||
			    old_dest_id != e->fields.dest_id) {
				/*
				 * Update vcpu_bitmap with vcpus specified in
				 * the previous request as well. This is done to
				 * keep ioapic_handled_vectors synchronized.
				 */
				irq.dest_id = old_dest_id;
				irq.dest_mode = old_dest_mode;
				kvm_bitmap_or_dest_vcpus(ioapic->kvm, &irq,
							 &vcpu_bitmap);
			}
			kvm_make_scan_ioapic_request_mask(ioapic->kvm,
							  &vcpu_bitmap);
		} else {
			kvm_make_scan_ioapic_request(ioapic->kvm);
		}
E
Eddie Dong 已提交
354 355 356 357
		break;
	}
}

358
static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
359
{
360 361
	union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
	struct kvm_lapic_irq irqe;
362
	int ret;
363

364 365 366
	if (entry->fields.mask ||
	    (entry->fields.trig_mode == IOAPIC_LEVEL_TRIG &&
	    entry->fields.remote_irr))
367 368
		return -1;

369 370 371 372 373 374 375
	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;
376
	irqe.msi_redir_hint = false;
377

378
	if (irqe.trig_mode == IOAPIC_EDGE_TRIG)
379
		ioapic->irr_delivered |= 1 << irq;
380

381
	if (irq == RTC_GSI && line_status) {
382 383 384 385 386 387
		/*
		 * 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).
		 */
388 389
		BUG_ON(ioapic->rtc_status.pending_eoi != 0);
		ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe,
390
					       &ioapic->rtc_status.dest_map);
391
		ioapic->rtc_status.pending_eoi = (ret < 0 ? 0 : ret);
392 393 394
	} else
		ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, NULL);

395 396 397
	if (ret && irqe.trig_mode == IOAPIC_LEVEL_TRIG)
		entry->fields.remote_irr = 1;

398
	return ret;
399 400
}

401
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
402
		       int level, bool line_status)
E
Eddie Dong 已提交
403
{
404 405 406
	int ret, irq_level;

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

408
	spin_lock(&ioapic->lock);
409 410
	irq_level = __kvm_irq_line_state(&ioapic->irq_states[irq],
					 irq_source_id, level);
411
	ret = ioapic_set_irq(ioapic, irq, irq_level, line_status);
412

413
	spin_unlock(&ioapic->lock);
G
Gleb Natapov 已提交
414

415
	return ret;
E
Eddie Dong 已提交
416 417
}

418 419 420 421 422 423 424 425 426 427
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);
}

428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
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

448 449
static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
			struct kvm_ioapic *ioapic, int vector, int trigger_mode)
E
Eddie Dong 已提交
450
{
451
	struct dest_map *dest_map = &ioapic->rtc_status.dest_map;
452
	struct kvm_lapic *apic = vcpu->arch.apic;
453 454 455 456 457 458
	int i;

	/* RTC special handling */
	if (test_bit(vcpu->vcpu_id, dest_map->map) &&
	    vector == dest_map->vectors[vcpu->vcpu_id])
		rtc_irq_eoi(ioapic, vcpu);
G
Gleb Natapov 已提交
459 460 461

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

G
Gleb Natapov 已提交
463 464
		if (ent->fields.vector != vector)
			continue;
E
Eddie Dong 已提交
465

G
Gleb Natapov 已提交
466 467 468 469 470 471 472 473
		/*
		 * 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.
		 */
474
		spin_unlock(&ioapic->lock);
G
Gleb Natapov 已提交
475
		kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i);
476
		spin_lock(&ioapic->lock);
G
Gleb Natapov 已提交
477

478
		if (trigger_mode != IOAPIC_LEVEL_TRIG ||
479
		    kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
G
Gleb Natapov 已提交
480
			continue;
M
Marcelo Tosatti 已提交
481 482 483

		ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
		ent->fields.remote_irr = 0;
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
		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 已提交
504
	}
E
Eddie Dong 已提交
505 506
}

507
void kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, int vector, int trigger_mode)
508
{
509
	struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
510

511
	spin_lock(&ioapic->lock);
512
	__kvm_ioapic_update_eoi(vcpu, ioapic, vector, trigger_mode);
513
	spin_unlock(&ioapic->lock);
514 515
}

G
Gregory Haskins 已提交
516 517 518 519 520
static inline struct kvm_ioapic *to_ioapic(struct kvm_io_device *dev)
{
	return container_of(dev, struct kvm_ioapic, dev);
}

521
static inline int ioapic_in_range(struct kvm_ioapic *ioapic, gpa_t addr)
E
Eddie Dong 已提交
522 523 524 525 526
{
	return ((addr >= ioapic->base_address &&
		 (addr < ioapic->base_address + IOAPIC_MEM_LENGTH)));
}

527 528
static int ioapic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
				gpa_t addr, int len, void *val)
E
Eddie Dong 已提交
529
{
G
Gregory Haskins 已提交
530
	struct kvm_ioapic *ioapic = to_ioapic(this);
E
Eddie Dong 已提交
531
	u32 result;
532 533
	if (!ioapic_in_range(ioapic, addr))
		return -EOPNOTSUPP;
E
Eddie Dong 已提交
534 535 536 537

	ASSERT(!(addr & 0xf));	/* check alignment */

	addr &= 0xff;
538
	spin_lock(&ioapic->lock);
E
Eddie Dong 已提交
539 540 541 542 543 544 545 546 547 548 549 550 551
	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;
	}
552
	spin_unlock(&ioapic->lock);
G
Gleb Natapov 已提交
553

E
Eddie Dong 已提交
554 555 556 557 558 559 560 561 562 563 564 565
	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);
	}
566
	return 0;
E
Eddie Dong 已提交
567 568
}

569 570
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 已提交
571
{
G
Gregory Haskins 已提交
572
	struct kvm_ioapic *ioapic = to_ioapic(this);
E
Eddie Dong 已提交
573
	u32 data;
574 575
	if (!ioapic_in_range(ioapic, addr))
		return -EOPNOTSUPP;
E
Eddie Dong 已提交
576 577

	ASSERT(!(addr & 0xf));	/* check alignment */
578

579 580 581
	switch (len) {
	case 8:
	case 4:
E
Eddie Dong 已提交
582
		data = *(u32 *) val;
583 584 585 586 587 588 589 590
		break;
	case 2:
		data = *(u16 *) val;
		break;
	case 1:
		data = *(u8  *) val;
		break;
	default:
E
Eddie Dong 已提交
591
		printk(KERN_WARNING "ioapic: Unsupported size %d\n", len);
G
Gleb Natapov 已提交
592
		return 0;
E
Eddie Dong 已提交
593 594 595
	}

	addr &= 0xff;
596
	spin_lock(&ioapic->lock);
E
Eddie Dong 已提交
597 598
	switch (addr) {
	case IOAPIC_REG_SELECT:
599
		ioapic->ioregsel = data & 0xFF; /* 8-bit register */
E
Eddie Dong 已提交
600 601 602 603 604 605 606 607 608
		break;

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

	default:
		break;
	}
609
	spin_unlock(&ioapic->lock);
610
	return 0;
E
Eddie Dong 已提交
611 612
}

613
static void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
614 615 616
{
	int i;

617
	cancel_delayed_work_sync(&ioapic->eoi_inject);
618 619 620 621 622
	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;
623
	ioapic->irr_delivered = 0;
624
	ioapic->id = 0;
J
Jiri Slaby 已提交
625
	memset(ioapic->irq_eoi, 0x00, sizeof(ioapic->irq_eoi));
626
	rtc_irq_eoi_tracking_reset(ioapic);
627 628
}

G
Gregory Haskins 已提交
629 630 631 632 633
static const struct kvm_io_device_ops ioapic_mmio_ops = {
	.read     = ioapic_mmio_read,
	.write    = ioapic_mmio_write,
};

E
Eddie Dong 已提交
634 635 636
int kvm_ioapic_init(struct kvm *kvm)
{
	struct kvm_ioapic *ioapic;
637
	int ret;
E
Eddie Dong 已提交
638

639
	ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL_ACCOUNT);
E
Eddie Dong 已提交
640 641
	if (!ioapic)
		return -ENOMEM;
642
	spin_lock_init(&ioapic->lock);
643
	INIT_DELAYED_WORK(&ioapic->eoi_inject, kvm_ioapic_eoi_inject_work);
644
	kvm->arch.vioapic = ioapic;
645
	kvm_ioapic_reset(ioapic);
G
Gregory Haskins 已提交
646
	kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
E
Eddie Dong 已提交
647
	ioapic->kvm = kvm;
648
	mutex_lock(&kvm->slots_lock);
649 650
	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, ioapic->base_address,
				      IOAPIC_MEM_LENGTH, &ioapic->dev);
651
	mutex_unlock(&kvm->slots_lock);
652 653
	if (ret < 0) {
		kvm->arch.vioapic = NULL;
654
		kfree(ioapic);
655
	}
656 657

	return ret;
E
Eddie Dong 已提交
658
}
659

660 661 662 663
void kvm_ioapic_destroy(struct kvm *kvm)
{
	struct kvm_ioapic *ioapic = kvm->arch.vioapic;

664 665 666
	if (!ioapic)
		return;

667
	cancel_delayed_work_sync(&ioapic->eoi_inject);
668
	mutex_lock(&kvm->slots_lock);
J
Julia Lawall 已提交
669
	kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &ioapic->dev);
670
	mutex_unlock(&kvm->slots_lock);
J
Julia Lawall 已提交
671 672
	kvm->arch.vioapic = NULL;
	kfree(ioapic);
673 674
}

675
void kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
G
Gleb Natapov 已提交
676
{
677
	struct kvm_ioapic *ioapic = kvm->arch.vioapic;
G
Gleb Natapov 已提交
678

679
	spin_lock(&ioapic->lock);
G
Gleb Natapov 已提交
680
	memcpy(state, ioapic, sizeof(struct kvm_ioapic_state));
681
	state->irr &= ~ioapic->irr_delivered;
682
	spin_unlock(&ioapic->lock);
G
Gleb Natapov 已提交
683 684
}

685
void kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
G
Gleb Natapov 已提交
686
{
687
	struct kvm_ioapic *ioapic = kvm->arch.vioapic;
G
Gleb Natapov 已提交
688

689
	spin_lock(&ioapic->lock);
G
Gleb Natapov 已提交
690
	memcpy(ioapic, state, sizeof(struct kvm_ioapic_state));
691
	ioapic->irr = 0;
692
	ioapic->irr_delivered = 0;
693
	kvm_make_scan_ioapic_request(kvm);
694
	kvm_ioapic_inject_all(ioapic, state->irr);
695
	spin_unlock(&ioapic->lock);
G
Gleb Natapov 已提交
696
}